diff --git a/apps/electron-backend/src/app/services/app-update.service.spec.ts b/apps/electron-backend/src/app/services/app-update.service.spec.ts index 352ca5264..3b3adac05 100644 --- a/apps/electron-backend/src/app/services/app-update.service.spec.ts +++ b/apps/electron-backend/src/app/services/app-update.service.spec.ts @@ -112,7 +112,62 @@ describe('AppUpdateService', () => { status: ELECTRON_BRIDGE_APP_UPDATE_STATUSES.Unsupported, supportedSelfUpdate: false, }); - expect(updater.autoDownload).toBe(false); + expect(updater.autoDownload).toBe(true); + }); + + it('does not resolve the updater adapter outside self-update builds', async () => { + const updaterFactory = jest.fn(() => new FakeUpdater()); + const service = new AppUpdateService({ + app: { + getVersion: () => '0.0', + isPackaged: false, + }, + getMainWindow: () => createWindow(), + updater: updaterFactory, + }); + + expect(service.getStatus()).toEqual({ + currentVersion: '0.0', + manualDownloadUrl: + 'https://github.com/4gray/iptvnator/releases/latest', + status: ELECTRON_BRIDGE_APP_UPDATE_STATUSES.Unsupported, + supportedSelfUpdate: false, + }); + + await service.checkForUpdatesOnStartup(); + + expect(updaterFactory).not.toHaveBeenCalled(); + }); + + it('checks GitHub releases without resolving the updater on unsupported packaged Linux builds', async () => { + const fetcher = createReleaseFetcher(); + const updaterFactory = jest.fn(() => new FakeUpdater()); + const service = new AppUpdateService({ + app: { + getVersion: () => '0.22.0', + isPackaged: true, + }, + getMainWindow: () => createWindow(), + platform: 'linux', + processEnv: {}, + releaseFetcher: fetcher, + updater: updaterFactory, + }); + + await service.checkForUpdates(); + + expect(updaterFactory).not.toHaveBeenCalled(); + expect(fetcher).toHaveBeenCalledWith( + 'https://api.github.com/repos/4gray/iptvnator/releases?per_page=10&page=1', + expect.any(Object) + ); + expect(service.getStatus()).toEqual( + expect.objectContaining({ + latestVersion: '0.24.0', + status: ELECTRON_BRIDGE_APP_UPDATE_STATUSES.Available, + supportedSelfUpdate: false, + }) + ); }); it('supports Linux self-update only for AppImage builds', () => { diff --git a/apps/electron-backend/src/app/services/app-update.service.ts b/apps/electron-backend/src/app/services/app-update.service.ts index 6efc736b3..83f0f7afd 100644 --- a/apps/electron-backend/src/app/services/app-update.service.ts +++ b/apps/electron-backend/src/app/services/app-update.service.ts @@ -67,6 +67,8 @@ interface AppUpdaterAdapter { on(event: 'error', listener: (error: Error) => void): this; } +type AppUpdaterAdapterProvider = AppUpdaterAdapter | (() => AppUpdaterAdapter); + interface GitHubReleaseResponse { body?: string | null; draft?: boolean; @@ -102,7 +104,7 @@ type ReleaseFetcher = ( export interface AppUpdateServiceOptions { app: AppUpdateAppAdapter; - updater: AppUpdaterAdapter; + updater: AppUpdaterAdapterProvider; getMainWindow: () => AppUpdateWindow | null | undefined; platform?: NodeJS.Platform; processEnv?: NodeJS.ProcessEnv; @@ -224,6 +226,7 @@ export class AppUpdateService { private readonly supportedSelfUpdate: boolean; private readonly releaseFetcher: ReleaseFetcher; private readonly releases: CachedGitHubRelease[] = []; + private readonly updater: AppUpdaterAdapter | null = null; private loadedReleasePages = 0; private loadedAllReleases = false; private checkForUpdatesPromise: Promise | null = @@ -248,9 +251,12 @@ export class AppUpdateService { supportedSelfUpdate: this.supportedSelfUpdate, }; - options.updater.autoDownload = false; - options.updater.autoInstallOnAppQuit = false; - this.attachUpdaterEvents(options.updater); + if (this.supportedSelfUpdate) { + this.updater = this.resolveUpdater(options.updater); + this.updater.autoDownload = false; + this.updater.autoInstallOnAppQuit = false; + this.attachUpdaterEvents(this.updater); + } } getStatus(): ElectronBridgeAppUpdateStatus { @@ -283,8 +289,8 @@ export class AppUpdateService { }); try { - if (this.supportedSelfUpdate) { - await this.options.updater.checkForUpdates(); + if (this.updater) { + await this.updater.checkForUpdates(); } else { await this.checkGitHubReleaseForManualUpdate(); } @@ -344,7 +350,7 @@ export class AppUpdateService { } async downloadUpdate(): Promise { - if (!this.supportedSelfUpdate) { + if (!this.updater) { this.setStatus({ status: ELECTRON_BRIDGE_APP_UPDATE_STATUSES.Unsupported, }); @@ -363,7 +369,7 @@ export class AppUpdateService { }); try { - await this.options.updater.downloadUpdate(); + await this.updater.downloadUpdate(); } catch (error) { this.handleError(error); } @@ -373,11 +379,11 @@ export class AppUpdateService { installUpdate(): ElectronBridgeAppUpdateStatus { if ( - this.supportedSelfUpdate && + this.updater && this.status.status === ELECTRON_BRIDGE_APP_UPDATE_STATUSES.Downloaded ) { - this.options.updater.quitAndInstall(); + this.updater.quitAndInstall(); } return this.getStatus(); @@ -430,6 +436,12 @@ export class AppUpdateService { }); } + private resolveUpdater( + updater: AppUpdaterAdapterProvider + ): AppUpdaterAdapter { + return typeof updater === 'function' ? updater() : updater; + } + private attachUpdaterEvents(updater: AppUpdaterAdapter): void { updater.on('checking-for-update', () => { this.setStatus({ diff --git a/apps/electron-backend/src/main.ts b/apps/electron-backend/src/main.ts index 518fe9baf..1ca4a3be0 100644 --- a/apps/electron-backend/src/main.ts +++ b/apps/electron-backend/src/main.ts @@ -89,7 +89,7 @@ export default class Main { const appUpdateService = new AppUpdateService({ app, getMainWindow: () => App.mainWindow, - updater: autoUpdater, + updater: () => autoUpdater, }); AppUpdateEvents.bootstrapAppUpdateEvents(appUpdateService);