0571d395b5
* a very very WIP first cut of peeking via MSC2753. doesn't yet compile or work. needs to actually add the peeking block into the sync response. checking in now before it gets any bigger, and to gather any initial feedback on the vague shape of it. * make PeekingDeviceSet private * add server_name param * blind stab at adding a `peek` section to /sync * make it build * make it launch * add peeking to getResponseWithPDUsForCompleteSync * cancel any peeks when we join a room * spell out how to runoutside of docker if you want speed * fix SQL * remove unnecessary txn for SelectPeeks * fix s/join/peek/ cargocult fail * HACK: Track goroutine IDs to determine when we write by the wrong thread To use: set `DENDRITE_TRACE_SQL=1` then grep for `unsafe` * Track partition offsets and only log unsafe for non-selects * Put redactions in the writer goroutine * Update filters on writer goroutine * wrap peek storage in goid hack * use exclusive writer, and MarkPeeksAsOld more efficiently * don't log ascii in binary at sql trace... * strip out empty roomd deltas * re-add txn to SelectPeeks * re-add accidentally deleted field * reject peeks for non-worldreadable rooms * move perform_peek * fix package * correctly refactor perform_peek * WIP of implementing MSC2444 * typo * Revert "Merge branch 'kegan/HACK-goid-sqlite-db-is-locked' into matthew/peeking" This reverts commit 3cebd8dbfbccdf82b7930b7b6eda92095ca6ef41, reversing changes made to ed4b3a58a7855acc43530693cc855b439edf9c7c. * (almost) make it build * clean up bad merge * support SendEventWithState with optional event * fix build & lint * fix build & lint * reinstate federated peeks in the roomserver (doh) * fix sql thinko * todo for authenticating state returned by /peek * support returning current state from QueryStateAndAuthChain * handle SS /peek * reimplement SS /peek to prod the RS to tell the FS about the peek * rename RemotePeeks as OutboundPeeks * rename remote_peeks_table as outbound_peeks_table * add perform_handle_remote_peek.go * flesh out federation doc * add inbound peeks table and hook it up * rename ambiguous RemotePeek as InboundPeek * rename FSAPI's PerformPeek as PerformOutboundPeek * setup inbound peeks db correctly * fix api.SendEventWithState with no event * track latestevent on /peek * go fmt * document the peek send stream race better * fix SendEventWithRewrite not to bail if handed a non-state event * add fixme * switch SS /peek to use SendEventWithRewrite * fix comment * use reverse topo ordering to find latest extrem * support postgres for federated peeking * go fmt * back out bogus go.mod change * Fix performOutboundPeekUsingServer * Fix getAuthChain -> GetAuthChain * Fix build issues * Fix build again * Fix getAuthChain -> GetAuthChain * Don't repeat outbound peeks for the same room ID to the same servers * Fix lint * Don't omitempty to appease sytest Co-authored-by: Kegan Dougal <kegan@matrix.org> Co-authored-by: Neil Alexander <neilalexander@users.noreply.github.com> |
||
---|---|---|
.. | ||
consumers | ||
internal | ||
notifier | ||
routing | ||
storage | ||
streams | ||
sync | ||
types | ||
README.md | ||
syncapi.go |
Sync API Server
This server is responsible for servicing /sync
requests. It gets its data from the room server output log. Currently, the sync server will:
- Return a valid
/sync
response for the user represented by the providedaccess_token
. - Return a "complete sync" if no
since
value is provided, and return a validnext_batch
token. This contains all rooms the user has been invited to or has joined. For joined rooms, this includes the complete current room state and the most recent 20 (hard-coded) events in the timeline. - For "incremental syncs" (a
since
value is provided), as you get invited to, join, or leave rooms they will be reflected correctly in the/sync
response. - For very large state deltas, the
state
section of a room is correctly populated with the state of the room at the start of the timeline. - When you join a room, the
/sync
which transitions your client to be "joined" will include the complete current room state as per the specification. - Only wake up user streams it needs to wake up.
- Honours the
timeout
query parameter value.
Internals
When the server gets a /sync
request, it needs to:
- Work out which rooms to return to the client.
- For each room, work out which events to return to the client.
The logic for working out which rooms is based on Synapse:
- Get the CURRENT joined room list for this user.
- Get membership list changes for this user between the provided stream position and now.
- For each room which has membership list changes:
- Check if the room is 'newly joined' (insufficient to just check for a join event because we allow dupe joins). If it is, then we need to send the full room state down (and 'limited' is always true).
- Check if user is still CURRENTLY invited to the room. If so, add room to 'invited' block.
- Check if the user is CURRENTLY left/banned. If so, add room to 'archived' block.
- Add joined rooms (joined room list)
For each room, the /sync response returns the most recent timeline events and the state of the room at the start of the timeline.
The logic for working out which events is not based entirely on Synapse code, as it is known broken with respect to working out
room state. In order to know which events to return, the server needs to calculate room state at various points in the history of
the room. For example, imagine a room with the following 15 events (letters are state events (updated via '
), numbers are timeline events):
index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 (1-based indexing as StreamPosition(0) represents no event)
timeline [A, B, C, D, 1, 2, 3, D', 4, D'', 5, B', D''', D'''', 6]
The current state of this room is: [A, B', C, D'''']
.
If this room was requested with ?since=14&limit=5
then 1 timeline event would be returned, the most recent one:
15
[ 6 ]
If this room was requested with ?since=9&limit=5
then 5 timeline events would be returned, the most recent ones:
11 12 13 14 15
[5, B', D''', D'''', 6]
The state of the room at the START of the timeline can be represented in 2 ways:
- The
full_state
from index 0 :[A, B, C, D'']
(aka the state between 0-11 exclusive) - A partial state from index 9 :
[D'']
(aka the state between 9-11 exclusive)
Servers advance state events (e.g from D'
to D''
) based on the state conflict resolution algorithm.
You might think that you could advance the current state by just updating the entry for the (event type, state_key)
tuple
for each state event, but this state can diverge from the state calculated using the state conflict resolution algorithm.
For example, if there are two "simultaneous" updates to the same state key, that is two updates at the same depth in the
event graph, then the final result of the state conflict resolution algorithm might not match the order the events appear
in the timeline.
The correct advancement for state events is represented by the AddsStateEventIDs
and RemovesStateEventIDs
that
are in OutputRoomEvents
from the room server.
This version of the sync server uses very simple indexing to calculate room state at various points.
This is inefficient when a very old since
value is provided, or the full_state
is requested, as the state delta becomes
very large. This is mitigated slightly with indexes, but better data structures could be used in the future.
Known Issues
m.room.history_visibility
is not honoured: it is always treated as "shared".- All ephemeral events are not implemented (presence, typing, receipts).
- Account data (both user and room) is not implemented.
to_device
messages are not implemented.- Back-pagination via
prev_batch
is not implemented. - The
limited
flag can lie. - Filters are not honoured or implemented. The
limit
for each room is hard-coded to 20. - The
full_state
query parameter is not implemented. - The
set_presence
query parameter is not implemented. - "Ignored" users are not ignored.
- Redacted events are still sent to clients.
- Invites over federation (if it existed) won't work as they aren't "real" events and so won't be in the right tables.
invite_state
is not implemented (for similar reasons to the above point).- The current implementation scales badly when a very old
since
token is provided. - The entire current room state can be re-sent to the client if they send a duplicate "join" event which should be a no-op.