Synchronization of delivery status

When we send a message to a conversation, the delivery status must be explicit and understandable for the end user. So, Jami must offer the possibility to know if the message was delivered to the other members of a conversation and synchronize this status (sent and displayed) across devices.

How it works (backend)

The status of messages is stored in the conversation layer via the variable messagesStatus (map<string, map<string, string>) with the following structure:

{uri, {
         {"fetch", "commitId"},
         {"fetched_ts", "timestamp"},
         {"read", "commitId"},
         {"read_ts", "timestamp"}
      }
}

The fetch status is the commitId of the last message fetched by the member. The fetched_ts is the timestamp of the last message fetched by the member. The read status is the commitId of the last message read by the member. The read_ts is the timestamp of the last message read by the member.

When a member fetches a message, the fetch status is updated with the commitId of the message and the fetched_ts is updated with the timestamp of the message. When a member reads a message, the read status is updated with the commitId of the message and the read_ts is updated with the timestamp of the message. This information is synced across devices and other devices will update their internal structure if the timestamp is newer.

This information is stored in conversation_data/xxxxxxxxx/status.

Client API

The client should get status from the current SwarmMessage structure when loading conversation and update the status via AccountMessageStatusChanged. In AccountMessageStatusChanged the client will have the commitId, peer uri and new status. So, this will correspond to message.status[uri].

SwarmMessage’s status structure is:

{
    {uri, status},
    {uri2, status2}
}

Where uri is the peer uri and status is the status of the message for this peer (from the MessageStates enum).

When sending a new message, the status map can be empty (because no one fetched). By default, if there is no fetch/read information for a message, the message MUST be considered as sending. The global status of a message is the maximum of the status of all members except ourselves. For example, if Alice sends a message and we have:

status = {alice: displayed, bob: sending, carl: sent}

The global status is sent.

Notes for client

  • If the client wants to show which message is the last read message for a member, they must check the index when responding to AccountMessageStatusChanged. Because this signal can emit that a previous message is displayed later.

  • The status of a message can be used to create a detailed view of who received/displayed a specific message. However, timestamps of those events are not stored, because this would represent too much data.