mirror of
https://github.com/Pandipipas/scoreko-electron-dev.git
synced 2026-06-06 05:32:06 +00:00
Improving Installer and Updater Process
This commit is contained in:
+4
-1
@@ -84,7 +84,10 @@
|
|||||||
"uninstallerIcon": "static/icons/icon.ico",
|
"uninstallerIcon": "static/icons/icon.ico",
|
||||||
"installerHeaderIcon": "static/icons/icon.ico",
|
"installerHeaderIcon": "static/icons/icon.ico",
|
||||||
"shortcutName": "Scoreko",
|
"shortcutName": "Scoreko",
|
||||||
"useZip": false
|
"useZip": false,
|
||||||
|
"deleteAppDataOnUninstall": true,
|
||||||
|
"showInstDetails": "show",
|
||||||
|
"showUninstDetails": "show"
|
||||||
},
|
},
|
||||||
"compression": "normal"
|
"compression": "normal"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -41,6 +41,22 @@ export async function askToInstallUpdate(update: ReleaseUpdate, parentWindow: Br
|
|||||||
return result.response === 0;
|
return result.response === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function showDownloadFailedDialog(
|
||||||
|
update: ReleaseUpdate,
|
||||||
|
error: unknown,
|
||||||
|
parentWindow: BrowserWindow | null,
|
||||||
|
): Promise<void> {
|
||||||
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
|
await showMessageBox(parentWindow, {
|
||||||
|
type: "error",
|
||||||
|
title: "Error de descarga",
|
||||||
|
message: `No se pudo descargar la actualización para Scoreko ${update.version}.`,
|
||||||
|
detail: `Detalles del error: ${errorMessage}\n\nPor favor, comprueba tu conexión a internet e inténtalo de nuevo.`,
|
||||||
|
buttons: ["Aceptar"],
|
||||||
|
defaultId: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function showMessageBox(
|
function showMessageBox(
|
||||||
parentWindow: BrowserWindow | null,
|
parentWindow: BrowserWindow | null,
|
||||||
options: MessageBoxOptions,
|
options: MessageBoxOptions,
|
||||||
|
|||||||
@@ -23,6 +23,13 @@ export async function downloadInstaller(update: ReleaseUpdate, config: UpdateDow
|
|||||||
const targetPath = getSafeChildPath(downloadDirectory, safeFileName);
|
const targetPath = getSafeChildPath(downloadDirectory, safeFileName);
|
||||||
const stagingPath = getSafeChildPath(downloadDirectory, `${safeFileName}.${process.pid}.${Date.now()}.download`);
|
const stagingPath = getSafeChildPath(downloadDirectory, `${safeFileName}.${process.pid}.${Date.now()}.download`);
|
||||||
|
|
||||||
|
if (fs.existsSync(targetPath)) {
|
||||||
|
const stats = fs.statSync(targetPath);
|
||||||
|
if (typeof update.installer.size === "number" && stats.size === update.installer.size) {
|
||||||
|
return targetPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fs.mkdirSync(downloadDirectory, { recursive: true });
|
fs.mkdirSync(downloadDirectory, { recursive: true });
|
||||||
fs.rmSync(stagingPath, { force: true });
|
fs.rmSync(stagingPath, { force: true });
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { app, BrowserWindow, shell } from "electron";
|
import { app, BrowserWindow, shell } from "electron";
|
||||||
|
|
||||||
import { AppRuntimeConfig } from "../config/runtime-config";
|
import { AppRuntimeConfig } from "../config/runtime-config";
|
||||||
import { askToDownloadUpdate, askToInstallUpdate } from "./update-dialogs";
|
import { askToDownloadUpdate, askToInstallUpdate, showDownloadFailedDialog } from "./update-dialogs";
|
||||||
import { loadUpdateSettings, UpdateSettings } from "./update-config";
|
import { loadUpdateSettings, UpdateSettings } from "./update-config";
|
||||||
import { downloadInstaller } from "./update-download";
|
import { downloadInstaller } from "./update-download";
|
||||||
import { buildReleaseUpdate, GiteaRelease, parseGiteaRelease } from "./update-schema";
|
import { buildReleaseUpdate, GiteaRelease, parseGiteaRelease } from "./update-schema";
|
||||||
@@ -76,10 +76,17 @@ async function checkForUpdates({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const installerPath = await downloadInstaller(update, {
|
let installerPath: string;
|
||||||
tempDirectory: app.getPath("temp"),
|
try {
|
||||||
allowInsecureHttp: protocolPolicy.allowInsecureHttp,
|
installerPath = await downloadInstaller(update, {
|
||||||
});
|
tempDirectory: app.getPath("temp"),
|
||||||
|
allowInsecureHttp: protocolPolicy.allowInsecureHttp,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
log("Update installer download failed.", error);
|
||||||
|
await showDownloadFailedDialog(update, error, getParentWindow());
|
||||||
|
return;
|
||||||
|
}
|
||||||
const shouldInstall = await askToInstallUpdate(update, getParentWindow());
|
const shouldInstall = await askToInstallUpdate(update, getParentWindow());
|
||||||
if (!shouldInstall) {
|
if (!shouldInstall) {
|
||||||
await shell.showItemInFolder(installerPath);
|
await shell.showItemInFolder(installerPath);
|
||||||
|
|||||||
@@ -56,3 +56,38 @@ test("downloadInstaller rejects insecure production download URLs", async () =>
|
|||||||
/unsupported protocol/,
|
/unsupported protocol/,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("downloadInstaller reuses existing file if size matches and does not download again", async () => {
|
||||||
|
const tempDirectory = fs.mkdtempSync(path.join(os.tmpdir(), "scoreko-update-download-"));
|
||||||
|
const downloadDirectory = path.join(tempDirectory, "scoreko-updates");
|
||||||
|
fs.mkdirSync(downloadDirectory, { recursive: true });
|
||||||
|
|
||||||
|
const installerPath = path.join(downloadDirectory, "Scoreko_setup_0.2.0.exe");
|
||||||
|
fs.writeFileSync(installerPath, "cached-installer-bytes");
|
||||||
|
const cachedSize = fs.statSync(installerPath).size;
|
||||||
|
|
||||||
|
const previousFetch = globalThis.fetch;
|
||||||
|
globalThis.fetch = async () => {
|
||||||
|
throw new Error("Should not fetch when using cached file!");
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resultPath = await downloadInstaller(
|
||||||
|
{
|
||||||
|
version: "0.2.0",
|
||||||
|
title: "Scoreko 0.2.0",
|
||||||
|
installer: {
|
||||||
|
name: "Scoreko/setup:0.2.0.exe",
|
||||||
|
downloadUrl: "https://updates.local/Scoreko-setup-0.2.0.exe",
|
||||||
|
size: cachedSize,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ tempDirectory, allowInsecureHttp: false },
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(resultPath, installerPath);
|
||||||
|
assert.equal(fs.readFileSync(resultPath, "utf8"), "cached-installer-bytes");
|
||||||
|
} finally {
|
||||||
|
globalThis.fetch = previousFetch;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user