Install downloaded updates while in tray
This commit is contained in:
parent
c4521a063c
commit
12a2ec8dd4
6 changed files with 87 additions and 24 deletions
|
@ -117,6 +117,10 @@ export class SystemTrayService {
|
||||||
this.isQuitting = true;
|
this.isQuitting = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isVisible(): boolean {
|
||||||
|
return this.tray !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
private render(): void {
|
private render(): void {
|
||||||
if (this.isEnabled && this.browserWindow) {
|
if (this.isEnabled && this.browserWindow) {
|
||||||
this.renderEnabled();
|
this.renderEnabled();
|
||||||
|
|
12
app/main.ts
12
app/main.ts
|
@ -1161,7 +1161,17 @@ async function readyForUpdates() {
|
||||||
settingsChannel !== undefined,
|
settingsChannel !== undefined,
|
||||||
'SettingsChannel must be initialized'
|
'SettingsChannel must be initialized'
|
||||||
);
|
);
|
||||||
await updater.start(settingsChannel, getLogger(), getMainWindow);
|
await updater.start({
|
||||||
|
settingsChannel,
|
||||||
|
logger: getLogger(),
|
||||||
|
getMainWindow,
|
||||||
|
canRunSilently: () => {
|
||||||
|
return (
|
||||||
|
systemTrayService?.isVisible() === true &&
|
||||||
|
mainWindow?.isVisible() === false
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
getLogger().error(
|
getLogger().error(
|
||||||
'Error starting update checks:',
|
'Error starting update checks:',
|
||||||
|
|
|
@ -45,3 +45,17 @@ ManifestDPIAware true
|
||||||
|
|
||||||
end_semver_check:
|
end_semver_check:
|
||||||
!macroend
|
!macroend
|
||||||
|
|
||||||
|
!macro customInstall
|
||||||
|
${If} ${Silent}
|
||||||
|
${AndIf} ${isUpdated}
|
||||||
|
# Copied from app-builder-lib templates/nsis/common.nsh:
|
||||||
|
|
||||||
|
# "otherwise app window will be in background"
|
||||||
|
HideWindow
|
||||||
|
|
||||||
|
# Signal modification: '--start-in-tray' added
|
||||||
|
${StdUtils.ExecShellAsUser} $0 "$launchLink" "open" \
|
||||||
|
"--updated --start-in-tray"
|
||||||
|
${EndIf}
|
||||||
|
!macroend
|
||||||
|
|
|
@ -84,6 +84,13 @@ type DownloadUpdateResultType = Readonly<{
|
||||||
signature: Buffer;
|
signature: Buffer;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
export type UpdaterOptionsType = Readonly<{
|
||||||
|
settingsChannel: SettingsChannel;
|
||||||
|
logger: LoggerType;
|
||||||
|
getMainWindow: () => BrowserWindow | undefined;
|
||||||
|
canRunSilently: () => boolean;
|
||||||
|
}>;
|
||||||
|
|
||||||
export abstract class Updater {
|
export abstract class Updater {
|
||||||
protected fileName: string | undefined;
|
protected fileName: string | undefined;
|
||||||
|
|
||||||
|
@ -91,17 +98,31 @@ export abstract class Updater {
|
||||||
|
|
||||||
protected cachedDifferentialData: DifferentialDownloadDataType | undefined;
|
protected cachedDifferentialData: DifferentialDownloadDataType | undefined;
|
||||||
|
|
||||||
|
protected readonly logger: LoggerType;
|
||||||
|
|
||||||
|
private readonly settingsChannel: SettingsChannel;
|
||||||
|
|
||||||
|
protected readonly getMainWindow: () => BrowserWindow | undefined;
|
||||||
|
|
||||||
private throttledSendDownloadingUpdate: (downloadedSize: number) => void;
|
private throttledSendDownloadingUpdate: (downloadedSize: number) => void;
|
||||||
|
|
||||||
private activeDownload: Promise<boolean> | undefined;
|
private activeDownload: Promise<boolean> | undefined;
|
||||||
|
|
||||||
private markedCannotUpdate = false;
|
private markedCannotUpdate = false;
|
||||||
|
|
||||||
constructor(
|
private readonly canRunSilently: () => boolean;
|
||||||
protected readonly logger: LoggerType,
|
|
||||||
private readonly settingsChannel: SettingsChannel,
|
constructor({
|
||||||
protected readonly getMainWindow: () => BrowserWindow | undefined
|
settingsChannel,
|
||||||
) {
|
logger,
|
||||||
|
getMainWindow,
|
||||||
|
canRunSilently,
|
||||||
|
}: UpdaterOptionsType) {
|
||||||
|
this.settingsChannel = settingsChannel;
|
||||||
|
this.logger = logger;
|
||||||
|
this.getMainWindow = getMainWindow;
|
||||||
|
this.canRunSilently = canRunSilently;
|
||||||
|
|
||||||
this.throttledSendDownloadingUpdate = throttle((downloadedSize: number) => {
|
this.throttledSendDownloadingUpdate = throttle((downloadedSize: number) => {
|
||||||
const mainWindow = this.getMainWindow();
|
const mainWindow = this.getMainWindow();
|
||||||
mainWindow?.webContents.send(
|
mainWindow?.webContents.send(
|
||||||
|
@ -141,7 +162,10 @@ export abstract class Updater {
|
||||||
|
|
||||||
protected abstract deletePreviousInstallers(): Promise<void>;
|
protected abstract deletePreviousInstallers(): Promise<void>;
|
||||||
|
|
||||||
protected abstract installUpdate(updateFilePath: string): Promise<void>;
|
protected abstract installUpdate(
|
||||||
|
updateFilePath: string,
|
||||||
|
isSilent: boolean
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Protected methods
|
// Protected methods
|
||||||
|
@ -255,7 +279,7 @@ export abstract class Updater {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.installUpdate(updateFilePath);
|
await this.installUpdate(updateFilePath, this.canRunSilently());
|
||||||
|
|
||||||
const mainWindow = this.getMainWindow();
|
const mainWindow = this.getMainWindow();
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
|
|
|
@ -2,26 +2,20 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import config from 'config';
|
import config from 'config';
|
||||||
import type { BrowserWindow } from 'electron';
|
|
||||||
|
|
||||||
import type { Updater } from './common';
|
import type { Updater, UpdaterOptionsType } from './common';
|
||||||
import { MacOSUpdater } from './macos';
|
import { MacOSUpdater } from './macos';
|
||||||
import { WindowsUpdater } from './windows';
|
import { WindowsUpdater } from './windows';
|
||||||
import { isLinuxVersionSupported } from './linux';
|
import { isLinuxVersionSupported } from './linux';
|
||||||
import type { LoggerType } from '../types/Logging';
|
|
||||||
import { DialogType } from '../types/Dialogs';
|
import { DialogType } from '../types/Dialogs';
|
||||||
import type { SettingsChannel } from '../main/settingsChannel';
|
|
||||||
|
|
||||||
let initialized = false;
|
let initialized = false;
|
||||||
|
|
||||||
let updater: Updater | undefined;
|
let updater: Updater | undefined;
|
||||||
|
|
||||||
export async function start(
|
export async function start(options: UpdaterOptionsType): Promise<void> {
|
||||||
settingsChannel: SettingsChannel,
|
|
||||||
logger: LoggerType,
|
|
||||||
getMainWindow: () => BrowserWindow | undefined
|
|
||||||
): Promise<void> {
|
|
||||||
const { platform } = process;
|
const { platform } = process;
|
||||||
|
const { logger, getMainWindow } = options;
|
||||||
|
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
throw new Error('updater/start: Updates have already been initialized!');
|
throw new Error('updater/start: Updates have already been initialized!');
|
||||||
|
@ -50,9 +44,9 @@ export async function start(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (platform === 'win32') {
|
if (platform === 'win32') {
|
||||||
updater = new WindowsUpdater(logger, settingsChannel, getMainWindow);
|
updater = new WindowsUpdater(options);
|
||||||
} else if (platform === 'darwin') {
|
} else if (platform === 'darwin') {
|
||||||
updater = new MacOSUpdater(logger, settingsChannel, getMainWindow);
|
updater = new MacOSUpdater(options);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('updater/start: Unsupported platform');
|
throw new Error('updater/start: Unsupported platform');
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,13 +44,16 @@ export class WindowsUpdater extends Updater {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
protected async installUpdate(updateFilePath: string): Promise<void> {
|
protected async installUpdate(
|
||||||
|
updateFilePath: string,
|
||||||
|
isSilent: boolean
|
||||||
|
): Promise<void> {
|
||||||
const { logger } = this;
|
const { logger } = this;
|
||||||
|
|
||||||
this.setUpdateListener(async () => {
|
const doInstall = async () => {
|
||||||
logger.info('downloadAndInstall: installing...');
|
logger.info('downloadAndInstall: installing...');
|
||||||
try {
|
try {
|
||||||
await this.install(updateFilePath);
|
await this.install(updateFilePath, isSilent);
|
||||||
this.installing = true;
|
this.installing = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.markCannotUpdate(error);
|
this.markCannotUpdate(error);
|
||||||
|
@ -61,10 +64,18 @@ export class WindowsUpdater extends Updater {
|
||||||
logger.info('downloadAndInstall: restarting...');
|
logger.info('downloadAndInstall: restarting...');
|
||||||
markShouldQuit();
|
markShouldQuit();
|
||||||
app.quit();
|
app.quit();
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if (isSilent) {
|
||||||
|
logger.info('downloadAndInstall: running immediately...');
|
||||||
|
await doInstall();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async install(filePath: string): Promise<void> {
|
this.setUpdateListener(doInstall);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async install(filePath: string, isSilent: boolean): Promise<void> {
|
||||||
if (this.installing) {
|
if (this.installing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +84,12 @@ export class WindowsUpdater extends Updater {
|
||||||
|
|
||||||
logger.info('windows/install: installing package...');
|
logger.info('windows/install: installing package...');
|
||||||
const args = ['--updated'];
|
const args = ['--updated'];
|
||||||
|
if (isSilent) {
|
||||||
|
// App isn't automatically restarted with "/S" flag, but "--updated"
|
||||||
|
// will trigger our code in `build/installer.nsh` that will start the app
|
||||||
|
// with "--start-in-tray" flag (see `app/main.ts`)
|
||||||
|
args.push('/S');
|
||||||
|
}
|
||||||
const options = {
|
const options = {
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: 'ignore' as const, // TypeScript considers this a plain string without help
|
stdio: 'ignore' as const, // TypeScript considers this a plain string without help
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue