Skip to content

Commit dc364aa

Browse files
committed
Attempt a potential workaround for stuck notifs
1 parent b7b1129 commit dc364aa

File tree

3 files changed

+159
-1
lines changed

3 files changed

+159
-1
lines changed

src/models/event-timeline-set.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,99 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
756756
this.emit(RoomEvent.Timeline, event, this.room, Boolean(toStartOfTimeline), false, data);
757757
}
758758

759+
/**
760+
* Insert event to the given timeline, and emit Room.timeline. Assumes
761+
* we have already checked we don't know about this event.
762+
*
763+
* TEMPORARY: until we have recursive relations, we need this function
764+
* to exist to allow us to insert events in timeline order, which is our
765+
* best guess for Sync Order.
766+
* This is a copy of addEventToTimeline above, modified to insert the event
767+
* after the event it relates to, and before any event with a later
768+
* timestamp. This is our best guess at Sync Order.
769+
*
770+
* Will fire "Room.timeline" for each event added.
771+
*
772+
* @param options - addEventToTimeline options
773+
*
774+
* @remarks
775+
* Fires {@link RoomEvent.Timeline}
776+
*/
777+
public insertEventIntoTimeline(event: MatrixEvent, timeline: EventTimeline, roomState: RoomState): void {
778+
if (timeline.getTimelineSet() !== this) {
779+
throw new Error(`EventTimelineSet.addEventToTimeline: Timeline=${timeline.toString()} does not belong " +
780+
"in timelineSet(threadId=${this.thread?.id})`);
781+
}
782+
783+
// Make sure events don't get mixed in timelines they shouldn't be in (e.g. a
784+
// threaded message should not be in the main timeline).
785+
//
786+
// We can only run this check for timelines with a `room` because `canContain`
787+
// requires it
788+
if (this.room && !this.canContain(event)) {
789+
let eventDebugString = `event=${event.getId()}`;
790+
if (event.threadRootId) {
791+
eventDebugString += `(belongs to thread=${event.threadRootId})`;
792+
}
793+
logger.warn(
794+
`EventTimelineSet.addEventToTimeline: Ignoring ${eventDebugString} that does not belong ` +
795+
`in timeline=${timeline.toString()} timelineSet(threadId=${this.thread?.id})`,
796+
);
797+
return;
798+
}
799+
800+
// Find the event that this event is related to - the "parent"
801+
const parentEventId = event.relationEventId;
802+
if (!parentEventId) {
803+
// Not related to anything - we just append
804+
this.addEventToTimeline(event, timeline, {
805+
toStartOfTimeline: false,
806+
fromCache: false,
807+
timelineWasEmpty: false,
808+
roomState,
809+
});
810+
return;
811+
}
812+
813+
const parentEvent = this.findEventById(parentEventId);
814+
if (!parentEvent) {
815+
// Not related to anything we know about - just append
816+
this.addEventToTimeline(event, timeline, {
817+
toStartOfTimeline: false,
818+
fromCache: false,
819+
timelineWasEmpty: false,
820+
roomState,
821+
});
822+
return;
823+
}
824+
825+
const timelineEvents = timeline.getEvents();
826+
const parentIndex = timelineEvents.indexOf(parentEvent);
827+
let insertIndex = parentIndex;
828+
for (; insertIndex < timelineEvents.length; insertIndex++) {
829+
const nextEvent = timelineEvents[insertIndex];
830+
if (nextEvent.getTs() > event.getTs()) {
831+
// We found an event later than ours, so insert before that.
832+
break;
833+
}
834+
}
835+
// If we got to the end of the loop, insertIndex points at the end of
836+
// the list.
837+
838+
const eventId = event.getId()!;
839+
timeline.insertEvent(event, insertIndex, roomState);
840+
this._eventIdToTimeline.set(eventId, timeline);
841+
842+
this.relations.aggregateParentEvent(event);
843+
this.relations.aggregateChildEvent(event, this);
844+
845+
const data: IRoomTimelineData = {
846+
timeline: timeline,
847+
liveEvent: timeline == this.liveTimeline,
848+
};
849+
this.emit(RoomEvent.Timeline, event, this.room, false, false, data);
850+
}
851+
759852
/**
760853
* Replaces event with ID oldEventId with one with newEventId, if oldEventId is
761854
* recognised. Otherwise, add to the live timeline. Used to handle remote echos.

src/models/event-timeline.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,43 @@ export class EventTimeline {
427427
}
428428
}
429429

430+
/**
431+
* Insert a new event into the timeline, and update the state.
432+
*
433+
* TEMPORARY: until we have recursive relations, we need this function
434+
* to exist to allow us to insert events in timeline order, which is our
435+
* best guess for Sync Order.
436+
* This is a copy of addEvent above, modified to allow inserting an event at
437+
* a specific index.
438+
*/
439+
public insertEvent(event: MatrixEvent, insertIndex: number, roomState: RoomState): void {
440+
const timelineSet = this.getTimelineSet();
441+
442+
if (timelineSet.room) {
443+
EventTimeline.setEventMetadata(event, roomState, false);
444+
445+
// modify state but only on unfiltered timelineSets
446+
if (event.isState() && timelineSet.room.getUnfilteredTimelineSet() === timelineSet) {
447+
roomState.setStateEvents([event], {});
448+
// it is possible that the act of setting the state event means we
449+
// can set more metadata (specifically sender/target props), so try
450+
// it again if the prop wasn't previously set. It may also mean that
451+
// the sender/target is updated (if the event set was a room member event)
452+
// so we want to use the *updated* member (new avatar/name) instead.
453+
//
454+
// However, we do NOT want to do this on member events if we're going
455+
// back in time, else we'll set the .sender value for BEFORE the given
456+
// member event, whereas we want to set the .sender value for the ACTUAL
457+
// member event itself.
458+
if (!event.sender || event.getType() === EventType.RoomMember) {
459+
EventTimeline.setEventMetadata(event, roomState!, false);
460+
}
461+
}
462+
}
463+
464+
this.events.splice(insertIndex, 0, event); // insert element
465+
}
466+
430467
/**
431468
* Remove an event from the timeline
432469
*

src/models/thread.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,31 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
236236
}
237237
}
238238

239+
/**
240+
* TEMPORARY. Only call this when MSC3981 is not available, and we have some
241+
* late-arriving events to insert, because we recursively found them as part
242+
* of populating a thread. When we have MSC3981 we won't need it, because
243+
* they will all be supplied by the homeserver in one request, and they will
244+
* already be in the right order in that response.
245+
* This is a copy of addEventToTimeline above, modified to call
246+
* insertEventIntoTimeline so this event is inserted into our best guess of
247+
* the right place based on timestamp. (We should be using Sync Order but we
248+
* don't have it.)
249+
*/
250+
public insertEventIntoTimeline(event: MatrixEvent): void {
251+
const eventId = event.getId();
252+
if (!eventId) {
253+
return;
254+
}
255+
if (this.findEventById(eventId)) {
256+
return;
257+
}
258+
this.timelineSet.insertEventIntoTimeline(event, this.liveTimeline, this.roomState);
259+
260+
// As far as we know, timeline should always be the same as events
261+
this.timeline = this.events;
262+
}
263+
239264
public addEvents(events: MatrixEvent[], toStartOfTimeline: boolean): void {
240265
events.forEach((ev) => this.addEvent(ev, toStartOfTimeline, false));
241266
this.updateThreadMetadata();
@@ -281,7 +306,8 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
281306
*/
282307
this.replayEvents?.push(event);
283308
} else {
284-
this.addEventToTimeline(event, toStartOfTimeline);
309+
// TODO: check with Germain is this right?
310+
this.insertEventIntoTimeline(event);
285311
}
286312
// Apply annotations and replace relations to the relations of the timeline only
287313
this.timelineSet.relations?.aggregateParentEvent(event);
@@ -473,6 +499,8 @@ export class Thread extends ReadReceipt<EmittedEvents, EventHandlerMap> {
473499
.then((relations) => {
474500
if (relations.events.length) {
475501
event.makeReplaced(relations.events[0]);
502+
// TODO: check with Germain: is this right?
503+
this.insertEventIntoTimeline(event);
476504
}
477505
})
478506
.catch((e) => {

0 commit comments

Comments
 (0)