| 123456 |
- #!/usr/bin/env node
- import {Server}from'socket.io';import {spawn,exec}from'child_process';import h from'fs/promises';import g from'path';import x from'net';import {EventEmitter}from'events';import N from'@d8d-localtunnel/client';import {createServer}from'http';import L from'chokidar';import {promises}from'fs';import H from'anymatch';var S=class extends EventEmitter{constructor(t){super();this.checkInterval=null;this.workspacePath=t.workspacePath,this.intervalTime=t.checkInterval||1e3,this.timeout=t.timeout||5*60*1e3,this.portRange={start:3e3,end:9999};}start(){this.checkInterval||(this.checkInterval=setInterval(async()=>{await this.detectServer();},this.intervalTime),setTimeout(()=>{this.stop();},this.timeout));}stop(){this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null);}async detectServer(){try{let t=await this.findVitePort();if(t){await this.handleServerFound(t);return}let e=[3e3,8080,4e3,3001,8e3];for(let r of e)if(await this.checkPort(r)&&await this.isProcessFromWorkspace(r)){await this.handleServerFound(r);return}}catch(t){console.error("[ServerDetector] Error detecting server:",t);}}async detectServerByPid(t){if(!t.pid)return;let e=null,r=async c=>{let a=c.toString();console.log(`[ServerDetector] \u89E3\u6790\u8F93\u51FA: ${a}`);let p=a.match(/(?:localhost|127\.0\.0\.1):(\d+)/g);if(p)for(let m of p){let d=parseInt(m.split(":")[1],10);if(console.log(`[ServerDetector] \u4ECE\u8F93\u51FA\u4E2D\u53D1\u73B0\u7AEF\u53E3: ${d}`),await this.checkPort(d)){console.log(`[ServerDetector] \u7AEF\u53E3 ${d} \u53EF\u7528\uFF0C\u521B\u5EFA\u96A7\u9053...`),e=d,await this.handleServerFound(d),t.stdout?.removeListener("data",r);return}}};if(t.stdout?.on("data",r),await new Promise(c=>setTimeout(c,500)),e)return;let o=5,n=1e3,i=0,l=async()=>{try{let c=await this.getProcessPorts(t.pid);if(console.log(`[ServerDetector] \u8FDB\u7A0B ${t.pid} \u7684\u7AEF\u53E3\u4FE1\u606F (\u5C1D\u8BD5 ${i+1}):`,c),c.length>0){for(let{port:p,protocol:m}of c)if(m==="tcp")return await this.handleServerFound(p),!0}let a=await this.getChildProcessPorts(t.pid);if(console.log(`[ServerDetector] \u5B50\u8FDB\u7A0B\u7AEF\u53E3\u4FE1\u606F (\u5C1D\u8BD5 ${i+1}):`,a),a.length>0){for(let{port:p,protocol:m}of a)if(m==="tcp")return await this.handleServerFound(p),!0}return !1}catch(c){return console.error("[ServerDetector] \u68C0\u6D4B\u7AEF\u53E3\u5931\u8D25:",c),!1}};for(;i<o&&!e;){if(await l()){t.stdout?.removeListener("data",r);return}i++,i<o&&(console.log(`[ServerDetector] \u7B49\u5F85 ${n}ms \u540E\u8FDB\u884C\u7B2C ${i+1} \u6B21\u5C1D\u8BD5...`),await new Promise(a=>setTimeout(a,n)));}console.log("[ServerDetector] \u7AEF\u53E3\u68C0\u6D4B\u91CD\u8BD5\u7ED3\u675F\uFF0C\u7EE7\u7EED\u76D1\u542C\u8FDB\u7A0B\u8F93\u51FA...");}async getChildProcessPorts(t){return new Promise(e=>{exec(`pgrep -P ${t}`,async(r,o)=>{if(r){console.error("[ServerDetector] pgrep \u6267\u884C\u5931\u8D25:",r),e([]);return}let n=o.trim().split(`
- `).filter(Boolean),i=[],l=n.map(c=>this.getProcessPorts(parseInt(c,10)));try{(await Promise.all(l)).forEach(a=>i.push(...a));}catch(c){console.error("[ServerDetector] \u68C0\u67E5\u5B50\u8FDB\u7A0B\u7AEF\u53E3\u5931\u8D25:",c);}e(i);});})}async getProcessPorts(t){return new Promise(e=>{exec(`lsof -i -P -n -p ${t} | grep LISTEN`,(r,o)=>{if(r){e([]);return}let n=[],i=o.split(`
- `).filter(Boolean);for(let l of i){let c=l.match(/\s+(\w+):(\d+)\s+\(LISTEN\)$/);c&&n.push({pid:t,port:parseInt(c[2],10),protocol:c[1].toLowerCase()});}e(n);});})}async handleServerFound(t){try{let e=await N({port:t,host:"https://pre.d8d.fun"});this.emit("server-ready",{port:t,url:e.url,localUrl:`http://localhost:${t}`});}catch(e){console.error("Failed to create tunnel:",e),this.emit("server-ready",{port:t,url:`http://localhost:${t}`});}this.stop();}async checkPort(t){return new Promise(e=>{let r=x.createConnection({port:t,host:"localhost",timeout:1e3});r.on("connect",()=>{r.end(),e(!0);}),r.on("error",()=>{e(!1);}),r.on("timeout",()=>{r.destroy(),e(!1);});})}async isProcessFromWorkspace(t){for(let o=0;o<3;o++)try{let n=new AbortController,i=setTimeout(()=>n.abort(),5e3),l=await fetch(`http://localhost:${t}`,{signal:n.signal});return clearTimeout(i),l.ok}catch{if(o===2)return console.log(`[ServerDetector] Failed to check port ${t} after 3 retries`),!1;await new Promise(i=>setTimeout(i,1e3));}return !1}async findActualPort(){let t=await this.findVitePort();return t||new Promise(e=>{exec("lsof -i -P -n | grep LISTEN | grep node",(r,o)=>{if(r){console.log("[ServerDetector] Error finding actual port:",r),e(null);return}try{let n=o.split(`
- `);for(let i of n){let l=i.match(/:51[7-9][0-9]/);if(l){let c=parseInt(l[0].substring(1));if(c>=5173&&c<=5179){console.log(`[ServerDetector] Found Vite server port from lsof: ${c}`),e(c);return}}}e(null);}catch(n){console.error("[ServerDetector] Error parsing port:",n),e(null);}});})}async findVitePort(){try{for(let t=5173;t<=5179;t++)if(await this.checkPort(t))try{let r=new AbortController,o=setTimeout(()=>r.abort(),3e3),n=await fetch(`http://localhost:${t}`,{signal:r.signal});if(clearTimeout(o),(await n.text()).includes("vite")||n.headers.get("server")?.includes("vite"))return console.log(`[ServerDetector] Found Vite server on port: ${t}`),t}catch{continue}}catch(t){console.error("[ServerDetector] Error in findVitePort:",t);}return null}static isDevServerCommand(t,e=[]){return [["npm",["run","dev"]],["npm",["run","start"]],["npm",["start"]],["yarn",["dev"]],["yarn",["start"]],["pnpm",["dev"]],["pnpm",["start"]],["vite"],["next"],["nuxt"]].some(([o,n])=>n?t===o&&JSON.stringify(e)===JSON.stringify(n):t===o)}};var D={KILL_TIMEOUT:5e3,CLEANUP_RETRIES:3},$={ENCODING:"utf-8",DIR_MODE:493,FILE_MODE:420},P={DEFAULT_PORT:3e3,DEFAULT_HOST:"localhost",DEFAULT_WORKSPACE_DIR:"workspaces",CORS:{origin:"*",methods:["GET","POST"]}},I={DEFAULT_IGNORE:["**/node_modules/**","**/.git/**","**/dist/**","**/.DS_Store","**/thumbs.db"],WATCH_OPTIONS:{persistent:!0,ignoreInitial:!1,followSymlinks:!1,disableGlobbing:!1,usePolling:!1}};var E=class{constructor(s={}){this.workspaces=new Map;this.processes=new Map;this.processHistory=new Map;this.watchers=new Map;this.config={port:s.port||P.DEFAULT_PORT,host:s.host||P.DEFAULT_HOST,workspaceRoot:s.workspaceRoot||g.join(process.cwd(),P.DEFAULT_WORKSPACE_DIR)},this.httpServer=createServer((t,e)=>{if(e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Access-Control-Allow-Methods","GET, OPTIONS"),t.method==="OPTIONS"){e.writeHead(204),e.end();return}if(t.url==="/"){e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({name:"@d8d-webcontainer/server",version:"1.0.0",status:"running",uptime:process.uptime(),config:{port:this.config.port,host:this.config.host,workspaceRoot:this.config.workspaceRoot},connections:this.io?.engine?.clientsCount||0,workspaces:this.workspaces.size||0}));return}e.writeHead(404,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"Not Found"}));}),this.io=new Server(this.httpServer,{cors:P.CORS}),this.setupSocketHandlers();}async start(){try{await h.mkdir(this.config.workspaceRoot,{recursive:!0});let s=["git","npm","node"];for(let t of s)await this.checkCommandExists(t)||console.warn(`\u8B66\u544A: \u547D\u4EE4 '${t}' \u672A\u5B89\u88C5\uFF0C\u8FD9\u53EF\u80FD\u4F1A\u5F71\u54CD\u67D0\u4E9B\u529F\u80FD\u7684\u4F7F\u7528`);return new Promise(t=>{this.httpServer.listen(this.config.port,this.config.host,()=>{console.log(`WebContainer Server is running on http://${this.config.host}:${this.config.port}`),console.log(`Workspace root: ${this.config.workspaceRoot}`),t();});})}catch(s){console.error("Failed to start server:",s),process.exit(1);}}setupSocketHandlers(){this.io.on("connection",async s=>{let t=Math.random().toString(36).substr(2,9),e=g.join(this.config.workspaceRoot,t);this.workspaces.set(s.id,e),this.processes.set(s.id,new Map),console.log(`Client connected. Workspace created at: ${e}`);try{await h.mkdir(e,{recursive:!0});}catch(r){console.error("Failed to configure NPM mirrors:",r);}s.on("mount",async(r,o)=>{try{await this.handleMount(e,r),o({success:!0});}catch(n){let i=n instanceof Error?n.message:"Unknown error occurred";o({error:i});}}),s.on("spawn",async({command:r,args:o=[],terminalId:n="default"},i)=>{try{let l=await this.handleSpawn(s.id,e,r,o,n);i({result:l});}catch(l){let c=l instanceof Error?l.message:"Unknown error occurred";i({error:c});}}),s.on("fs:list",async(r,o)=>{try{let n=await this.handleList(e,r);o({success:!0,result:n});}catch(n){let i=n instanceof Error?n.message:"Unknown error occurred";o({error:i});}}),s.on("fs:read",async(r,o)=>{try{let n=await this.handleRead(e,r);o({success:!0,result:n});}catch(n){let i=n instanceof Error?n.message:"Unknown error occurred";o({error:i});}}),s.on("fs:write",async(r,o)=>{try{await this.handleWrite(e,r.path,r.content),o({success:!0});}catch(n){let i=n instanceof Error?n.message:"Unknown error occurred";o({error:i});}}),s.on("fs:delete",async(r,o)=>{try{await this.handleDelete(e,r),o({success:!0});}catch(n){let i=n instanceof Error?n.message:"Unknown error occurred";o({error:i});}}),s.on("fs:mkdir",async(r,o)=>{try{await this.handleMkdir(e,r),o({success:!0});}catch(n){let i=n instanceof Error?n.message:"Unknown error occurred";o({error:i});}}),s.on("fs:watch",async({glob:r,ignore:o=I.DEFAULT_IGNORE,ignoreInitial:n},i=()=>{})=>{try{console.log(`[Watch] Socket ${s.id} \u5F00\u59CB\u76D1\u542C\u6587\u4EF6: ${r}`),console.log("[Watch] \u5FFD\u7565\u7684\u6587\u4EF6\u6A21\u5F0F:",o),console.log("[Watch] ignoreInitial:",n);let l=[r,`${r}/*`,`${r}/**/*`],c=L.watch(l,{cwd:e,...I.WATCH_OPTIONS,...n!==void 0?{ignoreInitial:n}:{},ignored:a=>{let p=H(o,a);return p&&console.log(`[Watch] \u5FFD\u7565\u8DEF\u5F84: ${a}`),p}});c.on("all",async(a,p)=>{let m=`${e}/${p}`,d=null;try{d=await promises.stat(m).catch(()=>null);}catch{}s.emit("fs:change",{type:a==="add"||a==="addDir"?"create":a==="change"?"update":a==="unlink"?"delete":a,path:p,kind:d?.isDirectory()?"directory":"file"});}),c.on("error",a=>{console.error("[Watch] \u76D1\u542C\u9519\u8BEF:",a);}),c.on("ready",()=>{console.log("[Watch] \u6587\u4EF6\u76D1\u542C\u5668\u5DF2\u5C31\u7EEA");}),this.watchers.set(s.id,c),typeof i=="function"&&i({success:!0});}catch(l){console.error("[Watch] \u8BBE\u7F6E\u76D1\u542C\u5931\u8D25:",l);let c=l instanceof Error?l.message:"\u8BBE\u7F6E\u76D1\u542C\u5931\u8D25";typeof i=="function"&&i({error:c});}}),s.on("fs:unwatch",async({glob:r},o=()=>{})=>{try{let n=this.watchers.get(s.id);n&&(await n.close(),this.watchers.delete(s.id)),typeof o=="function"&&o({success:!0});}catch(n){let i=n instanceof Error?n.message:"Unknown error occurred";typeof o=="function"&&o({error:i});}}),s.on("disconnect",async()=>{console.log(`\u5BA2\u6237\u7AEF\u65AD\u5F00\u8FDE\u63A5. \u5DE5\u4F5C\u533A: ${e}`);try{let r=this.watchers.get(s.id);r&&(await r.close(),this.watchers.delete(s.id),console.log(`\u6587\u4EF6\u76D1\u542C\u5668\u5DF2\u6E05\u7406: ${s.id}`)),console.log(`\u6B63\u5728\u7EC8\u6B62\u5DE5\u4F5C\u533A\u8FDB\u7A0B: ${e}`),await this.killAllProcesses(s.id),console.log(`\u6B63\u5728\u6E05\u7406\u5DE5\u4F5C\u533A\u76EE\u5F55: ${e}`),await h.access(e).then(()=>!0).catch(()=>!1)?(await h.rm(e,{recursive:!0,force:!0}),console.log(`\u5DE5\u4F5C\u533A\u76EE\u5F55\u5DF2\u6E05\u7406: ${e}`)):console.log(`\u5DE5\u4F5C\u533A\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u6E05\u7406: ${e}`),this.workspaces.delete(s.id),this.processes.delete(s.id),console.log(`\u5BA2\u6237\u7AEF\u8D44\u6E90\u6E05\u7406\u5B8C\u6210: ${s.id}`);}catch(r){console.error("\u5BA2\u6237\u7AEF\u6E05\u7406\u8FC7\u7A0B\u4E2D\u53D1\u751F\u9519\u8BEF:",r);}}),s.on("process:kill",async({pid:r,terminalId:o="default"},n)=>{try{await this.killProcess(s.id,r,o),n({success:!0});}catch(i){let l=i instanceof Error?i.message:"Unknown error occurred";n({error:l});}});});}async killAllProcesses(s){let t=this.processes.get(s);if(!t){console.log(`\u6CA1\u6709\u627E\u5230 socket ${s} \u7684\u8FDB\u7A0B\u8BB0\u5F55`);return}await Promise.all(Array.from(t.entries()).map(async([e,r])=>{try{if(!r.pid){console.log(`\u8FDB\u7A0B (\u7EC8\u7AEF ${e}) \u6CA1\u6709\u6709\u6548\u7684 PID`);return}await new Promise((o,n)=>{let i=r.pid;spawn("pkill",["-TERM","-P",i.toString()]).on("close",async()=>{try{r.kill("SIGINT"),console.log(`\u8FDB\u7A0B ${i} (\u7EC8\u7AEF ${e}) \u5DF2\u53D1\u9001 SIGINT \u4FE1\u53F7`),await new Promise(c=>{let a=setTimeout(()=>{try{spawn("pkill",["-KILL","-P",i.toString()]),r.kill("SIGKILL"),console.log(`\u8FDB\u7A0B ${i} (\u7EC8\u7AEF ${e}) \u5DF2\u5F3A\u5236\u7EC8\u6B62`);}catch(p){console.error(`\u5F3A\u5236\u7EC8\u6B62\u8FDB\u7A0B ${i} (\u7EC8\u7AEF ${e}) \u5931\u8D25:`,p);}c();},D.KILL_TIMEOUT);r.once("exit",p=>{clearTimeout(a),console.log(`\u8FDB\u7A0B ${i} (\u7EC8\u7AEF ${e}) \u5DF2\u9000\u51FA\uFF0C\u9000\u51FA\u7801: ${p}`),c();});}),o();}catch(c){n(c);}});});}catch(o){o instanceof Error&&o.message.includes("ESRCH")?console.log(`\u8FDB\u7A0B ${r.pid} (\u7EC8\u7AEF ${e}) \u5DF2\u4E0D\u5B58\u5728`):console.error(`\u7EC8\u6B62\u8FDB\u7A0B ${r.pid} (\u7EC8\u7AEF ${e}) \u65F6\u53D1\u751F\u9519\u8BEF:`,o);}})),t.clear(),this.processHistory.set(s,[]),console.log(`Socket ${s} \u7684\u6240\u6709\u8FDB\u7A0B\u5DF2\u6E05\u7406\u5B8C\u6210`);}async handleMount(s,t){await h.mkdir(s,{recursive:!0}),await this.createFiles(s,t);}async createFiles(s,t){for(let[e,r]of Object.entries(t)){let o=g.join(s,e);"file"in r?await h.writeFile(o,r.file.contents):"directory"in r&&(await h.mkdir(o,{recursive:!0}),await this.createFiles(o,r.directory.contents));}}async checkCommandExists(s){try{return await new Promise((t,e)=>{spawn("which",[s]).on("close",o=>{o===0?t():e();});}),!0}catch{return !1}}async handleSpawn(s,t,e,r,o){let n=this.processes.get(s);if(!n)throw new Error("No process map found for socket");if(!await this.checkCommandExists(e))throw new Error(`\u547D\u4EE4 '${e}' \u672A\u5B89\u88C5\u3002\u8BF7\u786E\u4FDD\u7CFB\u7EDF\u5DF2\u5B89\u88C5\u8BE5\u547D\u4EE4\u5E76\u6DFB\u52A0\u5230 PATH \u73AF\u5883\u53D8\u91CF\u4E2D\u3002`);return new Promise((l,c)=>{let a=spawn(e,r,{cwd:t,stdio:["pipe","pipe","pipe"],shell:!0});if(!a.pid){c(new Error("Failed to get process ID"));return}let p={pid:a.pid,command:e,args:r,timestamp:Date.now()},m=this.processHistory.get(s)||[];if(m.push(p),this.processHistory.set(s,m),this.io.to(s).emit("process:started",{...p,terminalId:o}),S.isDevServerCommand(e,r)){console.log(`[ServerDetector] \u7B49\u5F85\u5F00\u53D1\u670D\u52A1\u5668\u542F\u52A8: ${e} ${r.join(" ")}`);let u=new S({workspacePath:t});u.on("server-ready",v=>{console.log("[ServerDetector] \u68C0\u6D4B\u5230\u670D\u52A1\u5668\u5C31\u7EEA:",v),this.io.to(s).emit("server:ready",{...v,command:e,args:r});});let f=!1;a.stdout.on("data",()=>{f||(f=!0,console.log("[ServerDetector] \u68C0\u6D4B\u5230\u8FDB\u7A0B\u8F93\u51FA\uFF0C\u5F00\u59CB\u7AEF\u53E3\u68C0\u6D4B..."),u.detectServerByPid(a));});}a.on("SIGINT",()=>{console.log(`Process ${a.pid} received SIGINT`),a.kill("SIGINT");}),a.stdout.on("data",u=>{let f=u.toString();console.log(`[${e}] Process ${a.pid} stdout:`,f),this.io.to(s).emit("process:output",{type:"stdout",data:f,terminalId:o});}),a.stderr.on("data",u=>{let f=u.toString();console.error(`[${e}] stderr:`,f),this.io.to(s).emit("process:output",{type:"stderr",data:f,terminalId:o});}),a.on("close",u=>{let f=this.processHistory.get(s)||[],v=f.findIndex(O=>O.pid===a.pid);v>-1&&f.splice(v,1),this.processHistory.set(s,f),this.io.to(s).emit("process:ended",{pid:a.pid,code:u}),a.pid&&n.delete(o),u!==0&&this.io.to(s).emit("process:output",{type:"exit",data:`Process exited with code ${u}`,terminalId:o}),u===0&&a.pid?l({pid:a.pid}):c(new Error(`Process exited with code ${u}`));}),a.on("error",u=>{n.delete(o),this.io.to(s).emit("process:output",{type:"stderr",data:u.message,terminalId:o}),c(u);}),n.set(o,a);})}async handleList(s,t){let e=g.join(s,t);return (await h.readdir(e,{withFileTypes:!0})).map(o=>({name:o.name,type:o.isDirectory()?"directory":"file"}))}async handleRead(s,t){let e=g.join(s,t);return h.readFile(e,"utf-8")}async handleWrite(s,t,e){let r=g.join(s,t);await h.mkdir(g.dirname(r),{recursive:!0,mode:$.DIR_MODE}),await h.writeFile(r,e,{encoding:$.ENCODING,mode:$.FILE_MODE});}async handleDelete(s,t){let e=g.join(s,t);await h.rm(e,{recursive:!0,force:!0});}async handleMkdir(s,t){let e=g.join(s,t);await h.mkdir(e,{recursive:!0});}stop(){return new Promise(async s=>{console.log("\u6B63\u5728\u505C\u6B62 WebContainer Server...");for(let[e,r]of this.watchers.entries())try{await r.close(),this.watchers.delete(e),console.log(`\u6587\u4EF6\u76D1\u542C\u5668\u5DF2\u6E05\u7406: ${e}`);}catch(o){console.error(`\u6E05\u7406\u6587\u4EF6\u76D1\u542C\u5668\u5931\u8D25 ${e}:`,o);}for(let e of this.processes.keys())this.killAllProcesses(e);console.log("\u6B63\u5728\u6E05\u7406\u5DE5\u4F5C\u533A\u76EE\u5F55...");let t=Array.from(this.workspaces.values());console.log(`\u9700\u8981\u6E05\u7406\u7684\u5DE5\u4F5C\u533A: ${t.join(", ")}`);try{if(await h.access(this.config.workspaceRoot).then(()=>!0).catch(()=>!1)){await Promise.all(t.map(async r=>{try{await h.access(r).then(()=>!0).catch(()=>!1)?(console.log(`\u6B63\u5728\u6E05\u7406\u5DE5\u4F5C\u533A: ${r}`),await h.rm(r,{recursive:!0,force:!0}),console.log(`\u5DE5\u4F5C\u533A\u5DF2\u6E05\u7406: ${r}`)):console.log(`\u5DE5\u4F5C\u533A\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u6E05\u7406: ${r}`);}catch(o){console.error(`\u6E05\u7406\u5DE5\u4F5C\u533A\u5931\u8D25 ${r}:`,o);}}));try{(await h.readdir(this.config.workspaceRoot)).length===0?(await h.rm(this.config.workspaceRoot,{recursive:!0,force:!0}),console.log(`\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55\u5DF2\u6E05\u7406: ${this.config.workspaceRoot}`)):console.log(`\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55\u975E\u7A7A\uFF0C\u4FDD\u7559: ${this.config.workspaceRoot}`);}catch(r){console.error("\u6E05\u7406\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55\u5931\u8D25:",r);}}else console.log(`\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55\u4E0D\u5B58\u5728: ${this.config.workspaceRoot}`);}catch(e){console.error("\u6E05\u7406\u5DE5\u4F5C\u533A\u65F6\u53D1\u751F\u9519\u8BEF:",e);}this.io.close(()=>{console.log("Socket.IO \u670D\u52A1\u5668\u5DF2\u5173\u95ED"),this.httpServer.close(()=>{console.log("HTTP \u670D\u52A1\u5668\u5DF2\u5173\u95ED"),this.workspaces.clear(),this.processes.clear(),console.log("\u5185\u5B58\u4E2D\u7684\u5DE5\u4F5C\u533A\u8BB0\u5F55\u5DF2\u6E05\u7406"),s();});});})}async killProcess(s,t,e){let r=this.processes.get(s);if(!r)throw new Error("No processes found for socket");let o=r.get(e);if(!o){console.warn(`No process found for terminal ${e}`);return}try{await new Promise((l,c)=>{spawn("pkill",["-TERM","-P",t.toString()]).on("close",async()=>{try{o.kill("SIGINT"),console.log(`\u8FDB\u7A0B ${t} \u5DF2\u53D1\u9001 SIGINT \u4FE1\u53F7`),await new Promise(p=>{let m=setTimeout(()=>{try{spawn("pkill",["-KILL","-P",t.toString()]),o.kill("SIGKILL"),console.log(`\u8FDB\u7A0B ${t} \u5DF2\u5F3A\u5236\u7EC8\u6B62`);}catch(d){console.error(`\u5F3A\u5236\u7EC8\u6B62\u8FDB\u7A0B ${t} \u5931\u8D25:`,d);}p();},5e3);o.once("exit",d=>{clearTimeout(m),console.log(`\u8FDB\u7A0B ${t} \u5DF2\u9000\u51FA\uFF0C\u9000\u51FA\u7801: ${d}`),p();});}),l();}catch(p){c(p);}});}),r.delete(e);let n=this.processHistory.get(s)||[],i=n.findIndex(l=>l.pid===t);i>-1&&n.splice(i,1),this.processHistory.set(s,n),this.io.to(s).emit("process:ended",{pid:t,code:0});}catch(n){throw console.error(`\u7EC8\u6B62\u8FDB\u7A0B ${t} \u5931\u8D25:`,n),n}}};var W=parseInt(process.env.PORT||"3000",10),U=process.env.HOST||"localhost",j=process.env.WORKSPACE_ROOT||g.join(process.cwd(),"workspaces"),F=new E({port:W,host:U,workspaceRoot:j}),R=!1;F.start();async function T(w){if(!R){R=!0,console.log(`
- \u6536\u5230 ${w} \u4FE1\u53F7\uFF0C\u6B63\u5728\u4F18\u96C5\u9000\u51FA...`);try{await F.stop(),console.log("\u670D\u52A1\u5668\u5DF2\u6210\u529F\u505C\u6B62"),setImmediate(()=>process.exit(0));}catch(s){console.error("\u670D\u52A1\u5668\u505C\u6B62\u65F6\u53D1\u751F\u9519\u8BEF:",s),setImmediate(()=>process.exit(1));}}}process.on("SIGTERM",()=>T("SIGTERM"));process.on("SIGINT",()=>T("SIGINT"));process.on("uncaughtException",w=>{console.error("\u672A\u6355\u83B7\u7684\u5F02\u5E38:",w),T("uncaughtException");});process.on("unhandledRejection",w=>{console.error("\u672A\u5904\u7406\u7684 Promise \u62D2\u7EDD:",w),T("unhandledRejection");});
|