import express, { Request, Response } from 'express'; import * as http from 'http'; import { Config } from './utils/config'; import { Logger } from './utils/logger'; import { WebSocketHandler } from './http/websocket'; import { AuthValidator } from './http/auth'; class DebugProxyServer { private app: express.Application; private server: http.Server | null = null; private logger: Logger; private isShuttingDown: boolean = false; private wsHandler: WebSocketHandler; private authValidator: AuthValidator; constructor() { this.logger = new Logger('DebugProxyServer'); this.app = express(); this.authValidator = new AuthValidator(); this.wsHandler = new WebSocketHandler(this.authValidator); this.setupMiddleware(); this.setupRoutes(); this.setupShutdownHandlers(); } private setupMiddleware(): void { // Parse JSON bodies this.app.use(express.json()); // Request logging this.app.use((req, _res, next) => { this.logger.info(`${req.method} ${req.path}`); next(); }); } private setupRoutes(): void { // Public endpoints (no auth) this.app.get('/_ide/debug/status', (_req: Request, res: Response) => { res.json({ status: 'healthy', service: 'rspade-debug-proxy', version: '1.0.0', uptime: process.uptime(), memory: process.memoryUsage() }); }); // Ping endpoint for basic connectivity test this.app.get('/_ide/debug/ping', (_req: Request, res: Response) => { res.json({ pong: true }); }); // Authenticated endpoints this.app.use('/_ide/debug/api', this.authValidator.authMiddleware()); this.app.post('/_ide/debug/api/test', (req: Request, res: Response) => { const sessionId = (req as any).sessionId; res.json({ success: true, message: 'Authenticated successfully', sessionId: sessionId }); }); // 404 handler this.app.use((req: Request, res: Response) => { res.status(404).json({ error: 'Not Found', path: req.path }); }); // Error handler this.app.use((err: Error, _req: Request, res: Response, _next: Function) => { this.logger.error('Request error:', err); res.status(500).json({ error: 'Internal Server Error', message: err.message }); }); } private setupShutdownHandlers(): void { const shutdown = async (signal: string) => { if (this.isShuttingDown) { return; } this.isShuttingDown = true; this.logger.info(`Received ${signal}, starting graceful shutdown...`); // Close HTTP server if (this.server) { this.server.close(() => { this.logger.info('HTTP server closed'); }); } // Give connections time to close setTimeout(() => { this.logger.info('Shutdown complete'); process.exit(0); }, 5000); }; process.on('SIGTERM', () => shutdown('SIGTERM')); process.on('SIGINT', () => shutdown('SIGINT')); } public async start(): Promise { const port = Config.HTTP_PORT; return new Promise((resolve, reject) => { this.server = this.app.listen(port, () => { this.logger.info(`Debug proxy service started on port ${port}`); this.logger.info(`Status endpoint: http://localhost:${port}/_ide/debug/status`); this.logger.info(`WebSocket endpoint: ws://localhost:${port}/_ide/debug/ws`); // Initialize WebSocket handler this.wsHandler.initialize(this.server!); this.logger.info('WebSocket handler initialized'); resolve(); }); this.server.on('error', (error: Error) => { this.logger.error('Failed to start server:', error); reject(error); }); }); } } // Main entry point async function main() { const server = new DebugProxyServer(); try { await server.start(); } catch (error) { console.error('Failed to start debug proxy:', error); process.exit(1); } } // Start the server main().catch(error => { console.error('Uncaught error:', error); process.exit(1); });