Skip to content

Commit f19f0a8

Browse files
andybalaamrichvdh
andauthoredOct 9, 2023
Comments attempting to explain the addEvent method (#3786)
* Warn when we drop an event trying to add it to a thread Added to try and help debug element-hq/element-web#26254 * Comment trying to explain lastEvent * Document some of my understanding of the addEvent logic * Refer to stable spec instead of MSC Co-authored-by: Richard van der Hoff <[email protected]> * Re-word comments based on review --------- Co-authored-by: Richard van der Hoff <[email protected]>
1 parent a5224c1 commit f19f0a8

File tree

1 file changed

+65
-6
lines changed

1 file changed

+65
-6
lines changed
 

‎src/models/thread.ts

+65-6
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,40 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
9090

9191
private reEmitter: TypedReEmitter<ThreadEmittedEvents, ThreadEventHandlerMap>;
9292

93+
/**
94+
* The last event in this thread, if we don't yet have this in the timeline.
95+
*
96+
* When we run {@link processRootEvent} (which I think happens during the
97+
* setting-up of the thread), we set this to the event pointed to by the
98+
* server in `latest_event` [1] that came through with the thread root.
99+
*
100+
* [1]: https://spec.matrix.org/v1.8/client-server-api/#server-side-aggregation-of-mthread-relationships
101+
*
102+
* Later, when we have populated the timeline, this is set to undefined, so
103+
* that methods like {@link replyToEvent} fall through to use lastReply,
104+
* which looks in the timeline for the latest event that is a "thread reply"
105+
* i.e. directly refers to the thread root with an m.thread relation.
106+
*
107+
* So it looks like this is only really relevant when initialEventsFetched
108+
* is false, because as soon as the initial events have been fetched, we
109+
* should have a timeline (I think).
110+
*
111+
* If all replies in this thread are redacted, this is set to the root
112+
* event. I'm not clear what the meaning of this is, since usually after the
113+
* initial events have been fetched, lastEvent should be undefined.
114+
* In fact, the whole usage inside onRedaction looks suspect - it may be
115+
* that we were thinking lastEvent always refers to the actual last event,
116+
* but it only does so before initialEventsFetched becomes true.
117+
*
118+
* The usage of lastEvent inside {@link onEcho} looks suspicious, since I'd
119+
* think we probably mean {@link replyToEvent} there - we are trying not to
120+
* echo a duplicate event, and we probably want that behaviour even after
121+
* initialEventsFetched has become true.
122+
*
123+
* -- andyb
124+
*/
93125
private lastEvent: MatrixEvent | undefined;
126+
94127
private replyCount = 0;
95128
private lastPendingEvent: MatrixEvent | undefined;
96129
private pendingReplyCount = 0;
@@ -324,25 +357,34 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
324357
* @param emit - whether to emit the Update event if the thread was updated or not.
325358
*/
326359
public async addEvent(event: MatrixEvent, toStartOfTimeline: boolean, emit = true): Promise<void> {
360+
// Modify this event to point at our room's state, and mark its thread
361+
// as this.
327362
this.setEventMetadata(event);
328363

364+
// Decide whether this event is going to be added at the end of the timeline.
329365
const lastReply = this.lastReply();
330366
const isNewestReply = !lastReply || event.localTimestamp >= lastReply!.localTimestamp;
331367

332-
// Add all incoming events to the thread's timeline set when there's no server support
333368
if (!Thread.hasServerSideSupport) {
334-
// all the relevant membership info to hydrate events with a sender
335-
// is held in the main room timeline
336-
// We want to fetch the room state from there and pass it down to this thread
337-
// timeline set to let it reconcile an event with its relevant RoomMember
369+
// When there's no server-side support, just add it to the end of the timeline.
338370
this.addEventToTimeline(event, toStartOfTimeline);
339-
340371
this.client.decryptEventIfNeeded(event, {});
341372
} else if (!toStartOfTimeline && this.initialEventsFetched && isNewestReply) {
373+
// When we've asked for the event to be added to the end, and we're
374+
// not in the initial state, and this event belongs at the end, add it.
342375
this.addEventToTimeline(event, false);
343376
this.fetchEditsWhereNeeded(event);
344377
} else if (event.isRelation(RelationType.Annotation) || event.isRelation(RelationType.Replace)) {
378+
// If this event is not a direct member of the thread, but is a
379+
// reference to something that is, then we have two cases:
380+
345381
if (!this.initialEventsFetched) {
382+
// Case 1: we haven't yet fetched events from the server. In
383+
// this case, when we do, the events we get back might only be
384+
// the first-order ones, so this event (which is second-order -
385+
// a reference to something directly in the thread) needs to be
386+
// kept so we can replay it when the first-order ones turn up.
387+
346388
/**
347389
* A thread can be fully discovered via a single sync response
348390
* And when that's the case we still ask the server to do an initialisation
@@ -354,6 +396,23 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
354396
*/
355397
this.replayEvents?.push(event);
356398
} else {
399+
// Case 2: this is happening later, and we have a timeline. In
400+
// this case, these events might be out-of order.
401+
//
402+
// Specifically, if the server doesn't support recursion, so we
403+
// only get these events through sync, they might be coming
404+
// later than the first-order ones, so we insert them based on
405+
// timestamp (despite the problems with this documented in
406+
// #3325).
407+
//
408+
// If the server does support recursion, we should have got all
409+
// the interspersed events from the server when we fetched the
410+
// initial events, so if they are coming via sync they should be
411+
// the latest ones, so we can add them as normal.
412+
//
413+
// (Note that both insertEventIntoTimeline and addEventToTimeline
414+
// do nothing if we have seen this event before.)
415+
357416
const recursionSupport =
358417
this.client.canSupport.get(Feature.RelationsRecursion) ?? ServerSupport.Unsupported;
359418

0 commit comments

Comments
 (0)
Please sign in to comment.