aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
authorflow <flowlnlnln@gmail.com>2022-07-24 15:11:41 -0300
committerflow <flowlnlnln@gmail.com>2022-07-24 17:46:54 -0300
commit631a93bcd83272b3e59ca6a06aaa18a1a6b03167 (patch)
tree175991368c48f83e69e6c89bc71e46b357ae6706 /launcher
parentb1763353ea0fd2d1924e3560f0a674cb6260721b (diff)
downloadPrismLauncher-631a93bcd83272b3e59ca6a06aaa18a1a6b03167.tar.gz
PrismLauncher-631a93bcd83272b3e59ca6a06aaa18a1a6b03167.tar.bz2
PrismLauncher-631a93bcd83272b3e59ca6a06aaa18a1a6b03167.zip
refactor: add a HashUtils place for hashing stuff
Signed-off-by: flow <flowlnlnln@gmail.com>
Diffstat (limited to 'launcher')
-rw-r--r--launcher/CMakeLists.txt2
-rw-r--r--launcher/modplatform/helpers/HashUtils.cpp81
-rw-r--r--launcher/modplatform/helpers/HashUtils.h47
-rw-r--r--launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp41
4 files changed, 152 insertions, 19 deletions
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index a4a1315d..3811ceaa 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -494,6 +494,8 @@ set(API_SOURCES
modplatform/modrinth/ModrinthAPI.cpp
modplatform/helpers/NetworkModAPI.h
modplatform/helpers/NetworkModAPI.cpp
+ modplatform/helpers/HashUtils.h
+ modplatform/helpers/HashUtils.cpp
)
set(FTB_SOURCES
diff --git a/launcher/modplatform/helpers/HashUtils.cpp b/launcher/modplatform/helpers/HashUtils.cpp
new file mode 100644
index 00000000..a7bbaba5
--- /dev/null
+++ b/launcher/modplatform/helpers/HashUtils.cpp
@@ -0,0 +1,81 @@
+#include "HashUtils.h"
+
+#include <QDebug>
+#include <QFile>
+
+#include "FileSystem.h"
+
+#include <MurmurHash2.h>
+
+namespace Hashing {
+
+static ModPlatform::ProviderCapabilities ProviderCaps;
+
+Hasher::Ptr createHasher(QString file_path, ModPlatform::Provider provider)
+{
+ switch (provider) {
+ case ModPlatform::Provider::MODRINTH:
+ return createModrinthHasher(file_path);
+ case ModPlatform::Provider::FLAME:
+ return createFlameHasher(file_path);
+ default:
+ qCritical() << "[Hashing]"
+ << "Unrecognized mod platform!";
+ return nullptr;
+ }
+}
+
+Hasher::Ptr createModrinthHasher(QString file_path)
+{
+ return new ModrinthHasher(file_path);
+}
+
+Hasher::Ptr createFlameHasher(QString file_path)
+{
+ return new FlameHasher(file_path);
+}
+
+void ModrinthHasher::executeTask()
+{
+ QFile file(m_path);
+
+ try {
+ file.open(QFile::ReadOnly);
+ } catch (FS::FileSystemException& e) {
+ qCritical() << QString("Failed to open JAR file in %1").arg(m_path);
+ qCritical() << QString("Reason: ") << e.cause();
+
+ emitFailed("Failed to open file for hashing.");
+ return;
+ }
+
+ auto hash_type = ProviderCaps.hashType(ModPlatform::Provider::MODRINTH).first();
+ m_hash = ProviderCaps.hash(ModPlatform::Provider::MODRINTH, &file, hash_type);
+
+ file.close();
+
+ if (m_hash.isEmpty()) {
+ emitFailed("Empty hash!");
+ } else {
+ emitSucceeded();
+ }
+}
+
+void FlameHasher::executeTask()
+{
+ // CF-specific
+ auto should_filter_out = [](char c) { return (c == 9 || c == 10 || c == 13 || c == 32); };
+
+ std::ifstream file_stream(m_path.toStdString(), std::ifstream::binary);
+ // TODO: This is very heavy work, but apparently QtConcurrent can't use move semantics, so we can't boop this to another thread.
+ // How do we make this non-blocking then?
+ m_hash = QString::number(MurmurHash2(std::move(file_stream), 4 * MiB, should_filter_out));
+
+ if (m_hash.isEmpty()) {
+ emitFailed("Empty hash!");
+ } else {
+ emitSucceeded();
+ }
+}
+
+} // namespace Hashing
diff --git a/launcher/modplatform/helpers/HashUtils.h b/launcher/modplatform/helpers/HashUtils.h
new file mode 100644
index 00000000..38fddf03
--- /dev/null
+++ b/launcher/modplatform/helpers/HashUtils.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <QString>
+
+#include "modplatform/ModIndex.h"
+#include "tasks/Task.h"
+
+namespace Hashing {
+
+class Hasher : public Task {
+ public:
+ using Ptr = shared_qobject_ptr<Hasher>;
+
+ Hasher(QString file_path) : m_path(std::move(file_path)) {}
+
+ /* We can't really abort this task, but we can say we aborted and finish our thing quickly :) */
+ bool abort() override { return true; }
+
+ void executeTask() override = 0;
+
+ QString getResult() const { return m_hash; };
+ QString getPath() const { return m_path; };
+
+ protected:
+ QString m_hash;
+ QString m_path;
+};
+
+class FlameHasher : public Hasher {
+ public:
+ FlameHasher(QString file_path) : Hasher(file_path) { setObjectName(QString("FlameHasher: %1").arg(file_path)); }
+
+ void executeTask() override;
+};
+
+class ModrinthHasher : public Hasher {
+ public:
+ ModrinthHasher(QString file_path) : Hasher(file_path) { setObjectName(QString("ModrinthHasher: %1").arg(file_path)); }
+
+ void executeTask() override;
+};
+
+Hasher::Ptr createHasher(QString file_path, ModPlatform::Provider provider);
+Hasher::Ptr createFlameHasher(QString file_path);
+Hasher::Ptr createModrinthHasher(QString file_path);
+
+} // namespace Hashing
diff --git a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp
index f4898591..e2d27547 100644
--- a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp
+++ b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp
@@ -2,11 +2,14 @@
#include "ModrinthAPI.h"
#include "ModrinthPackIndex.h"
-#include "FileSystem.h"
#include "Json.h"
#include "ModDownloadTask.h"
+#include "modplatform/helpers/HashUtils.h"
+
+#include "tasks/ConcurrentTask.h"
+
static ModrinthAPI api;
static ModPlatform::ProviderCapabilities ProviderCaps;
@@ -32,6 +35,8 @@ void ModrinthCheckUpdate::executeTask()
// Create all hashes
QStringList hashes;
auto best_hash_type = ProviderCaps.hashType(ModPlatform::Provider::MODRINTH).first();
+
+ ConcurrentTask hashing_task(this, "MakeModrinthHashesTask", 10);
for (auto* mod : m_mods) {
if (!mod->enabled()) {
emit checkFailed(mod, tr("Disabled mods won't be updated, to prevent mod duplication issues!"));
@@ -44,27 +49,25 @@ void ModrinthCheckUpdate::executeTask()
// need to generate a new hash if the current one is innadequate
// (though it will rarely happen, if at all)
if (mod->metadata()->hash_format != best_hash_type) {
- QByteArray jar_data;
-
- QFile file(mod->fileinfo().absoluteFilePath());
- try {
- file.open(QFile::ReadOnly);
- } catch (FS::FileSystemException& e) {
- qCritical() << QString("Failed to open JAR file of %1").arg(mod->name());
- qCritical() << QString("Reason: ") << e.cause();
-
- failed(e.what());
- return;
- }
-
- hash = ProviderCaps.hash(ModPlatform::Provider::MODRINTH, &file, best_hash_type);
- file.close();
+ auto hash_task = Hashing::createModrinthHasher(mod->fileinfo().absoluteFilePath());
+ connect(hash_task.get(), &Task::succeeded, [&] {
+ QString hash (hash_task->getResult());
+ hashes.append(hash);
+ mappings.insert(hash, mod);
+ });
+ connect(hash_task.get(), &Task::failed, [this, hash_task] { failed("Failed to generate hash"); });
+ hashing_task.addTask(hash_task);
+ } else {
+ hashes.append(hash);
+ mappings.insert(hash, mod);
}
-
- hashes.append(hash);
- mappings.insert(hash, mod);
}
+ QEventLoop loop;
+ connect(&hashing_task, &Task::finished, [&loop]{ loop.quit(); });
+ hashing_task.start();
+ loop.exec();
+
auto* response = new QByteArray();
auto job = api.latestVersions(hashes, best_hash_type, m_game_versions, m_loaders, response);