File size: 4,369 Bytes
ccb6b75
 
 
 
 
0dc8aef
ccb6b75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ca1b6c1
 
 
 
ccb6b75
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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);
});