Room List - Update the room list store on actions from the dispatcher (#29397)
* Update the store on action * Add more tests * Add newlines between case blocks * Make code more readable - Make if/else more consistent - Add comment on findAndAddRoom() * Add more tests * Remove redundant code On a timeline action, we return early if payload.room is falsy. So then why do we need to retry fetching the room? I think this can be removed but will ask others if there's some conext I'm missing. * Fix test * Remove more redundant code * Add more tests * Explain intention in comment * Emit only once even when adding multiple rooms * Add missing tsdoc
This commit is contained in:
@@ -5,7 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
|
||||
Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
import type { EmptyObject, Room } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { EventType } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import type { EmptyObject, Room, RoomState } from "matrix-js-sdk/src/matrix";
|
||||
import type { MatrixDispatcher } from "../../dispatcher/dispatcher";
|
||||
import type { ActionPayload } from "../../dispatcher/payloads";
|
||||
import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
|
||||
@@ -16,6 +19,8 @@ import { LISTS_UPDATE_EVENT } from "../room-list/RoomListStore";
|
||||
import { RoomSkipList } from "./skip-list/RoomSkipList";
|
||||
import { RecencySorter } from "./skip-list/sorters/RecencySorter";
|
||||
import { AlphabeticSorter } from "./skip-list/sorters/AlphabeticSorter";
|
||||
import { readReceiptChangeIsFor } from "../../utils/read-receipts";
|
||||
import { EffectiveMembership, getEffectiveMembership, getEffectiveMembershipTag } from "../../utils/membership";
|
||||
|
||||
/**
|
||||
* This store allows for fast retrieval of the room list in a sorted and filtered manner.
|
||||
@@ -78,7 +83,100 @@ export class RoomListStoreV3Class extends AsyncStoreWithClient<EmptyObject> {
|
||||
}
|
||||
|
||||
protected async onAction(payload: ActionPayload): Promise<void> {
|
||||
return;
|
||||
if (!this.matrixClient || !this.roomSkipList?.initialized) return;
|
||||
|
||||
/**
|
||||
* For the kind of updates that we care about (represented by the cases below),
|
||||
* we try to find the associated room and simply re-insert it into the
|
||||
* skiplist. If the position of said room in the sorted list changed, re-inserting
|
||||
* would put it in the correct place.
|
||||
*/
|
||||
switch (payload.action) {
|
||||
case "MatrixActions.Room.receipt": {
|
||||
if (readReceiptChangeIsFor(payload.event, this.matrixClient)) {
|
||||
const room = payload.room;
|
||||
if (!room) {
|
||||
logger.warn(`Own read receipt was in unknown room ${room.roomId}`);
|
||||
return;
|
||||
}
|
||||
this.addRoomAndEmit(room);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "MatrixActions.Room.tags": {
|
||||
const room = payload.room;
|
||||
this.addRoomAndEmit(room);
|
||||
break;
|
||||
}
|
||||
|
||||
case "MatrixActions.Event.decrypted": {
|
||||
const roomId = payload.event.getRoomId();
|
||||
if (!roomId) return;
|
||||
const room = this.matrixClient.getRoom(roomId);
|
||||
if (!room) {
|
||||
logger.warn(`Event ${payload.event.getId()} was decrypted in an unknown room ${roomId}`);
|
||||
return;
|
||||
}
|
||||
this.addRoomAndEmit(room);
|
||||
break;
|
||||
}
|
||||
|
||||
case "MatrixActions.accountData": {
|
||||
if (payload.event_type !== EventType.Direct) return;
|
||||
const dmMap = payload.event.getContent();
|
||||
let needsEmit = false;
|
||||
for (const userId of Object.keys(dmMap)) {
|
||||
const roomIds = dmMap[userId];
|
||||
for (const roomId of roomIds) {
|
||||
const room = this.matrixClient.getRoom(roomId);
|
||||
if (!room) {
|
||||
logger.warn(`${roomId} was found in DMs but the room is not in the store`);
|
||||
continue;
|
||||
}
|
||||
this.roomSkipList.addRoom(room);
|
||||
needsEmit = true;
|
||||
}
|
||||
}
|
||||
if (needsEmit) this.emit(LISTS_UPDATE_EVENT);
|
||||
break;
|
||||
}
|
||||
|
||||
case "MatrixActions.Room.timeline": {
|
||||
// Ignore non-live events (backfill) and notification timeline set events (without a room)
|
||||
if (!payload.isLiveEvent || !payload.isLiveUnfilteredRoomTimelineEvent || !payload.room) return;
|
||||
this.addRoomAndEmit(payload.room);
|
||||
break;
|
||||
}
|
||||
|
||||
case "MatrixActions.Room.myMembership": {
|
||||
const oldMembership = getEffectiveMembership(payload.oldMembership);
|
||||
const newMembership = getEffectiveMembershipTag(payload.room, payload.membership);
|
||||
if (oldMembership !== EffectiveMembership.Join && newMembership === EffectiveMembership.Join) {
|
||||
// If we're joining an upgraded room, we'll want to make sure we don't proliferate
|
||||
// the dead room in the list.
|
||||
const roomState: RoomState = payload.room.currentState;
|
||||
const predecessor = roomState.findPredecessor(this.msc3946ProcessDynamicPredecessor);
|
||||
if (predecessor) {
|
||||
const prevRoom = this.matrixClient?.getRoom(predecessor.roomId);
|
||||
if (prevRoom) this.roomSkipList.removeRoom(prevRoom);
|
||||
else logger.warn(`Unable to find predecessor room with id ${predecessor.roomId}`);
|
||||
}
|
||||
}
|
||||
this.addRoomAndEmit(payload.room);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a room to the skiplist and emit an update.
|
||||
* @param room The room to add to the skiplist
|
||||
*/
|
||||
private addRoomAndEmit(room: Room): void {
|
||||
if (!this.roomSkipList) throw new Error("roomSkipList hasn't been created yet!");
|
||||
this.roomSkipList.addRoom(room);
|
||||
this.emit(LISTS_UPDATE_EVENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user