From 63330bf1113e0da3f2733ec9d6ad98fc13ad4bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 30 Jun 2019 11:03:59 +0200 Subject: [PATCH] NOISSUE connect twitch URL resolving to modpack resolving. works now. --- .../modplatform/flame/FileResolvingTask.cpp | 66 ++----------------- api/logic/modplatform/flame/PackManifest.cpp | 60 +++++++++++++++++ api/logic/modplatform/flame/PackManifest.h | 3 + .../modplatform/flame/UrlResolvingTask.cpp | 58 ++++++++++++---- .../modplatform/flame/UrlResolvingTask.h | 7 +- application/pages/modplatform/TwitchPage.cpp | 10 ++- 6 files changed, 127 insertions(+), 77 deletions(-) diff --git a/api/logic/modplatform/flame/FileResolvingTask.cpp b/api/logic/modplatform/flame/FileResolvingTask.cpp index 24cafcdd..295574f0 100644 --- a/api/logic/modplatform/flame/FileResolvingTask.cpp +++ b/api/logic/modplatform/flame/FileResolvingTask.cpp @@ -1,7 +1,9 @@ #include "FileResolvingTask.h" #include "Json.h" -const char * metabase = "https://cursemeta.dries007.net"; +namespace { + const char * metabase = "https://cursemeta.dries007.net"; +} Flame::FileResolvingTask::FileResolvingTask(Flame::Manifest& toProcess) : m_toProcess(toProcess) @@ -34,70 +36,14 @@ void Flame::FileResolvingTask::netJobFinished() int index = 0; for(auto & bytes: results) { + auto & out = m_toProcess.files[index]; try { - auto doc = Json::requireDocument(bytes); - auto obj = Json::requireObject(doc); - auto & out = m_toProcess.files[index]; - // result code signifies true failure. - if(obj.contains("code")) - { - qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a negative result:"; - qCritical() << bytes; - failed = true; - continue; - } - out.fileName = Json::requireString(obj, "FileNameOnDisk"); - QString rawUrl = Json::requireString(obj, "DownloadURL"); - out.url = QUrl(rawUrl, QUrl::TolerantMode); - if(!out.url.isValid()) - { - throw JSONValidationError(QString("Invalid URL: %1").arg(rawUrl)); - } - // This is a piece of a Flame project JSON pulled out into the file metadata (here) for convenience - // It is also optional - QJsonObject projObj = Json::ensureObject(obj, "_Project", {}); - if(!projObj.isEmpty()) - { - QString strType = Json::ensureString(projObj, "PackageType", "mod").toLower(); - if(strType == "singlefile") - { - out.type = File::Type::SingleFile; - } - else if(strType == "ctoc") - { - out.type = File::Type::Ctoc; - } - else if(strType == "cmod2") - { - out.type = File::Type::Cmod2; - } - else if(strType == "mod") - { - out.type = File::Type::Mod; - } - else if(strType == "folder") - { - out.type = File::Type::Folder; - } - else if(strType == "modpack") - { - out.type = File::Type::Modpack; - } - else - { - qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of unknown file type:" << strType; - out.type = File::Type::Unknown; - failed = true; - continue; - } - out.targetFolder = Json::ensureString(projObj, "Path", "mods"); - } - out.resolved = true; + failed &= (!out.parseFromBytes(bytes)); } catch (const JSONValidationError &e) { - auto & out = m_toProcess.files[index]; + qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a parsing error:"; qCritical() << e.cause(); qCritical() << "JSON:"; diff --git a/api/logic/modplatform/flame/PackManifest.cpp b/api/logic/modplatform/flame/PackManifest.cpp index 0f57c9bc..1db0a161 100644 --- a/api/logic/modplatform/flame/PackManifest.cpp +++ b/api/logic/modplatform/flame/PackManifest.cpp @@ -64,3 +64,63 @@ void Flame::loadManifest(Flame::Manifest & m, const QString &filepath) } loadManifestV1(m, obj); } + +bool Flame::File::parseFromBytes(const QByteArray& bytes) +{ + auto doc = Json::requireDocument(bytes); + auto obj = Json::requireObject(doc); + // result code signifies true failure. + if(obj.contains("code")) + { + qCritical() << "Resolving of" << projectId << fileId << "failed because of a negative result:"; + qCritical() << bytes; + return false; + } + fileName = Json::requireString(obj, "FileNameOnDisk"); + QString rawUrl = Json::requireString(obj, "DownloadURL"); + url = QUrl(rawUrl, QUrl::TolerantMode); + if(!url.isValid()) + { + throw JSONValidationError(QString("Invalid URL: %1").arg(rawUrl)); + } + // This is a piece of a Flame project JSON pulled out into the file metadata (here) for convenience + // It is also optional + QJsonObject projObj = Json::ensureObject(obj, "_Project", {}); + if(!projObj.isEmpty()) + { + QString strType = Json::ensureString(projObj, "PackageType", "mod").toLower(); + if(strType == "singlefile") + { + type = File::Type::SingleFile; + } + else if(strType == "ctoc") + { + type = File::Type::Ctoc; + } + else if(strType == "cmod2") + { + type = File::Type::Cmod2; + } + else if(strType == "mod") + { + type = File::Type::Mod; + } + else if(strType == "folder") + { + type = File::Type::Folder; + } + else if(strType == "modpack") + { + type = File::Type::Modpack; + } + else + { + qCritical() << "Resolving of" << projectId << fileId << "failed because of unknown file type:" << strType; + type = File::Type::Unknown; + return false; + } + targetFolder = Json::ensureString(projObj, "Path", "mods"); + } + resolved = true; + return true; +} diff --git a/api/logic/modplatform/flame/PackManifest.h b/api/logic/modplatform/flame/PackManifest.h index 34232eee..02f39f0e 100644 --- a/api/logic/modplatform/flame/PackManifest.h +++ b/api/logic/modplatform/flame/PackManifest.h @@ -8,6 +8,9 @@ namespace Flame { struct File { + // NOTE: throws JSONValidationError + bool parseFromBytes(const QByteArray &bytes); + int projectId = 0; int fileId = 0; // NOTE: the opposite to 'optional'. This is at the time of writing unused. diff --git a/api/logic/modplatform/flame/UrlResolvingTask.cpp b/api/logic/modplatform/flame/UrlResolvingTask.cpp index 068b6a34..9d53e7e5 100644 --- a/api/logic/modplatform/flame/UrlResolvingTask.cpp +++ b/api/logic/modplatform/flame/UrlResolvingTask.cpp @@ -1,11 +1,11 @@ #include "UrlResolvingTask.h" #include +#include + -/* namespace { -const char * metabase = "https://cursemeta.dries007.net"; + const char * metabase = "https://cursemeta.dries007.net"; } -*/ Flame::UrlResolvingTask::UrlResolvingTask(const QString& toProcess) : m_url(toProcess) @@ -13,12 +13,17 @@ Flame::UrlResolvingTask::UrlResolvingTask(const QString& toProcess) } void Flame::UrlResolvingTask::executeTask() +{ + resolveUrl(); +} + +void Flame::UrlResolvingTask::resolveUrl() { setStatus(tr("Resolving URL...")); setProgress(0, 1); m_dljob.reset(new NetJob("URL resolver")); - weAreDigging = false; + bool weAreDigging = false; needle = QString(); if(m_url.startsWith("https://")) { @@ -48,17 +53,12 @@ void Flame::UrlResolvingTask::executeTask() } auto dl = Net::Download::makeByteArray(QUrl(m_url), &results); m_dljob->addNetAction(dl); - connect(m_dljob.get(), &NetJob::finished, this, &Flame::UrlResolvingTask::netJobFinished); - m_dljob->start(); -} - -void Flame::UrlResolvingTask::netJobFinished() -{ if(weAreDigging) { - processHTML(); + connect(m_dljob.get(), &NetJob::finished, this, &Flame::UrlResolvingTask::processHTML); } else { - processCCIP(); + connect(m_dljob.get(), &NetJob::finished, this, &Flame::UrlResolvingTask::processCCIP); } + m_dljob->start(); } void Flame::UrlResolvingTask::processHTML() @@ -83,7 +83,7 @@ void Flame::UrlResolvingTask::processHTML() qDebug() << "Found needle: " << found; // twitch://www.curseforge.com/minecraft/modpacks/ftb-sky-odyssey/download-client/2697088 m_url = found; - executeTask(); + resolveUrl(); return; } emitFailed(tr("Couldn't find the end of the needle in the haystack...")); @@ -135,6 +135,36 @@ void Flame::UrlResolvingTask::processCCIP() return; } qDebug() << "Resolved" << m_url << "as" << m_result.projectId << "/" << m_result.fileId; - emitSucceeded(); + resolveIDs(); } +void Flame::UrlResolvingTask::resolveIDs() +{ + setStatus(tr("Resolving mod IDs...")); + m_dljob.reset(new NetJob("Mod id resolver")); + auto projectIdStr = QString::number(m_result.projectId); + auto fileIdStr = QString::number(m_result.fileId); + QString metaurl = QString("%1/%2/%3.json").arg(metabase, projectIdStr, fileIdStr); + auto dl = Net::Download::makeByteArray(QUrl(metaurl), &results); + m_dljob->addNetAction(dl); + connect(m_dljob.get(), &NetJob::finished, this, &Flame::UrlResolvingTask::processCursemeta); + m_dljob->start(); +} + +void Flame::UrlResolvingTask::processCursemeta() +{ + try { + if(m_result.parseFromBytes(results)) { + emitSucceeded(); + qDebug() << results; + return; + } + } catch (const JSONValidationError &e) { + + qCritical() << "Resolving of" << m_result.projectId << m_result.fileId << "failed because of a parsing error:"; + qCritical() << e.cause(); + qCritical() << "JSON:"; + qCritical() << results; + } + emitFailed(tr("Failed to resolve the modpack file.")); +} diff --git a/api/logic/modplatform/flame/UrlResolvingTask.h b/api/logic/modplatform/flame/UrlResolvingTask.h index 72f3dce1..98b78f67 100644 --- a/api/logic/modplatform/flame/UrlResolvingTask.h +++ b/api/logic/modplatform/flame/UrlResolvingTask.h @@ -26,7 +26,11 @@ protected: protected slots: void processCCIP(); void processHTML(); - void netJobFinished(); + void processCursemeta(); + +private: + void resolveUrl(); + void resolveIDs(); private: /* data */ QString m_url; @@ -34,7 +38,6 @@ private: /* data */ Flame::File m_result; QByteArray results; NetJobPtr m_dljob; - bool weAreDigging = false; }; } diff --git a/application/pages/modplatform/TwitchPage.cpp b/application/pages/modplatform/TwitchPage.cpp index 2f138b94..52d87fa4 100644 --- a/application/pages/modplatform/TwitchPage.cpp +++ b/application/pages/modplatform/TwitchPage.cpp @@ -3,6 +3,7 @@ #include "MultiMC.h" #include "dialogs/NewInstanceDialog.h" +#include TwitchPage::TwitchPage(NewInstanceDialog* dialog, QWidget *parent) : QWidget(parent), ui(new Ui::TwitchPage), dialog(dialog) @@ -42,6 +43,13 @@ void TwitchPage::checkDone() { auto result = m_modIdResolver->getResults(); auto formatted = QString("Project %1, File %2").arg(result.projectId).arg(result.fileId); - ui->twitchLabel->setText(formatted); + if(result.resolved && result.type == Flame::File::Type::Modpack) { + ui->twitchLabel->setText(formatted); + QFileInfo fi(result.fileName); + dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(result.url)); + } else { + ui->twitchLabel->setPixmap(QPixmap(QString::fromUtf8(":/assets/deadglitch"))); + dialog->setSuggestedPack(); + } m_modIdResolver.reset(); }