dmclc
Version:
Dolphin Minecraft Launcher Core
119 lines (118 loc) • 3.5 kB
JavaScript
import fs from "fs";
import { ensureDir } from "fs-extra";
import got, { HTTPError } from "got";
import path from "path";
import * as streamPromises from "stream/promises";
import { FormattedError } from "../errors/FormattedError.js";
import { transformURL } from "./TransformURL.js";
import { checkFile } from "./check_file.js";
/**
* Download multi files after checking hash.
* @throws RequestError
* @param files A map from URL to path
* @param launcher Launcher
* @returns true if success
*/
export async function checkAndDownloadAll(files, launcher, algorithm = "sha1") {
const promises = [];
files.forEach((v, k) => {
if (v.a === "no") {
promises.push(download(k, v.b, launcher));
}
else {
promises.push(checkAndDownload(k, v.b, v.a, launcher, algorithm));
}
});
return !(await Promise.all(promises)).includes(false);
}
/**
* Download multi files.
* @throws RequestError
* @param files A map from URL to path
* @param launcher Launcher
* @returns true if success
*/
export async function downloadAll(files, launcher) {
const promises = [];
files.forEach((v, k) => {
promises.push(download(k, v, launcher));
});
return !(await Promise.all(promises)).includes(false);
}
/**
* Download a file after checking hash.
* @throws {@link FormattedError}
* @param url - URL.
* @param filename - File name.
* @param mirror - BMCLAPI mirror.
*/
export async function checkAndDownload(url, filename, hash, launcher, algorithm = "sha1") {
if (!await checkFile(filename, hash, algorithm)) {
return await download(url, filename, launcher);
}
return true;
}
/**
* Download a file.
* @throws {@link FormattedError}
* @param url - URL.
* @param filename - File name.
* @param mirror - BMCLAPI mirror.
*/
export async function download(url, filename, launcher) {
if (url.length === 0)
return true;
const dir = path.dirname(filename.toString());
await ensureDir(dir);
let realURL = transformURL(url, launcher.mirror);
if (launcher.downloader)
await launcher.downloader(realURL, filename, url);
else
await downloader(realURL, filename, url);
return true;
}
export async function downloadIntoStream(url, out, launcher) {
if (url.length === 0)
return true;
let realURL = transformURL(url, launcher.mirror);
let failed = true;
for (let i = 0; i < 10; i++) {
try {
await streamPromises.pipeline(got.stream(realURL), out);
failed = false;
break;
}
catch (e) {
if (e instanceof HTTPError) {
if (e.response.statusCode === 404) {
i--;
}
}
}
}
if (failed) {
throw new FormattedError(`Download failed: ${url}`);
}
return true;
}
async function downloader(url, filename, oldURL) {
let failed = true;
for (let i = 0; i < 10; i++) {
try {
await streamPromises.pipeline(got.stream(url), fs.createWriteStream(filename));
failed = false;
break;
}
catch (e) {
if (e instanceof HTTPError) {
if (e.response.statusCode === 404) {
url = oldURL.replaceAll("http://", "https://");
i--;
}
}
}
}
if (failed) {
throw new FormattedError(`Download failed: ${url}`);
}
}