68 lines
2.7 KiB
JavaScript
68 lines
2.7 KiB
JavaScript
"use strict";
|
||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||
};
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
exports.buildSocketServer = buildSocketServer;
|
||
const socket_io_1 = require("socket.io");
|
||
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
||
const env_1 = require("../../config/env");
|
||
const logger_1 = require("../../config/logger");
|
||
const dragonfly_1 = require("../cache/dragonfly");
|
||
// TTL em segundos: 70 = 2× o heartbeat do frontend (30s) + margem
|
||
const PRESENCE_TTL = 70;
|
||
function buildSocketServer(httpServer) {
|
||
const io = new socket_io_1.Server(httpServer, {
|
||
cors: {
|
||
origin: env_1.env.FRONTEND_URL,
|
||
credentials: true,
|
||
},
|
||
transports: ['websocket', 'polling'],
|
||
});
|
||
// Autenticação por token JWT no handshake
|
||
io.use((socket, next) => {
|
||
const token = socket.handshake.auth?.token;
|
||
if (!token) {
|
||
next(new Error('Token não fornecido'));
|
||
return;
|
||
}
|
||
try {
|
||
const payload = jsonwebtoken_1.default.verify(token, env_1.env.JWT_SECRET);
|
||
socket.data.userId = payload.sub;
|
||
socket.data.role = payload.role;
|
||
next();
|
||
}
|
||
catch {
|
||
next(new Error('Token inválido'));
|
||
}
|
||
});
|
||
io.on('connection', (socket) => {
|
||
const userId = socket.data.userId;
|
||
logger_1.logger.debug({ userId, socketId: socket.id }, 'Socket conectado');
|
||
// Cliente entra na sala do seu tenant automaticamente
|
||
socket.join(`tenant:${userId}`);
|
||
// Registra presença do usuário no Dragonfly com TTL
|
||
dragonfly_1.dragonfly.set(`presence:user:${userId}`, socket.id, PRESENCE_TTL).catch(() => { });
|
||
// Cliente pode entrar em salas específicas de instância ou chat
|
||
socket.on('join:instance', (instanceId) => {
|
||
socket.join(`instance:${instanceId}`);
|
||
});
|
||
socket.on('join:chat', (chatId) => {
|
||
socket.join(`chat:${chatId}`);
|
||
});
|
||
socket.on('leave:chat', (chatId) => {
|
||
socket.leave(`chat:${chatId}`);
|
||
});
|
||
// Heartbeat do frontend a cada 30s — renova TTL de presença
|
||
socket.on('user:heartbeat', () => {
|
||
dragonfly_1.dragonfly.set(`presence:user:${userId}`, socket.id, PRESENCE_TTL).catch(() => { });
|
||
});
|
||
socket.on('disconnect', (reason) => {
|
||
logger_1.logger.debug({ userId, reason }, 'Socket desconectado');
|
||
// Remove presença imediatamente ao desconectar
|
||
dragonfly_1.dragonfly.del(`presence:user:${userId}`).catch(() => { });
|
||
});
|
||
});
|
||
return io;
|
||
}
|