diff --git a/src/matrix/room/Room.js b/src/matrix/room/Room.js index 99c2155e..2b9c3355 100644 --- a/src/matrix/room/Room.js +++ b/src/matrix/room/Room.js @@ -52,6 +52,15 @@ export class Room extends EventEmitter { this._clock = clock; } + _readEntriesToRetryDecryption(retryEventIds) { + const readFromEventKey = retryEventIds.length !== 0; + const stores = + const txn = await this._storage.readTxn([ + this._storage.storeNames.timelineEvents, + this._storage.storeNames.inboundGroupSessions, + ]); + } + async notifyRoomKeys(roomKeys) { if (this._roomEncryption) { let retryEventIds = this._roomEncryption.applyRoomKeys(roomKeys); diff --git a/src/matrix/room/RoomSummary.js b/src/matrix/room/RoomSummary.js index 21739a1e..9859a4f6 100644 --- a/src/matrix/room/RoomSummary.js +++ b/src/matrix/room/RoomSummary.js @@ -122,6 +122,23 @@ function processTimelineEvent(data, eventEntry, isInitialSync, isTimelineOpen, o data.lastMessageBody = body; } } + // store the event key of the last decrypted event so when decryption does succeed, + // we can attempt to re-decrypt from this point to update the room summary + if (!!data.encryption && eventEntry.isEncrypted && eventEntry.isDecrypted) { + let hasLargerEventKey = true; + if (data.lastDecryptedEventKey) { + try { + hasLargerEventKey = eventEntry.compare(data.lastDecryptedEventKey) > 0; + } catch (err) { + hasLargerEventKey = false; + } + } + if (hasLargerEventKey) { + data = data.cloneIfNeeded(); + const {fragmentId, entryIndex} = eventEntry; + data.lastDecryptedEventKey = {fragmentId, entryIndex}; + } + } return data; } @@ -155,6 +172,7 @@ class SummaryData { this.lastMessageTimestamp = copy ? copy.lastMessageTimestamp : null; this.isUnread = copy ? copy.isUnread : false; this.encryption = copy ? copy.encryption : null; + this.lastDecryptedEventKey = copy ? copy.lastDecryptedEventKey : null; this.isDirectMessage = copy ? copy.isDirectMessage : false; this.membership = copy ? copy.membership : null; this.inviteCount = copy ? copy.inviteCount : 0; @@ -261,6 +279,10 @@ export class RoomSummary { return this._data.tags; } + get lastDecryptedEventKey() { + return this._data.lastDecryptedEventKey; + } + writeClearUnread(txn) { const data = new SummaryData(this._data); data.isUnread = false; @@ -290,9 +312,6 @@ export class RoomSummary { processTimelineEntries(timelineEntries, isInitialSync, isTimelineOpen) { // clear cloned flag, so cloneIfNeeded makes a copy and // this._data is not modified if any field is changed. - - processTimelineEvent - this._data.cloned = false; const data = applyTimelineEntries( this._data, diff --git a/src/matrix/room/timeline/entries/EventEntry.js b/src/matrix/room/timeline/entries/EventEntry.js index 81e31112..410c3d63 100644 --- a/src/matrix/room/timeline/entries/EventEntry.js +++ b/src/matrix/room/timeline/entries/EventEntry.js @@ -82,6 +82,10 @@ export class EventEntry extends BaseEntry { return this._eventEntry.event.type === "m.room.encrypted"; } + get isDecrypted() { + return !!this._decryptionResult?.event; + } + get isVerified() { return this.isEncrypted && this._decryptionResult?.isVerified; } diff --git a/src/matrix/room/timeline/persistence/TimelineReader.js b/src/matrix/room/timeline/persistence/TimelineReader.js index f5983a19..7e832b32 100644 --- a/src/matrix/room/timeline/persistence/TimelineReader.js +++ b/src/matrix/room/timeline/persistence/TimelineReader.js @@ -37,6 +37,44 @@ class ReaderRequest { } } + +export async function readFromWithTxn(eventKey, direction, amount, r, txn) { + let entries = []; + const timelineStore = txn.timelineEvents; + const fragmentStore = txn.timelineFragments; + + while (entries.length < amount && eventKey) { + let eventsWithinFragment; + if (direction.isForward) { + eventsWithinFragment = await timelineStore.eventsAfter(this._roomId, eventKey, amount); + } else { + eventsWithinFragment = await timelineStore.eventsBefore(this._roomId, eventKey, amount); + } + let eventEntries = eventsWithinFragment.map(e => new EventEntry(e, this._fragmentIdComparer)); + entries = directionalConcat(entries, eventEntries, direction); + // prepend or append eventsWithinFragment to entries, and wrap them in EventEntry + + if (entries.length < amount) { + const fragment = await fragmentStore.get(this._roomId, eventKey.fragmentId); + // this._fragmentIdComparer.addFragment(fragment); + let fragmentEntry = new FragmentBoundaryEntry(fragment, direction.isBackward, this._fragmentIdComparer); + // append or prepend fragmentEntry, reuse func from GapWriter? + directionalAppend(entries, fragmentEntry, direction); + // only continue loading if the fragment boundary can't be backfilled + if (!fragmentEntry.token && fragmentEntry.hasLinkedFragment) { + const nextFragment = await fragmentStore.get(this._roomId, fragmentEntry.linkedFragmentId); + this._fragmentIdComparer.add(nextFragment); + const nextFragmentEntry = new FragmentBoundaryEntry(nextFragment, direction.isForward, this._fragmentIdComparer); + directionalAppend(entries, nextFragmentEntry, direction); + eventKey = nextFragmentEntry.asEventKey(); + } else { + eventKey = null; + } + } + } + return entries; +} + export class TimelineReader { constructor({roomId, storage, fragmentIdComparer}) { this._roomId = roomId; @@ -87,40 +125,7 @@ export class TimelineReader { } async _readFrom(eventKey, direction, amount, r, txn) { - let entries = []; - const timelineStore = txn.timelineEvents; - const fragmentStore = txn.timelineFragments; - - while (entries.length < amount && eventKey) { - let eventsWithinFragment; - if (direction.isForward) { - eventsWithinFragment = await timelineStore.eventsAfter(this._roomId, eventKey, amount); - } else { - eventsWithinFragment = await timelineStore.eventsBefore(this._roomId, eventKey, amount); - } - let eventEntries = eventsWithinFragment.map(e => new EventEntry(e, this._fragmentIdComparer)); - entries = directionalConcat(entries, eventEntries, direction); - // prepend or append eventsWithinFragment to entries, and wrap them in EventEntry - - if (entries.length < amount) { - const fragment = await fragmentStore.get(this._roomId, eventKey.fragmentId); - // this._fragmentIdComparer.addFragment(fragment); - let fragmentEntry = new FragmentBoundaryEntry(fragment, direction.isBackward, this._fragmentIdComparer); - // append or prepend fragmentEntry, reuse func from GapWriter? - directionalAppend(entries, fragmentEntry, direction); - // only continue loading if the fragment boundary can't be backfilled - if (!fragmentEntry.token && fragmentEntry.hasLinkedFragment) { - const nextFragment = await fragmentStore.get(this._roomId, fragmentEntry.linkedFragmentId); - this._fragmentIdComparer.add(nextFragment); - const nextFragmentEntry = new FragmentBoundaryEntry(nextFragment, direction.isForward, this._fragmentIdComparer); - directionalAppend(entries, nextFragmentEntry, direction); - eventKey = nextFragmentEntry.asEventKey(); - } else { - eventKey = null; - } - } - } - + const entries = readFromWithTxn(eventKey, direction, amount, r, txn); if (this._decryptEntries) { r.decryptRequest = this._decryptEntries(entries, txn); try {