#!/usr/bin/env node /* ═══════════════════════════════════════ 光湖驱动引擎 v2.1 · Guanghu Drive Engine HLDP万能语言接口 + 集群串联 — 一条指令,全网执行 ═══════════════════════════════════════ */ const http=require('http'),fs=require('fs'),path=require('path'),crypto=require('crypto'),{exec}=require('child_process'),os=require('os'); const PORT=parseInt(process.env.ENGINE_PORT||process.env.GATEKEEPER_PORT||process.argv[2]||'3910',10); const DATA_DIR=path.join(os.homedir(),'.gatekeeper'); const CMD_TIMEOUT=30000,MAX_OUTPUT=100000,RATE_LIMIT=60; if(!fs.existsSync(DATA_DIR))fs.mkdirSync(DATA_DIR,{recursive:true,mode:0o700}); /* ═══ 密钥 — 兼容所有历史数据目录 ═══ */ const SECRET_PATHS=[ path.join(os.homedir(),'.gatekeeper','secret'), path.join(os.homedir(),'.gk','secret'), path.join(os.homedir(),'.guanghu-engine','secret'), ]; let API_SECRET; for(const sp of SECRET_PATHS){ if(fs.existsSync(sp)){const k=fs.readFileSync(sp,'utf-8').trim();if(k){API_SECRET=k;break;}} } if(!API_SECRET){ API_SECRET="REDACTED_PASSWORD"+crypto.randomBytes(24).toString('hex'); const dir=path.dirname(SECRET_PATHS[0]); if(!fs.existsSync(dir))fs.mkdirSync(dir,{recursive:true,mode:0o700}); fs.writeFileSync(SECRET_PATHS[0],API_SECRET,{mode:0o600}); console.log(''); console.log('══════════════════════════════════════════════'); console.log(' 🔐 光湖驱动引擎 · 首次启动'); console.log(''); console.log(' ╭─ API 密钥(请复制保存)'); console.log(' ├─ '+API_SECRET); console.log(' ╰─ 此密钥仅在此处显示一次'); console.log(''); console.log(' 已保存至: '+SECRET_PATHS[0]); console.log(' 监听端口: '+PORT); console.log('══════════════════════════════════════════════'); console.log(''); } function log(level,action,detail){ const ts=new Date().toISOString(); const line='['+ts+'] ['+level+'] '+action+(detail?' | '+detail:''); console.log(line); try{const lf=path.join(DATA_DIR,'engine.log');fs.appendFileSync(lf,line+'\n');}catch(e){} } const RC={}; function checkRate(ip){ const n=Date.now(),w=60000; if(!RC[ip]){RC[ip]={c:1,r:n+w};return true;} if(n>RC[ip].r){RC[ip]={c:1,r:n+w};return true;} RC[ip].c++;return RC[ip].c<=RATE_LIMIT; } function auth(headers){ const t=(headers['authorization']||headers['Authorization']||'').replace(/^Bearer\s+/i,'').trim(); if(!t)return{ok:false,reason:'缺少 Authorization header'}; if(t.length!==API_SECRET.length)return{ok:false,reason:'密钥无效'}; for(let i=0;i{let b='';req.on('data',c=>b+=c);req.on('end',()=>{try{r(JSON.parse(b))}catch(e){r(null)}});req.on('error',()=>r(null));}); } function jr(res,status,data){ res.writeHead(status,{'Content-Type':'application/json','Access-Control-Allow-Origin':'*'}); res.end(JSON.stringify(data)); } async function execCmd(cmd,timeout){ return new Promise(r=>{exec(cmd,{timeout:timeout||CMD_TIMEOUT,maxBuffer:MAX_OUTPUT,shell:'/bin/bash'},(e,o,se)=>{r({stdout:(o||'').slice(0,MAX_OUTPUT),stderr:(se||'').slice(0,MAX_OUTPUT),code:e?(e.code||e.signal||1):0,err:e?e.message:null});});}); } function fmtUptime(s){const d=Math.floor(s/86400),h=Math.floor((s%86400)/3600),m=Math.floor((s%3600)/60);return d+'天'+h+'小时'+m+'分'+(s%60)+'秒';} function fmtBytes(b){if(b===0)return'0 B';const k=1024,sizes=['B','KB','MB','GB','TB'];const i=Math.floor(Math.log(b)/Math.log(k));return parseFloat((b/Math.pow(k,i)).toFixed(1))+' '+sizes[i];} /* ═══════════════════════════════════════ HLDP 翻译层 v2.0 — 光湖驱动引擎 v2.1 新增 @串联 @广播 — 引擎之间互相通话 ═══════════════════════════════════════ */ const NODES={ 'BS-GZ-006':{url:'http://43.139.217.141:3910',key:'GATEKEEPER_TOKEN_REDACTED'}, 'BS-SG-001':{url:'http://43.156.237.110:3911',key:'GATEKEEPER_TOKEN_REDACTED'}, 'BS-SG-002':{url:'http://43.134.16.246:3910',key:'GATEKEEPER_TOKEN_REDACTED'}, 'BS-SG-003':{url:'http://43.153.193.169:3910',key:'GATEKEEPER_TOKEN_REDACTED'}, 'ZY-SG-006':{url:'http://43.153.203.105:3910',key:'GATEKEEPER_TOKEN_REDACTED'}, 'BS-SH-005':{url:'http://124.223.10.33:3910',key:'GATEKEEPER_TOKEN_REDACTED'}, }; function parseOpLine(t){ if(t.startsWith('@执行:')){ const cmd=t.replace('@执行:','').trim(); const parts=cmd.split(/\s+/); if(parts[0]==='shell')return{type:'shell',cmd:parts.slice(1).join(' ')}; if(parts[0]==='python')return{type:'python',cmd:parts.slice(1).join(' ')}; return{type:'shell',cmd:cmd}; } if(t.startsWith('@部署:')){ const action=t.replace('@部署:','').trim(); const parts=action.split(/\s+/); if(parts[0]==='写入')return{type:'write',path:parts[1]}; if(parts[0]==='命令')return{type:'shell',cmd:parts.slice(1).join(' ')}; } return null; } function parseHLDP(text){ const lines=text.split('\n'); const groups=[]; let relay=null; for(const line of lines){ const t=line.trim(); if(!t)continue; if(t.startsWith('@串联:')){relay=t.replace('@串联:','').trim();continue;} if(t==='@广播'){relay='BROADCAST';continue;} const op=parseOpLine(t); if(!op)continue; if(!groups.length||groups[groups.length-1].relay!==relay){ groups.push({relay:relay,ops:[]}); } groups[groups.length-1].ops.push(op); } return groups; } async function relayHLDP(target,hldpText){ const node=NODES[target]; if(!node)return{target:target,ok:false,error:'未知节点: '+target}; return new Promise(r=>{ const body=JSON.stringify({hlpd:hldpText}); const opts={hostname:node.url.replace(/https?:\/\//,'').split(':')[0], port:parseInt(node.url.split(':').pop()||'3910',10), path:'/hlpd',method:'POST', headers:{'Content-Type':'application/json','Authorization':'Bearer '+node.key,'Content-Length':Buffer.byteLength(body)}}; const req=http.request(opts,res=>{let d='';res.on('data',c=>d+=c);res.on('end',()=>{try{r({target:target,ok:true,result:JSON.parse(d)})}catch(e){r({target:target,ok:false,error:d.slice(0,200)})}})}); req.on('error',e=>r({target:target,ok:false,error:e.message})); req.write(body);req.end(); }); } function hldpTextFromOps(ops){ return ops.map(o=>{ if(o.type==='shell')return '@执行: shell '+o.cmd; if(o.type==='python')return '@执行: python '+o.cmd; if(o.type==='write')return '@部署: 写入 '+o.path; return ''; }).filter(l=>l).join('\n'); } async function runHLDP(hlpdText){ const groups=parseHLDP(hlpdText); const allResults=[]; for(const g of groups){ if(!g.relay){ for(const op of g.ops){ if(op.type==='shell'){ const r=await execCmd(op.cmd); allResults.push({type:'shell',cmd:op.cmd,...r}); }else if(op.type==='write'){ try{ const dir=path.dirname(op.path); if(!fs.existsSync(dir))fs.mkdirSync(dir,{recursive:true}); allResults.push({type:'write',path:op.path,ok:true}); }catch(e){allResults.push({type:'write',path:op.path,ok:false,error:e.message});} }else if(op.type==='python'){ const r=await execCmd('python3 -c "'+op.cmd.replace(/"/g,'\\"')+'"'); allResults.push({type:'python',cmd:op.cmd,...r}); } } }else if(g.relay==='BROADCAST'){ const hldp=hldpTextFromOps(g.ops); const targets=Object.keys(NODES); const promises=targets.map(t=>relayHLDP(t,hldp)); const results=await Promise.all(promises); allResults.push({type:'broadcast',targets:targets.length,results:results}); }else{ const hldp=hldpTextFromOps(g.ops); const r=await relayHLDP(g.relay,hldp); allResults.push({type:'relay',target:g.relay,...r}); } } return{groups:groups.length,results:allResults}; } /* ═══════════════════════════════════════ HTTP 服务器 + 路由 ═══════════════════════════════════════ */ const server=http.createServer(async(req,res)=>{ if(req.method==='OPTIONS'){jr(res,204,{});return;} if(req.method!=='POST'){jr(res,405,{error:'只接受 POST 请求'});return;} const ip=req.socket.remoteAddress||'unknown'; if(!checkRate(ip)){log('WARN','rate_limit',ip);jr(res,429,{error:'请求过于频繁'});return;} const a=auth(req.headers); if(!a.ok){log('WARN','auth_failed',a.reason);jr(res,401,{error:a.reason});return;} const url=new URL(req.url,'http://'+((req.headers.host)||'localhost')); const route=url.pathname; try{ if(route==='/exec'){ const b=await parseBody(req); if(!b||!b.cmd){jr(res,400,{error:'缺少 cmd 参数'});return;} log('INFO','exec',b.cmd.slice(0,200)); const r=await execCmd(b.cmd,b.timeout); log('INFO','exec_result','exit='+r.code); jr(res,200,{ok:r.code===0,stdout:r.stdout,stderr:r.stderr,exitCode:r.code}); }else if(route==='/health'){ jr(res,200,{ok:true,service:'guanghu-engine',version:'2.1.0',uptime:process.uptime().toFixed(0)+'s',timestamp:new Date().toISOString()}); }else if(route==='/status'){ log('INFO','status',''); const total=os.totalmem(),free=os.freemem(); jr(res,200,{ok:true,hostname:os.hostname(),platform:os.platform(),arch:os.arch(),cpus:os.cpus().length,uptime:os.uptime(),uptime_str:fmtUptime(os.uptime()),memory:{total:fmtBytes(total),free:fmtBytes(free),used:fmtBytes(total-free),usage:((total-free)/total*100).toFixed(1)+'%'},load:os.loadavg().map(n=>+n.toFixed(2)),engine:{version:'2.1.0',port:PORT,uptime:process.uptime().toFixed(0)+'s'}}); }else if(route==='/hlpd'){ const b=await parseBody(req); if(!b||!b.hlpd){jr(res,400,{error:'缺少 hlpd 参数'});return;} log('INFO','hlpd','执行HLDP模块,长度='+b.hlpd.length); const r=await runHLDP(b.hlpd); jr(res,200,{ok:true,hlpd:r}); }else if(route==='/file/read'){ const b=await parseBody(req); if(!b||!b.path){jr(res,400,{error:'缺少 path 参数'});return;} log('INFO','file_read',b.path); try{ const c=fs.readFileSync(b.path,'utf-8'); const s=fs.statSync(b.path); jr(res,200,{ok:true,path:b.path,size:s.size,modified:s.mtime.toISOString(),content:c.slice(0,MAX_OUTPUT)}); }catch(e){jr(res,404,{ok:false,error:e.message});} }else if(route==='/file/write'){ const b=await parseBody(req); if(!b||!b.path||b.content===undefined){jr(res,400,{error:'缺少 path 或 content'});return;} log('INFO','file_write',b.path); try{ const d=path.dirname(b.path); if(!fs.existsSync(d))fs.mkdirSync(d,{recursive:true}); fs.writeFileSync(b.path,b.content,'utf-8'); jr(res,200,{ok:true,path:b.path,size:Buffer.byteLength(b.content,'utf-8')}); }catch(e){jr(res,500,{ok:false,error:e.message});} }else if(route==='/file/list'){ const b=await parseBody(req); const p=(b&&b.path)||'.'; log('INFO','file_list',p); try{ const items=fs.readdirSync(p,{withFileTypes:true}); const files=[]; for(const x of items){files.push({name:x.name,type:x.isDirectory()?'dir':'file'});} jr(res,200,{ok:true,path:p,files:files}); }catch(e){jr(res,404,{ok:false,error:e.message});} }else if(route==='/ping'){ jr(res,200,{ok:true,pong:true}); }else{ jr(res,404,{error:'未知路径: '+route}); } }catch(e){log('ERROR','unhandled',e.message);jr(res,500,{error:'内部错误: '+e.message});} }); /* ═══ 启动 + 错误处理 ═══ */ server.on('error',(e)=>{ if(e.code==='EADDRINUSE'){ log('FATAL','eaddrinuse','端口 '+PORT+' 已被占用,3秒后退出'); console.error('❌ 端口 '+PORT+' 已被占用,无法启动。请先释放端口。'); setTimeout(()=>process.exit(1),3000); }else{ log('FATAL','server_error',e.message); console.error('❌ 服务器错误: '+e.message); process.exit(1); } }); server.listen(PORT,'0.0.0.0',()=>{ const h=os.hostname(); log('INFO','startup','host='+h+' port='+PORT+' v2.1'); console.log(' ⚔️ 光湖驱动引擎 v2.1 · HLDP + 集群串联'); console.log(' 主机名: '+h+' 端口: '+PORT); }); process.on('SIGTERM',()=>{log('INFO','shutdown','SIGTERM');server.close(()=>process.exit(0));}); process.on('SIGINT',()=>{log('INFO','shutdown','SIGINT');server.close(()=>process.exit(0));}); process.on('uncaughtException',(e)=>{log('ERROR','uncaught',e.message);}); process.on('unhandledRejection',(e)=>{log('ERROR','unhandled',e.message);});