Files
wallabicher/web/backend/services/websocket.js
2026-01-20 18:15:49 +01:00

117 lines
3.3 KiB
JavaScript

import { WebSocketServer } from 'ws';
import { getDB, getSession, getUser, deleteSession as deleteSessionFromDB } from './mongodb.js';
let wss = null;
// Duración de la sesión en milisegundos (24 horas)
const SESSION_DURATION = 24 * 60 * 60 * 1000;
// Inicializar WebSocket Server
export function initWebSocket(server) {
wss = new WebSocketServer({ server, path: '/ws' });
wss.on('connection', async (ws, req) => {
// Extraer token de los query parameters
const url = new URL(req.url, `http://${req.headers.host}`);
const token = url.searchParams.get('token');
if (!token) {
console.log('Intento de conexión WebSocket sin token');
ws.close(1008, 'Token requerido');
return;
}
// Validar token
try {
const db = getDB();
if (!db) {
console.error('MongoDB no disponible para validar WebSocket');
ws.close(1011, 'Servicio no disponible');
return;
}
// Verificar token en MongoDB
const session = await getSession(token);
if (!session) {
console.log('Intento de conexión WebSocket con token inválido');
ws.close(1008, 'Token inválido');
return;
}
// Verificar que la sesión no haya expirado
if (session.expiresAt && new Date(session.expiresAt) < new Date()) {
await deleteSessionFromDB(token);
console.log('Intento de conexión WebSocket con sesión expirada');
ws.close(1008, 'Sesión expirada');
return;
}
// Verificar que el usuario aún existe
const user = await getUser(session.username);
if (!user) {
// Eliminar sesión si el usuario ya no existe
await deleteSessionFromDB(token);
console.log('Intento de conexión WebSocket con usuario inexistente');
ws.close(1008, 'Usuario no encontrado');
return;
}
// Actualizar expiración de la sesión (refresh)
const sessionsCollection = db.collection('sessions');
const newExpiresAt = new Date(Date.now() + SESSION_DURATION);
await sessionsCollection.updateOne(
{ token },
{ $set: { expiresAt: newExpiresAt } }
);
// Autenticación exitosa - almacenar información del usuario en el websocket
ws.user = {
username: session.username,
role: user.role || 'user',
token: token
};
console.log(`Cliente WebSocket conectado: ${session.username} (${user.role || 'user'})`);
} catch (error) {
console.error('Error validando token WebSocket:', error);
ws.close(1011, 'Error de autenticación');
return;
}
ws.on('close', () => {
if (ws.user) {
console.log(`Cliente WebSocket desconectado: ${ws.user.username}`);
} else {
console.log('Cliente WebSocket desconectado');
}
});
ws.on('error', (error) => {
console.error('Error WebSocket:', error);
});
});
return wss;
}
// Broadcast a todos los clientes WebSocket
export function broadcast(data) {
if (!wss) return;
wss.clients.forEach((client) => {
if (client.readyState === 1) { // WebSocket.OPEN
client.send(JSON.stringify(data));
}
});
}
// Obtener instancia del WebSocket Server
export function getWebSocketServer() {
return wss;
}