feat(opencode): 改进 XCOpenCodeWeb 服务管理和健康检查

This commit is contained in:
2026-03-14 20:44:15 +08:00
parent b5343bcd9d
commit 88d42b37a6
4 changed files with 80 additions and 49 deletions

View File

@@ -1,4 +1,4 @@
import { spawn, ChildProcess } from 'child_process';
import { spawn, exec, ChildProcess } from 'child_process';
import { app } from 'electron';
import path from 'path';
import log from 'electron-log';
@@ -9,8 +9,10 @@ const HEALTH_CHECK_TIMEOUT = 2000;
class XCOpenCodeWebService {
private process: ChildProcess | null = null;
private processPid: number | null = null;
private healthCheckTimer: NodeJS.Timeout | null = null;
private _isRunning = false;
private _isStarting = false;
get port(): number {
return XCOPENCODEWEB_PORT;
@@ -81,6 +83,13 @@ class XCOpenCodeWebService {
return { success: true };
}
if (this._isStarting) {
log.info('[XCOpenCodeWebService] Already starting');
return { success: true };
}
this._isStarting = true;
try {
const exePath = this.getExePath();
const exeArgs = this.getExeArgs();
@@ -88,10 +97,10 @@ class XCOpenCodeWebService {
this.process = spawn(exePath, exeArgs, {
stdio: 'pipe',
shell: true,
detached: false,
});
this.processPid = this.process.pid ?? null;
this.process.stdout?.on('data', (data) => {
log.info(`[XCOpenCodeWeb] ${data}`);
});
@@ -103,18 +112,23 @@ class XCOpenCodeWebService {
this.process.on('error', (err) => {
log.error('[XCOpenCodeWebService] Process error:', err);
this._isRunning = false;
this._isStarting = false;
this.process = null;
this.processPid = null;
});
this.process.on('exit', (code) => {
log.info(`[XCOpenCodeWebService] Process exited with code ${code}`);
this._isRunning = false;
this._isStarting = false;
this.process = null;
this.processPid = null;
});
await new Promise<void>((resolve) => setTimeout(resolve, 2000));
this._isRunning = true;
this._isStarting = false;
this.startHealthCheck();
log.info(`[XCOpenCodeWebService] Started successfully on port ${this.port}`);
@@ -122,6 +136,7 @@ class XCOpenCodeWebService {
} catch (error: any) {
log.error('[XCOpenCodeWebService] Failed to start:', error);
this._isRunning = false;
this._isStarting = false;
return { success: false, error: error.message };
}
}
@@ -132,31 +147,28 @@ class XCOpenCodeWebService {
this.healthCheckTimer = null;
}
if (!this.process) {
if (!this.processPid) {
log.info('[XCOpenCodeWebService] Not running');
return { success: true };
}
try {
log.info('[XCOpenCodeWebService] Stopping...');
return new Promise((resolve) => {
log.info(`[XCOpenCodeWebService] Stopping process ${this.processPid}...`);
this.process.kill('SIGTERM');
await new Promise<void>((resolve) => setTimeout(resolve, 1000));
exec(`taskkill /F /PID ${this.processPid}`, (error) => {
this.process = null;
this.processPid = null;
this._isRunning = false;
if (this.process && !this.process.killed) {
this.process.kill('SIGKILL');
}
this.process = null;
this._isRunning = false;
log.info('[XCOpenCodeWebService] Stopped');
return { success: true };
} catch (error: any) {
log.error('[XCOpenCodeWebService] Failed to stop:', error);
return { success: false, error: error.message };
}
if (error) {
log.error('[XCOpenCodeWebService] Failed to stop:', error);
resolve({ success: false, error: error.message });
} else {
log.info('[XCOpenCodeWebService] Stopped');
resolve({ success: true });
}
});
});
}
}