mirror of
https://github.com/vector-im/element-call.git
synced 2026-08-29 21:15:19 +00:00
Remove well-known discovery
This commit is contained in:
@@ -191,10 +191,24 @@ backend mxrtc_auth_backend
|
|||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> As defined in
|
> As defined in
|
||||||
> [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143),
|
> [MSC4143](https://github.com/matrix-org/matrix-spec-proposals/pull/4143),
|
||||||
> the MatrixRTC backend(s) must be announced to the client via your **Matrix site's
|
> the MatrixRTC backend(s) must be announced to the client via `/_matrix/client/unstable/org.matrix.msc4143/rtc/transports`.
|
||||||
> `.well-known/matrix/client`** file (e.g.
|
|
||||||
> `example.com/.well-known/matrix/client` matching the site deployment example
|
Enable the unstable feature flag `msc4143_enabled`, and update the synapse config file:
|
||||||
> from above). The configuration is a list of Foci configs:
|
|
||||||
|
```yaml
|
||||||
|
|
||||||
|
matrix_rtc:
|
||||||
|
- transports:
|
||||||
|
- type: livekit
|
||||||
|
livekit_service_url: https://matrix-rtc.example.com/livekit/jwt
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**⚠️ Well-known discovery will soon be deprecated, but needed if MSC4143 is not supported on your Homeserver**
|
||||||
|
|
||||||
|
your **Matrix site's .well-known/matrix/client`** file (e.g. `example.com/.well-known/matrix/client` matching the site deployment example
|
||||||
|
from above). The configuration is a list of Foci configs:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"org.matrix.msc4143.rtc_foci": [
|
"org.matrix.msc4143.rtc_foci": [
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
type MockedObject,
|
type MockedObject,
|
||||||
vi,
|
vi,
|
||||||
} from "vitest";
|
} from "vitest";
|
||||||
import { type IClientWellKnown, MatrixError } from "matrix-js-sdk";
|
import { MatrixError } from "matrix-js-sdk";
|
||||||
import { logger as rootLogger } from "matrix-js-sdk/lib/logger";
|
import { logger as rootLogger } from "matrix-js-sdk/lib/logger";
|
||||||
import {
|
import {
|
||||||
type LivekitTransportConfig,
|
type LivekitTransportConfig,
|
||||||
@@ -33,9 +33,9 @@ const backendTransport: LivekitTransportConfig = {
|
|||||||
livekit_service_url: "https://backend.example.org",
|
livekit_service_url: "https://backend.example.org",
|
||||||
};
|
};
|
||||||
|
|
||||||
const wellKnownTransport: LivekitTransportConfig = {
|
const configTransport: LivekitTransportConfig = {
|
||||||
type: "livekit",
|
type: "livekit",
|
||||||
livekit_service_url: "https://well-known.example.org",
|
livekit_service_url: "https://config.example.org",
|
||||||
};
|
};
|
||||||
|
|
||||||
function makeClient(): MockedObject<DiscoveryClient> {
|
function makeClient(): MockedObject<DiscoveryClient> {
|
||||||
@@ -59,12 +59,6 @@ function makeResolvedConfig(livekitServiceUrl?: string): ResolvedConfigOptions {
|
|||||||
} as ResolvedConfigOptions;
|
} as ResolvedConfigOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeWellKnown(rtcFoci?: Transport[]): IClientWellKnown {
|
|
||||||
return {
|
|
||||||
"org.matrix.msc4143.rtc_foci": rtcFoci,
|
|
||||||
} as unknown as IClientWellKnown;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("RtcTransportAutoDiscovery", () => {
|
describe("RtcTransportAutoDiscovery", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
@@ -75,33 +69,30 @@ describe("RtcTransportAutoDiscovery", () => {
|
|||||||
{ transports: [{ type: "not_livekit" }, backendTransport] },
|
{ transports: [{ type: "not_livekit" }, backendTransport] },
|
||||||
];
|
];
|
||||||
it.each(VALID_TEST_CASES)(
|
it.each(VALID_TEST_CASES)(
|
||||||
"prefers backend transport over well-known and app config $transports",
|
"prefers backend transport other app config $transports",
|
||||||
async ({ transports }) => {
|
async ({ transports }) => {
|
||||||
// it("prefers backend transport over well-known and app config", async () => {
|
// it("prefers backend transport over well-known and app config", async () => {
|
||||||
const client = makeClient();
|
const client = makeClient();
|
||||||
client._unstable_getRTCTransports.mockResolvedValue(transports);
|
client._unstable_getRTCTransports.mockResolvedValue(transports);
|
||||||
|
|
||||||
const wellKnownFetcher = vi
|
|
||||||
.fn<(domain: string) => Promise<IClientWellKnown>>()
|
|
||||||
.mockResolvedValue(makeWellKnown([wellKnownTransport]));
|
|
||||||
|
|
||||||
const discovery = new RtcTransportAutoDiscovery({
|
const discovery = new RtcTransportAutoDiscovery({
|
||||||
client,
|
client,
|
||||||
resolvedConfig: makeResolvedConfig("https://config.example.org"),
|
resolvedConfig: makeResolvedConfig(configTransport.livekit_service_url),
|
||||||
wellKnownFetcher,
|
|
||||||
logger: rootLogger,
|
logger: rootLogger,
|
||||||
});
|
});
|
||||||
|
|
||||||
await expect(
|
|
||||||
discovery.discoverPreferredTransport(),
|
const discoveredTransport = await discovery.discoverPreferredTransport();
|
||||||
).resolves.toStrictEqual(backendTransport);
|
|
||||||
|
expect(discoveredTransport).toStrictEqual(backendTransport);
|
||||||
|
expect(discoveredTransport).not.toStrictEqual(configTransport);
|
||||||
|
|
||||||
expect(client._unstable_getRTCTransports).toHaveBeenCalledTimes(1);
|
expect(client._unstable_getRTCTransports).toHaveBeenCalledTimes(1);
|
||||||
expect(wellKnownFetcher).not.toHaveBeenCalled();
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it("Retries limit_exceeded backend transport over well-known", async () => {
|
it("Retries limit_exceeded backend transport", async () => {
|
||||||
const client = makeClient();
|
const client = makeClient();
|
||||||
client._unstable_getRTCTransports
|
client._unstable_getRTCTransports
|
||||||
.mockRejectedValueOnce(
|
.mockRejectedValueOnce(
|
||||||
@@ -116,14 +107,10 @@ describe("RtcTransportAutoDiscovery", () => {
|
|||||||
)
|
)
|
||||||
.mockResolvedValue([backendTransport]);
|
.mockResolvedValue([backendTransport]);
|
||||||
|
|
||||||
const wellKnownFetcher = vi
|
|
||||||
.fn<(domain: string) => Promise<IClientWellKnown>>()
|
|
||||||
.mockResolvedValue(makeWellKnown([wellKnownTransport]));
|
|
||||||
|
|
||||||
const discovery = new RtcTransportAutoDiscovery({
|
const discovery = new RtcTransportAutoDiscovery({
|
||||||
client,
|
client,
|
||||||
resolvedConfig: makeResolvedConfig("https://config.example.org"),
|
resolvedConfig: makeResolvedConfig("https://config.example.org"),
|
||||||
wellKnownFetcher,
|
|
||||||
logger: rootLogger,
|
logger: rootLogger,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -132,7 +119,6 @@ describe("RtcTransportAutoDiscovery", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(client._unstable_getRTCTransports).toHaveBeenCalledTimes(2);
|
expect(client._unstable_getRTCTransports).toHaveBeenCalledTimes(2);
|
||||||
expect(wellKnownFetcher).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const INVALID_TEST_CASES: Array<{ transports: Transport[] }> = [
|
const INVALID_TEST_CASES: Array<{ transports: Transport[] }> = [
|
||||||
@@ -140,91 +126,32 @@ describe("RtcTransportAutoDiscovery", () => {
|
|||||||
{ transports: [{ type: "not_livekit" }] },
|
{ transports: [{ type: "not_livekit" }] },
|
||||||
];
|
];
|
||||||
it.each(INVALID_TEST_CASES)(
|
it.each(INVALID_TEST_CASES)(
|
||||||
"falls back to well-known when backend has no (valid) livekit transports $transports",
|
"falls back to config when backend has no (valid) livekit transports $transports",
|
||||||
async ({ transports }) => {
|
async ({ transports }) => {
|
||||||
const client = makeClient();
|
const client = makeClient();
|
||||||
client._unstable_getRTCTransports.mockResolvedValue(transports);
|
client._unstable_getRTCTransports.mockResolvedValue(transports);
|
||||||
|
|
||||||
const wellKnownFetcher = vi
|
|
||||||
.fn<(domain: string) => Promise<IClientWellKnown>>()
|
|
||||||
.mockResolvedValue(makeWellKnown([wellKnownTransport]));
|
|
||||||
|
|
||||||
const discovery = new RtcTransportAutoDiscovery({
|
const discovery = new RtcTransportAutoDiscovery({
|
||||||
client,
|
client,
|
||||||
resolvedConfig: makeResolvedConfig("https://config.example.org"),
|
resolvedConfig: makeResolvedConfig(configTransport.livekit_service_url),
|
||||||
wellKnownFetcher,
|
|
||||||
logger: rootLogger,
|
logger: rootLogger,
|
||||||
});
|
});
|
||||||
|
|
||||||
await expect(
|
const discoveredTransport = await discovery.discoverPreferredTransport();
|
||||||
discovery.discoverPreferredTransport(),
|
expect(discoveredTransport).not.toStrictEqual(backendTransport);
|
||||||
).resolves.toStrictEqual(wellKnownTransport);
|
expect(discoveredTransport).toStrictEqual(configTransport);
|
||||||
|
|
||||||
expect(wellKnownFetcher).toHaveBeenCalledWith("example.org");
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it("skips backend discovery in widget mode and uses well-known", async () => {
|
it("returns null when backend and config are all unavailable", async () => {
|
||||||
const client = makeClient();
|
|
||||||
// widget mode is detected by the absence of an access token
|
|
||||||
client.getAccessToken.mockReturnValue(null);
|
|
||||||
|
|
||||||
const wellKnownFetcher = vi
|
|
||||||
.fn<(domain: string) => Promise<IClientWellKnown>>()
|
|
||||||
.mockResolvedValue(makeWellKnown([wellKnownTransport]));
|
|
||||||
|
|
||||||
const discovery = new RtcTransportAutoDiscovery({
|
|
||||||
client,
|
|
||||||
resolvedConfig: makeResolvedConfig("https://config.example.org"),
|
|
||||||
wellKnownFetcher,
|
|
||||||
logger: rootLogger,
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(discovery.discoverPreferredTransport()).resolves.toStrictEqual(
|
|
||||||
wellKnownTransport,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(client._unstable_getRTCTransports).not.toHaveBeenCalled();
|
|
||||||
expect(wellKnownFetcher).toHaveBeenCalledWith("example.org");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("falls back to app config when backend fails and well-known has no rtc_foci", async () => {
|
|
||||||
const client = makeClient();
|
|
||||||
client._unstable_getRTCTransports.mockRejectedValue(
|
|
||||||
new MatrixError({ errcode: "M_UNKNOWN" }, 404),
|
|
||||||
);
|
|
||||||
|
|
||||||
const wellKnownFetcher = vi
|
|
||||||
.fn<(domain: string) => Promise<IClientWellKnown>>()
|
|
||||||
.mockResolvedValue({} as IClientWellKnown);
|
|
||||||
|
|
||||||
const discovery = new RtcTransportAutoDiscovery({
|
|
||||||
client,
|
|
||||||
resolvedConfig: makeResolvedConfig("https://config.example.org"),
|
|
||||||
wellKnownFetcher,
|
|
||||||
logger: rootLogger,
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(discovery.discoverPreferredTransport()).resolves.toStrictEqual(
|
|
||||||
{
|
|
||||||
type: "livekit",
|
|
||||||
livekit_service_url: "https://config.example.org",
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns null when backend, well-known and config are all unavailable", async () => {
|
|
||||||
const client = makeClient();
|
const client = makeClient();
|
||||||
client._unstable_getRTCTransports.mockResolvedValue([]);
|
client._unstable_getRTCTransports.mockResolvedValue([]);
|
||||||
|
|
||||||
const wellKnownFetcher = vi
|
|
||||||
.fn<(domain: string) => Promise<IClientWellKnown>>()
|
|
||||||
.mockResolvedValue({} as IClientWellKnown);
|
|
||||||
|
|
||||||
const discovery = new RtcTransportAutoDiscovery({
|
const discovery = new RtcTransportAutoDiscovery({
|
||||||
client,
|
client,
|
||||||
resolvedConfig: makeResolvedConfig(undefined),
|
resolvedConfig: makeResolvedConfig(undefined),
|
||||||
wellKnownFetcher,
|
|
||||||
logger: rootLogger,
|
logger: rootLogger,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
isLivekitTransportConfig,
|
isLivekitTransportConfig,
|
||||||
type LivekitTransportConfig,
|
type LivekitTransportConfig,
|
||||||
} from "matrix-js-sdk/lib/matrixrtc";
|
} from "matrix-js-sdk/lib/matrixrtc";
|
||||||
import { type IClientWellKnown, type MatrixClient } from "matrix-js-sdk";
|
import { type MatrixClient } from "matrix-js-sdk";
|
||||||
import { type Logger } from "matrix-js-sdk/lib/logger";
|
import { type Logger } from "matrix-js-sdk/lib/logger";
|
||||||
|
|
||||||
import type { ResolvedConfigOptions } from "../../../config/ConfigOptions.ts";
|
import type { ResolvedConfigOptions } from "../../../config/ConfigOptions.ts";
|
||||||
@@ -22,27 +22,21 @@ type TransportDiscoveryClient = Pick<
|
|||||||
export interface RtcTransportAutoDiscoveryProps {
|
export interface RtcTransportAutoDiscoveryProps {
|
||||||
client: TransportDiscoveryClient;
|
client: TransportDiscoveryClient;
|
||||||
resolvedConfig: ResolvedConfigOptions;
|
resolvedConfig: ResolvedConfigOptions;
|
||||||
wellKnownFetcher: (domain: string) => Promise<IClientWellKnown>;
|
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RtcTransportAutoDiscovery {
|
export class RtcTransportAutoDiscovery {
|
||||||
private readonly client: TransportDiscoveryClient;
|
private readonly client: TransportDiscoveryClient;
|
||||||
private readonly resolvedConfig: ResolvedConfigOptions;
|
private readonly resolvedConfig: ResolvedConfigOptions;
|
||||||
private readonly wellKnownFetcher: (
|
|
||||||
domain: string,
|
|
||||||
) => Promise<IClientWellKnown>;
|
|
||||||
private readonly logger: Logger;
|
private readonly logger: Logger;
|
||||||
|
|
||||||
public constructor({
|
public constructor({
|
||||||
client,
|
client,
|
||||||
resolvedConfig,
|
resolvedConfig,
|
||||||
wellKnownFetcher,
|
|
||||||
logger,
|
logger,
|
||||||
}: RtcTransportAutoDiscoveryProps) {
|
}: RtcTransportAutoDiscoveryProps) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.resolvedConfig = resolvedConfig;
|
this.resolvedConfig = resolvedConfig;
|
||||||
this.wellKnownFetcher = wellKnownFetcher;
|
|
||||||
this.logger = logger.getChild("[RtcTransportAutoDiscovery]");
|
this.logger = logger.getChild("[RtcTransportAutoDiscovery]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,21 +50,7 @@ export class RtcTransportAutoDiscovery {
|
|||||||
return backendTransport;
|
return backendTransport;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.info("No backend transport found, falling back to well-known");
|
// 2) app config URL
|
||||||
// 2) .well-known transports
|
|
||||||
const wellKnownTransport = await this.tryWellKnownTransports();
|
|
||||||
if (wellKnownTransport) {
|
|
||||||
this.logger.info(
|
|
||||||
`Found .well-known transport: ${wellKnownTransport.livekit_service_url}`,
|
|
||||||
);
|
|
||||||
return wellKnownTransport;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.info(
|
|
||||||
"No .well-known transport found, falling back to app config",
|
|
||||||
);
|
|
||||||
|
|
||||||
// 3) app config URL
|
|
||||||
const configTransport = this.tryConfigTransport();
|
const configTransport = this.tryConfigTransport();
|
||||||
if (configTransport) {
|
if (configTransport) {
|
||||||
this.logger.info(
|
this.logger.info(
|
||||||
@@ -110,44 +90,6 @@ export class RtcTransportAutoDiscovery {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the first rtc_foci from the .well-known/matrix/client.
|
|
||||||
* This will not throw errors, but instead just log them and return null if the expected config is not found or malformed.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
private async tryWellKnownTransports(): Promise<LivekitTransportConfig | null> {
|
|
||||||
// Legacy MSC4143 (to be removed) WELL_KNOWN: Prioritize the .well-known/matrix/client, if available.
|
|
||||||
const client = this.client;
|
|
||||||
const domain = client.getDomain();
|
|
||||||
if (domain) {
|
|
||||||
// we use AutoDiscovery instead of relying on the MatrixClient having already
|
|
||||||
// been fully configured and started
|
|
||||||
|
|
||||||
const wellKnownFoci = await this.wellKnownFetcher(domain);
|
|
||||||
|
|
||||||
const fociConfig = wellKnownFoci["org.matrix.msc4143.rtc_foci"];
|
|
||||||
if (fociConfig) {
|
|
||||||
if (!Array.isArray(fociConfig)) {
|
|
||||||
this.logger.warn(
|
|
||||||
`org.matrix.msc4143.rtc_foci is not an array in .well-known`,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return fociConfig[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.logger.info(
|
|
||||||
`No .well-known "org.matrix.msc4143.rtc_foci" found for ${domain}`,
|
|
||||||
wellKnownFoci,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Should never happen, but just in case
|
|
||||||
this.logger.warn(`No domain configured for client`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private tryConfigTransport(): LivekitTransportConfig | null {
|
private tryConfigTransport(): LivekitTransportConfig | null {
|
||||||
const url = this.resolvedConfig.livekit?.livekit_service_url;
|
const url = this.resolvedConfig.livekit?.livekit_service_url;
|
||||||
if (url) {
|
if (url) {
|
||||||
|
|||||||
Reference in New Issue
Block a user