Dedupe room list store updates by marking for updates
The core of this is in the MarkedExecution class, with the remainder of the commit ensuring that the right marks and triggers are in place to do the firing. Because everything is async/await and run through the RoomListStore, we don't have to worry about self-fed updates in the algorithm classes. This also means we have to trigger pretty much all the time. Changes to tag ordering / list sorting get hit through two paths, so we mark before we do a bulk update and otherwise assume the call is coming in from outside.
This commit is contained in:
parent
f9e8487d5a
commit
1315f34662
3 changed files with 108 additions and 23 deletions
|
@ -33,6 +33,7 @@ import { EffectiveMembership, getEffectiveMembership } from "./membership";
|
|||
import { ListLayout } from "./ListLayout";
|
||||
import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
|
||||
import RoomListLayoutStore from "./RoomListLayoutStore";
|
||||
import { MarkedExecution } from "../../utils/MarkedExecution";
|
||||
|
||||
interface IState {
|
||||
tagsEnabled?: boolean;
|
||||
|
@ -51,7 +52,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
private algorithm = new Algorithm();
|
||||
private filterConditions: IFilterCondition[] = [];
|
||||
private tagWatcher = new TagWatcher(this);
|
||||
private layoutMap: Map<TagID, ListLayout> = new Map<TagID, ListLayout>();
|
||||
private updateFn = new MarkedExecution(() => this.emit(LISTS_UPDATE_EVENT));
|
||||
|
||||
private readonly watchedSettings = [
|
||||
'feature_custom_tags',
|
||||
|
@ -91,24 +92,26 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
await this.updateAlgorithmInstances();
|
||||
}
|
||||
|
||||
private onRVSUpdate = () => {
|
||||
private onRVSUpdate = async (quiet = false) => {
|
||||
if (!this.enabled) return; // TODO: Remove with https://github.com/vector-im/riot-web/issues/14231
|
||||
if (!this.matrixClient) return; // We assume there won't be RVS updates without a client
|
||||
|
||||
const activeRoomId = RoomViewStore.getRoomId();
|
||||
if (!activeRoomId && this.algorithm.stickyRoom) {
|
||||
this.algorithm.stickyRoom = null;
|
||||
await this.algorithm.setStickyRoom(null);
|
||||
} else if (activeRoomId) {
|
||||
const activeRoom = this.matrixClient.getRoom(activeRoomId);
|
||||
if (!activeRoom) {
|
||||
console.warn(`${activeRoomId} is current in RVS but missing from client - clearing sticky room`);
|
||||
this.algorithm.stickyRoom = null;
|
||||
await this.algorithm.setStickyRoom(null);
|
||||
} else if (activeRoom !== this.algorithm.stickyRoom) {
|
||||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||
console.log(`Changing sticky room to ${activeRoomId}`);
|
||||
this.algorithm.stickyRoom = activeRoom;
|
||||
await this.algorithm.setStickyRoom(activeRoom);
|
||||
}
|
||||
}
|
||||
|
||||
if (!quiet) this.updateFn.trigger();
|
||||
};
|
||||
|
||||
protected async onDispatch(payload: ActionPayload) {
|
||||
|
@ -127,8 +130,12 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
// Update any settings here, as some may have happened before we were logically ready.
|
||||
console.log("Regenerating room lists: Startup");
|
||||
await this.readAndCacheSettingsFromStore();
|
||||
await this.regenerateAllLists();
|
||||
this.onRVSUpdate(); // fake an RVS update to adjust sticky room, if needed
|
||||
await this.regenerateAllLists(true);
|
||||
await this.onRVSUpdate(true); // fake an RVS update to adjust sticky room, if needed
|
||||
|
||||
this.updateFn.trigger();
|
||||
|
||||
return; // no point in running the next conditions - they won't match
|
||||
}
|
||||
|
||||
// TODO: Remove this once the RoomListStore becomes default
|
||||
|
@ -137,7 +144,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
if (payload.action === 'on_client_not_viable' || payload.action === 'on_logged_out') {
|
||||
// Reset state without causing updates as the client will have been destroyed
|
||||
// and downstream code will throw NPE errors.
|
||||
this.reset(null, true);
|
||||
await this.reset(null, true);
|
||||
this._matrixClient = null;
|
||||
this.initialListsGenerated = false; // we'll want to regenerate them
|
||||
}
|
||||
|
@ -151,7 +158,8 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
console.log("Regenerating room lists: Settings changed");
|
||||
await this.readAndCacheSettingsFromStore();
|
||||
|
||||
await this.regenerateAllLists(); // regenerate the lists now
|
||||
await this.regenerateAllLists(true); // regenerate the lists now
|
||||
this.updateFn.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,6 +180,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||
console.log(`[RoomListDebug] Got own read receipt in ${room.roomId}`);
|
||||
await this.handleRoomUpdate(room, RoomUpdateCause.ReadReceipt);
|
||||
this.updateFn.trigger();
|
||||
return;
|
||||
}
|
||||
} else if (payload.action === 'MatrixActions.Room.tags') {
|
||||
|
@ -179,6 +188,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||
console.log(`[RoomListDebug] Got tag change in ${roomPayload.room.roomId}`);
|
||||
await this.handleRoomUpdate(roomPayload.room, RoomUpdateCause.PossibleTagChange);
|
||||
this.updateFn.trigger();
|
||||
} else if (payload.action === 'MatrixActions.Room.timeline') {
|
||||
const eventPayload = (<any>payload); // TODO: Type out the dispatcher types
|
||||
|
||||
|
@ -202,6 +212,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
}
|
||||
}
|
||||
await this.handleRoomUpdate(updatedRoom, RoomUpdateCause.Timeline);
|
||||
this.updateFn.trigger();
|
||||
};
|
||||
if (!room) {
|
||||
console.warn(`Live timeline event ${eventPayload.event.getId()} received without associated room`);
|
||||
|
@ -225,6 +236,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||
console.log(`[RoomListDebug] Decrypted timeline event ${eventPayload.event.getId()} in ${roomId}`);
|
||||
await this.handleRoomUpdate(room, RoomUpdateCause.Timeline);
|
||||
this.updateFn.trigger();
|
||||
} else if (payload.action === 'MatrixActions.accountData' && payload.event_type === 'm.direct') {
|
||||
const eventPayload = (<any>payload); // TODO: Type out the dispatcher types
|
||||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||
|
@ -246,6 +258,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
await this.handleRoomUpdate(room, RoomUpdateCause.PossibleTagChange);
|
||||
}
|
||||
}
|
||||
this.updateFn.trigger();
|
||||
} else if (payload.action === 'MatrixActions.Room.myMembership') {
|
||||
const membershipPayload = (<any>payload); // TODO: Type out the dispatcher types
|
||||
const oldMembership = getEffectiveMembership(membershipPayload.oldMembership);
|
||||
|
@ -264,7 +277,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
const isSticky = this.algorithm.stickyRoom === prevRoom;
|
||||
if (isSticky) {
|
||||
console.log(`[RoomListDebug] Clearing sticky room due to room upgrade`);
|
||||
await this.algorithm.setStickyRoomAsync(null);
|
||||
await this.algorithm.setStickyRoom(null);
|
||||
}
|
||||
|
||||
// Note: we hit the algorithm instead of our handleRoomUpdate() function to
|
||||
|
@ -276,6 +289,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
|
||||
console.log(`[RoomListDebug] Adding new room to room list`);
|
||||
await this.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.NewRoom);
|
||||
this.updateFn.trigger();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -283,6 +297,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||
console.log(`[RoomListDebug] Handling invite to ${membershipPayload.room.roomId}`);
|
||||
await this.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.NewRoom);
|
||||
this.updateFn.trigger();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -291,6 +306,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||
console.log(`[RoomListDebug] Handling membership change in ${membershipPayload.room.roomId}`);
|
||||
await this.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.PossibleTagChange);
|
||||
this.updateFn.trigger();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -301,7 +317,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
if (shouldUpdate) {
|
||||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||
console.log(`[DEBUG] Room "${room.name}" (${room.roomId}) triggered by ${cause} requires list update`);
|
||||
this.emit(LISTS_UPDATE_EVENT, this);
|
||||
this.updateFn.mark();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,6 +325,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
await this.algorithm.setTagSorting(tagId, sort);
|
||||
// TODO: Per-account? https://github.com/vector-im/riot-web/issues/14114
|
||||
localStorage.setItem(`mx_tagSort_${tagId}`, sort);
|
||||
this.updateFn.triggerIfWillMark();
|
||||
}
|
||||
|
||||
public getTagSorting(tagId: TagID): SortAlgorithm {
|
||||
|
@ -347,6 +364,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
await this.algorithm.setListOrdering(tagId, order);
|
||||
// TODO: Per-account? https://github.com/vector-im/riot-web/issues/14114
|
||||
localStorage.setItem(`mx_listOrder_${tagId}`, order);
|
||||
this.updateFn.triggerIfWillMark();
|
||||
}
|
||||
|
||||
public getListOrder(tagId: TagID): ListAlgorithm {
|
||||
|
@ -382,6 +400,10 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
}
|
||||
|
||||
private async updateAlgorithmInstances() {
|
||||
// We'll require an update, so mark for one. Marking now also prevents the calls
|
||||
// to setTagSorting and setListOrder from causing triggers.
|
||||
this.updateFn.mark();
|
||||
|
||||
for (const tag of Object.keys(this.orderedLists)) {
|
||||
const definedSort = this.getTagSorting(tag);
|
||||
const definedOrder = this.getListOrder(tag);
|
||||
|
@ -406,11 +428,11 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
|
||||
private onAlgorithmListUpdated = () => {
|
||||
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
|
||||
console.log("Underlying algorithm has triggered a list update - refiring");
|
||||
this.emit(LISTS_UPDATE_EVENT, this);
|
||||
console.log("Underlying algorithm has triggered a list update - marking");
|
||||
this.updateFn.mark();
|
||||
};
|
||||
|
||||
private async regenerateAllLists() {
|
||||
private async regenerateAllLists(quiet = false) {
|
||||
console.warn("Regenerating all room lists");
|
||||
|
||||
const sorts: ITagSortingMap = {};
|
||||
|
@ -435,7 +457,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
|
||||
this.initialListsGenerated = true;
|
||||
|
||||
this.emit(LISTS_UPDATE_EVENT, this);
|
||||
if (!quiet) this.updateFn.trigger();
|
||||
}
|
||||
|
||||
public addFilter(filter: IFilterCondition): void {
|
||||
|
@ -445,6 +467,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
if (this.algorithm) {
|
||||
this.algorithm.addFilterCondition(filter);
|
||||
}
|
||||
this.updateFn.trigger();
|
||||
}
|
||||
|
||||
public removeFilter(filter: IFilterCondition): void {
|
||||
|
@ -458,6 +481,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
|||
this.algorithm.removeFilterCondition(filter);
|
||||
}
|
||||
}
|
||||
this.updateFn.trigger();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue