Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ interface ClientInfo {
}

const clients = new Map<string, ClientInfo>();
// Secondary index for O(1) lookup: clientId -> Set<socketId>
const clientIdMap = new Map<string, Set<string>>();

// Rate limiting: messages per second per client
const RATE_LIMIT_MSGS_PER_SEC = 100;
Expand Down Expand Up @@ -219,6 +221,12 @@ io.on('connection', (socket: Socket) => {
};
clients.set(socket.id, clientInfo);

// Update secondary index
if (!clientIdMap.has(clientId)) {
clientIdMap.set(clientId, new Set());
}
clientIdMap.get(clientId)!.add(socket.id);

logger.info({ clientId, socketId: socket.id, totalClients: clients.size }, 'Client connected');

// Send current queue state to newly connected client
Expand Down Expand Up @@ -259,8 +267,16 @@ io.on('connection', (socket: Socket) => {
messageStore.acknowledge(data.messageId);

// Notify the original sender (if they're connected)
const targetClient = Array.from(clients.values())
.find(c => c.clientId === data.senderId);
let targetClient: ClientInfo | undefined;
const socketIds = clientIdMap.get(data.senderId);

if (socketIds && socketIds.size > 0) {
// Get the first socket ID (preserves "first one wins" behavior)
const firstSocketId = socketIds.values().next().value;
if (firstSocketId) {
targetClient = clients.get(firstSocketId);
}
}

if (targetClient) {
targetClient.socket.emit('message:acked', { messageId: data.messageId });
Expand All @@ -286,6 +302,16 @@ io.on('connection', (socket: Socket) => {
// Handle disconnection
socket.on('disconnect', (reason) => {
logger.info({ clientId, socketId: socket.id, reason, totalClients: clients.size - 1 }, 'Client disconnected');

// Remove from secondary index
const socketIds = clientIdMap.get(clientId);
if (socketIds) {
socketIds.delete(socket.id);
if (socketIds.size === 0) {
clientIdMap.delete(clientId);
}
}

clients.delete(socket.id);
});

Expand Down Expand Up @@ -351,7 +377,7 @@ async function shutdown(signal: string) {
logger.info({ signal }, 'Shutting down server...');

// Close all client connections
for (const [socketId, client] of clients) {
for (const client of clients.values()) {
client.socket.disconnect(true);
}
clients.clear();
Expand Down
Loading