0
0
Fork 0
mirror of https://github.com/matrix-org/dendrite synced 2024-09-18 08:58:56 +02:00
dendrite/syncapi
jjj333_p 8c6cf51b8f
Fixing Presence Conflicts (#3320)
This is meant to cache client presence for a moment so that it doesn't
oscillate.

Currently Dendrite just federates out whatever presence it gets from the
sync loop, which means if theres any clients attempting to sync without
setting the user online, and there is an online client, it will just
flip back and forth each time one of the clients polls /sync.

This pull request essentially stores in a map when the client last set
online ideally to allow the online client to sync again and set an
online presence before setting idle or offline.

I am not great at programming nor am I familiar with this codebase so if
this pr is just shitwater feel free to discard, just trying to fix an
issue that severely bothers me. If it is easier you can also steal the
code and write it in yourself. I ran the linter, not sure that it did
anything, the vscode go extension seems to format and lint anyways.

I tried to run unit tests but I have no idea any of this thing. it
errors on
`TestRequestPool_updatePresence/same_presence_is_not_published_dummy2
(10m0s)` which I think making this change broke. I am unsure how to
comply, if y'all point me in the right direction ill try to fix it. I
have tested it with all the situations I can think of on my personal
instance pain.agency, and this seems to stand up under all the
previously bugged situations.

~~My go also decided to update a bunch of the dependencies, I hate git
and github and have no idea how to fix that, it was not intentional.~~ i
just overwrote them with the ones from the main repo and committed it,
seems to have done what was needed.

### Pull Request Checklist

<!-- Please read
https://matrix-org.github.io/dendrite/development/contributing before
submitting your pull request -->

* [x] I have added Go unit tests or [Complement integration
tests](https://github.com/matrix-org/complement) for this PR _or_ I have
justified why this PR doesn't need tests
* [x] Pull request includes a [sign off below using a legally
identifiable
name](https://matrix-org.github.io/dendrite/development/contributing#sign-off)
_or_ I have already signed off privately

Signed-off-by: `Joseph Winkie <jjj333.p.1325@gmail.com>`

---------

Co-authored-by: Till Faelligen <2353100+S7evinK@users.noreply.github.com>
2024-08-03 22:03:39 +02:00
..
consumers Fix: Edited messages appear twice in fulltext search (#3363) 2024-07-27 22:30:17 +02:00
internal Fix tests for x86 (#3214) 2023-09-28 14:50:31 +02:00
notifier Update gmsl to use new validated RoomID on PDUs (#3200) 2023-09-15 14:39:06 +00:00
producers Introduce a new stream for the appservice consumer (#3277) 2023-12-12 12:13:55 +01:00
routing Limit filter to limit/2 for before/after events on /context (#3332) 2024-02-20 07:38:51 +00:00
storage More rows.Close() and rows.Err() (#3262) 2023-11-09 08:42:33 +01:00
streams Only fetch events once for all rooms (#3311) 2024-01-25 20:10:46 +01:00
sync Fixing Presence Conflicts (#3320) 2024-08-03 22:03:39 +02:00
synctypes Complement fixes for pseudoIDs (#3206) 2023-09-26 17:44:49 +00:00
types Fix x86 tests (#3317) 2024-01-29 20:44:43 +01:00
README.md use go module for dependencies (#594) 2019-05-21 21:56:55 +01:00
syncapi.go Introduce a new stream for the appservice consumer (#3277) 2023-12-12 12:13:55 +01:00
syncapi_test.go Fix: Edited messages appear twice in fulltext search (#3363) 2024-07-27 22:30:17 +02:00

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 provided access_token.
  • Return a "complete sync" if no since value is provided, and return a valid next_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:

  1. Get the CURRENT joined room list for this user.
  2. Get membership list changes for this user between the provided stream position and now.
  3. 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.
  4. 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.