diff --git a/src/core/assets.ts b/src/core/assets.ts index a30482e..45702e7 100644 --- a/src/core/assets.ts +++ b/src/core/assets.ts @@ -44,7 +44,10 @@ export async function AssetsDownloader( } } - const pool = new DownloadPool(files, { concurrency: 5 }); + const pool = new DownloadPool(files, { + pQueueOptions: { concurrency: 5 }, + overwrite: false, + }); return pool; } diff --git a/src/core/java.ts b/src/core/java.ts index d08637f..067415a 100644 --- a/src/core/java.ts +++ b/src/core/java.ts @@ -30,8 +30,8 @@ export async function JavaDownloader( ) ).files; - const componentDestination = path.join(rootDestination, component) - await ensureDir(componentDestination, true) + const componentDestination = path.join(rootDestination, component); + await ensureDir(componentDestination, true); const files: PoolFile[] = []; @@ -50,10 +50,13 @@ export async function JavaDownloader( } } - const pool = new DownloadPool(files, { concurrency: 5 }, async () => { - if (process.platform !== "win32") { - await fs.chmod(path.join(componentDestination, "bin/java"), 0o777); - } + const pool = new DownloadPool(files, { + pQueueOptions: { concurrency: 5 }, + cleanup: async () => { + if (process.platform !== "win32") { + await fs.chmod(path.join(componentDestination, "bin/java"), 0o777); + } + }, }); return pool; diff --git a/src/core/libraries.ts b/src/core/libraries.ts index 4aed67a..20bde90 100644 --- a/src/core/libraries.ts +++ b/src/core/libraries.ts @@ -28,7 +28,7 @@ export async function LibrariesDownloader( ) { const libs = getLibraries(versionManifest, librariesRoot); - const dPool = new DownloadPool(libs, { concurrency: 5 }); + const dPool = new DownloadPool(libs, { pQueueOptions: { concurrency: 5 } }); return dPool; } diff --git a/src/core/natives.ts b/src/core/natives.ts index 4469804..9c707f5 100644 --- a/src/core/natives.ts +++ b/src/core/natives.ts @@ -47,10 +47,12 @@ export async function NativesDownloader( natives, nativesPath, tempNativesPath, - { - concurrency: 5, - }, [".git", "META-INF", ".sha1"], + { + pQueueOptions: { + concurrency: 5, + }, + }, ); return pool; diff --git a/src/utils/fetch.ts b/src/utils/fetch.ts index 29e277f..cb924b0 100644 --- a/src/utils/fetch.ts +++ b/src/utils/fetch.ts @@ -1,29 +1,32 @@ import fs from "fs"; import { pipeline } from "stream/promises"; -import { PoolFile } from "./types"; -import { ensureDir } from "./fs"; +import { PoolFile, PoolOptions } from "./types"; +import { ensureDir, exists } from "./fs"; import path from "path"; -import PQueue, { Options } from "p-queue"; +import PQueue from "p-queue"; export async function fetchJson(url: string): Promise { return await (await fetch(url)).json(); } -export async function downloadFile(file: PoolFile) { - try { - await ensureDir(path.dirname(file.path), true); - const res = await fetch(file.url); +export async function downloadFile(file: PoolFile, overwrite = true) { + if (overwrite || !(await exists(file.path))) { + try { + await ensureDir(path.dirname(file.path), true); + const res = await fetch(file.url); - if (!res.ok) - throw new Error( - `Failed to download ${file.url}: ${res.status} ${res.statusText}`, - ); - await pipeline(res.body, fs.createWriteStream(file.path)); - } catch (error) { - if (error.name !== "AbortError") throw error; - return; + if (!res.ok) + throw new Error( + `Failed to download ${file.url}: ${res.status} ${res.statusText}`, + ); + await pipeline(res.body, fs.createWriteStream(file.path)); + } catch (error) { + if (error.name !== "AbortError") throw error; + return; + } } } + export class DownloadPool extends PQueue { done = 0; total = 0; @@ -31,16 +34,17 @@ export class DownloadPool extends PQueue { totalSize = 0; elements: PoolFile[]; cleanup: () => Promise; + overwrite: boolean; constructor( elements: PoolFile[], - options?: Options, - cleanup?: () => Promise, + options: PoolOptions = { pQueueOptions: {}, overwrite: true }, ) { - super(options); + super(options.pQueueOptions); this.elements = elements; this.total = this.elements.length; - this.cleanup = cleanup; + this.cleanup = options.cleanup; + this.overwrite = options.overwrite; } async run() { @@ -48,7 +52,7 @@ export class DownloadPool extends PQueue { this.totalSize += element.size; this.add(async () => { - await downloadFile(element); + await downloadFile(element, this.overwrite); // update status here to ensure that it is run before "completed" events listeners this.done++; this.doneSize += element.size; @@ -60,4 +64,4 @@ export class DownloadPool extends PQueue { await this.cleanup(); } } -} \ No newline at end of file +} diff --git a/src/utils/types.ts b/src/utils/types.ts index 70b3d01..c2a418b 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -1,3 +1,5 @@ +import { type Options as PQueueOptions } from "p-queue"; + export type RuntimeComponent = | "java-runtime-alpha" | "java-runtime-beta" @@ -212,3 +214,9 @@ export type LauncherProfiles = { }; }; }; + +export type PoolOptions = { + pQueueOptions: PQueueOptions; + cleanup?: () => Promise; + overwrite?: boolean; +}; diff --git a/src/utils/unzip.ts b/src/utils/unzip.ts index 506c446..e30e799 100644 --- a/src/utils/unzip.ts +++ b/src/utils/unzip.ts @@ -1,8 +1,7 @@ import AdmZip from "adm-zip"; -import { PoolFile } from "./types"; +import { PoolFile, PoolOptions } from "./types"; import { downloadFile, DownloadPool } from "./fetch"; import path from "path"; -import { Options } from "p-queue"; export function unzipAll(from: string, to: string, filters: string[]) { const zip = new AdmZip(from); @@ -12,7 +11,7 @@ export function unzipAll(from: string, to: string, filters: string[]) { for (const filter of filters) { if (entry.entryName.includes(filter)) { shouldSkip = true; - console.log("skipping", entry.entryName) + console.log("skipping", entry.entryName); } } if (shouldSkip) continue; @@ -29,8 +28,8 @@ export class DownloadAndUnzipPool extends DownloadPool { elements: PoolFile[], destination: string, tempPath: string, - options?: Options, filters: string[] = [], + options: PoolOptions = { pQueueOptions: {}, overwrite: true }, ) { super(elements, options); this.tempPath = tempPath;