Skip to content

Commit

Permalink
Clarify message ordering and update serial definitions
Browse files Browse the repository at this point in the history
Refine definitions of `serial` and `latestActionSerial` for message ordering to be lexicographically sortable.
  • Loading branch information
splindsay-92 committed Nov 12, 2024
1 parent e18b42a commit 36761e9
Showing 1 changed file with 47 additions and 36 deletions.
83 changes: 47 additions & 36 deletions textile/chat-features.textile
Original file line number Diff line number Diff line change
Expand Up @@ -188,46 +188,57 @@ Messages are the quintessential component of a chat room - the purpose of chat i

Broadly speaking, messages are published via REST calls to the Chat HTTP API and message events are received in Realtime over a corresponding realtime channel.

@Serial@ is used to provide a global ordering for messages. A @Serial@ is a unique lexicographically sortable string.

* @(CHA-S1)@ @[Testable]@ In the context of lexicographical sorting, the following applies:
** @(CHA-S1a)@ @[Testable]@ A @Serial@ is considered before another @Serial@ in the global order if it comes first in a lexicographical sort.
** @(CHA-S1b)@ @[Testable]@ A @Serial@ is considered after another @Serial@ in the global order if it comes second in a lexicographical sort.
** @(CHA-S1c)@ @[Testable]@ A @Serial@ is considered to be equal to another @Serial@ if both @Serial@ strings are identical.

@Messages@ shall be exposed to consumers via the @messages@ property of a @Room@.

* @(CHA-M1)@ Chat messages for a Room are sent on a corresponding realtime channel @<roomId>::$chat::$chatMessages@. For example, if your room id is @my-room@ then the messages channel will be @my-room::$chat::$chatMessages@.
* @(CHA-M2)@ A @Message@ corresponds to a single message in a chat room. This is analogous to a single user-specified message on an Ably channel (NOTE: **not** a @ProtocolMessage@).
<div class=deprecated>
** @(CHA-M2a)@ @[Testable]@ @[Deprecated]@ A @Message@ is considered before another @Message@ in the global order if the @timeserial@ of the corresponding realtime channel message comes first.
** @(CHA-M2b)@ @[Testable]@ @[Deprecated]@ A @Message@ is considered after another @Message@ in the global order if the @timeserial@ of the corresponding realtime channel message comes second.
** @(CHA-M2c)@ @[Testable]@ @[Deprecated]@ A @Message@ is considered to be equal to another @Message@ if they have the same timeserial.
** @(CHA-M2a)@ @[Testable]@ @(deprecated)@ A @Message@ is considered before another @Message@ in the global order if the @timeserial@ of the corresponding realtime channel message comes first.
** @(CHA-M2b)@ @[Testable]@ @(deprecated)@ A @Message@ is considered after another @Message@ in the global order if the @timeserial@ of the corresponding realtime channel message comes second.
** @(CHA-M2c)@ @[Testable]@ @(deprecated)@ A @Message@ is considered to be equal to another @Message@ if they have the same timeserial.
</div>
** @(CHA-M2d)@ @[Testable]@ A @Message@ is considered before another @Message@ in the global order if the @serial@ of the corresponding realtime channel message comes first.
** @(CHA-M2e)@ @[Testable]@ A @Message@ is considered after another @Message@ in the global order if the @serial@ of the corresponding realtime channel message comes second.
** @(CHA-M2f)@ @[Testable]@ A @Message@ is considered to be equal to another @Message@ if they have the same serial.
* @(CHA-M10)@ A @Message@ can be modified by applying a new @action@ to it, such as an update or delete. Doing so would result in a new @Message@ with a different @latestActionSerial@, but the same @serial@ as the original message.
** @(CHA-M10a)@ @[Testable]@ An @action@ is considered before another @action@ in the global order if the @latestActionSerial@ of the corresponding realtime channel message comes first.
** @(CHA-M10b)@ @[Testable]@ An @action@ is considered after another @action@ in the global order if the @latestActionSerial@ of the corresponding realtime channel message comes second.
** @(CHA-M10c)@ @[Testable]@ An @action@ is considered to be equal to another @action@ if they have the same @latestActionSerial@.
* @(CHA-M3)@ Messages are sent to Ably via the Chat REST API, using the @send@ method.
** @(CHA-M3a)@ @[Testable]@ When a message is sent successfully, the caller shall receive a struct representing the "@Message@":#chat-structs-message in response (as if it were received via Realtime event).
** @(CHA-M2d)@ @[Testable]@ A @Message@ contains a unique, immutable @serial@, which is a lexicographically sortable string.
** @(CHA-M2e)@ @[Testable]@ In global ordering, a @Message@ is considered to occur before another @Message@ if the @serial@ of the first @Message@ is before the latter when lexicographically sorted.
** @(CHA-M2f)@ @[Testable]@ In global ordering, a @Message@ is considered after another @Message@ if the @serial@ of the first @Message@ is after the latter when lexicographically sorted.
** @(CHA-M2g)@ @[Testable]@ Two @Messages@ are considered to be the same if they have the same @serial@, that is to say, both @Serial@ strings are identical.
* @(CHA-M10)@ A @Message@ can be modified by applying a new @action@ to it, such as an update or delete. Applying an @action@ generates a new @Message@ instance with an updated @latestActionSerial@, while the original Message’s @serial@ remains unchanged.
** @(CHA-M10a)@ @[Testable]@ The @latestActionSerial@ of a @Message@ is a lexicographically sortable, unique identifier for each action applied to the @Message@. Unlike @serial@, @latestActionSerial@ is mutable and is updated each time an @action@ is applied.
** @(CHA-M10a)@ @[Testable]@ In global ordering, an @action@ is considered to occur before another @action@ if the @latestActionSerial@ of the first @action@ is lexicographically smaller than that of the latter.
** @(CHA-M10b)@ @[Testable]@ In global ordering, an @action@ is considered to occur after another @action@ if the @latestActionSerial@ of the first @action@ is lexicographically greater than that of the latter.
** @(CHA-M10c)@ @[Testable]@ Two @actions@ are considered to be the same if they have the same @latestActionSerial@, that is to say, both @latestActionSerial@ strings are identical.
* @(CHA-M3)@ A client must be able to send a message to a room via the Chat REST API.
** @(CHA-M3a)@ @[Testable]@ When a message is sent successfully, the caller shall receive a struct representing the "@Message@":#chat-structs-message in response, as if it were received via Realtime event.
** @(CHA-M3b)@ @[Testable]@ A message may be sent without @metadata@ or @headers@. When these are not specified by the user, they must be omitted from the REST payload.
** @(CHA-M3c)@ This clause has been deleted.
** @(CHA-M3d)@ This clause has been deleted.
** @(CHA-M3e)@ @[Testable]@ If an error is returned from the REST API, its @ErrorInfo@ representation shall be thrown as the result of the @send@ call.
* @(CHA-M8)@ Message updates are sent to Ably via the Chat REST API, using the @update@ method.
** @(CHA-M8a)@ @[Testable]@ When a message is updated successfully, the caller shall receive a struct representing the "@Message@":#chat-structs-message-v2 in response (as if it were received via Realtime event).
** @(CHA-M8b)@ @[Testable]@ An update is treated as a whole single change (PUT). If a field is not specified in the update, it is assumed to be removed.
** @(CHA-M8a)@ @[Testable]@ When a message is updated successfully, the caller shall receive a struct representing the "@Message@":#chat-structs-message-v2 in response, as if it were received via Realtime event.
** @(CHA-M8b)@ @[Testable]@ An update operation has PUT semantics. If a field is not specified in the update, it is assumed to be removed.
** @(CHA-M8c)@ @[Testable]@ If an error is returned from the REST API, its @ErrorInfo@ representation shall be thrown as the result of the @update@ call.
* @(CHA-M9)@ Messages deletions are sent to Ably via the Chat REST API, using the @delete@ method.
** @(CHA-M9a)@ @[Testable]@ When a message is deleted successfully, the caller shall receive a struct representing the "@Message@":#chat-structs-message-v2 in response (as if it were received via Realtime event).
** @(CHA-M9b)@ @[Testable]@ If an error is returned from the REST API, its @ErrorInfo@ representation shall be thrown as the result of the @delete@ call.
* @(CHA-M4)@ Messages can be received via a subscription in realtime.
** @(CHA-M4a)@ @[Testable]@ A subscription can be registered to receive incoming messages. Adding a subscription has no side effects on the status of the room or the underlying realtime channel.
** @(CHA-M4b)@ @[Testable]@ A subscription can de-registered from incoming messages. Removing a subscription has no side effects on the status of the room or the underlying realtime channel.
** @(CHA-M4c)@ @[Testable]@ @[Deprecated]@ When a realtime message with @name@ set to @message.created@ is received, it is translated into a message event, which contains a @type@ field with the event type as well as a @message@ field containing the "@Message Struct@":#chat-structs-message. This event is then broadcast to all subscribers.
** @(CHA-M4l)@ @[Testable]@ When a realtime message with @name@ set to @chat.message@ is received, it is translated into a message event based on its @action@. This message event contains a @type@ field with the event type as well as a @message@ field containing the "@Message Struct@":#chat-structs-message. This event is then broadcast to all subscribers.
<div class=deprecated>
** @(CHA-M4c)@ @[Testable]@ @(deprecated)@ When a realtime message with @name@ set to @message.created@ is received, it is translated into a message event, which contains a @type@ field with the event type as well as a @message@ field containing the "@Message Struct@":#chat-structs-message. This event is then broadcast to all subscribers.
</div>
** @(CHA-M4l)@ @[Testable]@ When a realtime message with the @name@ field set to @chat.message@ is received, it is translated into a message event based on its @action@. This message event contains a @type@ field with the event type as well as a @message@ field containing the "@Message Struct@":#chat-structs-message-v2. This event is then broadcast to all subscribers.
** @(CHA-M4d)@ @[Testable]@ If a realtime message with an unknown @name@ is received, the SDK shall silently discard the message, though it may log at @DEBUG@ or @TRACE@ level.
** @(CHA-M4m)@ @[Testable]@ The @action@ field of the realtime message determines the type of chat message event that is emitted, based on the following rules.
*** @(CHA-M4m1)@ @[Testable]@ If @action@ is set to @MESSAGE_CREATE@, then an event with @type@ set to @message.created@ will be emitted.
*** @(CHA-M4m2)@ @[Testable]@ If @action@ is set to @MESSAGE_UPDATE@, then an event with @type@ set to @message.updated@ will be emitted.
*** @(CHA-M4m3)@ @[Testable]@ If @action@ is set to @MESSAGE_DELETE@, then an event with @type@ set to @message.deleted@ will be emitted.
*** @(CHA-M4m4)@ @[Testable]@ If a realtime message with an unknown @action@ is received, the SDK shall silently discard the message, though it may log at @DEBUG@ or @TRACE@ level.
** @(CHA-M4d)@ @[Testable]@ If a realtime message with an unknown @name@ is received, the SDK shall silently discard the message, though it may log at @DEBUG@ or @TRACE@ level.
** @(CHA-M5k)@ @[Testable]@ Incoming realtime events that are malformed (unknown field should be ignored) shall not be emitted to subscribers.
* @(CHA-M5)@ For a given subscription, messages prior to the point of subscription can be retrieved in a history-like request. Note that this is the point in the message flow @(subscription point)@ at which the subscription was made, NOT the channel attachment point.
** @(CHA-M5a)@ @[Testable]@ If a subscription is added when the underlying realtime channel is @ATTACHED@, then the @subscription point@ is the current @channelSerial@ of the realtime channel.
Expand Down Expand Up @@ -387,7 +398,7 @@ h3(#rest-general). General

h3(#rest-sending-messages). Sending Messages

h4(#rest-sending-messages-request-v1). Request V1 @[Deprecated]@
h4(#rest-sending-messages-request-v1). Request V1 @(deprecated)@

Below is the full REST payload format for the V1 endpoint. The @metadata@ and @headers@ keys are optional.

Expand All @@ -406,7 +417,7 @@ Below is the full REST payload format for the V1 endpoint. The @metadata@ and @h
}
</pre>

h4(#rest-sending-messages-request-v1). Response V1 @[Deprecated]@
h4(#rest-sending-messages-request-v1). Response V1 @(deprecated)@

A successful request shall result in status code @201 Created@.

Expand All @@ -419,7 +430,7 @@ The response body is as follows.
}
</pre>

h4(#rest-sending-messages-request-v1). Corresponding Realtime Event V1 @[Deprecated]@
h4(#rest-sending-messages-request-v1). Corresponding Realtime Event V1 @(deprecated)@

<pre>
{
Expand Down Expand Up @@ -470,7 +481,7 @@ The response body is as follows.

<pre>
{
"serial": "cbfqxperABgItU52203559@1726232498871-0:0",
"serial": "01726585978590-001@abcdefghij:001",
"createdAt": 1726232498871
}
</pre>
Expand All @@ -495,7 +506,7 @@ h4(#rest-sending-messages-request-v2). Corresponding Realtime Event V2
"baz": "qux"
},
},
"serial": "cbfqxperABgItU52203559@1726232498871-0:0"
"serial": "01726585978590-001@abcdefghij:001"
"action": "message.create"
"updatedAt": undefined
"updateSerial": undefined
Expand Down Expand Up @@ -538,7 +549,7 @@ The response body is as follows.

<pre>
{
"serial": "cbfqxperABgItU52203559@1826232498871-0:0",
"serial": "01826232498871-001@abcdefghij:001",
"updatedAt": 1726232498871
}
</pre>
Expand All @@ -565,10 +576,10 @@ h4(#rest-updating-messages-request). Corresponding Realtime Event
"baz": "qux"
},
}
"serial": "cbfqxperABgItU52203559@1726232498871-0:0",
"serial": "01726585978590-001@abcdefghij:001",
"action": "message.update"
"updatedAt": 1826232498871
"updateSerial": "cbfqxperABgItU52203559@1826232498871-0:0"
"updateSerial": "01826232498871-001@abcdefghij:001"
"operation": {
"clientId": "who-performed-the-action",
"description": "why-the-action-was-performed"
Expand Down Expand Up @@ -603,7 +614,7 @@ The response body is as follows.

<pre>
{
"serial": "cbfqxperABgItU52203559@1826232498871-0:0",
"serial": "01826232498871-001@abcdefghij:001",
"deletedAt": 1826232498871
}
</pre>
Expand All @@ -630,10 +641,10 @@ h4(#rest-deleting-messages-request). Corresponding Realtime Event
"baz": "qux"
},
}
"serial": "cbfqxperABgItU52203559@1726232498871-0:0",
"serial": "01726585978590-001@abcdefghij:001",
"action": "message.deleted"
"updatedAt": 1826232498871
"updateSerial": "cbfqxperABgItU52203559@1826232498871-0:0"
"updateSerial": "01826232498871-001@abcdefghij:001",
"operation": {
"clientId": "who-performed-the-action",
"description": "why-the-action-was-performed"
Expand All @@ -646,15 +657,15 @@ h4(#rest-deleting-messages-request). Corresponding Realtime Event

h3(#rest-fetching-messages). Fetching Message History

h4(#rest-fetching-messages-request-v1). Request V1 @[Deprecated]@
h4(#rest-fetching-messages-request-v1). Request V1 @(deprecated)@

<pre>
GET /chat/v1/rooms/<roomId>/messages
</pre>

The method accepts query parameters identical to the standard Ably REST API.

h4(#rest-fetching-messages-response). Response V1 @[Deprecated]@
h4(#rest-fetching-messages-response). Response V1 @(deprecated)@

An array of "@Message@ structs":#chat-structs-message

Expand Down Expand Up @@ -735,7 +746,7 @@ The RoomOptions struct describes configuration options for a Chat room. A proper

h3(#chat-structs-message). Messages

h4(#chat-structs-message-v1). Messages V1 @[Deprecated]@
h4(#chat-structs-message-v1). Messages V1 @(deprecated)@
<pre>
{
"timeserial": "cbfqxperABgItU52203559@1726232498871-0",
Expand All @@ -754,13 +765,13 @@ h4(#chat-structs-message-v1). Messages V1 @[Deprecated]@
}
</pre>

@[Deprecated]@ Determining the global order of messages may be achieved by comparing the timeserials. See @CHA-M2@ for more information.
@(deprecated)@ Determining the global order of messages may be achieved by comparing the timeserials. See @CHA-M2@ for more information.

h4(#chat-structs-message-v2). Messages V2

<pre>
{
"serial": "cbfqxperABgItU52203559@1726232498871-0",
"serial": "01726585978590-001@abcdefghij:001",
"roomId": "my-room",
"clientId": "who-sent-the-message",
"text": "my-message",
Expand All @@ -774,7 +785,7 @@ h4(#chat-structs-message-v2). Messages V2
"baz": "qux"
}
"latestAction": "message.created",
"latestActionSerial": "cbfqxperABgItU52203559@1726232498871-0",
"latestActionSerial": "01726585978590-001@abcdefghij:001",
"deletedAt": DateTime() | undefined,
"updatedAt": DateTime() | undefined,
"latestActionDetails": {
Expand All @@ -789,9 +800,9 @@ h4(#chat-structs-message-v2). Messages V2
}
</pre>

Determining the global order of messages may be achieved by comparing the serials. See @CHA-M2@ for more information.
Determining the global order of messages may be achieved by lexicographically comparing the serials. See @CHA-M2@ for more information.

Determining the global order of message actions may be achieved by comparing the @latestActionSerial@. See @CHA-M10@ for more information.
Determining the global order of message actions may be achieved by lexicographically comparing the @latestActionSerial@. See @CHA-M10@ for more information.

h3(#chat-structs-ephemeral-reactions). Ephemeral Room Reactions

Expand Down

0 comments on commit 36761e9

Please sign in to comment.