From 407f2bbd008b92522e7666d9697a2fcd2f55b80d Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Wed, 12 Jun 2024 23:35:06 +0200 Subject: [PATCH] feat: Kill tor, monero-wallet-rpc and cli before allowing GUI to quit --- src/main/cli/cli.ts | 42 ++++++++++++++++++++++++++---------------- src/main/main.ts | 35 ++++++++++++++++++++++++++++++----- src/main/tor.ts | 4 ++++ 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/src/main/cli/cli.ts b/src/main/cli/cli.ts index de09144..5073bb2 100644 --- a/src/main/cli/cli.ts +++ b/src/main/cli/cli.ts @@ -8,10 +8,7 @@ import pidtree from 'pidtree'; import util from 'util'; import { getPlatform, isTestnet } from 'store/config'; import { CliLog, isCliLog } from 'models/cliModel'; -import { - getLogsAndStringsFromRawFileString, - getLogsFromRawFileString, -} from 'utils/parseUtils'; +import { getLogsAndStringsFromRawFileString } from 'utils/parseUtils'; import { store } from 'main/store/mainStore'; import { swapProcessExited } from 'store/features/swapSlice'; import { RpcProcessStateType } from 'models/rpcModel'; @@ -36,6 +33,10 @@ const BITCOIN_BALANCE_FORCE_REFRESH_INTERVAL = 1000 * 60; const queue = new PQueue({ concurrency: 1 }); let cli: ChildProcessWithoutNullStreams | null = null; +export function isCliRunning() { + return cli !== null; +} + async function attemptKillMoneroWalletRpcProcess() { if (process.env.SKIP_MONERO_WALLET_RPC_KILL === 'true') { logger.debug('Skipping monero-wallet-rpc kill'); @@ -83,20 +84,29 @@ async function getSpawnArgs( export async function stopCli() { const rootPid = cli?.pid; if (rootPid) { - const childrenPids = await pidtree(rootPid); - childrenPids.forEach((childPid) => { - try { - process.kill(childPid); - } catch (err) { - logger.error( - { pid: childPid, err }, - `Failed to kill children cli process`, - ); - } - }); + try { + const childrenPids = await pidtree(rootPid); + childrenPids.forEach((childPid) => { + try { + process.kill(childPid); + logger.info({ pid: childPid }, `Force killed child cli process`); + } catch (err) { + logger.error( + { pid: childPid, err }, + `Failed to kill children cli process`, + ); + } + }); + } catch (err) { + logger.error( + { pid: rootPid, err }, + `Failed to get children cli processes`, + ); + } + try { process.kill(rootPid); - logger.info({ rootPid, childrenPids }, `Force killed cli`); + logger.info({ rootPid }, `Force killed cli`); } catch (err) { logger.error({ pid: rootPid, err }, `Failed to kill root cli process`); } diff --git a/src/main/main.ts b/src/main/main.ts index d16b6ff..c6ec5b3 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -17,11 +17,11 @@ import { isDevelopment, } from 'store/config'; import { resolveHtmlPath } from './util'; -import { startRPC, stopCli } from './cli/cli'; +import { isCliRunning, startRPC, stopCli } from './cli/cli'; import getSavedLogsOfSwapId, { getAssetPath, fixAppDataPath } from './cli/dirs'; import initSocket from './socket'; import logger from '../utils/logger'; -import { spawnTor, stopTor } from './tor'; +import { isTorRunning, spawnTor, stopTor } from './tor'; import { buyXmr, cancelRefundSwap, @@ -105,9 +105,34 @@ async function createWindow() { fixAppDataPath(); -app.on('will-quit', async () => { - await stopCli(); - stopTor(); +app.on('before-quit', async (e) => { + if (isCliRunning() || isTorRunning()) { + logger.debug( + 'Preventing Electron from quitting, stopping CLI, Tor and their child processes first', + ); + e.preventDefault(); + } else { + logger.info('Letting Electron quit, there are no running child processes'); + return; + } + + if (isCliRunning()) { + try { + await stopCli(); + } catch (err) { + logger.warn('Failed to stop CLI', err); + } + } + + if (isTorRunning()) { + try { + stopTor(); + } catch (err) { + logger.warn('Failed to stop Tor', err); + } + } + + app.quit(); }); app.on('window-all-closed', () => { diff --git a/src/main/tor.ts b/src/main/tor.ts index da87e0e..3d262ec 100644 --- a/src/main/tor.ts +++ b/src/main/tor.ts @@ -13,6 +13,10 @@ import { getTorBinary, makeFileExecutable } from './cli/dirs'; let torProc: ChildProcessWithoutNullStreams | null = null; +export function isTorRunning(): boolean { + return torProc != null; +} + export function stopTor() { torProc?.kill(); torProc = null;