117 lines
4.2 KiB
TypeScript
117 lines
4.2 KiB
TypeScript
import { Server } from 'socket.io';
|
|
|
|
let io: Server | null = null;
|
|
|
|
// Track online users per request: { requestId: Set<userId> }
|
|
const onlineUsersPerRequest = new Map<string, Set<string>>();
|
|
|
|
export function initSocket(httpServer: any) {
|
|
const defaultOrigins = [
|
|
'http://localhost:3000',
|
|
'http://127.0.0.1:3000',
|
|
'http://localhost:5173',
|
|
'http://127.0.0.1:5173'
|
|
];
|
|
const configured = (process.env.FRONTEND_ORIGIN || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
const origins = configured.length ? configured : defaultOrigins;
|
|
|
|
io = new Server(httpServer, {
|
|
cors: {
|
|
origin: origins,
|
|
methods: ['GET', 'POST'],
|
|
credentials: true
|
|
},
|
|
path: '/socket.io',
|
|
transports: ['websocket', 'polling']
|
|
});
|
|
|
|
io.on('connection', (socket: any) => {
|
|
let currentRequestId: string | null = null;
|
|
let currentUserId: string | null = null;
|
|
|
|
// Join user's personal notification room
|
|
socket.on('join:user', (data: { userId: string }) => {
|
|
const userId = typeof data === 'string' ? data : data.userId;
|
|
socket.join(`user:${userId}`);
|
|
currentUserId = userId;
|
|
console.log(`[Socket] User ${userId} joined personal notification room`);
|
|
});
|
|
|
|
socket.on('join:request', (data: { requestId: string; userId?: string }) => {
|
|
const requestId = typeof data === 'string' ? data : data.requestId;
|
|
const userId = typeof data === 'object' ? data.userId : null;
|
|
|
|
socket.join(`request:${requestId}`);
|
|
currentRequestId = requestId;
|
|
currentUserId = userId || null;
|
|
|
|
if (userId) {
|
|
// Track this user as online for this request
|
|
if (!onlineUsersPerRequest.has(requestId)) {
|
|
onlineUsersPerRequest.set(requestId, new Set());
|
|
}
|
|
onlineUsersPerRequest.get(requestId)!.add(userId);
|
|
|
|
const onlineUsers = Array.from(onlineUsersPerRequest.get(requestId) || []);
|
|
|
|
// Broadcast presence to others in the room
|
|
socket.to(`request:${requestId}`).emit('presence:join', { userId, requestId });
|
|
|
|
// Send current online users to the newly joined socket
|
|
socket.emit('presence:online', { requestId, userIds: onlineUsers });
|
|
}
|
|
});
|
|
|
|
// Handle request for current online users (when component loads after join)
|
|
socket.on('request:online-users', (data: { requestId: string }) => {
|
|
const requestId = typeof data === 'string' ? data : data.requestId;
|
|
const onlineUsers = Array.from(onlineUsersPerRequest.get(requestId) || []);
|
|
socket.emit('presence:online', { requestId, userIds: onlineUsers });
|
|
});
|
|
|
|
socket.on('leave:request', (requestId: string) => {
|
|
socket.leave(`request:${requestId}`);
|
|
|
|
if (currentUserId && onlineUsersPerRequest.has(requestId)) {
|
|
onlineUsersPerRequest.get(requestId)!.delete(currentUserId);
|
|
if (onlineUsersPerRequest.get(requestId)!.size === 0) {
|
|
onlineUsersPerRequest.delete(requestId);
|
|
}
|
|
// Broadcast leave to others
|
|
socket.to(`request:${requestId}`).emit('presence:leave', { userId: currentUserId, requestId });
|
|
}
|
|
|
|
if (requestId === currentRequestId) {
|
|
currentRequestId = null;
|
|
currentUserId = null;
|
|
}
|
|
});
|
|
|
|
socket.on('disconnect', () => {
|
|
// Handle user going offline when connection drops
|
|
if (currentRequestId && currentUserId && onlineUsersPerRequest.has(currentRequestId)) {
|
|
onlineUsersPerRequest.get(currentRequestId)!.delete(currentUserId);
|
|
if (onlineUsersPerRequest.get(currentRequestId)!.size === 0) {
|
|
onlineUsersPerRequest.delete(currentRequestId);
|
|
}
|
|
// Broadcast disconnect to others in the room
|
|
socket.to(`request:${currentRequestId}`).emit('presence:leave', { userId: currentUserId, requestId: currentRequestId });
|
|
}
|
|
});
|
|
});
|
|
return io;
|
|
}
|
|
|
|
export function emitToRequestRoom(requestId: string, event: string, payload: any) {
|
|
if (!io) return;
|
|
io.to(`request:${requestId}`).emit(event, payload);
|
|
}
|
|
|
|
export function emitToUser(userId: string, event: string, payload: any) {
|
|
if (!io) return;
|
|
io.to(`user:${userId}`).emit(event, payload);
|
|
console.log(`[Socket] Emitted '${event}' to user ${userId}`);
|
|
}
|
|
|
|
|