feat(remote): 添加 XCOpenCodeWeb 服务管理
- 新增 XCOpenCodeWebService.js 服务模块 - 支持启动/停止/健康检测(每10秒) - 随 remote 服务启动/退出 - 配置文件添加 xcopencodeweb 配置 - 修复 opencode 默认端口配置
This commit is contained in:
@@ -28,8 +28,11 @@
|
||||
"configPath": "./frp/frpc.toml"
|
||||
},
|
||||
"opencode": {
|
||||
"enabled": true
|
||||
},
|
||||
"xcopencodeweb": {
|
||||
"enabled": true,
|
||||
"port": 3002
|
||||
"port": 9999
|
||||
},
|
||||
"gitea": {
|
||||
"enabled": true
|
||||
|
||||
@@ -124,7 +124,17 @@ class App {
|
||||
const opencodeConfig = config.getSection('opencode') || {};
|
||||
return new OpenCodeService({
|
||||
enabled: opencodeConfig.enabled !== false,
|
||||
port: opencodeConfig.port || 3002
|
||||
port: opencodeConfig.port
|
||||
});
|
||||
});
|
||||
|
||||
this.container.register('xcOpenCodeWebService', (c) => {
|
||||
const XCOpenCodeWebService = require('../services/opencode/XCOpenCodeWebService');
|
||||
const config = c.resolve('config');
|
||||
const xcopencodewebConfig = config.getSection('xcopencodeweb') || {};
|
||||
return new XCOpenCodeWebService({
|
||||
enabled: xcopencodewebConfig.enabled !== false,
|
||||
port: xcopencodewebConfig.port
|
||||
});
|
||||
});
|
||||
|
||||
@@ -206,6 +216,10 @@ class App {
|
||||
openCodeService.start();
|
||||
logger.info('OpenCode service started');
|
||||
|
||||
const xcOpenCodeWebService = this.container.resolve('xcOpenCodeWebService');
|
||||
xcOpenCodeWebService.start();
|
||||
logger.info('XCOpenCodeWeb service started');
|
||||
|
||||
const giteaService = this.container.resolve('giteaService');
|
||||
giteaService.start();
|
||||
logger.info('Gitea service started');
|
||||
@@ -488,6 +502,10 @@ class App {
|
||||
openCodeService.stop();
|
||||
logger.info('OpenCode service stopped');
|
||||
|
||||
const xcOpenCodeWebService = this.container.resolve('xcOpenCodeWebService');
|
||||
xcOpenCodeWebService.stop();
|
||||
logger.info('XCOpenCodeWeb service stopped');
|
||||
|
||||
const giteaService = this.container.resolve('giteaService');
|
||||
giteaService.stop();
|
||||
logger.info('Gitea service stopped');
|
||||
|
||||
149
remote/src/services/opencode/XCOpenCodeWebService.js
Normal file
149
remote/src/services/opencode/XCOpenCodeWebService.js
Normal file
@@ -0,0 +1,149 @@
|
||||
const { spawn } = require('child_process');
|
||||
const path = require('path');
|
||||
const logger = require('../../utils/logger');
|
||||
|
||||
class XCOpenCodeWebService {
|
||||
constructor(options = {}) {
|
||||
this.process = null;
|
||||
this.isRunning = false;
|
||||
this.port = options.port || 9999;
|
||||
this.enabled = options.enabled !== false;
|
||||
this.healthCheckInterval = 10000;
|
||||
this.healthCheckTimeout = 2000;
|
||||
this.healthCheckTimer = null;
|
||||
}
|
||||
|
||||
getExePath() {
|
||||
const exeName = 'XCOpenCodeWeb.exe';
|
||||
const basePath = path.join(__dirname, '../../xcopencodeweb');
|
||||
return path.join(basePath, exeName);
|
||||
}
|
||||
|
||||
getExeArgs() {
|
||||
return ['--port', this.port.toString()];
|
||||
}
|
||||
|
||||
async checkHealth() {
|
||||
try {
|
||||
const timeoutMs = this.healthCheckTimeout;
|
||||
|
||||
const fetchPromise = fetch(`http://127.0.0.1:${this.port}`);
|
||||
const timeoutPromise = new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Timeout')), timeoutMs)
|
||||
);
|
||||
|
||||
const response = await Promise.race([fetchPromise, timeoutPromise]);
|
||||
return response.ok || response.status === 401;
|
||||
} catch (error) {
|
||||
logger.warn('[XCOpenCodeWebService] Health check failed:', error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
startHealthCheck() {
|
||||
if (this.healthCheckTimer) {
|
||||
clearInterval(this.healthCheckTimer);
|
||||
}
|
||||
|
||||
this.healthCheckTimer = setInterval(async () => {
|
||||
const isHealthy = await this.checkHealth();
|
||||
if (!isHealthy && this.isRunning) {
|
||||
logger.warn('[XCOpenCodeWebService] Service not responding');
|
||||
}
|
||||
}, this.healthCheckInterval);
|
||||
}
|
||||
|
||||
stopHealthCheck() {
|
||||
if (this.healthCheckTimer) {
|
||||
clearInterval(this.healthCheckTimer);
|
||||
this.healthCheckTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
if (!this.enabled) {
|
||||
logger.info('XCOpenCodeWeb service is disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isRunning && this.process) {
|
||||
logger.warn('XCOpenCodeWeb service is already running');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const exePath = this.getExePath();
|
||||
const exeArgs = this.getExeArgs();
|
||||
logger.info(`[XCOpenCodeWebService] Starting from: ${exePath} with args: ${exeArgs.join(' ')}`);
|
||||
|
||||
this.process = spawn(exePath, exeArgs, {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
detached: false,
|
||||
});
|
||||
|
||||
this.process.stdout.on('data', (data) => {
|
||||
const output = data.toString().trim();
|
||||
if (output) {
|
||||
logger.info(`[XCOpenCodeWeb] ${output}`);
|
||||
}
|
||||
});
|
||||
|
||||
this.process.stderr.on('data', (data) => {
|
||||
const output = data.toString().trim();
|
||||
if (output) {
|
||||
logger.error(`[XCOpenCodeWeb error] ${output}`);
|
||||
}
|
||||
});
|
||||
|
||||
this.process.on('error', (error) => {
|
||||
logger.error('[XCOpenCodeWebService] Process error', { error: error.message });
|
||||
this.isRunning = false;
|
||||
this.process = null;
|
||||
});
|
||||
|
||||
this.process.on('exit', (code) => {
|
||||
logger.info('[XCOpenCodeWebService] Process exited', { code });
|
||||
this.isRunning = false;
|
||||
this.process = null;
|
||||
});
|
||||
|
||||
this.isRunning = true;
|
||||
this.startHealthCheck();
|
||||
|
||||
logger.info(`[XCOpenCodeWebService] Started successfully on port ${this.port}`);
|
||||
} catch (error) {
|
||||
logger.error('[XCOpenCodeWebService] Failed to start', { error: error.message });
|
||||
this.isRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.stopHealthCheck();
|
||||
|
||||
if (!this.process) {
|
||||
logger.info('[XCOpenCodeWebService] Not running');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info('[XCOpenCodeWebService] Stopping...');
|
||||
|
||||
this.process.kill();
|
||||
this.process = null;
|
||||
this.isRunning = false;
|
||||
|
||||
logger.info('[XCOpenCodeWebService] Stopped');
|
||||
} catch (error) {
|
||||
logger.error('[XCOpenCodeWebService] Failed to stop', { error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
getStatus() {
|
||||
return {
|
||||
running: this.isRunning,
|
||||
port: this.port
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = XCOpenCodeWebService;
|
||||
Reference in New Issue
Block a user