Stop connecting to a video room if the widget messaging disappears (#8660)
* Stop connecting to a video room if the widget messaging disappears * Clean up more listeners * Clean up even more listeners
This commit is contained in:
parent
0343548dbe
commit
7edc4b1965
3 changed files with 58 additions and 12 deletions
|
@ -136,14 +136,40 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that we got the messaging, we need a way to ensure that it doesn't get stopped
|
||||||
|
const dontStopMessaging = new Promise<void>((resolve, reject) => {
|
||||||
|
const listener = (uid: string) => {
|
||||||
|
if (uid === jitsiUid) {
|
||||||
|
cleanup();
|
||||||
|
reject(new Error("Messaging stopped"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const done = () => {
|
||||||
|
cleanup();
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
const cleanup = () => {
|
||||||
|
messagingStore.off(WidgetMessagingStoreEvent.StopMessaging, listener);
|
||||||
|
this.off(VideoChannelEvent.Connect, done);
|
||||||
|
this.off(VideoChannelEvent.Disconnect, done);
|
||||||
|
};
|
||||||
|
|
||||||
|
messagingStore.on(WidgetMessagingStoreEvent.StopMessaging, listener);
|
||||||
|
this.on(VideoChannelEvent.Connect, done);
|
||||||
|
this.on(VideoChannelEvent.Disconnect, done);
|
||||||
|
});
|
||||||
|
|
||||||
if (!messagingStore.isWidgetReady(jitsiUid)) {
|
if (!messagingStore.isWidgetReady(jitsiUid)) {
|
||||||
// Wait for the widget to be ready to receive our join event
|
// Wait for the widget to be ready to receive our join event
|
||||||
try {
|
try {
|
||||||
await waitForEvent(
|
await Promise.race([
|
||||||
|
waitForEvent(
|
||||||
messagingStore,
|
messagingStore,
|
||||||
WidgetMessagingStoreEvent.WidgetReady,
|
WidgetMessagingStoreEvent.WidgetReady,
|
||||||
(uid: string) => uid === jitsiUid,
|
(uid: string) => uid === jitsiUid,
|
||||||
);
|
),
|
||||||
|
dontStopMessaging,
|
||||||
|
]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`Video channel in room ${roomId} never became ready: ${e}`);
|
throw new Error(`Video channel in room ${roomId} never became ready: ${e}`);
|
||||||
}
|
}
|
||||||
|
@ -178,11 +204,12 @@ export default class VideoChannelStore extends AsyncStoreWithClient<null> {
|
||||||
videoDevice: videoDevice?.label,
|
videoDevice: videoDevice?.label,
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await waitForJoin;
|
await Promise.race([waitForJoin, dontStopMessaging]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// If it timed out, clean up our advance preparations
|
// If it timed out, clean up our advance preparations
|
||||||
this.activeChannel = null;
|
this.activeChannel = null;
|
||||||
this.roomId = null;
|
this.roomId = null;
|
||||||
|
|
||||||
messaging.off(`action:${ElementWidgetActions.CallParticipants}`, this.onParticipants);
|
messaging.off(`action:${ElementWidgetActions.CallParticipants}`, this.onParticipants);
|
||||||
messaging.off(`action:${ElementWidgetActions.MuteAudio}`, this.onMuteAudio);
|
messaging.off(`action:${ElementWidgetActions.MuteAudio}`, this.onMuteAudio);
|
||||||
messaging.off(`action:${ElementWidgetActions.UnmuteAudio}`, this.onUnmuteAudio);
|
messaging.off(`action:${ElementWidgetActions.UnmuteAudio}`, this.onUnmuteAudio);
|
||||||
|
|
|
@ -25,6 +25,7 @@ import WidgetUtils from "../../utils/WidgetUtils";
|
||||||
|
|
||||||
export enum WidgetMessagingStoreEvent {
|
export enum WidgetMessagingStoreEvent {
|
||||||
StoreMessaging = "store_messaging",
|
StoreMessaging = "store_messaging",
|
||||||
|
StopMessaging = "stop_messaging",
|
||||||
WidgetReady = "widget_ready",
|
WidgetReady = "widget_ready",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,9 +72,7 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<unknown> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public stopMessaging(widget: Widget, roomId: string) {
|
public stopMessaging(widget: Widget, roomId: string) {
|
||||||
const uid = WidgetUtils.calcWidgetUid(widget.id, roomId);
|
this.stopMessagingByUid(WidgetUtils.calcWidgetUid(widget.id, roomId));
|
||||||
this.widgetMap.remove(uid)?.stop();
|
|
||||||
this.readyWidgets.delete(uid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getMessaging(widget: Widget, roomId: string): ClientWidgetApi {
|
public getMessaging(widget: Widget, roomId: string): ClientWidgetApi {
|
||||||
|
@ -86,6 +85,8 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<unknown> {
|
||||||
*/
|
*/
|
||||||
public stopMessagingByUid(widgetUid: string) {
|
public stopMessagingByUid(widgetUid: string) {
|
||||||
this.widgetMap.remove(widgetUid)?.stop();
|
this.widgetMap.remove(widgetUid)?.stop();
|
||||||
|
this.readyWidgets.delete(widgetUid);
|
||||||
|
this.emit(WidgetMessagingStoreEvent.StopMessaging, widgetUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -114,23 +114,26 @@ describe("VideoChannelStore", () => {
|
||||||
expect(store.roomId).toBeFalsy();
|
expect(store.roomId).toBeFalsy();
|
||||||
expect(store.connected).toEqual(false);
|
expect(store.connected).toEqual(false);
|
||||||
|
|
||||||
store.connect("!1:example.org", null, null);
|
const connectPromise = store.connect("!1:example.org", null, null);
|
||||||
await confirmConnect();
|
await confirmConnect();
|
||||||
|
await expect(connectPromise).resolves.toBeUndefined();
|
||||||
expect(store.roomId).toEqual("!1:example.org");
|
expect(store.roomId).toEqual("!1:example.org");
|
||||||
expect(store.connected).toEqual(true);
|
expect(store.connected).toEqual(true);
|
||||||
|
|
||||||
store.disconnect();
|
const disconnectPromise = store.disconnect();
|
||||||
await confirmDisconnect();
|
await confirmDisconnect();
|
||||||
|
await expect(disconnectPromise).resolves.toBeUndefined();
|
||||||
expect(store.roomId).toBeFalsy();
|
expect(store.roomId).toBeFalsy();
|
||||||
expect(store.connected).toEqual(false);
|
expect(store.connected).toEqual(false);
|
||||||
WidgetMessagingStore.instance.stopMessaging(widget, "!1:example.org");
|
WidgetMessagingStore.instance.stopMessaging(widget, "!1:example.org");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("waits for messaging when connecting", async () => {
|
it("waits for messaging when connecting", async () => {
|
||||||
store.connect("!1:example.org", null, null);
|
const connectPromise = store.connect("!1:example.org", null, null);
|
||||||
WidgetMessagingStore.instance.storeMessaging(widget, "!1:example.org", messaging);
|
WidgetMessagingStore.instance.storeMessaging(widget, "!1:example.org", messaging);
|
||||||
widgetReady();
|
widgetReady();
|
||||||
await confirmConnect();
|
await confirmConnect();
|
||||||
|
await expect(connectPromise).resolves.toBeUndefined();
|
||||||
expect(store.roomId).toEqual("!1:example.org");
|
expect(store.roomId).toEqual("!1:example.org");
|
||||||
expect(store.connected).toEqual(true);
|
expect(store.connected).toEqual(true);
|
||||||
|
|
||||||
|
@ -138,4 +141,19 @@ describe("VideoChannelStore", () => {
|
||||||
await confirmDisconnect();
|
await confirmDisconnect();
|
||||||
WidgetMessagingStore.instance.stopMessaging(widget, "!1:example.org");
|
WidgetMessagingStore.instance.stopMessaging(widget, "!1:example.org");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("rejects if the widget's messaging gets stopped mid-connect", async () => {
|
||||||
|
WidgetMessagingStore.instance.storeMessaging(widget, "!1:example.org", messaging);
|
||||||
|
widgetReady();
|
||||||
|
expect(store.roomId).toBeFalsy();
|
||||||
|
expect(store.connected).toEqual(false);
|
||||||
|
|
||||||
|
const connectPromise = store.connect("!1:example.org", null, null);
|
||||||
|
// Wait for the store to contact the widget API, then stop the messaging
|
||||||
|
await messageSent;
|
||||||
|
WidgetMessagingStore.instance.stopMessaging(widget, "!1:example.org");
|
||||||
|
await expect(connectPromise).rejects.toBeDefined();
|
||||||
|
expect(store.roomId).toBeFalsy();
|
||||||
|
expect(store.connected).toEqual(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue