From 7e5a8b8feb2acaac02045987c87ef567eb94c6b1 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Wed, 18 Sep 2024 10:08:03 +0100 Subject: [PATCH 1/2] Retry a join on invite if the response was M_FORBIDDEN --- src/room/useLoadGroupCall.ts | 47 ++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/room/useLoadGroupCall.ts b/src/room/useLoadGroupCall.ts index 8b758726..eacf090a 100644 --- a/src/room/useLoadGroupCall.ts +++ b/src/room/useLoadGroupCall.ts @@ -17,7 +17,7 @@ import { SyncState } from "matrix-js-sdk/src/sync"; import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { RoomEvent, Room } from "matrix-js-sdk/src/models/room"; import { KnownMembership } from "matrix-js-sdk/src/types"; -import { JoinRule } from "matrix-js-sdk/src/matrix"; +import { JoinRule, MatrixError } from "matrix-js-sdk/src/matrix"; import { useTranslation } from "react-i18next"; import { widget } from "../widget"; @@ -54,6 +54,40 @@ export type GroupCallStatus = | GroupCallWaitForInvite | GroupCallCanKnock; +const MAX_RETRIES_FOR_INVITE_JOIN_FAILURE = 3; + +/** + * Join a room, and retry on M_FORBIDDEN error in order to work + * around a potential race when joining rooms over federation. + * + * Will retry up to `MAX_RETRIES_FOR_INVITE_JOIN_FAILURE` times. + * + * @see https://github.com/element-hq/element-call/issues/2634 + * @param client The matrix client + * @param retries Number of attempts made. + * @param params Parameters to pass to client.joinRoom + */ +async function joinRoomAfterInvite( + client: MatrixClient, + retries = 0, + ...params: Parameters +): ReturnType { + try { + return await client.joinRoom(...params); + } catch (ex) { + if ( + ex instanceof MatrixError && + ex.errcode === "M_FORBIDDEN" && + retries < MAX_RETRIES_FOR_INVITE_JOIN_FAILURE + ) { + // If we were invited and got a M_FORBIDDEN, it's highly likely the server hasn't caught up yet. + await new Promise((r) => setTimeout(r, 5000)); + return joinRoomAfterInvite(client, retries + 1, ...params); + } + throw ex; + } +} + export class CallTerminatedMessage extends Error { /** * @param messageBody The message explaining the kind of termination (kick, ban, knock reject, etc.) (translated) @@ -162,10 +196,13 @@ export const useLoadGroupCall = ( membership === KnownMembership.Invite && prevMembership === KnownMembership.Knock ) { - client.joinRoom(room.roomId, { viaServers }).then((room) => { - logger.log("Auto-joined %s", room.roomId); - resolve(room); - }, reject); + joinRoomAfterInvite(client, 0, room.roomId, { viaServers }).then( + (room) => { + logger.log("Auto-joined %s", room.roomId); + resolve(room); + }, + reject, + ); } if (membership === KnownMembership.Ban) reject(bannedError()); if (membership === KnownMembership.Leave) From c19645c7108f5f530fbe62e39eed969df14adc00 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Wed, 18 Sep 2024 10:10:29 +0100 Subject: [PATCH 2/2] consts --- src/room/useLoadGroupCall.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/room/useLoadGroupCall.ts b/src/room/useLoadGroupCall.ts index eacf090a..6e07aa52 100644 --- a/src/room/useLoadGroupCall.ts +++ b/src/room/useLoadGroupCall.ts @@ -54,22 +54,24 @@ export type GroupCallStatus = | GroupCallWaitForInvite | GroupCallCanKnock; -const MAX_RETRIES_FOR_INVITE_JOIN_FAILURE = 3; +const MAX_ATTEMPTS_FOR_INVITE_JOIN_FAILURE = 3; +const DELAY_MS_FOR_INVITE_JOIN_FAILURE = 3000; /** * Join a room, and retry on M_FORBIDDEN error in order to work * around a potential race when joining rooms over federation. * - * Will retry up to `MAX_RETRIES_FOR_INVITE_JOIN_FAILURE` times. + * Will wait up to to `DELAY_MS_FOR_INVITE_JOIN_FAILURE` per attempt. + * Will try up to `MAX_ATTEMPTS_FOR_INVITE_JOIN_FAILURE` times. * * @see https://github.com/element-hq/element-call/issues/2634 * @param client The matrix client - * @param retries Number of attempts made. + * @param attempt Number of attempts made. * @param params Parameters to pass to client.joinRoom */ async function joinRoomAfterInvite( client: MatrixClient, - retries = 0, + attempt = 0, ...params: Parameters ): ReturnType { try { @@ -78,11 +80,11 @@ async function joinRoomAfterInvite( if ( ex instanceof MatrixError && ex.errcode === "M_FORBIDDEN" && - retries < MAX_RETRIES_FOR_INVITE_JOIN_FAILURE + attempt < MAX_ATTEMPTS_FOR_INVITE_JOIN_FAILURE ) { // If we were invited and got a M_FORBIDDEN, it's highly likely the server hasn't caught up yet. - await new Promise((r) => setTimeout(r, 5000)); - return joinRoomAfterInvite(client, retries + 1, ...params); + await new Promise((r) => setTimeout(r, DELAY_MS_FOR_INVITE_JOIN_FAILURE)); + return joinRoomAfterInvite(client, attempt + 1, ...params); } throw ex; }