@@ -28,6 +28,7 @@ import {
28
28
WidgetApiAction ,
29
29
IWidgetApiResponse ,
30
30
IWidgetApiResponseData ,
31
+ IUpdateStateToWidgetActionRequest ,
31
32
} from "matrix-widget-api" ;
32
33
33
34
import { MatrixEvent , IEvent , IContent , EventStatus } from "./models/event.ts" ;
@@ -136,6 +137,7 @@ export type EventHandlerMap = { [RoomWidgetClientEvent.PendingEventsChanged]: ()
136
137
export class RoomWidgetClient extends MatrixClient {
137
138
private room ?: Room ;
138
139
private readonly widgetApiReady : Promise < void > ;
140
+ private readonly roomStateSynced : Promise < void > ;
139
141
private lifecycle ?: AbortController ;
140
142
private syncState : SyncState | null = null ;
141
143
@@ -189,6 +191,11 @@ export class RoomWidgetClient extends MatrixClient {
189
191
} ;
190
192
191
193
this . widgetApiReady = new Promise < void > ( ( resolve ) => this . widgetApi . once ( "ready" , resolve ) ) ;
194
+ this . roomStateSynced = capabilities . receiveState ?. length
195
+ ? new Promise < void > ( ( resolve ) =>
196
+ this . widgetApi . once ( `action:${ WidgetApiToWidgetAction . UpdateState } ` , resolve ) ,
197
+ )
198
+ : Promise . resolve ( ) ;
192
199
193
200
// Request capabilities for the functionality this client needs to support
194
201
if (
@@ -241,6 +248,7 @@ export class RoomWidgetClient extends MatrixClient {
241
248
242
249
widgetApi . on ( `action:${ WidgetApiToWidgetAction . SendEvent } ` , this . onEvent ) ;
243
250
widgetApi . on ( `action:${ WidgetApiToWidgetAction . SendToDevice } ` , this . onToDevice ) ;
251
+ widgetApi . on ( `action:${ WidgetApiToWidgetAction . UpdateState } ` , this . onStateUpdate ) ;
244
252
245
253
// Open communication with the host
246
254
widgetApi . start ( ) ;
@@ -276,37 +284,16 @@ export class RoomWidgetClient extends MatrixClient {
276
284
277
285
await this . widgetApiReady ;
278
286
279
- // Backfill the requested events
280
- // We only get the most recent event for every type + state key combo,
281
- // so it doesn't really matter what order we inject them in
282
- await Promise . all (
283
- this . capabilities . receiveState ?. map ( async ( { eventType, stateKey } ) => {
284
- const rawEvents = await this . widgetApi . readStateEvents ( eventType , undefined , stateKey , [ this . roomId ] ) ;
285
- const events = rawEvents . map ( ( rawEvent ) => new MatrixEvent ( rawEvent as Partial < IEvent > ) ) ;
286
-
287
- if ( this . syncApi instanceof SyncApi ) {
288
- // Passing undefined for `stateAfterEventList` allows will make `injectRoomEvents` run in legacy mode
289
- // -> state events in `timelineEventList` will update the state.
290
- await this . syncApi . injectRoomEvents ( this . room ! , undefined , events ) ;
291
- } else {
292
- await this . syncApi ! . injectRoomEvents ( this . room ! , events ) ; // Sliding Sync
293
- }
294
- events . forEach ( ( event ) => {
295
- this . emit ( ClientEvent . Event , event ) ;
296
- logger . info ( `Backfilled event ${ event . getId ( ) } ${ event . getType ( ) } ${ event . getStateKey ( ) } ` ) ;
297
- } ) ;
298
- } ) ?? [ ] ,
299
- ) ;
300
-
301
287
if ( opts . clientWellKnownPollPeriod !== undefined ) {
302
288
this . clientWellKnownIntervalID = setInterval ( ( ) => {
303
289
this . fetchClientWellKnown ( ) ;
304
290
} , 1000 * opts . clientWellKnownPollPeriod ) ;
305
291
this . fetchClientWellKnown ( ) ;
306
292
}
307
293
294
+ await this . roomStateSynced ;
308
295
this . setSyncState ( SyncState . Syncing ) ;
309
- logger . info ( "Finished backfilling events " ) ;
296
+ logger . info ( "Finished initial sync " ) ;
310
297
311
298
this . matrixRTC . start ( ) ;
312
299
@@ -317,6 +304,7 @@ export class RoomWidgetClient extends MatrixClient {
317
304
public stopClient ( ) : void {
318
305
this . widgetApi . off ( `action:${ WidgetApiToWidgetAction . SendEvent } ` , this . onEvent ) ;
319
306
this . widgetApi . off ( `action:${ WidgetApiToWidgetAction . SendToDevice } ` , this . onToDevice ) ;
307
+ this . widgetApi . off ( `action:${ WidgetApiToWidgetAction . UpdateState } ` , this . onStateUpdate ) ;
320
308
321
309
super . stopClient ( ) ;
322
310
this . lifecycle ! . abort ( ) ; // Signal to other async tasks that the client has stopped
@@ -574,36 +562,15 @@ export class RoomWidgetClient extends MatrixClient {
574
562
// Only inject once we have update the txId
575
563
await this . updateTxId ( event ) ;
576
564
577
- // The widget API does not tell us whether a state event came from `state_after` or not so we assume legacy behaviour for now.
578
565
if ( this . syncApi instanceof SyncApi ) {
579
- // The code will want to be something like:
580
- // ```
581
- // if (!params.addToTimeline && !params.addToState) {
582
- // // Passing undefined for `stateAfterEventList` makes `injectRoomEvents` run in "legacy mode"
583
- // // -> state events part of the `timelineEventList` parameter will update the state.
584
- // this.injectRoomEvents(this.room!, [], undefined, [event]);
585
- // } else {
586
- // this.injectRoomEvents(this.room!, undefined, params.addToState ? [event] : [], params.addToTimeline ? [event] : []);
587
- // }
588
- // ```
589
-
590
- // Passing undefined for `stateAfterEventList` allows will make `injectRoomEvents` run in legacy mode
591
- // -> state events in `timelineEventList` will update the state.
592
- await this . syncApi . injectRoomEvents ( this . room ! , [ ] , undefined , [ event ] ) ;
566
+ await this . syncApi . injectRoomEvents ( this . room ! , undefined , [ ] , [ event ] ) ;
593
567
} else {
594
- // The code will want to be something like:
595
- // ```
596
- // if (!params.addToTimeline && !params.addToState) {
597
- // this.injectRoomEvents(this.room!, [], [event]);
598
- // } else {
599
- // this.injectRoomEvents(this.room!, params.addToState ? [event] : [], params.addToTimeline ? [event] : []);
600
- // }
601
- // ```
602
- await this . syncApi ! . injectRoomEvents ( this . room ! , [ ] , [ event ] ) ; // Sliding Sync
568
+ // Sliding Sync
569
+ await this . syncApi ! . injectRoomEvents ( this . room ! , [ ] , [ event ] ) ;
603
570
}
604
571
this . emit ( ClientEvent . Event , event ) ;
605
572
this . setSyncState ( SyncState . Syncing ) ;
606
- logger . info ( `Received event ${ event . getId ( ) } ${ event . getType ( ) } ${ event . getStateKey ( ) } ` ) ;
573
+ logger . info ( `Received event ${ event . getId ( ) } ${ event . getType ( ) } ` ) ;
607
574
} else {
608
575
const { event_id : eventId , room_id : roomId } = ev . detail . data ;
609
576
logger . info ( `Received event ${ eventId } for a different room ${ roomId } ; discarding` ) ;
@@ -628,6 +595,32 @@ export class RoomWidgetClient extends MatrixClient {
628
595
await this . ack ( ev ) ;
629
596
} ;
630
597
598
+ private onStateUpdate = async ( ev : CustomEvent < IUpdateStateToWidgetActionRequest > ) : Promise < void > => {
599
+ ev . preventDefault ( ) ;
600
+
601
+ for ( const rawEvent of ev . detail . data . state ) {
602
+ // Verify the room ID matches, since it's possible for the client to
603
+ // send us state updates from other rooms if this widget is always
604
+ // on screen
605
+ if ( rawEvent . room_id === this . roomId ) {
606
+ const event = new MatrixEvent ( rawEvent as Partial < IEvent > ) ;
607
+
608
+ if ( this . syncApi instanceof SyncApi ) {
609
+ await this . syncApi . injectRoomEvents ( this . room ! , undefined , [ event ] ) ;
610
+ } else {
611
+ // Sliding Sync
612
+ await this . syncApi ! . injectRoomEvents ( this . room ! , [ event ] ) ;
613
+ }
614
+ logger . info ( `Updated state entry ${ event . getType ( ) } ${ event . getStateKey ( ) } to ${ event . getId ( ) } ` ) ;
615
+ } else {
616
+ const { event_id : eventId , room_id : roomId } = ev . detail . data ;
617
+ logger . info ( `Received state entry ${ eventId } for a different room ${ roomId } ; discarding` ) ;
618
+ }
619
+ }
620
+
621
+ await this . ack ( ev ) ;
622
+ } ;
623
+
631
624
private async watchTurnServers ( ) : Promise < void > {
632
625
const servers = this . widgetApi . getTurnServers ( ) ;
633
626
const onClientStopped = ( ) : void => {
0 commit comments