mirror of
https://github.com/vector-im/element-call.git
synced 2026-08-17 20:39:19 +00:00
Merge branch 'livekit' into defaut-server-config
This commit is contained in:
54
src/config/Config.test.ts
Normal file
54
src/config/Config.test.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2026 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { describe, expect, it, vi, afterEach } from "vitest";
|
||||
import { logger } from "matrix-js-sdk/lib/logger";
|
||||
|
||||
import { validateConfig } from "./Config";
|
||||
import { MatrixRTCMode } from "./ConfigOptions";
|
||||
|
||||
describe("validateConfig", () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("passes through a missing matrix_rtc_mode unchanged", () => {
|
||||
const result = validateConfig({});
|
||||
expect(result.matrix_rtc_mode).toBeUndefined();
|
||||
});
|
||||
|
||||
it.each(Object.values(MatrixRTCMode))(
|
||||
"keeps a valid matrix_rtc_mode value (%s)",
|
||||
(mode) => {
|
||||
const warnSpy = vi.spyOn(logger, "warn").mockImplementation(() => {});
|
||||
const result = validateConfig({ matrix_rtc_mode: mode });
|
||||
expect(result.matrix_rtc_mode).toBe(mode);
|
||||
expect(warnSpy).not.toHaveBeenCalled();
|
||||
},
|
||||
);
|
||||
|
||||
it("drops an invalid matrix_rtc_mode value and warns", () => {
|
||||
const warnSpy = vi.spyOn(logger, "warn").mockImplementation(() => {});
|
||||
const result = validateConfig({
|
||||
// Intentionally bypass the type to simulate bad JSON.
|
||||
matrix_rtc_mode: "nonsense" as unknown as MatrixRTCMode,
|
||||
});
|
||||
expect(result.matrix_rtc_mode).toBeUndefined();
|
||||
expect(warnSpy).toHaveBeenCalledTimes(1);
|
||||
expect(warnSpy.mock.calls[0][0]).toContain("nonsense");
|
||||
});
|
||||
|
||||
it("does not touch unrelated fields when dropping an invalid mode", () => {
|
||||
vi.spyOn(logger, "warn").mockImplementation(() => {});
|
||||
const result = validateConfig({
|
||||
matrix_rtc_mode: "nope" as unknown as MatrixRTCMode,
|
||||
ssla: "https://example.invalid/ssla",
|
||||
});
|
||||
expect(result.matrix_rtc_mode).toBeUndefined();
|
||||
expect(result.ssla).toBe("https://example.invalid/ssla");
|
||||
});
|
||||
});
|
||||
@@ -6,6 +6,7 @@ Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { merge } from "lodash-es";
|
||||
import { logger } from "matrix-js-sdk/lib/logger";
|
||||
|
||||
import { getUrlParams } from "../UrlParams";
|
||||
import {
|
||||
@@ -14,6 +15,11 @@ import {
|
||||
type ResolvedConfigOptions,
|
||||
} from "./ConfigOptions";
|
||||
import { isFailure } from "../utils/fetch";
|
||||
import { MatrixRTCMode } from "./ConfigOptions";
|
||||
|
||||
const VALID_MATRIX_RTC_MODES: ReadonlySet<string> = new Set(
|
||||
Object.values(MatrixRTCMode),
|
||||
);
|
||||
|
||||
export class Config {
|
||||
private static internalInstance: Config | undefined;
|
||||
@@ -44,7 +50,11 @@ export class Config {
|
||||
|
||||
Config.internalInstance.initPromise = downloadConfig(fetchTarget).then(
|
||||
(config) => {
|
||||
internalInstance.config = merge({}, DEFAULT_CONFIG, config);
|
||||
internalInstance.config = merge(
|
||||
{},
|
||||
DEFAULT_CONFIG,
|
||||
validateConfig(config),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -84,6 +94,17 @@ export class Config {
|
||||
private initPromise?: Promise<void>;
|
||||
}
|
||||
|
||||
export function validateConfig(config: ConfigOptions): ConfigOptions {
|
||||
const mode = config.matrix_rtc_mode;
|
||||
if (mode !== undefined && !VALID_MATRIX_RTC_MODES.has(mode)) {
|
||||
logger.warn(
|
||||
`Ignoring invalid matrix_rtc_mode in config.json: ${String(mode)}`,
|
||||
);
|
||||
delete config.matrix_rtc_mode;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
async function downloadConfig(fetchTarget: string): Promise<ConfigOptions> {
|
||||
const response = await fetch(fetchTarget);
|
||||
|
||||
|
||||
@@ -1,10 +1,31 @@
|
||||
/*
|
||||
Copyright 2022-2024 New Vector Ltd.
|
||||
Copyright 2026 Element Creations Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The MatrixRTC mode determines how Element Call interacts with the
|
||||
* MatrixRTC backend and other participants. Selectable via the Developer
|
||||
* Settings, or pinned for a deployment via `matrix_rtc_mode` in config.json.
|
||||
*/
|
||||
export enum MatrixRTCMode {
|
||||
/** Legacy single-SFU + user-keyed memberships + legacy JWT endpoint. */
|
||||
Legacy = "legacy",
|
||||
/** Multi-SFU transport, legacy JWT endpoint, no sticky events. */
|
||||
Compatibility = "compatibility",
|
||||
/**
|
||||
* Multi-SFU transport with:
|
||||
* - sticky events
|
||||
* - hashed RTC backend identity
|
||||
* - the new endpoint for the jwt token on the local membership (remote memberships will always try the new jwt endpoint first -> then the legacy one)
|
||||
* - use the hashed identity for the local membership
|
||||
*/
|
||||
Matrix_2_0 = "matrix_2_0",
|
||||
}
|
||||
|
||||
export interface ConfigOptions {
|
||||
/**
|
||||
* The Posthog endpoint to which analytics data will be sent.
|
||||
@@ -14,6 +35,7 @@ export interface ConfigOptions {
|
||||
api_key: string;
|
||||
api_host: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The Sentry endpoint to which crash data will be sent.
|
||||
* This is only used in the full package of Element Call.
|
||||
@@ -22,6 +44,7 @@ export interface ConfigOptions {
|
||||
DSN: string;
|
||||
environment: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The rageshake server to which feedback and debug logs will be sent.
|
||||
* This is only used in the full package of Element Call.
|
||||
@@ -66,6 +89,7 @@ export interface ConfigOptions {
|
||||
* Allow to join group calls without audio and video.
|
||||
*/
|
||||
feature_group_calls_without_video_and_audio?: boolean;
|
||||
|
||||
/**
|
||||
* Send device-specific call session membership state events instead of
|
||||
* legacy user-specific call membership state events.
|
||||
@@ -86,6 +110,7 @@ export interface ConfigOptions {
|
||||
* Defines whether participants should start with audio enabled by default.
|
||||
*/
|
||||
enable_audio?: boolean;
|
||||
|
||||
/**
|
||||
* Defines whether participants should start with video enabled by default.
|
||||
*/
|
||||
@@ -93,12 +118,18 @@ export interface ConfigOptions {
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether upon entering a room, the user should be prompted to launch the
|
||||
* native mobile app. (Affects only Android and iOS.)
|
||||
*
|
||||
* Note that this can additionally be disabled by the app's URL parameters.
|
||||
* Grace period in milliseconds to wait before reporting the sync loop as disconnected.
|
||||
* This allows brief sync interruptions without triggering a reconnection message.
|
||||
* Default is 10000ms (10 seconds). Set to 0 to disable the grace period.
|
||||
*/
|
||||
app_prompt?: boolean;
|
||||
sync_disconnect_grace_period_ms?: number;
|
||||
|
||||
/**
|
||||
* Pins the {@link MatrixRTCMode} for all clients on this deployment,
|
||||
* overriding any per-user choice from the Developer Settings. If unset,
|
||||
* the user's Developer Settings choice (or its default of `Legacy`) wins.
|
||||
*/
|
||||
matrix_rtc_mode?: MatrixRTCMode;
|
||||
|
||||
/**
|
||||
* These are low level options that are used to configure the MatrixRTC session.
|
||||
@@ -109,41 +140,69 @@ export interface ConfigOptions {
|
||||
* How long (in milliseconds) to wait before rotating end-to-end media encryption keys
|
||||
* when someone leaves a call.
|
||||
*/
|
||||
key_rotation_on_leave_delay?: number;
|
||||
wait_for_key_rotation_ms?: number;
|
||||
|
||||
/**
|
||||
* How often (in milliseconds) keep-alive messages should be sent to the server for
|
||||
* the MatrixRTC membership event.
|
||||
* The duration (in milliseconds) after the most recent keep-alive (delayed leave event restart)
|
||||
* that the server waits before sending the leave MatrixRTC membership event.
|
||||
*/
|
||||
membership_keep_alive_period?: number;
|
||||
delayed_leave_event_delay_ms?: number;
|
||||
|
||||
/**
|
||||
* How long (in milliseconds) after the last keep-alive the server should expire the
|
||||
* MatrixRTC membership event.
|
||||
* The time (in milliseconds) after which we consider a delayed event restart http request to have failed.
|
||||
* Setting this to a lower value will result in more frequent retries but also a higher chance of failiour.
|
||||
*
|
||||
* In the presence of network packet loss (hurting TCP connections), the custom delayedEventRestartLocalTimeoutMs
|
||||
* helps by keeping more delayed event reset candidates in flight,
|
||||
* improving the chances of a successful reset. (its is equivalent to the js-sdk `localTimeout` configuration,
|
||||
* but only applies to calls to the `_unstable_updateDelayedEvent` endpoint with a body of `{action:"restart"}`.)
|
||||
*/
|
||||
membership_server_side_expiry_timeout?: number;
|
||||
delayed_leave_event_restart_local_timeout_ms?: number;
|
||||
|
||||
/**
|
||||
* The time interval (in milliseconds) at which the client sends membership keep-alive
|
||||
* messages to the server by restarting the timer for the delayed leave event.
|
||||
*/
|
||||
delayed_leave_event_restart_ms?: number;
|
||||
|
||||
/**
|
||||
* How long we wait before retrying after a network error on any of the requests.
|
||||
*/
|
||||
network_error_retry_ms?: number;
|
||||
|
||||
/**
|
||||
* The timeout (in milliseconds) after we joined the call, that our membership should expire
|
||||
* unless we have explicitly updated it.
|
||||
*
|
||||
* This is what goes into the m.rtc.member event expiry field and is typically set to a number of hours.
|
||||
*/
|
||||
membership_event_expiry_ms?: number;
|
||||
};
|
||||
}
|
||||
|
||||
// Overrides members from ConfigOptions that are always provided by the
|
||||
// default config and are therefore non-optional.
|
||||
export interface ResolvedConfigOptions extends ConfigOptions {
|
||||
sync_disconnect_grace_period_ms: number;
|
||||
ssla: string;
|
||||
media_devices: {
|
||||
enable_audio: boolean;
|
||||
enable_video: boolean;
|
||||
matrix_rtc_session: {
|
||||
wait_for_key_rotation_ms?: number;
|
||||
delayed_leave_event_delay_ms: number;
|
||||
delayed_leave_event_restart_local_timeout_ms?: number;
|
||||
delayed_leave_event_restart_ms?: number;
|
||||
network_error_retry_ms: number;
|
||||
membership_event_expiry_ms?: number;
|
||||
};
|
||||
app_prompt: boolean;
|
||||
}
|
||||
|
||||
export const DEFAULT_CONFIG: ResolvedConfigOptions = {
|
||||
features: {
|
||||
feature_use_device_session_member_events: true,
|
||||
},
|
||||
sync_disconnect_grace_period_ms: 10000,
|
||||
ssla: "https://static.element.io/legal/element-software-and-services-license-agreement-uk-1.pdf",
|
||||
media_devices: {
|
||||
enable_audio: true,
|
||||
enable_video: true,
|
||||
matrix_rtc_session: {
|
||||
delayed_leave_event_delay_ms: 10000,
|
||||
network_error_retry_ms: 1000,
|
||||
},
|
||||
app_prompt: true,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user