pollymc/launcher/modplatform/flame/FlameAPI.cpp
flow 6a18079953
refactor: generalize mod models and APIs to resources
Firstly, this abstract away behavior in the mod download models that can
also be applied to other types of resources into a superclass, allowing
other resource types to be implemented without so much code duplication.

For that, this also generalizes the APIs used (currently, ModrinthAPI
and FlameAPI) to be able to make requests to other types of resources.

It also does a general cleanup of both of those. In particular, this
makes use of std::optional instead of invalid values for errors and,
well, optional values :p

This is a squash of some commits that were becoming too interlaced
together to be cleanly separated.

Signed-off-by: flow <flowlnlnln@gmail.com>
2023-01-13 16:23:00 -03:00

215 lines
6.8 KiB
C++

#include "FlameAPI.h"
#include "FlameModIndex.h"
#include "Application.h"
#include "BuildConfig.h"
#include "Json.h"
#include "net/Upload.h"
auto FlameAPI::matchFingerprints(const QList<uint>& fingerprints, QByteArray* response) -> NetJob::Ptr
{
auto* netJob = new NetJob(QString("Flame::MatchFingerprints"), APPLICATION->network());
QJsonObject body_obj;
QJsonArray fingerprints_arr;
for (auto& fp : fingerprints) {
fingerprints_arr.append(QString("%1").arg(fp));
}
body_obj["fingerprints"] = fingerprints_arr;
QJsonDocument body(body_obj);
auto body_raw = body.toJson();
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/fingerprints"), response, body_raw));
QObject::connect(netJob, &NetJob::finished, [response] { delete response; });
return netJob;
}
auto FlameAPI::getModFileChangelog(int modId, int fileId) -> QString
{
QEventLoop lock;
QString changelog;
auto* netJob = new NetJob(QString("Flame::FileChangelog"), APPLICATION->network());
auto* response = new QByteArray();
netJob->addNetAction(Net::Download::makeByteArray(
QString("https://api.curseforge.com/v1/mods/%1/files/%2/changelog")
.arg(QString::fromStdString(std::to_string(modId)), QString::fromStdString(std::to_string(fileId))),
response));
QObject::connect(netJob, &NetJob::succeeded, [netJob, response, &changelog] {
QJsonParseError parse_error{};
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
if (parse_error.error != QJsonParseError::NoError) {
qWarning() << "Error while parsing JSON response from Flame::FileChangelog at " << parse_error.offset
<< " reason: " << parse_error.errorString();
qWarning() << *response;
netJob->failed(parse_error.errorString());
return;
}
changelog = Json::ensureString(doc.object(), "data");
});
QObject::connect(netJob, &NetJob::finished, [response, &lock] {
delete response;
lock.quit();
});
netJob->start();
lock.exec();
return changelog;
}
auto FlameAPI::getModDescription(int modId) -> QString
{
QEventLoop lock;
QString description;
auto* netJob = new NetJob(QString("Flame::ModDescription"), APPLICATION->network());
auto* response = new QByteArray();
netJob->addNetAction(Net::Download::makeByteArray(
QString("https://api.curseforge.com/v1/mods/%1/description")
.arg(QString::number(modId)), response));
QObject::connect(netJob, &NetJob::succeeded, [netJob, response, &description] {
QJsonParseError parse_error{};
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
if (parse_error.error != QJsonParseError::NoError) {
qWarning() << "Error while parsing JSON response from Flame::ModDescription at " << parse_error.offset
<< " reason: " << parse_error.errorString();
qWarning() << *response;
netJob->failed(parse_error.errorString());
return;
}
description = Json::ensureString(doc.object(), "data");
});
QObject::connect(netJob, &NetJob::finished, [response, &lock] {
delete response;
lock.quit();
});
netJob->start();
lock.exec();
return description;
}
auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion
{
auto versions_url_optional = getVersionsURL(args);
if (!versions_url_optional.has_value())
return {};
auto versions_url = versions_url_optional.value();
QEventLoop loop;
auto netJob = new NetJob(QString("Flame::GetLatestVersion(%1)").arg(args.addonId), APPLICATION->network());
auto response = new QByteArray();
ModPlatform::IndexedVersion ver;
netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
QObject::connect(netJob, &NetJob::succeeded, [response, args, &ver] {
QJsonParseError parse_error{};
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
if (parse_error.error != QJsonParseError::NoError) {
qWarning() << "Error while parsing JSON response from latest mod version at " << parse_error.offset
<< " reason: " << parse_error.errorString();
qWarning() << *response;
return;
}
try {
auto obj = Json::requireObject(doc);
auto arr = Json::requireArray(obj, "data");
QJsonObject latest_file_obj;
ModPlatform::IndexedVersion ver_tmp;
for (auto file : arr) {
auto file_obj = Json::requireObject(file);
auto file_tmp = FlameMod::loadIndexedPackVersion(file_obj);
if(file_tmp.date > ver_tmp.date) {
ver_tmp = file_tmp;
latest_file_obj = file_obj;
}
}
ver = FlameMod::loadIndexedPackVersion(latest_file_obj);
} catch (Json::JsonException& e) {
qCritical() << "Failed to parse response from a version request.";
qCritical() << e.what();
qDebug() << doc;
}
});
QObject::connect(netJob, &NetJob::finished, [response, netJob, &loop] {
netJob->deleteLater();
delete response;
loop.quit();
});
netJob->start();
loop.exec();
return ver;
}
NetJob::Ptr FlameAPI::getProjects(QStringList addonIds, QByteArray* response) const
{
auto* netJob = new NetJob(QString("Flame::GetProjects"), APPLICATION->network());
QJsonObject body_obj;
QJsonArray addons_arr;
for (auto& addonId : addonIds) {
addons_arr.append(addonId);
}
body_obj["modIds"] = addons_arr;
QJsonDocument body(body_obj);
auto body_raw = body.toJson();
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods"), response, body_raw));
QObject::connect(netJob, &NetJob::finished, [response] { delete response; });
QObject::connect(netJob, &NetJob::failed, [body_raw] { qDebug() << body_raw; });
return netJob;
}
NetJob::Ptr FlameAPI::getFiles(const QStringList& fileIds, QByteArray* response) const
{
auto* netJob = new NetJob(QString("Flame::GetFiles"), APPLICATION->network());
QJsonObject body_obj;
QJsonArray files_arr;
for (auto& fileId : fileIds) {
files_arr.append(fileId);
}
body_obj["fileIds"] = files_arr;
QJsonDocument body(body_obj);
auto body_raw = body.toJson();
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods/files"), response, body_raw));
QObject::connect(netJob, &NetJob::finished, [response] { delete response; });
QObject::connect(netJob, &NetJob::failed, [body_raw] { qDebug() << body_raw; });
return netJob;
}