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 manifestURL = "https://cdn.plutonium.pw/updater/prod/info.json"; var basePath = path.join(process.env["LOCALAPPDATA"], "Plutonium"); 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 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(manifest) { 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("File " + file.name + " needs to be downloaded. "); filesToDownload.push(file); continue; } var sum = await getFileSHA1(filePath); if (sum !== file.hash) { console.log("File " + file.name + " needs to be downloaded again. "); filesToDownload.push(file); } else { console.log("File " + file.name + " doesn't need to be downloaded again. "); } } return filesToDownload; } async function downloadFiles(baseURL, files) { for (var f = 0; f < files.length; f++) { var file = files[f]; var filePath = path.join(basePath, ...(file.name.split("/"))); console.log("Downloading file " + file.name + "... "); await httpsDownload(baseURL + file.hash, filePath); } } function launchLauncher() { console.log("Launching the launcher ! "); 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(); }); } console.log("Getting manifest..."); httpsGet(manifestURL).then(async function (response) { try { var data = JSON.parse(response.body); checkFiles(data).then(function (wrongFiles) { if (wrongFiles.length > 0) { console.log("We have " + wrongFiles.length + " files to download. "); downloadFiles(data.baseUrl, 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 { console.log("All files seem good ! "); } }).catch(function (error) { console.error("An error has occurred while checking the files. \n" + error.stack); }); } catch (error) { console.error("An error has occurred while decoding the main manifest. \n" + error.stack); } }).catch(function (error) { console.error("An error has occurred while getting the main manifest. \n" + error.stack); });