mirror of
https://github.com/vector-im/element-call.git
synced 2026-10-16 23:45:50 +00:00
Make the auth choice mode independent again
This commit is contained in:
@@ -54,21 +54,20 @@ const cases: {
|
|||||||
guestFlows: ["cs-api"],
|
guestFlows: ["cs-api"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// In compatibility mode both publish a membership state event, so both
|
// Publishers keep the legacy participant identity that clients predating
|
||||||
// must keep the legacy participant identity that clients predating MSC4195
|
// MSC4195 expect, which only the JWT service assigns.
|
||||||
// expect, which only the JWT service assigns.
|
|
||||||
hostShape: "both",
|
hostShape: "both",
|
||||||
guestShape: "both",
|
guestShape: "both",
|
||||||
hostFlows: ["service-legacy"],
|
hostFlows: ["service-legacy"],
|
||||||
guestFlows: ["service-legacy"],
|
guestFlows: ["service-legacy"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// In Matrix 2.0 mode nobody expects a legacy identity, so the CS API wins.
|
// The MatrixRTC mode has no bearing on the choice.
|
||||||
hostShape: "both",
|
hostShape: "both",
|
||||||
guestShape: "both",
|
guestShape: "both",
|
||||||
mode: "2_0",
|
mode: "2_0",
|
||||||
hostFlows: ["cs-api"],
|
hostFlows: ["service-legacy"],
|
||||||
guestFlows: ["cs-api"],
|
guestFlows: ["service-legacy"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
hostShape: "url",
|
hostShape: "url",
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import { delegateDelayedLeave, getSFUConfig } from ".";
|
|||||||
import { mocked } from "storybook/test";
|
import { mocked } from "storybook/test";
|
||||||
import { ConnectionError, MatrixError } from "matrix-js-sdk";
|
import { ConnectionError, MatrixError } from "matrix-js-sdk";
|
||||||
import { NoMatrix2AuthorizationService } from "../../utils/errors";
|
import { NoMatrix2AuthorizationService } from "../../utils/errors";
|
||||||
import { MatrixRTCMode } from "../../config/ConfigOptions";
|
|
||||||
import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/EncryptionManager";
|
import { type CallMembershipIdentityParts } from "matrix-js-sdk/lib/matrixrtc/EncryptionManager";
|
||||||
|
|
||||||
vi.mock("./openID", () => ({ getSFUConfig: vi.fn() }));
|
vi.mock("./openID", () => ({ getSFUConfig: vi.fn() }));
|
||||||
@@ -84,7 +83,6 @@ describe("getSFUConfig", () => {
|
|||||||
membership,
|
membership,
|
||||||
serverName: "example.org",
|
serverName: "example.org",
|
||||||
role: "subscriber" as const,
|
role: "subscriber" as const,
|
||||||
matrixRTCMode: MatrixRTCMode.Matrix_2_0,
|
|
||||||
roomId,
|
roomId,
|
||||||
slotId,
|
slotId,
|
||||||
logger,
|
logger,
|
||||||
@@ -186,12 +184,24 @@ describe("getSFUConfig", () => {
|
|||||||
expect(openID.getSFUConfig).not.toHaveBeenCalled();
|
expect(openID.getSFUConfig).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses CS API when publishing with url transport", async () => {
|
||||||
|
expect(
|
||||||
|
await getSFUConfig({
|
||||||
|
...defaultParams,
|
||||||
|
transport: urlTransport,
|
||||||
|
role: "publisher",
|
||||||
|
}),
|
||||||
|
).toEqual(expect.objectContaining({ jwt: csApiJWTToken }));
|
||||||
|
expect(client._unstable_getLivekitToken).toHaveBeenCalled();
|
||||||
|
expect(openID.getSFUConfig).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it("does not fall back to OpenID when publishing", async () => {
|
it("does not fall back to OpenID when publishing", async () => {
|
||||||
client._unstable_getLivekitToken.mockRejectedValueOnce(unsupportedError);
|
client._unstable_getLivekitToken.mockRejectedValueOnce(unsupportedError);
|
||||||
await expect(
|
await expect(
|
||||||
getSFUConfig({
|
getSFUConfig({
|
||||||
...defaultParams,
|
...defaultParams,
|
||||||
transport: urlAndServiceUrlTransport,
|
transport: urlTransport,
|
||||||
role: "publisher",
|
role: "publisher",
|
||||||
}),
|
}),
|
||||||
).rejects.toThrow(expect.any(NoMatrix2AuthorizationService));
|
).rejects.toThrow(expect.any(NoMatrix2AuthorizationService));
|
||||||
@@ -199,7 +209,7 @@ describe("getSFUConfig", () => {
|
|||||||
expect(openID.getSFUConfig).not.toHaveBeenCalled();
|
expect(openID.getSFUConfig).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses OpenID when publishing in compatibility mode with url + livekit_service_url transport", async () => {
|
it("uses OpenID when publishing with url + livekit_service_url transport", async () => {
|
||||||
// Subscribers predating MSC4195 expect a legacy participant identity from
|
// Subscribers predating MSC4195 expect a legacy participant identity from
|
||||||
// anyone advertising a state event, which only the JWT service assigns
|
// anyone advertising a state event, which only the JWT service assigns
|
||||||
expect(
|
expect(
|
||||||
@@ -207,7 +217,6 @@ describe("getSFUConfig", () => {
|
|||||||
...defaultParams,
|
...defaultParams,
|
||||||
transport: urlAndServiceUrlTransport,
|
transport: urlAndServiceUrlTransport,
|
||||||
role: "publisher",
|
role: "publisher",
|
||||||
matrixRTCMode: MatrixRTCMode.Compatibility,
|
|
||||||
}),
|
}),
|
||||||
).toEqual(
|
).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -221,31 +230,6 @@ describe("getSFUConfig", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses CS API when publishing in compatibility mode with url transport", async () => {
|
|
||||||
expect(
|
|
||||||
await getSFUConfig({
|
|
||||||
...defaultParams,
|
|
||||||
transport: urlTransport,
|
|
||||||
role: "publisher",
|
|
||||||
matrixRTCMode: MatrixRTCMode.Compatibility,
|
|
||||||
}),
|
|
||||||
).toEqual(expect.objectContaining({ jwt: csApiJWTToken }));
|
|
||||||
expect(client._unstable_getLivekitToken).toHaveBeenCalled();
|
|
||||||
expect(openID.getSFUConfig).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("uses CS API when subscribing in compatibility mode with url + livekit_service_url transport", async () => {
|
|
||||||
expect(
|
|
||||||
await getSFUConfig({
|
|
||||||
...defaultParams,
|
|
||||||
transport: urlAndServiceUrlTransport,
|
|
||||||
matrixRTCMode: MatrixRTCMode.Compatibility,
|
|
||||||
}),
|
|
||||||
).toEqual(expect.objectContaining({ jwt: csApiJWTToken }));
|
|
||||||
expect(client._unstable_getLivekitToken).toHaveBeenCalled();
|
|
||||||
expect(openID.getSFUConfig).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not fall back to OpenID on connection error", async () => {
|
it("does not fall back to OpenID on connection error", async () => {
|
||||||
const client_ = {
|
const client_ = {
|
||||||
...client,
|
...client,
|
||||||
@@ -275,7 +259,6 @@ describe("delegateDelayedLeave", () => {
|
|||||||
roomId,
|
roomId,
|
||||||
slotId,
|
slotId,
|
||||||
delayId: "delay123",
|
delayId: "delay123",
|
||||||
matrixRTCMode: MatrixRTCMode.Matrix_2_0,
|
|
||||||
logger,
|
logger,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -305,21 +288,11 @@ describe("delegateDelayedLeave", () => {
|
|||||||
expect(openID.getSFUConfig).toHaveBeenCalled();
|
expect(openID.getSFUConfig).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses CS API with url + livekit_service_url transport", async () => {
|
it("uses OpenID with url + livekit_service_url transport", async () => {
|
||||||
await delegateDelayedLeave({
|
|
||||||
...defaultParams,
|
|
||||||
transport: urlAndServiceUrlTransport,
|
|
||||||
});
|
|
||||||
expect(client._unstable_delegateDelayedLeave).toHaveBeenCalled();
|
|
||||||
expect(openID.getSFUConfig).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("uses OpenID in compatibility mode with url + livekit_service_url transport", async () => {
|
|
||||||
// Must match the flow that got the token, so the identities line up
|
// Must match the flow that got the token, so the identities line up
|
||||||
await delegateDelayedLeave({
|
await delegateDelayedLeave({
|
||||||
...defaultParams,
|
...defaultParams,
|
||||||
transport: urlAndServiceUrlTransport,
|
transport: urlAndServiceUrlTransport,
|
||||||
matrixRTCMode: MatrixRTCMode.Compatibility,
|
|
||||||
});
|
});
|
||||||
expect(client._unstable_delegateDelayedLeave).not.toHaveBeenCalled();
|
expect(client._unstable_delegateDelayedLeave).not.toHaveBeenCalled();
|
||||||
expect(openID.getSFUConfig).toHaveBeenCalledWith(
|
expect(openID.getSFUConfig).toHaveBeenCalledWith(
|
||||||
@@ -330,18 +303,4 @@ describe("delegateDelayedLeave", () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not fall back to OpenID with url + livekit_service_url transport", async () => {
|
|
||||||
client._unstable_delegateDelayedLeave.mockRejectedValueOnce(
|
|
||||||
unsupportedError,
|
|
||||||
);
|
|
||||||
await expect(
|
|
||||||
delegateDelayedLeave({
|
|
||||||
...defaultParams,
|
|
||||||
transport: urlAndServiceUrlTransport,
|
|
||||||
}),
|
|
||||||
).rejects.toThrow();
|
|
||||||
expect(client._unstable_delegateDelayedLeave).toHaveBeenCalled();
|
|
||||||
expect(openID.getSFUConfig).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import * as openID from "./openID";
|
|||||||
import * as csApi from "./csApi";
|
import * as csApi from "./csApi";
|
||||||
import { type SFUConfig } from "./types";
|
import { type SFUConfig } from "./types";
|
||||||
import { NoMatrix2AuthorizationService } from "../../utils/errors";
|
import { NoMatrix2AuthorizationService } from "../../utils/errors";
|
||||||
import { MatrixRTCMode } from "../../config/ConfigOptions";
|
|
||||||
|
|
||||||
export type { ClientOpenIDParts } from "./openID";
|
export type { ClientOpenIDParts } from "./openID";
|
||||||
export type { ClientGetTokenParts, ClientDelegationParts } from "./csApi";
|
export type { ClientGetTokenParts, ClientDelegationParts } from "./csApi";
|
||||||
@@ -80,11 +79,6 @@ export interface GetSFUConfigParams {
|
|||||||
* Whether we want to publish or only subscribe on the {@link transport}.
|
* Whether we want to publish or only subscribe on the {@link transport}.
|
||||||
*/
|
*/
|
||||||
role: "publisher" | "subscriber";
|
role: "publisher" | "subscriber";
|
||||||
/**
|
|
||||||
* The MatrixRTC mode, which decides the format of our membership event and
|
|
||||||
* so the participant identity a publisher must have.
|
|
||||||
*/
|
|
||||||
matrixRTCMode: MatrixRTCMode;
|
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +93,6 @@ export async function getSFUConfig({
|
|||||||
roomId,
|
roomId,
|
||||||
slotId,
|
slotId,
|
||||||
role,
|
role,
|
||||||
matrixRTCMode,
|
|
||||||
logger,
|
logger,
|
||||||
}: GetSFUConfigParams): Promise<SFUConfig> {
|
}: GetSFUConfigParams): Promise<SFUConfig> {
|
||||||
const viaOpenID = async (serviceUrl: string): Promise<SFUConfig> =>
|
const viaOpenID = async (serviceUrl: string): Promise<SFUConfig> =>
|
||||||
@@ -113,7 +106,7 @@ export async function getSFUConfig({
|
|||||||
logger,
|
logger,
|
||||||
});
|
});
|
||||||
|
|
||||||
const flow = chooseAuthFlow(transport, role, matrixRTCMode);
|
const flow = chooseAuthFlow(transport, role);
|
||||||
if (flow.kind === "openID") return await viaOpenID(flow.serviceUrl);
|
if (flow.kind === "openID") return await viaOpenID(flow.serviceUrl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -174,10 +167,6 @@ export interface DelegateDelayedLeaveParams {
|
|||||||
* The delay ID of the leave event to be delegated.
|
* The delay ID of the leave event to be delegated.
|
||||||
*/
|
*/
|
||||||
delayId: string;
|
delayId: string;
|
||||||
/**
|
|
||||||
* The MatrixRTC mode, which decides the format of our membership event.
|
|
||||||
*/
|
|
||||||
matrixRTCMode: MatrixRTCMode;
|
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,13 +181,12 @@ export async function delegateDelayedLeave({
|
|||||||
roomId,
|
roomId,
|
||||||
slotId,
|
slotId,
|
||||||
delayId,
|
delayId,
|
||||||
matrixRTCMode,
|
|
||||||
logger,
|
logger,
|
||||||
}: DelegateDelayedLeaveParams): Promise<void> {
|
}: DelegateDelayedLeaveParams): Promise<void> {
|
||||||
// It's important that we use the same flow (CS API or OpenID) as whatever we
|
// It's important that we use the same flow (CS API or OpenID) as whatever we
|
||||||
// would've used to get a JWT token for this transport, since the participant
|
// would've used to get a JWT token for this transport, since the participant
|
||||||
// identity computed by the service needs to match.
|
// identity computed by the service needs to match.
|
||||||
const flow = chooseAuthFlow(transport, "publisher", matrixRTCMode);
|
const flow = chooseAuthFlow(transport, "publisher");
|
||||||
if (flow.kind === "csApi") {
|
if (flow.kind === "csApi") {
|
||||||
try {
|
try {
|
||||||
await csApi.delegateDelayedLeave({
|
await csApi.delegateDelayedLeave({
|
||||||
@@ -246,25 +234,19 @@ export type AuthFlow =
|
|||||||
*
|
*
|
||||||
* Only the JWT service's `/sfu/get` endpoint assigns the legacy participant
|
* Only the JWT service's `/sfu/get` endpoint assigns the legacy participant
|
||||||
* identity that clients predating MSC4195 expect from anyone advertising a
|
* identity that clients predating MSC4195 expect from anyone advertising a
|
||||||
* membership state event, which is what compatibility mode sends. So a
|
* membership state event. So a publisher keeps using the JWT service wherever
|
||||||
* publisher in compatibility mode keeps using the JWT service wherever the
|
* the transport still offers one, even if it also has a `url`. Subscribers may
|
||||||
* transport still offers one, even if it also has a `url`. Subscribers may use
|
* use the CS API regardless, as nobody matches their identity.
|
||||||
* the CS API regardless, as nobody matches their identity.
|
|
||||||
* @param transport The transport to authenticate against.
|
* @param transport The transport to authenticate against.
|
||||||
* @param role Whether we want to publish or only subscribe on the transport.
|
* @param role Whether we want to publish or only subscribe on the transport.
|
||||||
* @param matrixRTCMode The MatrixRTC mode, which decides the format of our
|
|
||||||
* membership event.
|
|
||||||
*/
|
*/
|
||||||
export function chooseAuthFlow(
|
export function chooseAuthFlow(
|
||||||
transport: UnstableLivekitTransport,
|
transport: UnstableLivekitTransport,
|
||||||
role: "publisher" | "subscriber",
|
role: "publisher" | "subscriber",
|
||||||
matrixRTCMode: MatrixRTCMode,
|
|
||||||
): AuthFlow {
|
): AuthFlow {
|
||||||
if ("url" in transport) {
|
if ("url" in transport) {
|
||||||
const useCsApi =
|
const useCsApi =
|
||||||
!("livekit_service_url" in transport) ||
|
!("livekit_service_url" in transport) || role === "subscriber";
|
||||||
role === "subscriber" ||
|
|
||||||
matrixRTCMode === MatrixRTCMode.Matrix_2_0;
|
|
||||||
if (useCsApi) return { kind: "csApi", url: transport.url };
|
if (useCsApi) return { kind: "csApi", url: transport.url };
|
||||||
}
|
}
|
||||||
return { kind: "openID", serviceUrl: transport.livekit_service_url };
|
return { kind: "openID", serviceUrl: transport.livekit_service_url };
|
||||||
|
|||||||
@@ -531,7 +531,6 @@ export const DeveloperSettingsTab: FC<Props> = ({
|
|||||||
roomId,
|
roomId,
|
||||||
slotId: "org.example.fake-slot#room",
|
slotId: "org.example.fake-slot#room",
|
||||||
role: "publisher",
|
role: "publisher",
|
||||||
matrixRTCMode: effectiveMatrixRTCMode,
|
|
||||||
logger,
|
logger,
|
||||||
});
|
});
|
||||||
setCustomLivekitUrlUpdateError(null);
|
setCustomLivekitUrlUpdateError(null);
|
||||||
@@ -542,13 +541,7 @@ export const DeveloperSettingsTab: FC<Props> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[customTransportTextBuffer, setCustomTransport, client, roomId],
|
||||||
customTransportTextBuffer,
|
|
||||||
setCustomTransport,
|
|
||||||
client,
|
|
||||||
roomId,
|
|
||||||
effectiveMatrixRTCMode,
|
|
||||||
],
|
|
||||||
)}
|
)}
|
||||||
value={customTransportTextBuffer ?? ""}
|
value={customTransportTextBuffer ?? ""}
|
||||||
onChange={useCallback(
|
onChange={useCallback(
|
||||||
|
|||||||
@@ -575,7 +575,6 @@ export function createCallViewModel$(
|
|||||||
client,
|
client,
|
||||||
matrixRoom.roomId,
|
matrixRoom.roomId,
|
||||||
matrixRTCSession.slotId,
|
matrixRTCSession.slotId,
|
||||||
matrixRTCMode,
|
|
||||||
mediaDevices,
|
mediaDevices,
|
||||||
trackProcessorState$,
|
trackProcessorState$,
|
||||||
livekitKeyProvider,
|
livekitKeyProvider,
|
||||||
@@ -666,7 +665,6 @@ export function createCallViewModel$(
|
|||||||
).pipe(map(([delayId]) => delayId ?? null)),
|
).pipe(map(([delayId]) => delayId ?? null)),
|
||||||
matrixRTCSession.delayId ?? null,
|
matrixRTCSession.delayId ?? null,
|
||||||
),
|
),
|
||||||
matrixRTCMode,
|
|
||||||
logger: logger.getChild(`[${Date.now()}]`),
|
logger: logger.getChild(`[${Date.now()}]`),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -230,7 +230,6 @@ export function withCallViewModel(mode: MatrixRTCMode) {
|
|||||||
client: room.client,
|
client: room.client,
|
||||||
roomId: room.roomId,
|
roomId: room.roomId,
|
||||||
slotId: "m.call#ROOM",
|
slotId: "m.call#ROOM",
|
||||||
matrixRTCMode: mode,
|
|
||||||
livekitRoomFactory,
|
livekitRoomFactory,
|
||||||
},
|
},
|
||||||
logger,
|
logger,
|
||||||
|
|||||||
@@ -346,27 +346,31 @@ describe("LocalMembership", () => {
|
|||||||
.mockResolvedValue();
|
.mockResolvedValue();
|
||||||
afterEach(() => delegationSpy.mockClear());
|
afterEach(() => delegationSpy.mockClear());
|
||||||
|
|
||||||
// The transport has both a `url` and a `livekit_service_url`. In Matrix 2.0
|
const urlOnlyTransport: UnstableLivekitTransport = {
|
||||||
// mode we publish through the CS API, so the homeserver delegates; in
|
type: "livekit",
|
||||||
// compatibility mode we publish through the JWT service, so that delegates.
|
url: "https://sfu.example.org",
|
||||||
|
};
|
||||||
|
|
||||||
|
// With a `url` only we publish through the CS API, so the homeserver
|
||||||
|
// delegates. With a `livekit_service_url` we publish through the JWT
|
||||||
|
// service, so that delegates.
|
||||||
it.each([
|
it.each([
|
||||||
["no", MatrixRTCMode.Compatibility, null, timings],
|
["no", mockTransport, null, timings],
|
||||||
["no", MatrixRTCMode.Matrix_2_0, null, timings],
|
|
||||||
[
|
[
|
||||||
"homeserver",
|
"homeserver",
|
||||||
MatrixRTCMode.Matrix_2_0,
|
urlOnlyTransport,
|
||||||
"https://matrix.example.org/_matrix/client/unstable/io.element.msc4195/rtc/livekit/delegate_delayed_leave",
|
"https://matrix.example.org/_matrix/client/unstable/io.element.msc4195/rtc/livekit/delegate_delayed_leave",
|
||||||
delegatedTimings,
|
delegatedTimings,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"transport",
|
"transport",
|
||||||
MatrixRTCMode.Compatibility,
|
mockTransport,
|
||||||
"https://jwt.example.org/delegate_delayed_leave",
|
"https://jwt.example.org/delegate_delayed_leave",
|
||||||
delegatedTimings,
|
delegatedTimings,
|
||||||
],
|
],
|
||||||
])(
|
])(
|
||||||
"joins session with %s delegation support in %s mode",
|
"joins session with %s delegation support",
|
||||||
async (_serviceName, matrixRTCMode, delegationUrl, delayedLeaveTimings) => {
|
async (_serviceName, transport, delegationUrl, delayedLeaveTimings) => {
|
||||||
const scope = testScope();
|
const scope = testScope();
|
||||||
const joinMatrixRTC = vi.fn();
|
const joinMatrixRTC = vi.fn();
|
||||||
const delayId$ = new BehaviorSubject<string | null>(null);
|
const delayId$ = new BehaviorSubject<string | null>(null);
|
||||||
@@ -375,15 +379,17 @@ describe("LocalMembership", () => {
|
|||||||
fetchMock.post(delegationUrl, () => ({ status: 401, body: {} }));
|
fetchMock.post(delegationUrl, () => ({ status: 401, body: {} }));
|
||||||
|
|
||||||
const connectionMap = new ConnectionMap();
|
const connectionMap = new ConnectionMap();
|
||||||
connectionMap.add(connectionTransportAConnected, []);
|
connectionMap.add(
|
||||||
|
{ ...connectionTransportAConnected, transport } as Connection,
|
||||||
|
[],
|
||||||
|
);
|
||||||
const localMembership = createLocalMembership$({
|
const localMembership = createLocalMembership$({
|
||||||
scope,
|
scope,
|
||||||
...defaultCreateLocalMemberValues,
|
...defaultCreateLocalMemberValues,
|
||||||
connectionMap$: constant(new Epoch(connectionMap)),
|
connectionMap$: constant(new Epoch(connectionMap)),
|
||||||
joinMatrixRTC,
|
joinMatrixRTC,
|
||||||
localTransport$: constant(mockTransportLocator),
|
localTransport$: constant({ transport, serverName: "example.org" }),
|
||||||
delayId$,
|
delayId$,
|
||||||
matrixRTCMode,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
localMembership.requestJoinAndPublish();
|
localMembership.requestJoinAndPublish();
|
||||||
@@ -391,7 +397,7 @@ describe("LocalMembership", () => {
|
|||||||
await flushPromises();
|
await flushPromises();
|
||||||
// Joins with timings appropriate for the level of delegation support
|
// Joins with timings appropriate for the level of delegation support
|
||||||
expect(joinMatrixRTC).toHaveBeenCalledWith(
|
expect(joinMatrixRTC).toHaveBeenCalledWith(
|
||||||
mockTransport,
|
transport,
|
||||||
delayedLeaveTimings,
|
delayedLeaveTimings,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -407,10 +413,9 @@ describe("LocalMembership", () => {
|
|||||||
expect(delegationSpy).toHaveBeenLastCalledWith({
|
expect(delegationSpy).toHaveBeenLastCalledWith({
|
||||||
client: mockedClient,
|
client: mockedClient,
|
||||||
membership: ownMemberMock,
|
membership: ownMemberMock,
|
||||||
transport: mockTransport,
|
transport,
|
||||||
roomId: "!test-room-id:example.org",
|
roomId: "!test-room-id:example.org",
|
||||||
delayId,
|
delayId,
|
||||||
matrixRTCMode,
|
|
||||||
logger: expect.anything(),
|
logger: expect.anything(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -165,8 +165,6 @@ interface Props {
|
|||||||
hostBridge: HostBridge;
|
hostBridge: HostBridge;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
delayId$: Behavior<string | null>;
|
delayId$: Behavior<string | null>;
|
||||||
/** The MatrixRTC mode, which decides the format of our membership event. */
|
|
||||||
matrixRTCMode: MatrixRTCMode;
|
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +212,6 @@ export const createLocalMembership$ = ({
|
|||||||
hostBridge,
|
hostBridge,
|
||||||
ownMembershipIdentity,
|
ownMembershipIdentity,
|
||||||
delayId$,
|
delayId$,
|
||||||
matrixRTCMode,
|
|
||||||
}: Props): {
|
}: Props): {
|
||||||
/**
|
/**
|
||||||
* This request to start audio and video tracks.
|
* This request to start audio and video tracks.
|
||||||
@@ -318,7 +315,7 @@ export const createLocalMembership$ = ({
|
|||||||
switchMap(async ({ transport }) => {
|
switchMap(async ({ transport }) => {
|
||||||
// Delegation goes through whichever service authenticates us as a
|
// Delegation goes through whichever service authenticates us as a
|
||||||
// publisher, so only that service's support counts
|
// publisher, so only that service's support counts
|
||||||
const flow = chooseAuthFlow(transport, "publisher", matrixRTCMode);
|
const flow = chooseAuthFlow(transport, "publisher");
|
||||||
const delegationSupported =
|
const delegationSupported =
|
||||||
flow.kind === "openID"
|
flow.kind === "openID"
|
||||||
? await checkDelegationSupport(
|
? await checkDelegationSupport(
|
||||||
@@ -735,7 +732,6 @@ export const createLocalMembership$ = ({
|
|||||||
slotId: matrixRTCSession.slotId,
|
slotId: matrixRTCSession.slotId,
|
||||||
roomId,
|
roomId,
|
||||||
delayId,
|
delayId,
|
||||||
matrixRTCMode,
|
|
||||||
logger,
|
logger,
|
||||||
});
|
});
|
||||||
logger.info("Delayed leave successfully delegated");
|
logger.info("Delayed leave successfully delegated");
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ import {
|
|||||||
} from "./Connection.ts";
|
} from "./Connection.ts";
|
||||||
import { ObservableScope } from "../../ObservableScope.ts";
|
import { ObservableScope } from "../../ObservableScope.ts";
|
||||||
import { FailToGetOpenIdToken } from "../../../utils/errors.ts";
|
import { FailToGetOpenIdToken } from "../../../utils/errors.ts";
|
||||||
import { MatrixRTCMode } from "../../../config/ConfigOptions.ts";
|
|
||||||
import { testJWTToken } from "../../../utils/test-fixtures.ts";
|
import { testJWTToken } from "../../../utils/test-fixtures.ts";
|
||||||
import { mockRemoteParticipant, ownMemberMock } from "../../../utils/test.ts";
|
import { mockRemoteParticipant, ownMemberMock } from "../../../utils/test.ts";
|
||||||
import {
|
import {
|
||||||
@@ -124,7 +123,6 @@ function setupRemoteConnection(): Connection {
|
|||||||
client,
|
client,
|
||||||
roomId: ROOM_ID,
|
roomId: ROOM_ID,
|
||||||
slotId: SLOT_ID,
|
slotId: SLOT_ID,
|
||||||
matrixRTCMode: MatrixRTCMode.Matrix_2_0,
|
|
||||||
role: "subscriber",
|
role: "subscriber",
|
||||||
transport,
|
transport,
|
||||||
serverName: "m.localhost",
|
serverName: "m.localhost",
|
||||||
@@ -174,7 +172,6 @@ describe("Start connection states", () => {
|
|||||||
client,
|
client,
|
||||||
roomId: ROOM_ID,
|
roomId: ROOM_ID,
|
||||||
slotId: SLOT_ID,
|
slotId: SLOT_ID,
|
||||||
matrixRTCMode: MatrixRTCMode.Matrix_2_0,
|
|
||||||
role: "subscriber",
|
role: "subscriber",
|
||||||
transport,
|
transport,
|
||||||
serverName: "m.localhost",
|
serverName: "m.localhost",
|
||||||
@@ -195,7 +192,6 @@ describe("Start connection states", () => {
|
|||||||
client,
|
client,
|
||||||
roomId: ROOM_ID,
|
roomId: ROOM_ID,
|
||||||
slotId: SLOT_ID,
|
slotId: SLOT_ID,
|
||||||
matrixRTCMode: MatrixRTCMode.Matrix_2_0,
|
|
||||||
role: "subscriber",
|
role: "subscriber",
|
||||||
transport,
|
transport,
|
||||||
serverName: "m.localhost",
|
serverName: "m.localhost",
|
||||||
@@ -251,7 +247,6 @@ describe("Start connection states", () => {
|
|||||||
client,
|
client,
|
||||||
roomId: ROOM_ID,
|
roomId: ROOM_ID,
|
||||||
slotId: SLOT_ID,
|
slotId: SLOT_ID,
|
||||||
matrixRTCMode: MatrixRTCMode.Matrix_2_0,
|
|
||||||
role: "subscriber",
|
role: "subscriber",
|
||||||
transport,
|
transport,
|
||||||
serverName: "m.localhost",
|
serverName: "m.localhost",
|
||||||
@@ -316,7 +311,6 @@ describe("Start connection states", () => {
|
|||||||
client,
|
client,
|
||||||
roomId: ROOM_ID,
|
roomId: ROOM_ID,
|
||||||
slotId: SLOT_ID,
|
slotId: SLOT_ID,
|
||||||
matrixRTCMode: MatrixRTCMode.Matrix_2_0,
|
|
||||||
role: "subscriber",
|
role: "subscriber",
|
||||||
transport,
|
transport,
|
||||||
serverName: "m.localhost",
|
serverName: "m.localhost",
|
||||||
@@ -567,7 +561,6 @@ describe("remote track logging", () => {
|
|||||||
client,
|
client,
|
||||||
roomId: ROOM_ID,
|
roomId: ROOM_ID,
|
||||||
slotId: SLOT_ID,
|
slotId: SLOT_ID,
|
||||||
matrixRTCMode: MatrixRTCMode.Matrix_2_0,
|
|
||||||
role: "subscriber",
|
role: "subscriber",
|
||||||
transport,
|
transport,
|
||||||
serverName: "m.localhost",
|
serverName: "m.localhost",
|
||||||
|
|||||||
@@ -44,15 +44,12 @@ import {
|
|||||||
type ClientOpenIDParts,
|
type ClientOpenIDParts,
|
||||||
type SFUConfig,
|
type SFUConfig,
|
||||||
} from "../../../livekit/auth";
|
} from "../../../livekit/auth";
|
||||||
import { type MatrixRTCMode } from "../../../config/ConfigOptions.ts";
|
|
||||||
|
|
||||||
export interface ConnectionOpts {
|
export interface ConnectionOpts {
|
||||||
/** The identity parts to use on this connection */
|
/** The identity parts to use on this connection */
|
||||||
ownMembershipIdentity: CallMembershipIdentityParts;
|
ownMembershipIdentity: CallMembershipIdentityParts;
|
||||||
/** Whether we want to publish or only subscribe on this connection. */
|
/** Whether we want to publish or only subscribe on this connection. */
|
||||||
role: "publisher" | "subscriber";
|
role: "publisher" | "subscriber";
|
||||||
/** The MatrixRTC mode, which decides the format of our membership event. */
|
|
||||||
matrixRTCMode: MatrixRTCMode;
|
|
||||||
/** The media transport to connect to. */
|
/** The media transport to connect to. */
|
||||||
transport: UnstableLivekitTransport;
|
transport: UnstableLivekitTransport;
|
||||||
/** The name of the homeserver to which the {@link transport} belongs. */
|
/** The name of the homeserver to which the {@link transport} belongs. */
|
||||||
@@ -141,7 +138,6 @@ export class Connection {
|
|||||||
private readonly client: ClientGetTokenParts & ClientOpenIDParts;
|
private readonly client: ClientGetTokenParts & ClientOpenIDParts;
|
||||||
private readonly roomId: string;
|
private readonly roomId: string;
|
||||||
private readonly slotId: string;
|
private readonly slotId: string;
|
||||||
private readonly matrixRTCMode: MatrixRTCMode;
|
|
||||||
private readonly logger: Logger;
|
private readonly logger: Logger;
|
||||||
private readonly ownMembershipIdentity: CallMembershipIdentityParts;
|
private readonly ownMembershipIdentity: CallMembershipIdentityParts;
|
||||||
/**
|
/**
|
||||||
@@ -155,7 +151,6 @@ export class Connection {
|
|||||||
this.ownMembershipIdentity = opts.ownMembershipIdentity;
|
this.ownMembershipIdentity = opts.ownMembershipIdentity;
|
||||||
this.roomId = opts.roomId;
|
this.roomId = opts.roomId;
|
||||||
this.slotId = opts.slotId;
|
this.slotId = opts.slotId;
|
||||||
this.matrixRTCMode = opts.matrixRTCMode;
|
|
||||||
this.logger = logger.getChild(
|
this.logger = logger.getChild(
|
||||||
`[Connection ${JSON.stringify(opts.transport)}]`,
|
`[Connection ${JSON.stringify(opts.transport)}]`,
|
||||||
);
|
);
|
||||||
@@ -399,7 +394,6 @@ export class Connection {
|
|||||||
serverName: this.serverName,
|
serverName: this.serverName,
|
||||||
roomId: this.roomId,
|
roomId: this.roomId,
|
||||||
slotId: this.slotId,
|
slotId: this.slotId,
|
||||||
matrixRTCMode: this.matrixRTCMode,
|
|
||||||
logger: this.logger,
|
logger: this.logger,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import {
|
|||||||
type ClientGetTokenParts,
|
type ClientGetTokenParts,
|
||||||
type ClientOpenIDParts,
|
type ClientOpenIDParts,
|
||||||
} from "../../../livekit/auth";
|
} from "../../../livekit/auth";
|
||||||
import { type MatrixRTCMode } from "../../../config/ConfigOptions.ts";
|
|
||||||
|
|
||||||
// TODO evaluate if this should be done like the Publisher Factory
|
// TODO evaluate if this should be done like the Publisher Factory
|
||||||
export interface ConnectionFactory {
|
export interface ConnectionFactory {
|
||||||
@@ -62,7 +61,6 @@ export class ECConnectionFactory implements ConnectionFactory {
|
|||||||
* @param client - The OpenID client parts for authentication, needed to get openID and JWT tokens.
|
* @param client - The OpenID client parts for authentication, needed to get openID and JWT tokens.
|
||||||
* @param roomId - The ID of the Matrix room in which the session takes place.
|
* @param roomId - The ID of the Matrix room in which the session takes place.
|
||||||
* @param slotId - The ID of the MatrixRTC slot in which the session takes place.
|
* @param slotId - The ID of the MatrixRTC slot in which the session takes place.
|
||||||
* @param matrixRTCMode - The MatrixRTC mode, which decides the format of our membership event.
|
|
||||||
* @param devices - Used for video/audio out/in capture options.
|
* @param devices - Used for video/audio out/in capture options.
|
||||||
* @param processorState$ - Effects like background blur (only for publishing connection?)
|
* @param processorState$ - Effects like background blur (only for publishing connection?)
|
||||||
* @param livekitKeyProvider - Optional key provider for end-to-end encryption.
|
* @param livekitKeyProvider - Optional key provider for end-to-end encryption.
|
||||||
@@ -73,7 +71,6 @@ export class ECConnectionFactory implements ConnectionFactory {
|
|||||||
private client: ClientGetTokenParts & ClientOpenIDParts,
|
private client: ClientGetTokenParts & ClientOpenIDParts,
|
||||||
private readonly roomId: string,
|
private readonly roomId: string,
|
||||||
private readonly slotId: string,
|
private readonly slotId: string,
|
||||||
private readonly matrixRTCMode: MatrixRTCMode,
|
|
||||||
private devices: MediaDevices,
|
private devices: MediaDevices,
|
||||||
private processorState$: Behavior<ProcessorState>,
|
private processorState$: Behavior<ProcessorState>,
|
||||||
livekitKeyProvider: BaseKeyProvider | undefined,
|
livekitKeyProvider: BaseKeyProvider | undefined,
|
||||||
@@ -120,7 +117,6 @@ export class ECConnectionFactory implements ConnectionFactory {
|
|||||||
{
|
{
|
||||||
roomId: this.roomId,
|
roomId: this.roomId,
|
||||||
slotId: this.slotId,
|
slotId: this.slotId,
|
||||||
matrixRTCMode: this.matrixRTCMode,
|
|
||||||
role,
|
role,
|
||||||
transport,
|
transport,
|
||||||
serverName,
|
serverName,
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import {
|
|||||||
cameraCodec,
|
cameraCodec,
|
||||||
} from "../../../settings/settings.ts";
|
} from "../../../settings/settings.ts";
|
||||||
import { testJWTToken } from "../../../utils/test-fixtures.ts";
|
import { testJWTToken } from "../../../utils/test-fixtures.ts";
|
||||||
import { MatrixRTCMode } from "../../../config/ConfigOptions.ts";
|
|
||||||
|
|
||||||
// At the top of your test file, after imports
|
// At the top of your test file, after imports
|
||||||
vi.mock("livekit-client", async (importOriginal) => {
|
vi.mock("livekit-client", async (importOriginal) => {
|
||||||
@@ -85,7 +84,6 @@ describe("ECConnectionFactory - Audio inputs options", () => {
|
|||||||
mockClient,
|
mockClient,
|
||||||
"!roomid:example.org",
|
"!roomid:example.org",
|
||||||
"m.call#ROOM",
|
"m.call#ROOM",
|
||||||
MatrixRTCMode.Matrix_2_0,
|
|
||||||
mockMediaDevices({}),
|
mockMediaDevices({}),
|
||||||
new BehaviorSubject<ProcessorState>({
|
new BehaviorSubject<ProcessorState>({
|
||||||
supported: true,
|
supported: true,
|
||||||
@@ -131,7 +129,6 @@ describe("ECConnectionFactory - ControlledAudioDevice", () => {
|
|||||||
mockClient,
|
mockClient,
|
||||||
"!roomid:example.org",
|
"!roomid:example.org",
|
||||||
"m.call#ROOM",
|
"m.call#ROOM",
|
||||||
MatrixRTCMode.Matrix_2_0,
|
|
||||||
mockMediaDevices({
|
mockMediaDevices({
|
||||||
audioOutput: {
|
audioOutput: {
|
||||||
available$: constant(new Map<never, never>()),
|
available$: constant(new Map<never, never>()),
|
||||||
@@ -176,7 +173,6 @@ describe("ECConnectionFactory - Camera quality settings", () => {
|
|||||||
mockClient,
|
mockClient,
|
||||||
"!roomid:example.org",
|
"!roomid:example.org",
|
||||||
"m.call#ROOM",
|
"m.call#ROOM",
|
||||||
MatrixRTCMode.Matrix_2_0,
|
|
||||||
mockMediaDevices({}),
|
mockMediaDevices({}),
|
||||||
new BehaviorSubject<ProcessorState>({
|
new BehaviorSubject<ProcessorState>({
|
||||||
supported: true,
|
supported: true,
|
||||||
@@ -217,7 +213,6 @@ describe("ECConnectionFactory - Camera quality settings", () => {
|
|||||||
mockClient,
|
mockClient,
|
||||||
"!roomid:example.org",
|
"!roomid:example.org",
|
||||||
"m.call#ROOM",
|
"m.call#ROOM",
|
||||||
MatrixRTCMode.Matrix_2_0,
|
|
||||||
mockMediaDevices({}),
|
mockMediaDevices({}),
|
||||||
new BehaviorSubject<ProcessorState>({
|
new BehaviorSubject<ProcessorState>({
|
||||||
supported: true,
|
supported: true,
|
||||||
@@ -259,7 +254,6 @@ describe("ECConnectionFactory - Camera quality settings", () => {
|
|||||||
mockClient,
|
mockClient,
|
||||||
"!roomid:example.org",
|
"!roomid:example.org",
|
||||||
"m.call#ROOM",
|
"m.call#ROOM",
|
||||||
MatrixRTCMode.Matrix_2_0,
|
|
||||||
mockMediaDevices({}),
|
mockMediaDevices({}),
|
||||||
new BehaviorSubject<ProcessorState>({
|
new BehaviorSubject<ProcessorState>({
|
||||||
supported: true,
|
supported: true,
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ import { createConnectionMap$ } from "./ConnectionMap.ts";
|
|||||||
import { membershipsAndTransports$ } from "../../SessionBehaviors.ts";
|
import { membershipsAndTransports$ } from "../../SessionBehaviors.ts";
|
||||||
import { localRtcMember, testJWTToken } from "../../../utils/test-fixtures.ts";
|
import { localRtcMember, testJWTToken } from "../../../utils/test-fixtures.ts";
|
||||||
import { deepCompare } from "matrix-js-sdk/lib/utils";
|
import { deepCompare } from "matrix-js-sdk/lib/utils";
|
||||||
import { MatrixRTCMode } from "../../../config/ConfigOptions.ts";
|
|
||||||
|
|
||||||
// Test the integration of ConnectionMap and MatrixLivekitMembers
|
// Test the integration of ConnectionMap and MatrixLivekitMembers
|
||||||
|
|
||||||
@@ -76,7 +75,6 @@ beforeEach(() => {
|
|||||||
mockClient,
|
mockClient,
|
||||||
"!roomid:example.org",
|
"!roomid:example.org",
|
||||||
"m.call#ROOM",
|
"m.call#ROOM",
|
||||||
MatrixRTCMode.Matrix_2_0,
|
|
||||||
mockMediaDevices({}),
|
mockMediaDevices({}),
|
||||||
new BehaviorSubject<ProcessorState>({
|
new BehaviorSubject<ProcessorState>({
|
||||||
supported: true,
|
supported: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user