diff --git a/app/main.ts b/app/main.ts index 31ee1ced52ab..9463bc972aef 100644 --- a/app/main.ts +++ b/app/main.ts @@ -871,6 +871,7 @@ async function createWindow() { ); } if (!shouldClose) { + updater.onRestartCancelled(); return; } diff --git a/app/window_state.ts b/app/window_state.ts index 53798e459d79..0d9f381606b8 100644 --- a/app/window_state.ts +++ b/app/window_state.ts @@ -7,6 +7,10 @@ export function markShouldQuit(): void { shouldQuitFlag = true; } +export function markShouldNotQuit(): void { + shouldQuitFlag = false; +} + export function shouldQuit(): boolean { return shouldQuitFlag; } diff --git a/ts/updater/common.ts b/ts/updater/common.ts index 264929d43a08..31a77b722e09 100644 --- a/ts/updater/common.ts +++ b/ts/updater/common.ts @@ -21,6 +21,7 @@ import { app, ipcMain } from 'electron'; import * as durations from '../util/durations'; import { getTempPath, getUpdateCachePath } from '../../app/attachments'; +import { markShouldNotQuit, markShouldQuit } from '../../app/window_state'; import { DialogType } from '../types/Dialogs'; import * as Errors from '../types/errors'; import { isAlpha, isBeta, isStaging } from '../util/version'; @@ -117,6 +118,8 @@ export abstract class Updater { private markedCannotUpdate = false; + private restarting = false; + private readonly canRunSilently: () => boolean; constructor({ @@ -148,6 +151,26 @@ export abstract class Updater { return this.checkForUpdatesMaybeInstall(true); } + // If the updater was about to restart the app but the user cancelled it, show dialog + // to let them retry the restart + public onRestartCancelled(): void { + if (!this.restarting) { + return; + } + + this.logger.info( + 'updater/onRestartCancelled: restart was cancelled. showing update dialog.' + ); + this.restarting = false; + markShouldNotQuit(); + + const mainWindow = this.getMainWindow(); + mainWindow?.webContents.send( + 'show-update-dialog', + DialogType.DownloadedUpdate + ); + } + public async start(): Promise { this.logger.info('updater/start: starting checks...'); @@ -173,7 +196,7 @@ export abstract class Updater { // protected setUpdateListener( - performUpdateCallback: () => Promise + performUpdateCallback: () => Promise | void ): void { ipcMain.removeHandler('start-update'); ipcMain.handleOnce('start-update', performUpdateCallback); @@ -209,6 +232,11 @@ export abstract class Updater { }); } + protected markRestarting(): void { + this.restarting = true; + markShouldQuit(); + } + // // Private methods // diff --git a/ts/updater/index.ts b/ts/updater/index.ts index 48613434978a..02b60e24e9e2 100644 --- a/ts/updater/index.ts +++ b/ts/updater/index.ts @@ -64,6 +64,12 @@ export async function force(): Promise { } } +export function onRestartCancelled(): void { + if (updater) { + updater.onRestartCancelled(); + } +} + function autoUpdateDisabled() { return ( process.platform === 'linux' || process.mas || !config.get('updatesEnabled') diff --git a/ts/updater/macos.ts b/ts/updater/macos.ts index 676ea067cdfc..105b53396675 100644 --- a/ts/updater/macos.ts +++ b/ts/updater/macos.ts @@ -9,7 +9,6 @@ import { join } from 'path'; import { Updater, createTempDir, deleteTempDir } from './common'; import { explodePromise } from '../util/explodePromise'; import * as Errors from '../types/errors'; -import { markShouldQuit } from '../../app/window_state'; import { DialogType } from '../types/Dialogs'; export class MacOSUpdater extends Updater { @@ -41,7 +40,7 @@ export class MacOSUpdater extends Updater { this.setUpdateListener(async () => { logger.info('downloadAndInstall: restarting...'); - markShouldQuit(); + this.markRestarting(); autoUpdater.quitAndInstall(); }); } diff --git a/ts/updater/windows.ts b/ts/updater/windows.ts index 6cb545a52a4c..080a688da62a 100644 --- a/ts/updater/windows.ts +++ b/ts/updater/windows.ts @@ -10,7 +10,6 @@ import { app } from 'electron'; import pify from 'pify'; import { Updater } from './common'; -import { markShouldQuit } from '../../app/window_state'; const readdir = pify(readdirCallback); const unlink = pify(unlinkCallback); @@ -61,9 +60,9 @@ export class WindowsUpdater extends Updater { throw error; } - logger.info('downloadAndInstall: restarting...'); - markShouldQuit(); - app.quit(); + // If interrupted at this point, we only want to restart (not reattempt install) + this.setUpdateListener(this.restart); + this.restart(); }; if (isSilent) { @@ -75,6 +74,12 @@ export class WindowsUpdater extends Updater { this.setUpdateListener(doInstall); } + protected restart(): void { + this.logger.info('downloadAndInstall: restarting...'); + this.markRestarting(); + app.quit(); + } + private async install(filePath: string, isSilent: boolean): Promise { if (this.installing) { return;