nakama/backend/websocket.js

157 lines
4.0 KiB
JavaScript
Raw Normal View History

2025-11-03 20:35:01 +00:00
const { Server } = require('socket.io');
const config = require('./config');
const Notification = require('./models/Notification');
2025-11-10 20:13:22 +00:00
const { isModerationAdmin, normalizeUsername } = require('./services/moderationAdmin');
const { log } = require('./middleware/logger');
2025-11-03 20:35:01 +00:00
let io = null;
2025-11-10 20:13:22 +00:00
let moderationNamespace = null;
const connectedModerators = new Map();
2025-11-03 20:35:01 +00:00
// Инициализация 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}`);
});
});
2025-11-10 20:13:22 +00:00
registerModerationChat();
2025-11-03 20:35:01 +00:00
console.log('✅ WebSocket сервер инициализирован');
return io;
}
2025-11-10 20:13:22 +00:00
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();
});
});
}
2025-11-03 20:35:01 +00:00
// Отправить уведомление пользователю в 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
};