You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
** @(RTO4b)@ If the @HAS_OBJECTS@ flag is 0 or there is no @flags@ field, the sync sequence must be considered complete immediately, and the client library must perform the following actions in order:
36
36
*** @(RTO4b1)@ All objects except the one with id @root@ must be removed from the internal @ObjectsPool@
37
37
*** @(RTO4b2)@ The data for the @LiveMap@ with id @root@ must be cleared by setting it to a zero-value per "RTLM4":#RTLM4
38
-
*** @(RTO4b3)@ The @SyncObjectsPool@ must be cleared
38
+
*** @(RTO4b3)@ The @SyncObjectsPool@ list must be cleared
39
+
*** @(RTO4b5)@ The @BufferedObjectOperations@ list must be cleared
39
40
*** @(RTO4b4)@ Perform the actions for objects sync completion as described in "RTO5c":#RTO5c
40
41
* @(RTO5)@ The realtime system reserves the right to initiate an objects sync of the objects on a channel at any point once a channel is attached. A server initiated objects sync provides Ably with a means to send a complete list of objects present on the channel at any point
41
42
** @(RTO5a)@ When an @OBJECT_SYNC@ @ProtocolMessage@ is received with a @channel@ attribute matching the channel name, the client library must parse the @channelSerial@ attribute:
42
43
*** @(RTO5a1)@ The @channelSerial@ is used as the sync cursor and is a two-part identifier: @<sequence id>:<cursor value>@
43
44
*** @(RTO5a2)@ If a new sequence id is sent from Ably, the client library must treat it as the start of a new objects sync sequence, and any previous in-flight sync must be discarded:
44
-
**** @(RTO5a2a)@ The current @SyncObjectsPool@ list must be cleared
45
+
**** @(RTO5a2a)@ The @SyncObjectsPool@ list must be cleared
46
+
**** @(RTO5a2b)@ The @BufferedObjectOperations@ list must be cleared
45
47
*** @(RTO5a3)@ If the sequence id matches the previously received sequence id, the client library should continue the sync process
46
48
*** @(RTO5a4)@ The objects sync sequence for that sequence identifier is considered complete once the cursor is empty; that is when the @channelSerial@ looks like @<sequence id>:@
47
49
*** @(RTO5a5)@ An @OBJECT_SYNC@ may also be sent with no @channelSerial@ attribute. In this case, the sync data is entirely contained within the @ProtocolMessage@
48
-
** @(RTO5b)@ During the sync sequence, the @ObjectMessage.object@ values from incoming @OBJECT_SYNC@ @ProtocolMessage@s must be temporarily stored in the internal @SyncObjectsPool@ list
50
+
** @(RTO5b)@ During the sync sequence, the @ObjectMessage.object@ values from incoming @OBJECT_SYNC@ @ProtocolMessages@ must be temporarily stored in the internal @SyncObjectsPool@ list
49
51
** @(RTO5c)@ When the objects sync has completed, the client library must perform the following actions in order:
50
52
*** @(RTO5c1)@ For each @ObjectState@ member in the @SyncObjectsPool@ list:
51
53
**** @(RTO5c1a)@ If an object with @ObjectState.objectId@ exists in the internal @ObjectsPool@:
****** @(RTO5c1b1c)@ Otherwise, log a warning that an unsupported object state message has been received, and discard the current @ObjectState@ without taking any action
58
60
*** @(RTO5c2)@ Remove any objects from the internal @ObjectsPool@ for which @objectId@s were not received during the sync sequence
59
61
**** @(RTO5c2a)@ The object with ID @root@ must not be removed from @ObjectsPool@, as per "RTO3b":#RTO3b
62
+
*** @(RTO5c6)@ @ObjectMessages@ stored in the @BufferedObjectOperations@ list are applied as described in "RTO9":#RTO9
60
63
*** @(RTO5c3)@ Clear any stored sync sequence identifiers and cursor values
61
64
*** @(RTO5c4)@ The @SyncObjectsPool@ must be cleared
65
+
*** @(RTO5c5)@ The @BufferedObjectOperations@ list must be cleared
62
66
* @(RTO6)@ When needed, a zero-value object can be created if it does not exist in the internal @ObjectsPool@ for an @objectId@, in the following way:
63
67
** @(RTO6a)@ If an object with @objectId@ exists in @ObjectsPool@, do not create a new object
64
68
** @(RTO6b)@ The expected type of the object can be inferred from the provided @objectId@:
65
69
*** @(RTO6b1)@ Split the @objectId@ (formatted as @type:hash@timestamp@) on the separator @:@ and parse the first part as the type string
66
70
*** @(RTO6b2)@ If the parsed type is @map@, create a zero-value @LiveMap@ per "RTLM4":#RTLM4 in the @ObjectsPool@
67
71
*** @(RTO6b3)@ If the parsed type is @counter@, create a zero-value @LiveCounter@ per "RTLC4":#RTLC4 in the @ObjectsPool@
72
+
* @(RTO7)@ The client library may receive @OBJECT@ @ProtocolMessages@ in realtime over the channel concurrently with @OBJECT_SYNC@ @ProtocolMessages@ during the object sync sequence ("RTO5":#RTO5). Some of the incoming @OBJECT@ messages may have already been applied to the objects described in the sync sequence, while others may not. Therefore, the client must buffer @OBJECT@ messages during the sync sequence so that it can determine which of them should be applied to the objects once the sync is complete. See "RTO8":#RTO8
73
+
** @(RTO7a)@ An internal @BufferedObjectOperations@ should be used to store the buffered @ObjectMessages@, as described in "RTO8a":#RTO8a. @BufferedObjectOperations@ is an array of @ObjectMessage@ instances
74
+
*** @(RTO7a1)@ This array is empty upon @RealtimeObjects@ initialization
75
+
* @(RTO8)@ When the library receives a @ProtocolMessage@ with an action of @OBJECT@, each member of the @ProtocolMessage.state@ array (decoded into @ObjectMessage@ objects) is passed to the @RealtimeObjects@ instance per "RTL1":../features#RTL1. Each @ObjectMessage@ from @OBJECT@ @ProtocolMessage@ (also referred to as an @OBJECT@ message) describes an operation to be applied to an object on a channel and must be handled as follows:
76
+
** @(RTO8a)@ If an object sync sequence is currently in progress, add the @ObjectMessages@ to the internal @BufferedObjectOperations@ array
77
+
** @(RTO8b)@ Otherwise, apply the @ObjectMessages@ as described in "RTO9":#RTO9
78
+
* @(RTO9)@ @OBJECT@ messages can be applied to @RealtimeObjects@ in the following way:
79
+
** @(RTO9a)@ For each @ObjectMessage@ in the provided list:
80
+
*** @(RTO9a1)@ If @ObjectMessage.operation@ is null or omitted, log a warning indicating that an unsupported object operation message has been received, and discard the current @ObjectMessage@ without taking any action
81
+
*** @(RTO9a2)@ The @ObjectMessage.operation.action@ field (see "@ObjectOperationAction@":../features#OOP2) determines the type of operation to apply:
82
+
**** @(RTO9a2a)@ If @ObjectMessage.operation.action@ is one of the following: @MAP_CREATE@, @MAP_SET@, @MAP_REMOVE@, @COUNTER_CREATE@, @COUNTER_INC@, or @OBJECT_DELETE@, then:
83
+
***** @(RTO9a2a1)@ If it does not already exist, create a zero-value @LiveObject@ in the internal @ObjectsPool@ per "RTO6":#RTO6 using the @objectId@ from @ObjectMessage.operation.objectId@
84
+
***** @(RTO9a2a2)@ Get the @LiveObject@ instance from the internal @ObjectsPool@ using the @objectId@ from @ObjectMessage.operation.objectId@
85
+
***** @(RTO9a2a3)@ Apply the @ObjectMessage.operation@ to the @LiveObject@; see "RTLC7":#RTLC7, "RTLM15":#RTLM15
86
+
**** @(RTO9a2b)@ Otherwise, log a warning that an object operation message with an unsupported action has been received, and discard the current @ObjectMessage@ without taking any action
87
+
88
+
h3(#livecounter). LiveObject
89
+
90
+
* @(RTLO1)@ The @LiveObject@ represents the common interface and includes shared functionality for concrete object types
91
+
* @(RTLO2)@ The client library may choose to implement @LiveObject@ as an abstract class
92
+
* @(RTLO3)@ @LiveObject@ properties:
93
+
** @(RTLO3a)@ protected @objectId@ string - an Object ID for this object
94
+
*** @(RTLO3a1)@ Must be provided and set in the constructor
95
+
** @(RTLO3b)@ protected @siteTimeserials@ @Dict<String, String>@ - a map of "serials":../features#OM2h keyed by "siteCode":../features#OM2i, representing the last operations applied to this object
96
+
*** @(RTLO3b1)@ Set to an empty map when the @LiveObject@ is initialized, so that any future operation can be applied to this object
97
+
** @(RTLO3c)@ protected @createOperationIsMerged@ boolean - a flag indicating whether the corresponding @MAP_CREATE@ or @COUNTER_CREATE@ operation has been applied to this @LiveObject@ instance
98
+
*** @(RTLO3c1)@ Set to @false@ when the @LiveObject@ is initialized
99
+
* @(RTLO4)@ @LiveObject@ methods:
100
+
** @(RTLO4a)@ A convenience method @canApplyOperation@ - used to determine whether the @ObjectMessage.operation@ should be applied to this object based on a serial value:
101
+
*** @(RTLO4a1)@ Expects the following arguments:
102
+
**** @(RTLO4a1a)@ @ObjectMessage@
103
+
*** @(RTLO4a2)@ Returns a boolean indicating whether the operation should be applied to this object
104
+
*** @(RTLO4a3)@ Both @ObjectMessage.serial@ and @ObjectMessage.siteCode@ must be non-empty strings. Otherwise, log a warning that the object operation message has invalid serial values. The client library must not apply this operation to the object
105
+
*** @(RTLO4a4)@ Get the @siteSerial@ value stored for this @LiveObject@ in the @siteTimeserials@ map using the key @ObjectMessage.siteCode@
106
+
*** @(RTLO4a5)@ If the @siteSerial@ for this @LiveObject@ is null or an empty string, return true
107
+
*** @(RTLO4a6)@ If the @siteSerial@ for this @LiveObject@ is not an empty string, return true if @ObjectMessage.serial@ is greater than @siteSerial@ when compared lexicographically
68
108
69
109
h3(#livecounter). LiveCounter
70
110
@@ -80,9 +120,29 @@ h3(#livecounter). LiveCounter
80
120
** @(RTLC6a)@ Replace the private @siteTimeserials@ of the @LiveCounter@ with the value from @ObjectState.siteTimeserials@
81
121
** @(RTLC6b)@ Set the private flag @createOperationIsMerged@ to @false@
82
122
** @(RTLC6c)@ Set @data@ to the value of @ObjectState.counter.count@, or to 0 if it does not exist
83
-
** @(RTLC6d)@ If @ObjectState.createOp@ is present:
84
-
*** @(RTLC6d1)@ Add @ObjectState.createOp.counter.count@ to @data@, if it exists
85
-
*** @(RTLC6d2)@ Set the private flag @createOperationIsMerged@ to @true@
123
+
** @(RTLC6d)@ If @ObjectState.createOp@ is present, merge the initial value into the @LiveCounter@ as described in "RTLC10":#RTLC10, passing in the @ObjectState.createOp@ instance
124
+
*** @(RTLC6d1)@ This clause has been replaced by "RTLC10a":#RTLC10a
125
+
*** @(RTLC6d2)@ This clause has been replaced by "RTLC10b":#RTLC10b
126
+
* @(RTLC7)@ An @ObjectOperation@ from @ObjectMessage.operation@ can be applied to a @LiveCounter@ in the following way:
127
+
** @(RTLC7a)@ A client library may choose to implement this logic as a convenience method named @applyOperation@, which accepts an @ObjectMessage@ instance with an existing @ObjectMessage.operation@ object, with @ObjectMessage.operation.objectId@ matching the Object ID of this @LiveCounter@. This @ObjectMessage@ represents the operation to be applied to this @LiveCounter@
128
+
** @(RTLC7b)@ If @ObjectMessage.operation@ cannot be applied based on the result of "@LiveObject.canApplyOperation@":#RTLO4a, log a debug or trace message indicating that the operation cannot be applied because its serial value is not newer than the object's, and discard the @ObjectMessage@ without taking any action
129
+
** @(RTLC7c)@ Set the entry in the private @siteTimeserials@ map at the key @ObjectMessage.siteCode@ to equal @ObjectMessage.serial@
130
+
** @(RTLC7d)@ The @ObjectMessage.operation.action@ field (see "@ObjectOperationAction@":../features#OOP2) determines the type of operation to apply:
131
+
*** @(RTLC7d1)@ If @ObjectMessage.operation.action@ is set to @COUNTER_CREATE@, apply the operation as described in "RTLC8":#RTLC8, passing in @ObjectMessage.operation@
132
+
*** @(RTLC7d2)@ If @ObjectMessage.operation.action@ is set to @COUNTER_INC@, apply the operation as described in "RTLC9":#RTLC9, passing in @ObjectMessage.operation.counterOp@
133
+
*** @(RTLC7d3)@ Otherwise, log a warning that an object operation message with an unsupported action has been received, and discard the current @ObjectMessage@ without taking any action
134
+
* @(RTLC8)@ A @COUNTER_CREATE@ operation can be applied to a @LiveCounter@ in the following way:
135
+
** @(RTLC8a)@ Expects the following arguments:
136
+
*** @(RTLC8a1)@ @ObjectOperation@
137
+
** @(RTLC8b)@ If the private flag @createOperationIsMerged@ is @true@, log a debug or trace message indicating that the operation will not be applied because a @COUNTER_CREATE@ operation has already been applied to this @LiveCounter@, and discard the operation without taking any action
138
+
** @(RTLC8c)@ Merge the initial value into the @LiveCounter@ as described in "RTLC10":#RTLC10, passing in the @ObjectOperation@ instance
139
+
* @(RTLC9)@ A @COUNTER_INC@ operation can be applied to a @LiveCounter@ in the following way:
140
+
** @(RTLC9a)@ Expects the following arguments:
141
+
*** @(RTLC9a1)@ @ObjectsCounterOp@
142
+
** @(RTLC9b)@ Add @ObjectsCounterOp.amount@ to @data@, if it exists
143
+
* @(RTLC10)@ The initial value from @ObjectOperation.counter@ can be merged into this @LiveCounter@ in the following way:
144
+
** @(RTLC10a)@ Add @ObjectOperation.counter.count@ to @data@, if it exists
145
+
** @(RTLC10b)@ Set the private flag @createOperationIsMerged@ to @true@
86
146
87
147
h3(#livemap). LiveMap
88
148
@@ -131,12 +191,30 @@ h3(#livemap). LiveMap
131
191
** @(RTLM6a)@ Replace the private @siteTimeserials@ of the @LiveMap@ with the value from @ObjectState.siteTimeserials@
132
192
** @(RTLM6b)@ Set the private flag @createOperationIsMerged@ to @false@
133
193
** @(RTLM6c)@ Set @data@ to @ObjectState.map.entries@, or to an empty map if it does not exist
134
-
** @(RTLM6d)@ If @ObjectState.createOp@ is present:
135
-
*** @(RTLM6d1)@ For each key–@ObjectsMapEntry@ pair in @ObjectState.createOp.map.entries@:
136
-
**** @(RTLM6d1a)@ If @ObjectsMapEntry.tombstone@ is @false@, apply the @MAP_SET@ operation to the specified key using @ObjectsMapEntry.timeserial@ and @ObjectsMapEntry.data@ per "RTLM7":#RTLM7
137
-
**** @(RTLM6d1b)@ If @ObjectsMapEntry.tombstone@ is @true@, apply the @MAP_REMOVE@ operation to the specified key using @ObjectsMapEntry.timeserial@ per "RTLM8":#RTLM8
138
-
*** @(RTLM6d2)@ Set the private flag @createOperationIsMerged@ to @true@
139
-
* @(RTLM7)@ @MAP_SET@ operation for a key can be applied to a @LiveMap@ in the following way:
194
+
** @(RTLM6d)@ If @ObjectState.createOp@ is present, merge the initial value into the @LiveMap@ as described in "RTLM17":#RTLM17, passing in the @ObjectState.createOp@ instance
195
+
*** @(RTLM6d1)@ This clause has been replaced by "RTLM17a":#RTLM17a
196
+
**** @(RTLM6d1a)@ This clause has been replaced by "RTLM17a1":#RTLM17a1
197
+
**** @(RTLM6d1b)@ This clause has been replaced by "RTLM17a2":#RTLM17a2
198
+
*** @(RTLM6d2)@ This clause has been replaced by "RTLM17b":#RTLM17b
199
+
* @(RTLM15)@ An @ObjectOperation@ from @ObjectMessage.operation@ can be applied to a @LiveMap@ in the following way:
200
+
** @(RTLM15a)@ A client library may choose to implement this logic as a convenience method named @applyOperation@, which accepts an @ObjectMessage@ instance with an existing @ObjectMessage.operation@ object, with @ObjectMessage.operation.objectId@ matching the Object ID of this @LiveMap@. This @ObjectMessage@ represents the operation to be applied to this @LiveMap@
201
+
** @(RTLM15b)@ If @ObjectMessage.operation@ cannot be applied based on the result of "@LiveObject.canApplyOperation@":#RTLO4a, log a debug or trace message indicating that the operation cannot be applied because its serial value is not newer than the object's, and discard the @ObjectMessage@ without taking any action
202
+
** @(RTLM15c)@ Set the entry in the private @siteTimeserials@ map at the key @ObjectMessage.siteCode@ to equal @ObjectMessage.serial@
203
+
** @(RTLM15d)@ The @ObjectMessage.operation.action@ field (see "@ObjectOperationAction@":../features#OOP2) determines the type of operation to apply:
204
+
*** @(RTLM15d1)@ If @ObjectMessage.operation.action@ is set to @MAP_CREATE@, apply the operation as described in "RTLM16":#RTLM16, passing in @ObjectMessage.operation@
205
+
*** @(RTLM15d2)@ If @ObjectMessage.operation.action@ is set to @MAP_SET@, apply the operation as described in "RTLM7":#RTLM7, passing in @ObjectMessage.operation.mapOp@ and @ObjectMessage.serial@
206
+
*** @(RTLM15d3)@ If @ObjectMessage.operation.action@ is set to @MAP_REMOVE@, apply the operation as described in "RTLM8":#RTLM8, passing in @ObjectMessage.operation.mapOp@ and @ObjectMessage.serial@
207
+
*** @(RTLM15d4)@ Otherwise, log a warning that an object operation message with an unsupported action has been received, and discard the current @ObjectMessage@ without taking any action
208
+
* @(RTLM16)@ A @MAP_CREATE@ operation can be applied to a @LiveMap@ in the following way:
209
+
** @(RTLM16a)@ Expects the following argument:
210
+
*** @(RTLM16a1)@ @ObjectOperation@
211
+
** @(RTLM16b)@ If the private flag @createOperationIsMerged@ is @true@, log a debug or trace message indicating that the operation will not be applied because a @MAP_CREATE@ operation has already been applied to this @LiveMap@, and discard the operation without taking any action
212
+
** @(RTLM16c)@ If the private @semantics@ field does not match @ObjectOperation.map.semantics@, log a warning that the operation cannot be applied due to mismatched semantics, and discard the operation without taking any action
213
+
** @(RTLM16d)@ Merge the initial value into the @LiveMap@ as described in "RTLM17":#RTLM17, passing in the @ObjectOperation@ instance
214
+
* @(RTLM7)@ A @MAP_SET@ operation for a key can be applied to a @LiveMap@ in the following way:
215
+
** @(RTLM7d)@ Expects the following arguments:
216
+
*** @(RTLM7d1)@ @ObjectsMapOp@
217
+
*** @(RTLM7d2)@ @serial@ string - operation's serial value
140
218
** @(RTLM7a)@ If an entry exists in the private @data@ for the specified key:
141
219
*** @(RTLM7a1)@ If the operation cannot be applied as per "RTLM9":#RTLM9, discard the operation without taking any action
142
220
*** @(RTLM7a2)@ Otherwise, apply the operation:
@@ -149,6 +227,9 @@ h3(#livemap). LiveMap
149
227
** @(RTLM7c)@ If the operation has a non-empty @ObjectData.objectId@ attribute:
150
228
*** @(RTLM7c1)@ Create a zero-value @LiveObject@ in the internal @ObjectsPool@ per "RTO6":#RTO6
151
229
* @(RTLM8)@ @MAP_REMOVE@ operation for a key can be applied to a @LiveMap@ in the following way:
230
+
** @(RTLM8c)@ Expects the following arguments:
231
+
*** @(RTLM8c1)@ @ObjectsMapOp@
232
+
*** @(RTLM8c2)@ @serial@ string - operation's serial value
152
233
** @(RTLM8a)@ If an entry exists in the private @data@ for the specified key:
153
234
*** @(RTLM8a1)@ If the operation cannot be applied as per "RTLM9":#RTLM9, discard the operation without taking any action
154
235
*** @(RTLM8a2)@ Otherwise, apply the operation:
@@ -164,3 +245,8 @@ h3(#livemap). LiveMap
164
245
** @(RTLM9c)@ If only the entry serial exists, the missing operation serial is considered lower than the existing entry serial, so the operation must not be applied
165
246
** @(RTLM9d)@ If only the operation serial exists, it is considered greater than the missing entry serial, so the operation can be applied
166
247
** @(RTLM9e)@ If both serials exist, compare them lexicographically and allow operation to be applied only if the operation's serial is greater than the entry's serial
248
+
* @(RTLM17)@ The initial value from @ObjectOperation.map@ can be merged into this @LiveMap@ in the following way:
249
+
** @(RTLM17a)@ For each key–@ObjectsMapEntry@ pair in @ObjectOperation.map.entries@:
250
+
*** @(RTLM17a1)@ If @ObjectsMapEntry.tombstone@ is @false@, apply the @MAP_SET@ operation as described in "RTLM7":#RTLM7, passing in @ObjectsMapEntry.data@ and the current key as @ObjectsMapOp@, and @ObjectsMapEntry.timeserial@ as the operation's serial
251
+
*** @(RTLM17a2)@ If @ObjectsMapEntry.tombstone@ is @true@, apply the @MAP_REMOVE@ operation as described in "RTLM8":#RTLM8, passing in the current key as @ObjectsMapOp@, and @ObjectsMapEntry.timeserial@ as the operation's serial
252
+
** @(RTLM17b)@ Set the private flag @createOperationIsMerged@ to @true@
0 commit comments