@iflow-mcp/ejmockler-brutalist
Version:
Deploy Claude, Codex & Gemini CLI agents to demolish your work before users do. Real file analysis. Brutal honesty. Now with conversation continuation & intelligent pagination.
321 lines • 11.6 kB
JavaScript
import { EventEmitter } from 'events';
import { logger } from '../logger.js';
/**
* Enhanced Server-Sent Events transport with session isolation
*
* Features:
* - Session-scoped connections with isolation guarantees
* - Connection pooling with resource limits
* - Heartbeat monitoring and automatic cleanup
* - Graceful connection management
* - Event filtering and routing by session
* - Memory-efficient streaming with backpressure
*/
export class EnhancedSSETransport extends EventEmitter {
connections = new Map();
sessionManager;
heartbeatInterval = null;
// Configuration constants
MAX_CONNECTIONS = 100;
HEARTBEAT_INTERVAL = 30000; // 30 seconds
CONNECTION_TIMEOUT = 300000; // 5 minutes
MAX_EVENTS_PER_CONNECTION = 10000;
constructor(sessionManager) {
super();
this.sessionManager = sessionManager;
this.startHeartbeat();
// Handle session events
this.sessionManager.on('streamingEvent', this.handleSessionEvent.bind(this));
this.sessionManager.on('sessionComplete', this.handleSessionComplete.bind(this));
}
/**
* Establish SSE connection for a session
*/
async connect(req, res, sessionId) {
const connectionId = `${sessionId}-${Date.now()}`;
const clientOrigin = req.headers.origin || 'unknown';
// Validate session exists
if (!this.sessionManager.hasSession(sessionId)) {
res.status(404).json({ error: 'Session not found' });
return;
}
// Check connection limits
if (this.connections.size >= this.MAX_CONNECTIONS) {
logger.warn(`🚫 SSE connection limit reached (${this.MAX_CONNECTIONS})`);
res.status(503).json({ error: 'Connection limit reached' });
return;
}
// Set SSE headers
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': clientOrigin,
'Access-Control-Allow-Credentials': 'true'
});
// Send initial connection event
this.sendEvent(res, {
type: 'connection',
data: {
connectionId,
sessionId,
connectedAt: Date.now()
}
});
// Create connection record
const connection = {
id: connectionId,
sessionId,
response: res,
clientOrigin,
connectedAt: Date.now(),
lastActivity: Date.now(),
eventsSent: 0,
isActive: true
};
this.connections.set(connectionId, connection);
logger.info(`🔗 SSE connection established: ${connectionId} for session ${sessionId}`);
// Handle client disconnect
req.on('close', () => {
this.disconnect(connectionId, 'client_disconnect');
});
req.on('error', (error) => {
logger.error(`💥 SSE connection error for ${connectionId}:`, error);
this.disconnect(connectionId, 'connection_error');
});
// Send buffered events for this session
this.sendBufferedEvents(connection);
}
/**
* Handle streaming events from session manager
*/
handleSessionEvent(event) {
if (!event.sessionId) {
logger.warn('⚠️ Received streaming event without session ID');
return;
}
// Find connections for this session
const sessionConnections = Array.from(this.connections.values())
.filter(conn => conn.sessionId === event.sessionId && conn.isActive);
if (sessionConnections.length === 0) {
logger.debug(`📭 No active SSE connections for session ${event.sessionId}`);
return;
}
// Send event to all session connections
for (const connection of sessionConnections) {
this.sendStreamingEvent(connection, event);
}
}
/**
* Handle session completion
*/
handleSessionComplete(sessionId) {
logger.info(`🏁 Session ${sessionId} completed, closing SSE connections`);
const sessionConnections = Array.from(this.connections.values())
.filter(conn => conn.sessionId === sessionId);
for (const connection of sessionConnections) {
this.sendEvent(connection.response, {
type: 'session_complete',
data: {
sessionId,
completedAt: Date.now()
}
});
this.disconnect(connection.id, 'session_complete');
}
}
/**
* Send streaming event to specific connection
*/
sendStreamingEvent(connection, event) {
if (!connection.isActive) {
return;
}
// Check event limit
if (connection.eventsSent >= this.MAX_EVENTS_PER_CONNECTION) {
logger.warn(`📊 Connection ${connection.id} reached event limit`);
this.disconnect(connection.id, 'event_limit_reached');
return;
}
try {
this.sendEvent(connection.response, {
type: 'streaming_event',
data: event
});
connection.eventsSent++;
connection.lastActivity = Date.now();
}
catch (error) {
logger.error(`💥 Failed to send event to ${connection.id}:`, error);
this.disconnect(connection.id, 'send_error');
}
}
/**
* Send buffered events for a newly connected session
*/
sendBufferedEvents(connection) {
const sessionContext = this.sessionManager.getSession(connection.sessionId);
if (!sessionContext) {
return;
}
const bufferedEvents = sessionContext.eventBuffer.flush(connection.sessionId);
if (bufferedEvents && bufferedEvents.events.length > 0) {
logger.info(`📤 Sending ${bufferedEvents.events.length} buffered events to ${connection.id}`);
for (const event of bufferedEvents.events) {
this.sendStreamingEvent(connection, event);
}
}
}
/**
* Send raw SSE event
*/
sendEvent(res, event) {
const eventId = Date.now().toString();
const eventData = JSON.stringify(event.data);
res.write(`id: ${eventId}\n`);
res.write(`event: ${event.type}\n`);
res.write(`data: ${eventData}\n\n`);
}
/**
* Disconnect and cleanup SSE connection
*/
disconnect(connectionId, reason) {
const connection = this.connections.get(connectionId);
if (!connection) {
return;
}
logger.info(`🔌 Disconnecting SSE ${connectionId}: ${reason}`);
connection.isActive = false;
try {
if (!connection.response.destroyed) {
this.sendEvent(connection.response, {
type: 'disconnect',
data: {
reason,
disconnectedAt: Date.now(),
eventsSent: connection.eventsSent
}
});
connection.response.end();
}
}
catch (error) {
logger.debug(`Failed to send disconnect event: ${error}`);
}
this.connections.delete(connectionId);
this.emit('connectionClosed', {
connectionId,
sessionId: connection.sessionId,
reason,
duration: Date.now() - connection.connectedAt,
eventsSent: connection.eventsSent
});
}
/**
* Start heartbeat monitoring
*/
startHeartbeat() {
this.heartbeatInterval = setInterval(() => {
this.checkConnectionHealth();
}, this.HEARTBEAT_INTERVAL);
// Allow Node.js to exit if this is the only active timer
this.heartbeatInterval.unref();
}
/**
* Check connection health and cleanup stale connections
*/
checkConnectionHealth() {
const now = Date.now();
const staleConnections = [];
for (const [connectionId, connection] of this.connections) {
if (!connection.isActive) {
staleConnections.push(connectionId);
continue;
}
// Check for timeout
if (now - connection.lastActivity > this.CONNECTION_TIMEOUT) {
logger.info(`⏰ Connection ${connectionId} timed out`);
staleConnections.push(connectionId);
continue;
}
// Send heartbeat
try {
this.sendEvent(connection.response, {
type: 'heartbeat',
data: {
timestamp: now,
sessionId: connection.sessionId
}
});
connection.lastActivity = now;
}
catch (error) {
logger.debug(`Heartbeat failed for ${connectionId}, marking for cleanup`);
staleConnections.push(connectionId);
}
}
// Cleanup stale connections
for (const connectionId of staleConnections) {
this.disconnect(connectionId, 'stale_connection');
}
if (this.connections.size > 0) {
logger.debug(`💓 Heartbeat: ${this.connections.size} active SSE connections`);
}
}
/**
* Get connection statistics
*/
getStats() {
const activeConnections = Array.from(this.connections.values())
.filter(conn => conn.isActive);
const sessionDistribution = {};
let totalEvents = 0;
for (const connection of activeConnections) {
sessionDistribution[connection.sessionId] =
(sessionDistribution[connection.sessionId] || 0) + 1;
totalEvents += connection.eventsSent;
}
return {
totalConnections: this.connections.size,
activeConnections: activeConnections.length,
sessionDistribution,
averageEventsPerConnection: activeConnections.length > 0
? totalEvents / activeConnections.length
: 0
};
}
/**
* Force disconnect all connections for a session
*/
disconnectSession(sessionId, reason = 'forced_disconnect') {
const sessionConnections = Array.from(this.connections.values())
.filter(conn => conn.sessionId === sessionId);
for (const connection of sessionConnections) {
this.disconnect(connection.id, reason);
}
}
/**
* Cleanup and shutdown transport
*/
shutdown() {
logger.info('🛑 Shutting down SSE transport');
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
this.heartbeatInterval = null;
}
// Disconnect all connections
const connectionIds = Array.from(this.connections.keys());
for (const connectionId of connectionIds) {
this.disconnect(connectionId, 'server_shutdown');
}
this.removeAllListeners();
}
/**
* Get active connection for session (for testing)
*/
getSessionConnections(sessionId) {
return Array.from(this.connections.values())
.filter(conn => conn.sessionId === sessionId && conn.isActive);
}
}
//# sourceMappingURL=sse-transport.js.map