-
Notifications
You must be signed in to change notification settings - Fork 398
MSC2409: Proposal to send typing, presence and receipts to appservices #2409
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
turt2live
merged 29 commits into
matrix-org:old_master
from
Sorunome:soru+hs/appservice-edus
Oct 28, 2024
Merged
Changes from 17 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
96213b5
Initial proposal commit
Half-Shot c70ba2b
Add body of proposal
Half-Shot 553837c
Merge branch 'hs/appservice-edus' of https://github.com/Half-Shot/mat…
Sorunome 771cafe
rename file
Sorunome 7912fda
finish up MSC
Sorunome 9339848
address issues
Sorunome 49f2087
change key names and add unstable prefix
Sorunome 4a06e25
Merge branch 'master' into soru+hs/appservice-edus
turt2live fdee029
Clarifications; to-device handling
turt2live 231084d
It's not exactly like sync
turt2live 0c794bc
Move to-device messages
turt2live 9d20145
Copy edu_type behaviour
turt2live 91436e4
Add full transaction example
turt2live ce393b1
Add implementation notes for to-device cleanup
turt2live c21f86a
Use type instead of edu_type to match realities of implementations
Half-Shot 15f4582
Add note to say ephemeral can be omitted.
Half-Shot d1783c4
Improve wording on why we use a seperate array.
Half-Shot f4b1ec8
push_ephemeral -> receive_ephemeral
tulir 3a8fc4d
Fix some typos and clarify EDU room association
tulir 18abe04
Clarify EDU formatting
tulir 5989fc8
Explicitly list all event types
tulir d7fb52a
Delete to-device events
tulir 7057ba0
Update spec link and fix typo
tulir 20501b4
Add private read receipt rules
tulir 5a745fd
Apply suggestions from code review
tulir fa4d518
Wrap lines
tulir 5431045
Apply suggestions from code review
tulir 842c44e
Explicitly mention to-device events are not here
tulir 94e605e
Mention the possibility of more granular filtering
tulir File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
# MSC2409: Proposal to send EDUs to appservices | ||
Half-Shot marked this conversation as resolved.
Show resolved
Hide resolved
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
*Node: This proposal is a continuation of [MSC1888](https://github.com/matrix-org/matrix-doc/pull/1888) | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
and deprecates that one.* | ||
|
||
The [appservice /transactions API](https://matrix.org/docs/spec/application_service/r0.1.2#put-matrix-app-v1-transactions-txnid) | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
currently supports pushing PDU events (regular message and state events) | ||
however it doesn't provison for EDU events (typing, presence and more). This means that bridges cannot | ||
react to Matrix users who send any typing or presence information in a room the service is part of. | ||
|
||
There is an interest amongst the community to have equal bridging on both sides of a bridge, so that | ||
read reciepts and typing notifications can be seen on the remote side. To that end, this proposal | ||
specifies how these can be pushed to an appservice. | ||
turt2live marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Proposal | ||
|
||
### Changes to the registration file | ||
|
||
In order that appservices don't get flooded with EDUs, appservices have to opt-in to receive them by | ||
setting `push_ephemeral` to true. A registration file could look like following: | ||
turt2live marked this conversation as resolved.
Show resolved
Hide resolved
Half-Shot marked this conversation as resolved.
Show resolved
Hide resolved
tulir marked this conversation as resolved.
Show resolved
Hide resolved
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```yaml | ||
id: "IRC Bridge" | ||
url: "http://127.0.0.1:1234" | ||
as_token: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46" | ||
hs_token: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e" | ||
sender_localpart: "_irc_bot" | ||
# We want to receive EDUs | ||
push_ephemeral: true | ||
namespaces: | ||
users: | ||
- exclusive: true | ||
regex: "@_irc_bridge_.*" | ||
aliases: | ||
- exclusive: false | ||
regex: "#_irc_bridge_.*" | ||
rooms: [] | ||
``` | ||
|
||
### Changes to the /transactions/ API | ||
|
||
The `PUT /_matrix/app/v1/transactions/{txnId}` API currently supports sending PDUs | ||
via the `events` array. | ||
|
||
```json | ||
{ | ||
"events": [ | ||
{ | ||
"content": { | ||
"membership": "join", | ||
"avatar_url": "mxc://domain.com/SEsfnsuifSDFSSEF#auto", | ||
"displayname": "Alice Margatroid" | ||
}, | ||
"type": "m.room.member", | ||
"event_id": "$143273582443PhrSn:domain.com", | ||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com", | ||
"sender": "@example:domain.com", | ||
"origin_server_ts": 1432735824653, | ||
"unsigned": { | ||
"age": 1234 | ||
}, | ||
"state_key": "@alice:domain.com" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
This proposal would extend the `PUT /_matrix/app/v1/transactions/` endpoint to include a new key | ||
`ephemeral` to behave similar to the various sections of the CS API `/sync` endpoint. The `ephemeral` key | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
MAY be omitted entirely if there are ephemeral no events to send. | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```json | ||
{ | ||
"ephemeral": [ | ||
turt2live marked this conversation as resolved.
Show resolved
Hide resolved
richvdh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
"type": "m.typing", | ||
turt2live marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com", | ||
"content": { | ||
"user_ids": [ | ||
"@alice:example.com" | ||
] | ||
} | ||
}, | ||
{ | ||
"type": "m.receipt", | ||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com", | ||
"content": { | ||
"$1435641916114394fHBLK:matrix.org": { | ||
"m.read": { | ||
"@rikj:jki.re": { | ||
"ts": 1436451550453 | ||
} | ||
} | ||
} | ||
} | ||
} | ||
], | ||
"events": [ | ||
// ... | ||
] | ||
} | ||
``` | ||
|
||
The reason for a new key rather than bundling the events into `events` is that | ||
existing appservices may mistake them for PDUs and might behave erratically. | ||
While `events` may now be a somewhat misleading name, this is an acceptable tradeoff. | ||
|
||
Note that the EDU is otherwise formatted as it would for client-server API transport. | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
To-device messages are a bit special as they are aimed at a particular user/device ID | ||
combo. These events are annotated by the server with a `to_device_id` and `to_user_id` | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
field at the top level of the message for transport to the appservice: | ||
|
||
```json5 | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
"type": "org.example.to_device_event_type", | ||
"sender": "@alice:example.com", | ||
"to_user_id": "@_irc_bob:example.org", | ||
"to_device_id": "ABCDEF123", | ||
"content": { | ||
"hello": "world" | ||
} | ||
} | ||
``` | ||
|
||
Unlike other ephemeral events, to-device messages are included at a top level `to_device` | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
array in the transaction. If there are no messages to be sent, the array can be omitted. | ||
Half-Shot marked this conversation as resolved.
Show resolved
Hide resolved
|
||
This is primarily due to how to-device messages work over federation: they get wrapped in | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
an EDU (`m.direct_to_device`) but that parent EDU is stripped out before sending the message | ||
off to clients. This can lead to potential conflict where if down the line we support EDUs | ||
and to-device messages with the same event type: consumers would be uncertain as to whether | ||
they are handling an EDU or to-device message. | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
A complete example of the transaction with all 3 arrays populated would be: | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```json5 | ||
{ | ||
"ephemeral": [ | ||
{ | ||
"type": "m.typing", | ||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com", | ||
"content": { | ||
"user_ids": [ | ||
"@alice:example.com" | ||
] | ||
} | ||
} | ||
], | ||
"events": [ | ||
{ | ||
"content": { | ||
"membership": "join", | ||
"avatar_url": "mxc://domain.com/SEsfnsuifSDFSSEF#auto", | ||
"displayname": "Alice Margatroid" | ||
}, | ||
"type": "m.room.member", | ||
"event_id": "$143273582443PhrSn:domain.com", | ||
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com", | ||
"sender": "@example:domain.com", | ||
"origin_server_ts": 1432735824653, | ||
"unsigned": { | ||
"age": 1234 | ||
}, | ||
"state_key": "@alice:domain.com" | ||
} | ||
], | ||
"to_device": [ | ||
{ | ||
"type": "org.example.to_device_event_type", | ||
"sender": "@alice:example.com", | ||
"to_user_id": "@_irc_bob:example.org", | ||
"to_device_id": "ABCDEF123", | ||
"content": { | ||
"hello": "world" | ||
} | ||
} | ||
] | ||
} | ||
``` | ||
|
||
### Expectations of when an EDU should be pushed to an appservice | ||
|
||
It is not clear at face value what should be pushed to an appservice. Appservices claim | ||
namespaces of users which registers "interest" in the rooms where those users reside, as | ||
well as claiming namespaces of rooms for explicit interest. However, not all EDUs are | ||
associated with a single room (presence, etc). | ||
|
||
If the EDU is capable of being associated to a particular room, it should be sent to the | ||
appservice under the same rules as regular events (interest in the room means sending it). | ||
For EDUs which are not associated with a particular room, the appservice receives the EDU | ||
if it contextually *would* apply. For example, a presence update for a user an appservice | ||
shares a room with (or is under the appservice's namespace) would be sent to the appservice. | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
To-device messages for devices belonging to the appservice's user namespaces should always | ||
be sent. | ||
|
||
### Implementation detail: when to delete a to-device message | ||
|
||
Not defined by this MSC is an explicit algorithm for when to delete a to-device message (mark | ||
it as sent). This is left as an implementation detail, though a suggested approach is as | ||
follows: | ||
|
||
* If the message is sent to a user under an appservice's *exclusive* namespace, mark it as sent | ||
and delete it. Note that retried transactions will still need to include the message. | ||
* If the message is sent to a user under an appservice's *inclusive* namespace, mark it as sent | ||
to the appservice but do not delete it until a `/sync` request is completed which includes the | ||
message. Note that retried transactions will still need to include the message. | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
This approach is largely to align with how namespaces are used by appservices in practice, but | ||
is not applicable to all scenarios (and thus is an implementation detail). The majority of known | ||
appservices use exclusive namespaces, which typically also means that those users will not be | ||
calling `/sync`. Because of this, the server may never get another opportunity to delete the | ||
messages until it has confirmed that the appservice received the transaction successfully. Inclusive | ||
namespaces are typically used when the appservice wants to impact a subset of users, but without | ||
controlling those users explicitly. Typically, inclusive users are also calling `/sync` and so | ||
the appservice should be CC'd on the to-device messages that would normally go down `/sync`. | ||
|
||
## Potential issues | ||
|
||
Determining which EDUs to transmit to the appservice could lead to quite some overhead on the | ||
homeservers side. Additionally, more network traffic is produced, potentially straining the local | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
network and the appservice more. As such, appservices have to opt-in to receive EDUs. | ||
|
||
## Security considerations | ||
Sorunome marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
The homeserver needs to accuratley determine which EDUs to send to the appservice, as to not leak | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
any metadata about users. Particularly `m.presence` could be tricky, as no `room_id` is present in | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
that EDU. | ||
tulir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Unstable prefix | ||
|
||
In the transaction body, instead of `ephemeral`, `de.sorunome.msc2409.ephemeral` is used. | ||
|
||
In the transaction body, instead of `to_device`, `de.sorunome.msc2409.to_device` is used. | ||
|
||
In the registration file, instead of `push_ephemeral`, `de.sorunome.msc2409.push_ephemeral` is used. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.