diff --git a/package.json b/package.json index 3d3d938b..6a5a47a1 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "i18next-http-backend": "^1.4.4", "livekit-client": "1.12.0", "lodash": "^4.17.21", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#d79d9ae69c3220c02406706d4a1ec52c22c44fbd", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#b698217445318f453e0b1086364a33113eaa85d9", "matrix-widget-api": "^1.3.1", "mermaid": "^8.13.8", "normalize.css": "^8.0.1", diff --git a/src/ClientContext.tsx b/src/ClientContext.tsx index d488d6de..69a9295e 100644 --- a/src/ClientContext.tsx +++ b/src/ClientContext.tsx @@ -327,10 +327,6 @@ async function loadClient(): Promise { logger.log("Using a standalone client"); - const foci = Config.get().livekit - ? [{ livekitServiceUrl: Config.get().livekit!.livekit_service_url }] - : undefined; - /* eslint-disable camelcase */ const { user_id, device_id, access_token, passwordlessUser } = session; const initClientParams = { @@ -339,7 +335,7 @@ async function loadClient(): Promise { userId: user_id, deviceId: device_id, fallbackICEServerAllowed: fallbackICEServerAllowed, - foci, + livekitServiceURL: Config.get().livekit!.livekit_service_url, }; try { diff --git a/src/livekit/OpenIDLoader.tsx b/src/livekit/OpenIDLoader.tsx index 66b5cc76..911a1ae7 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 as Error }); } })(); - }, [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..3cc61fbb 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 9afc2ec3..29d14b82 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 { @@ -219,20 +218,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 ( { // message so that we can use the widget API in less racy mode, but we need to change // element-web to use waitForIFrameLoad=false. Once that change has rolled out, // we can just start the client after we've fetched the config. - foci: [], + livekitServiceURL: undefined, } ); @@ -178,9 +178,7 @@ export const widget: WidgetHelpers | null = (() => { // Now we've fetched the config, be evil and use the getter to inject the focus // into the client (see above XXX). if (focus) { - client.getFoci().push({ - livekitServiceUrl: livekit.livekit_service_url, - }); + client.setLivekitServiceURL(livekit.livekit_service_url); } await client.startClient(); resolve(client); diff --git a/yarn.lock b/yarn.lock index 7073bdf9..d8207984 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2187,9 +2187,9 @@ clsx "^1.2.1" "@matrix-org/matrix-sdk-crypto-js@^0.1.1": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.2.tgz#b58679e161f3d734359a8665922956309b1a4417" - integrity sha512-bbal0RcWwerS/DgqhOgM7wkXJ2YSv9fySK/qgLlrAsdYLpMSTqG8wDQ89/v+RYo9WmA5hwUN/wXcCDdFaFEXQQ== + version "0.1.3" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.3.tgz#19981e7613d3673d07c885a98d39276b5fe74ef0" + integrity sha512-RcRlE3wcMnE5ijACHIHmhXFogEEJdIcb/CbJ4rK1PCMduQ4yvxycVpMxwh7aKxFNitZbHZLCK7TfRzUpzjU2tw== "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz": version "3.2.14" @@ -11012,9 +11012,9 @@ matrix-events-sdk@0.0.1: resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd" integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#d79d9ae69c3220c02406706d4a1ec52c22c44fbd": +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#b698217445318f453e0b1086364a33113eaa85d9": version "26.2.0" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/d79d9ae69c3220c02406706d4a1ec52c22c44fbd" + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/b698217445318f453e0b1086364a33113eaa85d9" dependencies: "@babel/runtime" "^7.12.5" "@matrix-org/matrix-sdk-crypto-js" "^0.1.1"