index.js
2.56 KB
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
const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const http = require('http');
const config = require('./config');
const app = express();
const server = http.createServer(app);
// ─── 中间件 ───
app.use(cors(config.cors));
app.use(cookieParser());
// 控制字符净化:Agent 通过 curl 发送的 JSON body 可能含原始换行符导致解析失败
app.use((req, res, next) => {
if (req.headers['content-type']?.includes('application/json')) {
let rawBody = '';
req.on('data', chunk => rawBody += chunk);
req.on('end', () => {
if (!rawBody) return next();
try {
req.body = JSON.parse(rawBody);
req._bodyParsed = true;
next();
} catch (e) {
try {
// eslint-disable-next-line no-control-regex
const cleaned = rawBody.replace(/[\x00-\x1F\x7F]/g, (ch) => {
if (ch === '\n') return '\\n';
if (ch === '\r') return '\\r';
if (ch === '\t') return '\\t';
return '';
});
req.body = JSON.parse(cleaned);
req._bodyParsed = true;
next();
} catch (e2) {
res.status(400).json({ error: 'Invalid JSON: ' + e2.message });
}
}
});
} else {
next();
}
});
app.use((req, res, next) => {
if (req._bodyParsed) return next();
express.json()(req, res, next);
});
app.use((err, req, res, next) => {
if (err instanceof SyntaxError && err['status'] === 400 && 'body' in err) {
return res.status(400).json({ error: 'Invalid JSON', details: err.message });
}
next(err);
});
// ─── API 路由 ───
app.use('/api/config', require('./routes/config'));
app.use('/api/master', require('./routes/master-chat'));
// ─── 系统端点 ───
app.get('/api/health', (req, res) => res.json({
status: 'ok', timestamp: new Date().toISOString(),
}));
app.use((err, req, res, next) => {
console.error('Server error:', err);
res.status(500).json({ error: err.message });
});
// ─── 启动 ───
async function start() {
try {
const host = config.host || '0.0.0.0';
server.listen(Number(config.port), host, () => {
console.log(`✅ LemonACP 启动: http://${host}:${config.port}`);
});
} catch (error) {
console.error('Failed to start server:', error);
process.exit(1);
}
}
process.on('SIGTERM', () => { console.log('\n正在关闭...'); process.exit(0); });
process.on('SIGINT', () => { console.log('\n正在关闭...'); process.exit(0); });
start();
module.exports = app;