const fs = require("node:fs"); const https = require("node:https"); const path = require("node:path"); const child_process = require("node:child_process"); const crypto = require("node:crypto"); const manifestURLs = [ "https://cdn.plutonium.pw/updater/prod/info.json", "https://cdn.kroniker.fr/updater/prod/info.json" ]; var basePath = path.join(process.env["LOCALAPPDATA"], "Plutonium"); var mustSkipCustom = false; for (var a = 0; a < process.argv.length; a++) { if (a > 0) { switch (process.argv[a - 1]) { case "--install-dir": basePath = process.argv[a]; break; default: break; } } switch (process.argv[a]) { case "--skip-custom": mustSkipCustom = true; break; default: break; } } var manifest = { "files": [] }; function httpsGet(url) { return new Promise(function (resolve, reject) { var request = https.request(url, function (response) { var body = ""; response.setEncoding("utf-8"); response.on("data", function (chunk) { body += chunk; }); response.on("end", function () { resolve({ "status": response.statusCode, "headers": response.headers, "body": body }); }); }); request.on("error", function (error) { reject(error.message); }); request.end(); }); } function httpsDownload(url, filePath) { return new Promise(function (resolve, reject) { var fileDirectory = path.dirname(filePath); if (!fs.existsSync(fileDirectory)) { fs.mkdirSync(fileDirectory, { "recursive": true }); } var fileWriter = fs.createWriteStream(filePath); var request = https.request(url, function (response) { var body = ""; response.pipe(fileWriter); response.on("end", function () { resolve(); }); }); request.on("error", function (error) { reject(error.message); fileWriter.close(); }); request.end(); }); } function readAndMergeManifest(manifestURL) { return new Promise(function (resolve, reject) { httpsGet(manifestURL).then(function (response) { try { var data = JSON.parse(response.body); if ("version" in data) manifest.version = data.version; for (var f = 0; f < data.files.length; f++) { var file = data.files[f]; file.baseUrl = data.baseUrl; var fileMatch = manifest.files.find(entry => entry.name == file.name); if (typeof fileMatch == "object") { var matchIndex = manifest.files.indexOf(fileMatch); manifest.files.splice(matchIndex, 1); } manifest.files.push(file); } resolve(); } catch (error) { reject(error); } }).catch(function (error) { reject(error); }); }); } function getFileSHA1(filePath) { return new Promise(function (resolve, reject) { var fileStream = fs.createReadStream(filePath); var hash = crypto.createHash("sha1"); hash.setEncoding("hex"); fileStream.on("end", function () { hash.end(); resolve(hash.read()); }); fileStream.pipe(hash); }); } async function checkFiles() { var filesToDownload = []; for (var f = 0; f < manifest.files.length; f++) { var file = manifest.files[f]; var filePath = path.join(basePath, ...(file.name.split("/"))); if (!fs.existsSync(filePath)) { console.log("\x1b[32mFile " + file.name + " needs to be downloaded.\x1b[0m"); filesToDownload.push(file); continue; } var sum = await getFileSHA1(filePath); if (sum !== file.hash) { console.log("\x1b[33mFile " + file.name + " needs to be updated.\x1b[0m"); filesToDownload.push(file); } } return filesToDownload; } async function downloadFiles(files) { for (var f = 0; f < files.length; f++) { var file = files[f]; var filePath = path.join(basePath, ...(file.name.split("/"))); console.log("\x1b[35mDownloading file " + file.name + "...\x1b[0m"); await httpsDownload(file.baseUrl + file.hash, filePath); } return true; } function launchLauncher() { return new Promise(function (resolve, reject) { var launcherPath = path.join(basePath, "bin", "plutonium-launcher-win32.exe"); var subprocess = child_process.spawn(launcherPath, [], { "detached": true, "stdio": "ignore" }); subprocess.on("spawn", function () { subprocess.unref(); resolve(); }); subprocess.on("error", function (error) { reject(error); }); }); } process.title = "Kroniker Updater - Plutonium Black Ops II"; process.stdout.write("\x1b]0;Kroniker Updater - Plutonium Black Ops II\x07"); (async function () { var manifestCount = mustSkipCustom ? 1 : manifestURLs.length; for (var m = 0; m < manifestCount; m++) { try { await readAndMergeManifest(manifestURLs[m]); } catch (error) { console.error("An error has occurred while obtaining manifest " + (m + 1) + " : " + error.message); } } console.log("\x1b[36mChecking the files...\x1b[0m"); checkFiles().then(function (wrongFiles) { if (wrongFiles.length > 0) { console.log("We have " + wrongFiles.length + " files to download. "); downloadFiles(wrongFiles).then(function () { launchLauncher().then(function () { }).catch(function (error) { console.error("An error has occurred while opening the launcher. \n" + error.stack); }); }).catch(function (error) { console.error("An error has occurred while downloading a file. \n" + error.stack); }); } else { launchLauncher().then(function () { }).catch(function (error) { console.error("An error has occurred while opening the launcher. \n" + error.stack); }); } }).catch(function (error) { console.error("An error has occurred while checking the files. \n" + error.stack); }); })();