fix: confirm proxy exit before disconnect
APT build checks / build-checks (push) Successful in 36s
APT build checks / build-checks (pull_request) Successful in 38s

This commit is contained in:
2026-08-19 23:12:56 +00:00
parent f65273c7a9
commit 4a10e6051e
5 changed files with 308 additions and 52 deletions
+69 -12
View File
@@ -1,6 +1,6 @@
'use strict';
const { app, BrowserWindow, ipcMain, safeStorage, shell } = require('electron');
const { app, BrowserWindow, dialog, ipcMain, safeStorage, shell } = require('electron');
const http = require('node:http');
const path = require('node:path');
const { pathToFileURL } = require('node:url');
@@ -23,6 +23,8 @@ let bridgeServer = null;
let runtime = null;
let pairingController = null;
let firstRunPairingSecret = null;
let quitCleanupInProgress = false;
let allowConfirmedQuit = false;
function getAppDirectory() {
return app.isPackaged
@@ -83,8 +85,8 @@ function registerIpcHandlers() {
sendConnectionState();
return result;
});
registerIpc('disconnect', () => {
const state = runtime.disconnect();
registerIpc('disconnect', async () => {
const state = await runtime.disconnect();
sendConnectionState();
return state;
});
@@ -157,17 +159,72 @@ app.whenReady().then(() => {
startBridgeServer();
});
function closeBridgeServer() {
if (!bridgeServer) return Promise.resolve();
const server = bridgeServer;
return new Promise((resolve, reject) => {
const finish = (error) => {
if (!error || error.code === 'ERR_SERVER_NOT_RUNNING') {
if (bridgeServer === server) bridgeServer = null;
resolve();
return;
}
reject(error);
};
try { server.close(finish); } catch (error) { finish(error); }
});
}
async function notifyQuitBlocked(state) {
sendConnectionState();
const activeCount = state && Array.isArray(state.activeProxies) ? state.activeProxies.length : 0;
const activeProxiesRemain = activeCount > 0;
const processDetail = activeProxiesRemain
? `${activeCount} app-owned proxy process${activeCount === 1 ? '' : 'es'} remain active.`
: 'No app-owned proxy process remains active.';
const sessionDetail = state && state.connected
? ' The Alta session is still connected; resolve the process error and try quitting again.'
: ' Resolve the shutdown error and try quitting again.';
await dialog.showMessageBox({
type: 'error',
title: activeProxiesRemain ? 'Alta Camera Proxy is still running' : 'Alta Camera Proxy could not close',
message: activeProxiesRemain
? 'The app could not confirm that every proxy process exited.'
: 'The app could not complete shutdown safely.',
detail: `${processDetail}${sessionDetail}`,
buttons: ['OK'],
noLink: true,
});
}
app.on('before-quit', (event) => {
if (runtime) {
const state = runtime.disconnect();
if (state.activeProxies.length > 0) {
event.preventDefault();
sendConnectionState();
return;
if (allowConfirmedQuit) return;
event.preventDefault();
if (quitCleanupInProgress) return;
quitCleanupInProgress = true;
(async () => {
try {
const state = runtime
? await runtime.disconnect()
: { success: true, connected: false, activeProxies: [] };
if (!state.success || state.activeProxies.length > 0) {
await notifyQuitBlocked(state);
return;
}
await closeBridgeServer();
if (runtime) runtime.sessionStore.dispose();
allowConfirmedQuit = true;
app.quit();
} catch {
const state = runtime
? runtime.getConnectionState()
: { connected: false, activeProxies: [] };
await notifyQuitBlocked(state);
} finally {
quitCleanupInProgress = false;
}
runtime.sessionStore.dispose();
}
if (bridgeServer) bridgeServer.close();
})();
});
app.on('window-all-closed', () => {