message: Fix issue with room duplication caused by filtering and selecting room using keyboard
  Wrap sticky room updates in lock to prevent setStickyRoom running in middle of setKnownRooms
diff: @@ -16,8 +16,10 @@ limitations under the License.
  import { Room } from "matrix-js-sdk/src/models/room";
  import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
  -import DMRoomMap from "../../../utils/DMRoomMap";
  import { EventEmitter } from "events";
  +import AwaitLock from "await-lock";
  +
  +import DMRoomMap from "../../../utils/DMRoomMap";
  import { arrayDiff, arrayHasDiff } from "../../../utils/arrays";
  import { DefaultTagID, RoomUpdateCause, TagID } from "../models";
  import {
  @@ -78,6 +80,7 @@ export class Algorithm extends EventEmitter {
  } = {};
  private allowedByFilter: Map<IFilterCondition, Room[]> = new Map<IFilterCondition, Room[]>();
  private allowedRoomsByFilters: Set<Room> = new Set<Room>();
  + private stickyLock = new AwaitLock();
  /**
  * Set to true to suspend emissions of algorithm updates.
  @@ -123,7 +126,12 @@ export class Algorithm extends EventEmitter {
  * @param val The new room to sticky.
  */
  public async setStickyRoom(val: Room) {
  + await this.stickyLock.acquireAsync();
  + try {
  await this.updateStickyRoom(val);
  + } finally {
  + this.stickyLock.release();
  + }
  }
  public getTagSorting(tagId: TagID): SortAlgorithm {
  @@ -519,6 +527,8 @@ export class Algorithm extends EventEmitter {
  if (isNullOrUndefined(rooms)) throw new Error(`Array of rooms cannot be null`);
  if (!this.sortAlgorithms) throw new Error(`Cannot set known rooms without a tag sorting map`);
  + await this.stickyLock.acquireAsync();
  + try {
  if (!this.updatesInhibited) {
  // We only log this if we're expecting to be publishing updates, which means that
  // this could be an unexpected invocation. If we're inhibited, then this is probably
  @@ -529,7 +539,7 @@ export class Algorithm extends EventEmitter {
  // Before we go any further we need to clear (but remember) the sticky room to
  // avoid accidentally duplicating it in the list.
  const oldStickyRoom = this._stickyRoom;
  - await this.updateStickyRoom(null);
  + if (oldStickyRoom) await this.updateStickyRoom(null);
  this.rooms = rooms;
  @@ -596,6 +606,9 @@ export class Algorithm extends EventEmitter {
  }
  }
  }
  + } finally {
  + this.stickyLock.release();
  + }
  }
  public getTagsForRoom(room: Room): TagID[] {
  @@ -685,9 +698,9 @@ export class Algorithm extends EventEmitter {
  if (!this.algorithms) throw new Error("Not ready: no algorithms to determine tags from");
  // Note: check the isSticky against the room ID just in case the reference is wrong
  - const isSticky = this._stickyRoom && this._stickyRoom.room && this._stickyRoom.room.roomId === room.roomId;
  + const isSticky = this._stickyRoom?.room?.roomId === room.roomId;
  if (cause === RoomUpdateCause.NewRoom) {
  - const isForLastSticky = this._lastStickyRoom && this._lastStickyRoom.room === room;
  + const isForLastSticky = this._lastStickyRoom?.room === room;
  const roomTags = this.roomIdsToTags[room.roomId];
  const hasTags = roomTags && roomTags.length > 0;
  