From 4fe6ac6b2d02fda32fc091daff05bf9405a46a45 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 12 Jul 2023 16:49:27 +0100 Subject: [PATCH] Update livekit service URLs if they fail Requires https://github.com/matrix-org/matrix-js-sdk/pull/3598 Fixes https://github.com/vector-im/element-call/issues/1190 Fixes https://github.com/matrix-org/matrix-hosted/issues/8021 --- src/livekit/OpenIDLoader.tsx | 14 ++---- src/livekit/openIDSFU.ts | 93 +++++++++++++++++++++++++++++------- src/room/GroupCallView.tsx | 10 +--- 3 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/livekit/OpenIDLoader.tsx b/src/livekit/OpenIDLoader.tsx index 9e68d311..5fbb6a07 100644 --- a/src/livekit/OpenIDLoader.tsx +++ b/src/livekit/OpenIDLoader.tsx @@ -22,6 +22,7 @@ import { useState, } from "react"; import { logger } from "matrix-js-sdk/src/logger"; +import { GroupCall } from "matrix-js-sdk"; import { OpenIDClientParts, @@ -32,7 +33,7 @@ import { ErrorView, LoadingView } from "../FullScreenView"; interface Props { client: OpenIDClientParts; - livekitServiceURL: string; + groupCall: GroupCall; roomName: string; children: ReactNode; } @@ -41,12 +42,7 @@ const SFUConfigContext = createContext(undefined); export const useSFUConfig = () => useContext(SFUConfigContext); -export function OpenIDLoader({ - client, - livekitServiceURL, - roomName, - children, -}: Props) { +export function OpenIDLoader({ client, groupCall, roomName, children }: Props) { const [state, setState] = useState< SFUConfigLoading | SFUConfigLoaded | SFUConfigFailed >({ kind: "loading" }); @@ -56,7 +52,7 @@ export function OpenIDLoader({ try { const result = await getSFUConfigWithOpenID( client, - livekitServiceURL, + groupCall, roomName ); setState({ kind: "loaded", sfuConfig: result }); @@ -65,7 +61,7 @@ export function OpenIDLoader({ setState({ kind: "failed", error: e }); } })(); - }, [client, livekitServiceURL, roomName]); + }, [client, groupCall, roomName]); switch (state.kind) { case "loading": diff --git a/src/livekit/openIDSFU.ts b/src/livekit/openIDSFU.ts index 88adcc70..ee88342c 100644 --- a/src/livekit/openIDSFU.ts +++ b/src/livekit/openIDSFU.ts @@ -14,9 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MatrixClient } from "matrix-js-sdk"; +import { GroupCall, IOpenIDToken, MatrixClient } from "matrix-js-sdk"; import { logger } from "matrix-js-sdk/src/logger"; +import { Config } from "../config/Config"; + export interface SFUConfig { url: string; jwt: string; @@ -30,25 +32,84 @@ export type OpenIDClientParts = Pick< export async function getSFUConfigWithOpenID( client: OpenIDClientParts, - livekitServiceURL: string, + groupCall: GroupCall, roomName: string ): Promise { const openIdToken = await client.getOpenIdToken(); logger.debug("Got openID token", openIdToken); - const res = await fetch(livekitServiceURL + "/sfu/get", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - room: roomName, - openid_token: openIdToken, - device_id: client.getDeviceId(), - }), - }); - if (!res.ok) { - throw new Error("SFU Config fetch failed with status code " + res.status); + // if the call has a livekit service URL, try it. + if (groupCall.livekitServiceURL) { + try { + logger.info(`Trying to get JWT from ${groupCall.livekitServiceURL}...`); + const sfuConfig = await getLiveKitJWT( + client, + groupCall.livekitServiceURL, + roomName, + openIdToken + ); + + return sfuConfig; + } catch (e) { + logger.warn( + `Failed to get JWT from group call's configured URL of ${groupCall.livekitServiceURL}.`, + e + ); + } + } + + // otherwise, try our configured one and, if it works, update the call's service URL in the state event + // NB. This wuill update it for everyone so we may end up with multiple clients updating this when they + // join at similar times, but we don't have a huge number of options here. + const urlFromConf = Config.get().livekit.livekit_service_url; + logger.info(`Trying livekit service URL from our config: ${urlFromConf}...`); + try { + const sfuConfig = await getLiveKitJWT( + client, + urlFromConf, + roomName, + openIdToken + ); + + logger.info(`Updating call livekit service URL with: ${urlFromConf}...`); + try { + await groupCall.updateLivekitServiceURL(urlFromConf); + } catch (e) { + logger.warn( + `Failed to update call livekit service URL: continuing anyway.` + ); + } + + return sfuConfig; + } catch (e) { + logger.error("Failed to get JWT from URL defined in Config.", e); + throw e; + } +} + +async function getLiveKitJWT( + client: OpenIDClientParts, + livekitServiceURL: string, + roomName: string, + openIDToken: IOpenIDToken +): Promise { + try { + const res = await fetch(livekitServiceURL + "/sfu/get", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + room: roomName, + openid_token: openIDToken, + device_id: client.getDeviceId(), + }), + }); + if (!res.ok) { + throw new Error("SFU Config fetch failed with status code " + res.status); + } + return await res.json(); + } catch (e) { + throw new Error("SFU Config fetch failed with exception " + e); } - return await res.json(); } diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index 1ed4726c..d85ea453 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -36,7 +36,6 @@ import { UserChoices } from "../livekit/useLiveKit"; import { findDeviceByName } from "../media-utils"; import { OpenIDLoader } from "../livekit/OpenIDLoader"; import { ActiveCall } from "./InCallView"; -import { Config } from "../config/Config"; declare global { interface Window { @@ -220,20 +219,13 @@ export function GroupCallView({ undefined ); - const livekitServiceURL = - groupCall.foci[0]?.livekitServiceUrl ?? - Config.get().livekit.livekit_service_url; - if (!livekitServiceURL) { - return ; - } - if (error) { return ; } else if (state === GroupCallState.Entered && userChoices) { return (