| |
| |
| |
| export const autoStartNgrok = async (): Promise<{ success: boolean; url?: string; error?: string }> => { |
| try { |
| console.log('🚀 Attempting to auto-start ngrok...'); |
| |
| |
| const existingUrl = await detectNgrokUrl(); |
| if (existingUrl) { |
| console.log('✅ ngrok already running:', existingUrl); |
| return { success: true, url: existingUrl }; |
| } |
| |
| |
| const response = await fetch('http://localhost:8000/start-ngrok', { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ port: 8080 }) |
| }); |
| |
| if (response.ok) { |
| const data = await response.json(); |
| if (data.success && data.url) { |
| console.log('✅ ngrok started successfully:', data.url); |
| return { success: true, url: data.url }; |
| } |
| } |
| |
| |
| await new Promise(resolve => setTimeout(resolve, 2000)); |
| const newUrl = await detectNgrokUrl(); |
| if (newUrl) { |
| console.log('✅ ngrok detected after waiting:', newUrl); |
| return { success: true, url: newUrl }; |
| } |
| |
| return { |
| success: false, |
| error: 'Could not start ngrok automatically. Please run: ngrok http 8080' |
| }; |
| |
| } catch (error) { |
| console.error('❌ Error auto-starting ngrok:', error); |
| return { |
| success: false, |
| error: 'Failed to start ngrok. Please run manually: ngrok http 8080' |
| }; |
| } |
| }; |
|
|
| |
| |
| |
| const detectNgrokUrl = async (): Promise<string | null> => { |
| try { |
| |
| const response = await fetch('http://localhost:4040/api/tunnels'); |
| if (response.ok) { |
| const data = await response.json(); |
| const tunnel = data.tunnels?.find((t: { config?: { addr?: string }; public_url?: string }) => |
| t.config?.addr === 'http://localhost:8080' && t.public_url?.startsWith('https://') |
| ); |
| if (tunnel?.public_url) { |
| console.log('🔗 Detected ngrok HTTPS tunnel:', tunnel.public_url); |
| return tunnel.public_url; |
| } |
| } |
| } catch (error) { |
| |
| console.log('📡 No ngrok tunnel detected'); |
| } |
| return null; |
| }; |
|
|
| |
| |
| |
| export const getAccessibleFrontendAddress = async (): Promise<string> => { |
| |
| if (window.location.protocol === 'https:') { |
| return window.location.origin; |
| } |
| |
| |
| const ngrokUrl = await detectNgrokUrl(); |
| if (ngrokUrl) { |
| return ngrokUrl; |
| } |
| |
| const currentHostname = window.location.hostname; |
| const currentPort = window.location.port; |
| const currentProtocol = window.location.protocol; |
| |
| |
| if (currentHostname !== 'localhost' && currentHostname !== '127.0.0.1') { |
| return `${currentProtocol}//${currentHostname}${currentPort ? `:${currentPort}` : ''}`; |
| } |
| |
| |
| const localIP = await detectLocalNetworkIP(); |
| if (localIP) { |
| return `${currentProtocol}//${localIP}${currentPort ? `:${currentPort}` : ''}`; |
| } |
| |
| |
| return window.location.origin; |
| }; |
|
|
| |
| |
| |
| export const detectLocalNetworkIP = (): Promise<string | null> => { |
| return new Promise((resolve) => { |
| |
| const pc = new RTCPeerConnection({ |
| iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] |
| }); |
| |
| let resolved = false; |
| |
| pc.onicecandidate = (event) => { |
| if (event.candidate && !resolved) { |
| const candidate = event.candidate.candidate; |
| |
| const ipMatch = candidate.match(/(\d+\.\d+\.\d+\.\d+)/); |
| if (ipMatch) { |
| const ip = ipMatch[1]; |
| |
| if (ip.startsWith('192.168.') || ip.startsWith('10.') || |
| (ip.startsWith('172.') && parseInt(ip.split('.')[1]) >= 16 && parseInt(ip.split('.')[1]) <= 31)) { |
| resolved = true; |
| pc.close(); |
| resolve(ip); |
| } |
| } |
| } |
| }; |
| |
| |
| pc.createDataChannel('ip-detection'); |
| pc.createOffer().then(offer => pc.setLocalDescription(offer)); |
| |
| |
| setTimeout(() => { |
| if (!resolved) { |
| pc.close(); |
| resolve(null); |
| } |
| }, 3000); |
| }); |
| }; |
|
|
| |
| |
| |
| export const generatePhoneCameraQR = async (webrtcId: string): Promise<string> => { |
| try { |
| |
| const baseUrl = await getAccessibleFrontendAddress(); |
| const phoneUrl = `${baseUrl}/remote_cam/${webrtcId}`; |
| console.log('📱 Generated phone camera URL:', phoneUrl); |
| return phoneUrl; |
| } catch (error) { |
| console.error('Error generating phone camera QR:', error); |
| |
| return `http://localhost:8080/remote_cam/${webrtcId}`; |
| } |
| }; |
|
|
| |
| |
| |
| export const generateWebRTCId = (): string => { |
| return `phone_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; |
| }; |
|
|