/** * Socket Tracker Utility * Provides standardized socket cleanup with proper listener and timer management */ import type { Socket } from 'net'; export type SocketTracked = { cleanup: () => void; addListener: (event: E, listener: (...args: any[]) => void) => void; addTimer: (t: NodeJS.Timeout | null | undefined) => void; safeDestroy: (reason?: Error) => void; }; /** * Create a socket tracker to manage listeners and timers * Ensures proper cleanup and prevents memory leaks */ export function createSocketTracker(socket: Socket): SocketTracked { const listeners: Array<{ event: string; listener: (...args: any[]) => void }> = []; const timers: NodeJS.Timeout[] = []; let cleaned = false; const addListener = (event: string, listener: (...args: any[]) => void) => { socket.on(event, listener); listeners.push({ event, listener }); }; const addTimer = (t: NodeJS.Timeout | null | undefined) => { if (!t) return; timers.push(t); // Unref timer so it doesn't keep process alive if (typeof t.unref === 'function') { t.unref(); } }; const cleanup = () => { if (cleaned) return; cleaned = true; // Clear all tracked timers for (const t of timers) { clearTimeout(t); } timers.length = 0; // Remove all tracked listeners for (const { event, listener } of listeners) { socket.off(event, listener); } listeners.length = 0; }; const safeDestroy = (reason?: Error) => { cleanup(); if (!socket.destroyed) { socket.destroy(reason); } }; return { cleanup, addListener, addTimer, safeDestroy }; }