From 087c74ee88115d3b0bc8fea05d3d6538044efd4f Mon Sep 17 00:00:00 2001 From: Timo Date: Mon, 20 May 2024 12:55:21 +0200 Subject: [PATCH] Add usecase specific section. Add event type to the body Add event id template variable --- proposals/4140-delayed-events-futures.md | 158 +++++++++++++++++------ 1 file changed, 120 insertions(+), 38 deletions(-) diff --git a/proposals/4140-delayed-events-futures.md b/proposals/4140-delayed-events-futures.md index 630771be7..c157b077d 100644 --- a/proposals/4140-delayed-events-futures.md +++ b/proposals/4140-delayed-events-futures.md @@ -17,7 +17,7 @@ A generic way in which one can automate expirations is desired. The described usecase is solved if we allow to send an event in advance to the homeserver but let the homeserver compute when its actually added to the -dag. +DAG. The condition for actually sending the delayed event would could be a timeout. ## Proposal @@ -30,21 +30,28 @@ since any event that will be sent once expired can be defined. We call those events `Futures`. A new endpoint is introduced: -`PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}/future` -and -`PUT /_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}/future` +`PUT /_matrix/client/v3/rooms/{roomId}/send/future/{txnId}` It behaves exactly like the normal send endpoint except that that it allows to send a list of event contents. The body looks as following: ```json { "m.timeout": 10, - "m.send_on_timeout": {...sendEventBody}, - - "m.send_on_action:${actionName}": {...sendEventBody}, + "m.send_on_timeout": { + "content": sendEventBody0, + "type": "m.room.message", + }, + + "m.send_on_action:${actionName}": { + "content": sendEventBody1, + "type": "m.room.message" + }, // optional - "m.send_now": {...sendEventBody}, + "m.send_now": { + "content": sendEventBody2, + "type": "m.room.message" + }, } ``` @@ -59,75 +66,79 @@ This guarantees that all tokens will expire eventually. The homeserver can set a limit to the timeout and return an error if the limit is exceeded. +### Response + The response will mimic the request: ```json { - "m.send_on_timeout": { "eventId": "id_hash" }, "m.send_on_action:${actionName}": { "eventId": "id_hash" }, - + "future_token": "token", - + // optional - "m.send_now": { "eventId": "id_hash"}, + "m.send_now": { "eventId": "id_hash" } } ``` +### Delegating futures + The `token` can be used to call another future related endpoint: `PUT /_matrix/client/v3/futures/refresh` and `PUT /_matrix/client/v3/futures/action/${actionName}`. where the body is: ```json { - "future_token":"token" + "future_token": "token" } ``` The information required to call this endpoint is very limited so that almost no metadata is leaked. This allows to share a refresh link to a different -service (an SFU for instance) that can track the current client connection state, +service. This allows to delegate the send time. An SFU for instance, that tracks the current client connection state, and pings the HS to refresh and call a dedicated action to communicate that the user has intentionally left the conference. The homeserver does the following when receiving a Future. -- It sends the optional `m.send_now` event. -- It generates a `future_token` and stores it alongside with the time -of retrieval, the event list and the timeout duration. -- Starts a timer for the stored `future_token`. - - If a `PUT /_matrix/client/v3/futures/refresh` is received, the - timer is restarted with the stored timeout duration. - - If a `PUT /_matrix/client/v3/futures/action/${actionName}` is received, one of - the associated `m.action:${actionName}` - event will be send. - - If the timer times out, the one of the `m.send_timeout` event will be sent. - - If the future - - is a state event (`PUT /_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}/future`) - - and includes a `m.send_now` event - +- It **sends** the optional `m.send_now` event. +- It **generates** a `future_token` and stores it alongside with the time + of retrieval, the event list and the timeout duration. +- **Starts a timer** for the stored `future_token`. + + - If a `PUT /_matrix/client/v3/futures/refresh` is received, it + **restarts the timer** with the stored timeout duration. + - If a `PUT /_matrix/client/v3/futures/action/${actionName}` is received, it **sends the associated action event** + `m.action:${actionName}`. + - If the timer times out, **it sends the timeout event** `m.send_timeout`. + - If the future is a state event and includes a `m.send_now` event the future is only valid while the `m.send_now` - is still the current state. This means, if the homeserver receives - a new state event for the same state key, the `future_token` - gets invalidated and the associated timer is stopped. + is still the current state: + + - This means, if the homeserver receives + a new state event for the same state key, the **`future_token`** + **gets invalidated and the associated timer is stopped**. + - There is no race condition here since a possible race between timeout and - new event will always converge to the new event: + new event will always converge to the new event: - Timeout -> new event: the room state will be updated twice. once by - the content of the `m.send_on_timeout` event but later with the new event. + the content of the `m.send_on_timeout` event but later with the new event. - new event -> timeout: the new event will invalidate the future. No -- When a timeout or action future is sent, the homeserver stops the associated -timer and invalidates (deletes) the `future_token`. + +- After the homeservers sends a timeout or action future event, the associated + timer and `future_token` is canceled/invalidated. So for each Future the client sends, the homeserver will send one event conditionally at an unknown time that can trigger logic on the client. This allows for any generic timeout logic. - Timed messages/reminders or ephemeral events could be implemented using this where - clients send a redact as a future or a room event with intentional mentions. +Timed messages/reminders or ephemeral events could be implemented using this where +clients send a redact as a future or a room event with intentional mentions. In some scenarios it is important to allow to send an event with an associated future at the same time. @@ -143,6 +154,78 @@ future at the same time. For this usecase an optional `m.send_now` field can be added to the body. +## Usecase specific considerations + +### MatrixRTC + +We want can use the actions and the timeout for matrix rtc for the following situations + +- If the client takes care of its membership, we use a short timeout value (around 5-20 seconds) + The client will have to ping the refresh endpoint approx every 2-19 seconds. +- When the SFU is capable of taking care of managing our connection state and we trust the SFU to + not disconnect a really long value can be chosen (approx. 2-10hours). The SFU will then only send + an action once the user disconnects or looses connection (it could even be a different action for both cases + handling them differently on the client) + This significantly reduces the amount of calls for the `/future` endpoint since the sfu only needs to ping + once per session (per user) and every 2-5hours (instead of every `X` seconds.) + +### Self destructing messages + +This MSC also allows to implement self destructing messages: + +`PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}` + +```json +{ + "m.text": "my msg" +} +``` + +`PUT /_matrix/client/v3/rooms/{roomId}/send/future/{txnId}` + +```json +{ + "m.timeout": 10*60, + "m.send_on_timeout": { + "type":"m.room.readact", + "content":{ + "redacts": "EvId" + } + } +} +``` + +## EventId template variable + +It would be useful to be able to send redactions and edits as one http request. +This would make sure that the client cannot loose connection after sending the first event. +For instance sending a self destructing message without the redaction. + +The optional proposal is to introduce template variables that are only valid in `Future` events. +`$m.send_now.event_id` in the content of one of the `m.send_on_action:${actionName}` and +`m.send_on_timeout` contents this template variable can be used. +The **Self destructing messages** example would simplify to: + +`PUT /_matrix/client/v3/rooms/{roomId}/send/future/{txnId}` + +```json +{ + "m.send_now":{ + "type":"m.room.message", + "content":{ + "m.text": "my msg" + } + }, + "m.timeout": 10*60, + "m.send_on_timeout": { + "type":"m.room.readact", + "content":{ + "redacts": "$m.send_now.event_id" + } + } +} +``` + ## Potential issues ## Alternatives @@ -181,4 +264,3 @@ even tell with which room or user it is interacting. ## Unstable prefix ## Dependencies -