From 0ea5d01062a8c47dd5373e8f3478195dd2531639 Mon Sep 17 00:00:00 2001 From: Franco Montenegro Date: Fri, 4 Mar 2022 12:01:08 -0300 Subject: [PATCH] Allow to properly cancel download upgrade and prevent multiple downloads. --- electron/index.js | 36 +++++++++++++++++++++++++++--------- ui/redux/actions/app.js | 22 ++-------------------- ui/redux/selectors/app.js | 2 -- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/electron/index.js b/electron/index.js index 68ee2c946..b7143b87a 100644 --- a/electron/index.js +++ b/electron/index.js @@ -51,11 +51,9 @@ let showingAutoUpdateCloseAlert = false; // https://www.electronjs.org/docs/latest/api/auto-updater#autoupdatercheckforupdates let keepCheckingForUpdates = true; -// Auto updater doesn't support Linux installations (only trough AppImages) -// this is why, for that case, we download a full executable (.deb package) -// as a fallback support. This variable will be used to prevent -// multiple downloads when auto updater isn't supported. -let downloadUpgradeInProgress = false; +let downloadUpgradeInitiated = false; + +let downloadUpgradeItem; // Keep a global reference, if you don't, they will be closed automatically when the JavaScript // object is garbage collected. @@ -328,23 +326,43 @@ ipcMain.on('get-disk-space', async (event) => { } }); +ipcMain.on('cancel-download-upgrade', () => { + if (downloadUpgradeItem) { + // Cancel the download and execute the onCancel + // callback set in the options. + downloadUpgradeItem.cancel(); + } +}); + ipcMain.on('download-upgrade', async (event, params) => { - if (downloadUpgradeInProgress) { + // Prevent downloading multiple times. + if (downloadUpgradeInitiated || downloadUpgradeItem) { return; } - const { url, options } = params; const dir = fs.mkdtempSync(app.getPath('temp') + path.sep); + + downloadUpgradeInitiated = true; + + // Grab the download item's handler to allow + // cancelling the operation if required. + options.onStarted = function(downloadItem) { + downloadUpgradeItem = downloadItem; + }; + options.onCancel = function() { + downloadUpgradeItem = undefined; + downloadUpgradeInitiated = false; + }; options.onProgress = function(p) { rendererWindow.webContents.send('download-progress-update', p); }; options.directory = dir; options.onCompleted = function(c) { - downloadUpgradeInProgress = false; + downloadUpgradeInitiated = false; + downloadUpgradeItem = undefined; rendererWindow.webContents.send('download-update-complete', c); }; const win = BrowserWindow.getFocusedWindow(); - downloadUpgradeInProgress = true; await download(win, url, options).catch(e => console.log('e', e)); }); diff --git a/ui/redux/actions/app.js b/ui/redux/actions/app.js index a431a7352..f8916d36e 100644 --- a/ui/redux/actions/app.js +++ b/ui/redux/actions/app.js @@ -28,7 +28,6 @@ import { import { selectIsUpgradeSkipped, selectUpdateUrl, - selectUpgradeDownloadItem, selectUpgradeDownloadPath, selectAutoUpdateDeclined, selectRemoteVersion, @@ -163,25 +162,8 @@ export function doAutoUpdateDeclined() { } export function doCancelUpgrade() { - return (dispatch, getState) => { - const state = getState(); - const upgradeDownloadItem = selectUpgradeDownloadItem(state); - - if (upgradeDownloadItem) { - /* - * Right now the remote reference to the download item gets garbage collected as soon as the - * the download is over (maybe even earlier), so trying to cancel a finished download may - * throw an error. - */ - try { - upgradeDownloadItem.cancel(); - } catch (err) { - console.error(err); // eslint-disable-line no-console - } - } - - dispatch({ type: ACTIONS.UPGRADE_CANCELLED }); - }; + ipcRenderer.send('cancel-download-upgrade'); + return { type: ACTIONS.UPGRADE_CANCELLED }; } export function doCheckUpgradeAvailable() { diff --git a/ui/redux/selectors/app.js b/ui/redux/selectors/app.js index c2e65de7d..920267b62 100644 --- a/ui/redux/selectors/app.js +++ b/ui/redux/selectors/app.js @@ -50,8 +50,6 @@ export const selectIsUpgradeSkipped = createSelector(selectState, (state) => sta export const selectUpgradeDownloadPath = createSelector(selectState, (state) => state.downloadPath); -export const selectUpgradeDownloadItem = createSelector(selectState, (state) => state.downloadItem); - export const selectAutoUpdateDownloaded = createSelector(selectState, (state) => state.autoUpdateDownloaded); export const selectAutoUpdateDeclined = createSelector(selectState, (state) => state.autoUpdateDeclined);