prettier !

This commit is contained in:
Valere
2025-10-07 16:24:02 +02:00
parent 7437961195
commit 529cb8a7ec
12 changed files with 547 additions and 421 deletions

View File

@@ -5,12 +5,27 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
import { connectedParticipantsObserver, connectionStateObserver } from "@livekit/components-core";
import { type ConnectionState, type E2EEOptions, Room as LivekitRoom, type RoomOptions } from "livekit-client";
import { type CallMembership, type LivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
import {
connectedParticipantsObserver,
connectionStateObserver,
} from "@livekit/components-core";
import {
type ConnectionState,
type E2EEOptions,
Room as LivekitRoom,
type RoomOptions,
} from "livekit-client";
import {
type CallMembership,
type LivekitTransport,
} from "matrix-js-sdk/lib/matrixrtc";
import { BehaviorSubject, combineLatest } from "rxjs";
import { getSFUConfigWithOpenID, type OpenIDClientParts, type SFUConfig } from "../livekit/openIDSFU";
import {
getSFUConfigWithOpenID,
type OpenIDClientParts,
type SFUConfig,
} from "../livekit/openIDSFU";
import { type Behavior } from "./Behavior";
import { type ObservableScope } from "./ObservableScope";
import { defaultLiveKitOptions } from "../livekit/options";
@@ -23,20 +38,26 @@ export interface ConnectionOpts {
/** The observable scope to use for this connection. */
scope: ObservableScope;
/** An observable of the current RTC call memberships and their associated focus. */
remoteTransports$: Behavior<{ membership: CallMembership; transport: LivekitTransport }[]>;
remoteTransports$: Behavior<
{ membership: CallMembership; transport: LivekitTransport }[]
>;
/** Optional factory to create the Livekit room, mainly for testing purposes. */
livekitRoomFactory?: (options?: RoomOptions) => LivekitRoom;
}
export type FocusConnectionState =
| { state: 'Initialized' }
| { state: 'FetchingConfig', focus: LivekitTransport }
| { state: 'ConnectingToLkRoom', focus: LivekitTransport }
| { state: 'PublishingTracks', focus: LivekitTransport }
| { state: 'FailedToStart', error: Error, focus: LivekitTransport }
| { state: 'ConnectedToLkRoom', connectionState: ConnectionState, focus: LivekitTransport }
| { state: 'Stopped', focus: LivekitTransport };
| { state: "Initialized" }
| { state: "FetchingConfig"; focus: LivekitTransport }
| { state: "ConnectingToLkRoom"; focus: LivekitTransport }
| { state: "PublishingTracks"; focus: LivekitTransport }
| { state: "FailedToStart"; error: Error; focus: LivekitTransport }
| {
state: "ConnectedToLkRoom";
connectionState: ConnectionState;
focus: LivekitTransport;
}
| { state: "Stopped"; focus: LivekitTransport };
/**
* A connection to a Matrix RTC LiveKit backend.
@@ -44,10 +65,9 @@ export type FocusConnectionState =
* Expose observables for participants and connection state.
*/
export class Connection {
// Private Behavior
private readonly _focusedConnectionState$
= new BehaviorSubject<FocusConnectionState>({ state: 'Initialized' });
private readonly _focusedConnectionState$ =
new BehaviorSubject<FocusConnectionState>({ state: "Initialized" });
/**
* The current state of the connection to the focus server.
@@ -71,31 +91,44 @@ export class Connection {
public async start(): Promise<void> {
this.stopped = false;
try {
this._focusedConnectionState$.next({ state: 'FetchingConfig', focus: this.localTransport });
this._focusedConnectionState$.next({
state: "FetchingConfig",
focus: this.localTransport,
});
// TODO could this be loaded earlier to save time?
const { url, jwt } = await this.getSFUConfigWithOpenID();
// If we were stopped while fetching the config, don't proceed to connect
if (this.stopped) return;
this._focusedConnectionState$.next({ state: 'ConnectingToLkRoom', focus: this.localTransport });
this._focusedConnectionState$.next({
state: "ConnectingToLkRoom",
focus: this.localTransport,
});
await this.livekitRoom.connect(url, jwt);
// If we were stopped while connecting, don't proceed to update state.
if (this.stopped) return;
this._focusedConnectionState$.next({ state: 'ConnectedToLkRoom', focus: this.localTransport, connectionState: this.livekitRoom.state });
this._focusedConnectionState$.next({
state: "ConnectedToLkRoom",
focus: this.localTransport,
connectionState: this.livekitRoom.state,
});
} catch (error) {
this._focusedConnectionState$.next({ state: 'FailedToStart', error: error instanceof Error ? error : new Error(`${error}`), focus: this.localTransport });
this._focusedConnectionState$.next({
state: "FailedToStart",
error: error instanceof Error ? error : new Error(`${error}`),
focus: this.localTransport,
});
throw error;
}
}
protected async getSFUConfigWithOpenID(): Promise<SFUConfig> {
return await getSFUConfigWithOpenID(
this.client,
this.localTransport.livekit_service_url,
this.localTransport.livekit_alias
)
this.localTransport.livekit_alias,
);
}
/**
* Stops the connection.
@@ -106,11 +139,13 @@ export class Connection {
public async stop(): Promise<void> {
if (this.stopped) return;
await this.livekitRoom.disconnect();
this._focusedConnectionState$.next({ state: 'Stopped', focus: this.localTransport });
this._focusedConnectionState$.next({
state: "Stopped",
focus: this.localTransport,
});
this.stopped = true;
}
/**
* An observable of the participants that are publishing on this connection.
* This is derived from `participantsIncludingSubscribers$` and `membershipsFocusMap$`.
@@ -135,20 +170,20 @@ export class Connection {
public readonly livekitRoom: LivekitRoom,
opts: ConnectionOpts,
) {
const { transport, client, scope, remoteTransports$ } =
opts;
const { transport, client, scope, remoteTransports$ } = opts;
this.livekitRoom = livekitRoom
this.livekitRoom = livekitRoom;
this.localTransport = transport;
this.client = client;
this.focusedConnectionState$ = scope.behavior(
this._focusedConnectionState$, { state: 'Initialized' }
this._focusedConnectionState$,
{ state: "Initialized" },
);
const participantsIncludingSubscribers$ = scope.behavior(
connectedParticipantsObserver(this.livekitRoom),
[]
[],
);
this.publishingParticipants$ = scope.behavior(
@@ -161,7 +196,7 @@ export class Connection {
transport.livekit_service_url ===
this.localTransport.livekit_service_url
? [membership]
: []
: [],
)
// Pair with their associated LiveKit participant (if any)
// Uses flatMap to filter out memberships with no associated rtc participant ([])
@@ -171,18 +206,22 @@ export class Connection {
return participant ? [{ participant, membership }] : [];
}),
),
[]
[],
);
scope.behavior<ConnectionState>(
connectionStateObserver(this.livekitRoom)
).subscribe((connectionState) => {
const current = this._focusedConnectionState$.value;
// Only update the state if we are already connected to the LiveKit room.
if (current.state === 'ConnectedToLkRoom') {
this._focusedConnectionState$.next({ state: 'ConnectedToLkRoom', connectionState, focus: current.focus });
}
});
scope
.behavior<ConnectionState>(connectionStateObserver(this.livekitRoom))
.subscribe((connectionState) => {
const current = this._focusedConnectionState$.value;
// Only update the state if we are already connected to the LiveKit room.
if (current.state === "ConnectedToLkRoom") {
this._focusedConnectionState$.next({
state: "ConnectedToLkRoom",
connectionState,
focus: current.focus,
});
}
});
scope.onEnd(() => void this.stop());
}
@@ -195,17 +234,21 @@ export class Connection {
* It does not publish any local tracks.
*/
export class RemoteConnection extends Connection {
/**
* Creates a new remote connection to a matrix RTC LiveKit backend.
* @param opts
* @param sharedE2eeOption - The shared E2EE options to use for the connection.
*/
public constructor(opts: ConnectionOpts, sharedE2eeOption: E2EEOptions | undefined) {
const factory = opts.livekitRoomFactory ?? ((options: RoomOptions): LivekitRoom => new LivekitRoom(options));
public constructor(
opts: ConnectionOpts,
sharedE2eeOption: E2EEOptions | undefined,
) {
const factory =
opts.livekitRoomFactory ??
((options: RoomOptions): LivekitRoom => new LivekitRoom(options));
const livekitRoom = factory({
...defaultLiveKitOptions,
e2ee: sharedE2eeOption
e2ee: sharedE2eeOption,
});
super(livekitRoom, opts);
}