Spaces:
Sleeping
Sleeping
| 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); | |
| }); | |