diff --git a/src/event-mapper.ts b/src/event-mapper.ts index 9b9384860..73d442039 100644 --- a/src/event-mapper.ts +++ b/src/event-mapper.ts @@ -29,7 +29,21 @@ export function eventMapperFor(client: MatrixClient, options: MapperOpts): Event const decrypt = options.decrypt !== false; function mapper(plainOldJsObject: Partial) { - const event = new MatrixEvent(plainOldJsObject); + const room = client.getRoom(plainOldJsObject.room_id); + let event: MatrixEvent; + + // If the event is already known to the room, let's re-use the model + // rather than creating a duplicate + if (room) { + event = room.findEventById(plainOldJsObject.event_id); + } + + // If no event is found or if the event found was only local we can + // safely create a new model + if (!event || event.status) { + event = new MatrixEvent(plainOldJsObject); + } + if (event.isEncrypted()) { if (!preventReEmit) { client.reEmitter.reEmit(event, [ diff --git a/src/models/event.ts b/src/models/event.ts index f95f3f3e2..147758056 100644 --- a/src/models/event.ts +++ b/src/models/event.ts @@ -277,7 +277,7 @@ export class MatrixEvent extends EventEmitter { * it to us and the time we're now constructing this event, but that's better * than assuming the local clock is in sync with the origin HS's clock. */ - public readonly localTimestamp: number; + public localTimestamp: number; // XXX: these should be read-only public sender: RoomMember = null; @@ -342,7 +342,7 @@ export class MatrixEvent extends EventEmitter { }); this.txnId = event.txn_id || null; - this.localTimestamp = Date.now() - this.getAge(); + this.localTimestamp = Date.now() - (this.getAge() ?? 0); this.reEmitter = new ReEmitter(this); } @@ -584,9 +584,10 @@ export class MatrixEvent extends EventEmitter { * Get the age of this event. This represents the age of the event when the * event arrived at the device, and not the age of the event when this * function was called. - * @return {Number} The age of this event in milliseconds. + * Can only be returned once the server has echo'ed back + * @return {Number|undefined} The age of this event in milliseconds. */ - public getAge(): number { + public getAge(): number | undefined { return this.getUnsigned().age || this.event.age; // v2 / v1 } @@ -1269,6 +1270,8 @@ export class MatrixEvent extends EventEmitter { // emit the event if it changed this.emit("Event.localEventIdReplaced", this); } + + this.localTimestamp = Date.now() - this.getAge(); } /** diff --git a/src/models/thread.ts b/src/models/thread.ts index b882f7904..85f94b986 100644 --- a/src/models/thread.ts +++ b/src/models/thread.ts @@ -77,8 +77,6 @@ export class Thread extends TypedEventEmitter { }); this.reEmitter = new ReEmitter(this); - this.initialiseThread(this.rootEvent); - this.reEmitter.reEmit(this.timelineSet, [ "Room.timeline", "Room.timelineReset", @@ -92,6 +90,7 @@ export class Thread extends TypedEventEmitter { } else { this.id = rootEvent.getId(); } + this.initialiseThread(this.rootEvent); opts?.initialEvents?.forEach(event => this.addEvent(event));