Use local metadata

Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
TheKodeToad 2023-04-06 19:18:36 +01:00
parent e42050cc8a
commit 871d647c93
3 changed files with 73 additions and 21 deletions

View File

@ -36,6 +36,7 @@
#pragma once #pragma once
#include <QString> #include <QString>
#include <QList>
/** /**
* \brief The Config class holds all the build-time information passed from the build system. * \brief The Config class holds all the build-time information passed from the build system.
@ -160,6 +161,7 @@ class Config {
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2"; QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2"; QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
QStringList MODRINTH_MRPACK_HOSTS{"cdn.modrinth.com", "github.com", "raw.githubusercontent.com", "gitlab.com"};
QString FLAME_BASE_URL = "https://api.curseforge.com/v1"; QString FLAME_BASE_URL = "https://api.curseforge.com/v1";

View File

@ -22,14 +22,15 @@
#include <QFileInfo> #include <QFileInfo>
#include <QFileInfoList> #include <QFileInfoList>
#include <QMessageBox> #include <QMessageBox>
#include <QtConcurrent>
#include "Json.h" #include "Json.h"
#include "MMCZip.h" #include "MMCZip.h"
#include "minecraft/MinecraftInstance.h" #include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h" #include "minecraft/PackProfile.h"
#include "minecraft/mod/ModFolderModel.h"
#include "modplatform/modrinth/ModrinthAPI.h" #include "modplatform/modrinth/ModrinthAPI.h"
const QStringList ModrinthPackExportTask::PREFIXES = QStringList({ "mods", "coremods", "resourcepacks", "texturepacks", "shaderpacks" }); const QStringList ModrinthPackExportTask::PREFIXES({ "mods", "coremods", "resourcepacks", "texturepacks", "shaderpacks" });
const QStringList ModrinthPackExportTask::ALLOWED_HOSTS({ "mods", "coremods", "resourcepacks", "texturepacks", "shaderpacks" });
ModrinthPackExportTask::ModrinthPackExportTask(const QString& name, ModrinthPackExportTask::ModrinthPackExportTask(const QString& name,
const QString& version, const QString& version,
@ -45,16 +46,6 @@ void ModrinthPackExportTask::executeTask()
setStatus(tr("Searching for files...")); setStatus(tr("Searching for files..."));
setProgress(0, 0); setProgress(0, 0);
collectFiles(); collectFiles();
if (pendingHashes.isEmpty())
buildZip();
else {
QByteArray* response = new QByteArray;
task = api.currentVersions(pendingHashes.values(), "sha512", response);
connect(task.get(), &NetJob::succeeded, [this, response]() { parseApiResponse(response); });
connect(task.get(), &NetJob::failed, this, &ModrinthPackExportTask::emitFailed);
task->start();
}
} }
bool ModrinthPackExportTask::abort() bool ModrinthPackExportTask::abort()
@ -83,6 +74,17 @@ void ModrinthPackExportTask::collectFiles()
pendingHashes.clear(); pendingHashes.clear();
resolvedFiles.clear(); resolvedFiles.clear();
const MinecraftInstance* mcInstance = dynamic_cast<const MinecraftInstance*>(instance.get());
auto mods = mcInstance->loaderModList();
mods->update();
connect(mods.get(), &ModFolderModel::updateFinished, this, &ModrinthPackExportTask::collectHashes);
}
void ModrinthPackExportTask::collectHashes()
{
const MinecraftInstance* mcInstance = dynamic_cast<const MinecraftInstance*>(instance.get());
auto mods = mcInstance->loaderModList();
QDir mc(instance->gameRoot()); QDir mc(instance->gameRoot());
for (QFileInfo file : files) { for (QFileInfo file : files) {
QString relative = mc.relativeFilePath(file.absoluteFilePath()); QString relative = mc.relativeFilePath(file.absoluteFilePath());
@ -102,13 +104,58 @@ void ModrinthPackExportTask::collectFiles()
continue; continue;
} }
if (!hash.addData(&openFile)) { QByteArray data = openFile.readAll();
qWarning() << "Could not add hash data for" << file; if (openFile.error() != QFileDevice::NoError) {
qWarning() << "Could not read" << file;
continue; continue;
} }
hash.addData(data);
auto allMods = mods->allMods();
if (auto modIter = std::find_if(allMods.begin(), allMods.end(), [&file](Mod* mod) { return mod->fileinfo() == file; });
modIter != allMods.end()) {
Mod* mod = *modIter;
if (mod->metadata() != nullptr) {
QUrl& url = mod->metadata()->url;
// most likely some of these may be from curseforge
if (!url.isEmpty() && BuildConfig.MODRINTH_MRPACK_HOSTS.contains(url.host())) {
qDebug() << "Resolving" << relative << "from index";
// we've already read it
// let's go back!
openFile.seek(openFile.size());
QCryptographicHash hash2(QCryptographicHash::Algorithm::Sha1);
hash2.addData(data);
ResolvedFile file{ hash2.result().toHex(), hash.result().toHex(), url.toString(), openFile.size() };
resolvedFiles[relative] = file;
// nice! we've managed to resolve based on local metadata!
// no need to enqueue it
continue;
}
}
}
qDebug() << "Enqueueing" << relative << "for Modrinth query";
pendingHashes[relative] = hash.result().toHex(); pendingHashes[relative] = hash.result().toHex();
} }
makeApiRequest();
}
void ModrinthPackExportTask::makeApiRequest()
{
if (pendingHashes.isEmpty())
buildZip();
else {
QByteArray* response = new QByteArray;
task = api.currentVersions(pendingHashes.values(), "sha512", response);
connect(task.get(), &NetJob::succeeded, [this, response]() { parseApiResponse(response); });
connect(task.get(), &NetJob::failed, this, &ModrinthPackExportTask::emitFailed);
task->start();
}
} }
void ModrinthPackExportTask::parseApiResponse(QByteArray* response) void ModrinthPackExportTask::parseApiResponse(QByteArray* response)
@ -146,7 +193,7 @@ void ModrinthPackExportTask::parseApiResponse(QByteArray* response)
void ModrinthPackExportTask::buildZip() void ModrinthPackExportTask::buildZip()
{ {
QtConcurrent::run(QThreadPool::globalInstance(), [this]() { QThreadPool::globalInstance()->start([this]() {
setStatus("Adding files..."); setStatus("Adding files...");
QuaZip zip(output); QuaZip zip(output);
if (!zip.open(QuaZip::mdCreate)) { if (!zip.open(QuaZip::mdCreate)) {
@ -183,7 +230,7 @@ void ModrinthPackExportTask::buildZip()
if (!resolvedFiles.contains(relative) && !JlCompress::compressFile(&zip, file.absoluteFilePath(), "overrides/" + relative)) { if (!resolvedFiles.contains(relative) && !JlCompress::compressFile(&zip, file.absoluteFilePath(), "overrides/" + relative)) {
QFile::remove(output); QFile::remove(output);
QMetaObject::invokeMethod( QMetaObject::invokeMethod(
this, [this, relative]() { emitFailed(tr("Could not compress %1").arg(relative)); }, Qt::QueuedConnection); this, [this, relative]() { emitFailed(tr("Could not read and compress %1").arg(relative)); }, Qt::QueuedConnection);
return; return;
} }
i++; i++;
@ -216,10 +263,10 @@ QByteArray ModrinthPackExportTask::generateIndex()
if (mc) { if (mc) {
auto profile = mc->getPackProfile(); auto profile = mc->getPackProfile();
// collect all supported components // collect all supported components
auto minecraft = profile->getComponent("net.minecraft"); ComponentPtr minecraft = profile->getComponent("net.minecraft");
auto quilt = profile->getComponent("org.quiltmc.quilt-loader"); ComponentPtr quilt = profile->getComponent("org.quiltmc.quilt-loader");
auto fabric = profile->getComponent("net.fabricmc.fabric-loader"); ComponentPtr fabric = profile->getComponent("net.fabricmc.fabric-loader");
auto forge = profile->getComponent("net.minecraftforge"); ComponentPtr forge = profile->getComponent("net.minecraftforge");
// convert all available components to mrpack dependencies // convert all available components to mrpack dependencies
QJsonObject dependencies; QJsonObject dependencies;

View File

@ -39,10 +39,11 @@ class ModrinthPackExportTask : public Task {
private: private:
struct ResolvedFile { struct ResolvedFile {
QString sha1, sha512, url; QString sha1, sha512, url;
int size; qint64 size;
}; };
static const QStringList PREFIXES; static const QStringList PREFIXES;
static const QStringList ALLOWED_HOSTS;
// inputs // inputs
const QString name, version, summary; const QString name, version, summary;
@ -58,6 +59,8 @@ class ModrinthPackExportTask : public Task {
bool pendingAbort = false; bool pendingAbort = false;
void collectFiles(); void collectFiles();
void collectHashes();
void makeApiRequest();
void parseApiResponse(QByteArray* response); void parseApiResponse(QByteArray* response);
void buildZip(); void buildZip();