Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stats function implementation #324

Draft
wants to merge 52 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
e2aab9b
Generated constants for realtimeTime
ikbalkaya Dec 14, 2021
8022b67
Time function implemenation in Dart side
ikbalkaya Dec 14, 2021
d56ff4d
Java / Android side implementation of time
ikbalkaya Dec 14, 2021
95942a5
IOS/objective C implementation of realtimeTime
ikbalkaya Dec 14, 2021
5463f49
Added time information to realtime_sliver.dart
ikbalkaya Dec 14, 2021
5b7c684
Replaced realtimeTime with time (codegen)
ikbalkaya Dec 14, 2021
1a1f961
Updated platform references to time
ikbalkaya Dec 14, 2021
78c7621
Renamed method to time in Java
ikbalkaya Dec 14, 2021
2662612
Updated refercen name to _time
ikbalkaya Dec 14, 2021
7b83e0f
Implemented time function in rest.dart
ikbalkaya Dec 14, 2021
f6fafeb
Added rest time to UI
ikbalkaya Dec 14, 2021
2a3b4c8
Used getAblyClient to get the rest instance
ikbalkaya Dec 14, 2021
f99dcca
Add code to be able to switch between rest/realtime for objective-c code
ikbalkaya Dec 14, 2021
a16be43
Code formatting
ikbalkaya Dec 14, 2021
f23f523
Code formatting for rest.dart and realtime.dart
ikbalkaya Dec 15, 2021
1719a4a
Made explicit differences between restTime and realtimeTime
ikbalkaya Dec 16, 2021
ea9315f
Split realtimeTime and restTime in two methods Android id side
ikbalkaya Dec 16, 2021
c570f08
Split realtimeTime and restTime in two methods iOSside
ikbalkaya Dec 16, 2021
dcaf6d0
Flutter format
ikbalkaya Dec 16, 2021
15a743c
Regenerated platform constants for time function
ikurek Feb 2, 2022
41f2d41
Fixed time methods code smells, added missing AblyBase import
ikurek Feb 2, 2022
38df5e5
Fixed restTime method message handling on iOS side
ikurek Feb 8, 2022
4457a5e
Made explicit differences between restTime and realtimeTime
ikbalkaya Dec 16, 2021
cdc153c
Codegen for realtime stats
ikbalkaya Dec 16, 2021
8249b95
Stats encoding from Android side
ikbalkaya Dec 20, 2021
fdd3027
Moved stats mapping from realtime to rest
ikbalkaya Dec 21, 2021
e588837
File formatting
ikbalkaya Dec 21, 2021
8a18f25
Created StatsEncoder for iOS
ikbalkaya Dec 21, 2021
8fc48e2
Stats encoding mappings in Obj-C
ikbalkaya Dec 21, 2021
d04a956
Fix function calls in StatsEncoders
ikbalkaya Dec 22, 2021
da16005
Stats function mapping in Objective-C
ikbalkaya Dec 22, 2021
bb2d954
File formattings
ikbalkaya Dec 22, 2021
244cb8f
Fix messageCategory encoding
ikbalkaya Dec 23, 2021
13f57de
File formatting
ikbalkaya Dec 23, 2021
7be18b9
Added params to the call in example app and confirmed it's working in…
ikbalkaya Dec 23, 2021
cd12ae1
Added param query builder for stat params
ikbalkaya Dec 23, 2021
6f2cfd6
file formatting
ikbalkaya Dec 23, 2021
f48023e
Removed leftover realtime stats widget
ikurek Feb 2, 2022
8bf9837
Regenerated platform constants
ikurek Feb 2, 2022
c902a1e
Added Java message codec support for Stats message type
ikurek Feb 3, 2022
c130b31
Implemented basic methods for decoding Stats JSON object
ikurek Feb 3, 2022
d66e5aa
Reduced Stats count fetched in example app
ikurek Feb 3, 2022
0e7ad6a
Removed unnecessary formatting changes from AblyMessageCodec to make …
ikurek Feb 3, 2022
2031824
Moved stats to proper category in codegen_context
ikurek Feb 3, 2022
b211abd
Added serialization method for StatsRequestCount
ikurek Feb 4, 2022
749c2cf
Added serialization method for StatsMessageTypes, fixed Android issue…
ikurek Feb 7, 2022
38a2918
Added serialization method for StatsConnectionTypes
ikurek Feb 7, 2022
f54f6f5
Added serialization method for StatsMessageTraffic
ikurek Feb 7, 2022
ca14d9c
Fixed tokenrequest serialization on dart side
ikurek Feb 7, 2022
289d451
Added decoding StatsMessageTypes for persisted field
ikurek Feb 7, 2022
9ad87dc
Fixed stats method message handling on iOS side
ikurek Feb 8, 2022
541e38f
Regenerated platform constants with codegen
ikurek Feb 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 87 additions & 3 deletions android/src/main/java/io/ably/flutter/plugin/AblyMessageCodec.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import io.ably.lib.types.MessageExtras;
import io.ably.lib.types.Param;
import io.ably.lib.types.PresenceMessage;
import io.ably.lib.types.Stats;
import io.ably.lib.util.Crypto;
import io.ably.lib.util.Log;
import io.flutter.plugin.common.StandardMessageCodec;
Expand Down Expand Up @@ -112,6 +113,8 @@ public AblyMessageCodec(CipherParamsStorage cipherParamsStorage) {
new CodecPair<>(null, self::decodeRestHistoryParams));
put(PlatformConstants.CodecTypes.realtimeHistoryParams,
new CodecPair<>(null, self::decodeRealtimeHistoryParams));
put(PlatformConstants.CodecTypes.stats,
new CodecPair<>(self::encodeStats, null));
put(PlatformConstants.CodecTypes.restPresenceParams,
new CodecPair<>(null, self::decodeRestPresenceParams));
put(PlatformConstants.CodecTypes.realtimePresenceParams,
Expand Down Expand Up @@ -144,6 +147,81 @@ public AblyMessageCodec(CipherParamsStorage cipherParamsStorage) {
};
}

private Map<String, Object> encodeStats(Stats stats) {
if (stats == null) return null;
final HashMap<String, Object> jsonMap = new HashMap<>();
writeValueToJson(jsonMap, PlatformConstants.TxStats.all, encodeStatsMessageTypes(stats.all));
writeValueToJson(jsonMap, PlatformConstants.TxStats.apiRequests, encodeStatsRequestCount(stats.apiRequests));
writeValueToJson(jsonMap, PlatformConstants.TxStats.channels, encodeStatsResourceCount(stats.channels));
writeValueToJson(jsonMap, PlatformConstants.TxStats.connections, encodeStatsConnectionTypes(stats.connections));
writeValueToJson(jsonMap, PlatformConstants.TxStats.inbound, encodeStatsMessageTraffic(stats.inbound));
writeValueToJson(jsonMap, PlatformConstants.TxStats.intervalId, stats.intervalId);
writeValueToJson(jsonMap, PlatformConstants.TxStats.outbound, encodeStatsMessageTraffic(stats.outbound));
writeValueToJson(jsonMap, PlatformConstants.TxStats.persisted, encodeStatsMessageTypes(stats.persisted));
writeValueToJson(jsonMap, PlatformConstants.TxStats.tokenRequests, encodeStatsRequestCount(stats.tokenRequests));
return jsonMap;
}

private Map<String, Object> encodeStatsMessageTraffic(Stats.MessageTraffic messageTraffic) {
if (messageTraffic == null) return null;
final HashMap<String, Object> jsonMap = new HashMap<>();
writeValueToJson(jsonMap, PlatformConstants.TxStatsMessageTraffic.all, encodeStatsMessageTypes(messageTraffic.all));
writeValueToJson(jsonMap, PlatformConstants.TxStatsMessageTraffic.realtime, encodeStatsMessageTypes(messageTraffic.realtime));
writeValueToJson(jsonMap, PlatformConstants.TxStatsMessageTraffic.rest, encodeStatsMessageTypes(messageTraffic.rest));
writeValueToJson(jsonMap, PlatformConstants.TxStatsMessageTraffic.webhook, encodeStatsMessageTypes(messageTraffic.webhook));
return jsonMap;
}

private Map<String, Object> encodeStatsConnectionTypes(Stats.ConnectionTypes connectionTypes) {
if (connectionTypes == null) return null;
final HashMap<String, Object> jsonMap = new HashMap<>();
writeValueToJson(jsonMap, PlatformConstants.TxStatsConnectionTypes.all, encodeStatsResourceCount(connectionTypes.all));
writeValueToJson(jsonMap, PlatformConstants.TxStatsConnectionTypes.plain, encodeStatsResourceCount(connectionTypes.plain));
writeValueToJson(jsonMap, PlatformConstants.TxStatsConnectionTypes.tls, encodeStatsResourceCount(connectionTypes.tls));
return jsonMap;
}

private Map<String, Object> encodeStatsResourceCount(Stats.ResourceCount resourceCount) {
if (resourceCount == null) return null;
final HashMap<String, Object> jsonMap = new HashMap<>();
writeValueToJson(jsonMap, PlatformConstants.TxStatsResourceCount.mean, resourceCount.mean);
writeValueToJson(jsonMap, PlatformConstants.TxStatsResourceCount.min, resourceCount.min);
writeValueToJson(jsonMap, PlatformConstants.TxStatsResourceCount.opened, resourceCount.opened);
writeValueToJson(jsonMap, PlatformConstants.TxStatsResourceCount.peak, resourceCount.peak);
writeValueToJson(jsonMap, PlatformConstants.TxStatsResourceCount.refused, resourceCount.refused);
return jsonMap;
}

private Map<String, Object> encodeStatsRequestCount(Stats.RequestCount apiRequests) {
if (apiRequests == null) return null;
final HashMap<String, Object> jsonMap = new HashMap<>();
writeValueToJson(jsonMap, PlatformConstants.TxStatsRequestCount.succeeded, apiRequests.succeeded);
writeValueToJson(jsonMap, PlatformConstants.TxStatsRequestCount.failed, apiRequests.failed);
writeValueToJson(jsonMap, PlatformConstants.TxStatsRequestCount.refused, apiRequests.refused);
return jsonMap;
}

private Map<String, Object> encodeStatsMessageTypes(Stats.MessageTypes messageTypes) {
if (messageTypes == null) return null;
final HashMap<String, Object> jsonMap = new HashMap<>();
writeValueToJson(jsonMap, PlatformConstants.TxStatsMessageTypes.all, encodeStatsMessageCategory(messageTypes.all));
writeValueToJson(jsonMap, PlatformConstants.TxStatsMessageTypes.messages, encodeStatsMessageCategory(messageTypes.messages));
writeValueToJson(jsonMap, PlatformConstants.TxStatsMessageTypes.presence, encodeStatsMessageCategory(messageTypes.presence));
return jsonMap;
}

// This is different in other platform and will correspond to StatsMessageCount for other
// libraries
private Map<String, Object> encodeStatsMessageCategory(Stats.MessageCategory category) {
if (category == null) return null;
final HashMap<String, Object> jsonMap = new HashMap<>();

writeValueToJson(jsonMap, PlatformConstants.TxStatsMessageCount.count, category.count);
writeValueToJson(jsonMap, PlatformConstants.TxStatsMessageCount.data, category.data);

return jsonMap;
}

@Override
protected Object readValueOfType(final byte type, final ByteBuffer buffer) {
CodecPair pair = codecMap.get(type);
Expand Down Expand Up @@ -199,6 +277,8 @@ private Byte getType(Object value) {
} else if (value instanceof ChannelOptions) {
// Encoding it into a RealtimeChannelOptions instance, because it extends RestChannelOptions
return PlatformConstants.CodecTypes.realtimeChannelOptions;
} else if (value instanceof Stats) {
return PlatformConstants.CodecTypes.stats;
}
return null;
}
Expand Down Expand Up @@ -303,9 +383,13 @@ private PlatformClientOptions decodeClientOptions(Map<String, Object> jsonMap) {
readValueFromJson(jsonMap, PlatformConstants.TxClientOptions.realtimeHost, v -> o.realtimeHost = (String) v);
readValueFromJson(jsonMap, PlatformConstants.TxClientOptions.port, v -> o.port = (Integer) v);
readValueFromJson(jsonMap, PlatformConstants.TxClientOptions.tlsPort, v -> o.tlsPort = (Integer) v);
o.autoConnect = false; // Always avoid auto-connect, to allow handle to be returned back to Dart side before authCallback is called.
// If the user specifies autoConnect, we call connect once we get the handle back to the dart side
// In other words, Ably Flutter internally manually connects, but to the SDK user this looks like autoConnect.
/* Always avoid auto-connect, to allow handle to be returned back to Dart side before
* authCallback is called.
* If the user specifies autoConnect, we call connect once we get the handle back to the dart side
* In other words, Ably Flutter internally manually connects, but to the SDK user this looks
* like autoConnect.
*/
o.autoConnect = false;
readValueFromJson(jsonMap, PlatformConstants.TxClientOptions.useBinaryProtocol, v -> o.useBinaryProtocol = (Boolean) v);
readValueFromJson(jsonMap, PlatformConstants.TxClientOptions.queueMessages, v -> o.queueMessages = (Boolean) v);
readValueFromJson(jsonMap, PlatformConstants.TxClientOptions.echoMessages, v -> o.echoMessages = (Boolean) v);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import io.ably.lib.realtime.Channel;
import io.ably.lib.realtime.CompletionListener;
import io.ably.lib.realtime.Presence;
import io.ably.lib.rest.AblyBase;
import io.ably.lib.rest.AblyRest;
import io.ably.lib.rest.Auth;
import io.ably.lib.transport.Defaults;
Expand Down Expand Up @@ -87,6 +88,9 @@ public AblyMethodCallHandler(final MethodChannel methodChannel,
_map.put(PlatformConstants.PlatformMethod.realtimePresenceUpdate, this::updateRealtimePresence);
_map.put(PlatformConstants.PlatformMethod.realtimePresenceLeave, this::leaveRealtimePresence);
_map.put(PlatformConstants.PlatformMethod.releaseRealtimeChannel, this::releaseRealtimeChannel);
_map.put(PlatformConstants.PlatformMethod.realtimeTime, this::realtimeTime);
_map.put(PlatformConstants.PlatformMethod.restTime, this::restTime);
_map.put(PlatformConstants.PlatformMethod.stats, this::stats);

// Push Notifications
_map.put(PlatformConstants.PlatformMethod.pushActivate, this::pushActivate);
Expand Down Expand Up @@ -304,6 +308,26 @@ private void getRestHistory(@NonNull MethodCall call, @NonNull MethodChannel.Res
});
}

private void stats(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
final AblyFlutterMessage message = (AblyFlutterMessage) call.arguments;
final AblyFlutterMessage<Map<String, Object>> paramsMessage =
(AblyFlutterMessage<Map<String, Object>>) message.message;
final Map<String, Object> map = paramsMessage.message;
final HashMap<String, Object> paramsMap =
(HashMap<String, Object>) map.get(PlatformConstants.TxTransportKeys.params);
Param[] params = new Param[paramsMap != null ? paramsMap.size() : 0];
if (paramsMap != null) {
int i = 0;
for (String paramKey : paramsMap.keySet()) {
final Param param = new Param(paramKey, paramsMap.get(paramKey));
params[i++] = param;
}
}
instanceStore
.getRest(paramsMessage.handle)
.statsAsync(params, this.paginatedResponseHandler(result, null));
}

private void getRestPresence(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
final AblyFlutterMessage message = (AblyFlutterMessage) call.arguments;
this.<AblyFlutterMessage<Map<String, Object>>>ablyDo(message, (ablyLibrary, messageData) -> {
Expand Down Expand Up @@ -600,7 +624,33 @@ private void releaseRealtimeChannel(@NonNull MethodCall call, @NonNull MethodCha
});
}

private void getRealtimeHistory(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
private void realtimeTime(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) {
final AblyFlutterMessage message = (AblyFlutterMessage) methodCall.arguments;
time(result, instanceStore.getRealtime((int) message.message));
}

private void restTime(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) {
final AblyFlutterMessage message = (AblyFlutterMessage) methodCall.arguments;
time(result, instanceStore.getRest((int) message.message));
}

private void time(@NonNull MethodChannel.Result result, AblyBase client) {
Callback<Long> callback = new Callback<Long>() {
@Override
public void onSuccess(Long timeResult) {
result.success(timeResult);
}

@Override
public void onError(ErrorInfo reason) {
result.error("40000", reason.message, reason);
}
};
client.timeAsync(callback);
}


private void getRealtimeHistory(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
final AblyFlutterMessage message = (AblyFlutterMessage) call.arguments;
this.<AblyFlutterMessage<Map<String, Object>>>ablyDo(message, (ablyLibrary, messageData) -> {
final Map<String, Object> map = messageData.message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,17 @@ static final public class CodecTypes {
public static final byte restPresenceParams = (byte) 142;
public static final byte presenceMessage = (byte) 143;
public static final byte realtimePresenceParams = (byte) 144;
public static final byte deviceDetails = (byte) 145;
public static final byte localDevice = (byte) 146;
public static final byte pushChannelSubscription = (byte) 147;
public static final byte unNotificationSettings = (byte) 148;
public static final byte remoteMessage = (byte) 149;
public static final byte errorInfo = (byte) 150;
public static final byte logLevel = (byte) 151;
public static final byte connectionStateChange = (byte) 152;
public static final byte channelStateChange = (byte) 153;
public static final byte cipherParams = (byte) 154;
public static final byte stats = (byte) 145;
public static final byte deviceDetails = (byte) 146;
public static final byte localDevice = (byte) 147;
public static final byte pushChannelSubscription = (byte) 148;
public static final byte unNotificationSettings = (byte) 149;
public static final byte remoteMessage = (byte) 150;
public static final byte errorInfo = (byte) 151;
public static final byte logLevel = (byte) 152;
public static final byte connectionStateChange = (byte) 153;
public static final byte channelStateChange = (byte) 154;
public static final byte cipherParams = (byte) 155;
}

static final public class PlatformMethod {
Expand Down Expand Up @@ -66,6 +67,9 @@ static final public class PlatformMethod {
public static final String publishRealtimeChannelMessage = "publishRealtimeChannelMessage";
public static final String releaseRealtimeChannel = "releaseRealtimeChannel";
public static final String realtimeHistory = "realtimeHistory";
public static final String realtimeTime = "realtimeTime";
public static final String restTime = "restTime";
public static final String stats = "stats";
public static final String pushActivate = "pushActivate";
public static final String pushDeactivate = "pushDeactivate";
public static final String pushSubscribeDevice = "pushSubscribeDevice";
Expand Down Expand Up @@ -444,4 +448,54 @@ static final public class TxCryptoGenerateRandomKey {
public static final String keyLength = "keyLength";
}

static final public class TxStats {
public static final String all = "all";
public static final String apiRequests = "apiRequests";
public static final String channels = "channels";
public static final String connections = "connections";
public static final String inbound = "inbound";
public static final String intervalId = "intervalId";
public static final String outbound = "outbound";
public static final String persisted = "persisted";
public static final String tokenRequests = "tokenRequests";
}

static final public class TxStatsMessageTypes {
public static final String all = "all";
public static final String messages = "messages";
public static final String presence = "presence";
}

static final public class TxStatsMessageCount {
public static final String count = "count";
public static final String data = "data";
}

static final public class TxStatsRequestCount {
public static final String failed = "failed";
public static final String refused = "refused";
public static final String succeeded = "succeeded";
}

static final public class TxStatsResourceCount {
public static final String mean = "mean";
public static final String min = "min";
public static final String opened = "opened";
public static final String peak = "peak";
public static final String refused = "refused";
}

static final public class TxStatsConnectionTypes {
public static final String all = "all";
public static final String plain = "plain";
public static final String tls = "tls";
}

static final public class TxStatsMessageTraffic {
public static final String all = "all";
public static final String realtime = "realtime";
public static final String rest = "rest";
public static final String webhook = "webhook";
}

}
42 changes: 42 additions & 0 deletions bin/codegen_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Iterable<Map<String, dynamic>> get _types sync* {
'restPresenceParams',
'presenceMessage',
'realtimePresenceParams',
'stats',

// Push Notifications
'deviceDetails',
Expand Down Expand Up @@ -94,6 +95,9 @@ const List<Map<String, dynamic>> _platformMethods = [
},
{'name': 'releaseRealtimeChannel', 'value': 'releaseRealtimeChannel'},
{'name': 'realtimeHistory', 'value': 'realtimeHistory'},
{'name': 'realtimeTime', 'value': 'realtimeTime'},
{'name': 'restTime', 'value': 'restTime'},
{'name': 'stats', 'value': 'stats'},

// Push Notifications
{'name': 'pushActivate', 'value': 'pushActivate'},
Expand Down Expand Up @@ -507,6 +511,44 @@ const List<Map<String, dynamic>> _objects = [
{
'name': 'CryptoGenerateRandomKey',
'properties': ['keyLength']
},
{
'name': 'Stats',
'properties': <String>[
'all',
'apiRequests',
'channels',
'connections',
'inbound',
'intervalId',
'outbound',
'persisted',
'tokenRequests'
]
},
{
'name': 'StatsMessageTypes',
'properties': <String>['all', 'messages', 'presence']
},
{
'name': 'StatsMessageCount',
'properties': <String>['count', 'data']
},
{
'name': 'StatsRequestCount',
'properties': <String>['failed', 'refused', 'succeeded']
},
{
'name': 'StatsResourceCount',
'properties': <String>['mean', 'min', 'opened', 'peak', 'refused']
},
{
'name': 'StatsConnectionTypes',
'properties': <String>['all', 'plain', 'tls']
},
{
'name': 'StatsMessageTraffic',
'properties': <String>['all', 'realtime', 'rest', 'webhook']
}
];

Expand Down
3 changes: 3 additions & 0 deletions example/lib/ui/realtime_sliver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,10 @@ class RealtimeSliver extends HookWidget {
final latestMessage = useState<ably.Message?>(null);
final channelSubscription =
useState<StreamSubscription<ably.Message>?>(null);
final realtimeTime = useState<DateTime?>(null);

useEffect(() {
realtime.time().then((value) => realtimeTime.value = value);
setupListeners(connectionState, channelState);
return dispose;
}, []);
Expand All @@ -166,6 +168,7 @@ class RealtimeSliver extends HookWidget {
'Realtime',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
Text('Realtime time: ${realtimeTime.value}'),
Text('Connection State: ${connectionState.value}'),
Row(
children: <Widget>[
Expand Down
Loading