@@ -19,102 +19,119 @@ time window after a user disconnected.
1919
2020## Proposal
2121
22- Events can contain a ` "m.will_expire": "running" | "expired" | "ended" ` field.
23- This is marking the event as expired ` "m.will_expire": "expired" | "ended" ` or as
24- still alive ` "m.will_expire": "running" ` .
25- This field lives outside the ciphertext content (hence it also works for encrypted
26- events) and is set via the usual ` PUT ` request if the content contains the additional
27- ` "m.will_expire": 10 ` field (similar how it is done with relations), with the desired
28- timeout duration in seconds.
22+ The proposed solution is to allow sending multiple presigned events and delegate
23+ the control of when to actually send these events to an external services.
2924
30- Request
25+ We call those events ` Futures ` .
26+
27+ A new endpoint is introduced:
28+ ` PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}/future `
29+ and
30+ ` PUT /_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}/future `
31+ It behaves exactly like the normal send endpoint except that that it allows
32+ to send a list of event contents. The body looks as following:
3133
3234``` json
3335{
34- "m.will_expire" : 10 ,
35- "body" : " hello"
36+ "m.timeout" : 10 ,
37+ "m.send_on_timeout" : {...sendEventBody },
38+
39+ "m.send_on_action:${actionName}" : {...sendEventBody },
40+
41+ // optional
42+ "m.send_now" : {...sendEventBody },
3643}
3744```
3845
39- If the homeserver detects a ` m.will_expire ` field it will store and distribute the
40- event as hiding the timeout duration:
46+ Each of the ` sendEventBody ` objects are exactly the same as sending a normal
47+ event.
4148
42- ``` json
43- {
44- "content" :{
45- "m.will_expire" : " running" ,
46- "body" : " hello" ,
47- },
48- "other_fields" :" sender, origin_server_ts ..."
49- }
50- ```
49+ There can be an arbitrary amount of ` actionName ` s.
50+
51+ All of the fields are optional except the ` timeout ` and the ` send_on_timeout ` .
52+ This guarantees that all tokens will expire eventually.
53+
54+ The homeserver can set a limit to the timeout and return an error if the limit
55+ is exceeded.
5156
52- The response to the client will be :
57+ The response will mimic the request :
5358
5459``` json
5560{
56- "eventId" : " id_hash" ,
57- "expire_refresh_token" : " refresh_hash" ,
61+
62+ "m.send_on_timeout" : {
63+ "eventId" : " id_hash"
64+ },
65+ "m.send_on_action:${actionName}" : {
66+ "eventId" : " id_hash"
67+ },
68+
69+ "timeout_refresh_token" : " refresh_token" ,
70+
71+ // optional
72+ "m.send_now" : { "eventId" : " id_hash" },
5873}
5974```
6075
61- The default response is extended with the ` expire_refresh_token ` which
62- can be used to reset the expiration timeout (in this example 10 seconds).
63- A new unauthenticated endpoint is introduced:
64- ` PUT /_matrix/client/v3/expiration/{refresh_method} `
65- where the ` refresh_method ` is one of: ` [refresh, end] `
66- The body contains the refresh token so the homeserver knows what to refresh.
76+ The ` refresh_token ` can be used to call another future related endpoint:
77+ ` PUT /_matrix/client/v3/futures/refresh ` and ` PUT /_matrix/client/v3/futures/action/${actionName} ` .
78+ where the body is:
6779
6880``` json
6981{
70- "expire_refresh_token" : " refresh_hash " ,
82+ "timeout_refresh_token" : " refresh_token "
7183}
7284```
7385
7486The information required to call this endpoint is very limited so that almost
7587no metadata is leaked. This allows to share a refresh link to a different
7688service (an SFU for instance) that can track the current client connection state,
77- and pings the HS to refresh and informs the HS about a disconnect.
89+ and pings the HS to refresh and call a dedicated action to communicate
90+ that the user has intentionally left the conference.
7891
79- The homeserver does the following when receiving an event with ` m.will_expire `
92+ The homeserver does the following when receiving a Future.
8093
94+ - It sends the optional ` m.send_now ` event.
8195- It generates a token and stores it alongside with the time of retrieval,
82- the eventId and the expire duration.
96+ the list of events and the expire duration.
8397- Starts a timer for the stored expiration token.
84- - If a ` PUT /_matrix/client/v3/expiration /refresh ` is received, the
98+ - If a ` PUT /_matrix/client/v3/futures /refresh ` is received, the
8599 timer is restarted with the stored expire duration.
86- - If a ` PUT /_matrix/client/v3/expiration/end ` is received, the
100+ - If a ` PUT /_matrix/client/v3/futures/action/${actionName} ` is received, the
87101 event _ gets ended_ .
88102 - If the timer times out, the event _ gets expired_ .
89103 - If the event is a state event only the latest/current state is considered. If
90- the homeserver receives a new state event without ` m.will_expire ` but with the
91- same state key, the expire_refresh_token gets invalidated and the associated timer
92- is stopped.
104+ the homeserver receives a new state event for the same state key, the ` timeout_refresh_token `
105+ gets invalidated and the associated timer is stopped.
93106
94107The event _ gets expired_ /_ gets ended_ means:
95108
96- - The homeserver ** sends a new event** that is a copy of the previous event but:
97- - If it gets _ expired_ the event will include: ` "m.will_expire": "expired" `
98- - If it gets _ ended_ the event will include: ` "m.will_expire": "ended" ` .
99- - Additionally it includes a relation to the original event with ` rel_type: "m.expire.relationship" `
100-
101- ``` json
102- "m.relates_to" : {
103- "event_id" : " $original_event" ,
104- "rel_type" : " m.expire.relationship"
105- },
106- "m.will_expire" : " ended" | "expired",
107- ```
109+ - The homeserver ** sends one of** the possible events:
110+ - If it _ gets expired_ the ` m.timeout ` event will be sent.
111+ - If it _ gets ended_ with an action, the associated: ` m.action:${actionName} `
112+ event will be send.
113+ - The homeserver stops the associated timer and invalidates (deletes) the ` timeout_refresh_token `
114+
115+ So for each Future the client sends, the homeserver will send one event
116+ conditionally at an unknown time that can trigger logic on the client.
117+ This allows for any generic timeout logic.
108118
109- - The homeserver stops the associated timer and invalidates (deletes) the `expire_refresh_token`
119+ Timed messages/reminders or ephemeral events could be implemented using this where
120+ clients send a redact as a future or a room event with intentional mentions.
110121
111- So for each event that is sent with `m.will_expire: X` where X is duration in
112- seconds > 0. The homeserver will sent another event which can be used to trigger
113- logic on the client. This allows for any generic timeout logic.
122+ In some scenarios it is important to allow to send an event with an associated
123+ future at the same time.
114124
115- Timed messages/reminders could also be implemented using this where clients ignore
116- the `"will_expire":"running"` events for a specific event type but render the
117- `"will_expire":"expired"` events.
125+ - One example would be redacting an event. It only makes sense to redact the event
126+ if it exists.
127+ It might be important to have the guarantee, that the redact is received
128+ by the server at the time where the original message is sent.
129+ - In the case of a state event we might want to set the state to ` A ` and after a
130+ timeout reset it to ` {} ` . If we have two separate request sending ` A ` could work
131+ but the event with content ` {} ` could fail. The state would not automatically
132+ reset to ` {} ` .
133+
134+ For this usecase an optional ` m.send_now ` field can be added to the body.
118135
119136## Potential issues
120137
@@ -126,28 +143,6 @@ an indicator to determine if the event is expired. Instead of letting the SFU
126143inform about the call termination or using the call app ping loop like we propose
127144here.
128145
129- ---
130- It might not be necessary to change the value of `"m.will_expire" = 10` to
131- `"m.will_expire" = "running"` it makes it easier to understand and also
132- hides more potential metadata but it is questionable if that bring any benefit.
133-
134- ---
135- The name `m.will_expire` has been chosen since it communicates that it becomes
136- invalid. And that it is an event that automatically changes state
137- (`will_expire` vs `expired`). But it does not imply what expired vs non expired
138- means, it is flexible in how can be used.
139- Alternatives could by:
140-
141- - `m.alive`
142- - pro: communicates it might change (alive is always temporal)
143- - con: ver strong bias on how to use it `valid/invalid`
144- - `m.timeout`
145- - pro: very unbiased in how its used - timeout over can also mean the client
146- will show a reminder.
147- - pro: clear that it has something to do with time.
148- - con: not so clear the homeserver will automatically do sth.
149- - con: not so clear that this timeout can be refreshed?
150-
151146## Security considerations
152147
153148We are using unauthenticated endpoint to refresh the expirations. Since we use
0 commit comments