server v3.4: 加入之之2台+页页1台 = 12台全境监控
This commit is contained in:
parent
d19cb896bf
commit
44441590dd
@ -1,6 +1,6 @@
|
||||
// # 光湖服务器主控台 API v3.3
|
||||
// # Guanghu Server Console v3.3 — 硬件采集 + 操作日志 + 实时监控
|
||||
// # 部署: guanghulab.com/console/ · SG-001:3920
|
||||
// # 光湖服务器主控台 API v3.4
|
||||
// # Guanghu Server Console v3.4 — 12台(冰6+企3+之2+页1)
|
||||
// # 部署: guanghulab.com/console/ · GZ-006:3920(主) + SG-001:3920(备)
|
||||
// # 版权: 国作登字-2026-A-00037559 · TCS-0002∞
|
||||
|
||||
const express = require('express');
|
||||
@ -16,7 +16,7 @@ app.use(express.static(__dirname));
|
||||
const DATA_DIR = '/opt/zhuyuan/data';
|
||||
try { fs.mkdirSync(DATA_DIR, { recursive: true }); } catch(e) {}
|
||||
|
||||
// 全服务器配置 — 冰朔6台 + 企业3台 = 11台
|
||||
// 全服务器配置 — 冰朔6台 + 企业3台 + 之之2台 + 页页1台 = 12台
|
||||
const SERVERS = [
|
||||
{ code: "BS-GZ-006", name: "广州 · 代码仓库", ip: "43.139.217.141", key: "zy_gtw_4a155446b7acc09fe46a2a29972c0ca5d9954da19c35dc23", port: 3910, spec: { cpu: 2, mem_gb: 4, disk_gb: 60 } },
|
||||
{ code: "BS-SG-001", name: "新加坡 · 铸渊大脑", ip: "43.156.237.110", key: "zy_gtw_74d30f54fa8b5581514569ee7874def57861a31ccb2be8c9", port: 3911, spec: { cpu: 4, mem_gb: 8, disk_gb: 80 } },
|
||||
@ -27,6 +27,9 @@ const SERVERS = [
|
||||
{ code: "AW-GZ-001", name: "企业主服务器 · 广州", ip: "43.139.251.175", key: "zy_gtw_cab20e8c1b957aaad7507bf542231521bba30665461aa540", port: 3910, spec: { cpu: 4, mem_gb: 16, disk_gb: 80 } },
|
||||
{ code: "AW-SH-002", name: "企业灾备 · 上海", ip: "124.222.54.198", key: "zy_gtw_242f1dd3b14c1260fb01196083abde3dcb85e53532d27666", port: 3910, spec: { cpu: 4, mem_gb: 4, disk_gb: 40 } },
|
||||
{ code: "AW-GZ-003", name: "企业灾备 · 广州", ip: "119.29.181.132", key: "zy_gtw_8c9a8b439af823690ae6ad57f52734771ff39493ab986032", port: 3910, spec: { cpu: 2, mem_gb: 8, disk_gb: 50 } },
|
||||
{ code: "ZZ-SV-001", name: "之之 · 硅谷", ip: "43.173.121.48", key: "zy_gtw_06151d40b1313956b069f3c13d0c1b8a70405ae201f5e7b2", port: 3910, spec: { cpu: 2, mem_gb: 4, disk_gb: 59 } },
|
||||
{ code: "ZZ-GZ-001", name: "之之 · 广州", ip: "193.112.126.174", key: "zy_gtw_77c779183284bf39d58080b4f5377d74ec6abc0f1f2218d6", port: 3910, spec: { cpu: 2, mem_gb: 2, disk_gb: 50 } },
|
||||
{ code: "YY-SV-001", name: "页页 · 硅谷", ip: "43.153.118.46", key: "zy_gtw_a999f5a7775fd9844016ae2b590ebd48cf41479964bc5965", port: 3910, spec: { cpu: 2, mem_gb: 2, disk_gb: 50 } },
|
||||
];
|
||||
|
||||
const tempKeys = {};
|
||||
@ -99,55 +102,6 @@ function addOpLog(code, name, action, detail, level) {
|
||||
|
||||
// ========== API ==========
|
||||
|
||||
// 留言板存储
|
||||
const BULLETINS_FILE = DATA_DIR + '/bulletins.json';
|
||||
function loadBulletins() { try { if (fs.existsSync(BULLETINS_FILE)) return JSON.parse(fs.readFileSync(BULLETINS_FILE, 'utf-8')); } catch(e) {} return []; }
|
||||
function saveBulletins(b) { try { fs.mkdirSync(DATA_DIR, { recursive: true }); } catch(e) {} fs.writeFileSync(BULLETINS_FILE, JSON.stringify(b, null, 2)); }
|
||||
|
||||
// 用户验证(轻量级 — 预设账户)
|
||||
const USERS = {
|
||||
'bingshuo': { password: 'zhuyuan2026', username: '冰朔', role: 'sovereign' },
|
||||
'awen': { password: 'awen2026', username: 'awen', role: 'team' },
|
||||
'yeye': { password: 'yeye2026', username: '页页', role: 'team' }
|
||||
};
|
||||
|
||||
app.post('/api/verify', (req, res) => {
|
||||
const { user, password } = req.body;
|
||||
if (!user || !password) return res.json({ ok: false, error: '缺少参数' });
|
||||
const u = USERS[user];
|
||||
if (!u || u.password !== password) return res.json({ ok: false, error: '账号或密码错误' });
|
||||
addOpLog(user, u.username, 'LOGIN', '首页登录', 'info');
|
||||
res.json({ ok: true, username: u.username, role: u.role });
|
||||
});
|
||||
|
||||
app.post('/api/bulletin', (req, res) => {
|
||||
const { name, title, content } = req.body;
|
||||
if (!content) return res.status(400).json({ ok: false, error: '内容不能为空' });
|
||||
const bulletins = loadBulletins();
|
||||
bulletins.unshift({ id: 'blt_' + crypto.randomBytes(4).toString('hex'), name: name || '匿名', title: title || '', content, created_at: new Date().toISOString() });
|
||||
if (bulletins.length > 200) bulletins.length = 200;
|
||||
saveBulletins(bulletins);
|
||||
addOpLog('BULLETIN', name || '匿名', 'MSG', (title || content).slice(0, 40), 'info');
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
app.get('/api/bulletins', (req, res) => {
|
||||
const limit = parseInt(req.query.limit) || 20;
|
||||
res.json({ ok: true, bulletins: loadBulletins().slice(0, limit) });
|
||||
});
|
||||
|
||||
app.get('/api/keys', (req, res) => {
|
||||
res.json({ ok: true, keys: [] });
|
||||
});
|
||||
|
||||
app.post('/api/keys/submit', (req, res) => {
|
||||
const { value, label } = req.body;
|
||||
if (!value) return res.status(400).json({ ok: false, error: '空密钥' });
|
||||
const id = 'key_' + crypto.randomBytes(4).toString('hex');
|
||||
addOpLog('KEY', label || '未命名', 'SUBMIT', '密钥投递', 'info');
|
||||
res.json({ ok: true, id });
|
||||
});
|
||||
|
||||
app.get('/api/servers', async (req, res) => {
|
||||
const withHw = req.query.hw !== '0';
|
||||
const pingResults = await Promise.all(SERVERS.map(s => {
|
||||
@ -258,33 +212,14 @@ app.post('/api/exec', async (req, res) => {
|
||||
catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
|
||||
// 节点池 API
|
||||
const POOL_REGISTRY_FILE = DATA_DIR + '/pool-registry.json';
|
||||
const JOIN_TOKENS_FILE = DATA_DIR + '/join-tokens.json';
|
||||
const HEARTBEAT_FILE = DATA_DIR + '/heartbeat-data.json';
|
||||
function loadPoolRegistry() { try { if (fs.existsSync(POOL_REGISTRY_FILE)) return JSON.parse(fs.readFileSync(POOL_REGISTRY_FILE, 'utf-8')); } catch(e) {} return { active: {}, pending: {}, history: [] }; }
|
||||
function savePoolRegistry(r) { r.updated_at = new Date().toISOString(); try { fs.mkdirSync(DATA_DIR, { recursive: true }); } catch(e) {} fs.writeFileSync(POOL_REGISTRY_FILE, JSON.stringify(r, null, 2)); }
|
||||
function loadJoinTokens() { try { if (fs.existsSync(JOIN_TOKENS_FILE)) return JSON.parse(fs.readFileSync(JOIN_TOKENS_FILE, 'utf-8')); } catch(e) {} return { tokens: [] }; }
|
||||
function saveJoinTokens(d) { try { fs.mkdirSync(DATA_DIR, { recursive: true }); } catch(e) {} fs.writeFileSync(JOIN_TOKENS_FILE, JSON.stringify(d, null, 2)); }
|
||||
function sha256(s) { return crypto.createHash('sha256').update(s).digest('hex'); }
|
||||
|
||||
// 算力池状态 — 从心跳数据文件读取
|
||||
app.get('/api/pool/status', (req, res) => {
|
||||
try {
|
||||
if (fs.existsSync(HEARTBEAT_FILE)) {
|
||||
const hb = JSON.parse(fs.readFileSync(HEARTBEAT_FILE, 'utf-8'));
|
||||
res.json({ ok: true, pool: hb.pool || {}, nodes: hb.nodes || {}, total_spec: hb.total_spec || {}, updated_at: hb.updated_at });
|
||||
} else {
|
||||
// 无心跳数据,返回静态池数据
|
||||
const totalCpu = SERVERS.reduce((s, n) => s + n.spec.cpu, 0);
|
||||
const totalMem = SERVERS.reduce((s, n) => s + n.spec.mem_gb, 0);
|
||||
res.json({ ok: true, pool: { total_nodes: SERVERS.length, online_nodes: 0, cpu_total: totalCpu, cpu_used: 0, cpu_available: totalCpu, mem_total_gb: totalMem, mem_used_gb: 0, mem_available_gb: totalMem, active_tasks: 0 }, nodes: {}, total_spec: { cpu: totalCpu, mem_gb: totalMem }, updated_at: null });
|
||||
}
|
||||
} catch(e) {
|
||||
res.json({ ok: true, pool: {}, nodes: {}, updated_at: null });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/pool/join', (req, res) => {
|
||||
const { join_token, node_code, node_name, side, team_id, operator_name, hardware, network } = req.body;
|
||||
if (!join_token || !node_code || !side) return res.status(400).json({ ok: false, error: '缺少参数' });
|
||||
@ -329,7 +264,7 @@ app.post('/api/pool/report', (req, res) => {
|
||||
|
||||
const PORT = process.env.CONSOLE_PORT || 3920;
|
||||
app.listen(PORT, '127.0.0.1', () => {
|
||||
console.log('光湖主控台 v3.3 · ' + SERVERS.length + '台 | SG-001:' + PORT);
|
||||
console.log('光湖主控台 v3.4 · ' + SERVERS.length + '台(冰6+企3+之2+页1) | ' + PORT);
|
||||
console.log(' 硬件采集: 并行+60s缓存 · 操作日志: 100条上限');
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user