const { Server } = require('socket.io'); const config = require('./config'); const Notification = require('./models/Notification'); const { isModerationAdmin, normalizeUsername } = require('./services/moderationAdmin'); const { log } = require('./middleware/logger'); let io = null; let moderationNamespace = null; const connectedModerators = new Map(); // Инициализация WebSocket сервера function initWebSocket(server) { const corsOrigin = config.corsOrigin === '*' ? '*' : config.corsOrigin.split(','); io = new Server(server, { cors: { origin: corsOrigin, methods: ['GET', 'POST'], credentials: true }, transports: ['websocket', 'polling'], // Поддержка обоих транспортов pingTimeout: 60000, pingInterval: 25000 }); io.on('connection', (socket) => { console.log(`✅ WebSocket подключен: ${socket.id}`); // Присоединиться к комнате пользователя socket.on('join', (userId) => { socket.join(`user_${userId}`); console.log(`Пользователь ${userId} присоединился к комнате`); }); // Отключение socket.on('disconnect', () => { console.log(`❌ WebSocket отключен: ${socket.id}`); }); }); registerModerationChat(); console.log('✅ WebSocket сервер инициализирован'); return io; } function registerModerationChat() { if (!io || moderationNamespace) { return; } moderationNamespace = io.of('/mod-chat'); const broadcastOnline = () => { const unique = Array.from( new Map( Array.from(connectedModerators.values()).map((value) => [value.username, value]) ).values() ); moderationNamespace.emit('online', unique); }; moderationNamespace.on('connection', (socket) => { socket.data.authorized = false; socket.on('auth', async (payload = {}) => { const username = normalizeUsername(payload.username); const telegramId = payload.telegramId; if (!username || !telegramId) { socket.emit('unauthorized'); return socket.disconnect(true); } const allowed = await isModerationAdmin({ username, telegramId }); if (!allowed) { socket.emit('unauthorized'); return socket.disconnect(true); } socket.data.authorized = true; socket.data.username = username; socket.data.telegramId = telegramId; connectedModerators.set(socket.id, { username, telegramId }); socket.emit('ready'); broadcastOnline(); }); socket.on('message', (payload = {}) => { if (!socket.data.authorized) { return; } const text = (payload.text || '').trim(); if (!text) { return; } const message = { id: `${Date.now()}-${Math.round(Math.random() * 1e6)}`, username: socket.data.username, telegramId: socket.data.telegramId, text, createdAt: new Date().toISOString() }; moderationNamespace.emit('message', message); }); socket.on('disconnect', () => { connectedModerators.delete(socket.id); broadcastOnline(); }); }); } // Отправить уведомление пользователю в real-time function sendNotification(userId, notification) { if (io) { io.to(`user_${userId}`).emit('notification', notification); } } // Отправить обновление поста function sendPostUpdate(postId, data) { if (io) { io.emit('post_update', { postId, ...data }); } } // Отправить новый комментарий function sendNewComment(postId, comment) { if (io) { io.emit('new_comment', { postId, comment }); } } // Отправить информацию о том, кто онлайн function broadcastOnlineUsers(users) { if (io) { io.emit('online_users', users); } } module.exports = { initWebSocket, sendNotification, sendPostUpdate, sendNewComment, broadcastOnlineUsers };