fix(mac): prevent updater hang on manual install
Bump to 1.0.20. Disable autoDownload during manual check and fix Squirrel.Mac quitAndInstall race on darwin. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -14,6 +14,43 @@ import type { LicenseService } from '../license/licenseService';
|
|||||||
const STARTUP_CHECK_DELAY_MS = 12_000;
|
const STARTUP_CHECK_DELAY_MS = 12_000;
|
||||||
/** Не дёргать сервер чаще (смена лицензии / повторные emit). */
|
/** Не дёргать сервер чаще (смена лицензии / повторные emit). */
|
||||||
const RE_CHECK_COOLDOWN_MS = 30_000;
|
const RE_CHECK_COOLDOWN_MS = 30_000;
|
||||||
|
/** Ручная загрузка из модалки — не зависать бесконечно на «Загрузка…». */
|
||||||
|
const MANUAL_DOWNLOAD_TIMEOUT_MS = 30 * 60 * 1000;
|
||||||
|
|
||||||
|
function withTimeout<T>(promise: Promise<T>, ms: number, code: string): Promise<T> {
|
||||||
|
return new Promise<T>((resolve, reject) => {
|
||||||
|
const timer = setTimeout(() => reject(new Error(code)), ms);
|
||||||
|
promise.then(
|
||||||
|
(v) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
resolve(v);
|
||||||
|
},
|
||||||
|
(e: unknown) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
reject(e instanceof Error ? e : new Error(String(e)));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* На macOS Squirrel.Mac может уже получить update-downloaded к моменту quitAndInstall.
|
||||||
|
* При autoInstallOnAppQuit=true MacUpdater не вызывает checkForUpdates повторно и зависает.
|
||||||
|
*/
|
||||||
|
function quitAndInstallForPlatform(): void {
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
autoUpdater.autoInstallOnAppQuit = false;
|
||||||
|
}
|
||||||
|
autoUpdater.quitAndInstall(false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUpdaterError(e: unknown): string {
|
||||||
|
const raw = e instanceof Error ? e.message : String(e);
|
||||||
|
if (raw === 'UPDATE_DOWNLOAD_TIMEOUT') {
|
||||||
|
return 'Превышено время ожидания загрузки обновления';
|
||||||
|
}
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
let lastCheckAt = 0;
|
let lastCheckAt = 0;
|
||||||
/** Ручная установка: не показывать второй диалог из `update-downloaded`. */
|
/** Ручная установка: не показывать второй диалог из `update-downloaded`. */
|
||||||
@@ -42,6 +79,8 @@ async function runManualUpdaterCheck(licenseService: LicenseService): Promise<Up
|
|||||||
if (!isLicensedForUpdates(licenseService)) {
|
if (!isLicensedForUpdates(licenseService)) {
|
||||||
return { outcome: 'no_license' };
|
return { outcome: 'no_license' };
|
||||||
}
|
}
|
||||||
|
const prevAutoDownload = autoUpdater.autoDownload;
|
||||||
|
autoUpdater.autoDownload = false;
|
||||||
try {
|
try {
|
||||||
const result = await autoUpdater.checkForUpdates();
|
const result = await autoUpdater.checkForUpdates();
|
||||||
if (result && result.isUpdateAvailable && result.updateInfo.version) {
|
if (result && result.isUpdateAvailable && result.updateInfo.version) {
|
||||||
@@ -51,6 +90,8 @@ async function runManualUpdaterCheck(licenseService: LicenseService): Promise<Up
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
const message = e instanceof Error ? e.message : String(e);
|
const message = e instanceof Error ? e.message : String(e);
|
||||||
return { outcome: 'error', message };
|
return { outcome: 'error', message };
|
||||||
|
} finally {
|
||||||
|
autoUpdater.autoDownload = prevAutoDownload;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,15 +99,25 @@ async function runManualDownloadAndRestart(): Promise<UpdaterDownloadResponse> {
|
|||||||
if (!app.isPackaged) {
|
if (!app.isPackaged) {
|
||||||
return { ok: false, message: 'NOT_PACKAGED' };
|
return { ok: false, message: 'NOT_PACKAGED' };
|
||||||
}
|
}
|
||||||
|
const prevAutoInstallOnAppQuit = autoUpdater.autoInstallOnAppQuit;
|
||||||
try {
|
try {
|
||||||
suppressAutoInstallDialog = true;
|
suppressAutoInstallDialog = true;
|
||||||
await autoUpdater.downloadUpdate();
|
if (process.platform === 'darwin') {
|
||||||
autoUpdater.quitAndInstall(false, true);
|
autoUpdater.autoInstallOnAppQuit = false;
|
||||||
|
}
|
||||||
|
await withTimeout(
|
||||||
|
autoUpdater.downloadUpdate(),
|
||||||
|
MANUAL_DOWNLOAD_TIMEOUT_MS,
|
||||||
|
'UPDATE_DOWNLOAD_TIMEOUT',
|
||||||
|
);
|
||||||
|
quitAndInstallForPlatform();
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
suppressAutoInstallDialog = false;
|
suppressAutoInstallDialog = false;
|
||||||
const message = e instanceof Error ? e.message : String(e);
|
if (process.platform === 'darwin') {
|
||||||
return { ok: false, message };
|
autoUpdater.autoInstallOnAppQuit = prevAutoInstallOnAppQuit;
|
||||||
|
}
|
||||||
|
return { ok: false, message: formatUpdaterError(e) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +170,7 @@ export function installAutoUpdater(licenseService: LicenseService, register: Reg
|
|||||||
})
|
})
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
if (r.response === 0) {
|
if (r.response === 0) {
|
||||||
autoUpdater.quitAndInstall(false, true);
|
quitAndInstallForPlatform();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "TTRPGPlayer",
|
"name": "TTRPGPlayer",
|
||||||
"version": "1.0.18",
|
"version": "1.0.20",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "TTRPGPlayer",
|
"name": "TTRPGPlayer",
|
||||||
"version": "1.0.18",
|
"version": "1.0.20",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "TTRPGPlayer",
|
"name": "TTRPGPlayer",
|
||||||
"version": "1.0.19",
|
"version": "1.0.20",
|
||||||
"description": "TTRPG Player — редактор и проигрыватель НРИ",
|
"description": "TTRPG Player — редактор и проигрыватель НРИ",
|
||||||
"main": "dist/main/index.cjs",
|
"main": "dist/main/index.cjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Reference in New Issue
Block a user