复用下载中心(1/2)

This commit is contained in:
2026-04-12 17:53:16 +08:00
parent 6fcfa438d9
commit e2f59b3cdf
9 changed files with 532 additions and 306 deletions

View File

@@ -1,7 +1,5 @@
import { mkdir } from "node:fs/promises";
import { join } from "node:path";
import { spawn } from "node:child_process";
import { downloadPackage, type DownloadResult } from "../shared-installer";
import type { UpdateCenterItem } from "./types";
export interface Aria2DownloadResult {
@@ -16,8 +14,6 @@ export interface RunAria2DownloadOptions {
signal?: AbortSignal;
}
const PROGRESS_PATTERN = /(\d{1,3}(?:\.\d+)?)%/;
export const runAria2Download = async ({
item,
downloadDir,
@@ -29,68 +25,18 @@ export const runAria2Download = async ({
throw new Error(`Missing download metadata for ${item.pkgname}`);
}
await mkdir(downloadDir, { recursive: true });
const filePath = join(downloadDir, item.fileName);
// Use .metalink URL for download (same as Qt version)
// 使用与商店安装相同的下载逻辑
const metalinkUrl = `${item.downloadUrl}.metalink`;
await new Promise<void>((resolve, reject) => {
const child = spawn("aria2c", [
"--dir",
downloadDir,
"--out",
item.fileName,
"--enable-rpc=false",
"--console-log-level=warn",
"--summary-interval=1",
"--allow-overwrite=true",
"--connect-timeout=30",
"--max-tries=3",
metalinkUrl,
]);
const abortDownload = () => {
child.kill();
reject(new Error(`Update task cancelled: ${item.pkgname}`));
};
if (signal?.aborted) {
abortDownload();
return;
}
signal?.addEventListener("abort", abortDownload, { once: true });
const handleOutput = (chunk: Buffer) => {
const message = chunk.toString().trim();
if (!message) {
return;
}
onLog?.(message);
const progressMatch = message.match(PROGRESS_PATTERN);
if (progressMatch) {
onProgress?.(Number(progressMatch[1]));
}
};
child.stdout?.on("data", handleOutput);
child.stderr?.on("data", handleOutput);
child.on("error", reject);
child.on("close", (code) => {
signal?.removeEventListener("abort", abortDownload);
if (code === 0) {
resolve();
return;
}
reject(new Error(`aria2c exited with code ${code ?? -1}`));
});
const result = await downloadPackage({
pkgname: item.pkgname,
metalinkUrl,
filename: item.fileName,
downloadDir,
onLog,
onProgress,
signal,
});
onProgress?.(100);
return { filePath };
return { filePath: result.filePath };
};