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
+58
View File
@@ -7,6 +7,7 @@ import { DEFAULT_CONFIG } from './config/definitions';
import { readConfiguredWindowsMpvLaunch } from './main-entry-launch-config';
import {
configureEarlyAppPaths,
exitBackgroundBootstrap,
normalizeLaunchMpvExtraArgs,
normalizeStartupArgv,
normalizeLaunchMpvTargets,
@@ -21,10 +22,17 @@ import {
shouldHandleStatsDaemonCommandAtEntry,
hasTransportedStartupArgs,
shouldForwardStartupArgvViaAppControl,
applyBackgroundBootstrapCommandLineSwitches,
applyEarlyLinuxCommandLineSwitches,
resolveLinuxPasswordStoreValue,
} from './main-entry-runtime';
test('background bootstrap exits through Electron so Chromium children shut down', () => {
const exitCodes: number[] = [];
exitBackgroundBootstrap({ exit: (code) => exitCodes.push(code) });
assert.deepEqual(exitCodes, [0]);
});
test('normalizeStartupArgv defaults no-arg startup to --start --background on non-Windows', () => {
const originalPlatform = process.platform;
try {
@@ -151,6 +159,56 @@ test('applyEarlyLinuxCommandLineSwitches appends password store before main star
]);
});
test('background bootstrap keeps the GPU in-process so no child outlives its AppImage mount', () => {
const collect = () => {
const switches: Array<[string, string | undefined]> = [];
return {
switches,
commandLine: {
appendSwitch: (name: string, value?: string) => {
switches.push([name, value]);
},
},
};
};
const bootstrap = collect();
applyBackgroundBootstrapCommandLineSwitches(
bootstrap.commandLine,
['SubMiner.AppImage', '--start', '--background'],
{},
'linux',
);
assert.deepEqual(bootstrap.switches, [['in-process-gpu', undefined]]);
const detachedChild = collect();
applyBackgroundBootstrapCommandLineSwitches(
detachedChild.commandLine,
['SubMiner.AppImage', '--start', '--background'],
{ SUBMINER_BACKGROUND_CHILD: '1' },
'linux',
);
assert.deepEqual(detachedChild.switches, []);
const foreground = collect();
applyBackgroundBootstrapCommandLineSwitches(
foreground.commandLine,
['SubMiner.AppImage', '--stop'],
{},
'linux',
);
assert.deepEqual(foreground.switches, []);
const windows = collect();
applyBackgroundBootstrapCommandLineSwitches(
windows.commandLine,
['SubMiner.exe', '--start', '--background'],
{},
'win32',
);
assert.deepEqual(windows.switches, []);
});
test('transported AppImage visibility commands forward through app control', () => {
assert.equal(
shouldForwardStartupArgvViaAppControl(['SubMiner.AppImage', '--hide-visible-overlay'], {