CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Test (windows-latest) (push) Canceled after 0s
CI / Storage tests on PostgreSQL (push) Canceled after 0s
CI / Complement (federation off) (push) Canceled after 0s
CI / golangci-lint (push) Canceled after 0s
CI / Smoke test the binary (push) Canceled after 0s
Implements PLAN.md Phase 10. Simplified Sliding Sync (MSC4186) is served at the unstable org.matrix.simplified_msc3575 endpoint and advertised in /versions. Lists are sorted by activity and filtered by DM, invite, encryption, room type, space and tag; room subscriptions, required_state with wildcards, $ME and $LAZY, and the to_device, e2ee, account_data, receipts and typing extensions are supported. Per-connection state is kept in memory and an unknown pos answers M_UNKNOWN_POS. Threads and relations: m.relates_to is indexed on roomserver_events (migration 0012), /relations (with recursion) and /threads are served, and every event a timeline read returns carries its m.thread, m.replace and m.reference summaries in unsigned.m.relations. Notifications carry a thread ID (migration 0013): threaded receipts clear only their thread, and sync reports unread_thread_notifications when the filter asks. Spaces: /hierarchy walks a space breadth first, asking other servers about rooms this one is not in through the new federation hierarchy endpoint; room_summary describes one room. /search runs on FTS5 (sqlite, pocketbase) or tsvector (postgres), bounded to what each user may see, with context, profiles, state, grouping and paging. The PocketBase driver is real: the sqlite schema and store on an embedded PocketBase app's database, with media in its filesystem, local or S3 (database.pocketbase.s3). It runs the full storage test suite. Ops: OpenTelemetry tracing over OTLP/HTTP (tracing.*), with server spans per route, component spans, and trace propagation on federation, push and application service calls. New metrics for persisted events, waiting syncs, sliding sync connections and the database pool, with a Grafana dashboard. deploy/ adds a Compose setup (PostgreSQL, Prometheus, Grafana, Jaeger) and a Helm chart; cmd/warp-loadtest loads a server and reports request and delivery latencies. The load tester found a long-standing bug, fixed here: on a server where no account data had been written, every incremental /sync re-sent the push rules and returned at once, and an all-zero token was taken for an initial sync, so long polls became busy loops. The PostgreSQL migrations and search dialect compile but were not run against a live PostgreSQL in this change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
4.0 KiB
Markdown
86 lines
4.0 KiB
Markdown
# Spaces
|
|
|
|
A space is a room whose create event says `"type": "m.space"`, and whose
|
|
`m.space.child` state events name the rooms in it. As with relations, the
|
|
authorisation rules know nothing of it: a child event is a pointer, and
|
|
the room it points at need not know. What the server provides is the walk.
|
|
|
|
The code is in `internal/roomserver/hierarchy.go`.
|
|
|
|
## `GET /_matrix/client/v1/rooms/{roomID}/hierarchy`
|
|
|
|
The space's tree, breadth first, a page at a time. Each room is described
|
|
the way the public room directory describes it — name, topic, avatar,
|
|
alias, member count, join rule, room type, room version and encryption —
|
|
plus its `children_state`: the `m.space.child` events, each with its
|
|
`origin_server_ts`.
|
|
|
|
| Parameter | |
|
|
|---|---|
|
|
| `max_depth` | How far below the root to go; `0` is the root alone. Capped at 50. |
|
|
| `suggested_only` | Follow only children marked `"suggested": true`. |
|
|
| `limit` | Rooms per page: 50 by default, 100 at most. |
|
|
| `from` | The previous page's `next_batch`. |
|
|
|
|
Children are visited in the spec's order: those with a valid `order` (printable ASCII, at most 50 characters) by that string, then by when the child event was sent, then by room ID.
|
|
A child event whose `via` is missing or empty is how a space removes a
|
|
child — a state event cannot be deleted, only emptied — and is skipped.
|
|
Only a space's children are walked into: an ordinary room that happens to
|
|
hold an `m.space.child` event is not a space.
|
|
|
|
Paging walks from the root again and skips what earlier pages returned.
|
|
That keeps the server free of per-walk state, and a walk is capped at 2000
|
|
rooms whatever the page size, which bounds the cost of the last page of a
|
|
very large space.
|
|
|
|
### Who sees what
|
|
|
|
A room is shown to a user who:
|
|
|
|
- is joined to it or invited to it; or
|
|
- may know about it anyway: its join rule is `public`, `knock` or
|
|
`knock_restricted`, or its history is world-readable; or
|
|
- is joined to one of the rooms a `restricted` room lets in.
|
|
|
|
Everything else is left out, and so are its children. The root itself is
|
|
the exception: a space the user may not see is `403`.
|
|
|
|
### Rooms this server is not in
|
|
|
|
A child this server is not in is asked about over federation, of the
|
|
servers its `via` names, with `GET /_matrix/federation/v1/hierarchy`. The
|
|
answer is remembered for the rest of the walk. The other server has
|
|
already judged the room for this server as a whole; Warp then checks a
|
|
restricted room's allow list against its own user. A child that no server
|
|
will describe is left out. With federation off, rooms this server is not
|
|
in are simply not shown.
|
|
|
|
## `GET /_matrix/federation/v1/hierarchy/{roomID}`
|
|
|
|
Another server walking one of Warp's spaces: the room and the children
|
|
Warp is in, each judged for the asking server. A room is shown to a server
|
|
when anybody could be shown it (see above), when it is restricted — with
|
|
`allowed_room_ids`, so the asking server can check its own users — or
|
|
when a user of that server is joined or invited. Children it may not see
|
|
are listed in `inaccessible_children`. A root it may not see is `404`,
|
|
which is also the answer for a room Warp is not in.
|
|
|
|
## `GET /_matrix/client/v1/room_summary/{roomIDOrAlias}`
|
|
|
|
One room's face, for a link preview or an invite: the same fields as a
|
|
hierarchy room without its children, plus the user's `membership`
|
|
(`leave` for a user who was never in it). An alias is resolved first, and
|
|
the servers it names are added to `?via=`. The same visibility rules apply;
|
|
a room the user may not see is `403`.
|
|
|
|
The endpoint is in the spec from v1.15. Warp still advertises v1.14,
|
|
because v1.15 also brought requirements Warp does not meet yet.
|
|
|
|
## What is deliberately missing
|
|
|
|
| Thing | Why |
|
|
|---|---|
|
|
| Unauthenticated `room_summary` | The spec allows it for guests; Warp asks for a token. |
|
|
| Caching other servers' hierarchy answers between walks | Each walk asks again; a space with many remote children costs a federation request per child per page. |
|
|
| `m.space.parent` checks | Parent events are state like any other, and are not used to validate children. |
|