From 053dddb76d829b29d3a8aeba8aba826d0bc99336 Mon Sep 17 00:00:00 2001 From: The one with the braid Date: Fri, 22 Sep 2023 09:42:07 +0200 Subject: [PATCH 1/4] chore: incrementally add left rooms to archive - store left rooms in archive during sync (as well as they are removed on join already) - refactor room archive code - fix typo Internal reference: SMC-385 Signed-off-by: The one with the braid --- lib/src/client.dart | 117 ++++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/lib/src/client.dart b/lib/src/client.dart index 23fa4769..61470a12 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -261,7 +261,7 @@ class Client extends MatrixApi { bool enableDehydratedDevices = false; - /// Wether read receipts are sent as public receipts by default or just as private receipts. + /// Whether read receipts are sent as public receipts by default or just as private receipts. bool receiptsPublicByDefault = true; /// Whether this client supports end-to-end encryption using olm. @@ -933,60 +933,66 @@ class Client extends MatrixApi { final leave = syncResp.rooms?.leave; if (leave != null) { for (final entry in leave.entries) { - final id = entry.key; - final room = entry.value; - final leftRoom = Room( - id: id, - membership: Membership.leave, - client: this, - roomAccountData: - room.accountData?.asMap().map((k, v) => MapEntry(v.type, v)) ?? - {}, - ); - - final timeline = Timeline( - room: leftRoom, - chunk: TimelineChunk( - events: room.timeline?.events?.reversed - .toList() // we display the event in the other sence - .map((e) => Event.fromMatrixEvent(e, leftRoom)) - .toList() ?? - [])); - - leftRoom.prev_batch = room.timeline?.prevBatch; - room.state?.forEach((event) { - leftRoom.setState(Event.fromMatrixEvent( - event, - leftRoom, - )); - }); - - room.timeline?.events?.forEach((event) { - leftRoom.setState(Event.fromMatrixEvent( - event, - leftRoom, - )); - }); - - for (var i = 0; i < timeline.events.length; i++) { - // Try to decrypt encrypted events but don't update the database. - if (leftRoom.encrypted && leftRoom.client.encryptionEnabled) { - if (timeline.events[i].type == EventTypes.Encrypted) { - timeline.events[i] = - await leftRoom.client.encryption!.decryptRoomEvent( - leftRoom.id, - timeline.events[i], - ); - } - } - } - - _archivedRooms.add(ArchivedRoom(room: leftRoom, timeline: timeline)); + await _storeArchivedRoom(entry.key, entry.value); } } return _archivedRooms; } + Future _storeArchivedRoom(String id, LeftRoomUpdate update) async { + final room = update; + final leftRoom = Room( + id: id, + membership: Membership.leave, + client: this, + roomAccountData: + room.accountData?.asMap().map((k, v) => MapEntry(v.type, v)) ?? + {}, + ); + + final timeline = Timeline( + room: leftRoom, + chunk: TimelineChunk( + events: room.timeline?.events?.reversed + .toList() // we display the event in the other sence + .map((e) => Event.fromMatrixEvent(e, leftRoom)) + .toList() ?? + [])); + + leftRoom.prev_batch = room.timeline?.prevBatch; + room.state?.forEach((event) { + leftRoom.setState(Event.fromMatrixEvent( + event, + leftRoom, + )); + }); + + room.timeline?.events?.forEach((event) { + leftRoom.setState(Event.fromMatrixEvent( + event, + leftRoom, + )); + }); + + for (var i = 0; i < timeline.events.length; i++) { + // Try to decrypt encrypted events but don't update the database. + if (leftRoom.encrypted && leftRoom.client.encryptionEnabled) { + if (timeline.events[i].type == EventTypes.Encrypted) { + await leftRoom.client.encryption! + .decryptRoomEvent( + leftRoom.id, + timeline.events[i], + ) + .then( + (decrypted) => timeline.events[i] = decrypted, + ); + } + } + } + + _archivedRooms.add(ArchivedRoom(room: leftRoom, timeline: timeline)); + } + /// Uploads a file and automatically caches it in the database, if it is small enough /// and returns the mxc url. @override @@ -1885,7 +1891,7 @@ class Client extends MatrixApi { final syncRoomUpdate = entry.value; await database?.storeRoomUpdate(id, syncRoomUpdate, this); - final room = _updateRoomsByRoomUpdate(id, syncRoomUpdate); + final room = await _updateRoomsByRoomUpdate(id, syncRoomUpdate); final timelineUpdateType = direction != null ? (direction == Direction.b @@ -2125,7 +2131,8 @@ class Client extends MatrixApi { } } - Room _updateRoomsByRoomUpdate(String roomId, SyncRoomUpdate chatUpdate) { + Future _updateRoomsByRoomUpdate( + String roomId, SyncRoomUpdate chatUpdate) async { // Update the chat list item. // Search the room in the rooms final roomIndex = rooms.indexWhere((r) => r.id == roomId); @@ -2169,7 +2176,7 @@ class Client extends MatrixApi { rooms.removeAt(roomIndex); } - // Update notification, highlight count and/or additional informations + // Update notification, highlight count and/or additional information else if (found && chatUpdate is JoinedRoomUpdate && (rooms[roomIndex].membership != membership || @@ -2202,6 +2209,10 @@ class Client extends MatrixApi { runInRoot(rooms[roomIndex].requestHistory); } } + // in order to keep the archive in sync, add left room to archive + if (chatUpdate is LeftRoomUpdate) { + await _storeArchivedRoom(room.id, chatUpdate); + } return room; } From 0ec6a64cc83f18af88aba665903d3636cf3242f8 Mon Sep 17 00:00:00 2001 From: Clemens-Toegel <42837076+Clemens-Toegel@users.noreply.github.com> Date: Fri, 13 Oct 2023 10:14:20 +0200 Subject: [PATCH 2/4] chore: store states to archived rooms (#1) * chore: store states to archived rooms * chore: PR fix --------- Co-authored-by: Clemens Toegel --- lib/src/client.dart | 67 ++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/lib/src/client.dart b/lib/src/client.dart index 61470a12..d6fd346a 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -939,48 +939,58 @@ class Client extends MatrixApi { return _archivedRooms; } - Future _storeArchivedRoom(String id, LeftRoomUpdate update) async { - final room = update; - final leftRoom = Room( - id: id, - membership: Membership.leave, - client: this, - roomAccountData: - room.accountData?.asMap().map((k, v) => MapEntry(v.type, v)) ?? + /// [_storeArchivedRoom] + /// @leftRoom we can pass a room which was left so that we don't loose states + Future _storeArchivedRoom( + String id, + LeftRoomUpdate update, { + Room? leftRoom, + }) async { + final roomUpdate = update; + final archivedRoom = leftRoom ?? + Room( + id: id, + membership: Membership.leave, + client: this, + roomAccountData: roomUpdate.accountData + ?.asMap() + .map((k, v) => MapEntry(v.type, v)) ?? {}, - ); - + ); + // Set membership of room to leave, in the case we got a left room passed, otherwise + // the left room would have still membership join, which would be wrong for the setState later + archivedRoom.membership = Membership.leave; final timeline = Timeline( - room: leftRoom, + room: archivedRoom, chunk: TimelineChunk( - events: room.timeline?.events?.reversed + events: roomUpdate.timeline?.events?.reversed .toList() // we display the event in the other sence - .map((e) => Event.fromMatrixEvent(e, leftRoom)) + .map((e) => Event.fromMatrixEvent(e, archivedRoom)) .toList() ?? [])); - leftRoom.prev_batch = room.timeline?.prevBatch; - room.state?.forEach((event) { - leftRoom.setState(Event.fromMatrixEvent( + archivedRoom.prev_batch = update.timeline?.prevBatch; + update.state?.forEach((event) { + archivedRoom.setState(Event.fromMatrixEvent( event, - leftRoom, + archivedRoom, )); }); - room.timeline?.events?.forEach((event) { - leftRoom.setState(Event.fromMatrixEvent( + update.timeline?.events?.forEach((event) { + archivedRoom.setState(Event.fromMatrixEvent( event, - leftRoom, + archivedRoom, )); }); for (var i = 0; i < timeline.events.length; i++) { // Try to decrypt encrypted events but don't update the database. - if (leftRoom.encrypted && leftRoom.client.encryptionEnabled) { + if (archivedRoom.encrypted && archivedRoom.client.encryptionEnabled) { if (timeline.events[i].type == EventTypes.Encrypted) { - await leftRoom.client.encryption! + await archivedRoom.client.encryption! .decryptRoomEvent( - leftRoom.id, + archivedRoom.id, timeline.events[i], ) .then( @@ -990,7 +1000,7 @@ class Client extends MatrixApi { } } - _archivedRooms.add(ArchivedRoom(room: leftRoom, timeline: timeline)); + _archivedRooms.add(ArchivedRoom(room: archivedRoom, timeline: timeline)); } /// Uploads a file and automatically caches it in the database, if it is small enough @@ -2175,6 +2185,11 @@ class Client extends MatrixApi { room.stopStaleCallsChecker(room.id); rooms.removeAt(roomIndex); + + // in order to keep the archive in sync, add left room to archive + if (chatUpdate is LeftRoomUpdate) { + await _storeArchivedRoom(room.id, chatUpdate, leftRoom: room); + } } // Update notification, highlight count and/or additional information else if (found && @@ -2209,10 +2224,6 @@ class Client extends MatrixApi { runInRoot(rooms[roomIndex].requestHistory); } } - // in order to keep the archive in sync, add left room to archive - if (chatUpdate is LeftRoomUpdate) { - await _storeArchivedRoom(room.id, chatUpdate); - } return room; } From f1fd6f43f9a88729785ddf729e41a5be7d985fbc Mon Sep 17 00:00:00 2001 From: Clemens-Toegel <42837076+Clemens-Toegel@users.noreply.github.com> Date: Fri, 20 Oct 2023 09:50:01 +0200 Subject: [PATCH 3/4] chore: remove archived room on forget (#2) Co-authored-by: Clemens Toegel --- lib/src/room.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/src/room.dart b/lib/src/room.dart index 861f41d2..37ed4f5e 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -1187,6 +1187,12 @@ class Room { Future forget() async { await client.database?.forgetRoom(id); await client.forgetRoom(id); + // Update archived rooms, otherwise an archived room may still be in the + // list after a forget room call + final roomIndex = client.archivedRooms.indexWhere((r) => r.room.id == id); + if(roomIndex != -1){ + client.archivedRooms.removeAt(roomIndex); + } return; } From 5dea95f02c103be0a572122835063b1a220e2802 Mon Sep 17 00:00:00 2001 From: The one with the braid Date: Fri, 20 Oct 2023 12:57:54 +0200 Subject: [PATCH 4/4] fix: Code style Signed-off-by: The one with the braid --- lib/src/client.dart | 2 +- lib/src/room.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/client.dart b/lib/src/client.dart index d6fd346a..cc027207 100644 --- a/lib/src/client.dart +++ b/lib/src/client.dart @@ -2221,7 +2221,7 @@ class Client extends MatrixApi { requestHistoryOnLimitedTimeline) { Logs().v( 'Limited timeline for ${rooms[roomIndex].id} request history now'); - runInRoot(rooms[roomIndex].requestHistory); + unawaited(runInRoot(rooms[roomIndex].requestHistory)); } } return room; diff --git a/lib/src/room.dart b/lib/src/room.dart index 37ed4f5e..d9327ab9 100644 --- a/lib/src/room.dart +++ b/lib/src/room.dart @@ -1190,7 +1190,7 @@ class Room { // Update archived rooms, otherwise an archived room may still be in the // list after a forget room call final roomIndex = client.archivedRooms.indexWhere((r) => r.room.id == id); - if(roomIndex != -1){ + if (roomIndex != -1) { client.archivedRooms.removeAt(roomIndex); } return;