Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Stop connecting to a video room if the widget messaging disappears (#…
Browse files Browse the repository at this point in the history
…8660)

* Stop connecting to a video room if the widget messaging disappears

* Clean up more listeners

* Clean up even more listeners
  • Loading branch information
robintown authored May 24, 2022
1 parent 0343548 commit 7edc4b1
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 12 deletions.
39 changes: 33 additions & 6 deletions src/stores/VideoChannelStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
messagingStore,
WidgetMessagingStoreEvent.WidgetReady,
(uid: string) => uid === jitsiUid,
);
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}`);
}
Expand Down Expand Up @@ -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);
Expand Down
7 changes: 4 additions & 3 deletions src/stores/widgets/WidgetMessagingStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import WidgetUtils from "../../utils/WidgetUtils";

export enum WidgetMessagingStoreEvent {
StoreMessaging = "store_messaging",
StopMessaging = "stop_messaging",
WidgetReady = "widget_ready",
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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);
}

/**
Expand Down
24 changes: 21 additions & 3 deletions test/stores/VideoChannelStore-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,28 +114,46 @@ 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);

store.disconnect();
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);
});
});

0 comments on commit 7edc4b1

Please sign in to comment.