forked from mystiq/hydrogen-web
also pass timeline entries to summary after initial decryption failed
This commit is contained in:
parent
f3f07a0672
commit
49f330279b
2 changed files with 77 additions and 14 deletions
|
@ -70,8 +70,15 @@ export class Room extends EventEmitter {
|
||||||
await decryptRequest.complete();
|
await decryptRequest.complete();
|
||||||
|
|
||||||
this._timeline?.replaceEntries(retryEntries);
|
this._timeline?.replaceEntries(retryEntries);
|
||||||
|
// we would ideally write the room summary in the same txn as the groupSessionDecryptions in the
|
||||||
|
// _decryptEntries entries and could even know which events have been decrypted for the first
|
||||||
|
// time from DecryptionChanges.write and only pass those to the summary. As timeline changes
|
||||||
|
// are not essential to the room summary, it's fine to write this in a separate txn for now.
|
||||||
|
const changes = this._summary.processTimelineEntries(retryEntries, false, this._isTimelineOpen);
|
||||||
|
if (changes) {
|
||||||
|
this._summary.writeAndApplyChanges(changes, this._storage);
|
||||||
|
this._emitUpdate();
|
||||||
}
|
}
|
||||||
// pass decryptedEntries to roomSummary
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,19 @@ limitations under the License.
|
||||||
|
|
||||||
import {MEGOLM_ALGORITHM} from "../e2ee/common.js";
|
import {MEGOLM_ALGORITHM} from "../e2ee/common.js";
|
||||||
|
|
||||||
function applySyncResponse(data, roomResponse, timelineEntries, membership, isInitialSync, isTimelineOpen, ownUserId) {
|
|
||||||
|
function applyTimelineEntries(data, timelineEntries, isInitialSync, isTimelineOpen, ownUserId) {
|
||||||
|
if (timelineEntries.length) {
|
||||||
|
data = timelineEntries.reduce((data, entry) => {
|
||||||
|
return processTimelineEvent(data, entry,
|
||||||
|
isInitialSync, isTimelineOpen, ownUserId);
|
||||||
|
}, data);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function applySyncResponse(data, roomResponse, membership) {
|
||||||
if (roomResponse.summary) {
|
if (roomResponse.summary) {
|
||||||
data = updateSummary(data, roomResponse.summary);
|
data = updateSummary(data, roomResponse.summary);
|
||||||
}
|
}
|
||||||
|
@ -31,13 +43,14 @@ function applySyncResponse(data, roomResponse, timelineEntries, membership, isIn
|
||||||
if (roomResponse.state) {
|
if (roomResponse.state) {
|
||||||
data = roomResponse.state.events.reduce(processStateEvent, data);
|
data = roomResponse.state.events.reduce(processStateEvent, data);
|
||||||
}
|
}
|
||||||
if (timelineEntries.length) {
|
const {timeline} = roomResponse;
|
||||||
data = timelineEntries.reduce((data, entry) => {
|
// process state events in timeline
|
||||||
if (typeof entry.stateKey === "string") {
|
// non-state events are handled by applyTimelineEntries
|
||||||
return processStateEvent(data, entry.event);
|
// so decryption is handled properly
|
||||||
} else {
|
if (timeline && Array.isArray(timeline.events)) {
|
||||||
return processTimelineEvent(data, entry,
|
data = timeline.events.reduce((data, event) => {
|
||||||
isInitialSync, isTimelineOpen, ownUserId);
|
if (typeof event.state_key === "string") {
|
||||||
|
return processStateEvent(data, event);
|
||||||
}
|
}
|
||||||
}, data);
|
}, data);
|
||||||
}
|
}
|
||||||
|
@ -92,15 +105,19 @@ function processStateEvent(data, event) {
|
||||||
|
|
||||||
function processTimelineEvent(data, eventEntry, isInitialSync, isTimelineOpen, ownUserId) {
|
function processTimelineEvent(data, eventEntry, isInitialSync, isTimelineOpen, ownUserId) {
|
||||||
if (eventEntry.eventType === "m.room.message") {
|
if (eventEntry.eventType === "m.room.message") {
|
||||||
|
if (!data.lastMessageTimestamp || eventEntry.timestamp > data.lastMessageTimestamp) {
|
||||||
data = data.cloneIfNeeded();
|
data = data.cloneIfNeeded();
|
||||||
data.lastMessageTimestamp = eventEntry.timestamp;
|
data.lastMessageTimestamp = eventEntry.timestamp;
|
||||||
|
}
|
||||||
if (!isInitialSync && eventEntry.sender !== ownUserId && !isTimelineOpen) {
|
if (!isInitialSync && eventEntry.sender !== ownUserId && !isTimelineOpen) {
|
||||||
|
data = data.cloneIfNeeded();
|
||||||
data.isUnread = true;
|
data.isUnread = true;
|
||||||
}
|
}
|
||||||
const {content} = eventEntry;
|
const {content} = eventEntry;
|
||||||
const body = content?.body;
|
const body = content?.body;
|
||||||
const msgtype = content?.msgtype;
|
const msgtype = content?.msgtype;
|
||||||
if (msgtype === "m.text" && !eventEntry.isEncrypted) {
|
if (msgtype === "m.text" && !eventEntry.isEncrypted) {
|
||||||
|
data = data.cloneIfNeeded();
|
||||||
data.lastMessageBody = body;
|
data.lastMessageBody = body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,14 +283,34 @@ export class RoomSummary {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* after retrying decryption
|
||||||
|
*/
|
||||||
|
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,
|
||||||
|
timelineEntries,
|
||||||
|
isInitialSync, isTimelineOpen,
|
||||||
|
this._ownUserId);
|
||||||
|
if (data !== this._data) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
writeSync(roomResponse, timelineEntries, membership, isInitialSync, isTimelineOpen, txn) {
|
writeSync(roomResponse, timelineEntries, membership, isInitialSync, isTimelineOpen, txn) {
|
||||||
// clear cloned flag, so cloneIfNeeded makes a copy and
|
// clear cloned flag, so cloneIfNeeded makes a copy and
|
||||||
// this._data is not modified if any field is changed.
|
// this._data is not modified if any field is changed.
|
||||||
this._data.cloned = false;
|
this._data.cloned = false;
|
||||||
const data = applySyncResponse(
|
let data = applySyncResponse(this._data, roomResponse, membership);
|
||||||
this._data, roomResponse,
|
data = applyTimelineEntries(
|
||||||
|
this._data,
|
||||||
timelineEntries,
|
timelineEntries,
|
||||||
membership,
|
|
||||||
isInitialSync, isTimelineOpen,
|
isInitialSync, isTimelineOpen,
|
||||||
this._ownUserId);
|
this._ownUserId);
|
||||||
if (data !== this._data) {
|
if (data !== this._data) {
|
||||||
|
@ -282,6 +319,25 @@ export class RoomSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only to be used with processTimelineEntries,
|
||||||
|
* other methods like writeSync, writeHasFetchedMembers,
|
||||||
|
* writeIsTrackingMembers, ... take a txn directly.
|
||||||
|
*/
|
||||||
|
async writeAndApplyChanges(data, storage) {
|
||||||
|
const txn = await storage.readTxn([
|
||||||
|
storage.storeNames.roomSummary,
|
||||||
|
]);
|
||||||
|
try {
|
||||||
|
txn.roomSummary.set(data.serialize());
|
||||||
|
} catch (err) {
|
||||||
|
txn.abort();
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
await txn.complete();
|
||||||
|
this.applyChanges(data);
|
||||||
|
}
|
||||||
|
|
||||||
applyChanges(data) {
|
applyChanges(data) {
|
||||||
this._data = data;
|
this._data = data;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue