import crypto from 'crypto'; import { closeTunnelIfUnused } from "./tunnel.manager"; interface RoomPermissions { canControl: boolean; canManageQueue: boolean; } interface RoomUser { id: string; username: string; avatar?: string; isHost: boolean; isGuest: boolean; userId?: number; permissions?: RoomPermissions; ipAddress?: string; } interface SourceContext { animeId: string; episode: string | number; source: string; extension: string; server: string; category: string; } export interface QueueItem { uid: string; metadata: RoomMetadata; videoData: any; addedBy: string; } interface RoomMetadata { id: string; title: string; episode: number; image?: string; source?: string; malId?: number; } interface RoomData { id: string; name: string; host: RoomUser; users: Map; createdAt: number; currentVideo: { animeId?: number; episode?: number; source?: string; videoData?: any; currentTime: number; isPlaying: boolean; context?: SourceContext; } | null; password?: string; metadata?: RoomMetadata | null; exposed: boolean; publicUrl?: string; queue: QueueItem[]; bannedIPs: Set; } export const DEFAULT_GUEST_PERMISSIONS: RoomPermissions = { canControl: false, canManageQueue: false }; const rooms = new Map(); export function generateRoomId(): string { return crypto.randomBytes(8).toString('hex'); } export function createRoom(name: string, host: RoomUser, password?: string, exposed = false, publicUrl?: string): RoomData { const roomId = generateRoomId(); const room: RoomData = { id: roomId, name, host, users: new Map([[host.id, host]]), createdAt: Date.now(), currentVideo: null, password: password || undefined, metadata: null, exposed, publicUrl, queue: [], bannedIPs: new Set() // NUEVO }; rooms.set(roomId, room); return room; } export function updateUserPermissions(roomId: string, userId: string, permissions: Partial): boolean { const room = rooms.get(roomId); if (!room) return false; const user: any = room.users.get(userId); if (!user) return false; if (user.isHost) return false; user.permissions = { ...user.permissions, ...permissions }; return true; } export function banUserIP(roomId: string, ipAddress: string): boolean { const room = rooms.get(roomId); if (!room) return false; room.bannedIPs.add(ipAddress); // Remover a todos los usuarios con esa IP Array.from(room.users.values()).forEach(user => { if (user.ipAddress === ipAddress) { removeUserFromRoom(roomId, user.id); } }); return true; } export function unbanUserIP(roomId: string, ipAddress: string): boolean { const room = rooms.get(roomId); if (!room) return false; return room.bannedIPs.delete(ipAddress); } export function isIPBanned(roomId: string, ipAddress: string): boolean { const room = rooms.get(roomId); if (!room) return false; return room.bannedIPs.has(ipAddress); } export function getBannedIPs(roomId: string): string[] { const room = rooms.get(roomId); if (!room) return []; return Array.from(room.bannedIPs); } export function hasPermission(roomId: string, userId: string, permission: keyof RoomPermissions): boolean { const room = rooms.get(roomId); if (!room) return false; const user = room.users.get(userId); if (!user) return false; // El host siempre tiene todos los permisos if (user.isHost) return true; // Si no tiene permisos definidos, usar defaults const userPerms = user.permissions || DEFAULT_GUEST_PERMISSIONS; return userPerms[permission] || false; } export function getRoom(roomId: string): RoomData | null { return rooms.get(roomId) || null; } export function getAllRooms(): RoomData[] { return Array.from(rooms.values()).map(room => ({ ...room, users: room.users })); } export function addQueueItem(roomId: string, item: QueueItem): boolean { const room = rooms.get(roomId); if (!room) return false; room.queue.push(item); return true; } export function removeQueueItem(roomId: string, itemUid: string): boolean { const room = rooms.get(roomId); if (!room) return false; room.queue = room.queue.filter(i => i.uid !== itemUid); return true; } export function getNextQueueItem(roomId: string): QueueItem | undefined { const room = rooms.get(roomId); if (!room || room.queue.length === 0) return undefined; return room.queue.shift(); // Saca el primero y lo retorna } export function getAndRemoveQueueItem(roomId: string, itemUid: string): QueueItem | undefined { const room = rooms.get(roomId); if (!room) return undefined; const index = room.queue.findIndex(i => i.uid === itemUid); if (index === -1) return undefined; const [item] = room.queue.splice(index, 1); return item; } export function moveQueueItem(roomId: string, itemUid: string, direction: 'up' | 'down'): boolean { const room = rooms.get(roomId); if (!room) return false; const index = room.queue.findIndex(i => i.uid === itemUid); if (index === -1) return false; const newIndex = direction === 'up' ? index - 1 : index + 1; if (newIndex < 0 || newIndex >= room.queue.length) return false; const temp = room.queue[newIndex]; room.queue[newIndex] = room.queue[index]; room.queue[index] = temp; return true; } export function addUserToRoom(roomId: string, user: RoomUser): boolean { const room = rooms.get(roomId); if (!room) return false; room.users.set(user.id, user); return true; } export function removeUserFromRoom(roomId: string, userId: string): boolean { const room = rooms.get(roomId); if (!room) return false; room.users.delete(userId); if (room.users.size === 0) { if (room.exposed) { closeTunnelIfUnused(); } rooms.delete(roomId); return true; } if (room.host.id === userId && room.users.size > 0) { const newHost = Array.from(room.users.values())[0]; newHost.isHost = true; room.host = newHost; } return true; } export function updateRoomVideo(roomId: string, videoData: any): boolean { const room = rooms.get(roomId); if (!room) return false; room.currentVideo = { ...room.currentVideo, ...videoData }; return true; } export function deleteRoom(roomId: string): boolean { const room = rooms.get(roomId); if (!room) return false; if (room.exposed) { closeTunnelIfUnused(); } return rooms.delete(roomId); } export function verifyRoomPassword(roomId: string, password?: string): boolean { const room = rooms.get(roomId); if (!room) return false; if (!room.password) return true; if (!password) return false; return room.password === password; } export function updateRoomMetadata(roomId: string, metadata: any): boolean { const room = rooms.get(roomId); if (!room) return false; room.metadata = metadata; return true; }