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

Protocol 2.0 #842

Closed
wants to merge 70 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
bd1993d
Remove serial implementation from Connection and ConnectionManager
Sep 21, 2022
131fd6e
Remove connectionSerial implementation from ProtocolMessage and Conne…
Sep 21, 2022
7d21386
Set Ably API version from 1.2 to 2.0
Sep 22, 2022
49bfde9
Remove recovery key direct access and create getter as spec RTN16g
Sep 22, 2022
d347a2c
Implement channelSerial in onMessage and onPresence by spec RTL25
Sep 23, 2022
8ad9623
Implement channelSerial clearing on detached, suspended or failed by …
Sep 23, 2022
63d7f04
Remove lastPayloadProtocolMessageChannelSerial as it's implementation…
Sep 23, 2022
8d9d772
Implement reattaching channels by spec RTN15c6
Sep 26, 2022
46b2567
Fix reattaching channels by spec RTN15c6
Sep 26, 2022
e994379
Set channel state to attaching on reattach
Sep 26, 2022
3f102b9
Implement reattaching channels by spec RTN15c7
Sep 26, 2022
014fc38
Implement recover querystring to websocket by spec RTN16k
Sep 27, 2022
7ae2fe7
Implement client recovery by spec RTN16i, RTN16f and RTN16j
Sep 27, 2022
c6b2c64
Fix client recovery attachment by spec RTN16i
Sep 28, 2022
8a4e8e7
Remove unused imports
Oct 3, 2022
6d27773
Add spec comments for implemented features in channel recovery
Oct 3, 2022
761a572
Add spec comments for implemented features in ConnectionManager
Oct 3, 2022
52eee30
Fix duplicate request state on onConnected
Oct 4, 2022
c2d5fab
Add spec comments for getRecoveryKey
Oct 4, 2022
4773476
Fix recovery implementation by spec RTN16l
Oct 4, 2022
bdcc5e0
Fix recovery implementation by spec RTL15b
Oct 5, 2022
ed019ed
Update memberKey by spec RTP17h
Oct 5, 2022
7297b00
Update specification comment documentation
Oct 5, 2022
0e705a5
Add re-entry of presence members by spec RTP17g and RTP17f
Oct 6, 2022
271794b
Fix test missing deviceSecret by API protocol 2.0
Oct 7, 2022
f3d0dd7
Remove old implementation spec RTN15c3
Oct 10, 2022
1658a2f
Fix recovery option test to implement new spec
Oct 10, 2022
486ff01
Fix teardown after test class is finished on null objects
Oct 11, 2022
f62ebc7
Improve channels reattach test with closing Ably instance
Oct 11, 2022
bfd621d
Add device secret key required by protocol 2.0
Oct 12, 2022
429ff78
Fix deviceSecret missing in DeviceDetails per new API requirement
Oct 17, 2022
2dba619
Fix connection history test on reattach
Oct 17, 2022
fe8ed2c
Fix re-attaching channel with force reattach
Oct 18, 2022
ce44c37
Improve test for channel resuming
Oct 18, 2022
602a223
Fix re-auth history check state
Oct 19, 2022
73ced2d
Remove connectionSerial as it is not used any more
Oct 20, 2022
4221b80
Remove unnecessary connected check and add doc comment in onConnected…
Oct 21, 2022
0287b17
Fix spec RTP17f to not reEnter if old state was already attached
Oct 21, 2022
9376960
Refactor sending pending messages when client is connected per spec R…
Oct 21, 2022
201f388
Refactor sending pending messages when client is connected and remove…
Oct 21, 2022
86625b8
Refactor presence map manipulation by spec RTP17h
Oct 21, 2022
fc543d0
Ignore bulk publish tests as they are not supported in protocol 2.0
Oct 21, 2022
b4eaadd
Remove public modifier from PresenceMap
Oct 21, 2022
e91d770
Improve re-enter by spec RTP17f
Oct 25, 2022
a6eeb00
Improve reattach of the channels on every connected message
Oct 25, 2022
4591971
Improve re-enter on attached message by spec RTP17f
Oct 25, 2022
5fae005
Fix removing sending pending messages by spec RTN19a
Oct 25, 2022
d1e262d
Fix test for attached channel
Oct 25, 2022
4dd11ee
Fix test for presence enter
Oct 26, 2022
52e06b3
Add spec RTL5k to fix channel attaching on detaching or detached state
Oct 27, 2022
90dd275
Rename getRecoveryKey->createRecoveryKey per updated spec
SimonWoolf Oct 31, 2022
a6fd26d
Add spec RTL5k to fix channel attaching on detaching or detached state
Nov 1, 2022
1b5781a
Merge remote-tracking branch 'origin/integration/protocol-2.0' into i…
Nov 1, 2022
0fa91f7
Refactor internal map by spec RTP17h
Nov 1, 2022
52884b5
Rename getRecoveryKey->createRecoveryKey per updated spec
SimonWoolf Oct 31, 2022
28f438a
Rename entry of map and serials iterator
Nov 2, 2022
dc5ed8c
Merge remote-tracking branch 'origin/integration/protocol-2.0' into i…
Nov 4, 2022
18415fc
Add encapsulation for ConnectionRecoveryKey
Nov 4, 2022
ee0dcd7
Remove unused import
Nov 4, 2022
5b99907
Add error logs instead of printing stack trace
Nov 4, 2022
d022c3d
Emit update on re-attach error
Nov 7, 2022
d7ed41a
Add error info to test fail log
Nov 7, 2022
f0e09fb
Remove old implementation of re-enter
Nov 7, 2022
865bca8
Emit update on send pending message error
Nov 7, 2022
e079abb
Update core/src/main/java/io/ably/lib/realtime/ConnectionRecoveryKey.…
qsdigor Nov 8, 2022
bd5a540
Update core/src/main/java/io/ably/lib/transport/ConnectionManager.java
qsdigor Nov 8, 2022
437bb08
Fix wrong method name in ConnectionRecoveryKey
Nov 8, 2022
28531da
Fix spec RTP17g
Nov 11, 2022
7752068
Merge branch 'integration/version-2' into integration/protocol-2.0
Nov 14, 2022
49f8d6a
Add missing javadoc
Nov 14, 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
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
import io.ably.lib.types.ClientOptions;
import io.ably.lib.types.ErrorInfo;
import io.ably.lib.types.Param;
import io.ably.lib.types.RegistrationToken;
import io.ably.lib.util.Base64Coder;
import io.ably.lib.util.IntentUtils;
import io.ably.lib.util.JsonUtils;
Expand Down Expand Up @@ -1372,11 +1371,12 @@ public void run() throws Exception {
}

testActivation.registerAndWait();
DeviceDetails otherDevice = DeviceDetails.fromJsonObject(JsonUtils.object()
LocalDevice otherDevice = LocalDevice.fromJsonObject(JsonUtils.object()
.add("id", "other")
.add("platform", "android")
.add("formFactor", "tablet")
.add("metadata", JsonUtils.object())
.add("deviceSecret", "testdevicesecret==") //Required by API protocol 2.0
.add("push", JsonUtils.object()
.add("recipient", JsonUtils.object()
.add("transportType", "fcm")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import io.ably.lib.types.Callback;
import io.ably.lib.types.ErrorInfo;
import io.ably.lib.types.Param;
import io.ably.lib.types.RegistrationToken;
import io.ably.lib.util.IntentUtils;
import io.ably.lib.util.Log;
import io.ably.lib.util.ParamsUtils;
Expand Down
15 changes: 6 additions & 9 deletions android/src/main/java/io/ably/lib/push/LocalDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@
import io.ably.lib.types.RegistrationToken;
import io.ably.lib.util.Base64Coder;
import io.ably.lib.util.Log;
import io.ably.lib.util.Serialisation;

public class LocalDevice extends DeviceDetails {
/**
* A unique device secret generated by the Ably SDK.
*/
public String deviceSecret;

/**
* A unique device identity token used to communicate with APNS or FCM.
*/
Expand All @@ -42,12 +40,11 @@ public LocalDevice(ActivationContext activationContext, Storage storage) {
}

public JsonObject toJsonObject() {
JsonObject o = super.toJsonObject();
if (deviceSecret != null) {
o.addProperty("deviceSecret", deviceSecret);
}
return super.toJsonObject();
}

return o;
public static LocalDevice fromJsonObject(JsonObject o) {
return Serialisation.gson.fromJson(o, LocalDevice.class);
}

private void loadPersisted() {
Expand Down
42 changes: 41 additions & 1 deletion core/src/main/java/io/ably/lib/realtime/AblyRealtimeBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public AblyRealtimeBase(String key, PlatformAgentProvider platformAgentProvider)
* @param platformAgentProvider for providing the platform specific part of the agent header
* @throws AblyException
*/
public AblyRealtimeBase(ClientOptions options, PlatformAgentProvider platformAgentProvider) throws AblyException {
public AblyRealtimeBase(final ClientOptions options, PlatformAgentProvider platformAgentProvider) throws AblyException {
super(options, platformAgentProvider);
final InternalChannels channels = new InternalChannels();
this.channels = (Channels<ChannelType>) channels;
Expand All @@ -79,6 +79,31 @@ public void onConnectionStateChanged(ConnectionStateListener.ConnectionStateChan
}
});

if (options.recover != null) {
ConnectionRecoveryKey recoveryKey = ConnectionRecoveryKey.fromJson(options.recover);
if (recoveryKey == null) {
Log.d(TAG, "Recovery key initialization failed!");
connection.connectionManager.msgSerial = 0; //RTN16f
} else {
connection.connectionManager.msgSerial = recoveryKey.getMsgSerial(); //RTN16f

for (Map.Entry<String, String> serial : recoveryKey.getSerials().entrySet()) {
//RTN16j
RealtimeChannelBase channel = channels.get(serial.getKey());
if (channel != null) {
channel.properties.channelSerial = serial.getValue(); //RTN16i
}
}
}

connection.on(ConnectionEvent.connected, new ConnectionStateListener() {
@Override
public void onConnectionStateChanged(ConnectionStateChange state) {
options.recover = null; //RTN16k
}
});
}

if(options.autoConnect) connection.connect();
}

Expand Down Expand Up @@ -232,6 +257,21 @@ public void suspendAll(ErrorInfo error, boolean notifyStateChange) {
}
}

/**
* By spec RTN15c6, RTN15c7
*/
@Override
public void reAttach() {
for (Map.Entry<String, RealtimeChannelBase> channelEntry : map.entrySet()) {
RealtimeChannelBase channel = channelEntry.getValue();
if (channel.state == ChannelState.attaching || channel.state == ChannelState.attached || channel.state == ChannelState.suspended) {
Log.d(TAG, "reAttach(); channel = " + channel.name);
channel.state = ChannelState.attaching;
channel.attach(true, null);
}
}
}

private void clear() {
map.clear();
}
Expand Down
42 changes: 30 additions & 12 deletions core/src/main/java/io/ably/lib/realtime/Connection.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,6 @@ public class Connection extends EventEmitter<ConnectionEvent, ConnectionStateLis
*/
public String id;

/**
* The serial number of the last message to be received on this connection,
* used automatically by the library when recovering or resuming a connection.
* When recovering a connection explicitly, the recoveryKey is used in the recover
* client options as it contains both the key and the last message serial.
* <p>
* Spec: RTN10
*/
public long serial;

/**
* Explicitly calling connect() is unnecessary unless the autoConnect attribute of the {@link io.ably.lib.types.ClientOptions}
* object is false.
Expand Down Expand Up @@ -101,7 +91,6 @@ public void ping(CompletionListener listener) {
*/
public void close() {
key = null;
recoveryKey = null;
connectionManager.close();
}

Expand All @@ -124,7 +113,7 @@ public void onConnectionStateChange(ConnectionStateChange stateChange) {
@Override
protected void apply(ConnectionStateListener listener, ConnectionEvent event, Object... args) {
try {
listener.onConnectionStateChanged((ConnectionStateChange)args[0]);
listener.onConnectionStateChanged((ConnectionStateChange) args[0]);
} catch (Throwable t) {
Log.e(TAG, "Unexpected exception calling ConnectionStateListener", t);
}
Expand All @@ -135,6 +124,35 @@ public void emitUpdate(ErrorInfo errorInfo) {
emit(ConnectionEvent.update, ConnectionStateListener.ConnectionStateChange.createUpdateEvent(errorInfo));
}

/**
* Spec: RTN16g
*
* @return a json string which incorporates the @connectionKey@, the current @msgSerial@,
* and a collection of pairs of channel @name@ and current @channelSerial@ for every currently attached channel.
*/
public String createRecoveryKey() {
if (key == null || connectionManager == null || connectionManager.getConnectionState() == null ||
connectionManager.getConnectionState().state == ConnectionState.closed ||
connectionManager.getConnectionState().state == ConnectionState.closing ||
connectionManager.getConnectionState().state == ConnectionState.failed ||
connectionManager.getConnectionState().state == ConnectionState.suspended
) {
//RTN16h
return null;
}

ConnectionRecoveryKey recoveryKey = new ConnectionRecoveryKey(key, connectionManager.msgSerial);

for (Object channel : ably.channels.values()) {
if (channel instanceof RealtimeChannelBase) {
RealtimeChannelBase rcb = (RealtimeChannelBase) channel;
recoveryKey.addSerial(rcb.name, rcb.properties.channelSerial);
}
}

return recoveryKey.asJson();
}

@Deprecated
public void emit(ConnectionState state, ConnectionStateChange stateChange) {
super.emit(state.getConnectionEvent(), stateChange);
Expand Down
62 changes: 62 additions & 0 deletions core/src/main/java/io/ably/lib/realtime/ConnectionRecoveryKey.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.ably.lib.realtime;

import com.google.gson.JsonSyntaxException;

import java.util.HashMap;
import java.util.Map;

import io.ably.lib.util.Log;
import io.ably.lib.util.Serialisation;

public class ConnectionRecoveryKey {
private static final String TAG = "RecoveryKey";

private final String connectionKey;
private final long msgSerial;
/**
* Key - channel name
* <p>
* Value - channelSerial
*/
private final Map<String, String> serials = new HashMap<>();

public ConnectionRecoveryKey(String connectionKey, long msgSerial) {
this.connectionKey = connectionKey;
this.msgSerial = msgSerial;
}

public String getConnectionKey() {
return connectionKey;
}

public long getMsgSerial() {
return msgSerial;
}

public Map<String, String> getSerials() {
return serials;
}

public void setSerials(Map<String, String> serials) {
this.serials.clear();
this.serials.putAll(serials);
}

public void addSerial(String channelName, String channelSerial) {
this.serials.put(channelName, channelSerial);
}

public String asJson() {
return Serialisation.gson.toJson(this);
}

public static ConnectionRecoveryKey fromJson(String json) {
try {
return Serialisation.gson.fromJson(json, ConnectionRecoveryKey.class);
} catch (JsonSyntaxException e) {
Log.e(TAG, "Cannot create recovery key from json: " + e.getMessage());
return null;
}
}

}
Loading