Skip to content

Commit bd82f69

Browse files
authored
fix: handle quit with proper cleanup (#223)
* wip: bring back changes from #191 * chore: remove unnecessary debug config * fix: make sure getReadyQuit doesn't indefinitely hang if bg window dies out for some reason
1 parent 9715cff commit bd82f69

File tree

14 files changed

+157
-170
lines changed

14 files changed

+157
-170
lines changed

src/lib/autoupdate/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class AutoUpdate {
9393
ipcMain.handle("quit-and-install", () => {
9494
log.info("recieved quit and install")
9595
global.quitAndInstall = true;
96-
let res = autoUpdater.quitAndInstall();
96+
const res = autoUpdater.quitAndInstall();
9797
log.info("finished quit and install", res)
9898
});
9999
};

src/main/actions/cleanup.js

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
const { app, ipcMain } = require("electron");
22

3-
export const cleanupAndQuit = () => {
4-
cleanup();
5-
6-
if (global.backgroundWindow) {
7-
ipcMain.on("shutdown-success", () => {
8-
console.log("shudown sucess");
9-
app.quit();
10-
});
11-
}
12-
};
13-
143
const cleanup = () => {
15-
if (global.backgroundWindow) {
16-
global.backgroundWindow.webContents.send("shutdown");
4+
if(global.backgroundProcessStarted) {
5+
if (global.backgroundWindow) {
6+
global.backgroundWindow.webContents.send("shutdown");
7+
} else {
8+
// No backgroundWindow. Quit directly without cleanup
9+
app.quit();
10+
}
1711
} else {
18-
// No backgroundWindow. Quit directly without cleanup
1912
app.quit();
2013
}
2114
};
15+
16+
17+
export const getReadyToQuitApp = async () => {
18+
return new Promise((resolve) => {
19+
cleanup();
20+
21+
if (global.backgroundWindow) {
22+
ipcMain.once("shutdown-success", () => {
23+
console.log("shudown sucess");
24+
global.backgroundWindow?.close();
25+
resolve()
26+
});
27+
} else {
28+
resolve();
29+
}
30+
})
31+
};

src/main/actions/logNetworkRequest.js

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,3 @@
1-
/**
2-
* @param {Array} array into which element will be pushed
3-
* @param {number} required max length of array
4-
* @param {*} element to push
5-
*/
6-
const addToLog = (array, limit, element) => {
7-
const arrayToModify = [...array];
8-
if (arrayToModify.length >= limit) {
9-
arrayToModify.shift();
10-
}
11-
arrayToModify.push(element);
12-
return arrayToModify;
13-
};
14-
151
const logNetworkRequest = (event, message, webAppWindow) => {
162
const newLog = message;
173
if (webAppWindow) {

src/main/actions/logNetworkRequestV2.js

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,6 @@
1-
/**
2-
* @param {Array} array into which element will be pushed
3-
* @param {number} required max length of array
4-
* @param {*} element to push
5-
*/
6-
const addToLog = (array, limit, element) => {
7-
const arrayToModify = [...array];
8-
if (arrayToModify.length >= limit) {
9-
arrayToModify.shift();
10-
}
11-
arrayToModify.push(element);
12-
return arrayToModify;
13-
};
14-
151
const logNetworkRequestV2 = (event, message, webAppWindow) => {
162
const newLog = message;
17-
if (webAppWindow) {
3+
if (webAppWindow && !webAppWindow.isDestroyed()) {
184
webAppWindow.send("log-network-request-v2", newLog);
195
}
206
};

src/main/actions/startBackgroundProcess.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,6 @@ const startBackgroundProcess = async () => {
7979
resolve(true);
8080
});
8181

82-
backgroundWindow.on("close", (event) => {
83-
if (global.isQuitActionConfirmed) {
84-
console.log("BG quitting");
85-
return;
86-
}
87-
88-
event.preventDefault();
89-
});
9082
});
9183
};
9284

src/main/events.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ function removeFileFromAccessRecords(filePath) {
7676

7777
// These events do not require the browser window
7878
export const registerMainProcessEvents = () => {
79+
ipcMain.on("background-process-started", () => {
80+
global.backgroundProcessStarted = true;
81+
});
7982
ipcMain.handle("start-background-process", startBackgroundProcess);
8083
/** Main Process State Management */
8184
ipcMain.handle("get-state", getState);
@@ -116,32 +119,32 @@ export const registerMainProcessEventsForWebAppWindow = (webAppWindow) => {
116119

117120
// Open handle for async source detection
118121
ipcMain.handle("app-detected", async (event, payload) => {
119-
webAppWindow.send("app-detected", payload);
122+
webAppWindow?.send("app-detected", payload);
120123
});
121124

122125
ipcMain.handle("browser-connected", async (event, payload) => {
123-
webAppWindow.send("browser-connected", payload);
126+
webAppWindow?.send("browser-connected", payload);
124127
});
125128

126129
ipcMain.handle("browser-disconnected", async (event, payload) => {
127-
webAppWindow.send("browser-disconnected", payload);
130+
webAppWindow?.send("browser-disconnected", payload);
128131
});
129132

130133
// Open handle for async browser close
131134
ipcMain.handle("browser-closed", async (event, payload) => {
132-
webAppWindow.send("browser-closed", payload);
135+
webAppWindow?.send("browser-closed", payload);
133136
});
134137

135138
// Open handle for async browser close
136139
ipcMain.handle("proxy-restarted", async (event, payload) => {
137140
createOrUpdateAxiosInstance(payload);
138-
webAppWindow.send("proxy-restarted", payload);
141+
webAppWindow?.send("proxy-restarted", payload);
139142
});
140143

141144
// hacky implementation for syncing addition and deletion
142145
const resendAllNetworkLogs = async () => {
143146
const res = await getAllNetworkSessions();
144-
webAppWindow.send("network-sessions-updated", res);
147+
webAppWindow?.send("network-sessions-updated", res);
145148
};
146149

147150
ipcMain.handle("get-all-network-sessions", async () => {
@@ -264,7 +267,7 @@ export const registerMainProcessEventsForWebAppWindow = (webAppWindow) => {
264267
});
265268

266269
ipcMain.handle("helper-server-hit", () => {
267-
webAppWindow.send("helper-server-hit");
270+
webAppWindow?.send("helper-server-hit");
268271
});
269272
};
270273

src/main/main.ts

Lines changed: 39 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import "core-js/stable";
1313
import "regenerator-runtime/runtime";
1414
import path from "path";
15-
import { app, BrowserWindow, shell, dialog, Tray, Menu, clipboard } from "electron";
15+
import { app, BrowserWindow, shell, dialog, Tray, Menu, clipboard, ipcMain } from "electron";
1616
import log from "electron-log";
1717
import MenuBuilder from "./menu";
1818
import {
@@ -24,9 +24,7 @@ import {
2424
/** Storage - State */
2525
import "./actions/initGlobalState";
2626
import AutoUpdate from "../lib/autoupdate";
27-
import { cleanupAndQuit } from "./actions/cleanup";
28-
import { trackEventViaWebApp } from "./actions/events";
29-
import EVENTS from "./actions/events/constants";
27+
import { getReadyToQuitApp } from "./actions/cleanup";
3028
import fs from "fs";
3129
import logger from "../utils/logger";
3230
import { setupIPCForwardingToWebApp } from "./actions/setupIPCForwarding";
@@ -85,7 +83,7 @@ export default function createTrayMenu(ip?: string, port?: number) {
8583
{
8684
label: "Show Requestly",
8785
click: () => {
88-
if(webAppWindow) {
86+
if(webAppWindow && !webAppWindow.isDestroyed()) {
8987
if(webAppWindow.isMinimized()) {
9088
webAppWindow.restore()
9189
}
@@ -151,7 +149,7 @@ export default function createTrayMenu(ip?: string, port?: number) {
151149
{
152150
label: "Quit",
153151
click: () => {
154-
app.quit();
152+
webAppWindow?.close();
155153
},
156154
},
157155
]
@@ -170,7 +168,7 @@ export default function createTrayMenu(ip?: string, port?: number) {
170168
tray.setContextMenu(trayMenu);
171169
}
172170

173-
171+
let closingAccepted = false
174172
const createWindow = async () => {
175173
if (isDevelopment) {
176174
await installExtensions();
@@ -258,63 +256,19 @@ const createWindow = async () => {
258256
}
259257
});
260258

261-
// webAppWindow.on('closed', () => {
262-
// webAppWindow = null;
263-
// });
264-
265-
webAppWindow.on("close", (e) => {
266-
// Check if user has already asked to Quit app from here or somewhere else
267-
// @ts-expect-error
268-
if (global.isQuitActionConfirmed) {
269-
saveCookies();
270-
app.quit();
271-
return;
272-
}
273-
274-
if (webAppWindow) {
275-
let message =
276-
"Do you really want to quit? This would also stop the proxy server.";
277-
278-
// @ts-expect-error
279-
if (global.quitAndInstall) {
280-
message = "Confirm to restart & install update";
281-
// @ts-expect-error
282-
global.quitAndInstall = false;
283-
}
284-
285-
const choice = dialog.showMessageBoxSync(webAppWindow, {
286-
type: "question",
287-
buttons: ["Yes, quit Requestly", "Minimize instead", "Cancel"],
288-
title: "Quit Requestly",
289-
message: message,
290-
});
291-
292-
switch (choice) {
293-
// If Quit is clicked
294-
case 0:
295-
// Set flag to check next iteration
296-
trackEventViaWebApp(webAppWindow, EVENTS.QUIT_APP)
297-
// @ts-expect-error
298-
global.isQuitActionConfirmed = true;
299-
// Calling app.quit() would again invoke this function
300-
e.preventDefault();
301-
cleanupAndQuit();
302-
break;
303-
// If Minimize is clicked
304-
case 1:
305-
webAppWindow.minimize();
306-
e.preventDefault();
307-
break;
308-
// If cancel is clicked
309-
case 2:
310-
e.preventDefault();
311-
break;
312-
default:
313-
break;
314-
}
259+
webAppWindow.on('close', async (event) => {
260+
if(!closingAccepted) {
261+
event.preventDefault();
262+
webAppWindow?.webContents.send("initiate-app-close")
315263
}
316-
});
264+
})
317265

266+
webAppWindow.on('closed', async () => {
267+
saveCookies();
268+
await getReadyToQuitApp();
269+
webAppWindow = null;
270+
return;
271+
})
318272
const enableBGWindowDebug = () => {
319273
// Show bg window and toggle the devtools
320274
try {
@@ -368,7 +322,7 @@ function handleCustomProtocolURL(urlString: string) {
368322

369323
// custom protocol (requestly) handler
370324
app.on("open-url", (_event, rqUrl) => {
371-
if(webAppWindow) {
325+
if(webAppWindow && !webAppWindow.isDestroyed()) {
372326
handleCustomProtocolURL(rqUrl)
373327
} else {
374328
onWebAppReadyHandlers.push(() => handleCustomProtocolURL(rqUrl))
@@ -401,7 +355,7 @@ async function handleFileOpen(filePath: string, webAppWindow?: BrowserWindow) {
401355

402356
app.on('open-file', async (event, filePath) => {
403357
event.preventDefault();
404-
if(webAppWindow) {
358+
if(webAppWindow && !webAppWindow.isDestroyed()) {
405359
handleFileOpen(filePath, webAppWindow);
406360
} else {
407361
logger.log("webAppWindow not ready")
@@ -492,3 +446,24 @@ app
492446
.catch((err) => {
493447
console.log(err);
494448
});
449+
450+
ipcMain.handle("quit-app", (_event) => {
451+
closingAccepted = true
452+
webAppWindow?.close();
453+
})
454+
455+
app.on("before-quit", () => {
456+
// cleanup when quitting has been finalised
457+
ipcMain.removeAllListeners();
458+
webAppWindow?.removeAllListeners();
459+
// @ts-expect-error BrowserWindow types are not being enforced for this variable
460+
backgroundWindow?.removeAllListeners();
461+
462+
ipcMain.removeAllListeners();
463+
process.on('uncaughtException', (err) => {
464+
logger.error('Unhandled Exception while quitting:', err);
465+
});
466+
process.on('unhandledRejection', (err) => {
467+
logger.error('Unhandled Rejection while quitting:', err);
468+
});
469+
})

src/main/menu.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
app,
32
Menu,
43
shell,
54
BrowserWindow,
@@ -13,6 +12,7 @@ interface DarwinMenuItemConstructorOptions extends MenuItemConstructorOptions {
1312

1413
export default class MenuBuilder {
1514
mainWindow: BrowserWindow;
15+
1616
enableBGWindowDebug: Function;
1717

1818
constructor(mainWindow: BrowserWindow, enableBGWindowDebug: Function) {
@@ -79,10 +79,7 @@ export default class MenuBuilder {
7979
label: "Quit",
8080
accelerator: "Command+Q",
8181
click: () => {
82-
if (this.mainWindow) {
83-
return this.mainWindow.close();
84-
}
85-
app.quit();
82+
return this.mainWindow?.close();
8683
},
8784
},
8885
],
@@ -289,10 +286,7 @@ export default class MenuBuilder {
289286
label: "&Close",
290287
accelerator: "Ctrl+W",
291288
click: () => {
292-
if (this.mainWindow) {
293-
return this.mainWindow.close();
294-
}
295-
app.quit();
289+
return this.mainWindow?.close();
296290
},
297291
},
298292
],

0 commit comments

Comments
 (0)