Merge pull request #2637 from element-hq/hs/workaround-federation-bug

Retry a join on invite if the response was M_FORBIDDEN
This commit is contained in:
Will Hunt 2024-09-18 12:31:20 +01:00 committed by GitHub
commit 4bf6509109
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -17,7 +17,7 @@ import { SyncState } from "matrix-js-sdk/src/sync";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession"; import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
import { RoomEvent, Room } from "matrix-js-sdk/src/models/room"; import { RoomEvent, Room } from "matrix-js-sdk/src/models/room";
import { KnownMembership } from "matrix-js-sdk/src/types"; 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 { useTranslation } from "react-i18next";
import { widget } from "../widget"; import { widget } from "../widget";
@ -54,6 +54,42 @@ export type GroupCallStatus =
| GroupCallWaitForInvite | GroupCallWaitForInvite
| GroupCallCanKnock; | GroupCallCanKnock;
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 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 attempt Number of attempts made.
* @param params Parameters to pass to client.joinRoom
*/
async function joinRoomAfterInvite(
client: MatrixClient,
attempt = 0,
...params: Parameters<MatrixClient["joinRoom"]>
): ReturnType<MatrixClient["joinRoom"]> {
try {
return await client.joinRoom(...params);
} catch (ex) {
if (
ex instanceof MatrixError &&
ex.errcode === "M_FORBIDDEN" &&
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, DELAY_MS_FOR_INVITE_JOIN_FAILURE));
return joinRoomAfterInvite(client, attempt + 1, ...params);
}
throw ex;
}
}
export class CallTerminatedMessage extends Error { export class CallTerminatedMessage extends Error {
/** /**
* @param messageBody The message explaining the kind of termination (kick, ban, knock reject, etc.) (translated) * @param messageBody The message explaining the kind of termination (kick, ban, knock reject, etc.) (translated)
@ -162,10 +198,13 @@ export const useLoadGroupCall = (
membership === KnownMembership.Invite && membership === KnownMembership.Invite &&
prevMembership === KnownMembership.Knock prevMembership === KnownMembership.Knock
) { ) {
client.joinRoom(room.roomId, { viaServers }).then((room) => { joinRoomAfterInvite(client, 0, room.roomId, { viaServers }).then(
logger.log("Auto-joined %s", room.roomId); (room) => {
resolve(room); logger.log("Auto-joined %s", room.roomId);
}, reject); resolve(room);
},
reject,
);
} }
if (membership === KnownMembership.Ban) reject(bannedError()); if (membership === KnownMembership.Ban) reject(bannedError());
if (membership === KnownMembership.Leave) if (membership === KnownMembership.Leave)