diff options
| author | Brendan Allan <[email protected]> | 2026-03-12 16:10:52 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-03-12 08:10:52 +0000 |
| commit | b76ead3fe80a6159fdbfcc9b82c7c6318be68e7f (patch) | |
| tree | bad16ba8185403eb9dc97b6c996bbfa78ae7918b /packages/desktop-electron/src/main | |
| parent | 51835ecf90e23b34957f4dde843bbba1134f17fe (diff) | |
| download | opencode-b76ead3fe80a6159fdbfcc9b82c7c6318be68e7f.tar.gz opencode-b76ead3fe80a6159fdbfcc9b82c7c6318be68e7f.zip | |
refactor(desktop): rework default server initialization and connection handling (#16965)
Diffstat (limited to 'packages/desktop-electron/src/main')
| -rw-r--r-- | packages/desktop-electron/src/main/index.ts | 139 | ||||
| -rw-r--r-- | packages/desktop-electron/src/main/server.ts | 45 |
2 files changed, 42 insertions, 142 deletions
diff --git a/packages/desktop-electron/src/main/index.ts b/packages/desktop-electron/src/main/index.ts index 7b6acd147..64c2eb10f 100644 --- a/packages/desktop-electron/src/main/index.ts +++ b/packages/desktop-electron/src/main/index.ts @@ -31,35 +31,13 @@ import { registerIpcHandlers, sendDeepLinks, sendMenuCommand, sendSqliteMigratio import { initLogging } from "./logging" import { parseMarkdown } from "./markdown" import { createMenu } from "./menu" -import { - checkHealth, - checkHealthOrAskRetry, - getDefaultServerUrl, - getSavedServerUrl, - getWslConfig, - setDefaultServerUrl, - setWslConfig, - spawnLocalServer, -} from "./server" +import { getDefaultServerUrl, getWslConfig, setDefaultServerUrl, setWslConfig, spawnLocalServer } from "./server" import { createLoadingWindow, createMainWindow, setDockIcon } from "./windows" -type ServerConnection = - | { variant: "existing"; url: string } - | { - variant: "cli" - url: string - password: null | string - health: { - wait: Promise<void> - } - events: any - } - const initEmitter = new EventEmitter() let initStep: InitStep = { phase: "server_waiting" } let mainWindow: BrowserWindow | null = null -const loadingWindow: BrowserWindow | null = null let sidecar: CommandChild | null = null const loadingComplete = defer<void>() @@ -131,77 +109,48 @@ function setInitStep(step: InitStep) { initEmitter.emit("step", step) } -async function setupServerConnection(): Promise<ServerConnection> { - const customUrl = await getSavedServerUrl() - - if (customUrl && (await checkHealthOrAskRetry(customUrl))) { - serverReady.resolve({ url: customUrl, password: null }) - return { variant: "existing", url: customUrl } - } +async function initialize() { + const needsMigration = !sqliteFileExists() + const sqliteDone = needsMigration ? defer<void>() : undefined + let overlay: BrowserWindow | null = null const port = await getSidecarPort() const hostname = "127.0.0.1" - const localUrl = `http://${hostname}:${port}` - - if (await checkHealth(localUrl)) { - serverReady.resolve({ url: localUrl, password: null }) - return { variant: "existing", url: localUrl } - } - + const url = `http://${hostname}:${port}` const password = randomUUID() + + logger.log("spawning sidecar", { url }) const { child, health, events } = spawnLocalServer(hostname, port, password) sidecar = child - - return { - variant: "cli", - url: localUrl, + serverReady.resolve({ + url, + username: "opencode", password, - health, - events, - } -} - -async function initialize() { - const needsMigration = !sqliteFileExists() - const sqliteDone = needsMigration ? defer<void>() : undefined + }) const loadingTask = (async () => { - logger.log("setting up server connection") - const serverConnection = await setupServerConnection() - logger.log("server connection ready", { - variant: serverConnection.variant, - url: serverConnection.url, - }) - - const cliHealthCheck = (() => { - if (serverConnection.variant == "cli") { - return async () => { - const { events, health } = serverConnection - events.on("sqlite", (progress: SqliteMigrationProgress) => { - setInitStep({ phase: "sqlite_waiting" }) - if (loadingWindow) sendSqliteMigrationProgress(loadingWindow, progress) - if (mainWindow) sendSqliteMigrationProgress(mainWindow, progress) - if (progress.type === "Done") sqliteDone?.resolve() - }) - await health.wait - serverReady.resolve({ - url: serverConnection.url, - password: serverConnection.password, - }) - } - } else { - serverReady.resolve({ url: serverConnection.url, password: null }) - return null - } - })() + logger.log("sidecar connection started", { url }) - logger.log("server connection started") + events.on("sqlite", (progress: SqliteMigrationProgress) => { + setInitStep({ phase: "sqlite_waiting" }) + if (overlay) sendSqliteMigrationProgress(overlay, progress) + if (mainWindow) sendSqliteMigrationProgress(mainWindow, progress) + if (progress.type === "Done") sqliteDone?.resolve() + }) - if (cliHealthCheck) { - if (needsMigration) await sqliteDone?.promise - cliHealthCheck?.() + if (needsMigration) { + await sqliteDone?.promise } + await Promise.race([ + health.wait, + delay(30_000).then(() => { + throw new Error("Sidecar health check timed out") + }), + ]).catch((error) => { + logger.error("sidecar health check failed", error) + }) + logger.log("loading task finished") })() @@ -211,32 +160,26 @@ async function initialize() { deepLinks: pendingDeepLinks, } - const loadingWindow = await (async () => { - if (needsMigration /** TOOD: 1 second timeout */) { - // showLoading = await Promise.race([init.then(() => false).catch(() => false), delay(1000).then(() => true)]) - const loadingWindow = createLoadingWindow(globals) - await delay(1000) - return loadingWindow - } else { - logger.log("showing main window without loading window") - mainWindow = createMainWindow(globals) - wireMenu() + wireMenu() + + if (needsMigration) { + const show = await Promise.race([loadingTask.then(() => false), delay(1_000).then(() => true)]) + if (show) { + overlay = createLoadingWindow(globals) + await delay(1_000) } - })() + } await loadingTask setInitStep({ phase: "done" }) - if (loadingWindow) { + if (overlay) { await loadingComplete.promise } - if (!mainWindow) { - mainWindow = createMainWindow(globals) - wireMenu() - } + mainWindow = createMainWindow(globals) - loadingWindow?.close() + overlay?.close() } function wireMenu() { diff --git a/packages/desktop-electron/src/main/server.ts b/packages/desktop-electron/src/main/server.ts index 92018e72e..2d09d119f 100644 --- a/packages/desktop-electron/src/main/server.ts +++ b/packages/desktop-electron/src/main/server.ts @@ -1,6 +1,4 @@ -import { dialog } from "electron" - -import { getConfig, serve, type CommandChild, type Config } from "./cli" +import { serve, type CommandChild } from "./cli" import { DEFAULT_SERVER_URL_KEY, WSL_ENABLED_KEY } from "./constants" import { store } from "./store" @@ -31,15 +29,6 @@ export function setWslConfig(config: WslConfig) { store.set(WSL_ENABLED_KEY, config.enabled) } -export async function getSavedServerUrl(): Promise<string | null> { - const direct = getDefaultServerUrl() - if (direct) return direct - - const config = await getConfig().catch(() => null) - if (!config) return null - return getServerUrlFromConfig(config) -} - export function spawnLocalServer(hostname: string, port: number, password: string) { const { child, exit, events } = serve(hostname, port, password) @@ -94,36 +83,4 @@ export async function checkHealth(url: string, password?: string | null): Promis } } -export async function checkHealthOrAskRetry(url: string): Promise<boolean> { - while (true) { - if (await checkHealth(url)) return true - - const result = await dialog.showMessageBox({ - type: "warning", - message: `Could not connect to configured server:\n${url}\n\nWould you like to retry or start a local server instead?`, - title: "Connection Failed", - buttons: ["Retry", "Start Local"], - defaultId: 0, - cancelId: 1, - }) - - if (result.response === 0) continue - return false - } -} - -export function normalizeHostnameForUrl(hostname: string) { - if (hostname === "0.0.0.0") return "127.0.0.1" - if (hostname === "::") return "[::1]" - if (hostname.includes(":") && !hostname.startsWith("[")) return `[${hostname}]` - return hostname -} - -export function getServerUrlFromConfig(config: Config) { - const server = config.server - if (!server?.port) return null - const host = server.hostname ? normalizeHostnameForUrl(server.hostname) : "127.0.0.1" - return `http://${host}:${server.port}` -} - export type { CommandChild } |
