feat: 添加发现设备页面

This commit is contained in:
2026-04-10 11:25:40 +08:00
parent 4d578b3f0b
commit 582b9e10fa
8 changed files with 129 additions and 11 deletions

View File

@@ -4,9 +4,43 @@ import fs from 'node:fs';
import net from 'node:net';
import { spawn } from 'node:child_process';
import started from 'electron-squirrel-startup';
import { Bonjour } from 'bonjour-service';
if (started) app.quit();
// ========== Bonjour 服务发现 ==========
const bonjour = new Bonjour();
let discoveredServices = new Map();
function getDiscoveredServices() {
return Array.from(discoveredServices.values());
}
function startBonjourDiscovery() {
const browser = bonjour.find({});
browser.on('up', (service) => {
console.log('[bonjour] Service up:', service.name);
discoveredServices.set(service.fqdn, service);
notifyServicesChanged();
});
browser.on('down', (service) => {
console.log('[bonjour] Service down:', service.name);
discoveredServices.delete(service.fqdn);
notifyServicesChanged();
});
return browser;
}
function notifyServicesChanged() {
const services = getDiscoveredServices();
BrowserWindow.getAllWindows().forEach((win) => {
win.webContents.send('bonjour:services-updated', services);
});
}
// ========== OpenCode 服务管理 ==========
const DEFAULT_PORT = 4096;
let opencodeProcess = null;
@@ -36,7 +70,10 @@ function waitForReady(port, timeout = 15000) {
const start = Date.now();
const check = () => {
const socket = net.createConnection({ port, host: '127.0.0.1' });
socket.once('connect', () => { socket.end(); resolve(); });
socket.once('connect', () => {
socket.end();
resolve();
});
socket.once('error', () => {
socket.destroy();
if (Date.now() - start >= timeout) return reject(new Error('OpenCode 服务启动超时'));
@@ -92,7 +129,9 @@ async function startOpencode() {
});
opencodeProcess.stdout?.on('data', (d) => console.log(`[opencode] ${d.toString().trim()}`));
opencodeProcess.stderr?.on('data', (d) => console.error(`[opencode error] ${d.toString().trim()}`));
opencodeProcess.stderr?.on('data', (d) =>
console.error(`[opencode error] ${d.toString().trim()}`)
);
opencodeProcess.once('error', (e) => console.error('[opencode spawn error]', e));
opencodeProcess.once('close', (code) => {
console.log(`[opencode exited] code=${code}`);
@@ -126,7 +165,10 @@ function stopOpencode() {
// ========== IPC Handlers ==========
function registerIpcHandlers() {
ipcMain.handle('opencode:start', () => startOpencode());
ipcMain.handle('opencode:stop', () => { stopOpencode(); return buildInfo(); });
ipcMain.handle('opencode:stop', () => {
stopOpencode();
return buildInfo();
});
ipcMain.handle('opencode:info', () => buildInfo());
ipcMain.handle('opencode:port', () => opencodePort);
@@ -158,6 +200,9 @@ function registerIpcHandlers() {
if (!res.ok) throw new Error(`发送消息失败: ${res.status}`);
return res.json();
});
// Bonjour
ipcMain.handle('bonjour:get-services', () => getDiscoveredServices());
}
// ========== 窗口 ==========
@@ -195,14 +240,13 @@ const createWindow = () => {
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
} else {
mainWindow.loadFile(
path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`)
);
mainWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`));
}
};
app.whenReady().then(() => {
registerIpcHandlers();
startBonjourDiscovery();
createWindow();
app.on('activate', () => {