const { app, BrowserWindow, dialog, shell } = require("electron"); const { spawn } = require("node:child_process"); const fs = require("node:fs"); const path = require("node:path"); const readline = require("node:readline"); let mainWindow = null; let backendProcess = null; app.disableHardwareAcceleration(); app.commandLine.appendSwitch("ozone-platform-hint", "auto"); function backendBinary() { const candidates = [ path.join(process.resourcesPath || "", "bin", "lazy-update-manager"), path.join(app.getAppPath(), "bin", "lazy-update-manager"), path.join(app.getAppPath(), "..", "bin", "lazy-update-manager"), ]; for (const candidate of candidates) { if (candidate && fs.existsSync(candidate)) { return candidate; } } return "lazy-update-manager"; } function startBackend() { return new Promise((resolve, reject) => { const binary = backendBinary(); backendProcess = spawn(binary, ["gui", "-no-open"], { stdio: ["ignore", "pipe", "pipe"], env: process.env, }); let stderr = ""; const rl = readline.createInterface({ input: backendProcess.stdout }); // Give the backend more time to start and report the URL (20s) const timeout = setTimeout(() => { // include any captured stderr to aid debugging const detail = stderr ? ("\nBackend stderr:\n" + stderr) : ""; reject(new Error("Backend did not report a GUI URL." + detail)); }, 20000); rl.on("line", (line) => { console.log("backend stdout:", line); const match = line.match(/LazyUpdateManager GUI:\s+(http:\/\/127\.0\.0\.1:\d+)/); if (!match) { return; } clearTimeout(timeout); console.log("backend reported GUI URL:", match[1]); resolve(match[1]); }); backendProcess.stderr.on("data", (chunk) => { const s = chunk.toString(); stderr += s; console.error("backend stderr:", s); }); backendProcess.on("error", (error) => { clearTimeout(timeout); reject(error); }); backendProcess.on("exit", (code) => { if (mainWindow) { return; } clearTimeout(timeout); reject(new Error(stderr || `Backend exited with code ${code}`)); }); }); } async function createWindow() { // If LAZY_BACKEND_URL is set, use it (helps debugging a separately started backend) let url = process.env.LAZY_BACKEND_URL || null; if (!url) { url = await startBackend(); } else { console.log('Using LAZY_BACKEND_URL:', url); } mainWindow = new BrowserWindow({ width: 1180, height: 760, minWidth: 860, minHeight: 560, title: "LazyUpdateManager", backgroundColor: "#101114", autoHideMenuBar: true, webPreferences: { contextIsolation: true, nodeIntegration: false, sandbox: true, }, }); mainWindow.webContents.setWindowOpenHandler(({ url: targetURL }) => { shell.openExternal(targetURL); return { action: "deny" }; }); await mainWindow.loadURL(url); } function stopBackend() { if (!backendProcess || backendProcess.killed) { return; } backendProcess.kill("SIGTERM"); backendProcess = null; } app.whenReady().then(async () => { try { await createWindow(); } catch (error) { // Avoid noisy GUI popups when the backend fails. Log the error and quit. console.error('Desktop app startup failed:', error && error.message ? error.message : error); app.quit(); } }); app.on("window-all-closed", () => { stopBackend(); app.quit(); }); app.on("before-quit", stopBackend);