Skip to content

Commit 9bcc991

Browse files
nsrCodeswrongsahil
andauthored
refactor: delegate quit to main renderer (#191)
* wip: remove original prompt for quitting and emit events for UI to be able to show prompt if required * hacky-fix: redirect before quit to prevent unsaved blocker * fix: all quit calls should first close main renderer * fix: cleanup processes and IPCs before shutting down * chore: review comments * fix: check if webAppWindow exists before sending any requests * fix: background process not closing (#194) * fix: background process not closing * chore: remove debug logs --------- Co-authored-by: Navdeep Singh Rathore <navdeep.r@browserstack.com> --------- Co-authored-by: Sahil Gupta <sahil865gupta@gmail.com>
1 parent 0b76ee5 commit 9bcc991

15 files changed

Lines changed: 156 additions & 171 deletions

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"deploy": "npm run build && electron-builder build --publish always",
1616
"postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts",
1717
"start": "ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer",
18-
"start:main": "cross-env NODE_ENV=development electron -r ts-node/register/transpile-only ./src/main/main.ts --trace-warnings",
18+
"start:main": "cross-env NODE_ENV=development electron --inspect=9229 -r ts-node/register/transpile-only ./src/main/main.ts --trace-warnings",
1919
"start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts",
2020
"test": "jest",
2121
"debug-prod-build": "cross-env DEBUG_PROD=true && npm run build",

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: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
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+
}
28+
})
29+
};

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
@@ -68,6 +68,9 @@ function removeFileFromAccessRecords(filePath) {
6868

6969
// These events do not require the browser window
7070
export const registerMainProcessEvents = () => {
71+
ipcMain.on("background-process-started", () => {
72+
global.backgroundProcessStarted = true;
73+
});
7174
ipcMain.handle("start-background-process", startBackgroundProcess);
7275
/** Main Process State Management */
7376
ipcMain.handle("get-state", getState);
@@ -108,32 +111,32 @@ export const registerMainProcessEventsForWebAppWindow = (webAppWindow) => {
108111

109112
// Open handle for async source detection
110113
ipcMain.handle("app-detected", async (event, payload) => {
111-
webAppWindow.send("app-detected", payload);
114+
webAppWindow?.send("app-detected", payload);
112115
});
113116

114117
ipcMain.handle("browser-connected", async (event, payload) => {
115-
webAppWindow.send("browser-connected", payload);
118+
webAppWindow?.send("browser-connected", payload);
116119
});
117120

118121
ipcMain.handle("browser-disconnected", async (event, payload) => {
119-
webAppWindow.send("browser-disconnected", payload);
122+
webAppWindow?.send("browser-disconnected", payload);
120123
});
121124

122125
// Open handle for async browser close
123126
ipcMain.handle("browser-closed", async (event, payload) => {
124-
webAppWindow.send("browser-closed", payload);
127+
webAppWindow?.send("browser-closed", payload);
125128
});
126129

127130
// Open handle for async browser close
128131
ipcMain.handle("proxy-restarted", async (event, payload) => {
129132
createOrUpdateAxiosInstance(payload);
130-
webAppWindow.send("proxy-restarted", payload);
133+
webAppWindow?.send("proxy-restarted", payload);
131134
});
132135

133136
// hacky implementation for syncing addition and deletion
134137
const resendAllNetworkLogs = async () => {
135138
const res = await getAllNetworkSessions();
136-
webAppWindow.send("network-sessions-updated", res);
139+
webAppWindow?.send("network-sessions-updated", res);
137140
};
138141

139142
ipcMain.handle("get-all-network-sessions", async () => {
@@ -246,7 +249,7 @@ export const registerMainProcessEventsForWebAppWindow = (webAppWindow) => {
246249
});
247250

248251
ipcMain.handle("helper-server-hit", () => {
249-
webAppWindow.send("helper-server-hit");
252+
webAppWindow?.send("helper-server-hit");
250253
});
251254
};
252255

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")
@@ -484,3 +438,24 @@ app
484438
.catch((err) => {
485439
console.log(err);
486440
});
441+
442+
ipcMain.handle("quit-app", (_event) => {
443+
closingAccepted = true
444+
webAppWindow?.close();
445+
})
446+
447+
app.on("before-quit", () => {
448+
// cleanup when quitting has been finalised
449+
ipcMain.removeAllListeners();
450+
webAppWindow?.removeAllListeners();
451+
// @ts-expect-error BrowserWindow types are not being enforced for this variable
452+
backgroundWindow?.removeAllListeners();
453+
454+
ipcMain.removeAllListeners();
455+
process.on('uncaughtException', (err) => {
456+
logger.error('Unhandled Exception while quitting:', err);
457+
});
458+
process.on('unhandledRejection', (err) => {
459+
logger.error('Unhandled Rejection while quitting:', err);
460+
});
461+
})

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)