From be63993ba2841677e7405868594df455d5397e8f Mon Sep 17 00:00:00 2001 From: lebaudantoine Date: Thu, 24 Jul 2025 15:52:34 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A9=B9(frontend)=20fix=20connection=20war?= =?UTF-8?q?mup=20with=20WebSocket=20pre-authentication?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Connection warmup wasn't working properly - only works when trying to establish WebSocket first, then workaround kicks in. Call WebSocket endpoint without auth info expecting 401 error, but enough to initiate cache for subsequent WebSocket functionality. Scope this **dirty** trick to Firefox users only. Haven't figured out how to detect proxy from JS code simply. Tested in staging and works on our constrained WiFi. --- src/backend/core/api/__init__.py | 5 ++- src/backend/meet/settings.py | 5 +++ src/frontend/src/api/useConfig.ts | 1 + .../features/rooms/components/Conference.tsx | 38 +++++++++++++++---- .../dev-keycloak/values.meet.yaml.gotmpl | 1 + 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/backend/core/api/__init__.py b/src/backend/core/api/__init__.py index 05ac309d..beb0ec3b 100644 --- a/src/backend/core/api/__init__.py +++ b/src/backend/core/api/__init__.py @@ -50,7 +50,10 @@ def get_frontend_configuration(request): else None, "default_country": settings.ROOM_TELEPHONY_DEFAULT_COUNTRY, }, - "livekit": {"url": settings.LIVEKIT_CONFIGURATION["url"]}, + "livekit": { + "url": settings.LIVEKIT_CONFIGURATION["url"], + "enable_firefox_proxy_workaround": settings.LIVEKIT_ENABLE_FIREFOX_PROXY_WORKAROUND, + }, } frontend_configuration.update(settings.FRONTEND_CONFIGURATION) return Response(frontend_configuration) diff --git a/src/backend/meet/settings.py b/src/backend/meet/settings.py index b423bcf0..f3ad1648 100755 --- a/src/backend/meet/settings.py +++ b/src/backend/meet/settings.py @@ -492,6 +492,11 @@ class Base(Configuration): ), "url": values.Value(environ_name="LIVEKIT_API_URL", environ_prefix=None), } + LIVEKIT_ENABLE_FIREFOX_PROXY_WORKAROUND = values.BooleanValue( + environ_name="LIVEKIT_ENABLE_FIREFOX_PROXY_WORKAROUND", + environ_prefix=None, + default=False, + ) LIVEKIT_VERIFY_SSL = values.BooleanValue( True, environ_name="LIVEKIT_VERIFY_SSL", environ_prefix=None ) diff --git a/src/frontend/src/api/useConfig.ts b/src/frontend/src/api/useConfig.ts index 876775da..887c6223 100644 --- a/src/frontend/src/api/useConfig.ts +++ b/src/frontend/src/api/useConfig.ts @@ -39,6 +39,7 @@ export interface ApiConfig { manifest_link?: string livekit: { url: string + enable_firefox_proxy_workaround: boolean } } diff --git a/src/frontend/src/features/rooms/components/Conference.tsx b/src/frontend/src/features/rooms/components/Conference.tsx index 27c0a303..891ce2e8 100644 --- a/src/frontend/src/features/rooms/components/Conference.tsx +++ b/src/frontend/src/features/rooms/components/Conference.tsx @@ -25,6 +25,7 @@ import { navigateTo } from '@/navigation/navigateTo' import { MediaDeviceErrorAlert } from './MediaDeviceErrorAlert' import { usePostHog } from 'posthog-js/react' import { useConfig } from '@/api/useConfig' +import { isFireFox } from '@/utils/livekit' export const Conference = ({ roomId, @@ -103,17 +104,40 @@ export const Conference = ({ * This prefetch helps reduce initial connection latency by establishing * an early HTTP connection to the WebRTC signaling server * - * FIREFOX + PROXY WORKAROUND: - * On Firefox behind proxy configurations, WebSocket signaling fails to establish. - * Client receives HTTP 200 instead of expected 101 (Switching Protocols). - * This appears to be a certificate/security issue where the initial request - * is considered unsecure. By first calling the signaling server via HTTPS, - * subsequent WebSocket establishment works correctly in these setups. - * This is a workaround - issue is reproducible on LiveKit's demo app. + * It should cache DNS and TLS keys. */ const prepareConnection = async () => { if (!apiConfig || isConnectionWarmedUp) return await room.prepareConnection(apiConfig.livekit.url) + + if (isFireFox() && apiConfig.livekit.enable_firefox_proxy_workaround) { + try { + const wssUrl = + apiConfig.livekit.url + .replace('https://', 'wss://') + .replace(/\/$/, '') + '/rtc' + + /** + * FIREFOX + PROXY WORKAROUND: + * + * Issue: On Firefox behind proxy configurations, WebSocket signaling fails to establish. + * Symptom: Client receives HTTP 200 instead of expected 101 (Switching Protocols). + * Root Cause: Certificate/security issue where the initial request is considered unsecure. + * + * Solution: Pre-establish a WebSocket connection to the signaling server, which fails. + * This "primes" the connection, allowing subsequent WebSocket establishments to work correctly. + * + * Note: This issue is reproducible on LiveKit's demo app. + * Reference: livekit-examples/meet/issues/466 + */ + const ws = new WebSocket(wssUrl) + // 401 unauthorized response is expected + ws.onerror = () => ws.readyState <= 1 && ws.close() + } catch (e) { + console.debug('Firefox WebSocket workaround failed.', e) + } + } + setIsConnectionWarmedUp(true) } prepareConnection() diff --git a/src/helm/env.d/dev-keycloak/values.meet.yaml.gotmpl b/src/helm/env.d/dev-keycloak/values.meet.yaml.gotmpl index 2b0ec523..c45d4de3 100644 --- a/src/helm/env.d/dev-keycloak/values.meet.yaml.gotmpl +++ b/src/helm/env.d/dev-keycloak/values.meet.yaml.gotmpl @@ -52,6 +52,7 @@ backend: {{- end }} {{- end }} LIVEKIT_API_URL: https://livekit.127.0.0.1.nip.io/ + LIVEKIT_ENABLE_FIREFOX_PROXY_WORKAROUND: True ALLOW_UNREGISTERED_ROOMS: False FRONTEND_SILENCE_LIVEKIT_DEBUG: False FRONTEND_SUPPORT: "{'id': '58ea6697-8eba-4492-bc59-ad6562585041', 'help_article_transcript': 'https://lasuite.crisp.help/fr/article/visio-transcript-1sjq43x', 'help_article_recording': 'https://lasuite.crisp.help/fr/article/visio-enregistrement-wgc8o0', 'help_article_more_tools': 'https://lasuite.crisp.help/fr/article/visio-tools-bvxj23'}"