feat(webrtc): integrate Cloudflare TURN/STUN servers
- Add backend endpoint to fetch ICE server credentials from Cloudflare - Implement dynamic ICE server configuration in frontend - Add fallback to public STUN servers when Cloudflare unavailable - Create comprehensive test suite for WebRTC API endpoint - Update environment configuration with Cloudflare TURN credentials Backend changes: - New route: GET /api/webrtc/ice-servers (authenticated) - Fetches temporary credentials from Cloudflare API with 24h TTL - Returns formatted ICE servers for RTCPeerConnection - Graceful fallback to Google STUN servers on errors Frontend changes: - Remove hardcoded ICE servers from useWebRTC hook - Fetch ICE servers dynamically from backend on mount - Store servers in ref for peer connection initialization - Add webrtcAPI service for backend communication Tests: - 9 comprehensive tests covering all scenarios - 100% coverage for webrtc.js route - Tests authentication, success, and all fallback scenarios
This commit is contained in:
@@ -1,33 +1,13 @@
|
||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { getSocket } from '../services/socket';
|
||||
import { CONNECTION_STATE } from '../constants';
|
||||
import { webrtcAPI } from '../services/api';
|
||||
|
||||
// WebRTC configuration with STUN and TURN servers for NAT traversal
|
||||
const rtcConfig = {
|
||||
iceServers: [
|
||||
// STUN servers for basic NAT traversal
|
||||
{ urls: 'stun:stun.l.google.com:19302' },
|
||||
{ urls: 'stun:stun1.l.google.com:19302' },
|
||||
{ urls: 'stun:stun2.l.google.com:19302' },
|
||||
|
||||
// TURN servers for symmetric NAT and strict firewalls (public relay for testing)
|
||||
{
|
||||
urls: 'turn:openrelay.metered.ca:80',
|
||||
username: 'openrelayproject',
|
||||
credential: 'openrelayproject',
|
||||
},
|
||||
{
|
||||
urls: 'turn:openrelay.metered.ca:443',
|
||||
username: 'openrelayproject',
|
||||
credential: 'openrelayproject',
|
||||
},
|
||||
{
|
||||
urls: 'turn:openrelay.metered.ca:443?transport=tcp',
|
||||
username: 'openrelayproject',
|
||||
credential: 'openrelayproject',
|
||||
},
|
||||
],
|
||||
};
|
||||
// Default fallback ICE servers (used if backend request fails)
|
||||
const DEFAULT_ICE_SERVERS = [
|
||||
{ urls: 'stun:stun.l.google.com:19302' },
|
||||
{ urls: 'stun:stun1.l.google.com:19302' },
|
||||
];
|
||||
|
||||
// File chunk size (16KB recommended for WebRTC DataChannel)
|
||||
const CHUNK_SIZE = 16384;
|
||||
@@ -50,6 +30,7 @@ export const useWebRTC = (matchId, userId) => {
|
||||
const socketRef = useRef(null);
|
||||
const matchIdRef = useRef(matchId);
|
||||
const userIdRef = useRef(userId);
|
||||
const iceServersRef = useRef(null);
|
||||
|
||||
// Update refs when props change
|
||||
useEffect(() => {
|
||||
@@ -57,6 +38,27 @@ export const useWebRTC = (matchId, userId) => {
|
||||
userIdRef.current = userId;
|
||||
}, [matchId, userId]);
|
||||
|
||||
// Fetch ICE servers from backend on mount
|
||||
useEffect(() => {
|
||||
const fetchIceServers = async () => {
|
||||
try {
|
||||
const response = await webrtcAPI.getIceServers();
|
||||
if (response.success && response.iceServers) {
|
||||
iceServersRef.current = response.iceServers;
|
||||
console.log('✅ Fetched ICE servers from backend:', response.iceServers.length, 'servers');
|
||||
} else {
|
||||
console.warn('⚠️ Using default ICE servers (backend response invalid)');
|
||||
iceServersRef.current = DEFAULT_ICE_SERVERS;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to fetch ICE servers, using defaults:', error);
|
||||
iceServersRef.current = DEFAULT_ICE_SERVERS;
|
||||
}
|
||||
};
|
||||
|
||||
fetchIceServers();
|
||||
}, []);
|
||||
|
||||
// File transfer state
|
||||
const fileTransferRef = useRef({
|
||||
file: null,
|
||||
@@ -80,10 +82,13 @@ export const useWebRTC = (matchId, userId) => {
|
||||
return peerConnectionRef.current;
|
||||
}
|
||||
|
||||
// Use full config with STUN servers for production
|
||||
// Use ICE servers from backend or fallback to defaults
|
||||
const iceServers = iceServersRef.current || DEFAULT_ICE_SERVERS;
|
||||
const rtcConfig = { iceServers };
|
||||
|
||||
const pc = new RTCPeerConnection(rtcConfig);
|
||||
peerConnectionRef.current = pc;
|
||||
console.log('🔧 Using rtcConfig with STUN servers for NAT traversal');
|
||||
console.log('🔧 Using ICE servers for NAT traversal:', iceServers.length, 'servers');
|
||||
|
||||
// ICE candidate handler
|
||||
pc.onicecandidate = (event) => {
|
||||
|
||||
Reference in New Issue
Block a user