fix(updater): opt macos electron updator (#187)

This commit is contained in:
Haze
2026-02-26 17:08:21 +08:00
committed by GitHub
Unverified
parent 9ff0eb81fd
commit a14552a474
2 changed files with 15 additions and 32 deletions

View File

@@ -231,9 +231,7 @@ app.on('window-all-closed', () => {
app.on('before-quit', () => { app.on('before-quit', () => {
isQuitting = true; isQuitting = true;
// Fire-and-forget: do not await gatewayManager.stop() here. // Fire-and-forget: do not await gatewayManager.stop() here.
// Awaiting inside a before-quit handler can stall Electron's // Awaiting inside before-quit can stall Electron's quit sequence.
// replyToApplicationShouldTerminate: call when the quit is initiated
// by Squirrel.Mac (quitAndInstall), preventing the app from ever exiting.
void gatewayManager.stop().catch((err) => { void gatewayManager.stop().catch((err) => {
logger.warn('gatewayManager.stop() error during quit:', err); logger.warn('gatewayManager.stop() error during quit:', err);
}); });

View File

@@ -52,22 +52,14 @@ export class AppUpdater extends EventEmitter {
constructor() { constructor() {
super(); super();
// Configure auto-updater
autoUpdater.autoDownload = false; autoUpdater.autoDownload = false;
// Must be true on macOS so that MacUpdater.updateDownloaded() triggers
// nativeUpdater.checkForUpdates() during the download phase, which lets
// Squirrel.Mac pre-stage the update. When false, the Squirrel download
// is deferred entirely to quitAndInstall() time, where it races against
// any safety timeout and often loses — resulting in the app quitting
// without installing the update.
autoUpdater.autoInstallOnAppQuit = true; autoUpdater.autoInstallOnAppQuit = true;
// Use logger
autoUpdater.logger = { autoUpdater.logger = {
info: (msg: string) => console.log('[Updater]', msg), info: (msg: string) => logger.info('[Updater]', msg),
warn: (msg: string) => console.warn('[Updater]', msg), warn: (msg: string) => logger.warn('[Updater]', msg),
error: (msg: string) => console.error('[Updater]', msg), error: (msg: string) => logger.error('[Updater]', msg),
debug: (msg: string) => console.debug('[Updater]', msg), debug: (msg: string) => logger.debug('[Updater]', msg),
}; };
// Override feed URL for prerelease channels so that // Override feed URL for prerelease channels so that
@@ -76,7 +68,7 @@ export class AppUpdater extends EventEmitter {
const channel = detectChannel(version); const channel = detectChannel(version);
const feedUrl = `${OSS_BASE_URL}/${channel}`; const feedUrl = `${OSS_BASE_URL}/${channel}`;
console.log(`[Updater] Version: ${version}, channel: ${channel}, feedUrl: ${feedUrl}`); logger.info(`[Updater] Version: ${version}, channel: ${channel}, feedUrl: ${feedUrl}`);
// Set channel so electron-updater requests the correct yml filename. // Set channel so electron-updater requests the correct yml filename.
// e.g. channel "alpha" → requests alpha-mac.yml, channel "latest" → requests latest-mac.yml // e.g. channel "alpha" → requests alpha-mac.yml, channel "latest" → requests latest-mac.yml
@@ -148,7 +140,12 @@ export class AppUpdater extends EventEmitter {
* Update status and notify renderer * Update status and notify renderer
*/ */
private updateStatus(newStatus: Partial<UpdateStatus>): void { private updateStatus(newStatus: Partial<UpdateStatus>): void {
this.status = { ...this.status, ...newStatus }; this.status = {
status: newStatus.status ?? this.status.status,
info: newStatus.info,
progress: newStatus.progress,
error: newStatus.error,
};
this.sendToRenderer('update:status-changed', this.status); this.sendToRenderer('update:status-changed', this.status);
} }
@@ -191,7 +188,7 @@ export class AppUpdater extends EventEmitter {
return result.updateInfo || null; return result.updateInfo || null;
} catch (error) { } catch (error) {
console.error('[Updater] Check for updates failed:', error); logger.error('[Updater] Check for updates failed:', error);
this.updateStatus({ status: 'error', error: (error as Error).message || String(error) }); this.updateStatus({ status: 'error', error: (error as Error).message || String(error) });
throw error; throw error;
} }
@@ -204,22 +201,13 @@ export class AppUpdater extends EventEmitter {
try { try {
await autoUpdater.downloadUpdate(); await autoUpdater.downloadUpdate();
} catch (error) { } catch (error) {
console.error('[Updater] Download update failed:', error); logger.error('[Updater] Download update failed:', error);
throw error; throw error;
} }
} }
/**
* Install update and restart app
*/
quitAndInstall(): void { quitAndInstall(): void {
logger.info('[Updater] quitAndInstall called invoking autoUpdater.quitAndInstall()'); logger.info('[Updater] quitAndInstall called');
// On macOS, MacUpdater.quitAndInstall() either:
// (a) calls nativeUpdater.quitAndInstall() immediately (Squirrel already staged), or
// (b) waits for Squirrel to finish staging, then calls nativeUpdater.quitAndInstall().
// In both cases electron-updater handles app.quit() internally.
// Do NOT add a safety timer that calls app.quit() — it kills the local
// proxy server that Squirrel.Mac is downloading from, aborting the update.
autoUpdater.quitAndInstall(); autoUpdater.quitAndInstall();
} }
@@ -243,9 +231,6 @@ export class AppUpdater extends EventEmitter {
}, 1000); }, 1000);
} }
/**
* Cancel a running auto-install countdown.
*/
cancelAutoInstall(): void { cancelAutoInstall(): void {
this.clearAutoInstallTimer(); this.clearAutoInstallTimer();
this.sendToRenderer('update:auto-install-countdown', { seconds: -1, cancelled: true }); this.sendToRenderer('update:auto-install-countdown', { seconds: -1, cancelled: true });