Before sorting, activities are grouped as a unit:
- Activities within the same part grouping are inserted next to each other
- Order is based on the
positionproperty - Logical timestamp of the part grouping is the "maximum logical timestamp" of all parts
- Parts can contain livestream session or ungrouped activities
- Order is based on the
- Activities within the same livestream session will be inserted next to each other
- Order is based on the
streamSequenceproperty - Logical timestamp of the livestream session is the logical timestamp of the finalizing activity (if any), or the logical timestamp of the first activity
- In other words, livestream will be reordered when they are inserted for the first time, or when they are finalized
- Interim updates will not reorder the livestream to avoid too much flickering
- Order is based on the
- All other activities are not grouped, they are individual units
Short answer: activities are sorted by logical timestamp when inserted.
Long answer:
- For grouped activities (such as part groupings or livestream sessions), all activities within the group are treated as a unit
- For ungrouped activities, each activity is a unit on its own
Units are sorted using their logical timestamp on insertion. If the unit is already in the chat history, they will be removed before being re-inserted.
By logical timestamp, in JavaScript:
logicalTimestamp = activity.channelData['webchat:sequence-id'] ?? +new Date(activity.timestamp) || +new Date(activity.localTimestamp);
activity.channelData['webchat:sequence-id']: number- This field represents the order of the activity in the chat history and can be a sparse number;
- This field is OPTIONAL, but RECOMMENDED;
- This field MUST be an integer number;
- This field MUST be a unique number assigned by the chat service;
- This field SHOULD be consistent across all members of the conversation.
- Otherwise,
activity.timestamp: string- This field represents the server timestamp of the activity;
- This field is REQUIRED;
- This field MUST be an ISO date-time string, for example,
2000-01-23T12:34:56.000Z; - This field MUST be assigned by the chat service, a.k.a. server timestamp;
- This field SHOULD have resolution up to 1 millisecond;
- This field MUST be the same across all members of the conversation.
- Otherwise,
activity.localTimestamp: string- This field represents the local timestamp of an outgoing activity;
- This field is REQUIRED for all outgoing activities;
- This field MUST be an ISO date-time string, for example,
2000-01-23T12:34:56.000Z; - This field MUST be assigned by the sender, a.k.a. Web Chat;
- This field SHOULD have resolution up to 1 millisecond;
- This field MUST be the same across all members of the conversation.
The following documentation is archived.
Web Chat sort activities based on a few sort keys stamped by the chat service, with the following fallback order:
activity.channelData['webchat:sequence-id']: number- This field represents the order of the activity in the chat history and can be a sparse number;
- This field is OPTIONAL, but RECOMMENDED;
- This field MUST be an integer number;
- This field MUST be an unique number assigned by the chat service;
- This field SHOULD be consistent across all members of the conversation.
- Otherwise,
activity.timestamp: string- This field represents the server timestamp of the activity.
- This field is REQUIRED;
- This field MUST be an ISO date time string, for example,
2000-01-23T12:34:56.000Z; - This field MUST be assigned by the chat service, a.k.a. server timestamp;
- This field SHOULD have resolution up to 1 millisecond;
- This field MUST be the same across all members of the conversation.
Whenever an activity is updated, Web Chat will remove the existing activity from the chat history, then insert the updated version based on the new sort keys from the updated activity.
When an activity transit from "sending" state to "sent" state, it will trigger an update. Thus, it is possible and expected that, an activity could initially appear at a certain position. When it is updated, it could move to a new position to make it consistent with other members of the conversation.
Since both all forementioned sort keys are assigned by the server, when the user is sending out a message, both sort keys are not available for sorting until Web Chat receive a server copy of the activities.
Web Chat will use the following algorithm to determine the temporal value of these activity-in-transit. This algorithm is applied when Web Chat is posting an activity to the chat service.
activity.channelData['webchat:sequence-id']: number- Find the largest sequence ID in the current chat history;
- Increment it by
0.001; - Assign the value to the activity-in-transit.
activity.timestamp: string- This field MUST be undefined.
activity.localTimestamp: string- This field is based on local clock;
- This field MUST be an ISO date time string;
- This field is used to determine if the chat service timed out while posting the activity.
Note: Web Chat assumes the chat service should not backlog more than 1,000 activities at a time.
After the activity-in-transit arrives at the chat service, the chat service MUST update the sort keys and send the updated activity back to Web Chat.
Combining the algorithms above, Web Chat has the following assumptions
- For all activities
activity.channelData['webchat:sequence-id']SHOULD be set- If unset, Web Chat will fill this value using epoch of
activity.timestamp
- If unset, Web Chat will fill this value using epoch of
- For activities from self
- For activity-in-transit
activity.localTimestampMUST be setactivity.timestampMUST beundefinedor unset
- For activity that has a server copy, a.k.a. successfully sent
activity.localTimestampis optionalactivity.timestampMUST be set
- For activity-in-transit
- For activities from others
activity.localTimestampis optionalactivity.timestampMUST be set
- Pull requests
- Posting an activity,
sagas/postActivitySaga.ts - Inserting an activity into the chat history,
reducers/activities.ts - Activity type,
types/WebChatActivity.ts