diff --git a/src/livekit/openIDSFU.ts b/src/livekit/openIDSFU.ts index 0f455a38..4a82de23 100644 --- a/src/livekit/openIDSFU.ts +++ b/src/livekit/openIDSFU.ts @@ -12,6 +12,9 @@ import { useEffect, useState } from "react"; import { type LivekitFocus } from "matrix-js-sdk/src/matrixrtc/LivekitFocus"; import { useActiveLivekitFocus } from "../room/useActiveFocus"; +import { useGroupCallErrorBoundary } from "../room/useCallErrorBoundary.ts"; +import { FailToGetOpenIdToken } from "../utils/errors.ts"; +import { doNetworkOperationWithRetry } from "../utils/matrix.ts"; export interface SFUConfig { url: string; @@ -38,6 +41,7 @@ export function useOpenIDSFU( const [sfuConfig, setSFUConfig] = useState(undefined); const activeFocus = useActiveLivekitFocus(rtcSession); + const { showGroupCallErrorBoundary } = useGroupCallErrorBoundary(); useEffect(() => { if (activeFocus) { @@ -46,13 +50,14 @@ export function useOpenIDSFU( setSFUConfig(sfuConfig); }, (e) => { + showGroupCallErrorBoundary(new FailToGetOpenIdToken(e)); logger.error("Failed to get SFU config", e); }, ); } else { setSFUConfig(undefined); } - }, [client, activeFocus]); + }, [client, activeFocus, showGroupCallErrorBoundary]); return sfuConfig; } @@ -61,7 +66,16 @@ export async function getSFUConfigWithOpenID( client: OpenIDClientParts, activeFocus: LivekitFocus, ): Promise { - const openIdToken = await client.getOpenIdToken(); + let openIdToken: IOpenIDToken; + try { + openIdToken = await doNetworkOperationWithRetry(async () => + client.getOpenIdToken(), + ); + } catch (error) { + throw new FailToGetOpenIdToken( + error instanceof Error ? error : new Error("Unknown error"), + ); + } logger.debug("Got openID token", openIdToken); try { diff --git a/src/room/GroupCallErrorBoundary.test.tsx b/src/room/GroupCallErrorBoundary.test.tsx index f99f01fa..c42e3ded 100644 --- a/src/room/GroupCallErrorBoundary.test.tsx +++ b/src/room/GroupCallErrorBoundary.test.tsx @@ -8,6 +8,7 @@ Please see LICENSE in the repository root for full details. import { describe, expect, test, vi } from "vitest"; import { render, screen } from "@testing-library/react"; import { + type FC, type ReactElement, type ReactNode, useCallback, diff --git a/src/utils/errors.ts b/src/utils/errors.ts index 91943fb4..e8adbca1 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -16,6 +16,7 @@ export enum ErrorCode { /** LiveKit indicates that the server has hit its track limits */ INSUFFICIENT_CAPACITY_ERROR = "INSUFFICIENT_CAPACITY_ERROR", E2EE_NOT_SUPPORTED = "E2EE_NOT_SUPPORTED", + OPEN_ID_ERROR = "OPEN_ID_ERROR", UNKNOWN_ERROR = "UNKNOWN_ERROR", } @@ -41,7 +42,7 @@ export class ElementCallError extends Error { localisedTitle: string, code: ErrorCode, category: ErrorCategory, - localisedMessage: string, + localisedMessage?: string, cause?: Error, ) { super(localisedTitle, { cause }); @@ -105,6 +106,19 @@ export class UnknownCallError extends ElementCallError { } } +export class FailToGetOpenIdToken extends ElementCallError { + public constructor(error: Error) { + super( + t("error.generic"), + ErrorCode.OPEN_ID_ERROR, + ErrorCategory.CONFIGURATION_ISSUE, + undefined, + // Properly set it as a cause for a better reporting on sentry + error, + ); + } +} + export class InsufficientCapacityError extends ElementCallError { public constructor() { super(