From 00c0abf354fe28866ab33223fbcf57a0912a799b Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 9 Dec 2025 13:04:53 +0000 Subject: [PATCH 1/4] Reduce complexity of ElementWidgetDriver.readRoomTimeline --- src/stores/widgets/ElementWidgetDriver.ts | 52 ++++++++++++++++------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/src/stores/widgets/ElementWidgetDriver.ts b/src/stores/widgets/ElementWidgetDriver.ts index e341f7627c0..931ea38a0c7 100644 --- a/src/stores/widgets/ElementWidgetDriver.ts +++ b/src/stores/widgets/ElementWidgetDriver.ts @@ -33,12 +33,12 @@ import { EventType, type IContent, MatrixError, - type MatrixEvent, Direction, THREAD_RELATION_TYPE, type SendDelayedEventResponse, type StateEvents, type TimelineEvents, + Room, } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; import { @@ -507,6 +507,40 @@ export class ElementWidgetDriver extends WidgetDriver { } } + /** + * Generator function that retrieves events for readRoomTimeline + * @param room The room to check the timeline of. + * @param eventType The event type to be read. + * @param msgtype The msgtype of the events to be read, if applicable/defined. + * @param stateKey The state key of the events to be read, if applicable/defined. + * @param limit The maximum number of events to retrieve. Will be zero to denote "as many as + * possible". + * @param since When null, retrieves the number of events specified by the "limit" parameter. + * Otherwise, the event ID at which only subsequent events will be returned, as many as specified + * in "limit". + * @returns A generator that emits events. + */ + private *readRoomTimelineIterator( + room: Room, + eventType: string, + msgtype: string | undefined, + stateKey: string | undefined, + limit: number, + since: string | undefined, + ): Generator { + let resultCount: number = 0; + const events = [...room.getLiveTimeline().getEvents()].reverse(); // timelines are most recent last + while (events.length && resultCount < limit) { + const ev = events.pop()!; + if (since !== undefined && ev.getId() === since) break; + if (ev.getType() !== eventType) continue; + if (eventType === EventType.RoomMessage && msgtype && msgtype !== ev.getContent()["msgtype"]) continue; + if (stateKey !== undefined && ev.getStateKey() !== stateKey) continue; + yield ev.getEffectiveEvent() as IRoomEvent; + resultCount++; + } + } + /** * Reads all events of the given type, and optionally `msgtype` (if applicable/defined), * the user has access to. The widget API will have already verified that the widget is @@ -532,23 +566,9 @@ export class ElementWidgetDriver extends WidgetDriver { since: string | undefined, ): Promise { limit = limit > 0 ? Math.min(limit, Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER; // relatively arbitrary - const room = MatrixClientPeg.safeGet().getRoom(roomId); if (room === null) return []; - const results: MatrixEvent[] = []; - const events = room.getLiveTimeline().getEvents(); // timelines are most recent last - for (let i = events.length - 1; i >= 0; i--) { - const ev = events[i]; - if (results.length >= limit) break; - if (since !== undefined && ev.getId() === since) break; - - if (ev.getType() !== eventType) continue; - if (eventType === EventType.RoomMessage && msgtype && msgtype !== ev.getContent()["msgtype"]) continue; - if (stateKey !== undefined && ev.getStateKey() !== stateKey) continue; - results.push(ev); - } - - return results.map((e) => e.getEffectiveEvent() as IRoomEvent); + return [...this.readRoomTimelineIterator(room, eventType, msgtype, stateKey, limit, since)]; } /** From 04581e4f2d964660d353fe3de320b6b871ec74c7 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 9 Dec 2025 13:21:43 +0000 Subject: [PATCH 2/4] Remove reverse to pass tests --- src/stores/widgets/ElementWidgetDriver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stores/widgets/ElementWidgetDriver.ts b/src/stores/widgets/ElementWidgetDriver.ts index 931ea38a0c7..1a40f1c0f2a 100644 --- a/src/stores/widgets/ElementWidgetDriver.ts +++ b/src/stores/widgets/ElementWidgetDriver.ts @@ -529,7 +529,7 @@ export class ElementWidgetDriver extends WidgetDriver { since: string | undefined, ): Generator { let resultCount: number = 0; - const events = [...room.getLiveTimeline().getEvents()].reverse(); // timelines are most recent last + const events = [...room.getLiveTimeline().getEvents()]; // timelines are most recent last while (events.length && resultCount < limit) { const ev = events.pop()!; if (since !== undefined && ev.getId() === since) break; From de78e086fdcce1198febf25aeec0d6324622ceb4 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 9 Dec 2025 13:27:46 +0000 Subject: [PATCH 3/4] Slightly more exotic loop --- src/stores/widgets/ElementWidgetDriver.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/stores/widgets/ElementWidgetDriver.ts b/src/stores/widgets/ElementWidgetDriver.ts index 1a40f1c0f2a..b53f4f2f8d2 100644 --- a/src/stores/widgets/ElementWidgetDriver.ts +++ b/src/stores/widgets/ElementWidgetDriver.ts @@ -39,6 +39,7 @@ import { type StateEvents, type TimelineEvents, Room, + MatrixEvent, } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; import { @@ -530,9 +531,7 @@ export class ElementWidgetDriver extends WidgetDriver { ): Generator { let resultCount: number = 0; const events = [...room.getLiveTimeline().getEvents()]; // timelines are most recent last - while (events.length && resultCount < limit) { - const ev = events.pop()!; - if (since !== undefined && ev.getId() === since) break; + for (let ev = events.pop(); ev && resultCount < limit && ev.getId() !== since; ev = events.pop()) { if (ev.getType() !== eventType) continue; if (eventType === EventType.RoomMessage && msgtype && msgtype !== ev.getContent()["msgtype"]) continue; if (stateKey !== undefined && ev.getStateKey() !== stateKey) continue; From 8907c6e4d0b5a6764ba3839aa3bad3864a1f1ec6 Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Tue, 9 Dec 2025 13:32:32 +0000 Subject: [PATCH 4/4] remove type --- src/stores/widgets/ElementWidgetDriver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stores/widgets/ElementWidgetDriver.ts b/src/stores/widgets/ElementWidgetDriver.ts index b53f4f2f8d2..9577d6be18d 100644 --- a/src/stores/widgets/ElementWidgetDriver.ts +++ b/src/stores/widgets/ElementWidgetDriver.ts @@ -39,7 +39,6 @@ import { type StateEvents, type TimelineEvents, Room, - MatrixEvent, } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; import {