import http from 'http'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import HumanBehaviorEngine from './index.js'; import logger from './utils/logger.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const PORT = parseInt(process.env.PORT) || 7860; const publicDir = path.join(__dirname, '..', 'public'); const engine = new HumanBehaviorEngine(); let isRunning = false; const mimeTypes = { '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css', '.json': 'application/json', '.png': 'image/png', '.svg': 'image/svg+xml', }; function serveStatic(res, filePath) { const ext = path.extname(filePath); const contentType = mimeTypes[ext] || 'application/octet-stream'; fs.readFile(filePath, (err, content) => { if (err) { res.writeHead(404); res.end(JSON.stringify({ error: 'not_found' })); return; } res.writeHead(200, { 'Content-Type': contentType }); res.end(content); }); } async function startEngine() { if (isRunning) return { status: 'already_running' }; isRunning = true; await engine.start(); return { status: 'started' }; } async function stopEngine() { isRunning = false; await engine.stop(); return { status: 'stopped' }; } async function getStatus() { return await engine.getStatus(); } const server = http.createServer(async (req, res) => { const url = new URL(req.url, `http://${req.headers.host}`); res.setHeader('Access-Control-Allow-Origin', '*'); if (req.method === 'GET' && url.pathname === '/health') { res.setHeader('Content-Type', 'application/json'); res.writeHead(200); res.end(JSON.stringify({ status: 'ok', uptime: process.uptime() })); return; } if (req.method === 'GET' && url.pathname === '/status') { res.setHeader('Content-Type', 'application/json'); try { const status = await getStatus(); res.writeHead(200); res.end(JSON.stringify(status)); } catch (e) { res.writeHead(500); res.end(JSON.stringify({ error: e.message })); } return; } if (req.method === 'POST' && url.pathname === '/start') { res.setHeader('Content-Type', 'application/json'); try { const result = await startEngine(); res.writeHead(200); res.end(JSON.stringify(result)); } catch (e) { res.writeHead(500); res.end(JSON.stringify({ error: e.message })); } return; } if (req.method === 'POST' && url.pathname === '/stop') { res.setHeader('Content-Type', 'application/json'); try { const result = await stopEngine(); res.writeHead(200); res.end(JSON.stringify(result)); } catch (e) { res.writeHead(500); res.end(JSON.stringify({ error: e.message })); } return; } if (req.method === 'POST' && url.pathname === '/cycle') { res.setHeader('Content-Type', 'application/json'); try { const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error('Cycle timed out after 60s')), 60000) ); await Promise.race([engine.runOnce(), timeout]); res.writeHead(200); res.end(JSON.stringify({ status: 'cycle_complete' })); } catch (e) { res.writeHead(500); res.end(JSON.stringify({ error: e.message })); } return; } if (req.method === 'GET') { if (url.pathname === '/' || url.pathname === '/index.html') { serveStatic(res, path.join(publicDir, 'index.html')); return; } const filePath = path.join(publicDir, url.pathname); if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) { serveStatic(res, filePath); return; } } res.setHeader('Content-Type', 'application/json'); res.writeHead(404); res.end(JSON.stringify({ error: 'not_found' })); }); server.listen(PORT, '0.0.0.0', () => { logger.info(`Cloud server listening on port ${PORT}`); logger.info(`Dashboard: http://localhost:${PORT}`); logger.info('Auto-starting simulator...'); startEngine().catch(e => logger.error(`Auto-start failed: ${e.message}`)); }); process.on('SIGTERM', async () => { logger.info('SIGTERM received, stopping engine...'); await stopEngine(); process.exit(0); }); process.on('SIGINT', async () => { logger.info('SIGINT received, stopping engine...'); await stopEngine(); process.exit(0); });