From 71454e31d1f1e3da449a80892586d9d9cf55668c Mon Sep 17 00:00:00 2001 From: Bas van den Aakster Date: Sun, 7 Dec 2025 11:26:44 +0100 Subject: [PATCH] Add WebRTC configuration settings UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a settings modal with dropdown to select from preset RTC configurations or provide custom JSON config: - IPv4 TURN (Recommended): Uses explicit IPv4 addresses to avoid DNS resolution issues and address type mismatches - Hostname TURNS (TLS): Uses secure TURNS on port 5349 with hostname - Google STUN Only: Minimal config for testing direct connections - Force TURN Relay: Testing mode that forces relay usage - Custom Configuration: Users can paste their own RTCConfiguration JSON Settings are persisted in localStorage and applied to all new connections and service exposures. This allows users to test different configurations without rebuilding and helps diagnose connection issues. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/App.jsx | 300 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 281 insertions(+), 19 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 876bf17..5c0bf56 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -4,22 +4,72 @@ import toast, { Toaster } from 'react-hot-toast'; const API_URL = 'https://api.ronde.vu'; -const RTC_CONFIG = { - iceServers: [ - { urls: ["stun:stun.share.fish:3478"] }, - { - urls: [ - // TURNS (secure) - TLS/DTLS on port 5349 - "turns:turn.share.fish:5349?transport=tcp", - "turns:turn.share.fish:5349?transport=udp", - // TURN (fallback) - plain on port 3478 - "turn:turn.share.fish:3478?transport=tcp", - "turn:turn.share.fish:3478?transport=udp", +// Preset RTC configurations +const RTC_PRESETS = { + 'ipv4-turn': { + name: 'IPv4 TURN (Recommended)', + config: { + iceServers: [ + { urls: ["stun:57.129.61.67:3478"] }, + { + urls: [ + "turn:57.129.61.67:3478?transport=tcp", + "turn:57.129.61.67:3478?transport=udp", + ], + username: "webrtcuser", + credential: "supersecretpassword" + } ], - username: "webrtcuser", - credential: "supersecretpassword" } - ], + }, + 'hostname-turns': { + name: 'Hostname TURNS (TLS)', + config: { + iceServers: [ + { urls: ["stun:turn.share.fish:3478"] }, + { + urls: [ + "turns:turn.share.fish:5349?transport=tcp", + "turns:turn.share.fish:5349?transport=udp", + "turn:turn.share.fish:3478?transport=tcp", + "turn:turn.share.fish:3478?transport=udp", + ], + username: "webrtcuser", + credential: "supersecretpassword" + } + ], + } + }, + 'google-stun': { + name: 'Google STUN Only', + config: { + iceServers: [ + { urls: 'stun:stun.l.google.com:19302' }, + { urls: 'stun:stun1.l.google.com:19302' } + ] + } + }, + 'relay-only': { + name: 'Force TURN Relay (Testing)', + config: { + iceServers: [ + { urls: ["stun:57.129.61.67:3478"] }, + { + urls: [ + "turn:57.129.61.67:3478?transport=tcp", + "turn:57.129.61.67:3478?transport=udp", + ], + username: "webrtcuser", + credential: "supersecretpassword" + } + ], + iceTransportPolicy: 'relay' + } + }, + 'custom': { + name: 'Custom Configuration', + config: null // Will be loaded from user input + } }; export default function App() { @@ -45,6 +95,48 @@ export default function App() { const [serviceHandle, setServiceHandle] = useState(null); const chatEndRef = useRef(null); + // Settings + const [showSettings, setShowSettings] = useState(false); + const [rtcPreset, setRtcPreset] = useState('ipv4-turn'); + const [customRtcConfig, setCustomRtcConfig] = useState(''); + + // Get current RTC configuration + const getCurrentRtcConfig = () => { + if (rtcPreset === 'custom') { + try { + return JSON.parse(customRtcConfig); + } catch (err) { + console.error('Invalid custom RTC config:', err); + return RTC_PRESETS['ipv4-turn'].config; + } + } + return RTC_PRESETS[rtcPreset]?.config || RTC_PRESETS['ipv4-turn'].config; + }; + + // Load saved settings + useEffect(() => { + const savedPreset = localStorage.getItem('rondevu-rtc-preset'); + const savedCustomConfig = localStorage.getItem('rondevu-rtc-custom'); + + if (savedPreset) { + setRtcPreset(savedPreset); + } + if (savedCustomConfig) { + setCustomRtcConfig(savedCustomConfig); + } + }, []); + + // Save settings when they change + useEffect(() => { + localStorage.setItem('rondevu-rtc-preset', rtcPreset); + }, [rtcPreset]); + + useEffect(() => { + if (customRtcConfig) { + localStorage.setItem('rondevu-rtc-custom', customRtcConfig); + } + }, [customRtcConfig]); + // Load saved data and auto-register useEffect(() => { const savedCreds = localStorage.getItem('rondevu-chat-credentials'); @@ -194,7 +286,7 @@ export default function App() { ttl: 300000, // 5 minutes - service auto-refreshes ttlRefreshMargin: 0.2, // Refresh at 80% of TTL poolSize: 10, // Support up to 10 simultaneous connections - rtcConfig: RTC_CONFIG, + rtcConfig: getCurrentRtcConfig(), handler: (channel, connectionId) => { console.log(`📡 New chat connection: ${connectionId}`); @@ -334,7 +426,7 @@ export default function App() { // Create durable connection const connection = await client.connect(contact, 'chat.rondevu@1.0.0', { - rtcConfig: RTC_CONFIG, + rtcConfig: getCurrentRtcConfig(), maxReconnectAttempts: 5 }); @@ -491,6 +583,67 @@ export default function App() {
+ {/* Settings Modal */} + {showSettings && ( +
setShowSettings(false)}> +
e.stopPropagation()}> +

WebRTC Configuration

+ +
+ + +
+ + {rtcPreset === 'custom' && ( +
+ +