@@ -18,7 +18,7 @@ import { Room } from "matrix-js-sdk/src/models/room";
1818import { isNullOrUndefined } from "matrix-js-sdk/src/utils" ;
1919import DMRoomMap from "../../../utils/DMRoomMap" ;
2020import { EventEmitter } from "events" ;
21- import { arrayHasDiff , ArrayUtil } from "../../../utils/arrays" ;
21+ import { arrayDiff , arrayHasDiff , ArrayUtil } from "../../../utils/arrays" ;
2222import { getEnumValues } from "../../../utils/enums" ;
2323import { DefaultTagID , RoomUpdateCause , TagID } from "../models" ;
2424import {
@@ -58,6 +58,7 @@ export class Algorithm extends EventEmitter {
5858 private _cachedStickyRooms : ITagMap = { } ; // a clone of the _cachedRooms, with the sticky room
5959 private filteredRooms : ITagMap = { } ;
6060 private _stickyRoom : IStickyRoom = null ;
61+ private _lastStickyRoom : IStickyRoom = null ;
6162 private sortAlgorithms : ITagSortingMap ;
6263 private listAlgorithms : IListOrderingMap ;
6364 private algorithms : IOrderingAlgorithmMap ;
@@ -172,6 +173,7 @@ export class Algorithm extends EventEmitter {
172173 if ( this . _stickyRoom ) {
173174 const stickyRoom = this . _stickyRoom . room ;
174175 this . _stickyRoom = null ; // clear before we go to update the algorithm
176+ this . _lastStickyRoom = stickyRoom ;
175177
176178 // Lie to the algorithm and re-add the room to the algorithm
177179 await this . handleRoomUpdate ( stickyRoom , RoomUpdateCause . NewRoom ) ;
@@ -198,7 +200,8 @@ export class Algorithm extends EventEmitter {
198200 // the same thing it no-ops. After we're done calling the algorithm, we'll issue
199201 // a new update for ourselves.
200202 const lastStickyRoom = this . _stickyRoom ;
201- this . _stickyRoom = null ;
203+ this . _stickyRoom = null ; // clear before we update the algorithm
204+ this . _lastStickyRoom = lastStickyRoom ;
202205 this . recalculateStickyRoom ( ) ;
203206
204207 // When we do have the room, re-add the old room (if needed) to the algorithm
@@ -562,7 +565,7 @@ export class Algorithm extends EventEmitter {
562565 /**
563566 * Updates the roomsToTags map
564567 */
565- protected updateTagsFromCache ( ) {
568+ private updateTagsFromCache ( ) {
566569 const newMap = { } ;
567570
568571 const tags = Object . keys ( this . cachedRooms ) ;
@@ -609,24 +612,73 @@ export class Algorithm extends EventEmitter {
609612 * processing.
610613 */
611614 public async handleRoomUpdate ( room : Room , cause : RoomUpdateCause ) : Promise < boolean > {
615+ // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
616+ console . trace ( `Handle room update for ${ room . roomId } called with cause ${ cause } ` ) ;
612617 try {
613618 await this . lock . acquireAsync ( ) ;
614619
615620 if ( ! this . algorithms ) throw new Error ( "Not ready: no algorithms to determine tags from" ) ;
616621
622+ // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
623+ console . log ( `[RoomListDebug] @@ ${ room . roomId } with ${ cause } for tags ${ this . roomIdsToTags [ room . roomId ] } and sticky is currently ${ this . _stickyRoom && this . _stickyRoom . room ? this . _stickyRoom . room . roomId : '<none>' } and last is ${ this . _lastStickyRoom && this . _lastStickyRoom . room ? this . _lastStickyRoom . room . roomId : '<none>' } ` ) ;
624+
617625 if ( cause === RoomUpdateCause . NewRoom ) {
626+ const isForLastSticky = this . _lastStickyRoom && this . _lastStickyRoom . room === room ;
618627 const roomTags = this . roomIdsToTags [ room . roomId ] ;
619- if ( roomTags && roomTags . length > 0 ) {
628+ const hasTags = roomTags && roomTags . length > 0 ;
629+
630+ // Don't change the cause if the last sticky room is being re-added. If we fail to
631+ // pass the cause through as NewRoom, we'll fail to lie to the algorithm and thus
632+ // lose the room.
633+ if ( hasTags && ! isForLastSticky ) {
620634 console . warn ( `${ room . roomId } is reportedly new but is already known - assuming TagChange instead` ) ;
621635 cause = RoomUpdateCause . PossibleTagChange ;
622636 }
637+
638+ // If we have tags for a room and don't have the room referenced, the room reference
639+ // probably changed. We need to swap out the problematic reference.
640+ if ( hasTags && ! this . rooms . includes ( room ) ) {
641+ console . warn ( `${ room . roomId } is missing from room array but is known - trying to find duplicate` ) ;
642+ this . rooms = this . rooms . map ( r => r . roomId === room . roomId ? room : r ) ;
643+
644+ // Sanity check
645+ if ( ! this . rooms . includes ( room ) ) {
646+ throw new Error ( `Failed to replace ${ room . roomId } with an updated reference` ) ;
647+ }
648+ }
623649 }
624650
625651 if ( cause === RoomUpdateCause . PossibleTagChange ) {
626- // TODO: Be smarter and splice rather than regen the planet. https://github.com/vector-im/riot-web/issues/14035
627- // TODO: No-op if no change. https://github.com/vector-im/riot-web/issues/14035
628- await this . setKnownRooms ( this . rooms ) ;
629- return true ;
652+ const oldTags = this . roomIdsToTags [ room . roomId ] || [ ] ;
653+ const newTags = this . getTagsForRoom ( room ) ;
654+ const diff = arrayDiff ( oldTags , newTags ) ;
655+ if ( diff . removed . length > 0 || diff . added . length > 0 ) {
656+ for ( const rmTag of diff . removed ) {
657+ // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
658+ console . log ( `Removing ${ room . roomId } from ${ rmTag } ` ) ;
659+ const algorithm : OrderingAlgorithm = this . algorithms [ rmTag ] ;
660+ if ( ! algorithm ) throw new Error ( `No algorithm for ${ rmTag } ` ) ;
661+ await algorithm . handleRoomUpdate ( room , RoomUpdateCause . RoomRemoved ) ;
662+ }
663+ for ( const addTag of diff . added ) {
664+ // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
665+ console . log ( `Adding ${ room . roomId } to ${ addTag } ` ) ;
666+ const algorithm : OrderingAlgorithm = this . algorithms [ addTag ] ;
667+ if ( ! algorithm ) throw new Error ( `No algorithm for ${ addTag } ` ) ;
668+ await algorithm . handleRoomUpdate ( room , RoomUpdateCause . NewRoom ) ;
669+ }
670+
671+ // Update the tag map so we don't regen it in a moment
672+ this . roomIdsToTags [ room . roomId ] = newTags ;
673+
674+ // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
675+ console . log ( `Changing update cause for ${ room . roomId } to TIMELINE to sort rooms` ) ;
676+ cause = RoomUpdateCause . Timeline ;
677+ } else {
678+ // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
679+ console . warn ( `Received no-op update for ${ room . roomId } - changing to TIMELINE update` ) ;
680+ cause = RoomUpdateCause . Timeline ;
681+ }
630682 }
631683
632684 // If the update is for a room change which might be the sticky room, prevent it. We
@@ -640,24 +692,27 @@ export class Algorithm extends EventEmitter {
640692 }
641693 }
642694
643- if ( cause === RoomUpdateCause . NewRoom && ! this . roomIdsToTags [ room . roomId ] ) {
695+ if ( ! this . roomIdsToTags [ room . roomId ] ) {
644696 // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
645- console . log ( `[RoomListDebug] Updating tags for new room ${ room . roomId } (${ room . name } )` ) ;
697+ console . log ( `[RoomListDebug] Updating tags for room ${ room . roomId } (${ room . name } )` ) ;
646698
647699 // Get the tags for the room and populate the cache
648700 const roomTags = this . getTagsForRoom ( room ) . filter ( t => ! isNullOrUndefined ( this . cachedRooms [ t ] ) ) ;
649701
650- // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
651- console . log ( `[RoomListDebug] Updated tags for ${ room . roomId } :` , roomTags ) ;
652-
653702 // "This should never happen" condition - we specify DefaultTagID.Untagged in getTagsForRoom(),
654703 // which means we should *always* have a tag to go off of.
655704 if ( ! roomTags . length ) throw new Error ( `Tags cannot be determined for ${ room . roomId } ` ) ;
656705
657706 this . roomIdsToTags [ room . roomId ] = roomTags ;
707+
708+ // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
709+ console . log ( `[RoomListDebug] Updated tags for ${ room . roomId } :` , roomTags ) ;
658710 }
659711
660- let tags = this . roomIdsToTags [ room . roomId ] ;
712+ // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
713+ console . log ( `[RoomListDebug] Reached algorithmic handling for ${ room . roomId } and cause ${ cause } ` ) ;
714+
715+ const tags = this . roomIdsToTags [ room . roomId ] ;
661716 if ( ! tags ) {
662717 console . warn ( `No tags known for "${ room . name } " (${ room . roomId } )` ) ;
663718 return false ;
@@ -677,7 +732,9 @@ export class Algorithm extends EventEmitter {
677732 changed = true ;
678733 }
679734
680- return true ;
735+ // TODO: Remove debug: https://github.com/vector-im/riot-web/issues/14035
736+ console . log ( `[RoomListDebug] Finished handling ${ room . roomId } with cause ${ cause } (changed=${ changed } )` ) ;
737+ return changed ;
681738 } finally {
682739 this . lock . release ( ) ;
683740 }
0 commit comments