Skip to content

Commit c7a83e6

Browse files
committed
Fix proliferation when joining upgraded rooms
We have to do a bit of a dance to return the sticky room to the list so we can remove it, if needed, and ensure that we generally swap the rooms out of the list.
1 parent 52b52df commit c7a83e6

File tree

2 files changed

+98
-19
lines changed

2 files changed

+98
-19
lines changed

src/stores/room-list/RoomListStore2.ts

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,10 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
9797
this.algorithm.stickyRoom = null;
9898
} else if (activeRoomId) {
9999
const activeRoom = this.matrixClient.getRoom(activeRoomId);
100-
if (!activeRoom) throw new Error(`${activeRoomId} is current in RVS but missing from client`);
101-
if (activeRoom !== this.algorithm.stickyRoom) {
100+
if (!activeRoom) {
101+
console.warn(`${activeRoomId} is current in RVS but missing from client - clearing sticky room`);
102+
this.algorithm.stickyRoom = null;
103+
} else if (activeRoom !== this.algorithm.stickyRoom) {
102104
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
103105
console.log(`Changing sticky room to ${activeRoomId}`);
104106
this.algorithm.stickyRoom = activeRoom;
@@ -187,10 +189,13 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
187189
console.log(`[RoomListDebug] Live timeline event ${eventPayload.event.getId()} in ${updatedRoom.roomId}`);
188190
if (eventPayload.event.getType() === 'm.room.tombstone' && eventPayload.event.getStateKey() === '') {
189191
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
190-
console.log(`[RoomListDebug] Got tombstone event - regenerating room list`);
191-
// TODO: We could probably be smarter about this: https://github.com/vector-im/riot-web/issues/14035
192-
await this.regenerateAllLists();
193-
return; // don't pass the update down - we will have already handled it in the regen
192+
console.log(`[RoomListDebug] Got tombstone event - trying to remove now-dead room`);
193+
const newRoom = this.matrixClient.getRoom(eventPayload.event.getContent()['replacement_room']);
194+
if (newRoom) {
195+
// If we have the new room, then the new room check will have seen the predecessor
196+
// and did the required updates, so do nothing here.
197+
return;
198+
}
194199
}
195200
await this.handleRoomUpdate(updatedRoom, RoomUpdateCause.Timeline);
196201
};
@@ -245,15 +250,37 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
245250
if (membershipPayload.oldMembership !== "join" && membershipPayload.membership === "join") {
246251
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
247252
console.log(`[RoomListDebug] Handling new room ${membershipPayload.room.roomId}`);
248-
await this.algorithm.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.NewRoom);
253+
254+
// If we're joining an upgraded room, we'll want to make sure we don't proliferate
255+
// the dead room in the list.
256+
const createEvent = membershipPayload.room.currentState.getStateEvents("m.room.create", "");
257+
if (createEvent && createEvent.getContent()['predecessor']) {
258+
console.log(`[RoomListDebug] Room has a predecessor`);
259+
const prevRoom = this.matrixClient.getRoom(createEvent.getContent()['predecessor']['room_id']);
260+
if (prevRoom) {
261+
const isSticky = this.algorithm.stickyRoom === prevRoom;
262+
if (isSticky) {
263+
console.log(`[RoomListDebug] Clearing sticky room due to room upgrade`);
264+
await this.algorithm.setStickyRoomAsync(null);
265+
}
266+
267+
// Note: we hit the algorithm instead of our handleRoomUpdate() function to
268+
// avoid redundant updates.
269+
console.log(`[RoomListDebug] Removing previous room from room list`);
270+
await this.algorithm.handleRoomUpdate(prevRoom, RoomUpdateCause.RoomRemoved);
271+
}
272+
}
273+
274+
console.log(`[RoomListDebug] Adding new room to room list`);
275+
await this.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.NewRoom);
249276
return;
250277
}
251278

252279
// If it's not a join, it's transitioning into a different list (possibly historical)
253280
if (membershipPayload.oldMembership !== membershipPayload.membership) {
254281
// TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
255282
console.log(`[RoomListDebug] Handling membership change in ${membershipPayload.room.roomId}`);
256-
await this.algorithm.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.PossibleTagChange);
283+
await this.handleRoomUpdate(membershipPayload.room, RoomUpdateCause.PossibleTagChange);
257284
return;
258285
}
259286
}

src/stores/room-list/algorithms/Algorithm.ts

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
SortAlgorithm
3131
} from "./models";
3232
import { FILTER_CHANGED, FilterPriority, IFilterCondition } from "../filters/IFilterCondition";
33-
import { EffectiveMembership, splitRoomsByMembership } from "../membership";
33+
import { EffectiveMembership, getEffectiveMembership, splitRoomsByMembership } from "../membership";
3434
import { OrderingAlgorithm } from "./list-ordering/OrderingAlgorithm";
3535
import { getListAlgorithmInstance } from "./list-ordering";
3636

@@ -99,6 +99,14 @@ export class Algorithm extends EventEmitter {
9999
return this._cachedRooms;
100100
}
101101

102+
/**
103+
* Awaitable version of the sticky room setter.
104+
* @param val The new room to sticky.
105+
*/
106+
public async setStickyRoomAsync(val: Room) {
107+
await this.updateStickyRoom(val);
108+
}
109+
102110
public getTagSorting(tagId: TagID): SortAlgorithm {
103111
return this.sortAlgorithms[tagId];
104112
}
@@ -160,10 +168,13 @@ export class Algorithm extends EventEmitter {
160168
// It's possible to have no selected room. In that case, clear the sticky room
161169
if (!val) {
162170
if (this._stickyRoom) {
171+
const stickyRoom = this._stickyRoom.room;
172+
this._stickyRoom = null; // clear before we go to update the algorithm
173+
163174
// Lie to the algorithm and re-add the room to the algorithm
164-
await this.handleRoomUpdate(this._stickyRoom.room, RoomUpdateCause.NewRoom);
175+
await this.handleRoomUpdate(stickyRoom, RoomUpdateCause.NewRoom);
176+
return;
165177
}
166-
this._stickyRoom = null;
167178
return;
168179
}
169180

@@ -289,6 +300,8 @@ export class Algorithm extends EventEmitter {
289300
}
290301

291302
protected recalculateFilteredRoomsForTag(tagId: TagID): void {
303+
if (!this.hasFilters) return; // don't bother doing work if there's nothing to do
304+
292305
console.log(`Recalculating filtered rooms for ${tagId}`);
293306
delete this.filteredRooms[tagId];
294307
const rooms = this.cachedRooms[tagId].map(r => r); // cheap clone
@@ -458,14 +471,7 @@ export class Algorithm extends EventEmitter {
458471

459472
// Now process all the joined rooms. This is a bit more complicated
460473
for (const room of memberships[EffectiveMembership.Join]) {
461-
let tags = Object.keys(room.tags || {});
462-
463-
if (tags.length === 0) {
464-
// Check to see if it's a DM if it isn't anything else
465-
if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
466-
tags = [DefaultTagID.DM];
467-
}
468-
}
474+
const tags = this.getTagsOfJoinedRoom(room);
469475

470476
let inTag = false;
471477
if (tags.length > 0) {
@@ -496,6 +502,39 @@ export class Algorithm extends EventEmitter {
496502
this.updateTagsFromCache();
497503
}
498504

505+
private getTagsForRoom(room: Room): TagID[] {
506+
// XXX: This duplicates a lot of logic from setKnownRooms above, but has a slightly
507+
// different use case and therefore different performance curve
508+
509+
const tags: TagID[] = [];
510+
511+
const membership = getEffectiveMembership(room.getMyMembership());
512+
if (membership === EffectiveMembership.Invite) {
513+
tags.push(DefaultTagID.Invite);
514+
} else if (membership === EffectiveMembership.Leave) {
515+
tags.push(DefaultTagID.Archived);
516+
} else {
517+
tags.push(...this.getTagsOfJoinedRoom(room));
518+
}
519+
520+
if (!tags.length) tags.push(DefaultTagID.Untagged);
521+
522+
return tags;
523+
}
524+
525+
private getTagsOfJoinedRoom(room: Room): TagID[] {
526+
let tags = Object.keys(room.tags || {});
527+
528+
if (tags.length === 0) {
529+
// Check to see if it's a DM if it isn't anything else
530+
if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) {
531+
tags = [DefaultTagID.DM];
532+
}
533+
}
534+
535+
return tags;
536+
}
537+
499538
/**
500539
* Updates the roomsToTags map
501540
*/
@@ -566,6 +605,19 @@ export class Algorithm extends EventEmitter {
566605
}
567606
}
568607

608+
if (cause === RoomUpdateCause.NewRoom && !this.roomIdsToTags[room.roomId]) {
609+
console.log(`[RoomListDebug] Updating tags for new room ${room.roomId} (${room.name})`);
610+
611+
// Get the tags for the room and populate the cache
612+
const roomTags = this.getTagsForRoom(room).filter(t => !isNullOrUndefined(this.cachedRooms[t]));
613+
614+
// "This should never happen" condition - we specify DefaultTagID.Untagged in getTagsForRoom(),
615+
// which means we should *always* have a tag to go off of.
616+
if (!roomTags.length) throw new Error(`Tags cannot be determined for ${room.roomId}`);
617+
618+
this.roomIdsToTags[room.roomId] = roomTags;
619+
}
620+
569621
let tags = this.roomIdsToTags[room.roomId];
570622
if (!tags) {
571623
console.warn(`No tags known for "${room.name}" (${room.roomId})`);

0 commit comments

Comments
 (0)