import { Router } from 'express'; import { checkSocialEnabled } from './social.middleware'; import { requireRole } from '../../middleware/rbac.middleware'; import { SOCIAL_ROLES } from '../../utils/roles'; import { sseService } from './sse.service'; import { presenceService } from './presence.service'; const MAX_SSE_CONNECTIONS_PER_USER = 5; const router = Router(); router.use(checkSocialEnabled); /** GET /api/social/sse — establish SSE connection */ router.get('/', (req, res) => { const userId = req.user!.id; // Enforce per-user connection limit to prevent resource exhaustion const existingCount = sseService.getConnectionCountForUser?.(userId) ?? 0; if (existingCount >= MAX_SSE_CONNECTIONS_PER_USER) { res.status(429).json({ error: { message: 'Too many SSE connections', code: 'TOO_MANY_CONNECTIONS' } }); return; } // Set SSE headers res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'X-Accel-Buffering': 'no', // Disable nginx buffering }); // Send initial connection event res.write(`event: connected\ndata: ${JSON.stringify({ userId })}\n\n`); // Register client const connectionId = sseService.addClient(userId, res); // Set user as online presenceService.setOnline(userId).catch(() => {}); // Handle client disconnect req.on('close', () => { sseService.removeClient(connectionId); // Only set offline if no more connections for this user if (!sseService.isConnected(userId)) { presenceService.setOffline(userId).catch(() => {}); } }); }); /** GET /api/social/sse/online-friends — get currently online friends */ router.get('/online-friends', async (req, res, next) => { try { const friends = await presenceService.getOnlineFriends(req.user!.id); res.json({ friends }); } catch (err) { next(err); } }); /** GET /api/social/sse/status — SSE service status (admin only) */ router.get('/status', requireRole(...SOCIAL_ROLES), (_req, res) => { res.json({ connections: sseService.getConnectionCount(), connectedUsers: sseService.getConnectedUserIds().length, }); }); export const sseRouter = router;