fix(desktop): guard destroyed recovery windows (#37406)
This commit is contained in:
parent
08fb473735
commit
4436678f7d
4 changed files with 38 additions and 11 deletions
|
|
@ -33,6 +33,7 @@ import {
|
||||||
type SidecarListener,
|
type SidecarListener,
|
||||||
} from "./server"
|
} from "./server"
|
||||||
import { setupAutoUpdater, showUpdaterDialog } from "./updater"
|
import { setupAutoUpdater, showUpdaterDialog } from "./updater"
|
||||||
|
import { safeWebContentsURL } from "./window-state"
|
||||||
import {
|
import {
|
||||||
getLastFocusedWindow,
|
getLastFocusedWindow,
|
||||||
registerRendererProtocol,
|
registerRendererProtocol,
|
||||||
|
|
@ -233,7 +234,7 @@ const main = Effect.gen(function* () {
|
||||||
})
|
})
|
||||||
|
|
||||||
app.on("render-process-gone", (_event, webContents, details) => {
|
app.on("render-process-gone", (_event, webContents, details) => {
|
||||||
writeLog("window", "app render process gone", { url: webContents.getURL(), details }, "error")
|
writeLog("window", "app render process gone", { url: safeWebContentsURL(webContents), details }, "error")
|
||||||
})
|
})
|
||||||
|
|
||||||
setRelaunchHandler(() => {
|
setRelaunchHandler(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import type { BrowserWindow } from "electron"
|
import type { BrowserWindow } from "electron"
|
||||||
import { write as writeLog } from "./logging"
|
import { write as writeLog } from "./logging"
|
||||||
|
import { safeWindowURL } from "./window-state"
|
||||||
|
|
||||||
const sampleInterval = 1000
|
const sampleInterval = 1000
|
||||||
const samplePeriod = 15000
|
const samplePeriod = 15000
|
||||||
|
|
@ -46,7 +47,7 @@ export function createUnresponsiveSampler(win: BrowserWindow, name: string) {
|
||||||
const message = [
|
const message = [
|
||||||
"renderer unresponsive samples",
|
"renderer unresponsive samples",
|
||||||
`Window: ${name}`,
|
`Window: ${name}`,
|
||||||
`URL: ${win.isDestroyed() ? "<destroyed>" : win.webContents.getURL()}`,
|
`URL: ${safeWindowURL(win)}`,
|
||||||
...entries.map((entry) => `<${entry[1]}> ${entry[0]}`),
|
...entries.map((entry) => `<${entry[1]}> ${entry[0]}`),
|
||||||
`Total Samples: ${total}`,
|
`Total Samples: ${total}`,
|
||||||
].join("\n")
|
].join("\n")
|
||||||
|
|
|
||||||
29
packages/desktop/src/main/window-state.ts
Normal file
29
packages/desktop/src/main/window-state.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
export const destroyedWindowURL = "<destroyed>"
|
||||||
|
|
||||||
|
type WebContentsURLState = {
|
||||||
|
isDestroyed(): boolean
|
||||||
|
getURL(): string
|
||||||
|
}
|
||||||
|
|
||||||
|
type WindowURLState = {
|
||||||
|
isDestroyed(): boolean
|
||||||
|
readonly webContents: WebContentsURLState
|
||||||
|
}
|
||||||
|
|
||||||
|
export function safeWebContentsURL(webContents: WebContentsURLState) {
|
||||||
|
try {
|
||||||
|
if (webContents.isDestroyed()) return destroyedWindowURL
|
||||||
|
return webContents.getURL()
|
||||||
|
} catch {
|
||||||
|
return destroyedWindowURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function safeWindowURL(win: WindowURLState) {
|
||||||
|
try {
|
||||||
|
if (win.isDestroyed()) return destroyedWindowURL
|
||||||
|
return safeWebContentsURL(win.webContents)
|
||||||
|
} catch {
|
||||||
|
return destroyedWindowURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ import { getStore, removeStoreFile } from "./store"
|
||||||
import { PINCH_ZOOM_ENABLED_KEY, WINDOW_IDS_KEY } from "./store-keys"
|
import { PINCH_ZOOM_ENABLED_KEY, WINDOW_IDS_KEY } from "./store-keys"
|
||||||
import { createUnresponsiveSampler } from "./unresponsive"
|
import { createUnresponsiveSampler } from "./unresponsive"
|
||||||
import { createWindowRegistry } from "./window-registry"
|
import { createWindowRegistry } from "./window-registry"
|
||||||
|
import { safeWindowURL } from "./window-state"
|
||||||
|
|
||||||
const root = dirname(fileURLToPath(import.meta.url))
|
const root = dirname(fileURLToPath(import.meta.url))
|
||||||
const rendererRoot = join(root, "../renderer")
|
const rendererRoot = join(root, "../renderer")
|
||||||
|
|
@ -364,7 +365,7 @@ function wireWindowRecovery(win: BrowserWindow, name: string) {
|
||||||
errorCode,
|
errorCode,
|
||||||
errorDescription,
|
errorDescription,
|
||||||
validatedURL,
|
validatedURL,
|
||||||
currentURL: win.webContents.getURL(),
|
currentURL: safeWindowURL(win),
|
||||||
isMainFrame,
|
isMainFrame,
|
||||||
},
|
},
|
||||||
"error",
|
"error",
|
||||||
|
|
@ -386,12 +387,7 @@ function wireWindowRecovery(win: BrowserWindow, name: string) {
|
||||||
})
|
})
|
||||||
win.webContents.on("render-process-gone", (_event, details) => {
|
win.webContents.on("render-process-gone", (_event, details) => {
|
||||||
sampler.stopAndFlush()
|
sampler.stopAndFlush()
|
||||||
writeLog(
|
writeLog("window", "renderer process gone", { window: name, currentURL: safeWindowURL(win), details }, "error")
|
||||||
"window",
|
|
||||||
"renderer process gone",
|
|
||||||
{ window: name, currentURL: win.webContents.getURL(), details },
|
|
||||||
"error",
|
|
||||||
)
|
|
||||||
void show(
|
void show(
|
||||||
"OpenCode window terminated unexpectedly",
|
"OpenCode window terminated unexpectedly",
|
||||||
[`Window: ${name}`, `Reason: ${details.reason}`, `Code: ${details.exitCode ?? "<unknown>"}`].join("\n"),
|
[`Window: ${name}`, `Reason: ${details.reason}`, `Code: ${details.exitCode ?? "<unknown>"}`].join("\n"),
|
||||||
|
|
@ -399,12 +395,12 @@ function wireWindowRecovery(win: BrowserWindow, name: string) {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
win.on("unresponsive", () => {
|
win.on("unresponsive", () => {
|
||||||
writeLog("window", "renderer unresponsive", { window: name, currentURL: win.webContents.getURL() }, "error")
|
writeLog("window", "renderer unresponsive", { window: name, currentURL: safeWindowURL(win) }, "error")
|
||||||
sampler.start()
|
sampler.start()
|
||||||
void show("OpenCode is not responding", "You can relaunch the app, open the logs, or keep waiting.", true)
|
void show("OpenCode is not responding", "You can relaunch the app, open the logs, or keep waiting.", true)
|
||||||
})
|
})
|
||||||
win.on("responsive", () => {
|
win.on("responsive", () => {
|
||||||
writeLog("window", "renderer responsive", { window: name, currentURL: win.webContents.getURL() }, "error")
|
writeLog("window", "renderer responsive", { window: name, currentURL: safeWindowURL(win) }, "error")
|
||||||
sampler.stopAndFlush()
|
sampler.stopAndFlush()
|
||||||
})
|
})
|
||||||
win.webContents.on("console-message", (_event, level, message, line, sourceId) => {
|
win.webContents.on("console-message", (_event, level, message, line, sourceId) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue