Skip to content

Commit bfcf05b

Browse files
committed
Improve phrasing and clarify a couple of spec points
1 parent fc46aed commit bfcf05b

1 file changed

Lines changed: 29 additions & 24 deletions

File tree

textile/objects-features.textile

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,25 @@ h3(#realtime-objects). RealtimeObjects
1717

1818
* @(RTO1)@ @Objects#getRoot@ function:
1919
** @(RTO1a)@ Requires the @OBJECT_SUBSCRIBE@ channel mode to be granted per "RTO2":#RTO2
20-
** @(RTO1b)@ If the channel is in the @DETACHED@ or @FAILED@ state, the library should indicate an error with code 90001
20+
** @(RTO1b)@ If the channel is in the @DETACHED@ or @FAILED@ state, the library should throw an @ErrorInfo@ error with @statusCode@ 400 and @code@ 90001
2121
** @(RTO1c)@ Waits for the objects sync sequence to complete and for "RTO5c":#RTO5c to finish
2222
** @(RTO1d)@ Returns the object with id @root@ from the internal @ObjectsPool@ as a @LiveMap@
2323
* @(RTO2)@ Various object operations may require a specific channel mode to be set on a channel in order to be performed. If a specific channel mode is required by an operation, then:
2424
** @(RTO2a)@ If the channel is in the @ATTACHED@ state, the presence of the required channel mode is checked against the set of channel modes granted by the server per "RTL4m":../features#RTL4m :
2525
*** @(RTO2a1)@ If the channel mode is in the set, the operation is allowed
26-
*** @(RTO2a2)@ If the channel mode is missing, unless otherwise specified by the operation, the library should indicate an error with code 40024 stating that the operation cannot be performed without the required channel mode
26+
*** @(RTO2a2)@ If the channel mode is missing, unless otherwise specified by the operation, the library should throw an @ErrorInfo@ error with @statusCode@ 400 and @code@ 40024, indicating that the operation cannot be performed without the required channel mode
2727
** @(RTO2b)@ Otherwise, a best-effort attempt is made, and the channel mode is checked against the set of channel modes requested by the user per "TB2d":../features#TB2d :
2828
*** @(RTO2b1)@ If the channel mode is in the set, the operation is allowed
29-
*** @(RTO2b2)@ If the channel mode is missing, unless otherwise specified by the operation, the library should indicate an error with code 40024 stating that the operation cannot be performed without the required channel mode
29+
*** @(RTO2b2)@ If the channel mode is missing, unless otherwise specified by the operation, the library should throw an @ErrorInfo@ error with @statusCode@ 400 and @code@ 40024, indicating that the operation cannot be performed without the required channel mode
3030
* @(RTO3)@ An internal @ObjectsPool@ should be used to maintain the list of objects present on a channel
3131
** @(RTO3a)@ @ObjectsPool@ is a @Dict<String, LiveObject>@ - a map of @LiveObject@s keyed by "@objectId@":../features#OST2a string
3232
** @(RTO3b)@ It must always contain a @LiveMap@ object with id @root@
33+
*** @(RTO3b1)@ Upon initialization of the @ObjectsPool@, create a new @LiveMap@ (per "RTLM4":#RTLM4) with @objectId@ set to @root@ and add it to the @ObjectsPool@
3334
* @(RTO4)@ When a channel @ATTACHED@ @ProtocolMessage@ is received, the @ProtocolMessage@ may contain a @HAS_OBJECTS@ bit flag indicating that it will perform an objects sync, see "TR3":../features#TR3 . Note that this does not imply that objects are definitely present on the channel, only that there may be; the @OBJECT_SYNC@ message may be empty
3435
** @(RTO4a)@ If the @HAS_OBJECTS@ flag is 1, the server will shortly perform an @OBJECT_SYNC@ sequence as described in "RTO5":#RTO5
3536
** @(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:
3637
*** @(RTO4b1)@ All objects except the one with id @root@ must be removed from the internal @ObjectsPool@
37-
*** @(RTO4b2)@ The data for the @LiveMap@ with id @root@ must be cleared by setting it to a zero-value per "RTLM4":#RTLM4
38+
*** @(RTO4b2)@ The data for the @LiveMap@ with id @root@ must be cleared by setting it to a zero-value per "RTLM4":#RTLM4. Note that the client SDK must not create a new @LiveMap@ instance with id @root@; it must only clear the internal data of the existing @LiveMap@ with id @root@
3839
*** @(RTO4b3)@ The @SyncObjectsPool@ must be cleared
3940
*** @(RTO4b4)@ Perform the actions for objects sync completion as described in "RTO5c":#RTO5c
4041
* @(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
@@ -47,13 +48,13 @@ h3(#realtime-objects). RealtimeObjects
4748
*** @(RTO5a5)@ An @OBJECT_SYNC@ may also be sent with no @channelSerial@ attribute. In this case, the sync data is entirely contained within the @ProtocolMessage@
4849
** @(RTO5b)@ During the sync sequence, the @ObjectMessage.object@ values from incoming @OBJECT_SYNC@ @ProtocolMessage@s must be temporarily stored in the internal @SyncObjectsPool@ list
4950
** @(RTO5c)@ When the objects sync has completed, the client library must perform the following actions in order:
50-
*** @(RTO5c1)@ For each @ObjectState@ member in the @SyncObjectsPool@ list:
51+
*** @(RTO5c1)@ For each @ObjectState@ in the @SyncObjectsPool@ list:
5152
**** @(RTO5c1a)@ If an object with @ObjectState.objectId@ exists in the internal @ObjectsPool@:
52-
***** @(RTO5c1a1)@ Override the internal data for the object as per "RTLC6":#RTLC6, "RTLM6":#RTLM6
53+
***** @(RTO5c1a1)@ Replace the internal data for the object as described in "RTLC6":#RTLC6 or "RTLM6":#RTLM6 depending on the object type, passing in current @ObjectState@
5354
**** @(RTO5c1b)@ If an object with @ObjectState.objectId@ does not exist in the internal @ObjectsPool@:
5455
***** @(RTO5c1b1)@ Create a new @LiveObject@ using the data from @ObjectState@ and add it to the internal @ObjectsPool@:
55-
****** @(RTO5c1b1a)@ If @ObjectState.counter@ is present, create a zero-value @LiveCounter@ (per "RTLC4":#RTLC4), set its private @objectId@ equal to @ObjectState.objectId@ and override its internal data using the current @ObjectState@ per "RTLC6":#RTLC6
56-
****** @(RTO5c1b1b)@ If @ObjectState.map@ is present, create a zero-value @LiveMap@ (per "RTLM4":#RTLM4), set its private @objectId@ equal to @ObjectState.objectId@, set its private @semantics@ equal to @ObjectState.map.semantics@ and override its internal data using the current @ObjectState@ per "RTLM6":#RTLM6
56+
****** @(RTO5c1b1a)@ If @ObjectState.counter@ is present, create a zero-value @LiveCounter@ (per "RTLC4":#RTLC4), set its private @objectId@ equal to @ObjectState.objectId@ and replace its internal data using the current @ObjectState@ per "RTLC6":#RTLC6
57+
****** @(RTO5c1b1b)@ If @ObjectState.map@ is present, create a zero-value @LiveMap@ (per "RTLM4":#RTLM4), set its private @objectId@ equal to @ObjectState.objectId@, set its private @semantics@ equal to @ObjectState.map.semantics@ and replace its internal data using the current @ObjectState@ per "RTLM6":#RTLM6
5758
****** @(RTO5c1b1c)@ Otherwise, log a warning that an unsupported object state message has been received, and discard the current @ObjectState@ without taking any action
5859
*** @(RTO5c2)@ Remove any objects from the internal @ObjectsPool@ for which @objectId@s were not received during the sync sequence
5960
**** @(RTO5c2a)@ The object with ID @root@ must not be removed from @ObjectsPool@, as per "RTO3b":#RTO3b
@@ -66,6 +67,10 @@ h3(#realtime-objects). RealtimeObjects
6667
*** @(RTO6b2)@ If the parsed type is @map@, create a zero-value @LiveMap@ per "RTLM4":#RTLM4 in the @ObjectsPool@
6768
*** @(RTO6b3)@ If the parsed type is @counter@, create a zero-value @LiveCounter@ per "RTLC4":#RTLC4 in the @ObjectsPool@
6869

70+
h3(#liveobject). LiveObject
71+
72+
* @(RTLO1)@ The @LiveObject@ represents the common interface and includes shared functionality for concrete object types
73+
6974
h3(#livecounter). LiveCounter
7075

7176
* @(RTLC1)@ The @LiveCounter@ extends @LiveObject@
@@ -74,9 +79,9 @@ h3(#livecounter). LiveCounter
7479
* @(RTLC4)@ The zero-value @LiveCounter@ is a @LiveCounter@ with @data@ set to 0
7580
* @(RTLC5)@ @LiveCounter#value@ function:
7681
** @(RTLC5a)@ Requires the @OBJECT_SUBSCRIBE@ channel mode to be granted per "RTO2":#RTO2
77-
** @(RTLC5b)@ If the channel is in the @DETACHED@ or @FAILED@ state, the library should indicate an error with code 90001
82+
** @(RTLC5b)@ If the channel is in the @DETACHED@ or @FAILED@ state, the library should throw an @ErrorInfo@ error with @statusCode@ 400 and @code@ 90001
7883
** @(RTLC5c)@ Returns the current @data@ value
79-
* @(RTLC6)@ @LiveCounter@'s internal @data@ can be overridden with the provided @ObjectState@ in the following way:
84+
* @(RTLC6)@ @LiveCounter@'s internal @data@ can be replaced with the provided @ObjectState@ in the following way:
8085
** @(RTLC6a)@ Replace the private @siteTimeserials@ of the @LiveCounter@ with the value from @ObjectState.siteTimeserials@
8186
** @(RTLC6b)@ Set the private flag @createOperationIsMerged@ to @false@
8287
** @(RTLC6c)@ Set @data@ to the value of @ObjectState.counter.count@, or to 0 if it does not exist
@@ -93,7 +98,7 @@ h3(#livemap). LiveMap
9398
* @(RTLM5)@ @LiveMap#get@ function:
9499
** @(RTLM5a)@ Accepts a key of type String
95100
** @(RTLM5b)@ Requires the @OBJECT_SUBSCRIBE@ channel mode to be granted per "RTO2":#RTO2
96-
** @(RTLM5c)@ If the channel is in the @DETACHED@ or @FAILED@ state, the library should indicate an error with code 90001
101+
** @(RTLM5c)@ If the channel is in the @DETACHED@ or @FAILED@ state, the library should throw an @ErrorInfo@ error with @statusCode@ 400 and @code@ 90001
97102
** @(RTLM5d)@ Returns the value from the current @data@ at the specified key, as follows:
98103
*** @(RTLM5d1)@ If no @ObjectsMapEntry@ exists at the key, return undefined/null
99104
*** @(RTLM5d2)@ If an @ObjectsMapEntry@ exists at the key:
@@ -106,40 +111,40 @@ h3(#livemap). LiveMap
106111
***** @(RTLM5d2f1)@ If an object with id @objectId@ does not exist, return undefined/null
107112
***** @(RTLM5d2f2)@ If an object with id @objectId@ exists, return it
108113
**** @(RTLM5d2g)@ Otherwise, return undefined/null
109-
* @(RTLM6)@ @LiveMap@ internal @data@ can be overridden with the provided @ObjectState@ in the following way:
114+
* @(RTLM6)@ @LiveMap@ internal @data@ can be replaced with the provided @ObjectState@ in the following way:
110115
** @(RTLM6a)@ Replace the private @siteTimeserials@ of the @LiveMap@ with the value from @ObjectState.siteTimeserials@
111116
** @(RTLM6b)@ Set the private flag @createOperationIsMerged@ to @false@
112117
** @(RTLM6c)@ Set @data@ to @ObjectState.map.entries@, or to an empty map if it does not exist
113118
** @(RTLM6d)@ If @ObjectState.createOp@ is present:
114119
*** @(RTLM6d1)@ For each key–@ObjectsMapEntry@ pair in @ObjectState.createOp.map.entries@:
115-
**** @(RTLM6d1a)@ If @ObjectsMapEntry.tombstone@ is @false@, apply the @MAP_SET@ operation to the specified key using @ObjectsMapEntry.timeserial@ and @ObjectsMapEntry.data@ per "RTLM7":#RTLM7
120+
**** @(RTLM6d1a)@ If @ObjectsMapEntry.tombstone@ is @false@ or omitted, apply the @MAP_SET@ operation to the specified key using @ObjectsMapEntry.timeserial@ and @ObjectsMapEntry.data@ per "RTLM7":#RTLM7
116121
**** @(RTLM6d1b)@ If @ObjectsMapEntry.tombstone@ is @true@, apply the @MAP_REMOVE@ operation to the specified key using @ObjectsMapEntry.timeserial@ per "RTLM8":#RTLM8
117122
*** @(RTLM6d2)@ Set the private flag @createOperationIsMerged@ to @true@
118123
* @(RTLM7)@ @MAP_SET@ operation for a key can be applied to a @LiveMap@ in the following way:
119-
** @(RTLM7a)@ If an entry exists in the private @data@ for the specified key:
120-
*** @(RTLM7a1)@ If the operation cannot be applied as per "RTLM9":#RTLM9, discard the operation without taking any action
121-
*** @(RTLM7a2)@ Otherwise, apply the operation:
124+
** @(RTLM7a)@ If an @ObjectsMapEntry@ exists in the private @data@ for the specified key:
125+
*** @(RTLM7a1)@ If the operation cannot be applied to the existing entry as per "RTLM9":#RTLM9, discard the operation without taking any action
126+
*** @(RTLM7a2)@ Otherwise, apply the operation to the existing entry:
122127
**** @(RTLM7a2a)@ Set @ObjectsMapEntry.data@ to the @ObjectData@ from the operation
123128
**** @(RTLM7a2b)@ Set @ObjectsMapEntry.timeserial@ to the operation's serial
124129
**** @(RTLM7a2c)@ Set @ObjectsMapEntry.tombstone@ to @false@
125130
** @(RTLM7b)@ If an entry does not exist in the private @data@ for the specified key:
126131
*** @(RTLM7b1)@ Create a new entry in @data@ for the specified key with the provided @ObjectData@ and the operation's serial
127132
*** @(RTLM7b2)@ Set @ObjectsMapEntry.tombstone@ for the new entry to @false@
128133
** @(RTLM7c)@ If the operation has a non-empty @ObjectData.objectId@ attribute:
129-
*** @(RTLM7c1)@ Create a zero-value @LiveObject@ in the internal @ObjectsPool@ per "RTO6":#RTO6
134+
*** @(RTLM7c1)@ Create a zero-value @LiveObject@ for this @ObjectData.objectId@ in the internal @ObjectsPool@ per "RTO6":#RTO6
130135
* @(RTLM8)@ @MAP_REMOVE@ operation for a key can be applied to a @LiveMap@ in the following way:
131-
** @(RTLM8a)@ If an entry exists in the private @data@ for the specified key:
132-
*** @(RTLM8a1)@ If the operation cannot be applied as per "RTLM9":#RTLM9, discard the operation without taking any action
133-
*** @(RTLM8a2)@ Otherwise, apply the operation:
136+
** @(RTLM8a)@ If an @ObjectsMapEntry@ exists in the private @data@ for the specified key:
137+
*** @(RTLM8a1)@ If the operation cannot be applied to the existing entry as per "RTLM9":#RTLM9, discard the operation without taking any action
138+
*** @(RTLM8a2)@ Otherwise, apply the operation to the existing entry:
134139
**** @(RTLM8a2a)@ Set @ObjectsMapEntry.data@ to undefined/null
135140
**** @(RTLM8a2b)@ Set @ObjectsMapEntry.timeserial@ to the operation's serial
136141
**** @(RTLM8a2c)@ Set @ObjectsMapEntry.tombstone@ to @true@
137142
** @(RTLM8b)@ If an entry does not exist in the private @data@ for the specified key:
138143
*** @(RTLM8b1)@ Create a new entry in @data@ for the specified key, with @ObjectsMapEntry.data@ set to undefined/null and the operation's serial
139144
*** @(RTLM8b2)@ Set @ObjectsMapEntry.tombstone@ for the new entry to @true@
140145
* @(RTLM9)@ Whether a map operation can be applied to a map entry is determined as follows:
141-
** @(RTLM9a)@ For a @LiveMap@ using @LWW@ (Last-Write-Wins) CRDT semantics, the operation must only be applied if its serial is strictly greater ("after") than the entry's serial when compared lexicographically
146+
** @(RTLM9a)@ For a @LiveMap@ with @semantics@ set to @ObjectsMapSemantics.LWW@ (Last-Write-Wins CRDT semantics), the operation must only be applied if its serial is strictly greater ("after") than the entry's serial when compared lexicographically
142147
** @(RTLM9b)@ If both the entry serial and the operation serial are null or empty strings, they are treated as the "earliest possible" serials and considered "equal", so the operation must not be applied
143-
** @(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
144-
** @(RTLM9d)@ If only the operation serial exists, it is considered greater than the missing entry serial, so the operation can be applied
145-
** @(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
148+
** @(RTLM9c)@ If only the entry serial exists and is not an empty string, the missing operation serial is considered lower than the existing entry serial, so the operation must not be applied
149+
** @(RTLM9d)@ If only the operation serial exists and is not an empty string, it is considered greater than the missing entry serial, so the operation can be applied
150+
** @(RTLM9e)@ If both serials exist and are not empty strings, compare them lexicographically and allow operation to be applied only if the operation's serial is greater than the entry's serial

0 commit comments

Comments
 (0)