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
pull/28217/head
Robin 2022-05-24 07:43:27 -04:00 committed by GitHub
parent 0343548dbe
commit 7edc4b1965
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 12 deletions

View File

@ -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)) {
// Wait for the widget to be ready to receive our join event
try {
await waitForEvent(
await Promise.race([
waitForEvent(
messagingStore,
WidgetMessagingStoreEvent.WidgetReady,
(uid: string) => uid === jitsiUid,
);
),
dontStopMessaging,
]);
} catch (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,
});
try {
await waitForJoin;
await Promise.race([waitForJoin, dontStopMessaging]);
} catch (e) {
// If it timed out, clean up our advance preparations
this.activeChannel = null;
this.roomId = null;
messaging.off(`action:${ElementWidgetActions.CallParticipants}`, this.onParticipants);
messaging.off(`action:${ElementWidgetActions.MuteAudio}`, this.onMuteAudio);
messaging.off(`action:${ElementWidgetActions.UnmuteAudio}`, this.onUnmuteAudio);

View File

@ -25,6 +25,7 @@ import WidgetUtils from "../../utils/WidgetUtils";
export enum WidgetMessagingStoreEvent {
StoreMessaging = "store_messaging",
StopMessaging = "stop_messaging",
WidgetReady = "widget_ready",
}
@ -71,9 +72,7 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<unknown> {
}
public stopMessaging(widget: Widget, roomId: string) {
const uid = WidgetUtils.calcWidgetUid(widget.id, roomId);
this.widgetMap.remove(uid)?.stop();
this.readyWidgets.delete(uid);
this.stopMessagingByUid(WidgetUtils.calcWidgetUid(widget.id, roomId));
}
public getMessaging(widget: Widget, roomId: string): ClientWidgetApi {
@ -86,6 +85,8 @@ export class WidgetMessagingStore extends AsyncStoreWithClient<unknown> {
*/
public stopMessagingByUid(widgetUid: string) {
this.widgetMap.remove(widgetUid)?.stop();
this.readyWidgets.delete(widgetUid);
this.emit(WidgetMessagingStoreEvent.StopMessaging, widgetUid);
}
/**

View File

@ -114,23 +114,26 @@ describe("VideoChannelStore", () => {
expect(store.roomId).toBeFalsy();
expect(store.connected).toEqual(false);
store.connect("!1:example.org", null, null);
const connectPromise = store.connect("!1:example.org", null, null);
await confirmConnect();
await expect(connectPromise).resolves.toBeUndefined();
expect(store.roomId).toEqual("!1:example.org");
expect(store.connected).toEqual(true);
store.disconnect();
const disconnectPromise = store.disconnect();
await confirmDisconnect();
await expect(disconnectPromise).resolves.toBeUndefined();
expect(store.roomId).toBeFalsy();
expect(store.connected).toEqual(false);
WidgetMessagingStore.instance.stopMessaging(widget, "!1:example.org");
});
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);
widgetReady();
await confirmConnect();
await expect(connectPromise).resolves.toBeUndefined();
expect(store.roomId).toEqual("!1:example.org");
expect(store.connected).toEqual(true);
@ -138,4 +141,19 @@ describe("VideoChannelStore", () => {
await confirmDisconnect();
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);
});
});