From 42a298925b06941008b4d7c92049fba242319aa6 Mon Sep 17 00:00:00 2001 From: Pandipipas Date: Sun, 31 May 2026 16:24:14 +0200 Subject: [PATCH] Investigating Electron Startup Failures --- docs/architecture.md | 9 +++--- package.json | 2 +- src/main/app/application-controller.ts | 8 ------ src/main/app/bootstrap.ts | 1 - src/tests/application-controller.test.ts | 35 ++++++++++++++++-------- 5 files changed, 28 insertions(+), 27 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 8f5edf0..655d985 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -5,11 +5,10 @@ 1. `src/main/main.ts` loads `appConfig` from `config/runtime-config.ts`. 2. Installs or refreshes the packaged NodeCG runtime in user data when needed (`nodecg/runtime-provisioner.ts`). 3. Creates windows (`windows/window-factory.ts`). -4. In packaged builds, relaunches once after a fresh runtime install so NodeCG starts from a settled user-data runtime. -5. Starts NodeCG with `nodecg/process-manager.ts`. -6. Waits for HTTP readiness and shows loading -> main dashboard. -7. Checks the configured Gitea latest-release endpoint for optional updates. -8. On shutdown, runs a single graceful-stop flow to avoid orphan processes. +4. Starts NodeCG with `nodecg/process-manager.ts`. +5. Waits for HTTP readiness and shows loading -> main dashboard. +6. Checks the configured Gitea latest-release endpoint for optional updates. +7. On shutdown, runs a single graceful-stop flow to avoid orphan processes. ## Main modules diff --git a/package.json b/package.json index 37e745e..816aee5 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ ], "icon": "static/icons/icon.ico", "executableName": "scoreko", - "signAndEditExecutable": false + "signAndEditExecutable": true }, "nsis": { "oneClick": false, diff --git a/src/main/app/application-controller.ts b/src/main/app/application-controller.ts index fae32a5..c747592 100644 --- a/src/main/app/application-controller.ts +++ b/src/main/app/application-controller.ts @@ -36,7 +36,6 @@ export type ApplicationControllerConfig = { bundleName: string; log: (...args: unknown[]) => void; }) => PreparedNodecgRuntime; - relaunch: () => void; scheduleUpdateCheck: (config: { getParentWindow: () => ApplicationWindow | null; beforeInstall: () => Promise; @@ -129,13 +128,6 @@ export function createApplicationController({ log: deps.log, }); - if (preparedRuntime.installed && isPackaged) { - deps.log("Runtime was installed or refreshed; relaunching Scoreko before starting NodeCG."); - deps.relaunch(); - deps.exit(0); - state = "stopped"; - return; - } nodecgManager = deps.createNodecgProcessManager(preparedRuntime.runtimePath); diff --git a/src/main/app/bootstrap.ts b/src/main/app/bootstrap.ts index 26ee8ee..5d2b22b 100644 --- a/src/main/app/bootstrap.ts +++ b/src/main/app/bootstrap.ts @@ -61,7 +61,6 @@ export function bootstrap(): void { getAllWindows: () => BrowserWindow.getAllWindows(), log, prepareRuntime: prepareUserNodecgRuntime, - relaunch: () => app.relaunch(), scheduleUpdateCheck: ({ getParentWindow, beforeInstall }) => { scheduleUpdateCheck({ appConfig, diff --git a/src/tests/application-controller.test.ts b/src/tests/application-controller.test.ts index f0fb07a..f2af329 100644 --- a/src/tests/application-controller.test.ts +++ b/src/tests/application-controller.test.ts @@ -114,7 +114,6 @@ test("ApplicationController preserves startup ordering and schedules updates aft events.push("prepare-runtime"); return { runtimePath: "/user-data/scoreko/nodecg", installed: false }; }, - relaunch: () => events.push("relaunch"), scheduleUpdateCheck: () => events.push("schedule-update"), setAppUserModelId: () => events.push("set-app-user-model-id"), exit: (code) => events.push(`exit:${code}`), @@ -145,7 +144,7 @@ test("ApplicationController preserves startup ordering and schedules updates aft ]); }); -test("ApplicationController relaunches packaged app after runtime install before starting NodeCG", async () => { +test("ApplicationController directly launches packaged app after runtime install without relaunching", async () => { const events: string[] = []; const controller = createApplicationController({ appConfig: getBaseConfig(), @@ -162,31 +161,45 @@ test("ApplicationController relaunches packaged app after runtime install before }, deps: { createLoadingWindow: () => { - throw new Error("window creation should wait until after relaunch decisions"); + events.push("create-loading"); + return new MockWindow("loading", events); }, createMainWindow: () => { - throw new Error("window creation should wait until after relaunch decisions"); + events.push("create-main"); + return new MockWindow("main", events); }, createNodecgProcessManager: () => { - throw new Error("NodeCG should not start before relaunch"); + events.push("create-manager"); + return createMockManager(events); }, getAllWindows: () => [], log: (...args) => events.push(String(args[0])), prepareRuntime: () => ({ runtimePath: "/user-data/scoreko/nodecg", installed: true }), - relaunch: () => events.push("relaunch"), scheduleUpdateCheck: () => events.push("schedule-update"), setAppUserModelId: () => events.push("set-app-user-model-id"), exit: (code) => events.push(`exit:${code}`), + now: () => 0, + sleep: async (ms) => { + events.push(`sleep:${ms}`); + }, }, }); await controller.launch(); - assert.equal(controller.getState(), "stopped"); + assert.equal(controller.getState(), "ready"); assert.deepEqual(events, [ - "Runtime was installed or refreshed; relaunching Scoreko before starting NodeCG.", - "relaunch", - "exit:0", + "create-manager", + "create-main", + "create-loading", + "start-nodecg", + "wait-nodecg", + "loading:load:http://localhost:9090/loading", + "loading:show", + "main:load:http://localhost:9090/main", + "main:show", + "loading:close", + "schedule-update", ]); }); @@ -215,7 +228,6 @@ test("ApplicationController activation before readiness routes through launch", events.push("prepare-runtime"); return { runtimePath: "/user-data/scoreko/nodecg", installed: false }; }, - relaunch: () => events.push("relaunch"), scheduleUpdateCheck: () => events.push("schedule-update"), setAppUserModelId: () => events.push("set-app-user-model-id"), exit: (code) => events.push(`exit:${code}`), @@ -253,7 +265,6 @@ test("ApplicationController shutdown is idempotent", async () => { getAllWindows: () => [], log: () => undefined, prepareRuntime: () => ({ runtimePath: "/user-data/scoreko/nodecg", installed: false }), - relaunch: () => events.push("relaunch"), scheduleUpdateCheck: () => events.push("schedule-update"), setAppUserModelId: () => events.push("set-app-user-model-id"), exit: (code) => events.push(`exit:${code}`),