import express from 'express' import { createServer } from 'http' import { WebSocketServer, WebSocket } from 'ws' import path from 'path' import fs from 'fs' import { apiRouter } from './routes' import { dashboardState, DashboardLog } from './state' import { log as botLog } from '../util/Logger' const PORT = process.env.DASHBOARD_PORT ? parseInt(process.env.DASHBOARD_PORT) : 3000 const HOST = process.env.DASHBOARD_HOST || '127.0.0.1' export class DashboardServer { private app: express.Application private server: ReturnType private wss: WebSocketServer private clients: Set = new Set() constructor() { this.app = express() this.server = createServer(this.app) this.wss = new WebSocketServer({ server: this.server }) this.setupMiddleware() this.setupRoutes() this.setupWebSocket() this.interceptBotLogs() this.setupStateListener() } private setupStateListener(): void { // Listen to dashboard state changes and broadcast to all clients dashboardState.addChangeListener((type, data) => { this.broadcastUpdate(type, data) }) } private setupMiddleware(): void { this.app.use(express.json()) this.app.use('/assets', express.static(path.join(__dirname, '../../assets'))) this.app.use(express.static(path.join(__dirname, '../../public'))) } private setupRoutes(): void { this.app.use('/api', apiRouter) // Health check this.app.get('/health', (_req, res) => { res.json({ status: 'ok', uptime: process.uptime() }) }) // Serve dashboard UI (with fallback if file doesn't exist) this.app.get('/', (_req, res) => { const dashboardPath = path.join(__dirname, '../../public/dashboard.html') const indexPath = path.join(__dirname, '../../public/index.html') if (fs.existsSync(dashboardPath)) { res.sendFile(dashboardPath) } else if (fs.existsSync(indexPath)) { res.sendFile(indexPath) } else { res.status(200).send(` Dashboard - API Only Mode

Dashboard API Active

Frontend UI not found. API endpoints are available:

`) } }) } private setupWebSocket(): void { this.wss.on('connection', (ws: WebSocket) => { this.clients.add(ws) console.log('[Dashboard] WebSocket client connected') ws.on('close', () => { this.clients.delete(ws) console.log('[Dashboard] WebSocket client disconnected') }) ws.on('error', (error) => { console.error('[Dashboard] WebSocket error:', error) }) // Send initial data on connect const recentLogs = dashboardState.getLogs(100) const status = dashboardState.getStatus() const accounts = dashboardState.getAccounts() ws.send(JSON.stringify({ type: 'init', data: { logs: recentLogs, status, accounts } })) }) } private interceptBotLogs(): void { // Store reference to this.clients for closure const clients = this.clients // Intercept bot logs and forward to dashboard const originalLog = botLog ;(global as Record).botLog = function( isMobile: boolean | 'main', title: string, message: string, type: 'log' | 'warn' | 'error' = 'log' ) { const result = originalLog(isMobile, title, message, type) const logEntry: DashboardLog = { timestamp: new Date().toISOString(), level: type, platform: isMobile === 'main' ? 'MAIN' : isMobile ? 'MOBILE' : 'DESKTOP', title, message } dashboardState.addLog(logEntry) // Broadcast to WebSocket clients const payload = JSON.stringify({ type: 'log', log: logEntry }) for (const client of clients) { if (client.readyState === WebSocket.OPEN) { try { client.send(payload) } catch (error) { console.error('[Dashboard] Error sending to WebSocket client:', error) } } } return result } } public broadcastUpdate(type: string, data: unknown): void { const payload = JSON.stringify({ type, data }) for (const client of this.clients) { if (client.readyState === WebSocket.OPEN) { try { client.send(payload) } catch (error) { console.error('[Dashboard] Error broadcasting update:', error) } } } } public start(): void { this.server.listen(PORT, HOST, () => { console.log(`[Dashboard] Server running on http://${HOST}:${PORT}`) console.log('[Dashboard] WebSocket ready for live logs') }) } public stop(): void { this.wss.close() this.server.close() console.log('[Dashboard] Server stopped') } } export function startDashboardServer(): DashboardServer { const server = new DashboardServer() server.start() return server }