From 8e25b4db291a58fd79d3dccf724a438e4f3aa16d Mon Sep 17 00:00:00 2001 From: fkwp Date: Wed, 24 Sep 2025 13:48:02 +0200 Subject: [PATCH 1/7] add config options for matrix_rtc --- synapse/config/homeserver.py | 2 ++ synapse/config/matrixrtc.py | 49 ++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 synapse/config/matrixrtc.py diff --git a/synapse/config/homeserver.py b/synapse/config/homeserver.py index 5d7089c2e6a..f46f41da319 100644 --- a/synapse/config/homeserver.py +++ b/synapse/config/homeserver.py @@ -37,6 +37,7 @@ from .key import KeyConfig from .logger import LoggingConfig from .mas import MasConfig +from .matrixrtc import MatrixRtcConfig from .metrics import MetricsConfig from .modules import ModulesConfig from .oembed import OembedConfig @@ -80,6 +81,7 @@ class HomeServerConfig(RootConfig): OembedConfig, CaptchaConfig, VoipConfig, + MatrixRtcConfig, RegistrationConfig, AccountValidityConfig, MetricsConfig, diff --git a/synapse/config/matrixrtc.py b/synapse/config/matrixrtc.py new file mode 100644 index 00000000000..2d407ee8222 --- /dev/null +++ b/synapse/config/matrixrtc.py @@ -0,0 +1,49 @@ +# +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright 2014-2016 OpenMarket Ltd +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] +# +# + +from typing import Any + +from synapse.types import JsonDict + +from ._base import Config, ConfigError + + +class MatrixRtcConfig(Config): + section = "matrix_rtc" + + def read_config( + self, config: JsonDict, allow_secrets_in_config: bool, **kwargs: Any + ) -> None: + + matrix_rtc: JsonDict = config.get("matrix_rtc", {}) + self.services = matrix_rtc.get("services", []) + + if not isinstance(self.services, list): + raise ConfigError( + "MatrixRTC endpoints needs to be an array of endpoints", + ("matrix_rtc",) + ) + + if any(("type" not in e for e in self.services)): + raise ConfigError( + "MatrixRTC endpoint is missing type", + ("matrix_rtc",) + ) From 93c297cc13052f642f128d9be523b46639e00996 Mon Sep 17 00:00:00 2001 From: fkwp Date: Wed, 24 Sep 2025 13:48:34 +0200 Subject: [PATCH 2/7] add rest client for matrix_rtc backend/services announcement --- synapse/rest/__init__.py | 2 ++ synapse/rest/client/matrixrtc.py | 59 ++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 synapse/rest/client/matrixrtc.py diff --git a/synapse/rest/__init__.py b/synapse/rest/__init__.py index a24ca098469..db3bd465425 100644 --- a/synapse/rest/__init__.py +++ b/synapse/rest/__init__.py @@ -42,6 +42,7 @@ login, login_token_request, logout, + matrixrtc, mutual_rooms, notifications, openid, @@ -89,6 +90,7 @@ presence.register_servlets, directory.register_servlets, voip.register_servlets, + matrixrtc.register_servlets, pusher.register_servlets, push_rule.register_servlets, logout.register_servlets, diff --git a/synapse/rest/client/matrixrtc.py b/synapse/rest/client/matrixrtc.py new file mode 100644 index 00000000000..ea5de8f7aeb --- /dev/null +++ b/synapse/rest/client/matrixrtc.py @@ -0,0 +1,59 @@ +# +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright 2014-2016 OpenMarket Ltd +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] +# +# + +import logging +from typing import TYPE_CHECKING, Tuple + +from synapse.http.server import HttpServer +from synapse.http.servlet import RestServlet +from synapse.http.site import SynapseRequest +from synapse.rest.client._base import client_patterns +from synapse.types import JsonDict + +if TYPE_CHECKING: + from synapse.server import HomeServer + +logger = logging.getLogger(__name__) + + +class MatrixRTCRestServlet(RestServlet): + PATTERNS = client_patterns(r"/org\.matrix\.msc4143/rtc/services$", releases=()) + CATEGORY = "Client API requests" + + def __init__(self, hs: "HomeServer"): + super().__init__() + self.hs = hs + self.auth = hs.get_auth() + + async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]: + requester = await self.auth.get_user_by_req(request) + logger.debug("hello %s", requester.user) + + services = self.hs.config.matrix_rtc.services + + if services: + return 200, {"services": services} + else: + return 200, {} + + +def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None: + MatrixRTCRestServlet(hs).register(http_server) From 6a40fb89100206f910cd4add7f3985297849ca94 Mon Sep 17 00:00:00 2001 From: fkwp Date: Wed, 24 Sep 2025 13:48:46 +0200 Subject: [PATCH 3/7] add simple test --- tests/rest/client/test_matrixrtc.py | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/rest/client/test_matrixrtc.py diff --git a/tests/rest/client/test_matrixrtc.py b/tests/rest/client/test_matrixrtc.py new file mode 100644 index 00000000000..d041a8e0f14 --- /dev/null +++ b/tests/rest/client/test_matrixrtc.py @@ -0,0 +1,55 @@ +# +# This file is licensed under the Affero General Public License (AGPL) version 3. +# +# Copyright 2014-2016 OpenMarket Ltd +# Copyright (C) 2023 New Vector, Ltd +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# See the GNU Affero General Public License for more details: +# . +# +# Originally licensed under the Apache License, Version 2.0: +# . +# +# [This file includes modifications made by New Vector Limited] +# +# + +"""Tests REST events for /rtc/endpoints path.""" + + +from synapse.rest import admin +from synapse.rest.client import login, matrixrtc, register,room + +from tests import unittest + +PATH_PREFIX = "/_matrix/client/unstable/org.matrix.msc4143" +RTC_ENDPOINT = {"type": "focusA", "required_field": "theField"} + +class MatrixRtcTestCase(unittest.HomeserverTestCase): + """Tests /rtc/endpoints REST API.""" + + servlets = [ + admin.register_servlets, + room.register_servlets, + login.register_servlets, + register.register_servlets, + matrixrtc.register_servlets + ] + + @unittest.override_config({"matrix_rtc": {"services": [RTC_ENDPOINT]}}) + def test_matrixrtc_endpoints(self) -> None: + channel = self.make_request("GET", f"{PATH_PREFIX}/rtc/services") + self.assertEqual(401, channel.code) + + self.register_user("user", "password") + tok = self.login("user", "password") + channel = self.make_request("GET", f"{PATH_PREFIX}/rtc/services", access_token=tok) + self.assertEqual(200, channel.code) + + self.assert_dict({"services": [RTC_ENDPOINT]}, channel.json_body) + From e4d6a10f7ad95eba00311887fc054c8a87a5c649 Mon Sep 17 00:00:00 2001 From: fkwp Date: Wed, 24 Sep 2025 13:49:04 +0200 Subject: [PATCH 4/7] add config documentation --- .../usage/configuration/config_documentation.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 3c401d569bb..701adcbc058 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -2575,6 +2575,23 @@ Example configuration: turn_allow_guests: false ``` --- +## MatrixRTC + +Options related to advertise MatrixRTC backend infrastructure like SFUs. + +--- +### `services` + +*(array|null)* + +Example configuration: +``` +matrix_rtc: + services: + - type: livekit + livekit_service_url: https://matrix-rtc.example.com/livekit/jwt +``` +--- ## Registration Registration can be rate-limited using the parameters in the [Ratelimiting](#ratelimiting) section of this manual. From 64f7667ed1a2fb7a62aca530140fe4e46ac9e2d8 Mon Sep 17 00:00:00 2001 From: fkwp Date: Wed, 24 Sep 2025 14:55:59 +0200 Subject: [PATCH 5/7] linting --- synapse/config/matrixrtc.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/synapse/config/matrixrtc.py b/synapse/config/matrixrtc.py index 2d407ee8222..323d970ad0d 100644 --- a/synapse/config/matrixrtc.py +++ b/synapse/config/matrixrtc.py @@ -32,18 +32,13 @@ class MatrixRtcConfig(Config): def read_config( self, config: JsonDict, allow_secrets_in_config: bool, **kwargs: Any ) -> None: - matrix_rtc: JsonDict = config.get("matrix_rtc", {}) self.services = matrix_rtc.get("services", []) if not isinstance(self.services, list): raise ConfigError( - "MatrixRTC endpoints needs to be an array of endpoints", - ("matrix_rtc",) + "MatrixRTC endpoints needs to be an array of endpoints", ("matrix_rtc",) ) if any(("type" not in e for e in self.services)): - raise ConfigError( - "MatrixRTC endpoint is missing type", - ("matrix_rtc",) - ) + raise ConfigError("MatrixRTC endpoint is missing type", ("matrix_rtc",)) From 7c3325df2bcf27f7a307fd49a8d99e2aeef0b60f Mon Sep 17 00:00:00 2001 From: fkwp Date: Wed, 24 Sep 2025 14:56:27 +0200 Subject: [PATCH 6/7] renamed services to rtc_services in the endpoint return object --- synapse/rest/client/matrixrtc.py | 2 +- tests/rest/client/test_matrixrtc.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/synapse/rest/client/matrixrtc.py b/synapse/rest/client/matrixrtc.py index ea5de8f7aeb..87cc774173e 100644 --- a/synapse/rest/client/matrixrtc.py +++ b/synapse/rest/client/matrixrtc.py @@ -50,7 +50,7 @@ async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]: services = self.hs.config.matrix_rtc.services if services: - return 200, {"services": services} + return 200, {"rtc_services": services} else: return 200, {} diff --git a/tests/rest/client/test_matrixrtc.py b/tests/rest/client/test_matrixrtc.py index d041a8e0f14..d6e35e89646 100644 --- a/tests/rest/client/test_matrixrtc.py +++ b/tests/rest/client/test_matrixrtc.py @@ -51,5 +51,5 @@ def test_matrixrtc_endpoints(self) -> None: channel = self.make_request("GET", f"{PATH_PREFIX}/rtc/services", access_token=tok) self.assertEqual(200, channel.code) - self.assert_dict({"services": [RTC_ENDPOINT]}, channel.json_body) + self.assert_dict({"rtc_services": [RTC_ENDPOINT]}, channel.json_body) From d70f0cdb0a12b153f34a53b8e1d13ca711615f73 Mon Sep 17 00:00:00 2001 From: fkwp Date: Mon, 29 Sep 2025 14:24:30 +0200 Subject: [PATCH 7/7] rename rtc/services to rtc/transports --- docs/usage/configuration/config_documentation.md | 4 ++-- synapse/config/matrixrtc.py | 15 ++++++++++----- synapse/rest/client/matrixrtc.py | 8 ++++---- tests/rest/client/test_matrixrtc.py | 10 +++++----- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 701adcbc058..6fe25d0d4c5 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -2580,14 +2580,14 @@ turn_allow_guests: false Options related to advertise MatrixRTC backend infrastructure like SFUs. --- -### `services` +### `transports` *(array|null)* Example configuration: ``` matrix_rtc: - services: + transports:: - type: livekit livekit_service_url: https://matrix-rtc.example.com/livekit/jwt ``` diff --git a/synapse/config/matrixrtc.py b/synapse/config/matrixrtc.py index 323d970ad0d..78dcd822d18 100644 --- a/synapse/config/matrixrtc.py +++ b/synapse/config/matrixrtc.py @@ -32,13 +32,18 @@ class MatrixRtcConfig(Config): def read_config( self, config: JsonDict, allow_secrets_in_config: bool, **kwargs: Any ) -> None: + matrix_rtc: JsonDict = config.get("matrix_rtc", {}) - self.services = matrix_rtc.get("services", []) + self.transports = matrix_rtc.get("transports", []) - if not isinstance(self.services, list): + if not isinstance(self.transports, list): raise ConfigError( - "MatrixRTC endpoints needs to be an array of endpoints", ("matrix_rtc",) + "MatrixRTC transports needs to be an array of transports", + ("matrix_rtc",) ) - if any(("type" not in e for e in self.services)): - raise ConfigError("MatrixRTC endpoint is missing type", ("matrix_rtc",)) + if any(("type" not in e for e in self.transports)): + raise ConfigError( + "MatrixRTC transport is missing type", + ("matrix_rtc",) + ) diff --git a/synapse/rest/client/matrixrtc.py b/synapse/rest/client/matrixrtc.py index 87cc774173e..16e7802ac8d 100644 --- a/synapse/rest/client/matrixrtc.py +++ b/synapse/rest/client/matrixrtc.py @@ -35,7 +35,7 @@ class MatrixRTCRestServlet(RestServlet): - PATTERNS = client_patterns(r"/org\.matrix\.msc4143/rtc/services$", releases=()) + PATTERNS = client_patterns(r"/org\.matrix\.msc4143/rtc/transports$", releases=()) CATEGORY = "Client API requests" def __init__(self, hs: "HomeServer"): @@ -47,10 +47,10 @@ async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]: requester = await self.auth.get_user_by_req(request) logger.debug("hello %s", requester.user) - services = self.hs.config.matrix_rtc.services + transports = self.hs.config.matrix_rtc.transports - if services: - return 200, {"rtc_services": services} + if transports: + return 200, {"rtc_transports": transports} else: return 200, {} diff --git a/tests/rest/client/test_matrixrtc.py b/tests/rest/client/test_matrixrtc.py index d6e35e89646..196639bea05 100644 --- a/tests/rest/client/test_matrixrtc.py +++ b/tests/rest/client/test_matrixrtc.py @@ -31,7 +31,7 @@ RTC_ENDPOINT = {"type": "focusA", "required_field": "theField"} class MatrixRtcTestCase(unittest.HomeserverTestCase): - """Tests /rtc/endpoints REST API.""" + """Tests /rtc/transports REST API.""" servlets = [ admin.register_servlets, @@ -41,15 +41,15 @@ class MatrixRtcTestCase(unittest.HomeserverTestCase): matrixrtc.register_servlets ] - @unittest.override_config({"matrix_rtc": {"services": [RTC_ENDPOINT]}}) + @unittest.override_config({"matrix_rtc": {"transports": [RTC_ENDPOINT]}}) def test_matrixrtc_endpoints(self) -> None: - channel = self.make_request("GET", f"{PATH_PREFIX}/rtc/services") + channel = self.make_request("GET", f"{PATH_PREFIX}/rtc/transports") self.assertEqual(401, channel.code) self.register_user("user", "password") tok = self.login("user", "password") - channel = self.make_request("GET", f"{PATH_PREFIX}/rtc/services", access_token=tok) + channel = self.make_request("GET", f"{PATH_PREFIX}/rtc/transports", access_token=tok) self.assertEqual(200, channel.code) - self.assert_dict({"rtc_services": [RTC_ENDPOINT]}, channel.json_body) + self.assert_dict({"rtc_transports": [RTC_ENDPOINT]}, channel.json_body)