From ec0de15da60524df83cb4942a6a38352377ec10d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 22 Apr 2021 17:21:29 +0200 Subject: [PATCH] handle overlap with existing timeline when rejoining room --- src/matrix/room/Room.js | 3 +- .../room/timeline/persistence/SyncWriter.js | 31 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/matrix/room/Room.js b/src/matrix/room/Room.js index 02b19a18..f75b1148 100644 --- a/src/matrix/room/Room.js +++ b/src/matrix/room/Room.js @@ -248,8 +248,9 @@ export class Room extends EventEmitter { /** @package */ async writeSync(roomResponse, isInitialSync, {summaryChanges, decryptChanges, roomEncryption, retryEntries}, txn, log) { log.set("id", this.id); + const isRejoin = summaryChanges.membership === "join" && this._summary.data.membership === "leave"; const {entries: newEntries, newLiveKey, memberChanges} = - await log.wrap("syncWriter", log => this._syncWriter.writeSync(roomResponse, txn, log), log.level.Detail); + await log.wrap("syncWriter", log => this._syncWriter.writeSync(roomResponse, isRejoin, txn, log), log.level.Detail); let allEntries = newEntries; if (decryptChanges) { const decryption = await log.wrap("decryptChanges", log => decryptChanges.write(txn, log)); diff --git a/src/matrix/room/timeline/persistence/SyncWriter.js b/src/matrix/room/timeline/persistence/SyncWriter.js index 4913ac53..dc2344e5 100644 --- a/src/matrix/room/timeline/persistence/SyncWriter.js +++ b/src/matrix/room/timeline/persistence/SyncWriter.js @@ -190,6 +190,26 @@ export class SyncWriter { return currentKey; } + async _handleRejoinOverlap(timeline, txn, log) { + if (this._lastLiveKey) { + const {fragmentId} = this._lastLiveKey; + const [lastEvent] = await txn.timelineEvents.lastEvents(this._roomId, fragmentId, 1); + if (lastEvent) { + const lastEventId = lastEvent.event.event_id; + const {events} = timeline; + const index = events.findIndex(event => event.event_id === lastEventId); + if (index !== -1) { + log.set("overlap_event_id", lastEventId); + return { + limited: false, + events: events.slice(index + 1) + }; + } + } + } + return timeline; + } + /** * @type {SyncWriterResult} * @property {Array} entries new timeline entries written @@ -197,12 +217,19 @@ export class SyncWriter { * @property {Map} memberChanges member changes in the processed sync ny user id * * @param {Object} roomResponse [description] + * @param {boolean} isRejoin whether the room was rejoined in the sync being processed * @param {Transaction} txn * @return {SyncWriterResult} */ - async writeSync(roomResponse, txn, log) { + async writeSync(roomResponse, isRejoin, txn, log) { const entries = []; - const {timeline} = roomResponse; + let {timeline} = roomResponse; + // we have rejoined the room after having synced it before, + // check for overlap with the last synced event + log.set("isRejoin", isRejoin); + if (isRejoin) { + timeline = await this._handleRejoinOverlap(timeline, txn, log); + } const memberChanges = new Map(); // important this happens before _writeTimeline so // members are available in the transaction