// WebSocket 管理模块 const jwt = require('jsonwebtoken'); const ADMINS = (process.env.ADMINS || '').split(',').map(s => s.trim()).filter(Boolean); const JWT_SECRET = process.env.JWT_SECRET || 'xiaocai-secret-2024'; const clients = new Map(); function init(wss) { wss.on('connection', (ws, req) => { console.log('✅ WebSocket 客户端已连接'); const url = new URL(req.url, 'http://localhost'); const token = url.searchParams.get('token'); if (!token) return ws.close(); let username; try { const decoded = jwt.verify(token, JWT_SECRET); username = decoded.username; } catch (e) { return ws.close(); } ws.username = username; ws.isAdmin = ADMINS.includes(username); clients.set(ws, { username, roomId: null, isAdmin: ws.isAdmin }); ws.on('message', (data) => { try { const msg = JSON.parse(data); if (msg.type === 'join') { ws.roomId = msg.roomId; clients.set(ws, { username, roomId: msg.roomId, isAdmin: ws.isAdmin }); } } catch (e) {} }); ws.on('close', () => clients.delete(ws)); }); } function broadcastToRoomExcludeSelf(roomId, excludeUsername, data) { const message = JSON.stringify(data); clients.forEach((info, ws) => { if (info.roomId === roomId && info.username !== excludeUsername && ws.readyState === 1) ws.send(message); }); } function broadcastToRoom(roomId, data) { const message = JSON.stringify(data); clients.forEach((info, ws) => { if (info.roomId === roomId && ws.readyState === 1) ws.send(message); }); } function broadcast(data) { const message = JSON.stringify(data); clients.forEach((info, ws) => { if (ws.readyState === 1) ws.send(message); }); } module.exports = { init, broadcastToRoomExcludeSelf, broadcastToRoom, broadcast };