From 16a99f86c73c735e0f1dbb2b2397867a605942b0 Mon Sep 17 00:00:00 2001 From: FinnHornhoover Date: Sun, 24 Sep 2023 00:48:01 +0300 Subject: [PATCH] added async hash checking --- assets/js/server-selector.js | 67 ++++++++++----------- index.js | 111 ++++++++++++++++++++++++++++++----- 2 files changed, 128 insertions(+), 50 deletions(-) diff --git a/assets/js/server-selector.js b/assets/js/server-selector.js index 08f245f..0a1a875 100644 --- a/assets/js/server-selector.js +++ b/assets/js/server-selector.js @@ -13,6 +13,11 @@ var configPath = path.join(userData, "config.json"); var serversPath = path.join(userData, "servers.json"); var versionsPath = path.join(userData, "versions.json"); var hashPath = path.join(userData, "hash.txt"); +var cacheRoot = path.join( + userData, + "/../../LocalLow/Unity/Web Player/Cache" +); +var offlineRoot = path.join(cacheRoot, "Offline"); var chunkSize = 1 << 16; var gb = 1 << 30; @@ -492,17 +497,22 @@ function loadCacheList() { $("#cache-tablebody").append(row); - checkPlayableCache(value.name); - checkOfflineCache(value.name); + ipc.send("hash-check", { + localDir: cacheRoot, + cacheMode: "playable", + versionString: value.name, + hashes: versionHashes.playable[value.name], + }); + ipc.send("hash-check", { + localDir: offlineRoot, + cacheMode: "offline", + versionString: value.name, + hashes: versionHashes.offline[value.name], + }); }) } function deletePlayableCache(versionString) { - var cacheRoot = path.join( - userData, - "/../../LocalLow/Unity/Web Player/Cache" - ); - resetCacheNames(); if (versionString === "Offline") { @@ -516,11 +526,6 @@ function deletePlayableCache(versionString) { } function downloadOfflineCache(versionString) { - var offlineRoot = path.join( - userData, - "/../../LocalLow/Unity/Web Player/Cache/Offline" - ); - var buttonDownload = document.getElementById(getCacheButtonID(versionString, "offline", "download")); var buttonFix = document.getElementById(getCacheButtonID(versionString, "offline", "fix")); var buttonDelete = document.getElementById(getCacheButtonID(versionString, "offline", "delete")); @@ -582,11 +587,6 @@ function downloadOfflineCache(versionString) { } function deleteOfflineCache(versionString) { - var offlineRoot = path.join( - userData, - "/../../LocalLow/Unity/Web Player/Cache/Offline" - ); - remotefs.removeSync(path.join(offlineRoot, versionString)); console.log("Offline cache " + versionString + " has been removed!"); @@ -594,11 +594,6 @@ function deleteOfflineCache(versionString) { } function checkPlayableCache(versionString) { - var cacheRoot = path.join( - userData, - "/../../LocalLow/Unity/Web Player/Cache" - ); - var button = document.getElementById(getCacheButtonID(versionString, "playable", "delete")); var label = document.getElementById(getCacheElemID(versionString, "playable", "label")); @@ -630,11 +625,6 @@ function checkPlayableCache(versionString) { } function checkOfflineCache(versionString) { - var offlineRoot = path.join( - userData, - "/../../LocalLow/Unity/Web Player/Cache/Offline" - ); - var buttonDownload = document.getElementById(getCacheButtonID(versionString, "offline", "download")); var buttonFix = document.getElementById(getCacheButtonID(versionString, "offline", "fix")); var buttonDelete = document.getElementById(getCacheButtonID(versionString, "offline", "delete")); @@ -674,10 +664,6 @@ function checkOfflineCache(versionString) { } function resetCacheNames() { - var cacheRoot = path.join( - userData, - "/../../LocalLow/Unity/Web Player/Cache" - ); var currentCache = path.join(cacheRoot, "Fusionfall"); var record = path.join(userData, ".lastver"); @@ -694,10 +680,6 @@ function resetCacheNames() { } function performCacheSwap(newVersion) { - var cacheRoot = path.join( - userData, - "/../../LocalLow/Unity/Web Player/Cache" - ); var currentCache = path.join(cacheRoot, "FusionFall"); var newCache = path.join(cacheRoot, newVersion); var record = path.join(userData, ".lastver"); @@ -910,3 +892,18 @@ ipc.on("download-success", function (versionString) { buttonFix.children[0].setAttribute("class", "fas fa-hammer"); checkOfflineCache(versionString); }); + +ipc.on("hash-update", function (arg) { + var sizes = versionSizes[arg.cacheMode][arg.versionString]; + + if (arg.sizes) { + sizes.intact += arg.sizes.intact; + sizes.altered += arg.sizes.altered; + } else { + sizes.intact = 0; + sizes.altered = 0; + } + + var label = document.getElementById(getCacheElemID(arg.versionString, arg.cacheMode, "label")); + label.innerHTML = getCacheLabelText(sizes); +}); \ No newline at end of file diff --git a/index.js b/index.js index c3de65f..e553241 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ var path = require("path"); var url = require("url"); var http = require("http"); var async = require("async"); +var createHash = require("crypto").createHash; var BrowserWindow = require("browser-window"); var mainWindow = null; @@ -122,6 +123,39 @@ app.on("ready", function () { mainWindow.on("closed", function () { mainWindow = null; }); + + ipc.on("download-files", function (event, arg) { + downloadFiles( + arg.nginxDir, + arg.localDir, + arg.fileRelativePaths, + function (size) { + mainWindow.webContents.send("download-update", { + size: size, + versionString: arg.versionString, + }); + }, + function () { + mainWindow.webContents.send("download-success", arg.versionString); + } + ); + }); + + ipc.on("hash-check", function (event, arg) { + mainWindow.webContents.send("hash-update", { + cacheMode: arg.cacheMode, + versionString: arg.versionString, + // no size sent, reset sizes + }); + + checkHashes(arg.localDir, arg.hashes, function (sizes) { + mainWindow.webContents.send("hash-update", { + cacheMode: arg.cacheMode, + versionString: arg.versionString, + sizes: sizes, + }); + }); + }); }); function showMainWindow() { @@ -239,10 +273,10 @@ function downloadFiles(nginxDir, localDir, fileRelativePaths, updateCallback, al async.eachLimit( fileRelativePaths, 5, // Number of parallel downloads - function(relativePath, callback) { + function (relativePath, callback) { downloadFile(nginxDir, localDir, relativePath, callback, updateCallback); }, - function(err) { + function (err) { if (err) { console.error("Download failed: " + err); } else { @@ -253,19 +287,66 @@ function downloadFiles(nginxDir, localDir, fileRelativePaths, updateCallback, al ); } -ipc.on("download-files", function (event, arg) { - downloadFiles( - arg.nginxDir, - arg.localDir, - arg.fileRelativePaths, - function (size) { - mainWindow.webContents.send("download-update", { - size: size, - versionString: arg.versionString, - }); +function checkHash(localDir, relativePath, fileHash, callback, updateCallback) { + var localPath = path.join(localDir, relativePath); + + var chunkSize = 1 << 16; + var totalCount = 0; + var buff = new Buffer(chunkSize); + var hash = createHash("sha256"); + + fs.open(localPath, "r", function (openErr, file) { + if (openErr) { + if (openErr.code !== "ENOENT") { + console.log("Error opening file for hash check: " + openErr); + } + return; + } + + var updater; + var reader = function () { + fs.read(file, buff, 0, chunkSize, null, updater); + }; + updater = function (readErr, readSize) { + if (readErr) { + console.log("Error reading file for hash check: " + readErr); + } else if (readSize > 0) { + hash.update(buff.slice(0, readSize)); + totalCount += readSize; + + reader(); + } else { + var state = (fileHash === hash.digest(encoding="hex")) ? "intact" : "altered"; + var sizes = { intact: 0, altered: 0 }; + sizes[state] = totalCount; + + fs.close(file, function (fileCloseErr) { + if (fileCloseErr) { + console.log("Error closing file for hash check: " + fileCloseErr); + } else { + callback(null, relativePath); + updateCallback(sizes); + } + }); + } + }; + + reader(); + }); +} + +function checkHashes(localDir, hashes, updateCallback) { + console.log(hashes); + async.eachLimit( + Object.keys(hashes), + 20, + function (relativePath, callback) { + checkHash(localDir, relativePath, hashes[relativePath], callback, updateCallback); }, - function () { - mainWindow.webContents.send("download-success", arg.versionString); + function (err) { + if (err) { + console.log("Hash check failed: " + err); + } } ); -}); \ No newline at end of file +} \ No newline at end of file