From 937c4c4b2f5ae0fa6ab4471697382bd9c2727a7c Mon Sep 17 00:00:00 2001 From: antoine lebaud Date: Wed, 10 Jul 2024 21:16:07 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7(frontend)=20pass=20dynamically=20t?= =?UTF-8?q?he=20LiveKit=20url?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems appropriate that backend owns the responsability of knowing any information/configurations of the LiveKit server. Then, it shares those with the frontend. Please see my previous commit to understand why environment variables are not appropriate for deployment in several remove environments. As of today, the LiveKit server URL is the only configuration exposed dynamically to the frontend. Thus, it doesn't justify adding a new route to the API, responsible for exposing configurations (e.g. /configuration). As the frontend needs to call the backend when it wants to initiate a new webconference room, let's pass the server URL when retrieving the room's token. It is relevant, to get both the room location and the keys to open the room in the same call. I prefered to be pragmatic, if the need appears any soon, I would refactor these parts. --- env.d/development/common.dist | 1 + src/backend/core/api/serializers.py | 2 + src/backend/core/api/viewsets.py | 1 + .../tests/rooms/test_api_rooms_retrieve.py | 48 +++++++++++++++++++ src/backend/meet/settings.py | 1 + src/frontend/.env.development | 1 - src/frontend/src/api/ApiRoom.ts | 1 + src/frontend/src/routes/Conference.tsx | 4 +- src/frontend/src/vite-env.d.ts | 1 - src/helm/env.d/dev/values.meet.yaml.gotmpl | 2 +- 10 files changed, 57 insertions(+), 5 deletions(-) diff --git a/env.d/development/common.dist b/env.d/development/common.dist index f591ed7e..42ca6092 100644 --- a/env.d/development/common.dist +++ b/env.d/development/common.dist @@ -43,3 +43,4 @@ OIDC_AUTH_REQUEST_EXTRA_PARAMS={"acr_values": "eidas1"} # Livekit Token settings LIVEKIT_API_SECRET="secret" LIVEKIT_API_KEY="devkey" +LIVEKIT_API_URL=http://localhost:7880 diff --git a/src/backend/core/api/serializers.py b/src/backend/core/api/serializers.py index 9e822388..525f2873 100644 --- a/src/backend/core/api/serializers.py +++ b/src/backend/core/api/serializers.py @@ -1,4 +1,5 @@ """Client serializers for the Meet core app.""" +from django.conf import settings from django.utils.translation import gettext_lazy as _ from rest_framework import serializers @@ -122,6 +123,7 @@ class RoomSerializer(serializers.ModelSerializer): slug = f"{instance.id!s}".replace("-", "") output["livekit"] = { + "url": settings.LIVEKIT_CONFIGURATION["url"], "room": slug, "token": utils.generate_token(room=slug, user=request.user), } diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py index 3c8e5f96..add59be3 100644 --- a/src/backend/core/api/viewsets.py +++ b/src/backend/core/api/viewsets.py @@ -191,6 +191,7 @@ class RoomViewSet( data = { "id": None, "livekit": { + "url": settings.LIVEKIT_CONFIGURATION["url"], "room": slug, "token": utils.generate_token(room=slug, user=request.user), }, diff --git a/src/backend/core/tests/rooms/test_api_rooms_retrieve.py b/src/backend/core/tests/rooms/test_api_rooms_retrieve.py index 8c5b5d9e..6e21c86d 100644 --- a/src/backend/core/tests/rooms/test_api_rooms_retrieve.py +++ b/src/backend/core/tests/rooms/test_api_rooms_retrieve.py @@ -85,6 +85,13 @@ def test_api_rooms_retrieve_anonymous_private_slug_not_normalized(): @override_settings(ALLOW_UNREGISTERED_ROOMS=True) +@override_settings( + LIVEKIT_CONFIGURATION={ + "api_key": "key", + "api_secret": "secret", + "url": "test_url_value", + } +) @mock.patch("core.utils.generate_token", return_value="foo") def test_api_rooms_retrieve_anonymous_unregistered_allowed(mock_token): """ @@ -98,6 +105,7 @@ def test_api_rooms_retrieve_anonymous_unregistered_allowed(mock_token): assert response.json() == { "id": None, "livekit": { + "url": "test_url_value", "room": "unregistered-room", "token": "foo", }, @@ -107,6 +115,13 @@ def test_api_rooms_retrieve_anonymous_unregistered_allowed(mock_token): @override_settings(ALLOW_UNREGISTERED_ROOMS=True) +@override_settings( + LIVEKIT_CONFIGURATION={ + "api_key": "key", + "api_secret": "secret", + "url": "test_url_value", + } +) @mock.patch("core.utils.generate_token", return_value="foo") def test_api_rooms_retrieve_anonymous_unregistered_allowed_not_normalized(mock_token): """ @@ -120,6 +135,7 @@ def test_api_rooms_retrieve_anonymous_unregistered_allowed_not_normalized(mock_t assert response.json() == { "id": None, "livekit": { + "url": "test_url_value", "room": "reunion", "token": "foo", }, @@ -141,6 +157,13 @@ def test_api_rooms_retrieve_anonymous_unregistered_not_allowed(): @mock.patch("core.utils.generate_token", return_value="foo") +@override_settings( + LIVEKIT_CONFIGURATION={ + "api_key": "key", + "api_secret": "secret", + "url": "test_url_value", + } +) def test_api_rooms_retrieve_anonymous_public(mock_token): """ Anonymous users should be able to retrieve a room with a token provided it is public. @@ -156,6 +179,7 @@ def test_api_rooms_retrieve_anonymous_public(mock_token): "is_administrable": False, "is_public": True, "livekit": { + "url": "test_url_value", "room": expected_name, "token": "foo", }, @@ -167,6 +191,13 @@ def test_api_rooms_retrieve_anonymous_public(mock_token): @mock.patch("core.utils.generate_token", return_value="foo") +@override_settings( + LIVEKIT_CONFIGURATION={ + "api_key": "key", + "api_secret": "secret", + "url": "test_url_value", + } +) def test_api_rooms_retrieve_authenticated_public(mock_token): """ Authenticated users should be allowed to retrieve a room and get a token for a room to @@ -190,6 +221,7 @@ def test_api_rooms_retrieve_authenticated_public(mock_token): "is_administrable": False, "is_public": True, "livekit": { + "url": "test_url_value", "room": expected_name, "token": "foo", }, @@ -226,6 +258,13 @@ def test_api_rooms_retrieve_authenticated(): @mock.patch("core.utils.generate_token", return_value="foo") +@override_settings( + LIVEKIT_CONFIGURATION={ + "api_key": "key", + "api_secret": "secret", + "url": "test_url_value", + } +) def test_api_rooms_retrieve_members(mock_token, django_assert_num_queries): """ Users who are members of a room should be allowed to see related users. @@ -280,6 +319,7 @@ def test_api_rooms_retrieve_members(mock_token, django_assert_num_queries): "is_administrable": False, "is_public": room.is_public, "livekit": { + "url": "test_url_value", "room": expected_name, "token": "foo", }, @@ -291,6 +331,13 @@ def test_api_rooms_retrieve_members(mock_token, django_assert_num_queries): @mock.patch("core.utils.generate_token", return_value="foo") +@override_settings( + LIVEKIT_CONFIGURATION={ + "api_key": "key", + "api_secret": "secret", + "url": "test_url_value", + } +) def test_api_rooms_retrieve_administrators(mock_token, django_assert_num_queries): """ A user who is an administrator or owner of a room should be allowed @@ -345,6 +392,7 @@ def test_api_rooms_retrieve_administrators(mock_token, django_assert_num_queries "is_public": room.is_public, "configuration": {}, "livekit": { + "url": "test_url_value", "room": expected_name, "token": "foo", }, diff --git a/src/backend/meet/settings.py b/src/backend/meet/settings.py index 94582f68..f0328164 100755 --- a/src/backend/meet/settings.py +++ b/src/backend/meet/settings.py @@ -372,6 +372,7 @@ class Base(Configuration): "api_secret": values.Value( environ_name="LIVEKIT_API_SECRET", environ_prefix=None ), + "url": values.Value(environ_name="LIVEKIT_API_URL", environ_prefix=None), } DEFAULT_ROOM_IS_PUBLIC = values.BooleanValue( True, environ_name="DEFAULT_ROOM_IS_PUBLIC", environ_prefix=None diff --git a/src/frontend/.env.development b/src/frontend/.env.development index 520d2fb3..a22395f9 100644 --- a/src/frontend/.env.development +++ b/src/frontend/.env.development @@ -1,2 +1 @@ VITE_API_BASE_URL=http://localhost:8071/ -VITE_LIVEKIT_SERVER_URL=http://localhost:7880 diff --git a/src/frontend/src/api/ApiRoom.ts b/src/frontend/src/api/ApiRoom.ts index 548cb726..37137e57 100644 --- a/src/frontend/src/api/ApiRoom.ts +++ b/src/frontend/src/api/ApiRoom.ts @@ -4,6 +4,7 @@ export type ApiRoom = { slug: string is_public: boolean livekit?: { + url: string room: string token: string } diff --git a/src/frontend/src/routes/Conference.tsx b/src/frontend/src/routes/Conference.tsx index 4facd50f..ab45cb8a 100644 --- a/src/frontend/src/routes/Conference.tsx +++ b/src/frontend/src/routes/Conference.tsx @@ -54,11 +54,11 @@ export const Conference = () => { return } - if (data?.livekit?.token) { + if (data?.livekit?.token && data?.livekit?.url) { return ( interface ImportMetaEnv { readonly VITE_API_BASE_URL: string - readonly VITE_LIVEKIT_SERVER_URL: string } interface ImportMeta { diff --git a/src/helm/env.d/dev/values.meet.yaml.gotmpl b/src/helm/env.d/dev/values.meet.yaml.gotmpl index e4a8417f..144271fb 100644 --- a/src/helm/env.d/dev/values.meet.yaml.gotmpl +++ b/src/helm/env.d/dev/values.meet.yaml.gotmpl @@ -49,6 +49,7 @@ backend: LIVEKIT_API_KEY: {{ $key }} {{- end }} {{- end }} + LIVEKIT_API_URL: https://livekit.127.0.0.1.nip.io/ migrate: @@ -80,7 +81,6 @@ frontend: VITE_PORT: 8080 VITE_HOST: 0.0.0.0 VITE_API_BASE_URL: https://meet.127.0.0.1.nip.io/ - VITE_LIVEKIT_SERVER_URL: https://livekit.127.0.0.1.nip.io/ replicas: 1