guanghulab/homepage/srv-cn.js
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

60 lines
2.9 KiB
JavaScript

const express = require('express');
const { exec, execSync } = require('child_process');
const util = require('util');
const execPromise = util.promisify(exec);
const fs = require('fs');
const crypto = require('crypto');
const TOKEN = 'zy-gk-Awen-CN-2026';
const app = express();
app.use(express.json());
app.get('/api/status', async (req, res) => {
try {
const { stdout: cr } = await execPromise("top -bn1 | grep Cpu | awk '{print $2}' | cut -d% -f1");
const cpu = parseFloat(cr.trim()) || 0;
const { stdout: mr } = await execPromise("free -m | grep Mem | awk '{print $3,$2,$7}'");
const [used, total, avail] = mr.trim().split(' ').map(Number);
const { stdout: dr } = await execPromise("df -h / | tail -1 | awk '{print $5,$2,$4}'");
const [du, dt, df] = dr.trim().split(' ');
res.json({ timestamp: new Date().toISOString(),
cpu: { usage: cpu.toFixed(1), status: cpu>80?'warn':cpu>50?'normal':'good' },
memory: { used, total, available: avail, percent: ((used/total)*100).toFixed(1), status: (used/total)>0.8?'warn':(used/total)>0.5?'normal':'good' },
disk: { used: du, total: dt, free: df, status: parseInt(du)>80?'warn':'good' } });
} catch(e) { res.status(500).json({ error: e.message }); }
});
app.get('/api/processes', async (req, res) => {
try {
const { stdout } = await execPromise('ps aux --sort=-%mem | head -20');
const procs = stdout.trim().split('\n').slice(1).map(line => {
const p = line.trim().split(/\s+/);
return { name: p[10], pid: p[1], mem: p[3], cpu: p[2] };
});
res.json({ procs });
} catch(e) { res.status(500).json({ error: e.message }); }
});
app.get('/api/services', async (req, res) => {
const svc = [];
try { execSync('ss -tlnp | grep :3920', {timeout:2000}); svc.push({name:'中控台',status:'running'}); } catch(e) {}
try { const p = JSON.parse(execSync('pm2 jlist 2>/dev/null', {timeout:2000}).toString()); p.forEach(x => svc.push({name:'PM2:'+x.name, status: x.pm2_env.status})); } catch(e) {}
res.json({ services: svc });
});
app.get('/api/heartbeat', (req, res) => {
res.json({
servers: [
{ id:'HL-CN-001', name:'国内·Awen', ip:'43.139.207.172', status:'online', spec:'4核4GB' },
{ id:'HL-SG-001', name:'硅谷·Awen', ip:'170.106.72.246', status:'online', spec:'2核2GB' }
],
gatekeeper: { status:'待部署' }
});
});
app.use(express.static('/opt/zhuyuan/console/public'));
app.post('/admin/exec', (req, res) => {
if (req.headers['x-admin-token'] !== TOKEN) return res.status(403).json({ error: 'unauthorized' });
const cmd = req.body.command;
if (!cmd || cmd.length > 5000) return res.status(400).json({ error: 'bad command' });
exec(cmd, { timeout: 60000, maxBuffer: 1048576 }, (e, stdout, stderr) => {
res.json({ output: stdout + (stderr || ''), error: e ? e.message : null });
});
});
app.listen(3920, '127.0.0.1', () => console.log('CN:3920'));