Skip to content

Commit 47e44d8

Browse files
authored
Merge pull request #319 from ably/chat-message-reactions
chat message reactions
2 parents f700448 + ef0d3e5 commit 47e44d8

1 file changed

Lines changed: 240 additions & 0 deletions

File tree

textile/chat-features.textile

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,15 @@ Broadly speaking, messages are published via REST calls to the Chat HTTP API and
326326
** @(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.
327327
** @(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.
328328

329+
* @(CHA-M11)@ A @Message@ must have a method @with@ to apply changes from events (@MessageEvent@ and @MessageReactionSummaryEvent@) to produce updated message instances.
330+
** @(CHA-M11a)@ @[Testable]@ When the method receives a @MessageEvent@ of type @created@, it must throw an @ErrorInfo@ with code @40000@ and status code @400@.
331+
** @(CHA-M11b)@ @[Testable]@ For @MessageEvent@ the method must verify that the @message.serial@ in the event matches the message's own serial. If they don't match, an error with code @40000@ and status code @400@ must be thrown.
332+
** @(CHA-M11c)@ @[Testable]@ For @MessageEvent@ of type @update@ and @delete@, if the event message is older or the same (see CHA-M10), the original message must be returned unchanged.
333+
** @(CHA-M11d)@ @[Testable]@ For @MessageEvent@ of type @update@ and @delete@, if the event message is newer (see CHA-M10), the method must return a new message based on the event and deep-copying the reactions from the original message.
334+
** @(CHA-M11e)@ @[Testable]@ For @MessageReactionSummaryEvent@, the method must verify that the @summary.messageSerial@ in the event matches the message's own serial. If they don't match, an error with code @40000@ and status code @400@ must be thrown.
335+
** @(CHA-M11f)@ @[Testable]@ For @MessageReactionSummaryEvent@, the method must return a new @Message@ instance (deep copy) with the updated reactions, preserving all other properties of the original message.
336+
** @(CHA-M11g)@ @[Testable]@ For @MessageReactionSummaryEvent@, the method must deep-copy the reactions from the event before applying them to the returned message instance.
337+
329338
<div class=deprecated>
330339
** @(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.
331340
</div>
@@ -354,6 +363,46 @@ Broadly speaking, messages are published via REST calls to the Chat HTTP API and
354363
* @(CHA-M6b)@ @[Testable]@ If the REST API returns an error, then the method must throw its @ErrorInfo@ representation.
355364
* @(CHA-M7)@ This specification point has been removed. It was valid up until the single-channel migration.
356365

366+
h2(#messageReactions). Message Reactions
367+
368+
Users can add reactions to messages, such as thumbs-up or heart emojis. Summaries (counts per reaction name, and who reacted) of the message reactions are stored with the message and are visible to all users in the room. Message reactions are powered by Pub/Sub message annotations.
369+
370+
@MessagesReactions@ object is the entry point for interacting with Message Reactions. It shall be exposed to consumers via a @reactions@ property inside the @Messages@ obejct. From the @Room@ level: @room.messages.reactions@.
371+
372+
* @(CHA-MR1)@ Message reactions are powered by Pub/Sub message annotations. The annotation type used is of the format @reaction:<aggregation>@.
373+
374+
* @(CHA-MR2)@ There are three types of message reactions, each corresponding to a different annotation aggregation type.
375+
** @(CHA-MR2a)@ Reactions of type @Unique@ use the annotation type @reaction:unique.v1@. In this type, each client can add only one reaction (by @name@). Reacting again changes the reaction to the new one (similar to WhatsApp or iMessage).
376+
** @(CHA-MR2b)@ Reactions of type @Distinct@ use the annotation type @reaction:distinct.v1@. Each client can add multiple reaction with different names, but each unique @name@ only once (similar to Slack).
377+
** @(CHA-MR2c)@ Reactions of type @Multiple@ use the annotation type @reaction:multiple.v1@. In this type, each client can add any reaction @name@ multiple times including duplicates. Reactions can include a @count@ field indicating how many times the reaction should be counted towards the total (similar to claps on Medium).
378+
379+
* @(CHA-MR3)@ @[Testable]@ The @reactions@ property of the @Message@ object is an object or map that contains summaries for all message reaction types. For convenience when using this in the public API, these are keyed by reaction type and not annotation type (eg. "distinct" and not "reaction:distinct.v1").
380+
** @(CHA-MR3a)@ @[Testable]@ The values for each reaction type summary are the same as defined in PubSub for the respective annotation aggregation types.
381+
** @(CHA-MR3b)@ @[Testable]@ For @Unique@ reaction types, the summary is at @Message.reactions.unique@ and is of type @Dict<string, SummaryClientIdList>@ (see @TM7b2@).
382+
** @(CHA-MR3b3)@ @[Testable]@ For @Distinct@ reaction types, the summary is at @Message.reactions.distinct@ and is of type @Dict<string, SummaryClientIdList>@ (see @TM7b1@).
383+
** @(CHA-MR3b2)@ @[Testable]@ For @Multiple@ reaction types, the summary is at @Message.reactions.multiple@ and is of type @Dict<string, SummaryClientIdCounts>@ (see @TM7b3@).
384+
385+
* @(CHA-MR4)@ @[Testable]@ Users should be able to send a reaction via the `add` method of the `MessagesReactions` object (@room.messages.reactions.add@).
386+
** @(CHA-MR4a)@ @[Testable]@ The `add` method accepts a message (or message serial) as the first parameter to identify which message to react to.
387+
** @(CHA-MR4b)@ @[Testable]@ The `add` method accepts a `params` object as the second parameter with the following properties:
388+
*** @(CHA-MR4b1)@ @[Testable]@ A `name` property (required) specifying the reaction identifier (e.g., emoji string).
389+
*** @(CHA-MR4b2)@ @[Testable]@ A `type` property (optional) specifying the reaction type. If not provided, the default reaction type for the room is used.
390+
*** @(CHA-MR4b3)@ @[Testable]@ A `count` property (optional) specifying the reaction count. This is only valid for reactions of type `multiple`. Defaults to 1 and must be a positive integer.
391+
392+
* @(CHA-MR5)@ @[Testable]@ Users may configure a default message reactions type for a room. This configuration is provided at the @RoomOptions.messages.defaultMessageReactionType@ property, or idiomatic equivalent. The default value is @distinct@.
393+
394+
* @(CHA-MR6)@ @[Testable]@ Users must be able to subscribe to message reaction summaries via the @subscribe@ method of the @MessagesReactions@ object (@room.messages.reactions.subscribe@). The events emitted will be of type @MessageReactionSummaryEvent@.
395+
396+
* @(CHA-MR7)@ @[Testable]@ Users must be able to subscribe to raw message reactions (as individual annotations) via the @subscribeRaw@ method of the @MessagesReactions@ object (@room.messages.reactions.subscribeRaw@). The events emitted are of type @MessageReactionRawEvent@.
397+
** @(CHA-MR7a)@ @[Testable]@ The attempt to subscribe to raw message reactions must throw an @ErrorInfo@ with code @40000@ and status code @400@ if the room is not configured to support raw message reactions (when room option @RoomOptions.messages.rawMessageReactions@ is not set to @true@; it defaults to @false@).
398+
399+
* @(CHA-MR8)@ Raw message reactions must not be used to update the message reaction summary on the client-side as this is likely to produce wrong results. Message reaction summaries are to be used for this.
400+
401+
* @(CHA-MR9)@ @[Testable]@ The room option @RoomOptions.messages.rawMessageReactions@ controls whether raw message reactions are enabled or not. The default value is @false@.
402+
** @(CHA-MR9a)@ @[Testable]@ If the room option is set to @true@, the SDK will add the @ANNOTATION_SUBSCRIBE@ channel mode to the realtime channel used for the room.
403+
404+
* @(CHA-MR10)@ @[Testable]@ The client must always add the @ANNOTATION_PUBLISH@ channel mode to the realtime channel used for the room.
405+
357406
h2(#reactions). Ephemeral Room Reactions
358407

359408
Ephemeral room reactions are one-time events that are sent to the room, such as thumbs-up or heart emojis. They are supposed to capture the current emotions in the room (e.g. everyone spamming the :tada: emoji when a team scores the winning goal).
@@ -746,6 +795,92 @@ h4(#rest-fetching-messages-response). Response V3
746795

747796
An array of V2 "@Message@ structs":#chat-structs-message-v2
748797

798+
799+
h3(#rest-sending-message-reactions). Sending message reactions
800+
801+
h4(#rest-sending-messages-reactions-request-v3). Request V3
802+
803+
Below is the full REST payload format for the V3 endpoint. The @count@ field is optional and it is only accepted for reactions of type @reaction:multiple.v1@.
804+
805+
<pre>
806+
POST /chat/v3/rooms/<roomId>/messages/<serial>/reactions
807+
{
808+
"type": "reaction:multiple.v1",
809+
"name": "🔥",
810+
"count": 5
811+
}
812+
</pre>
813+
814+
h4(#rest-sending-messages-response-v3). Response V3
815+
816+
A successful request shall result in status code @201 Created@.
817+
818+
The response body is as follows showing the serial of the new annotation.
819+
820+
<pre>
821+
{
822+
"serial": "01746631786947-000@cbfVqJopQBorrt95348450",
823+
}
824+
</pre>
825+
826+
h4(#rest-sending-messages-realtime-v3). Corresponding Realtime Event V3
827+
828+
Note this is an Annotation not a Message. ChannelMessage action is 21. The annotations are under the @annotations@ key.
829+
830+
<pre>
831+
{
832+
"action" : 0,
833+
"clientId" : "user-1",
834+
"messageSerial" : "01746631762878-000@cbfVqJopQBorrt95348450:000",
835+
"name" : "🔥",
836+
"serial" : "01746631786947-000@cbfVqJopQBorrt95348450:000",
837+
"type" : "reaction:multiple.v1",
838+
"count": 5
839+
}
840+
</pre>
841+
842+
A message summary event is also broadcast to the channel after adding or removing one or more annotations.
843+
844+
h3(#rest-deleting-message-reactions). Deleting message reactions
845+
846+
h4(#rest-deleting-messages-reactions-request-v3). Request V3
847+
848+
Below is the full REST payload format for the V3 endpoint. The @name@ param is ignored for reactions of type @reaction:unique.v1@ but it is required for all other reaction types.
849+
850+
<pre>
851+
DELETE /chat/v3/rooms/<roomId>/messages/<serial>/reactions?type=<reactionType>&name=<reaction>
852+
</pre>
853+
854+
h4(#rest-sending-messages-response-v3). Response V3
855+
856+
A successful request shall result in status code @200 OK@.
857+
858+
The response body is as follows showing the serial of the new annotation (annotation delete is also an annotation with annotation @action=1@).
859+
860+
<pre>
861+
{
862+
"serial": "01746632464399-000@cbfVqJopQBorrt95348450",
863+
}
864+
</pre>
865+
866+
h4(#rest-sending-messages-realtime-v3). Corresponding Realtime Event V3
867+
868+
Note this is an Annotation not a Message. ChannelMessage action is 21. The annotations are under the @annotations@ key.
869+
870+
<pre>
871+
{
872+
"action" : 1,
873+
"clientId" : "user-1",
874+
"messageSerial" : "01746631762878-000@cbfVqJopQBorrt95348450:000",
875+
"name" : "❤️",
876+
"serial" : "01746632464399-000@cbfVqJopQBorrt95348450:000",
877+
"type" : "reaction:distinct.v1"
878+
}
879+
</pre>
880+
881+
A message summary event is also broadcast to the channel after adding or removing one or more annotations.
882+
883+
749884
h2(#realtime-api). Chat Realtime API
750885

751886
This section describes the message formats for chat events that occur over a Realtime connection.
@@ -871,6 +1006,11 @@ h4(#chat-structs-message-v2). Messages V2
8711006
"bar": 1
8721007
}
8731008
},
1009+
},
1010+
"reactions": {
1011+
"unique": {"like": {"total": 2, "clientIds": ["userOne", "userTwo"]}, "love": {"total": 1, "clientIds": ["userThree"]}},
1012+
"distinct": {"like": {"total": 2, "clientIds": ["userOne", "userTwo"]}, "love": {"total": 1, "clientIds": ["userOne"]}},
1013+
"multiple": {"like": {"total": 5, "clientIds": {"userOne": 3, "userTwo": 2}}, "love": {"total": 10, "clientIds": {"userOne": 10}}},
8741014
}
8751015
}
8761016
</pre>
@@ -887,6 +1027,106 @@ Determining the global order of messages may be achieved by lexicographically co
8871027

8881028
Determining the global order of message versions may be achieved by lexicographically comparing the @version@. See @CHA-M10@ for more information.
8891029

1030+
When keeping a @Message@ updated, use the @Message.with(event)@ method to apply events to ensure correctness. The @with@ method returnes message instances with the event applied to them. If the event is not applicable due to being for an older version of the message, the method will return the message unchanged. If the event is applicable, a new instance will be returned with the event applied. @Message.with()@ correctly handles message reactions. See @CHA-M11@ for more information.
1031+
1032+
1033+
h3(#chat-structs-message-reactions-summary-event). Message reactions reaction summary
1034+
1035+
The @MessageReactionSummaryEvent@ interface provides information about reaction summaries for messages.
1036+
1037+
* The event must include a @type@ field set to indicate it's a reaction summary event.
1038+
* The event must include a @summary@ object containing:
1039+
** The @messageSerial@ identifying which message the reactions belong to.
1040+
** A @unique@ field containing reaction summaries for unique-type reactions.
1041+
** A @distinct@ field containing reaction summaries for distinct-type reactions.
1042+
** A @multiple@ field containing reaction summaries for multiple-type reactions.
1043+
1044+
Example:
1045+
1046+
<pre>
1047+
{
1048+
type: "reaction.summary",
1049+
summary: {
1050+
messageSerial: "01726585978590-001@abcdefghij:001",
1051+
"unique": {
1052+
"like": {
1053+
"total": 2,
1054+
"clientIds": ["userOne", "userTwo"]
1055+
},
1056+
"love": {
1057+
"total": 1,
1058+
"clientIds": ["userThree"]
1059+
}
1060+
},
1061+
"distinct": {
1062+
"like" : {
1063+
"clientIds" : [
1064+
"userOne",
1065+
"userTwo"
1066+
],
1067+
"total" : 2
1068+
},
1069+
"love" : {
1070+
"clientIds" : [
1071+
"userOne"
1072+
],
1073+
"total" : 1
1074+
}
1075+
},
1076+
"multiple": {
1077+
"like" : {
1078+
"clientIds" : {
1079+
"userOne" : 3,
1080+
"userTwo" : 2
1081+
},
1082+
"total" : 5
1083+
},
1084+
"love" : {
1085+
"clientIds" : {
1086+
"userOne" : 10
1087+
},
1088+
"total" : 10
1089+
}
1090+
}
1091+
}
1092+
}
1093+
</pre>
1094+
1095+
1096+
h3(#chat-structs-message-reactions-raw-event). Message reactions raw reaction event
1097+
1098+
The @MessageReactionRawEvent@ interface provides information about individual message reaction events.
1099+
* The event must include a @type@ field indicating whether a reaction was added or removed.
1100+
* The event must include a @timestamp@ field containing the date/time when the event occurred.
1101+
* The event must include a @reaction@ object containing:
1102+
** A @messageSerial@ identifying which message the reaction belongs to.
1103+
** A @type@ field indicating the reaction type (unique, distinct, or multiple).
1104+
** A @name@ field containing the name of the reaction (e.g. emoji string).
1105+
** An optional @count@ field for reactions of type Multiple.
1106+
** A @clientId@ identifying the user who added or removed the reaction.
1107+
1108+
<pre>
1109+
{
1110+
type: "reaction.create",
1111+
timestamp: DateTime(),
1112+
reaction: {
1113+
messageSerial: "01726585978590-001@abcdefghij:001",
1114+
type: "reaction:multiple.v1",
1115+
reaction: ":like:",
1116+
count: 3,
1117+
clientId: "user1",
1118+
};
1119+
}
1120+
</pre>
1121+
1122+
Event @type@ can be @reaction.update@ or @reaction.delete@.
1123+
1124+
Event @reaction.type@ can be @reaction:unique.v1@, @reaction:distinct.v1@ or @reaction:multiple.v1@.
1125+
1126+
@reaction.count@ is optional and only set for @reaction:multiple.v1@.
1127+
1128+
1129+
8901130
h3(#chat-structs-ephemeral-reactions). Ephemeral Room Reactions
8911131

8921132
<pre>

0 commit comments

Comments
 (0)