Skip to content

Commit 8b6ff0a

Browse files
authored
[js sdk embedded/widget] Fix race where this.syncApi.injectRoomEvents was called before the syncApi is instantiated (#5168)
* Make sure we do not call this.syncApi.injectRoomEvents before the syncApi is instanciated * sonarCube remove complexity (embedded.js constructor)
1 parent f2157f2 commit 8b6ff0a

File tree

1 file changed

+39
-30
lines changed

1 file changed

+39
-30
lines changed

src/embedded.ts

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,23 @@ export class RoomWidgetClient extends MatrixClient {
212212
)
213213
: Promise.resolve();
214214

215+
this.requestInitialCapabilities(capabilities, roomId);
216+
217+
widgetApi.on(`action:${WidgetApiToWidgetAction.SendEvent}`, this.onEvent);
218+
widgetApi.on(`action:${WidgetApiToWidgetAction.SendToDevice}`, this.onToDevice);
219+
widgetApi.on(`action:${WidgetApiToWidgetAction.UpdateState}`, this.onStateUpdate);
220+
221+
// Open communication with the host
222+
widgetApi.start();
223+
// Send a content loaded event now we've started the widget API
224+
// Note that element-web currently does not use waitForIFrameLoad=false and so
225+
// does *not* (yes, that is the right way around) wait for this event. Let's
226+
// start sending this, then once this has rolled out, we can change element-web to
227+
// use waitForIFrameLoad=false and have a widget API that's less racy.
228+
if (sendContentLoaded) widgetApi.sendContentLoaded();
229+
}
230+
231+
private requestInitialCapabilities(capabilities: ICapabilities, roomId: string): void {
215232
// Request capabilities for the functionality this client needs to support
216233
if (
217234
capabilities.sendEvent?.length ||
@@ -223,68 +240,58 @@ export class RoomWidgetClient extends MatrixClient {
223240
capabilities.sendState?.length ||
224241
capabilities.receiveState?.length
225242
) {
226-
widgetApi.requestCapabilityForRoomTimeline(roomId);
243+
this.widgetApi.requestCapabilityForRoomTimeline(roomId);
227244
}
228-
capabilities.sendEvent?.forEach((eventType) => widgetApi.requestCapabilityToSendEvent(eventType));
229-
capabilities.receiveEvent?.forEach((eventType) => widgetApi.requestCapabilityToReceiveEvent(eventType));
245+
capabilities.sendEvent?.forEach((eventType) => this.widgetApi.requestCapabilityToSendEvent(eventType));
246+
capabilities.receiveEvent?.forEach((eventType) => this.widgetApi.requestCapabilityToReceiveEvent(eventType));
230247
if (capabilities.sendMessage === true) {
231-
widgetApi.requestCapabilityToSendMessage();
248+
this.widgetApi.requestCapabilityToSendMessage();
232249
} else if (Array.isArray(capabilities.sendMessage)) {
233-
capabilities.sendMessage.forEach((msgType) => widgetApi.requestCapabilityToSendMessage(msgType));
250+
capabilities.sendMessage.forEach((msgType) => this.widgetApi.requestCapabilityToSendMessage(msgType));
234251
}
235252
if (capabilities.receiveMessage === true) {
236-
widgetApi.requestCapabilityToReceiveMessage();
253+
this.widgetApi.requestCapabilityToReceiveMessage();
237254
} else if (Array.isArray(capabilities.receiveMessage)) {
238-
capabilities.receiveMessage.forEach((msgType) => widgetApi.requestCapabilityToReceiveMessage(msgType));
255+
capabilities.receiveMessage.forEach((msgType) => this.widgetApi.requestCapabilityToReceiveMessage(msgType));
239256
}
240257
capabilities.sendState?.forEach(({ eventType, stateKey }) =>
241-
widgetApi.requestCapabilityToSendState(eventType, stateKey),
258+
this.widgetApi.requestCapabilityToSendState(eventType, stateKey),
242259
);
243260
capabilities.receiveState?.forEach(({ eventType, stateKey }) =>
244-
widgetApi.requestCapabilityToReceiveState(eventType, stateKey),
261+
this.widgetApi.requestCapabilityToReceiveState(eventType, stateKey),
262+
);
263+
capabilities.sendToDevice?.forEach((eventType) => this.widgetApi.requestCapabilityToSendToDevice(eventType));
264+
capabilities.receiveToDevice?.forEach((eventType) =>
265+
this.widgetApi.requestCapabilityToReceiveToDevice(eventType),
245266
);
246-
capabilities.sendToDevice?.forEach((eventType) => widgetApi.requestCapabilityToSendToDevice(eventType));
247-
capabilities.receiveToDevice?.forEach((eventType) => widgetApi.requestCapabilityToReceiveToDevice(eventType));
248267
if (
249268
capabilities.sendDelayedEvents &&
250269
(capabilities.sendEvent?.length ||
251270
capabilities.sendMessage === true ||
252271
(Array.isArray(capabilities.sendMessage) && capabilities.sendMessage.length) ||
253272
capabilities.sendState?.length)
254273
) {
255-
widgetApi.requestCapability(MatrixCapabilities.MSC4157SendDelayedEvent);
274+
this.widgetApi.requestCapability(MatrixCapabilities.MSC4157SendDelayedEvent);
256275
}
257276
if (capabilities.updateDelayedEvents) {
258-
widgetApi.requestCapability(MatrixCapabilities.MSC4157UpdateDelayedEvent);
277+
this.widgetApi.requestCapability(MatrixCapabilities.MSC4157UpdateDelayedEvent);
259278
}
260279
if (capabilities.sendSticky) {
261-
widgetApi.requestCapability(MatrixCapabilities.MSC4407SendStickyEvent);
280+
this.widgetApi.requestCapability(MatrixCapabilities.MSC4407SendStickyEvent);
262281
}
263282
if (capabilities.receiveSticky) {
264-
widgetApi.requestCapability(MatrixCapabilities.MSC4407ReceiveStickyEvent);
283+
this.widgetApi.requestCapability(MatrixCapabilities.MSC4407ReceiveStickyEvent);
265284
}
266285
if (capabilities.turnServers) {
267-
widgetApi.requestCapability(MatrixCapabilities.MSC3846TurnServers);
286+
this.widgetApi.requestCapability(MatrixCapabilities.MSC3846TurnServers);
268287
}
269-
270-
widgetApi.on(`action:${WidgetApiToWidgetAction.SendEvent}`, this.onEvent);
271-
widgetApi.on(`action:${WidgetApiToWidgetAction.SendToDevice}`, this.onToDevice);
272-
widgetApi.on(`action:${WidgetApiToWidgetAction.UpdateState}`, this.onStateUpdate);
273-
274-
// Open communication with the host
275-
widgetApi.start();
276-
// Send a content loaded event now we've started the widget API
277-
// Note that element-web currently does not use waitForIFrameLoad=false and so
278-
// does *not* (yes, that is the right way around) wait for this event. Let's
279-
// start sending this, then once this has rolled out, we can change element-web to
280-
// use waitForIFrameLoad=false and have a widget API that's less racy.
281-
if (sendContentLoaded) widgetApi.sendContentLoaded();
282288
}
283289

284290
public async supportUpdateState(): Promise<boolean> {
285291
return (await this.widgetApi.getClientVersions()).includes(UnstableApiVersion.MSC2762_UPDATE_STATE);
286292
}
287293

294+
private readonly syncApiResolver = Promise.withResolvers<void>();
288295
public async startClient(opts: IStartClientOpts = {}): Promise<void> {
289296
this.lifecycle = new AbortController();
290297

@@ -303,6 +310,7 @@ export class RoomWidgetClient extends MatrixClient {
303310
} else {
304311
this.syncApi = new SyncApi(this, opts, this.buildSyncApiOptions());
305312
}
313+
this.syncApiResolver.resolve();
306314

307315
this.room = this.syncApi.createRoom(this.roomId);
308316
this.store.storeRoom(this.room);
@@ -729,7 +737,7 @@ export class RoomWidgetClient extends MatrixClient {
729737

730738
// Only inject once we have update the txId
731739
await this.updateTxId(event);
732-
740+
await this.syncApiResolver.promise;
733741
if (this.syncApi instanceof SyncApi) {
734742
if (await this.supportUpdateState()) {
735743
await this.syncApi.injectRoomEvents(this.room!, undefined, [], [event]);
@@ -784,6 +792,7 @@ export class RoomWidgetClient extends MatrixClient {
784792
"received update_state widget action but the widget driver did not claim to support 'org.matrix.msc2762_update_state'",
785793
);
786794
}
795+
await this.syncApiResolver.promise;
787796
for (const rawEvent of ev.detail.data.state) {
788797
// Verify the room ID matches, since it's possible for the client to
789798
// send us state updates from other rooms if this widget is always

0 commit comments

Comments
 (0)