watch filesystem, compute and match hashes
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
		| @@ -35,6 +35,18 @@ Hasher::Ptr createFlameHasher(QString file_path) | ||||
|     return new FlameHasher(file_path); | ||||
| } | ||||
|  | ||||
| Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider) | ||||
| { | ||||
|     return new BlockedModHasher(file_path, provider); | ||||
| } | ||||
|  | ||||
| Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider, QString type) | ||||
| { | ||||
|     auto hasher = new BlockedModHasher(file_path, provider); | ||||
|     hasher->useHashType(type); | ||||
|     return hasher; | ||||
| } | ||||
|  | ||||
| void ModrinthHasher::executeTask() | ||||
| { | ||||
|     QFile file(m_path); | ||||
| @@ -78,4 +90,50 @@ void FlameHasher::executeTask() | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| BlockedModHasher::BlockedModHasher(QString file_path, ModPlatform::Provider provider)  | ||||
|     : Hasher(file_path), provider(provider) {  | ||||
|     setObjectName(QString("BlockedModHasher: %1").arg(file_path));  | ||||
|     hash_type = ProviderCaps.hashType(provider).first(); | ||||
| } | ||||
|  | ||||
| void BlockedModHasher::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; | ||||
|     } | ||||
|  | ||||
|     m_hash = ProviderCaps.hash(provider, &file, hash_type); | ||||
|  | ||||
|     file.close(); | ||||
|  | ||||
|     if (m_hash.isEmpty()) { | ||||
|         emitFailed("Empty hash!"); | ||||
|     } else { | ||||
|         emitSucceeded(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| QStringList BlockedModHasher::getHashTypes() { | ||||
|     return ProviderCaps.hashType(provider); | ||||
| } | ||||
|  | ||||
| bool BlockedModHasher::useHashType(QString type) { | ||||
|     auto types = ProviderCaps.hashType(provider); | ||||
|     if (types.contains(type)) { | ||||
|         hash_type = type; | ||||
|         return true; | ||||
|     } | ||||
|     qDebug() << "Bad hash type " << type << " for provider"; | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| }  // namespace Hashing | ||||
|   | ||||
| @@ -40,8 +40,23 @@ class ModrinthHasher : public Hasher { | ||||
|     void executeTask() override; | ||||
| }; | ||||
|  | ||||
| class BlockedModHasher : public Hasher { | ||||
|    public: | ||||
|     BlockedModHasher(QString file_path, ModPlatform::Provider provider); | ||||
|  | ||||
|     void executeTask() override; | ||||
|  | ||||
|     QStringList getHashTypes(); | ||||
|     bool useHashType(QString type); | ||||
|    private: | ||||
|     ModPlatform::Provider provider; | ||||
|     QString hash_type; | ||||
| }; | ||||
|  | ||||
| Hasher::Ptr createHasher(QString file_path, ModPlatform::Provider provider); | ||||
| Hasher::Ptr createFlameHasher(QString file_path); | ||||
| Hasher::Ptr createModrinthHasher(QString file_path); | ||||
| Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider); | ||||
| Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider, QString type); | ||||
|  | ||||
| }  // namespace Hashing | ||||
|   | ||||
| @@ -1,3 +1,6 @@ | ||||
| #include <qfileinfo.h> | ||||
| #include <qnamespace.h> | ||||
| #include "Application.h" | ||||
| #include "BlockedModsDialog.h" | ||||
| #include "ui_BlockedModsDialog.h" | ||||
| #include <QPushButton> | ||||
| @@ -5,20 +8,29 @@ | ||||
| #include <QDesktopServices> | ||||
|  | ||||
| #include <QDebug> | ||||
| #include <QStandardPaths> | ||||
|  | ||||
|  | ||||
| BlockedModsDialog::BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, const QList<BlockedMod> &mods) : | ||||
|  | ||||
|  | ||||
| BlockedModsDialog::BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, QList<BlockedMod> &mods) : | ||||
|         QDialog(parent), ui(new Ui::BlockedModsDialog), mods(mods) { | ||||
|     ui->setupUi(this); | ||||
|  | ||||
|     auto openAllButton = ui->buttonBox->addButton(tr("Open All"), QDialogButtonBox::ActionRole); | ||||
|     connect(openAllButton, &QPushButton::clicked, this, &BlockedModsDialog::openAll); | ||||
|  | ||||
|     connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &BlockedModsDialog::directoryChanged); | ||||
|  | ||||
|     hashing_task = shared_qobject_ptr<ConcurrentTask>(new ConcurrentTask(this, "MakeHashesTask", 10)); | ||||
|      | ||||
|     qDebug() << "Mods List: " << mods; | ||||
|  | ||||
|     setupWatch(); | ||||
|     scanPaths(true); | ||||
|  | ||||
|     this->setWindowTitle(title); | ||||
|     ui->label->setText(text); | ||||
|     ui->textBrowser->setText(body); | ||||
|     update(); | ||||
| } | ||||
|  | ||||
| @@ -50,6 +62,110 @@ void BlockedModsDialog::update() { | ||||
|     ui->textBrowser->setText(text); | ||||
| } | ||||
|  | ||||
| void BlockedModsDialog::directoryChanged(QString path) { | ||||
|     qDebug() << "Directory changed: " << path; | ||||
|     scanPath(path, false); | ||||
| } | ||||
|  | ||||
|  | ||||
| void BlockedModsDialog::setupWatch() { | ||||
|     const QString downloadsFolder = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); | ||||
|     const QString modsFolder = APPLICATION->settings()->get("CentralModsDir").toString(); | ||||
|     watcher.addPath(downloadsFolder); | ||||
|     watcher.addPath(modsFolder); | ||||
| } | ||||
|  | ||||
| void BlockedModsDialog::scanPaths(bool init) { | ||||
|     for (auto &dir : watcher.directories()) { | ||||
|         scanPath(dir, init); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void BlockedModsDialog::scanPath(QString path, bool init) { | ||||
|  | ||||
|     QDir scan_dir(path); | ||||
|     QDirIterator scan_it(path, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::NoIteratorFlags); | ||||
|     while (scan_it.hasNext()) { | ||||
|         QString file = scan_it.next(); | ||||
|  | ||||
|         if (checked_paths.contains(file)){ | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         if (!checkValidPath(file)) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         auto hash_task = Hashing::createBlockedModHasher(file, ModPlatform::Provider::FLAME, "sha1"); | ||||
|  | ||||
|         qDebug() << "Creating Hash task for path: " << file; | ||||
|  | ||||
|         connect(hash_task.get(), &Task::succeeded, [this, hash_task, file] {  | ||||
|             checkMatchHash(hash_task->getResult(), file); | ||||
|         }); | ||||
|         connect(hash_task.get(), &Task::failed, [this, hash_task, file] {  | ||||
|             qDebug() << "Failed to hash path: " << file; | ||||
|         }); | ||||
|  | ||||
|         if (init) { | ||||
|             checked_paths.insert(file); | ||||
|         } | ||||
|          | ||||
|         hashing_task->addTask(hash_task); | ||||
|     } | ||||
|  | ||||
|     hashing_task->start(); | ||||
|  | ||||
| } | ||||
|  | ||||
| void BlockedModsDialog::checkMatchHash(QString hash, QString path) { | ||||
|     bool match = false; | ||||
|  | ||||
|     qDebug() << "Checking for match on hash: " << hash << " | From path:" << path; | ||||
|  | ||||
|     for (auto &mod : mods) { | ||||
|         if (mod.matched) { | ||||
|             continue; | ||||
|         } | ||||
|         if (mod.hash.compare(hash, Qt::CaseInsensitive) == 0) { | ||||
|             mod.matched = true; | ||||
|             mod.localPath = path; | ||||
|             match = true; | ||||
|  | ||||
|             qDebug() << "Hash match found: " << mod.name << " " << hash << " | From path:" << path; | ||||
|  | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (match) { | ||||
|         update(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool BlockedModsDialog::checkValidPath(QString path) { | ||||
|  | ||||
|     QFileInfo file = QFileInfo(path); | ||||
|     QString filename = file.fileName(); | ||||
|  | ||||
|     for (auto &mod : mods) { | ||||
|         if (mod.name.compare(filename, Qt::CaseInsensitive) == 0) { | ||||
|             qDebug() << "Name match found: " << mod.name << " | From path:" << path; | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| bool BlockedModsDialog::allModsMatched() { | ||||
|     for (auto &mod : mods) { | ||||
|         if (!mod.matched) | ||||
|             return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
|  | ||||
| QDebug operator<<(QDebug debug, const BlockedMod &m) { | ||||
|     QDebugStateSaver saver(debug); | ||||
|   | ||||
| @@ -1,7 +1,14 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <QDialog> | ||||
| #include <QString> | ||||
| #include <QList> | ||||
|  | ||||
| #include <QFileSystemWatcher> | ||||
|  | ||||
| #include "modplatform/helpers/HashUtils.h" | ||||
|  | ||||
| #include "tasks/ConcurrentTask.h" | ||||
|  | ||||
| struct BlockedMod { | ||||
|     QString name; | ||||
| @@ -20,15 +27,27 @@ class BlockedModsDialog : public QDialog { | ||||
| Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, const QList<BlockedMod> &mods); | ||||
|     BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, QList<BlockedMod> &mods); | ||||
|  | ||||
|     ~BlockedModsDialog() override; | ||||
|  | ||||
|  | ||||
| private: | ||||
|     Ui::BlockedModsDialog *ui; | ||||
|     const QList<BlockedMod> &mods; | ||||
|     QList<BlockedMod> &mods; | ||||
|     QFileSystemWatcher watcher; | ||||
|     shared_qobject_ptr<ConcurrentTask> hashing_task; | ||||
|     QSet<QString> checked_paths; | ||||
|  | ||||
|     void openAll(); | ||||
|     void update(); | ||||
|     void directoryChanged(QString path); | ||||
|     void setupWatch(); | ||||
|     void scanPaths(bool init); | ||||
|     void scanPath(QString path, bool init); | ||||
|     void checkMatchHash(QString hash, QString path); | ||||
|  | ||||
|     bool checkValidPath(QString path); | ||||
|     bool allModsMatched(); | ||||
| }; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user