Change the server aggregation for edits (#1440)
per matrix-org/matrix-spec-proposals#3925
This commit is contained in:
parent
bdc87784a1
commit
acb631d3d6
2 changed files with 42 additions and 33 deletions
1
changelogs/client_server/newsfragments/1440.feature
Normal file
1
changelogs/client_server/newsfragments/1440.feature
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Changes to the server-side aggregation of `m.replace` (edit) events, as per [MSC3925](https://github.com/matrix-org/matrix-spec-proposals/pull/3925).
|
|
@ -133,13 +133,6 @@ being overwritten entirely by `m.new_content`, with the exception of `m.relates_
|
||||||
which is left *unchanged*. Any `m.relates_to` property within `m.new_content`
|
which is left *unchanged*. Any `m.relates_to` property within `m.new_content`
|
||||||
is ignored.
|
is ignored.
|
||||||
|
|
||||||
{{% boxes/note %}}
|
|
||||||
Note that server implementations must not *actually* overwrite
|
|
||||||
the original event's `content`: instead the server presents it as being overwritten
|
|
||||||
when it is served over the client-server API. See [Server-side replacement of content](#server-side-replacement-of-content)
|
|
||||||
below.
|
|
||||||
{{% /boxes/note %}}
|
|
||||||
|
|
||||||
For example, given a pair of events:
|
For example, given a pair of events:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
@ -195,14 +188,17 @@ replacement event.
|
||||||
|
|
||||||
##### Server-side aggregation of `m.replace` relationships
|
##### Server-side aggregation of `m.replace` relationships
|
||||||
|
|
||||||
|
{{< changed-in v="1.7" >}}
|
||||||
|
|
||||||
Note that there can be multiple events with an `m.replace` relationship to a
|
Note that there can be multiple events with an `m.replace` relationship to a
|
||||||
given event (for example, if an event is edited multiple times). These should
|
given event (for example, if an event is edited multiple times). These should
|
||||||
be [aggregated](#aggregations) by the homeserver.
|
be [aggregated](#aggregations) by the homeserver.
|
||||||
|
|
||||||
The aggregation format of `m.replace` relationships gives the `event_id`,
|
The aggregation format of `m.replace` relationships gives the **most recent**
|
||||||
`origin_server_ts`, and `sender` of the **most recent** replacement event. The
|
replacement event, formatted [as normal](#room-event-format).
|
||||||
most recent event is determined by comparing `origin_server_ts`; if two or more
|
|
||||||
replacement events have identical `origin_server_ts`, the event with the
|
The most recent event is determined by comparing `origin_server_ts`; if two or
|
||||||
|
more replacement events have identical `origin_server_ts`, the event with the
|
||||||
lexicographically largest `event_id` is treated as more recent.
|
lexicographically largest `event_id` is treated as more recent.
|
||||||
|
|
||||||
This aggregation is bundled under the `unsigned` property as `m.relations` for any
|
This aggregation is bundled under the `unsigned` property as `m.relations` for any
|
||||||
|
@ -211,49 +207,61 @@ event that is the target of an `m.replace` relationship. For example:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"event_id": "$original_event_id",
|
"event_id": "$original_event_id",
|
||||||
// irrelevant fields not shown
|
"type": "m.room.message",
|
||||||
|
"content": {
|
||||||
|
"body": "I really like cake",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"formatted_body": "I really like cake"
|
||||||
|
},
|
||||||
"unsigned": {
|
"unsigned": {
|
||||||
"m.relations": {
|
"m.relations": {
|
||||||
"m.replace": {
|
"m.replace": {
|
||||||
"event_id": "$latest_edit_event_id",
|
"event_id": "$latest_edit_event_id",
|
||||||
"origin_server_ts": 1649772304313,
|
"origin_server_ts": 1649772304313,
|
||||||
"sender": "@editing_user:localhost"
|
"sender": "@editing_user:localhost"
|
||||||
|
"type": "m.room.message",
|
||||||
|
"content": {
|
||||||
|
"body": "* I really like *chocolate* cake",
|
||||||
|
"msgtype": "m.text",
|
||||||
|
"m.new_content": {
|
||||||
|
"body": "I really like *chocolate* cake",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"m.relates_to": {
|
||||||
|
"rel_type": "m.replace",
|
||||||
|
"event_id": "$original_event_id"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// irrelevant fields not shown
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If the original event is
|
If the original event is [redacted](#redactions), any
|
||||||
[redacted](#redactions), any
|
|
||||||
`m.replace` relationship should **not** be bundled with it (whether or not any
|
`m.replace` relationship should **not** be bundled with it (whether or not any
|
||||||
subsequent replacements are themselves redacted). Note that this behaviour is
|
subsequent replacements are themselves redacted). Note that this behaviour is
|
||||||
specific to the `m.replace` relationship. See also [redactions of edited
|
specific to the `m.replace` relationship. See also [redactions of edited
|
||||||
events](#redactions-of-edited-events) below.
|
events](#redactions-of-edited-events) below.
|
||||||
|
|
||||||
##### Server-side replacement of content
|
**Note:** the `content` of the original event is left intact. In particular servers
|
||||||
|
should **not** replace the content with that of the replacement event.
|
||||||
|
|
||||||
Whenever an `m.replace` is to be bundled with an event as above, the server
|
{{ boxes/rationale }}
|
||||||
should also modify the content of the original event according to the
|
In previous versions of the specification, servers were expected to replace the
|
||||||
`m.new_content` of the most recent replacement event (determined as above).
|
content of an edited event whenever it was served to clients (with the
|
||||||
|
exception of the
|
||||||
An exception applies to [`GET /_matrix/client/v3/rooms/{roomId}/event/{eventId}`](#get_matrixclientv3roomsroomideventeventid),
|
[`GET /_matrix/client/v3/rooms/{roomId}/event/{eventId}`](#get_matrixclientv3roomsroomideventeventid)
|
||||||
which should return the unmodified event (though the relationship should still
|
endpoint). However, that behaviour made reliable client-side implementation
|
||||||
be bundled, as described above).
|
difficult, and servers should no longer make this replacement.
|
||||||
|
{{ /boxes/rationale }}
|
||||||
|
|
||||||
#### Client behaviour
|
#### Client behaviour
|
||||||
|
|
||||||
Clients can often ignore `m.replace` events, because any events returned
|
Since the server will not replace the content of any edited events, clients
|
||||||
by the server to the client will be updated by the server to account for
|
should take note of any replacement events they receive, and apply the
|
||||||
subsequent edits.
|
replacement whenever possible and appropriate.
|
||||||
|
|
||||||
However, clients should apply the replacement themselves when the server is
|
|
||||||
unable to do so. This happens in the following situations:
|
|
||||||
|
|
||||||
* The client has already received and stored the original event before the
|
|
||||||
message edit event arrives.
|
|
||||||
|
|
||||||
* The original event (and hence its replacement) are encrypted.
|
|
||||||
|
|
||||||
Client authors are reminded to take note of the requirements for [Validity of
|
Client authors are reminded to take note of the requirements for [Validity of
|
||||||
replacement events](#validity-of-replacement-events), and to ignore any
|
replacement events](#validity-of-replacement-events), and to ignore any
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue