From 32b37ed8f08f16448a8ee5d23de0efcc5dd0c651 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 20 Jul 2022 16:01:29 +0100 Subject: [PATCH] Fix 'cannot find room' error We weren't waiting for rooms to arrive down the sync stream after joining them but before trying to use them. More regression details in linked issue. Fixes https://github.com/vector-im/element-call/issues/477 --- src/home/RegisteredView.jsx | 2 +- src/home/UnauthenticatedView.jsx | 2 +- src/matrix-utils.ts | 6 ++--- src/room/useLoadGroupCall.ts | 40 +++++++++++++++++++++++++++++--- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/home/RegisteredView.jsx b/src/home/RegisteredView.jsx index 1d07d1c7..b5fef745 100644 --- a/src/home/RegisteredView.jsx +++ b/src/home/RegisteredView.jsx @@ -47,7 +47,7 @@ export function RegisteredView({ client }) { setError(undefined); setLoading(true); - const roomIdOrAlias = await createRoom(client, roomName, ptt); + const [roomIdOrAlias] = await createRoom(client, roomName, ptt); if (roomIdOrAlias) { history.push(`/room/${roomIdOrAlias}`); diff --git a/src/home/UnauthenticatedView.jsx b/src/home/UnauthenticatedView.jsx index f324d504..a6d7a6ed 100644 --- a/src/home/UnauthenticatedView.jsx +++ b/src/home/UnauthenticatedView.jsx @@ -70,7 +70,7 @@ export function UnauthenticatedView() { let roomIdOrAlias; try { - roomIdOrAlias = await createRoom(client, roomName, ptt); + [roomIdOrAlias] = await createRoom(client, roomName, ptt); } catch (error) { if (error.errcode === "M_ROOM_IN_USE") { setOnFinished(() => () => { diff --git a/src/matrix-utils.ts b/src/matrix-utils.ts index 9b6a005b..5986954b 100644 --- a/src/matrix-utils.ts +++ b/src/matrix-utils.ts @@ -220,8 +220,8 @@ export function isLocalRoomId(roomId: string): boolean { export async function createRoom( client: MatrixClient, name: string -): Promise { - await client.createRoom({ +): Promise<[string, string]> { + const result = await client.createRoom({ visibility: Visibility.Private, preset: Preset.PublicChat, name, @@ -251,7 +251,7 @@ export async function createRoom( }, }); - return fullAliasFromRoomName(name, client); + return [fullAliasFromRoomName(name, client), result.room_id]; } export function getRoomUrl(roomId: string): string { diff --git a/src/room/useLoadGroupCall.ts b/src/room/useLoadGroupCall.ts index 0d7fb7c7..301ba54f 100644 --- a/src/room/useLoadGroupCall.ts +++ b/src/room/useLoadGroupCall.ts @@ -21,6 +21,7 @@ import { GroupCallIntent, } from "matrix-js-sdk/src/webrtc/groupCall"; import { GroupCallEventHandlerEvent } from "matrix-js-sdk/src/webrtc/groupCallEventHandler"; +import { ClientEvent } from "matrix-js-sdk/src/client"; import type { MatrixClient } from "matrix-js-sdk/src/client"; import type { Room } from "matrix-js-sdk/src/models/room"; @@ -44,9 +45,38 @@ export const useLoadGroupCall = ( useEffect(() => { setState({ loading: true }); + const waitForRoom = async (roomId: string): Promise => { + const room = client.getRoom(roomId); + if (room) return room; + console.log(`Room ${roomId} hasn't arrived yet: waiting`); + + const waitPromise = new Promise((resolve) => { + const onRoomEvent = async (room: Room) => { + if (room.roomId === roomId) { + client.removeListener(ClientEvent.Room, onRoomEvent); + resolve(room); + } + }; + client.on(ClientEvent.Room, onRoomEvent); + }); + + // race the promise with a timeout so we don't + // wait forever for the room + const timeoutPromise = new Promise((_, reject) => { + setTimeout(() => { + reject(new Error("Timed out trying to join room")); + }, 30000); + }); + + return Promise.race([waitPromise, timeoutPromise]); + }; + const fetchOrCreateRoom = async (): Promise => { try { - return await client.joinRoom(roomIdOrAlias, { viaServers }); + const room = await client.joinRoom(roomIdOrAlias, { viaServers }); + // wait for the room to come down the sync stream, otherwise + // client.getRoom() won't return the room. + return waitForRoom(room.roomId); } catch (error) { if ( isLocalRoomId(roomIdOrAlias) && @@ -55,8 +85,12 @@ export const useLoadGroupCall = ( error.message.indexOf("Failed to fetch alias") !== -1)) ) { // The room doesn't exist, but we can create it - await createRoom(client, roomNameFromRoomId(roomIdOrAlias)); - return await client.joinRoom(roomIdOrAlias, { viaServers }); + const [, roomId] = await createRoom( + client, + roomNameFromRoomId(roomIdOrAlias) + ); + // likewise, wait for the room + return await waitForRoom(roomId); } else { throw error; }