-
Notifications
You must be signed in to change notification settings - Fork 413
MSC2946: Spaces Summary #2946
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
Merged
MSC2946: Spaces Summary #2946
Changes from 4 commits
Commits
Show all changes
77 commits
Select commit
Hold shift + click to select a range
059f324
Spaces Summary
kegsay 14eb56c
MSC2946
kegsay aea5336
Clarity
kegsay 7618ed6
More clarity
kegsay 6e051d5
Clarify what no room data means for clients
kegsay 619c100
Federation API
kegsay 104cf78
Update 2946-spaces-summary.md
kegsay 8f6fb9d
auto_join filter
kegsay 200147c
Blurb on auth for fed api
kegsay f2457cf
Update to reflect MSC1772 changes
kegsay 1430661
Mention auth chain on federation api
kegsay 09b0848
Add 'version' field
kegsay 7b2f3dc
Stripped state; remove room versions
kegsay 6224859
Update 2946-spaces-summary.md
kegsay 211e5e6
Update proposals/2946-spaces-summary.md
kegsay 725277e
Replace with link to draft doc.
richvdh 0fd8d8d
Add a preamble and copy the current draft API.
clokep dee9040
Switch to using stable identifiers (and add an unstable identifiers s…
clokep a3b62a8
Updates / clarifications.
clokep f28ad9b
Fix typo.
clokep d911c82
Clean-ups.
clokep 74f12d5
Update proposals/2946-spaces-summary.md
ara4n 8b1fe00
Drop unstable identifiers from MSC1772.
clokep 8fdbfb1
Various updates and clarifications.
clokep f145fa3
Include the origin_server_ts in the response, as needed by MSC1772.
clokep f9c00a5
Rename a parameter for clarity.
clokep 9c2e85a
Fix typo.
clokep 760cda8
Various clarifications based on feedback.
clokep a5ad9a4
Add auth / rate-limiting info.
clokep 4c10e02
Combine some double spaces.
clokep ad5af4d
Use only GET endpoints.
clokep dba41f9
Add notes about DoS potential.
clokep 8a968eb
Tweaks from review.
clokep b379c42
Add context about why stripped events are returned.
clokep 27f526c
Remove some implementation details.
clokep c142433
Add notes on ordering.
clokep af8c7b0
Remove unnecessary data.
clokep bcde9e0
Clarify the server-server API.
clokep 328ae81
More clarifications.
clokep 518db51
Remove obsolete note.
clokep 3b0051f
Some clarifications to what accessible means.
clokep 5cd8270
Update notes about sorting to include the origin_server_ts of the m.s…
clokep 797dda4
Only consider `m.space` rooms and do not return links to nowhere.
clokep 105fd93
Updates based on MSC3173 merging and updates to MSC3083.
clokep a7a08eb
Updates per MSC2403.
clokep 094de30
Remove field which is not part of the C-S API.
clokep c0a63ab
Rewrite the proposal.
clokep 3d7769f
Handle todo comments.
clokep 5627721
Update URLs.
clokep 7d0c8f6
Rename field.
clokep 420d698
Updates based on implementation.
clokep 5cd0db4
Clarify the state which is persisted.
clokep 14bdc42
Expand notes about errors.
clokep 00d3d67
Update MSC with pagination parameter.
clokep e39eac3
Fix wrong endpoint.
clokep 6823998
Clarifications based on implementation.
clokep 5a5a404
Remove empty section.
clokep 0174348
Fix typo.
clokep 545ff90
Rename field in example.
clokep 42ba46e
Clarify error code.
clokep dee3b2d
Clarify ordering changes.
clokep a9803c3
Clarify wording.
clokep e9592ff
Fix typos.
clokep 8978562
Clarify that rooms do not belong to servers.
clokep 622f8ed
Fix example to use correct URL.
clokep 6ad9ead
Clarify using local vs. remote data.
clokep 482597e
Clarify bits aboud stripped state.
clokep 41bfaa5
Clarify access control of federation responses.
clokep f6f41b1
Clarify error code.
clokep 828c076
Be less prescriptive about expiring data.
clokep 7fd45e5
Limit must be non-zero.
clokep 902a124
Rate limiting.
clokep bf5f84d
Add a note about room upgrades.
clokep b43333a
Update stable URLs per MSC2844.
clokep c74adf7
Clarify federation return values.
clokep fe5a9a7
Clarify `origin_server_ts`.
clokep a9f6cf6
Tweak wording around `inaccessible_children`.
clokep 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,187 @@ | ||
| ### Spaces Summary API | ||
|
|
||
| *This MSC depends on [MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772).* | ||
|
|
||
| Spaces are rooms with `m.space` as the [room type](https://github.com/matrix-org/matrix-doc/pull/1840). | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Spaces can include state events to specify parent/child relationships. | ||
| These relationships point to other rooms, which may themselves be spaces. | ||
| This means spaces can have subspaces and rooms. This creates a graph: a space directory. | ||
|
|
||
| This MSC defines a new endpoint which can be used to reveal information about the space directory. | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Consider the graph: | ||
| ``` | ||
| A | ||
| ^ | ||
| |___ | ||
| | | | ||
| V V | ||
| B R1 | ||
| ^ | ||
| | | ||
| V | ||
| R2 | ||
|
|
||
| R1,R2 = rooms | ||
| A,B = spaces | ||
| <--> = parent/child relationship events | ||
| ``` | ||
| This MSC aims to create a way for clients to produce a tree view along the lines of: | ||
| ``` | ||
| Space A | ||
| | | ||
| |___ Room 1 | ||
| | | ||
| Space B | ||
| | | ||
| |___ Room 2 | ||
| ``` | ||
| Clients are able to do this currently by peeking into all of these rooms | ||
| (assuming they have permission to) but this is costly and slow. | ||
|
|
||
| #### Client API | ||
|
|
||
| ``` | ||
| POST /_matrix/client/r0/rooms/{roomID}/spaces | ||
richvdh marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| "max_rooms_per_space": 5, // The maximum number of rooms/subspaces to return for a given space, if negative unbounded. default: -1. | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "limit": 100, // The maximum number of rooms/subspaces to return, server can override this, default: 100. | ||
kegsay marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "batch": "opaque_string" // A token to use if this is a subsequent HTTP hit, default: "". | ||
| } | ||
| ``` | ||
|
|
||
| which returns: | ||
|
|
||
| ``` | ||
| { | ||
| "next_batch": "opaque string", | ||
kegsay marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "rooms": [ | ||
| { | ||
| "aliases": [ | ||
| "#murrays:cheese.bar" | ||
| ], | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "avatar_url": "mxc://bleeker.street/CHEDDARandBRIE", | ||
| "guest_can_join": false, | ||
| "name": "CHEESE", | ||
| "num_joined_members": 37, | ||
| "room_id": "!ol19s:bleecker.street", | ||
| "topic": "Tasty tasty cheese", | ||
| "world_readable": true, | ||
|
|
||
| "num_refs": 42, | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "room_type": "m.space" | ||
kegsay marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }, | ||
| { ... } | ||
| ], | ||
| "events": [ | ||
richvdh marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| "type": "m.space.child", | ||
| "state_key": "!efgh:example.com", | ||
| "content": { | ||
| "via": ["example.com"], | ||
| "present": true, | ||
| "order": "abcd", | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "default": true | ||
| } | ||
| }, | ||
| { | ||
| "type": "m.room.parent", | ||
| "state_key": "", | ||
| "content": { | ||
| "room_id": "!space:example.com", | ||
| "via": ["example.com"] | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| Justifications for the request API shape are as follows: | ||
| - The HTTP path: Spaces are scoped to a specific room to act as an anchor point for | ||
| navigating the directory. Alternatives are `/r0/spaces` with `room_id` inside the | ||
| body, but this feels less idiomatic for room-scoped requests. | ||
| - The HTTP method: there's a lot of data to provide to the server, and GET requests | ||
| shouldn't have an HTTP body, hence opting for POST. The same request can produce | ||
| different results over time so PUT isn't acceptable as an alternative. | ||
| - `max_rooms_per_space`: UIs can only display a set number of rooms per space, so allowing | ||
| clients to specify this limit is desirable. Subsequent rooms can be obtained by paginating. | ||
| The graph has 2 distinct types of nodes, and some UIs may want to weight one type above | ||
| the other. However, it's impossible to always know what type of node a given room ID falls | ||
| under because the server may not be joined to that room (to determine the room type) or the | ||
| caller may not have permission to see this information. | ||
| - `limit`: The maximum number of events to return in `events`. It is desirable for clients | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| and servers to be able to put a maximum cap on the amount of data returned to the client. | ||
| **This limit may be exceeded if the root room has `> limit` rooms.** | ||
| - `batch`: Required for pagination. Could be a query parameter but it's easier if | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| request data is in one place. | ||
|
|
||
| Justifications for the response API shape are as follows: | ||
| - `rooms`: These are the nodes of the graph. The objects in the array are exactly the same as `PublicRoomsChunk` in the | ||
| [specification](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-publicrooms) | ||
| as the information displayed to users is the same. There are two _additional_ keys | ||
| which are: | ||
| * `num_refs` which is the total number of state events which point to or from this room (inbound/outbound edges). | ||
| This includes all `m.space.child` events in the room, _in addition to_ `m.room.parent` events which point to | ||
| this room as a parent. | ||
| * `room_type` which is the room type, which is `m.space` for subspaces. It can be omitted if there is no room type | ||
| in which case it should be interpreted as a normal room. | ||
| - `events`: These are the edges of the graph. The objects in the array are complete (or stripped?) `m.room.parent` | ||
| or `m.space.child` events. | ||
| - `next_batch`: Its presence indicates that there are more results to return. | ||
|
|
||
| Server behaviour: | ||
| - Extract the room ID from the request. Sanity check request data. Begin walking the graph | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| starting with the room ID in the request in a queue of unvisited rooms according to the | ||
| following rules: | ||
| * If this room has already been processed, skip. NB: do not remember this between calls, | ||
| as servers will need to visit the same room more than once to return additional events. | ||
| * Is the caller currently joined to the room or is the room `world_readable`? | ||
| If no, skip this room. If yes, continue. | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * If this room has not ever been in `rooms` (across multiple requests), extract the | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| `PublicRoomsChunk` for this room. | ||
| * Get all `m.space.child` and `m.room.parent` state events for the room. *In addition*, get | ||
| all `m.space.child` and `m.room.parent` state events which *point to* (via `state_key` or `content.room_id`) | ||
kegsay marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| this room. This requires servers to store reverse lookups. Add the total number of events | ||
| to `PublicRoomsChunk` under `num_refs`. Add `PublicRoomsChunk` to `rooms`. | ||
| * If this is the root room from the original request, insert all these events into `events` if | ||
| they haven't been added before (across multiple requests). | ||
| * Else add them to `events` honouring the `limit` and `max_rooms_per_space` values. If either | ||
| are exceeded, stop adding events. If the event has already been added, do not add it again. | ||
| * Mark this room as processed. | ||
| * For each referenced room ID in the events being returned to the caller (both parent and child) | ||
| add the room ID to the queue of unvisited rooms. Loop from the beginning. | ||
| - This guarantees that all edges for the root node are given to the client. Not all edges of subspaces | ||
| will be returned, nor will edges of all rooms be returned. This can be detected by clients in two ways: | ||
| * Comparing `num_refs` with the *total number* of edges pointing to/from the room. | ||
| * Comparing the number of `m.space.child` state events in the room with `max_rooms_per_space`, where | ||
| `max_rooms_per_space` is 1 greater than the actual desired maximum value. | ||
| - If not all events were returned due to reaching a `limit` or `max_rooms_per_space`, return a | ||
| `next_batch` token. The server SHOULD NOT return duplicate events or rooms on subsequent | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| requests: this can be achieved by remembering the event/room IDs returned to the caller between calls. | ||
| This results in each request uncovering more nodes/edges until the entire tree has been explored. | ||
|
|
||
|
|
||
| Client behaviour: | ||
| - Decide which room should be the root of the tree, then call this endpoint with the root room ID. | ||
| - The data in `rooms` determines _what_ to show. The events in `events` determine _where_ to show it. | ||
| Take all the data in `rooms` and key them by room ID. | ||
| - Loop through the `events` and keep track of parent->child relationships by looking at the `room_id` | ||
clokep marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| of the event and the `state_key` which is the child room ID. Clients may want to treat | ||
| child->parent relationships (`m.room.parent` events) the same way or differently. Treating them the | ||
| same way will guarantee that the entire graph is exposed on the UI, but can cause issues because it | ||
| can result in multiple roots (a child can refer to a new unknown parent). If a child->parent relationship | ||
| exists but a corresponding parent->child relationship does not exist, this room is a "secret" room which | ||
| should be indicated as such. If a parent->child relationship exists but a corresponding child->parent | ||
| relationship does not exist, this room is a "user-curated collection" and should be indicated as such. | ||
| Persist the mappings in a map: one child can have multiple parents and one parent can have multiple | ||
| children. | ||
| - Starting at the root room ID: | ||
| * Compare the `num_refs` value in `rooms.$room_id` to the total number of events which reference this | ||
| room in `events` (across all rooms). If they differ, a partial response has been returned for this | ||
| space and additional results should be loaded when required. The API guarantees that *all* events for | ||
| the root room ID will be returned, regardless of how many events there are (even if they exceed `limit`). | ||
| * Lookup all children for this room ID. For each child: | ||
| - If the child is a room (not a space, check the `room_type` field), look up the room data from | ||
| `rooms` and render it. | ||
| - Else the child is a space, render the space as a heading (using the room name/topic) and | ||
| restart the lookup using the new space room ID. | ||
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.