-
-
Notifications
You must be signed in to change notification settings - Fork 625
Add support for /hierarchy API and fall back to /spaces API if needed #1818
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
Changes from 4 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
d49d693
Add support for /children API and fall back to /spaces API if M_UNREC…
t3chguy 21a357c
fix typo
t3chguy 58c60d8
Refactor Space Hierarchy stuff in preparation for pagination
t3chguy 88b8b24
Merge room hierarchy pages
t3chguy db212a5
Update to latest version of MSC2946 API s/next_token/next_batch/
t3chguy fc78e63
Fix RoomHierarchy comments
t3chguy d91d1ce
Apply suggestions from code review
t3chguy 14b424e
Merge branch 'develop' of github.com:matrix-org/matrix-js-sdk into t3…
t3chguy 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
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
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,161 @@ | ||
/* | ||
Copyright 2021 The Matrix.org Foundation C.I.C. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
/** | ||
* @module room-hierarchy | ||
*/ | ||
|
||
import { Room } from "./models/room"; | ||
import { IHierarchyRoom, IHierarchyRelation } from "./@types/spaces"; | ||
import { MatrixClient } from "./client"; | ||
import { EventType } from "./@types/event"; | ||
|
||
export class RoomHierarchy { | ||
// Map from room id to list of servers which are listed as a via somewhere in the loaded hierarchy | ||
public readonly viaMap = new Map<string, Set<string>>(); | ||
// Map from room id to list of rooms which claim this room as their child | ||
public readonly backRefs = new Map<string, string[]>(); | ||
// Map from room id to object | ||
public readonly roomMap = new Map<string, IHierarchyRoom>(); | ||
private loadRequest: ReturnType<MatrixClient["getRoomHierarchy"]>; | ||
private nextToken?: string; | ||
private _rooms?: IHierarchyRoom[]; | ||
private serverSupportError?: Error; | ||
|
||
/** | ||
* Construct a new EventTimeline | ||
* | ||
* TODO | ||
* <p>An EventTimeline represents a contiguous sequence of events in a room. | ||
* | ||
* <p>As well as keeping track of the events themselves, it stores the state of | ||
* the room at the beginning and end of the timeline, and pagination tokens for | ||
* going backwards and forwards in the timeline. | ||
* | ||
* <p>In order that clients can meaningfully maintain an index into a timeline, | ||
* the EventTimeline object tracks a 'baseIndex'. This starts at zero, but is | ||
* incremented when events are prepended to the timeline. The index of an event | ||
* relative to baseIndex therefore remains constant. | ||
* | ||
* <p>Once a timeline joins up with its neighbour, they are linked together into a | ||
* doubly-linked list. | ||
* | ||
* @param {Room} root the root of this hierarchy | ||
* @param {number} pageSize the maximum number of rooms to return per page, can be overridden per load request. | ||
* @param {number} maxDepth the maximum depth to traverse the hierarchy to | ||
* @param {boolean} suggestedOnly whether to only return rooms with suggested=true. | ||
* @constructor | ||
*/ | ||
constructor( | ||
private readonly root: Room, | ||
private readonly pageSize?: number, | ||
private readonly maxDepth?: number, | ||
private readonly suggestedOnly = false, | ||
) {} | ||
|
||
public get noSupport(): boolean { | ||
return !!this.serverSupportError; | ||
} | ||
|
||
public get canLoadMore(): boolean { | ||
return !!this.serverSupportError || !!this.nextToken || !this._rooms; | ||
} | ||
|
||
public get rooms(): IHierarchyRoom[] { | ||
return this._rooms; | ||
} | ||
|
||
public async load(pageSize = this.pageSize): Promise<IHierarchyRoom[]> { | ||
if (this.loadRequest) return this.loadRequest.then(r => r.rooms); | ||
|
||
this.loadRequest = this.root.client.getRoomHierarchy( | ||
this.root.roomId, | ||
pageSize, | ||
this.maxDepth, | ||
this.suggestedOnly, | ||
this.nextToken, | ||
); | ||
|
||
let rooms: IHierarchyRoom[]; | ||
try { | ||
({ rooms, next_token: this.nextToken } = await this.loadRequest); | ||
} catch (e) { | ||
if (e.errcode === "M_UNRECOGNIZED") { | ||
this.serverSupportError = e; | ||
} else { | ||
// TODO retry? | ||
} | ||
|
||
return []; | ||
} finally { | ||
this.loadRequest = null; | ||
} | ||
|
||
if (this._rooms) { | ||
this._rooms = this._rooms.concat(rooms); | ||
} else { | ||
this._rooms = rooms; | ||
} | ||
|
||
rooms.forEach(room => { | ||
this.roomMap.set(room.room_id, room); | ||
|
||
room.children_state.forEach(ev => { | ||
if (ev.type !== EventType.SpaceChild) return; | ||
const childRoomId = ev.state_key; | ||
|
||
// track backrefs for quicker hierarchy navigation | ||
if (!this.backRefs.has(childRoomId)) { | ||
this.backRefs.set(childRoomId, []); | ||
} | ||
this.backRefs.get(childRoomId).push(ev.room_id); | ||
|
||
// fill viaMap | ||
if (Array.isArray(ev.content.via)) { | ||
if (!this.viaMap.has(childRoomId)) { | ||
this.viaMap.set(childRoomId, new Set()); | ||
} | ||
const vias = this.viaMap.get(childRoomId); | ||
ev.content.via.forEach(via => vias.add(via)); | ||
} | ||
}); | ||
}); | ||
|
||
return rooms; | ||
} | ||
|
||
public getRelation(parentId: string, childId: string): IHierarchyRelation { | ||
return this.roomMap.get(parentId)?.children_state.find(e => e.state_key === childId); | ||
} | ||
|
||
public isSuggested(parentId: string, childId: string): boolean { | ||
return this.getRelation(parentId, childId)?.content.suggested; | ||
} | ||
|
||
public removeRelation(parentId: string, childId: string): void { | ||
const backRefs = this.backRefs.get(childId); | ||
if (backRefs?.length === 1) { | ||
this.backRefs.delete(childId); | ||
} else if (backRefs?.length) { | ||
this.backRefs.set(childId, backRefs.filter(ref => ref !== parentId)); | ||
} | ||
|
||
const room = this.roomMap.get(parentId); | ||
if (room) { | ||
room.children_state = room.children_state.filter(ev => ev.state_key !== childId); | ||
} | ||
} | ||
} |
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.