fix(anki,appimage): handle proxy port conflicts and stray GPU child

- AnkiConnect proxy now detects EADDRINUSE, logs a warning, and surfaces an overlay notification instead of crashing video startup
- Background AppImage bootstrap runs Chromium with in-process-gpu so no GPU child survives app.exit() and outlives the FUSE mount, fixing the remaining DrKonqi "Service Crash" case
- Add changelog fragment for the proxy fix; update the AppImage quit fragment with the GPU child root cause
This commit is contained in:
2026-07-17 23:04:56 -07:00
parent 2398f5c030
commit 44959ed282
9 changed files with 210 additions and 2 deletions
+24
View File
@@ -35,6 +35,10 @@ type EarlyAppLike = {
setPath: (name: 'userData', value: string) => void;
};
type BackgroundBootstrapAppLike = {
exit: (code: number) => void;
};
type CommandLineLike = {
appendSwitch: (name: string, value?: string) => void;
};
@@ -132,6 +136,22 @@ export function applyEarlyLinuxCommandLineSwitches(
);
}
// The detach bootstrap exits within milliseconds, but a separate GPU child it
// spawned survives app.exit() and keeps executing from the bootstrap's FUSE
// mount until session teardown finally unmaps it — SIGBUS, surfaced by DrKonqi
// as a "Service Crash" notification on every video close. Keeping the GPU
// in-process means the bootstrap leaves no child behind.
export function applyBackgroundBootstrapCommandLineSwitches(
commandLine: CommandLineLike,
argv: string[],
env: NodeJS.ProcessEnv,
platform: NodeJS.Platform = process.platform,
): void {
if (platform !== 'linux') return;
if (!shouldDetachBackgroundLaunch(argv, env)) return;
commandLine.appendSwitch('in-process-gpu');
}
function consumesLaunchMpvValue(token: string): boolean {
return (
token.startsWith('--') &&
@@ -241,6 +261,10 @@ export function shouldDetachBackgroundLaunch(argv: string[], env: NodeJS.Process
return true;
}
export function exitBackgroundBootstrap(app: BackgroundBootstrapAppLike): void {
app.exit(0);
}
export function shouldHandleHelpOnlyAtEntry(argv: string[], env: NodeJS.ProcessEnv): boolean {
if (env.ELECTRON_RUN_AS_NODE === '1') return false;
const args = parseCliArgs(argv);