Ensure RoomListStore2 gets reset when the client becomes invalidated

Fixes https://github.com/vector-im/riot-web/issues/14384

We also make use of the new AsyncStore type to handle this more safely.
This commit is contained in:
Travis Ralston 2020-07-13 13:15:44 -06:00
parent 1f57b85b30
commit a8829f09d0
2 changed files with 18 additions and 32 deletions

View file

@ -33,6 +33,7 @@ import { EffectiveMembership, getEffectiveMembership } from "./membership";
import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
import RoomListLayoutStore from "./RoomListLayoutStore"; import RoomListLayoutStore from "./RoomListLayoutStore";
import { MarkedExecution } from "../../utils/MarkedExecution"; import { MarkedExecution } from "../../utils/MarkedExecution";
import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
interface IState { interface IState {
tagsEnabled?: boolean; tagsEnabled?: boolean;
@ -44,14 +45,13 @@ interface IState {
*/ */
export const LISTS_UPDATE_EVENT = "lists_update"; export const LISTS_UPDATE_EVENT = "lists_update";
export class RoomListStore2 extends AsyncStore<ActionPayload> { export class RoomListStore2 extends AsyncStoreWithClient<ActionPayload> {
/** /**
* Set to true if you're running tests on the store. Should not be touched in * Set to true if you're running tests on the store. Should not be touched in
* any other environment. * any other environment.
*/ */
public static TEST_MODE = false; public static TEST_MODE = false;
private _matrixClient: MatrixClient;
private initialListsGenerated = false; private initialListsGenerated = false;
private enabled = false; private enabled = false;
private algorithm = new Algorithm(); private algorithm = new Algorithm();
@ -78,33 +78,30 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
return this.algorithm.getOrderedRooms(); return this.algorithm.getOrderedRooms();
} }
public get matrixClient(): MatrixClient {
return this._matrixClient;
}
// Intended for test usage // Intended for test usage
public async resetStore() { public async resetStore() {
await this.reset(); await this.reset();
this.tagWatcher = new TagWatcher(this); this.tagWatcher = new TagWatcher(this);
this.filterConditions = []; this.filterConditions = [];
this.initialListsGenerated = false; this.initialListsGenerated = false;
this._matrixClient = null;
this.algorithm.off(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated); this.algorithm.off(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated);
this.algorithm.off(FILTER_CHANGED, this.onAlgorithmListUpdated); this.algorithm.off(FILTER_CHANGED, this.onAlgorithmListUpdated);
this.algorithm = new Algorithm(); this.algorithm = new Algorithm();
this.algorithm.on(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated); this.algorithm.on(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated);
this.algorithm.on(FILTER_CHANGED, this.onAlgorithmListUpdated); this.algorithm.on(FILTER_CHANGED, this.onAlgorithmListUpdated);
// Reset state without causing updates as the client will have been destroyed
// and downstream code will throw NPE errors.
await this.reset(null, true);
} }
// Public for test usage. Do not call this. // Public for test usage. Do not call this.
public async makeReady(client: MatrixClient) { public async makeReady() {
// TODO: Remove with https://github.com/vector-im/riot-web/issues/14367 // TODO: Remove with https://github.com/vector-im/riot-web/issues/14367
this.checkEnabled(); this.checkEnabled();
if (!this.enabled) return; if (!this.enabled) return;
this._matrixClient = client;
// Update any settings here, as some may have happened before we were logically ready. // Update any settings here, as some may have happened before we were logically ready.
// Update any settings here, as some may have happened before we were logically ready. // Update any settings here, as some may have happened before we were logically ready.
console.log("Regenerating room lists: Startup"); console.log("Regenerating room lists: Startup");
@ -161,7 +158,15 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
if (trigger) this.updateFn.trigger(); if (trigger) this.updateFn.trigger();
} }
protected async onDispatch(payload: ActionPayload) { protected async onReady(): Promise<any> {
await this.makeReady();
}
protected async onNotReady(): Promise<any> {
await this.resetStore();
}
protected async onAction(payload: ActionPayload) {
// When we're running tests we can't reliably use setImmediate out of timing concerns. // When we're running tests we can't reliably use setImmediate out of timing concerns.
// As such, we use a more synchronous model. // As such, we use a more synchronous model.
if (RoomListStore2.TEST_MODE) { if (RoomListStore2.TEST_MODE) {
@ -175,29 +180,10 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
} }
protected async onDispatchAsync(payload: ActionPayload) { protected async onDispatchAsync(payload: ActionPayload) {
if (payload.action === 'MatrixActions.sync') {
// Filter out anything that isn't the first PREPARED sync.
if (!(payload.prevState === 'PREPARED' && payload.state !== 'PREPARED')) {
return;
}
await this.makeReady(payload.matrixClient);
return; // no point in running the next conditions - they won't match
}
// TODO: Remove this once the RoomListStore becomes default // TODO: Remove this once the RoomListStore becomes default
if (!this.enabled) return; if (!this.enabled) return;
if (payload.action === 'on_client_not_viable' || payload.action === 'on_logged_out') { // Everything here requires a MatrixClient or some sort of logical readiness.
// Reset state without causing updates as the client will have been destroyed
// and downstream code will throw NPE errors.
await this.reset(null, true);
this._matrixClient = null;
this.initialListsGenerated = false; // we'll want to regenerate them
}
// Everything below here requires a MatrixClient or some sort of logical readiness.
const logicallyReady = this.matrixClient && this.initialListsGenerated; const logicallyReady = this.matrixClient && this.initialListsGenerated;
if (!logicallyReady) return; if (!logicallyReady) return;

View file

@ -109,7 +109,7 @@ describe('RoomList', () => {
client.getRoom = (roomId) => roomMap[roomId]; client.getRoom = (roomId) => roomMap[roomId];
// Now that everything has been set up, prepare and update the store // Now that everything has been set up, prepare and update the store
await RoomListStore.instance.makeReady(client); await RoomListStore.instance.makeReady();
done(); done();
}); });