Revert "Support for getting SFU config using OIDC"

This commit is contained in:
David Baker 2023-07-04 19:21:35 +01:00 committed by GitHub
parent c9f57cb2a3
commit 29553c1151
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 51 additions and 189 deletions

View file

@ -6,7 +6,8 @@
} }
}, },
"livekit": { "livekit": {
"livekit_service_url": "https://lk-jwt-service.lab.element.dev" "server_url": "wss://sfu.call.element.dev",
"jwt_service_url": "https://voip-sip-poc.element.io/lk/jwt_service"
}, },
"posthog": { "posthog": {
"api_key": "phc_rXGHx9vDmyEvyRxPziYtdVIv0ahEv8A9uLWFcCi1WcU", "api_key": "phc_rXGHx9vDmyEvyRxPziYtdVIv0ahEv8A9uLWFcCi1WcU",

View file

@ -55,8 +55,10 @@ export interface ConfigOptions {
// Describes the LiveKit configuration to be used. // Describes the LiveKit configuration to be used.
livekit?: { livekit?: {
// The link to the service that returns a livekit url and token to use it // The LiveKit server URL to connect to.
livekit_service_url: string; server_url: string;
// The link to the service that generates JWT tokens to join LiveKit rooms.
jwt_service_url: string;
}; };
/** /**

View file

@ -1,96 +0,0 @@
/*
Copyright 2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {
ReactNode,
createContext,
useContext,
useEffect,
useState,
} from "react";
import { logger } from "matrix-js-sdk/src/logger";
import {
OpenIDClientParts,
SFUConfig,
getSFUConfigWithOpenID,
} from "./openIDSFU";
import { ErrorView, LoadingView } from "../FullScreenView";
interface Props {
client: OpenIDClientParts;
livekitServiceURL: string;
roomName: string;
children: ReactNode;
}
const SFUConfigContext = createContext<SFUConfig>(undefined);
export const useSFUConfig = () => useContext(SFUConfigContext);
export function OpenIDLoader({
client,
livekitServiceURL,
roomName,
children,
}: Props) {
const [state, setState] = useState<
SFUConfigLoading | SFUConfigLoaded | SFUConfigFailed
>({ kind: "loading" });
useEffect(() => {
(async () => {
try {
const result = await getSFUConfigWithOpenID(
client,
livekitServiceURL,
roomName
);
setState({ kind: "loaded", sfuConfig: result });
} catch (e) {
logger.error("Failed to fetch SFU config: ", e);
setState({ kind: "failed", error: e });
}
})();
}, [client, livekitServiceURL, roomName]);
switch (state.kind) {
case "loading":
return <LoadingView />;
case "failed":
return <ErrorView error={state.error} />;
case "loaded":
return (
<SFUConfigContext.Provider value={state.sfuConfig}>
{children}
</SFUConfigContext.Provider>
);
}
}
type SFUConfigLoading = {
kind: "loading";
};
type SFUConfigLoaded = {
kind: "loaded";
sfuConfig: SFUConfig;
};
type SFUConfigFailed = {
kind: "failed";
error: Error;
};

View file

@ -1,54 +0,0 @@
/*
Copyright 2023 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { MatrixClient } from "matrix-js-sdk";
import { logger } from "matrix-js-sdk/src/logger";
export interface SFUConfig {
url: string;
jwt: string;
}
// The bits we need from MatrixClient
export type OpenIDClientParts = Pick<
MatrixClient,
"getOpenIdToken" | "getDeviceId"
>;
export async function getSFUConfigWithOpenID(
client: OpenIDClientParts,
livekitServiceURL: string,
roomName: string
): Promise<SFUConfig> {
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("SFO Config fetch failed with status code " + res.status);
}
return await res.json();
}

View file

@ -1,9 +1,8 @@
import { Room, RoomOptions } from "livekit-client"; import { Room, RoomOptions } from "livekit-client";
import { useLiveKitRoom } from "@livekit/components-react"; import { useLiveKitRoom, useToken } from "@livekit/components-react";
import { useMemo } from "react"; import { useMemo } from "react";
import { defaultLiveKitOptions } from "./options"; import { defaultLiveKitOptions } from "./options";
import { SFUConfig } from "./openIDSFU";
export type UserChoices = { export type UserChoices = {
audio?: DeviceChoices; audio?: DeviceChoices;
@ -15,10 +14,29 @@ export type DeviceChoices = {
enabled: boolean; enabled: boolean;
}; };
export type LiveKitConfig = {
sfuUrl: string;
jwtUrl: string;
roomName: string;
userDisplayName: string;
userIdentity: string;
};
export function useLiveKit( export function useLiveKit(
userChoices: UserChoices, userChoices: UserChoices,
sfuConfig: SFUConfig config: LiveKitConfig
): Room | undefined { ): Room | undefined {
const tokenOptions = useMemo(
() => ({
userInfo: {
name: config.userDisplayName,
identity: config.userIdentity,
},
}),
[config.userDisplayName, config.userIdentity]
);
const token = useToken(config.jwtUrl, config.roomName, tokenOptions);
const roomOptions = useMemo((): RoomOptions => { const roomOptions = useMemo((): RoomOptions => {
const options = defaultLiveKitOptions; const options = defaultLiveKitOptions;
options.videoCaptureDefaults = { options.videoCaptureDefaults = {
@ -33,8 +51,8 @@ export function useLiveKit(
}, [userChoices.video, userChoices.audio]); }, [userChoices.video, userChoices.audio]);
const { room } = useLiveKitRoom({ const { room } = useLiveKitRoom({
token: sfuConfig.jwt, token,
serverUrl: sfuConfig.url, serverUrl: config.sfuUrl,
audio: userChoices.audio?.enabled ?? false, audio: userChoices.audio?.enabled ?? false,
video: userChoices.video?.enabled ?? false, video: userChoices.video?.enabled ?? false,
options: roomOptions, options: roomOptions,

View file

@ -28,15 +28,13 @@ import { useGroupCall } from "./useGroupCall";
import { ErrorView, FullScreenView } from "../FullScreenView"; import { ErrorView, FullScreenView } from "../FullScreenView";
import { LobbyView } from "./LobbyView"; import { LobbyView } from "./LobbyView";
import { MatrixInfo } from "./VideoPreview"; import { MatrixInfo } from "./VideoPreview";
import { ActiveCall } from "./InCallView";
import { CallEndedView } from "./CallEndedView"; import { CallEndedView } from "./CallEndedView";
import { useSentryGroupCallHandler } from "./useSentryGroupCallHandler"; import { useSentryGroupCallHandler } from "./useSentryGroupCallHandler";
import { PosthogAnalytics } from "../analytics/PosthogAnalytics"; import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
import { useProfile } from "../profile/useProfile"; import { useProfile } from "../profile/useProfile";
import { UserChoices } from "../livekit/useLiveKit"; import { UserChoices } from "../livekit/useLiveKit";
import { findDeviceByName } from "../media-utils"; import { findDeviceByName } from "../media-utils";
import { OpenIDLoader } from "../livekit/OpenIDLoader";
import { ActiveCall } from "./InCallView";
import { Config } from "../config/Config";
declare global { declare global {
interface Window { interface Window {
@ -220,33 +218,21 @@ export function GroupCallView({
undefined undefined
); );
const lkServiceURL = Config.get().livekit?.livekit_service_url;
if (!lkServiceURL) {
return <ErrorView error={new Error("No livekit_service_url defined")} />;
}
if (error) { if (error) {
return <ErrorView error={error} />; return <ErrorView error={error} />;
} else if (state === GroupCallState.Entered && userChoices) { } else if (state === GroupCallState.Entered && userChoices) {
return ( return (
<OpenIDLoader <ActiveCall
groupCall={groupCall}
client={client} client={client}
livekitServiceURL={lkServiceURL} participants={participants}
roomName={matrixInfo.roomName} onLeave={onLeave}
> unencryptedEventsFromUsers={unencryptedEventsFromUsers}
<ActiveCall hideHeader={hideHeader}
client={client} matrixInfo={matrixInfo}
groupCall={groupCall} userChoices={userChoices}
participants={participants} otelGroupCallMembership={otelGroupCallMembership}
onLeave={onLeave} />
unencryptedEventsFromUsers={unencryptedEventsFromUsers}
hideHeader={hideHeader}
matrixInfo={matrixInfo}
userChoices={userChoices}
otelGroupCallMembership={otelGroupCallMembership}
/>
</OpenIDLoader>
); );
} else if (left) { } else if (left) {
// The call ended view is shown for two reasons: prompting guests to create // The call ended view is shown for two reasons: prompting guests to create

View file

@ -72,6 +72,7 @@ import { MatrixInfo } from "./VideoPreview";
import { useJoinRule } from "./useJoinRule"; import { useJoinRule } from "./useJoinRule";
import { ParticipantInfo } from "./useGroupCall"; import { ParticipantInfo } from "./useGroupCall";
import { ItemData, TileContent } from "../video-grid/VideoTile"; import { ItemData, TileContent } from "../video-grid/VideoTile";
import { Config } from "../config/Config";
import { NewVideoGrid } from "../video-grid/NewVideoGrid"; import { NewVideoGrid } from "../video-grid/NewVideoGrid";
import { OTelGroupCallMembership } from "../otel/OTelGroupCallMembership"; import { OTelGroupCallMembership } from "../otel/OTelGroupCallMembership";
import { SettingsModal } from "../settings/SettingsModal"; import { SettingsModal } from "../settings/SettingsModal";
@ -83,7 +84,6 @@ import { UserChoices, useLiveKit } from "../livekit/useLiveKit";
import { useMediaDevices } from "../livekit/useMediaDevices"; import { useMediaDevices } from "../livekit/useMediaDevices";
import { useFullscreen } from "./useFullscreen"; import { useFullscreen } from "./useFullscreen";
import { useLayoutStates } from "../video-grid/Layout"; import { useLayoutStates } from "../video-grid/Layout";
import { useSFUConfig } from "../livekit/OpenIDLoader";
const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {}); const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
// There is currently a bug in Safari our our code with cloning and sending MediaStreams // There is currently a bug in Safari our our code with cloning and sending MediaStreams
@ -91,13 +91,18 @@ const canScreenshare = "getDisplayMedia" in (navigator.mediaDevices ?? {});
// For now we can disable screensharing in Safari. // For now we can disable screensharing in Safari.
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
export interface ActiveCallProps extends Omit<InCallViewProps, "livekitRoom"> { interface ActiveCallProps extends Omit<Props, "livekitRoom"> {
userChoices: UserChoices; userChoices: UserChoices;
} }
export function ActiveCall(props: ActiveCallProps) { export function ActiveCall(props: ActiveCallProps) {
const sfuConfig = useSFUConfig(); const livekitRoom = useLiveKit(props.userChoices, {
const livekitRoom = useLiveKit(props.userChoices, sfuConfig); sfuUrl: Config.get().livekit!.server_url,
jwtUrl: `${Config.get().livekit!.jwt_service_url}/token`,
roomName: props.matrixInfo.roomName,
userDisplayName: props.matrixInfo.displayName,
userIdentity: `${props.client.getUserId()}:${props.client.getDeviceId()}`,
});
return ( return (
livekitRoom && ( livekitRoom && (
@ -108,7 +113,7 @@ export function ActiveCall(props: ActiveCallProps) {
); );
} }
export interface InCallViewProps { interface Props {
client: MatrixClient; client: MatrixClient;
groupCall: GroupCall; groupCall: GroupCall;
livekitRoom: Room; livekitRoom: Room;
@ -130,7 +135,7 @@ export function InCallView({
hideHeader, hideHeader,
matrixInfo, matrixInfo,
otelGroupCallMembership, otelGroupCallMembership,
}: InCallViewProps) { }: Props) {
const { t } = useTranslation(); const { t } = useTranslation();
usePreventScroll(); usePreventScroll();