feat: 将 OpenCode 服务管理抽取为独立模块

- 创建 electron/services/opencodeService.ts 独立服务模块
- 支持健康检测(每10秒)、自动重启(最多3次)
- 随软件生命周期自动启动/停止
This commit is contained in:
2026-03-13 20:30:02 +08:00
parent e6c41491b3
commit 8d4a9a3704
2 changed files with 187 additions and 54 deletions

View File

@@ -5,8 +5,8 @@ import fs from 'fs';
import log from 'electron-log';
import { generatePdf } from './services/pdfGenerator';
import { selectHtmlFile } from './services/htmlImport';
import { opencodeService } from './services/opencodeService';
import { electronState } from './state';
import { spawn, ChildProcess } from 'child_process';
log.initialize();
@@ -15,9 +15,6 @@ const __dirname = path.dirname(__filename);
electronState.setDevelopment(!app.isPackaged);
let opencodeProcess: ChildProcess | null = null;
const OPENCODE_PORT = 4096;
let lastClipboardText = '';
function startClipboardWatcher() {
@@ -352,60 +349,16 @@ ipcMain.handle('remote-download-file', async (_event, id: string, serverHost: st
}
});
ipcMain.handle('opencode-get-status', () => {
return opencodeService.getStatus();
});
ipcMain.handle('opencode-start-server', async () => {
if (opencodeProcess) {
log.info('Opencode server already running');
return { success: true, port: OPENCODE_PORT };
}
try {
log.info('Starting opencode server...');
opencodeProcess = spawn('opencode', ['serve'], {
stdio: 'pipe',
shell: true,
detached: false,
});
opencodeProcess.stdout?.on('data', (data) => {
log.info(`[opencode] ${data}`);
});
opencodeProcess.stderr?.on('data', (data) => {
log.error(`[opencode error] ${data}`);
});
opencodeProcess.on('error', (err) => {
log.error('Opencode process error:', err);
opencodeProcess = null;
});
opencodeProcess.on('exit', (code) => {
log.info(`Opencode process exited with code ${code}`);
opencodeProcess = null;
});
return { success: true, port: OPENCODE_PORT };
} catch (error: any) {
log.error('Failed to start opencode server:', error);
return { success: false, error: error.message };
}
return await opencodeService.start();
});
ipcMain.handle('opencode-stop-server', async () => {
if (!opencodeProcess) {
log.info('Opencode server not running');
return { success: true };
}
try {
log.info('Stopping opencode server...');
opencodeProcess.kill('SIGTERM');
opencodeProcess = null;
return { success: true };
} catch (error: any) {
log.error('Failed to stop opencode server:', error);
return { success: false, error: error.message };
}
return await opencodeService.stop();
});
async function startServer() {
@@ -444,6 +397,9 @@ app.whenReady().then(async () => {
}
await startServer();
await opencodeService.start();
await createWindow();
startClipboardWatcher();
@@ -473,6 +429,7 @@ app.whenReady().then(async () => {
app.on('window-all-closed', () => {
globalShortcut.unregisterAll();
opencodeService.stop();
if (process.platform !== 'darwin') {
app.quit();
}