feat: Integrar LiveKit y actualizar URLs en el panel de transmisión y API

This commit is contained in:
Cesar Mendivil 2025-11-07 15:42:53 -07:00
parent f57ce90c11
commit 396a803b1c
8 changed files with 409 additions and 387 deletions

1
package-lock.json generated
View File

@ -11875,6 +11875,7 @@
"ioredis": "^5.3.2",
"joi": "^17.11.0",
"jsonwebtoken": "^9.0.2",
"livekit-server-sdk": "^2.14.0",
"socket.io": "^4.6.2",
"stripe": "^14.9.0",
"winston": "^3.11.0"

View File

@ -25,6 +25,7 @@
"ioredis": "^5.3.2",
"joi": "^17.11.0",
"jsonwebtoken": "^9.0.2",
"livekit-server-sdk": "^2.14.0",
"socket.io": "^4.6.2",
"stripe": "^14.9.0",
"winston": "^3.11.0"

View File

@ -15,6 +15,9 @@ const allowedOrigins = process.env.FRONTEND_URLS?.split(',') || ['http://localho
if (process.env.NODE_ENV !== 'production') {
if (!allowedOrigins.includes('http://localhost:3020')) allowedOrigins.push('http://localhost:3020')
if (!allowedOrigins.includes('http://localhost:3021')) allowedOrigins.push('http://localhost:3021')
if (!allowedOrigins.includes('http://localhost:5175')) allowedOrigins.push('http://localhost:5175')
if (!allowedOrigins.includes('https://avanzacast-studio.bfzqqk.easypanel.host')) allowedOrigins.push('https://avanzacast-studio.bfzqqk.easypanel.host')
if (!allowedOrigins.includes('https://avanzacast-broadcastpanel.bfzqqk.easypanel.host')) allowedOrigins.push('https://avanzacast-broadcastpanel.bfzqqk.easypanel.host')
}
app.use(cors({
@ -44,6 +47,56 @@ app.get('/api/v1', (req, res) => {
});
});
// LiveKit token generation endpoint
app.get('/api/token', async (req, res) => {
const { room, username } = req.query;
if (!room || typeof room !== 'string') {
return res.status(400).json({ error: 'Room name is required' });
}
if (!username || typeof username !== 'string') {
return res.status(400).json({ error: 'Username is required' });
}
// TODO: Implement actual LiveKit token generation
// For now, return a placeholder response
const LIVEKIT_API_KEY = process.env.LIVEKIT_API_KEY;
const LIVEKIT_API_SECRET = process.env.LIVEKIT_API_SECRET;
if (!LIVEKIT_API_KEY || !LIVEKIT_API_SECRET) {
console.error('⚠️ LIVEKIT_API_KEY and LIVEKIT_API_SECRET must be set in environment variables');
return res.status(500).json({ error: 'LiveKit credentials not configured' });
}
try {
// Import AccessToken from livekit-server-sdk
const { AccessToken } = await import('livekit-server-sdk');
const at = new AccessToken(LIVEKIT_API_KEY, LIVEKIT_API_SECRET, {
identity: username,
name: username,
});
at.addGrant({
room,
roomJoin: true,
canPublish: true,
canSubscribe: true,
});
const token = await at.toJwt();
return res.json({
token,
url: process.env.LIVEKIT_URL || 'ws://localhost:7880',
});
} catch (error) {
console.error('Error generating LiveKit token:', error);
return res.status(500).json({ error: 'Failed to generate token' });
}
});
// Minimal LiveKit-related endpoints (placeholder implementation)
app.get('/api/v1/livekit/rooms', (req, res) => {
const roomName = typeof req.query.roomName === 'string' ? req.query.roomName : undefined;

View File

@ -15,7 +15,7 @@ const Studio: React.FC = () => {
localStorage.setItem('avanzacast_room', roomName)
// Redirigir al studio-panel (puerto 3001)
const studioUrl = `http://localhost:3001?user=${encodeURIComponent(userName)}&room=${encodeURIComponent(roomName)}`
const studioUrl = `https://avanzacast-studio.bfzqqk.easypanel.host?user=${encodeURIComponent(userName)}&room=${encodeURIComponent(roomName)}`
window.location.href = studioUrl
}, [])

View File

@ -61,7 +61,7 @@ const TransmissionsTable: React.FC<Props> = ({ transmissions, onDelete, onUpdate
console.log('[BroadcastPanel] Solicitando token:', { room: decodeURIComponent(room), user: decodeURIComponent(user) })
const TOKEN_SERVER = import.meta.env.VITE_TOKEN_SERVER_URL || 'https://avanzacast-studio.bfzqqk.easypanel.host'
const TOKEN_SERVER = import.meta.env.VITE_TOKEN_SERVER_URL || 'https://avanzacast-servertokens.bfzqqk.easypanel.host'
const tokenUrl = `${TOKEN_SERVER.replace(/\/$/, '')}/api/token?room=${room}&username=${user}`
const tokenRes = await fetch(tokenUrl)
if (!tokenRes.ok) throw new Error('No se pudo obtener token')

View File

@ -37,6 +37,11 @@ export default defineConfig({
server: {
port: 5175,
host: true,
allowedHosts: [
'localhost',
'.easypanel.host',
'avanzacast-broadcastpanel.bfzqqk.easypanel.host'
],
fs: {
// Allow serving files from the shared folder when mounted in Docker
allow: [

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
import type { LoginCredentials, RegisterData, AuthResponse, ApiResponse } from '@avanzacast/shared-types';
import { getAuthHeader } from './auth';
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:4000/api/v1';
const API_BASE_URL = import.meta.env.VITE_API_URL || 'https://avanzacast-servertokens.bfzqqk.easypanel.host/api/v1';
/**
* Cliente HTTP para hacer peticiones a la API