diff options
| author | Tobias Järvelöv <tobias.jarvelov@mullvad.net> | 2025-04-11 15:17:36 +0200 |
|---|---|---|
| committer | Sebastian Holmin <sebastian.holmin@mullvad.net> | 2025-05-28 13:25:30 +0200 |
| commit | 4db2d39d5a294581e59f7039d05a2c603c71bcd6 (patch) | |
| tree | 2dae0bd883f5e3a3f002da4b6d2a44c9d683b659 | |
| parent | 68ba62de70c40721cd049a8f52b9984b3c13d902 (diff) | |
| download | mullvadvpn-4db2d39d5a294581e59f7039d05a2c603c71bcd6.tar.xz mullvadvpn-4db2d39d5a294581e59f7039d05a2c603c71bcd6.zip | |
Rewrite how installer is started and handled
- Use spawn to detach the process from the main process.
- Listen for when installer process exits or has an error and notify the render process accordingly.
| -rw-r--r-- | desktop/packages/mullvad-vpn/src/main/app-upgrade.ts | 68 |
1 files changed, 51 insertions, 17 deletions
diff --git a/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts b/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts index 49e9649541..7aa385026b 100644 --- a/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts +++ b/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts @@ -1,5 +1,4 @@ -import { shell } from 'electron'; -import fs from 'fs/promises'; +import { spawn } from 'child_process'; import { DaemonAppUpgradeEvent } from '../shared/daemon-rpc-types'; import log from '../shared/logging'; @@ -18,9 +17,9 @@ export default class AppUpgrade { this.daemonRpc.appUpgradeAbort(); }); - IpcMainEventChannel.app.handleUpgradeInstallerStart(async (verifiedInstallerPath: string) => { + IpcMainEventChannel.app.handleUpgradeInstallerStart((verifiedInstallerPath: string) => { try { - await this.startInstaller(verifiedInstallerPath); + this.startInstaller(verifiedInstallerPath); IpcMainEventChannel.app.notifyUpgradeEvent?.({ type: 'APP_UPGRADE_STATUS_STARTED_INSTALLER', }); @@ -54,23 +53,58 @@ export default class AppUpgrade { return daemonAppUpgradeEventListener; } - private async startInstaller(verifiedInstallerPath: string) { - await this.isInstallerExecutable(verifiedInstallerPath); - await this.executeInstaller(verifiedInstallerPath); + private spawnChildMac(verifiedInstallerPath: string) { + const child = spawn('open', [verifiedInstallerPath, '--wait-apps'], { + detached: true, + }); + + return child; } - private async executeInstaller(verifiedInstallerPath: string) { - const errorMessage = await shell.openPath(verifiedInstallerPath); - if (errorMessage) { - throw new Error(`An error occurred when starting the installer: ${errorMessage}`); - } + private spawnChildWindows(verifiedInstallerPath: string) { + const SYSTEM_ROOT_PATH = process.env.SYSTEMROOT || process.env.windir || 'C:\\Windows'; + const POWERSHELL_PATH = `${SYSTEM_ROOT_PATH}\\System32\\WindowsPowerShell\\v1.0\\powershell`; + const quotedVerifiedInstallerPath = `'${verifiedInstallerPath}'`; + + const child = spawn(POWERSHELL_PATH, ['Start', '-Wait', quotedVerifiedInstallerPath], { + detached: true, + }); + + return child; } - private async isInstallerExecutable(verifiedInstallerPath: string) { - try { - await fs.access(verifiedInstallerPath, fs.constants.X_OK); - } catch { - throw new Error('The path to the installer is not executable.'); + private spawnChild(verifiedInstallerPath: string) { + if (process.platform === 'darwin') { + return this.spawnChildMac(verifiedInstallerPath); + } + + if (process.platform === 'win32') { + return this.spawnChildWindows(verifiedInstallerPath); } + + throw new Error(`Unsupported platform: ${process.platform}`); + } + + private startInstaller(verifiedInstallerPath: string) { + const child = this.spawnChild(verifiedInstallerPath); + + child.on('error', (error) => { + log.error(`An error occurred with the installer: ${error.message}`); + IpcMainEventChannel.app.notifyUpgradeError?.('INSTALLER_FAILED'); + IpcMainEventChannel.app.notifyUpgradeEvent?.({ + type: 'APP_UPGRADE_STATUS_EXITED_INSTALLER', + }); + }); + + child.on('exit', (code) => { + if (code !== 0) { + log.error(`The installer exited unexpectedly with exit code: ${code}`); + IpcMainEventChannel.app.notifyUpgradeError?.('INSTALLER_FAILED'); + } + + IpcMainEventChannel.app.notifyUpgradeEvent?.({ + type: 'APP_UPGRADE_STATUS_EXITED_INSTALLER', + }); + }); } } |
