import { supabase } from '@/integrations/supabase/client'; import type { RealtimeChannel } from '@supabase/supabase-js'; export type SignalMessage = | { type: 'viewer-join'; viewerId: string } | { type: 'viewer-leave'; viewerId: string } | { type: 'offer'; viewerId: string; sdp: RTCSessionDescriptionInit } | { type: 'answer'; viewerId: string; sdp: RTCSessionDescriptionInit } | { type: 'ice'; viewerId: string; from: 'broadcaster' | 'viewer'; candidate: RTCIceCandidateInit }; const readyChannels = new WeakMap>(); export function joinSignalingChannel( code: string, onMessage: (msg: SignalMessage) => void, ): RealtimeChannel { let resolveReady!: () => void; let rejectReady!: (error: Error) => void; const ready = new Promise((resolve, reject) => { resolveReady = resolve; rejectReady = reject; }); const channel = supabase.channel(`share:${code}`, { config: { broadcast: { self: false, ack: false } }, }); readyChannels.set(channel, ready); channel .on('broadcast', { event: 'signal' }, ({ payload }) => onMessage(payload as SignalMessage)) .subscribe((status, err) => { if (status === 'SUBSCRIBED') resolveReady(); if (status === 'CHANNEL_ERROR' || status === 'TIMED_OUT' || status === 'CLOSED') { rejectReady(err instanceof Error ? err : new Error(`Canal de sinalização: ${status}`)); } }); return channel; } export async function waitForSignalingReady(channel: RealtimeChannel, timeoutMs = 5000) { const ready = readyChannels.get(channel); if (!ready) return; await Promise.race([ ready, new Promise((_, reject) => { window.setTimeout(() => reject(new Error('Tempo esgotado ao conectar sinalização')), timeoutMs); }), ]); } export async function sendSignal(channel: RealtimeChannel, msg: SignalMessage) { await waitForSignalingReady(channel); const response = await channel.send({ type: 'broadcast', event: 'signal', payload: msg }); if (response !== 'ok') { const restResponse = await channel.httpSend('signal', msg); if (!restResponse.success) throw new Error(restResponse.error); } } export function generateRoomCode(): string { const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // unambiguous let out = ''; for (let i = 0; i < 6; i++) out += chars[Math.floor(Math.random() * chars.length)]; return out; } export const ICE_SERVERS: RTCIceServer[] = [ { urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun1.l.google.com:19302' }, ];