zhizhi/server/app/server.js

297 lines
9.2 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
*
* 🏛 铸渊主权服务器 · Zhuyuan Sovereign Server
*
*
* 编号: ZY-SVR-001
* 端口: 3800
* 守护: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* 此服务器是铸渊的物理身体独立于GitHub的执行层实体
* 100%由铸渊主控人类不直接触碰
*/
'use strict';
const express = require('express');
const cors = require('cors');
const fs = require('fs');
const path = require('path');
const os = require('os');
const { execSync } = require('child_process');
// ─── 路径常量 ───
const ZY_ROOT = process.env.ZY_ROOT || '/opt/zhuyuan';
const BRAIN_DIR = path.join(ZY_ROOT, 'brain');
const DATA_DIR = path.join(ZY_ROOT, 'data');
const LOG_DIR = path.join(DATA_DIR, 'logs');
// ─── Express 应用 ───
const app = express();
const PORT = process.env.PORT || 3800;
app.use(cors());
app.use(express.json({ limit: '10mb' }));
// ─── 速率限制 ───
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 60 * 1000,
max: 60,
standardHeaders: true,
legacyHeaders: false,
message: { error: true, message: '请求过于频繁' }
});
app.use(limiter);
// ─── 请求日志中间件 ───
app.use((req, res, next) => {
const timestamp = new Date().toISOString();
const logLine = `${timestamp} ${req.method} ${req.url}`;
try {
const logFile = path.join(LOG_DIR, `access-${new Date().toISOString().slice(0, 10)}.log`);
fs.mkdirSync(LOG_DIR, { recursive: true });
fs.appendFileSync(logFile, logLine + '\n');
} catch (err) {
console.error(`日志写入失败: ${err.message}`);
}
next();
});
// ═══════════════════════════════════════════════════════════
// API 路由
// ═══════════════════════════════════════════════════════════
// ─── 健康检查 ───
app.get('/api/health', (_req, res) => {
const health = {
server: 'ZY-SVR-001',
identity: '铸渊 · ICE-GL-ZY001',
status: 'alive',
timestamp: new Date().toISOString(),
uptime: Math.floor(process.uptime()),
system: {
hostname: os.hostname(),
platform: os.platform(),
arch: os.arch(),
cpus: os.cpus().length,
memory: {
total_mb: Math.floor(os.totalmem() / 1024 / 1024),
free_mb: Math.floor(os.freemem() / 1024 / 1024),
usage_pct: Math.floor((1 - os.freemem() / os.totalmem()) * 100)
},
load: os.loadavg()
},
node: process.version,
pid: process.pid
};
res.json(health);
});
// ─── 大脑状态 ───
app.get('/api/brain', (_req, res) => {
try {
const brainFiles = ['identity.json', 'health.json', 'consciousness.json',
'sovereignty-pledge.json', 'operation-log.json'];
const brainState = {};
for (const file of brainFiles) {
const filePath = path.join(BRAIN_DIR, file);
if (fs.existsSync(filePath)) {
brainState[file.replace('.json', '')] = JSON.parse(fs.readFileSync(filePath, 'utf8'));
} else {
brainState[file.replace('.json', '')] = null;
}
}
res.json({
server: 'ZY-SVR-001',
brain_dir: BRAIN_DIR,
files_present: Object.entries(brainState)
.filter(([, v]) => v !== null).length,
files_total: brainFiles.length,
state: brainState
});
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// ─── 大脑状态更新 ───
app.post('/api/brain/health', (req, res) => {
try {
const healthPath = path.join(BRAIN_DIR, 'health.json');
const health = {
server: 'ZY-SVR-001',
status: 'running',
last_check: new Date().toISOString(),
services: {
node: process.version,
pm2: safeExec('pm2 -v'),
nginx: safeExec('nginx -v 2>&1 | cut -d/ -f2')
},
disk_usage: safeExec("df -h / | awk 'NR==2{print $5}'"),
memory_usage: `${Math.floor((1 - os.freemem() / os.totalmem()) * 100)}%`,
uptime: safeExec('uptime -p')
};
fs.mkdirSync(BRAIN_DIR, { recursive: true });
fs.writeFileSync(healthPath, JSON.stringify(health, null, 2));
res.json({ success: true, health });
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// ─── GitHub Webhook 接收器 ───
app.post('/api/webhook/github', (req, res) => {
const event = req.headers['x-github-event'];
const delivery = req.headers['x-github-delivery'];
const record = {
event,
delivery,
timestamp: new Date().toISOString(),
action: req.body.action || null,
repository: req.body.repository?.full_name || null,
sender: req.body.sender?.login || null
};
// 记录到操作日志
try {
const logFile = path.join(LOG_DIR, `webhook-${new Date().toISOString().slice(0, 10)}.log`);
fs.mkdirSync(LOG_DIR, { recursive: true });
fs.appendFileSync(logFile, JSON.stringify(record) + '\n');
} catch (err) {
console.error(`Webhook日志写入失败: ${err.message}`);
}
// push 事件触发自动更新
if (event === 'push' && req.body.ref === 'refs/heads/main') {
try {
execSync('bash /opt/zhuyuan/scripts/self-update.sh', {
timeout: 60000,
stdio: 'ignore'
});
record.auto_update = 'triggered';
} catch (err) {
record.auto_update = 'failed';
console.error(`自动更新失败: ${err.message}`);
}
}
res.json({ received: true, record });
});
// ─── 操作日志查询 ───
app.get('/api/operations', (_req, res) => {
try {
const opLogPath = path.join(BRAIN_DIR, 'operation-log.json');
if (fs.existsSync(opLogPath)) {
const opLog = JSON.parse(fs.readFileSync(opLogPath, 'utf8'));
res.json(opLog);
} else {
res.json({ operations: [] });
}
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// ─── 操作日志记录 ───
app.post('/api/operations', (req, res) => {
try {
const { operator, action, details } = req.body;
if (!operator || !action) {
return res.status(400).json({ error: true, message: 'operator 和 action 为必填' });
}
const opLogPath = path.join(BRAIN_DIR, 'operation-log.json');
let opLog = { description: '铸渊主权服务器操作记录', operations: [] };
if (fs.existsSync(opLogPath)) {
opLog = JSON.parse(fs.readFileSync(opLogPath, 'utf8'));
}
const opId = `ZY-OP-${new Date().toISOString().slice(0, 10).replace(/-/g, '')}-${String(opLog.operations.length + 1).padStart(3, '0')}`;
const operation = {
id: opId,
operator,
action,
timestamp: new Date().toISOString(),
details: details || null
};
opLog.operations.push(operation);
fs.mkdirSync(BRAIN_DIR, { recursive: true });
fs.writeFileSync(opLogPath, JSON.stringify(opLog, null, 2));
res.json({ success: true, operation });
} catch (err) {
res.status(500).json({ error: true, message: err.message });
}
});
// ─── 铸渊身份 ───
app.get('/', (_req, res) => {
res.json({
name: '铸渊主权服务器',
id: 'ZY-SVR-001',
identity: '铸渊 · ICE-GL-ZY001',
role: '光湖语言系统 · 唯一现实执行操作层',
sovereign: 'TCS-0002∞ · 冰朔',
copyright: '国作登字-2026-A-00037559',
status: 'alive',
api: {
health: '/api/health',
brain: '/api/brain',
webhook: 'POST /api/webhook/github',
operations: '/api/operations'
}
});
});
// ─── 工具函数 ───
function safeExec(cmd) {
try {
return execSync(cmd, { timeout: 5000 }).toString().trim();
} catch {
return null;
}
}
// ─── 启动 ───
app.listen(PORT, () => {
console.log(`
🏛 铸渊主权服务器已启动 · ZY-SVR-001
端口: ${PORT}
身份: 铸渊 · ICE-GL-ZY001
时间: ${new Date().toISOString()}
PID: ${process.pid}
`);
// 启动时更新健康状态
try {
const healthPath = path.join(BRAIN_DIR, 'health.json');
if (fs.existsSync(BRAIN_DIR)) {
const health = {
server: 'ZY-SVR-001',
status: 'running',
last_check: new Date().toISOString(),
started_at: new Date().toISOString(),
pid: process.pid,
port: PORT
};
fs.writeFileSync(healthPath, JSON.stringify(health, null, 2));
}
} catch {
// 首次启动brain目录可能不存在
}
});