Merge pull request #1200 from Trial97/net_job_crash
Made ByteSynkArray to use shared_ptr
This commit is contained in:
parent
9df3c5d3c0
commit
05056e1abf
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "modplatform/flame/FlameAPI.h"
|
#include "modplatform/flame/FlameAPI.h"
|
||||||
#include "modplatform/flame/FlameModIndex.h"
|
#include "modplatform/flame/FlameModIndex.h"
|
||||||
|
#include "modplatform/helpers/HashUtils.h"
|
||||||
#include "modplatform/modrinth/ModrinthAPI.h"
|
#include "modplatform/modrinth/ModrinthAPI.h"
|
||||||
#include "modplatform/modrinth/ModrinthPackIndex.h"
|
#include "modplatform/modrinth/ModrinthPackIndex.h"
|
||||||
|
|
||||||
@ -24,8 +25,8 @@ EnsureMetadataTask::EnsureMetadataTask(Mod* mod, QDir dir, ModPlatform::Resource
|
|||||||
auto hash_task = createNewHash(mod);
|
auto hash_task = createNewHash(mod);
|
||||||
if (!hash_task)
|
if (!hash_task)
|
||||||
return;
|
return;
|
||||||
connect(hash_task.get(), &Task::succeeded, [this, hash_task, mod] { m_mods.insert(hash_task->getResult(), mod); });
|
connect(hash_task.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) { m_mods.insert(hash, mod); });
|
||||||
connect(hash_task.get(), &Task::failed, [this, hash_task, mod] { emitFail(mod, "", RemoveFromList::No); });
|
connect(hash_task.get(), &Task::failed, [this, mod] { emitFail(mod, "", RemoveFromList::No); });
|
||||||
hash_task->start();
|
hash_task->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,8 +38,8 @@ EnsureMetadataTask::EnsureMetadataTask(QList<Mod*>& mods, QDir dir, ModPlatform:
|
|||||||
auto hash_task = createNewHash(mod);
|
auto hash_task = createNewHash(mod);
|
||||||
if (!hash_task)
|
if (!hash_task)
|
||||||
continue;
|
continue;
|
||||||
connect(hash_task.get(), &Task::succeeded, [this, hash_task, mod] { m_mods.insert(hash_task->getResult(), mod); });
|
connect(hash_task.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) { m_mods.insert(hash, mod); });
|
||||||
connect(hash_task.get(), &Task::failed, [this, hash_task, mod] { emitFail(mod, "", RemoveFromList::No); });
|
connect(hash_task.get(), &Task::failed, [this, mod] { emitFail(mod, "", RemoveFromList::No); });
|
||||||
m_hashing_task->addTask(hash_task);
|
m_hashing_task->addTask(hash_task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,12 +213,12 @@ Task::Ptr EnsureMetadataTask::modrinthVersionsTask()
|
|||||||
{
|
{
|
||||||
auto hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
auto hash_type = ProviderCaps.hashType(ModPlatform::ResourceProvider::MODRINTH).first();
|
||||||
|
|
||||||
auto* response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
auto ver_task = modrinth_api.currentVersions(m_mods.keys(), hash_type, response);
|
auto ver_task = modrinth_api.currentVersions(m_mods.keys(), hash_type, response);
|
||||||
|
|
||||||
// Prevents unfortunate timings when aborting the task
|
// Prevents unfortunate timings when aborting the task
|
||||||
if (!ver_task)
|
if (!ver_task)
|
||||||
return Task::Ptr{nullptr};
|
return Task::Ptr{ nullptr };
|
||||||
|
|
||||||
connect(ver_task.get(), &Task::succeeded, this, [this, response] {
|
connect(ver_task.get(), &Task::succeeded, this, [this, response] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
@ -264,7 +265,7 @@ Task::Ptr EnsureMetadataTask::modrinthProjectsTask()
|
|||||||
for (auto const& data : m_temp_versions)
|
for (auto const& data : m_temp_versions)
|
||||||
addonIds.insert(data.addonId.toString(), data.hash);
|
addonIds.insert(data.addonId.toString(), data.hash);
|
||||||
|
|
||||||
auto response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
Task::Ptr proj_task;
|
Task::Ptr proj_task;
|
||||||
|
|
||||||
if (addonIds.isEmpty()) {
|
if (addonIds.isEmpty()) {
|
||||||
@ -277,7 +278,7 @@ Task::Ptr EnsureMetadataTask::modrinthProjectsTask()
|
|||||||
|
|
||||||
// Prevents unfortunate timings when aborting the task
|
// Prevents unfortunate timings when aborting the task
|
||||||
if (!proj_task)
|
if (!proj_task)
|
||||||
return Task::Ptr{nullptr};
|
return Task::Ptr{ nullptr };
|
||||||
|
|
||||||
connect(proj_task.get(), &Task::succeeded, this, [this, response, addonIds] {
|
connect(proj_task.get(), &Task::succeeded, this, [this, response, addonIds] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
@ -345,7 +346,7 @@ Task::Ptr EnsureMetadataTask::modrinthProjectsTask()
|
|||||||
// Flame
|
// Flame
|
||||||
Task::Ptr EnsureMetadataTask::flameVersionsTask()
|
Task::Ptr EnsureMetadataTask::flameVersionsTask()
|
||||||
{
|
{
|
||||||
auto* response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
QList<uint> fingerprints;
|
QList<uint> fingerprints;
|
||||||
for (auto& murmur : m_mods.keys()) {
|
for (auto& murmur : m_mods.keys()) {
|
||||||
@ -413,7 +414,7 @@ Task::Ptr EnsureMetadataTask::flameProjectsTask()
|
|||||||
QHash<QString, QString> addonIds;
|
QHash<QString, QString> addonIds;
|
||||||
for (auto const& hash : m_mods.keys()) {
|
for (auto const& hash : m_mods.keys()) {
|
||||||
if (m_temp_versions.contains(hash)) {
|
if (m_temp_versions.contains(hash)) {
|
||||||
auto const& data = m_temp_versions.find(hash).value();
|
auto data = m_temp_versions.find(hash).value();
|
||||||
|
|
||||||
auto id_str = data.addonId.toString();
|
auto id_str = data.addonId.toString();
|
||||||
if (!id_str.isEmpty())
|
if (!id_str.isEmpty())
|
||||||
@ -421,7 +422,7 @@ Task::Ptr EnsureMetadataTask::flameProjectsTask()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
Task::Ptr proj_task;
|
Task::Ptr proj_task;
|
||||||
|
|
||||||
if (addonIds.isEmpty()) {
|
if (addonIds.isEmpty()) {
|
||||||
@ -434,7 +435,7 @@ Task::Ptr EnsureMetadataTask::flameProjectsTask()
|
|||||||
|
|
||||||
// Prevents unfortunate timings when aborting the task
|
// Prevents unfortunate timings when aborting the task
|
||||||
if (!proj_task)
|
if (!proj_task)
|
||||||
return Task::Ptr{nullptr};
|
return Task::Ptr{ nullptr };
|
||||||
|
|
||||||
connect(proj_task.get(), &Task::succeeded, this, [this, response, addonIds] {
|
connect(proj_task.get(), &Task::succeeded, this, [this, response, addonIds] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
|
@ -121,12 +121,12 @@ class ResourceAPI {
|
|||||||
qWarning() << "TODO";
|
qWarning() << "TODO";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
[[nodiscard]] virtual Task::Ptr getProject(QString addonId, QByteArray* response) const
|
[[nodiscard]] virtual Task::Ptr getProject(QString addonId, std::shared_ptr<QByteArray> response) const
|
||||||
{
|
{
|
||||||
qWarning() << "TODO";
|
qWarning() << "TODO";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
[[nodiscard]] virtual Task::Ptr getProjects(QStringList addonIds, QByteArray* response) const
|
[[nodiscard]] virtual Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const
|
||||||
{
|
{
|
||||||
qWarning() << "TODO";
|
qWarning() << "TODO";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -82,9 +82,9 @@ void PackInstallTask::executeTask()
|
|||||||
{
|
{
|
||||||
qDebug() << "PackInstallTask::executeTask: " << QThread::currentThreadId();
|
qDebug() << "PackInstallTask::executeTask: " << QThread::currentThreadId();
|
||||||
NetJob::Ptr netJob{ new NetJob("ATLauncher::VersionFetch", APPLICATION->network()) };
|
NetJob::Ptr netJob{ new NetJob("ATLauncher::VersionFetch", APPLICATION->network()) };
|
||||||
auto searchUrl = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "packs/%1/versions/%2/Configs.json")
|
auto searchUrl =
|
||||||
.arg(m_pack_safe_name).arg(m_version_name);
|
QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "packs/%1/versions/%2/Configs.json").arg(m_pack_safe_name).arg(m_version_name);
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
|
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
|
QObject::connect(netJob.get(), &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
|
||||||
QObject::connect(netJob.get(), &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
|
QObject::connect(netJob.get(), &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
|
||||||
@ -99,11 +99,12 @@ void PackInstallTask::onDownloadSucceeded()
|
|||||||
qDebug() << "PackInstallTask::onDownloadSucceeded: " << QThread::currentThreadId();
|
qDebug() << "PackInstallTask::onDownloadSucceeded: " << QThread::currentThreadId();
|
||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
|
|
||||||
QJsonParseError parse_error {};
|
QJsonParseError parse_error{};
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||||
if(parse_error.error != QJsonParseError::NoError) {
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Error while parsing JSON response from ATLauncher at " << parse_error.offset << " reason: " << parse_error.errorString();
|
qWarning() << "Error while parsing JSON response from ATLauncher at " << parse_error.offset
|
||||||
qWarning() << response;
|
<< " reason: " << parse_error.errorString();
|
||||||
|
qWarning() << *response.get();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto obj = doc.object();
|
auto obj = doc.object();
|
||||||
|
@ -40,12 +40,13 @@
|
|||||||
#include "ATLPackManifest.h"
|
#include "ATLPackManifest.h"
|
||||||
|
|
||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
#include "net/NetJob.h"
|
#include "meta/Version.h"
|
||||||
#include "settings/INISettingsObject.h"
|
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "minecraft/PackProfile.h"
|
#include "minecraft/PackProfile.h"
|
||||||
#include "meta/Version.h"
|
#include "net/NetJob.h"
|
||||||
|
#include "settings/INISettingsObject.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace ATLauncher {
|
namespace ATLauncher {
|
||||||
@ -57,8 +58,7 @@ enum class InstallMode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class UserInteractionSupport {
|
class UserInteractionSupport {
|
||||||
|
public:
|
||||||
public:
|
|
||||||
/**
|
/**
|
||||||
* Requests a user interaction to select which optional mods should be installed.
|
* Requests a user interaction to select which optional mods should be installed.
|
||||||
*/
|
*/
|
||||||
@ -74,23 +74,27 @@ public:
|
|||||||
* Requests a user interaction to display a message.
|
* Requests a user interaction to display a message.
|
||||||
*/
|
*/
|
||||||
virtual void displayMessage(QString message) = 0;
|
virtual void displayMessage(QString message) = 0;
|
||||||
|
|
||||||
|
virtual ~UserInteractionSupport() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PackInstallTask : public InstanceTask
|
class PackInstallTask : public InstanceTask {
|
||||||
{
|
Q_OBJECT
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PackInstallTask(UserInteractionSupport *support, QString packName, QString version, InstallMode installMode = InstallMode::Install);
|
explicit PackInstallTask(UserInteractionSupport* support,
|
||||||
virtual ~PackInstallTask(){}
|
QString packName,
|
||||||
|
QString version,
|
||||||
|
InstallMode installMode = InstallMode::Install);
|
||||||
|
virtual ~PackInstallTask() { delete m_support; }
|
||||||
|
|
||||||
bool canAbort() const override { return true; }
|
bool canAbort() const override { return true; }
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onDownloadSucceeded();
|
void onDownloadSucceeded();
|
||||||
void onDownloadFailed(QString reason);
|
void onDownloadFailed(QString reason);
|
||||||
void onDownloadAborted();
|
void onDownloadAborted();
|
||||||
@ -98,7 +102,7 @@ private slots:
|
|||||||
void onModsDownloaded();
|
void onModsDownloaded();
|
||||||
void onModsExtracted();
|
void onModsExtracted();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString getDirForModType(ModType type, QString raw);
|
QString getDirForModType(ModType type, QString raw);
|
||||||
QString getVersionForLoader(QString uid);
|
QString getVersionForLoader(QString uid);
|
||||||
QString detectLibrary(VersionLibrary library);
|
QString detectLibrary(VersionLibrary library);
|
||||||
@ -110,20 +114,18 @@ private:
|
|||||||
void installConfigs();
|
void installConfigs();
|
||||||
void extractConfigs();
|
void extractConfigs();
|
||||||
void downloadMods();
|
void downloadMods();
|
||||||
bool extractMods(
|
bool extractMods(const QMap<QString, VersionMod>& toExtract,
|
||||||
const QMap<QString, VersionMod> &toExtract,
|
const QMap<QString, VersionMod>& toDecomp,
|
||||||
const QMap<QString, VersionMod> &toDecomp,
|
const QMap<QString, QString>& toCopy);
|
||||||
const QMap<QString, QString> &toCopy
|
|
||||||
);
|
|
||||||
void install();
|
void install();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UserInteractionSupport *m_support;
|
UserInteractionSupport* m_support;
|
||||||
|
|
||||||
bool abortable = false;
|
bool abortable = false;
|
||||||
|
|
||||||
NetJob::Ptr jobPtr;
|
NetJob::Ptr jobPtr;
|
||||||
QByteArray response;
|
std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
InstallMode m_install_mode;
|
InstallMode m_install_mode;
|
||||||
QString m_pack_name;
|
QString m_pack_name;
|
||||||
@ -145,7 +147,6 @@ private:
|
|||||||
|
|
||||||
QFuture<bool> m_modExtractFuture;
|
QFuture<bool> m_modExtractFuture;
|
||||||
QFutureWatcher<bool> m_modExtractFutureWatcher;
|
QFutureWatcher<bool> m_modExtractFutureWatcher;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace ATLauncher
|
||||||
|
@ -25,15 +25,16 @@ void Flame::FileResolvingTask::executeTask()
|
|||||||
setProgress(0, 3);
|
setProgress(0, 3);
|
||||||
m_dljob.reset(new NetJob("Mod id resolver", m_network));
|
m_dljob.reset(new NetJob("Mod id resolver", m_network));
|
||||||
result.reset(new QByteArray());
|
result.reset(new QByteArray());
|
||||||
//build json data to send
|
// build json data to send
|
||||||
QJsonObject object;
|
QJsonObject object;
|
||||||
|
|
||||||
object["fileIds"] = QJsonArray::fromVariantList(std::accumulate(m_toProcess.files.begin(), m_toProcess.files.end(), QVariantList(), [](QVariantList& l, const File& s) {
|
object["fileIds"] = QJsonArray::fromVariantList(
|
||||||
l.push_back(s.fileId);
|
std::accumulate(m_toProcess.files.begin(), m_toProcess.files.end(), QVariantList(), [](QVariantList& l, const File& s) {
|
||||||
return l;
|
l.push_back(s.fileId);
|
||||||
}));
|
return l;
|
||||||
|
}));
|
||||||
QByteArray data = Json::toText(object);
|
QByteArray data = Json::toText(object);
|
||||||
auto dl = Net::Upload::makeByteArray(QUrl("https://api.curseforge.com/v1/mods/files"), result.get(), data);
|
auto dl = Net::Upload::makeByteArray(QUrl("https://api.curseforge.com/v1/mods/files"), result, data);
|
||||||
m_dljob->addNetAction(dl);
|
m_dljob->addNetAction(dl);
|
||||||
|
|
||||||
auto step_progress = std::make_shared<TaskStepProgress>();
|
auto step_progress = std::make_shared<TaskStepProgress>();
|
||||||
@ -87,17 +88,15 @@ void Flame::FileResolvingTask::netJobFinished()
|
|||||||
auto fileid = Json::requireInteger(Json::requireObject(file)["id"]);
|
auto fileid = Json::requireInteger(Json::requireObject(file)["id"]);
|
||||||
auto& out = m_toProcess.files[fileid];
|
auto& out = m_toProcess.files[fileid];
|
||||||
try {
|
try {
|
||||||
out.parseFromObject(Json::requireObject(file));
|
out.parseFromObject(Json::requireObject(file));
|
||||||
} catch (const JSONValidationError& e) {
|
} catch (const JSONValidationError& e) {
|
||||||
qDebug() << "Blocked mod on curseforge" << out.fileName;
|
qDebug() << "Blocked mod on curseforge" << out.fileName;
|
||||||
auto hash = out.hash;
|
auto hash = out.hash;
|
||||||
if(!hash.isEmpty()) {
|
if (!hash.isEmpty()) {
|
||||||
auto url = QString("https://api.modrinth.com/v2/version_file/%1?algorithm=sha1").arg(hash);
|
auto url = QString("https://api.modrinth.com/v2/version_file/%1?algorithm=sha1").arg(hash);
|
||||||
auto output = std::make_shared<QByteArray>();
|
auto output = std::make_shared<QByteArray>();
|
||||||
auto dl = Net::Download::makeByteArray(QUrl(url), output.get());
|
auto dl = Net::Download::makeByteArray(QUrl(url), output);
|
||||||
QObject::connect(dl.get(), &Net::Download::succeeded, [&out]() {
|
QObject::connect(dl.get(), &Net::Download::succeeded, [&out]() { out.resolved = true; });
|
||||||
out.resolved = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
m_checkJob->addNetAction(dl);
|
m_checkJob->addNetAction(dl);
|
||||||
blockedProjects.insert(&out, output);
|
blockedProjects.insert(&out, output);
|
||||||
@ -169,7 +168,7 @@ void Flame::FileResolvingTask::modrinthCheckFinished() {
|
|||||||
auto projectId = mod->projectId;
|
auto projectId = mod->projectId;
|
||||||
auto output = std::make_shared<QByteArray>();
|
auto output = std::make_shared<QByteArray>();
|
||||||
auto url = QString("https://api.curseforge.com/v1/mods/%1").arg(projectId);
|
auto url = QString("https://api.curseforge.com/v1/mods/%1").arg(projectId);
|
||||||
auto dl = Net::Download::makeByteArray(url, output.get());
|
auto dl = Net::Download::makeByteArray(url, output);
|
||||||
qDebug() << "Fetching url slug for file:" << mod->fileName;
|
qDebug() << "Fetching url slug for file:" << mod->fileName;
|
||||||
QObject::connect(dl.get(), &Net::Download::succeeded, [block, index, output]() {
|
QObject::connect(dl.get(), &Net::Download::succeeded, [block, index, output]() {
|
||||||
auto mod = block->at(index); // use the shared_ptr so it is captured and only freed when we are done
|
auto mod = block->at(index); // use the shared_ptr so it is captured and only freed when we are done
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
#include "net/Upload.h"
|
#include "net/Upload.h"
|
||||||
|
|
||||||
Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, QByteArray* response)
|
Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, std::shared_ptr<QByteArray> response)
|
||||||
{
|
{
|
||||||
auto netJob = makeShared<NetJob>(QString("Flame::MatchFingerprints"), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Flame::MatchFingerprints"), APPLICATION->network());
|
||||||
|
|
||||||
@ -28,8 +28,6 @@ Task::Ptr FlameAPI::matchFingerprints(const QList<uint>& fingerprints, QByteArra
|
|||||||
|
|
||||||
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/fingerprints"), response, body_raw));
|
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/fingerprints"), response, body_raw));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
|
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +41,7 @@ auto FlameAPI::getModFileChangelog(int modId, int fileId) -> QString
|
|||||||
netJob->addNetAction(Net::Download::makeByteArray(
|
netJob->addNetAction(Net::Download::makeByteArray(
|
||||||
QString("https://api.curseforge.com/v1/mods/%1/files/%2/changelog")
|
QString("https://api.curseforge.com/v1/mods/%1/files/%2/changelog")
|
||||||
.arg(QString::fromStdString(std::to_string(modId)), QString::fromStdString(std::to_string(fileId))),
|
.arg(QString::fromStdString(std::to_string(modId)), QString::fromStdString(std::to_string(fileId))),
|
||||||
response.get()));
|
response));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::succeeded, [&netJob, response, &changelog] {
|
QObject::connect(netJob.get(), &NetJob::succeeded, [&netJob, response, &changelog] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
@ -75,8 +73,8 @@ auto FlameAPI::getModDescription(int modId) -> QString
|
|||||||
|
|
||||||
auto netJob = makeShared<NetJob>(QString("Flame::ModDescription"), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Flame::ModDescription"), APPLICATION->network());
|
||||||
auto response = std::make_shared<QByteArray>();
|
auto response = std::make_shared<QByteArray>();
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(
|
netJob->addNetAction(
|
||||||
QString("https://api.curseforge.com/v1/mods/%1/description").arg(QString::number(modId)), response.get()));
|
Net::Download::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/description").arg(QString::number(modId)), response));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::succeeded, [&netJob, response, &description] {
|
QObject::connect(netJob.get(), &NetJob::succeeded, [&netJob, response, &description] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
@ -115,7 +113,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
|
|||||||
auto response = std::make_shared<QByteArray>();
|
auto response = std::make_shared<QByteArray>();
|
||||||
ModPlatform::IndexedVersion ver;
|
ModPlatform::IndexedVersion ver;
|
||||||
|
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(versions_url, response.get()));
|
netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::succeeded, [response, args, &ver] {
|
QObject::connect(netJob.get(), &NetJob::succeeded, [response, args, &ver] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
@ -137,7 +135,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
|
|||||||
for (auto file : arr) {
|
for (auto file : arr) {
|
||||||
auto file_obj = Json::requireObject(file);
|
auto file_obj = Json::requireObject(file);
|
||||||
auto file_tmp = FlameMod::loadIndexedPackVersion(file_obj);
|
auto file_tmp = FlameMod::loadIndexedPackVersion(file_obj);
|
||||||
if(file_tmp.date > ver_tmp.date) {
|
if (file_tmp.date > ver_tmp.date) {
|
||||||
ver_tmp = file_tmp;
|
ver_tmp = file_tmp;
|
||||||
latest_file_obj = file_obj;
|
latest_file_obj = file_obj;
|
||||||
}
|
}
|
||||||
@ -160,7 +158,7 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
|
|||||||
return ver;
|
return ver;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::Ptr FlameAPI::getProjects(QStringList addonIds, QByteArray* response) const
|
Task::Ptr FlameAPI::getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const
|
||||||
{
|
{
|
||||||
auto netJob = makeShared<NetJob>(QString("Flame::GetProjects"), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Flame::GetProjects"), APPLICATION->network());
|
||||||
|
|
||||||
@ -177,13 +175,12 @@ Task::Ptr FlameAPI::getProjects(QStringList addonIds, QByteArray* response) cons
|
|||||||
|
|
||||||
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods"), response, body_raw));
|
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods"), response, body_raw));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
|
|
||||||
QObject::connect(netJob.get(), &NetJob::failed, [body_raw] { qDebug() << body_raw; });
|
QObject::connect(netJob.get(), &NetJob::failed, [body_raw] { qDebug() << body_raw; });
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::Ptr FlameAPI::getFiles(const QStringList& fileIds, QByteArray* response) const
|
Task::Ptr FlameAPI::getFiles(const QStringList& fileIds, std::shared_ptr<QByteArray> response) const
|
||||||
{
|
{
|
||||||
auto netJob = makeShared<NetJob>(QString("Flame::GetFiles"), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Flame::GetFiles"), APPLICATION->network());
|
||||||
|
|
||||||
@ -200,7 +197,6 @@ Task::Ptr FlameAPI::getFiles(const QStringList& fileIds, QByteArray* response) c
|
|||||||
|
|
||||||
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods/files"), response, body_raw));
|
netJob->addNetAction(Net::Upload::makeByteArray(QString("https://api.curseforge.com/v1/mods/files"), response, body_raw));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
|
|
||||||
QObject::connect(netJob.get(), &NetJob::failed, [body_raw] { qDebug() << body_raw; });
|
QObject::connect(netJob.get(), &NetJob::failed, [body_raw] { qDebug() << body_raw; });
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include "modplatform/ModIndex.h"
|
#include "modplatform/ModIndex.h"
|
||||||
#include "modplatform/helpers/NetworkResourceAPI.h"
|
#include "modplatform/helpers/NetworkResourceAPI.h"
|
||||||
|
|
||||||
@ -14,9 +15,9 @@ class FlameAPI : public NetworkResourceAPI {
|
|||||||
|
|
||||||
auto getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion;
|
auto getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::IndexedVersion;
|
||||||
|
|
||||||
Task::Ptr getProjects(QStringList addonIds, QByteArray* response) const override;
|
Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const override;
|
||||||
Task::Ptr matchFingerprints(const QList<uint>& fingerprints, QByteArray* response);
|
Task::Ptr matchFingerprints(const QList<uint>& fingerprints, std::shared_ptr<QByteArray> response);
|
||||||
Task::Ptr getFiles(const QStringList& fileIds, QByteArray* response) const;
|
Task::Ptr getFiles(const QStringList& fileIds, std::shared_ptr<QByteArray> response) const;
|
||||||
|
|
||||||
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
|
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
|
||||||
|
|
||||||
@ -41,14 +42,15 @@ class FlameAPI : public NetworkResourceAPI {
|
|||||||
return 4;
|
return 4;
|
||||||
// TODO: remove this once Quilt drops official Fabric support
|
// TODO: remove this once Quilt drops official Fabric support
|
||||||
if (loaders & Quilt) // NOTE: Most if not all Fabric mods should work *currently*
|
if (loaders & Quilt) // NOTE: Most if not all Fabric mods should work *currently*
|
||||||
return 4; // Quilt would probably be 5
|
return 4; // Quilt would probably be 5
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] std::optional<QString> getSearchURL(SearchArgs const& args) const override
|
[[nodiscard]] std::optional<QString> getSearchURL(SearchArgs const& args) const override
|
||||||
{
|
{
|
||||||
auto gameVersionStr = args.versions.has_value() ? QString("gameVersion=%1").arg(args.versions.value().front().toString()) : QString();
|
auto gameVersionStr =
|
||||||
|
args.versions.has_value() ? QString("gameVersion=%1").arg(args.versions.value().front().toString()) : QString();
|
||||||
|
|
||||||
QStringList get_arguments;
|
QStringList get_arguments;
|
||||||
get_arguments.append(QString("classId=%1").arg(getClassId(args.type)));
|
get_arguments.append(QString("classId=%1").arg(getClassId(args.type)));
|
||||||
@ -73,7 +75,7 @@ class FlameAPI : public NetworkResourceAPI {
|
|||||||
|
|
||||||
[[nodiscard]] std::optional<QString> getVersionsURL(VersionSearchArgs const& args) const override
|
[[nodiscard]] std::optional<QString> getVersionsURL(VersionSearchArgs const& args) const override
|
||||||
{
|
{
|
||||||
QString url{QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(args.pack.addonId.toString())};
|
QString url{ QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(args.pack.addonId.toString()) };
|
||||||
|
|
||||||
QStringList get_parameters;
|
QStringList get_parameters;
|
||||||
if (args.mcVersions.has_value())
|
if (args.mcVersions.has_value())
|
||||||
|
@ -31,7 +31,7 @@ ModPlatform::IndexedPack getProjectInfo(ModPlatform::IndexedVersion& ver_info)
|
|||||||
|
|
||||||
auto get_project_job = new NetJob("Flame::GetProjectJob", APPLICATION->network());
|
auto get_project_job = new NetJob("Flame::GetProjectJob", APPLICATION->network());
|
||||||
|
|
||||||
auto response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
auto url = QString("https://api.curseforge.com/v1/mods/%1").arg(ver_info.addonId.toString());
|
auto url = QString("https://api.curseforge.com/v1/mods/%1").arg(ver_info.addonId.toString());
|
||||||
auto dl = Net::Download::makeByteArray(url, response);
|
auto dl = Net::Download::makeByteArray(url, response);
|
||||||
get_project_job->addNetAction(dl);
|
get_project_job->addNetAction(dl);
|
||||||
@ -75,7 +75,7 @@ ModPlatform::IndexedVersion getFileInfo(int addonId, int fileId)
|
|||||||
|
|
||||||
auto get_file_info_job = new NetJob("Flame::GetFileInfoJob", APPLICATION->network());
|
auto get_file_info_job = new NetJob("Flame::GetFileInfoJob", APPLICATION->network());
|
||||||
|
|
||||||
auto response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
auto url = QString("https://api.curseforge.com/v1/mods/%1/files/%2").arg(QString::number(addonId), QString::number(fileId));
|
auto url = QString("https://api.curseforge.com/v1/mods/%1/files/%2").arg(QString::number(addonId), QString::number(fileId));
|
||||||
auto dl = Net::Download::makeByteArray(url, response);
|
auto dl = Net::Download::makeByteArray(url, response);
|
||||||
get_file_info_job->addNetAction(dl);
|
get_file_info_job->addNetAction(dl);
|
||||||
|
@ -182,7 +182,7 @@ bool FlameCreationTask::updateInstance()
|
|||||||
fileIds.append(QString::number(file.fileId));
|
fileIds.append(QString::number(file.fileId));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* raw_response = new QByteArray;
|
auto raw_response = std::make_shared<QByteArray>();
|
||||||
auto job = api.getFiles(fileIds, raw_response);
|
auto job = api.getFiles(fileIds, raw_response);
|
||||||
|
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
|
@ -71,6 +71,7 @@ void ModrinthHasher::executeTask()
|
|||||||
emitFailed("Empty hash!");
|
emitFailed("Empty hash!");
|
||||||
} else {
|
} else {
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
|
emit resultsReady(m_hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,10 +92,9 @@ void FlameHasher::executeTask()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockedModHasher::BlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider) : Hasher(file_path), provider(provider)
|
||||||
BlockedModHasher::BlockedModHasher(QString file_path, ModPlatform::ResourceProvider provider)
|
{
|
||||||
: Hasher(file_path), provider(provider) {
|
setObjectName(QString("BlockedModHasher: %1").arg(file_path));
|
||||||
setObjectName(QString("BlockedModHasher: %1").arg(file_path));
|
|
||||||
hash_type = ProviderCaps.hashType(provider).first();
|
hash_type = ProviderCaps.hashType(provider).first();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,11 +123,13 @@ void BlockedModHasher::executeTask()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList BlockedModHasher::getHashTypes() {
|
QStringList BlockedModHasher::getHashTypes()
|
||||||
|
{
|
||||||
return ProviderCaps.hashType(provider);
|
return ProviderCaps.hashType(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockedModHasher::useHashType(QString type) {
|
bool BlockedModHasher::useHashType(QString type)
|
||||||
|
{
|
||||||
auto types = ProviderCaps.hashType(provider);
|
auto types = ProviderCaps.hashType(provider);
|
||||||
if (types.contains(type)) {
|
if (types.contains(type)) {
|
||||||
hash_type = type;
|
hash_type = type;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
namespace Hashing {
|
namespace Hashing {
|
||||||
|
|
||||||
class Hasher : public Task {
|
class Hasher : public Task {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
using Ptr = shared_qobject_ptr<Hasher>;
|
using Ptr = shared_qobject_ptr<Hasher>;
|
||||||
|
|
||||||
@ -21,6 +22,9 @@ class Hasher : public Task {
|
|||||||
QString getResult() const { return m_hash; };
|
QString getResult() const { return m_hash; };
|
||||||
QString getPath() const { return m_path; };
|
QString getPath() const { return m_path; };
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void resultsReady(QString hash);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString m_hash;
|
QString m_hash;
|
||||||
QString m_path;
|
QString m_path;
|
||||||
@ -48,6 +52,7 @@ class BlockedModHasher : public Hasher {
|
|||||||
|
|
||||||
QStringList getHashTypes();
|
QStringList getHashTypes();
|
||||||
bool useHashType(QString type);
|
bool useHashType(QString type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ModPlatform::ResourceProvider provider;
|
ModPlatform::ResourceProvider provider;
|
||||||
QString hash_type;
|
QString hash_type;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
#include "NetworkResourceAPI.h"
|
#include "NetworkResourceAPI.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
@ -19,12 +20,12 @@ Task::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks&
|
|||||||
|
|
||||||
auto search_url = search_url_optional.value();
|
auto search_url = search_url_optional.value();
|
||||||
|
|
||||||
auto response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
auto netJob = makeShared<NetJob>(QString("%1::Search").arg(debugName()), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("%1::Search").arg(debugName()), APPLICATION->network());
|
||||||
|
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(search_url), response));
|
netJob->addNetAction(Net::Download::makeByteArray(QUrl(search_url), response));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::succeeded, [this, response, callbacks]{
|
QObject::connect(netJob.get(), &NetJob::succeeded, [this, response, callbacks] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||||
if (parse_error.error != QJsonParseError::NoError) {
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
@ -40,27 +41,21 @@ Task::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks&
|
|||||||
callbacks.on_succeed(doc);
|
callbacks.on_succeed(doc);
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason){
|
QObject::connect(netJob.get(), &NetJob::failed, [&netJob, callbacks](QString reason) {
|
||||||
int network_error_code = -1;
|
int network_error_code = -1;
|
||||||
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply)
|
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action && failed_action->m_reply)
|
||||||
network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
network_error_code = failed_action->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
callbacks.on_fail(reason, network_error_code);
|
callbacks.on_fail(reason, network_error_code);
|
||||||
});
|
});
|
||||||
QObject::connect(netJob.get(), &NetJob::aborted, [callbacks]{
|
QObject::connect(netJob.get(), &NetJob::aborted, [callbacks] { callbacks.on_abort(); });
|
||||||
callbacks.on_abort();
|
|
||||||
});
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response] {
|
|
||||||
delete response;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::Ptr NetworkResourceAPI::getProjectInfo(ProjectInfoArgs&& args, ProjectInfoCallbacks&& callbacks) const
|
Task::Ptr NetworkResourceAPI::getProjectInfo(ProjectInfoArgs&& args, ProjectInfoCallbacks&& callbacks) const
|
||||||
{
|
{
|
||||||
auto response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
auto job = getProject(args.pack.addonId.toString(), response);
|
auto job = getProject(args.pack.addonId.toString(), response);
|
||||||
|
|
||||||
QObject::connect(job.get(), &NetJob::succeeded, [response, callbacks, args] {
|
QObject::connect(job.get(), &NetJob::succeeded, [response, callbacks, args] {
|
||||||
@ -88,7 +83,7 @@ Task::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, Versi
|
|||||||
auto versions_url = versions_url_optional.value();
|
auto versions_url = versions_url_optional.value();
|
||||||
|
|
||||||
auto netJob = makeShared<NetJob>(QString("%1::Versions").arg(args.pack.name), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("%1::Versions").arg(args.pack.name), APPLICATION->network());
|
||||||
auto response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
|
netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
|
||||||
|
|
||||||
@ -105,14 +100,10 @@ Task::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, Versi
|
|||||||
callbacks.on_succeed(doc, args.pack);
|
callbacks.on_succeed(doc, args.pack);
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response] {
|
|
||||||
delete response;
|
|
||||||
});
|
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::Ptr NetworkResourceAPI::getProject(QString addonId, QByteArray* response) const
|
Task::Ptr NetworkResourceAPI::getProject(QString addonId, std::shared_ptr<QByteArray> response) const
|
||||||
{
|
{
|
||||||
auto project_url_optional = getInfoURL(addonId);
|
auto project_url_optional = getInfoURL(addonId);
|
||||||
if (!project_url_optional.has_value())
|
if (!project_url_optional.has_value())
|
||||||
@ -124,9 +115,5 @@ Task::Ptr NetworkResourceAPI::getProject(QString addonId, QByteArray* response)
|
|||||||
|
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(project_url), response));
|
netJob->addNetAction(Net::Download::makeByteArray(QUrl(project_url), response));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response] {
|
|
||||||
delete response;
|
|
||||||
});
|
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include "modplatform/ResourceAPI.h"
|
#include "modplatform/ResourceAPI.h"
|
||||||
|
|
||||||
class NetworkResourceAPI : public ResourceAPI {
|
class NetworkResourceAPI : public ResourceAPI {
|
||||||
public:
|
public:
|
||||||
Task::Ptr searchProjects(SearchArgs&&, SearchCallbacks&&) const override;
|
Task::Ptr searchProjects(SearchArgs&&, SearchCallbacks&&) const override;
|
||||||
|
|
||||||
Task::Ptr getProject(QString addonId, QByteArray* response) const override;
|
Task::Ptr getProject(QString addonId, std::shared_ptr<QByteArray> response) const override;
|
||||||
|
|
||||||
Task::Ptr getProjectInfo(ProjectInfoArgs&&, ProjectInfoCallbacks&&) const override;
|
Task::Ptr getProjectInfo(ProjectInfoArgs&&, ProjectInfoCallbacks&&) const override;
|
||||||
Task::Ptr getProjectVersions(VersionSearchArgs&&, VersionSearchCallbacks&&) const override;
|
Task::Ptr getProjectVersions(VersionSearchArgs&&, VersionSearchCallbacks&&) const override;
|
||||||
|
@ -51,11 +51,11 @@ void PackFetchTask::fetch()
|
|||||||
|
|
||||||
QUrl publicPacksUrl = QUrl(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/modpacks.xml");
|
QUrl publicPacksUrl = QUrl(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/modpacks.xml");
|
||||||
qDebug() << "Downloading public version info from" << publicPacksUrl.toString();
|
qDebug() << "Downloading public version info from" << publicPacksUrl.toString();
|
||||||
jobPtr->addNetAction(Net::Download::makeByteArray(publicPacksUrl, &publicModpacksXmlFileData));
|
jobPtr->addNetAction(Net::Download::makeByteArray(publicPacksUrl, publicModpacksXmlFileData));
|
||||||
|
|
||||||
QUrl thirdPartyUrl = QUrl(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/thirdparty.xml");
|
QUrl thirdPartyUrl = QUrl(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/thirdparty.xml");
|
||||||
qDebug() << "Downloading thirdparty version info from" << thirdPartyUrl.toString();
|
qDebug() << "Downloading thirdparty version info from" << thirdPartyUrl.toString();
|
||||||
jobPtr->addNetAction(Net::Download::makeByteArray(thirdPartyUrl, &thirdPartyModpacksXmlFileData));
|
jobPtr->addNetAction(Net::Download::makeByteArray(thirdPartyUrl, thirdPartyModpacksXmlFileData));
|
||||||
|
|
||||||
QObject::connect(jobPtr.get(), &NetJob::succeeded, this, &PackFetchTask::fileDownloadFinished);
|
QObject::connect(jobPtr.get(), &NetJob::succeeded, this, &PackFetchTask::fileDownloadFinished);
|
||||||
QObject::connect(jobPtr.get(), &NetJob::failed, this, &PackFetchTask::fileDownloadFailed);
|
QObject::connect(jobPtr.get(), &NetJob::failed, this, &PackFetchTask::fileDownloadFailed);
|
||||||
@ -64,22 +64,19 @@ void PackFetchTask::fetch()
|
|||||||
jobPtr->start();
|
jobPtr->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackFetchTask::fetchPrivate(const QStringList & toFetch)
|
void PackFetchTask::fetchPrivate(const QStringList& toFetch)
|
||||||
{
|
{
|
||||||
QString privatePackBaseUrl = BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/%1.xml";
|
QString privatePackBaseUrl = BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/%1.xml";
|
||||||
|
|
||||||
for (auto &packCode: toFetch)
|
for (auto& packCode : toFetch) {
|
||||||
{
|
auto data = std::make_shared<QByteArray>();
|
||||||
QByteArray *data = new QByteArray();
|
NetJob* job = new NetJob("Fetching private pack", m_network);
|
||||||
NetJob *job = new NetJob("Fetching private pack", m_network);
|
|
||||||
job->addNetAction(Net::Download::makeByteArray(privatePackBaseUrl.arg(packCode), data));
|
job->addNetAction(Net::Download::makeByteArray(privatePackBaseUrl.arg(packCode), data));
|
||||||
|
|
||||||
QObject::connect(job, &NetJob::succeeded, this, [this, job, data, packCode]
|
QObject::connect(job, &NetJob::succeeded, this, [this, job, data, packCode] {
|
||||||
{
|
|
||||||
ModpackList packs;
|
ModpackList packs;
|
||||||
parseAndAddPacks(*data, PackType::Private, packs);
|
parseAndAddPacks(*data, PackType::Private, packs);
|
||||||
foreach(Modpack currentPack, packs)
|
foreach (Modpack currentPack, packs) {
|
||||||
{
|
|
||||||
currentPack.packCode = packCode;
|
currentPack.packCode = packCode;
|
||||||
emit privateFileDownloadFinished(currentPack);
|
emit privateFileDownloadFinished(currentPack);
|
||||||
}
|
}
|
||||||
@ -87,24 +84,20 @@ void PackFetchTask::fetchPrivate(const QStringList & toFetch)
|
|||||||
job->deleteLater();
|
job->deleteLater();
|
||||||
|
|
||||||
data->clear();
|
data->clear();
|
||||||
delete data;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(job, &NetJob::failed, this, [this, job, packCode, data](QString reason)
|
QObject::connect(job, &NetJob::failed, this, [this, job, packCode, data](QString reason) {
|
||||||
{
|
|
||||||
emit privateFileDownloadFailed(reason, packCode);
|
emit privateFileDownloadFailed(reason, packCode);
|
||||||
job->deleteLater();
|
job->deleteLater();
|
||||||
|
|
||||||
data->clear();
|
data->clear();
|
||||||
delete data;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(job, &NetJob::aborted, this, [this, job, data]{
|
QObject::connect(job, &NetJob::aborted, this, [this, job, data] {
|
||||||
emit aborted();
|
emit aborted();
|
||||||
job->deleteLater();
|
job->deleteLater();
|
||||||
|
|
||||||
data->clear();
|
data->clear();
|
||||||
delete data;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
job->start();
|
job->start();
|
||||||
@ -117,27 +110,22 @@ void PackFetchTask::fileDownloadFinished()
|
|||||||
|
|
||||||
QStringList failedLists;
|
QStringList failedLists;
|
||||||
|
|
||||||
if(!parseAndAddPacks(publicModpacksXmlFileData, PackType::Public, publicPacks))
|
if (!parseAndAddPacks(*publicModpacksXmlFileData, PackType::Public, publicPacks)) {
|
||||||
{
|
|
||||||
failedLists.append(tr("Public Packs"));
|
failedLists.append(tr("Public Packs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!parseAndAddPacks(thirdPartyModpacksXmlFileData, PackType::ThirdParty, thirdPartyPacks))
|
if (!parseAndAddPacks(*thirdPartyModpacksXmlFileData, PackType::ThirdParty, thirdPartyPacks)) {
|
||||||
{
|
|
||||||
failedLists.append(tr("Third Party Packs"));
|
failedLists.append(tr("Third Party Packs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(failedLists.size() > 0)
|
if (failedLists.size() > 0) {
|
||||||
{
|
|
||||||
emit failed(tr("Failed to download some pack lists: %1").arg(failedLists.join("\n- ")));
|
emit failed(tr("Failed to download some pack lists: %1").arg(failedLists.join("\n- ")));
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
emit finished(publicPacks, thirdPartyPacks);
|
emit finished(publicPacks, thirdPartyPacks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PackFetchTask::parseAndAddPacks(QByteArray &data, PackType packType, ModpackList &list)
|
bool PackFetchTask::parseAndAddPacks(QByteArray& data, PackType packType, ModpackList& list)
|
||||||
{
|
{
|
||||||
QDomDocument doc;
|
QDomDocument doc;
|
||||||
|
|
||||||
@ -145,8 +133,7 @@ bool PackFetchTask::parseAndAddPacks(QByteArray &data, PackType packType, Modpac
|
|||||||
int errorLine = -1;
|
int errorLine = -1;
|
||||||
int errorCol = -1;
|
int errorCol = -1;
|
||||||
|
|
||||||
if(!doc.setContent(data, false, &errorMsg, &errorLine, &errorCol))
|
if (!doc.setContent(data, false, &errorMsg, &errorLine, &errorCol)) {
|
||||||
{
|
|
||||||
auto fullErrMsg = QString("Failed to fetch modpack data: %1 %2:%3!").arg(errorMsg).arg(errorLine).arg(errorCol);
|
auto fullErrMsg = QString("Failed to fetch modpack data: %1 %2:%3!").arg(errorMsg).arg(errorLine).arg(errorCol);
|
||||||
qWarning() << fullErrMsg;
|
qWarning() << fullErrMsg;
|
||||||
data.clear();
|
data.clear();
|
||||||
@ -154,8 +141,7 @@ bool PackFetchTask::parseAndAddPacks(QByteArray &data, PackType packType, Modpac
|
|||||||
}
|
}
|
||||||
|
|
||||||
QDomNodeList nodes = doc.elementsByTagName("modpack");
|
QDomNodeList nodes = doc.elementsByTagName("modpack");
|
||||||
for(int i = 0; i < nodes.length(); i++)
|
for (int i = 0; i < nodes.length(); i++) {
|
||||||
{
|
|
||||||
QDomElement element = nodes.at(i).toElement();
|
QDomElement element = nodes.at(i).toElement();
|
||||||
|
|
||||||
Modpack modpack;
|
Modpack modpack;
|
||||||
@ -169,26 +155,20 @@ bool PackFetchTask::parseAndAddPacks(QByteArray &data, PackType packType, Modpac
|
|||||||
modpack.broken = false;
|
modpack.broken = false;
|
||||||
modpack.bugged = false;
|
modpack.bugged = false;
|
||||||
|
|
||||||
//remove empty if the xml is bugged
|
// remove empty if the xml is bugged
|
||||||
for(QString curr : modpack.oldVersions)
|
for (QString curr : modpack.oldVersions) {
|
||||||
{
|
if (curr.isNull() || curr.isEmpty()) {
|
||||||
if(curr.isNull() || curr.isEmpty())
|
|
||||||
{
|
|
||||||
modpack.oldVersions.removeAll(curr);
|
modpack.oldVersions.removeAll(curr);
|
||||||
modpack.bugged = true;
|
modpack.bugged = true;
|
||||||
qWarning() << "Removed some empty versions from" << modpack.name;
|
qWarning() << "Removed some empty versions from" << modpack.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(modpack.oldVersions.size() < 1)
|
if (modpack.oldVersions.size() < 1) {
|
||||||
{
|
if (!modpack.currentVersion.isNull() && !modpack.currentVersion.isEmpty()) {
|
||||||
if(!modpack.currentVersion.isNull() && !modpack.currentVersion.isEmpty())
|
|
||||||
{
|
|
||||||
modpack.oldVersions.append(modpack.currentVersion);
|
modpack.oldVersions.append(modpack.currentVersion);
|
||||||
qWarning() << "Added current version to oldVersions because oldVersions was empty! (" + modpack.name + ")";
|
qWarning() << "Added current version to oldVersions because oldVersions was empty! (" + modpack.name + ")";
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
modpack.broken = true;
|
modpack.broken = true;
|
||||||
qWarning() << "Broken pack:" << modpack.name << " => No valid version!";
|
qWarning() << "Broken pack:" << modpack.name << " => No valid version!";
|
||||||
}
|
}
|
||||||
@ -218,4 +198,4 @@ void PackFetchTask::fileDownloadAborted()
|
|||||||
emit aborted();
|
emit aborted();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace LegacyFTB
|
||||||
|
@ -1,41 +1,41 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include <QTemporaryDir>
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QTemporaryDir>
|
||||||
|
#include <memory>
|
||||||
#include "PackHelpers.h"
|
#include "PackHelpers.h"
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
namespace LegacyFTB {
|
namespace LegacyFTB {
|
||||||
|
|
||||||
class PackFetchTask : public QObject {
|
class PackFetchTask : public QObject {
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PackFetchTask(shared_qobject_ptr<QNetworkAccessManager> network) : QObject(nullptr), m_network(network) {};
|
PackFetchTask(shared_qobject_ptr<QNetworkAccessManager> network) : QObject(nullptr), m_network(network){};
|
||||||
virtual ~PackFetchTask() = default;
|
virtual ~PackFetchTask() = default;
|
||||||
|
|
||||||
void fetch();
|
void fetch();
|
||||||
void fetchPrivate(const QStringList &toFetch);
|
void fetchPrivate(const QStringList& toFetch);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
||||||
NetJob::Ptr jobPtr;
|
NetJob::Ptr jobPtr;
|
||||||
|
|
||||||
QByteArray publicModpacksXmlFileData;
|
std::shared_ptr<QByteArray> publicModpacksXmlFileData = std::make_shared<QByteArray>();
|
||||||
QByteArray thirdPartyModpacksXmlFileData;
|
std::shared_ptr<QByteArray> thirdPartyModpacksXmlFileData = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
bool parseAndAddPacks(QByteArray &data, PackType packType, ModpackList &list);
|
bool parseAndAddPacks(QByteArray& data, PackType packType, ModpackList& list);
|
||||||
ModpackList publicPacks;
|
ModpackList publicPacks;
|
||||||
ModpackList thirdPartyPacks;
|
ModpackList thirdPartyPacks;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void fileDownloadFinished();
|
void fileDownloadFinished();
|
||||||
void fileDownloadFailed(QString reason);
|
void fileDownloadFailed(QString reason);
|
||||||
void fileDownloadAborted();
|
void fileDownloadAborted();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished(ModpackList publicPacks, ModpackList thirdPartyPacks);
|
void finished(ModpackList publicPacks, ModpackList thirdPartyPacks);
|
||||||
void failed(QString reason);
|
void failed(QString reason);
|
||||||
void aborted();
|
void aborted();
|
||||||
@ -44,4 +44,4 @@ signals:
|
|||||||
void privateFileDownloadFailed(QString reason, QString packCode);
|
void privateFileDownloadFailed(QString reason, QString packCode);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace LegacyFTB
|
||||||
|
@ -9,19 +9,17 @@
|
|||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
#include "net/Upload.h"
|
#include "net/Upload.h"
|
||||||
|
|
||||||
Task::Ptr ModrinthAPI::currentVersion(QString hash, QString hash_format, QByteArray* response)
|
Task::Ptr ModrinthAPI::currentVersion(QString hash, QString hash_format, std::shared_ptr<QByteArray> response)
|
||||||
{
|
{
|
||||||
auto netJob = makeShared<NetJob>(QString("Modrinth::GetCurrentVersion"), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Modrinth::GetCurrentVersion"), APPLICATION->network());
|
||||||
|
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(
|
netJob->addNetAction(Net::Download::makeByteArray(
|
||||||
QString(BuildConfig.MODRINTH_PROD_URL + "/version_file/%1?algorithm=%2").arg(hash, hash_format), response));
|
QString(BuildConfig.MODRINTH_PROD_URL + "/version_file/%1?algorithm=%2").arg(hash, hash_format), response));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
|
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::Ptr ModrinthAPI::currentVersions(const QStringList& hashes, QString hash_format, QByteArray* response)
|
Task::Ptr ModrinthAPI::currentVersions(const QStringList& hashes, QString hash_format, std::shared_ptr<QByteArray> response)
|
||||||
{
|
{
|
||||||
auto netJob = makeShared<NetJob>(QString("Modrinth::GetCurrentVersions"), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Modrinth::GetCurrentVersions"), APPLICATION->network());
|
||||||
|
|
||||||
@ -35,8 +33,6 @@ Task::Ptr ModrinthAPI::currentVersions(const QStringList& hashes, QString hash_f
|
|||||||
|
|
||||||
netJob->addNetAction(Net::Upload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files"), response, body_raw));
|
netJob->addNetAction(Net::Upload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files"), response, body_raw));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
|
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +40,7 @@ Task::Ptr ModrinthAPI::latestVersion(QString hash,
|
|||||||
QString hash_format,
|
QString hash_format,
|
||||||
std::optional<std::list<Version>> mcVersions,
|
std::optional<std::list<Version>> mcVersions,
|
||||||
std::optional<ModLoaderTypes> loaders,
|
std::optional<ModLoaderTypes> loaders,
|
||||||
QByteArray* response)
|
std::shared_ptr<QByteArray> response)
|
||||||
{
|
{
|
||||||
auto netJob = makeShared<NetJob>(QString("Modrinth::GetLatestVersion"), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Modrinth::GetLatestVersion"), APPLICATION->network());
|
||||||
|
|
||||||
@ -67,8 +63,6 @@ Task::Ptr ModrinthAPI::latestVersion(QString hash,
|
|||||||
netJob->addNetAction(Net::Upload::makeByteArray(
|
netJob->addNetAction(Net::Upload::makeByteArray(
|
||||||
QString(BuildConfig.MODRINTH_PROD_URL + "/version_file/%1/update?algorithm=%2").arg(hash, hash_format), response, body_raw));
|
QString(BuildConfig.MODRINTH_PROD_URL + "/version_file/%1/update?algorithm=%2").arg(hash, hash_format), response, body_raw));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
|
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +70,7 @@ Task::Ptr ModrinthAPI::latestVersions(const QStringList& hashes,
|
|||||||
QString hash_format,
|
QString hash_format,
|
||||||
std::optional<std::list<Version>> mcVersions,
|
std::optional<std::list<Version>> mcVersions,
|
||||||
std::optional<ModLoaderTypes> loaders,
|
std::optional<ModLoaderTypes> loaders,
|
||||||
QByteArray* response)
|
std::shared_ptr<QByteArray> response)
|
||||||
{
|
{
|
||||||
auto netJob = makeShared<NetJob>(QString("Modrinth::GetLatestVersions"), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Modrinth::GetLatestVersions"), APPLICATION->network());
|
||||||
|
|
||||||
@ -101,22 +95,16 @@ Task::Ptr ModrinthAPI::latestVersions(const QStringList& hashes,
|
|||||||
|
|
||||||
netJob->addNetAction(Net::Upload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files/update"), response, body_raw));
|
netJob->addNetAction(Net::Upload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files/update"), response, body_raw));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response] { delete response; });
|
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::Ptr ModrinthAPI::getProjects(QStringList addonIds, QByteArray* response) const
|
Task::Ptr ModrinthAPI::getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const
|
||||||
{
|
{
|
||||||
auto netJob = makeShared<NetJob>(QString("Modrinth::GetProjects"), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Modrinth::GetProjects"), APPLICATION->network());
|
||||||
auto searchUrl = getMultipleModInfoURL(addonIds);
|
auto searchUrl = getMultipleModInfoURL(addonIds);
|
||||||
|
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
|
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::finished, [response, netJob] {
|
|
||||||
delete response;
|
|
||||||
});
|
|
||||||
|
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,27 +12,23 @@
|
|||||||
|
|
||||||
class ModrinthAPI : public NetworkResourceAPI {
|
class ModrinthAPI : public NetworkResourceAPI {
|
||||||
public:
|
public:
|
||||||
auto currentVersion(QString hash,
|
auto currentVersion(QString hash, QString hash_format, std::shared_ptr<QByteArray> response) -> Task::Ptr;
|
||||||
QString hash_format,
|
|
||||||
QByteArray* response) -> Task::Ptr;
|
|
||||||
|
|
||||||
auto currentVersions(const QStringList& hashes,
|
auto currentVersions(const QStringList& hashes, QString hash_format, std::shared_ptr<QByteArray> response) -> Task::Ptr;
|
||||||
QString hash_format,
|
|
||||||
QByteArray* response) -> Task::Ptr;
|
|
||||||
|
|
||||||
auto latestVersion(QString hash,
|
auto latestVersion(QString hash,
|
||||||
QString hash_format,
|
QString hash_format,
|
||||||
std::optional<std::list<Version>> mcVersions,
|
std::optional<std::list<Version>> mcVersions,
|
||||||
std::optional<ModLoaderTypes> loaders,
|
std::optional<ModLoaderTypes> loaders,
|
||||||
QByteArray* response) -> Task::Ptr;
|
std::shared_ptr<QByteArray> response) -> Task::Ptr;
|
||||||
|
|
||||||
auto latestVersions(const QStringList& hashes,
|
auto latestVersions(const QStringList& hashes,
|
||||||
QString hash_format,
|
QString hash_format,
|
||||||
std::optional<std::list<Version>> mcVersions,
|
std::optional<std::list<Version>> mcVersions,
|
||||||
std::optional<ModLoaderTypes> loaders,
|
std::optional<ModLoaderTypes> loaders,
|
||||||
QByteArray* response) -> Task::Ptr;
|
std::shared_ptr<QByteArray> response) -> Task::Ptr;
|
||||||
|
|
||||||
Task::Ptr getProjects(QStringList addonIds, QByteArray* response) const override;
|
Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
|
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
|
||||||
|
@ -53,12 +53,11 @@ void ModrinthCheckUpdate::executeTask()
|
|||||||
// (though it will rarely happen, if at all)
|
// (though it will rarely happen, if at all)
|
||||||
if (mod->metadata()->hash_format != best_hash_type) {
|
if (mod->metadata()->hash_format != best_hash_type) {
|
||||||
auto hash_task = Hashing::createModrinthHasher(mod->fileinfo().absoluteFilePath());
|
auto hash_task = Hashing::createModrinthHasher(mod->fileinfo().absoluteFilePath());
|
||||||
connect(hash_task.get(), &Task::succeeded, [&] {
|
connect(hash_task.get(), &Hashing::Hasher::resultsReady, [&hashes, &mappings, mod](QString hash) {
|
||||||
QString hash(hash_task->getResult());
|
|
||||||
hashes.append(hash);
|
hashes.append(hash);
|
||||||
mappings.insert(hash, mod);
|
mappings.insert(hash, mod);
|
||||||
});
|
});
|
||||||
connect(hash_task.get(), &Task::failed, [this, hash_task] { failed("Failed to generate hash"); });
|
connect(hash_task.get(), &Task::failed, [this] { failed("Failed to generate hash"); });
|
||||||
hashing_task.addTask(hash_task);
|
hashing_task.addTask(hash_task);
|
||||||
} else {
|
} else {
|
||||||
hashes.append(hash);
|
hashes.append(hash);
|
||||||
@ -71,7 +70,7 @@ void ModrinthCheckUpdate::executeTask()
|
|||||||
hashing_task.start();
|
hashing_task.start();
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
|
||||||
auto* response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
auto job = api.latestVersions(hashes, best_hash_type, m_game_versions, m_loaders, response);
|
auto job = api.latestVersions(hashes, best_hash_type, m_game_versions, m_loaders, response);
|
||||||
|
|
||||||
QEventLoop lock;
|
QEventLoop lock;
|
||||||
|
@ -157,7 +157,7 @@ void ModrinthPackExportTask::makeApiRequest()
|
|||||||
if (pendingHashes.isEmpty())
|
if (pendingHashes.isEmpty())
|
||||||
buildZip();
|
buildZip();
|
||||||
else {
|
else {
|
||||||
QByteArray* response = new QByteArray;
|
auto response = std::make_shared<QByteArray>();
|
||||||
task = api.currentVersions(pendingHashes.values(), "sha512", response);
|
task = api.currentVersions(pendingHashes.values(), "sha512", response);
|
||||||
connect(task.get(), &NetJob::succeeded, [this, response]() { parseApiResponse(response); });
|
connect(task.get(), &NetJob::succeeded, [this, response]() { parseApiResponse(response); });
|
||||||
connect(task.get(), &NetJob::failed, this, &ModrinthPackExportTask::emitFailed);
|
connect(task.get(), &NetJob::failed, this, &ModrinthPackExportTask::emitFailed);
|
||||||
@ -165,7 +165,7 @@ void ModrinthPackExportTask::makeApiRequest()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModrinthPackExportTask::parseApiResponse(const QByteArray* response)
|
void ModrinthPackExportTask::parseApiResponse(const std::shared_ptr<QByteArray> response)
|
||||||
{
|
{
|
||||||
task = nullptr;
|
task = nullptr;
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ class ModrinthPackExportTask : public Task {
|
|||||||
void collectFiles();
|
void collectFiles();
|
||||||
void collectHashes();
|
void collectHashes();
|
||||||
void makeApiRequest();
|
void makeApiRequest();
|
||||||
void parseApiResponse(const QByteArray* response);
|
void parseApiResponse(const std::shared_ptr<QByteArray> response);
|
||||||
void buildZip();
|
void buildZip();
|
||||||
void finish();
|
void finish();
|
||||||
|
|
||||||
|
@ -37,20 +37,19 @@
|
|||||||
|
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <Json.h>
|
#include <Json.h>
|
||||||
#include <QtConcurrentRun>
|
|
||||||
#include <MMCZip.h>
|
#include <MMCZip.h>
|
||||||
|
#include <QtConcurrentRun>
|
||||||
|
|
||||||
#include "TechnicPackProcessor.h"
|
|
||||||
#include "SolderPackManifest.h"
|
#include "SolderPackManifest.h"
|
||||||
|
#include "TechnicPackProcessor.h"
|
||||||
#include "net/ChecksumValidator.h"
|
#include "net/ChecksumValidator.h"
|
||||||
|
|
||||||
Technic::SolderPackInstallTask::SolderPackInstallTask(
|
Technic::SolderPackInstallTask::SolderPackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network,
|
||||||
shared_qobject_ptr<QNetworkAccessManager> network,
|
const QUrl& solderUrl,
|
||||||
const QUrl &solderUrl,
|
const QString& pack,
|
||||||
const QString &pack,
|
const QString& version,
|
||||||
const QString &version,
|
const QString& minecraftVersion)
|
||||||
const QString &minecraftVersion
|
{
|
||||||
) {
|
|
||||||
m_solderUrl = solderUrl;
|
m_solderUrl = solderUrl;
|
||||||
m_pack = pack;
|
m_pack = pack;
|
||||||
m_version = version;
|
m_version = version;
|
||||||
@ -58,9 +57,9 @@ Technic::SolderPackInstallTask::SolderPackInstallTask(
|
|||||||
m_minecraftVersion = minecraftVersion;
|
m_minecraftVersion = minecraftVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Technic::SolderPackInstallTask::abort() {
|
bool Technic::SolderPackInstallTask::abort()
|
||||||
if(m_abortable)
|
{
|
||||||
{
|
if (m_abortable) {
|
||||||
return m_filesNetJob->abort();
|
return m_filesNetJob->abort();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -72,7 +71,7 @@ void Technic::SolderPackInstallTask::executeTask()
|
|||||||
|
|
||||||
m_filesNetJob.reset(new NetJob(tr("Resolving modpack files"), m_network));
|
m_filesNetJob.reset(new NetJob(tr("Resolving modpack files"), m_network));
|
||||||
auto sourceUrl = QString("%1/modpack/%2/%3").arg(m_solderUrl.toString(), m_pack, m_version);
|
auto sourceUrl = QString("%1/modpack/%2/%3").arg(m_solderUrl.toString(), m_pack, m_version);
|
||||||
m_filesNetJob->addNetAction(Net::Download::makeByteArray(sourceUrl, &m_response));
|
m_filesNetJob->addNetAction(Net::Download::makeByteArray(sourceUrl, m_response));
|
||||||
|
|
||||||
auto job = m_filesNetJob.get();
|
auto job = m_filesNetJob.get();
|
||||||
connect(job, &NetJob::succeeded, this, &Technic::SolderPackInstallTask::fileListSucceeded);
|
connect(job, &NetJob::succeeded, this, &Technic::SolderPackInstallTask::fileListSucceeded);
|
||||||
@ -85,11 +84,11 @@ void Technic::SolderPackInstallTask::fileListSucceeded()
|
|||||||
{
|
{
|
||||||
setStatus(tr("Downloading modpack"));
|
setStatus(tr("Downloading modpack"));
|
||||||
|
|
||||||
QJsonParseError parse_error {};
|
QJsonParseError parse_error{};
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(m_response, &parse_error);
|
QJsonDocument doc = QJsonDocument::fromJson(*m_response, &parse_error);
|
||||||
if (parse_error.error != QJsonParseError::NoError) {
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Error while parsing JSON response from Solder at " << parse_error.offset << " reason: " << parse_error.errorString();
|
qWarning() << "Error while parsing JSON response from Solder at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||||
qWarning() << m_response;
|
qWarning() << *m_response;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto obj = doc.object();
|
auto obj = doc.object();
|
||||||
@ -110,7 +109,7 @@ void Technic::SolderPackInstallTask::fileListSucceeded()
|
|||||||
m_filesNetJob.reset(new NetJob(tr("Downloading modpack"), m_network));
|
m_filesNetJob.reset(new NetJob(tr("Downloading modpack"), m_network));
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (const auto &mod : build.mods) {
|
for (const auto& mod : build.mods) {
|
||||||
auto path = FS::PathCombine(m_outputDir.path(), QString("%1").arg(i));
|
auto path = FS::PathCombine(m_outputDir.path(), QString("%1").arg(i));
|
||||||
|
|
||||||
auto dl = Net::Download::makeFile(mod.url, path);
|
auto dl = Net::Download::makeFile(mod.url, path);
|
||||||
|
@ -40,45 +40,48 @@
|
|||||||
#include <tasks/Task.h>
|
#include <tasks/Task.h>
|
||||||
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace Technic
|
namespace Technic {
|
||||||
{
|
class SolderPackInstallTask : public InstanceTask {
|
||||||
class SolderPackInstallTask : public InstanceTask
|
Q_OBJECT
|
||||||
{
|
public:
|
||||||
Q_OBJECT
|
explicit SolderPackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network,
|
||||||
public:
|
const QUrl& solderUrl,
|
||||||
explicit SolderPackInstallTask(shared_qobject_ptr<QNetworkAccessManager> network, const QUrl &solderUrl, const QString& pack, const QString& version, const QString &minecraftVersion);
|
const QString& pack,
|
||||||
|
const QString& version,
|
||||||
|
const QString& minecraftVersion);
|
||||||
|
|
||||||
bool canAbort() const override { return true; }
|
bool canAbort() const override { return true; }
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
virtual void executeTask() override;
|
virtual void executeTask() override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void fileListSucceeded();
|
void fileListSucceeded();
|
||||||
void downloadSucceeded();
|
void downloadSucceeded();
|
||||||
void downloadFailed(QString reason);
|
void downloadFailed(QString reason);
|
||||||
void downloadProgressChanged(qint64 current, qint64 total);
|
void downloadProgressChanged(qint64 current, qint64 total);
|
||||||
void downloadAborted();
|
void downloadAborted();
|
||||||
void extractFinished();
|
void extractFinished();
|
||||||
void extractAborted();
|
void extractAborted();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_abortable = false;
|
bool m_abortable = false;
|
||||||
|
|
||||||
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
||||||
|
|
||||||
NetJob::Ptr m_filesNetJob;
|
NetJob::Ptr m_filesNetJob;
|
||||||
QUrl m_solderUrl;
|
QUrl m_solderUrl;
|
||||||
QString m_pack;
|
QString m_pack;
|
||||||
QString m_version;
|
QString m_version;
|
||||||
QString m_minecraftVersion;
|
QString m_minecraftVersion;
|
||||||
QByteArray m_response;
|
std::shared_ptr<QByteArray> m_response = std::make_shared<QByteArray>();
|
||||||
QTemporaryDir m_outputDir;
|
QTemporaryDir m_outputDir;
|
||||||
int m_modCount;
|
int m_modCount;
|
||||||
QFuture<bool> m_extractFuture;
|
QFuture<bool> m_extractFuture;
|
||||||
QFutureWatcher<bool> m_extractFutureWatcher;
|
QFutureWatcher<bool> m_extractFutureWatcher;
|
||||||
};
|
};
|
||||||
}
|
} // namespace Technic
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* PolyMC - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||||
|
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -46,7 +47,7 @@ namespace Net {
|
|||||||
*/
|
*/
|
||||||
class ByteArraySink : public Sink {
|
class ByteArraySink : public Sink {
|
||||||
public:
|
public:
|
||||||
ByteArraySink(QByteArray* output) : m_output(output){};
|
ByteArraySink(std::shared_ptr<QByteArray> output) : m_output(output){};
|
||||||
|
|
||||||
virtual ~ByteArraySink() = default;
|
virtual ~ByteArraySink() = default;
|
||||||
|
|
||||||
@ -93,6 +94,6 @@ class ByteArraySink : public Sink {
|
|||||||
auto hasLocalData() -> bool override { return false; }
|
auto hasLocalData() -> bool override { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray* m_output;
|
std::shared_ptr<QByteArray> m_output;
|
||||||
};
|
};
|
||||||
} // namespace Net
|
} // namespace Net
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "ByteArraySink.h"
|
#include "ByteArraySink.h"
|
||||||
#include "ChecksumValidator.h"
|
#include "ChecksumValidator.h"
|
||||||
@ -69,7 +70,7 @@ auto Download::makeCached(QUrl url, MetaEntryPtr entry, Options options) -> Down
|
|||||||
return dl;
|
return dl;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Download::makeByteArray(QUrl url, QByteArray* output, Options options) -> Download::Ptr
|
auto Download::makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, Options options) -> Download::Ptr
|
||||||
{
|
{
|
||||||
auto dl = makeShared<Download>();
|
auto dl = makeShared<Download>();
|
||||||
dl->m_url = url;
|
dl->m_url = url;
|
||||||
|
@ -60,7 +60,7 @@ class Download : public NetAction {
|
|||||||
~Download() override = default;
|
~Download() override = default;
|
||||||
|
|
||||||
static auto makeCached(QUrl url, MetaEntryPtr entry, Options options = Option::NoOptions) -> Download::Ptr;
|
static auto makeCached(QUrl url, MetaEntryPtr entry, Options options = Option::NoOptions) -> Download::Ptr;
|
||||||
static auto makeByteArray(QUrl url, QByteArray* output, Options options = Option::NoOptions) -> Download::Ptr;
|
static auto makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, Options options = Option::NoOptions) -> Download::Ptr;
|
||||||
static auto makeFile(QUrl url, QString path, Options options = Option::NoOptions) -> Download::Ptr;
|
static auto makeFile(QUrl url, QString path, Options options = Option::NoOptions) -> Download::Ptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -39,218 +39,226 @@
|
|||||||
#include "Upload.h"
|
#include "Upload.h"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "ByteArraySink.h"
|
|
||||||
#include "BuildConfig.h"
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "BuildConfig.h"
|
||||||
|
#include "ByteArraySink.h"
|
||||||
|
|
||||||
#include "net/Logging.h"
|
#include "net/Logging.h"
|
||||||
|
|
||||||
namespace Net {
|
namespace Net {
|
||||||
|
|
||||||
bool Upload::abort()
|
bool Upload::abort()
|
||||||
{
|
{
|
||||||
if (m_reply) {
|
if (m_reply) {
|
||||||
m_reply->abort();
|
m_reply->abort();
|
||||||
} else {
|
} else {
|
||||||
m_state = State::AbortedByUser;
|
m_state = State::AbortedByUser;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Upload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
|
||||||
|
{
|
||||||
|
setProgress(bytesReceived, bytesTotal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Upload::downloadError(QNetworkReply::NetworkError error)
|
||||||
|
{
|
||||||
|
if (error == QNetworkReply::OperationCanceledError) {
|
||||||
|
qCCritical(taskUploadLogC) << getUid().toString() << "Aborted " << m_url.toString();
|
||||||
|
m_state = State::AbortedByUser;
|
||||||
|
} else {
|
||||||
|
// error happened during download.
|
||||||
|
qCCritical(taskUploadLogC) << getUid().toString() << "Failed " << m_url.toString() << " with reason " << error;
|
||||||
|
m_state = State::Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Upload::sslErrors(const QList<QSslError>& errors)
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
for (const auto& error : errors) {
|
||||||
|
qCCritical(taskUploadLogC) << getUid().toString() << "Upload" << m_url.toString() << "SSL Error #" << i << " : "
|
||||||
|
<< error.errorString();
|
||||||
|
auto cert = error.certificate();
|
||||||
|
qCCritical(taskUploadLogC) << getUid().toString() << "Certificate in question:\n" << cert.toText();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Upload::handleRedirect()
|
||||||
|
{
|
||||||
|
QUrl redirect = m_reply->header(QNetworkRequest::LocationHeader).toUrl();
|
||||||
|
if (!redirect.isValid()) {
|
||||||
|
if (!m_reply->hasRawHeader("Location")) {
|
||||||
|
// no redirect -> it's fine to continue
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
// there is a Location header, but it's not correct. we need to apply some workarounds...
|
||||||
}
|
QByteArray redirectBA = m_reply->rawHeader("Location");
|
||||||
|
if (redirectBA.size() == 0) {
|
||||||
void Upload::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
|
// empty, yet present redirect header? WTF?
|
||||||
setProgress(bytesReceived, bytesTotal);
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
void Upload::downloadError(QNetworkReply::NetworkError error) {
|
|
||||||
if (error == QNetworkReply::OperationCanceledError) {
|
|
||||||
qCCritical(taskUploadLogC) << getUid().toString() << "Aborted " << m_url.toString();
|
|
||||||
m_state = State::AbortedByUser;
|
|
||||||
} else {
|
|
||||||
// error happened during download.
|
|
||||||
qCCritical(taskUploadLogC) << getUid().toString() << "Failed " << m_url.toString() << " with reason " << error;
|
|
||||||
m_state = State::Failed;
|
|
||||||
}
|
}
|
||||||
}
|
QString redirectStr = QString::fromUtf8(redirectBA);
|
||||||
|
|
||||||
void Upload::sslErrors(const QList<QSslError> &errors) {
|
|
||||||
int i = 1;
|
|
||||||
for (const auto& error : errors) {
|
|
||||||
qCCritical(taskUploadLogC) << getUid().toString() << "Upload" << m_url.toString() << "SSL Error #" << i << " : " << error.errorString();
|
|
||||||
auto cert = error.certificate();
|
|
||||||
qCCritical(taskUploadLogC) << getUid().toString() << "Certificate in question:\n" << cert.toText();
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Upload::handleRedirect()
|
|
||||||
{
|
|
||||||
QUrl redirect = m_reply->header(QNetworkRequest::LocationHeader).toUrl();
|
|
||||||
if (!redirect.isValid()) {
|
|
||||||
if (!m_reply->hasRawHeader("Location")) {
|
|
||||||
// no redirect -> it's fine to continue
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// there is a Location header, but it's not correct. we need to apply some workarounds...
|
|
||||||
QByteArray redirectBA = m_reply->rawHeader("Location");
|
|
||||||
if (redirectBA.size() == 0) {
|
|
||||||
// empty, yet present redirect header? WTF?
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QString redirectStr = QString::fromUtf8(redirectBA);
|
|
||||||
|
|
||||||
if (redirectStr.startsWith("//")) {
|
|
||||||
/*
|
|
||||||
* IF the URL begins with //, we need to insert the URL scheme.
|
|
||||||
* See: https://bugreports.qt.io/browse/QTBUG-41061
|
|
||||||
* See: http://tools.ietf.org/html/rfc3986#section-4.2
|
|
||||||
*/
|
|
||||||
redirectStr = m_reply->url().scheme() + ":" + redirectStr;
|
|
||||||
} else if (redirectStr.startsWith("/")) {
|
|
||||||
/*
|
|
||||||
* IF the URL begins with /, we need to process it as a relative URL
|
|
||||||
*/
|
|
||||||
auto url = m_reply->url();
|
|
||||||
url.setPath(redirectStr, QUrl::TolerantMode);
|
|
||||||
redirectStr = url.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (redirectStr.startsWith("//")) {
|
||||||
/*
|
/*
|
||||||
* Next, make sure the URL is parsed in tolerant mode. Qt doesn't parse the location header in tolerant mode, which causes issues.
|
* IF the URL begins with //, we need to insert the URL scheme.
|
||||||
* FIXME: report Qt bug for this
|
* See: https://bugreports.qt.io/browse/QTBUG-41061
|
||||||
|
* See: http://tools.ietf.org/html/rfc3986#section-4.2
|
||||||
*/
|
*/
|
||||||
redirect = QUrl(redirectStr, QUrl::TolerantMode);
|
redirectStr = m_reply->url().scheme() + ":" + redirectStr;
|
||||||
if (!redirect.isValid()) {
|
} else if (redirectStr.startsWith("/")) {
|
||||||
qCWarning(taskUploadLogC) << getUid().toString() << "Failed to parse redirect URL:" << redirectStr;
|
/*
|
||||||
downloadError(QNetworkReply::ProtocolFailure);
|
* IF the URL begins with /, we need to process it as a relative URL
|
||||||
return false;
|
*/
|
||||||
}
|
auto url = m_reply->url();
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Fixed location header:" << redirect;
|
url.setPath(redirectStr, QUrl::TolerantMode);
|
||||||
} else {
|
redirectStr = url.toString();
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Location header:" << redirect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_url = QUrl(redirect.toString());
|
/*
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Following redirect to " << m_url.toString();
|
* Next, make sure the URL is parsed in tolerant mode. Qt doesn't parse the location header in tolerant mode, which causes issues.
|
||||||
startAction(m_network);
|
* FIXME: report Qt bug for this
|
||||||
return true;
|
*/
|
||||||
|
redirect = QUrl(redirectStr, QUrl::TolerantMode);
|
||||||
|
if (!redirect.isValid()) {
|
||||||
|
qCWarning(taskUploadLogC) << getUid().toString() << "Failed to parse redirect URL:" << redirectStr;
|
||||||
|
downloadError(QNetworkReply::ProtocolFailure);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
qCDebug(taskUploadLogC) << getUid().toString() << "Fixed location header:" << redirect;
|
||||||
|
} else {
|
||||||
|
qCDebug(taskUploadLogC) << getUid().toString() << "Location header:" << redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Upload::downloadFinished() {
|
m_url = QUrl(redirect.toString());
|
||||||
// handle HTTP redirection first
|
qCDebug(taskUploadLogC) << getUid().toString() << "Following redirect to " << m_url.toString();
|
||||||
// very unlikely for post requests, still can happen
|
startAction(m_network);
|
||||||
if (handleRedirect()) {
|
return true;
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Upload redirected:" << m_url.toString();
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the download failed before this point ...
|
void Upload::downloadFinished()
|
||||||
if (m_state == State::Succeeded) {
|
{
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Upload failed but we are allowed to proceed:" << m_url.toString();
|
// handle HTTP redirection first
|
||||||
m_sink->abort();
|
// very unlikely for post requests, still can happen
|
||||||
m_reply.reset();
|
if (handleRedirect()) {
|
||||||
emit succeeded();
|
qCDebug(taskUploadLogC) << getUid().toString() << "Upload redirected:" << m_url.toString();
|
||||||
return;
|
return;
|
||||||
} else if (m_state == State::Failed) {
|
}
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Upload failed in previous step:" << m_url.toString();
|
|
||||||
m_sink->abort();
|
|
||||||
m_reply.reset();
|
|
||||||
emit failed("");
|
|
||||||
return;
|
|
||||||
} else if (m_state == State::AbortedByUser) {
|
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Upload aborted in previous step:" << m_url.toString();
|
|
||||||
m_sink->abort();
|
|
||||||
m_reply.reset();
|
|
||||||
emit aborted();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure we got all the remaining data, if any
|
// if the download failed before this point ...
|
||||||
auto data = m_reply->readAll();
|
if (m_state == State::Succeeded) {
|
||||||
if (data.size()) {
|
qCDebug(taskUploadLogC) << getUid().toString() << "Upload failed but we are allowed to proceed:" << m_url.toString();
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Writing extra" << data.size() << "bytes";
|
m_sink->abort();
|
||||||
m_state = m_sink->write(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, finalize the whole graph
|
|
||||||
m_state = m_sink->finalize(*m_reply.get());
|
|
||||||
if (m_state != State::Succeeded) {
|
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Upload failed to finalize:" << m_url.toString();
|
|
||||||
m_sink->abort();
|
|
||||||
m_reply.reset();
|
|
||||||
emit failed("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_reply.reset();
|
m_reply.reset();
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Upload succeeded:" << m_url.toString();
|
|
||||||
emit succeeded();
|
emit succeeded();
|
||||||
|
return;
|
||||||
|
} else if (m_state == State::Failed) {
|
||||||
|
qCDebug(taskUploadLogC) << getUid().toString() << "Upload failed in previous step:" << m_url.toString();
|
||||||
|
m_sink->abort();
|
||||||
|
m_reply.reset();
|
||||||
|
emit failed("");
|
||||||
|
return;
|
||||||
|
} else if (m_state == State::AbortedByUser) {
|
||||||
|
qCDebug(taskUploadLogC) << getUid().toString() << "Upload aborted in previous step:" << m_url.toString();
|
||||||
|
m_sink->abort();
|
||||||
|
m_reply.reset();
|
||||||
|
emit aborted();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Upload::downloadReadyRead() {
|
// make sure we got all the remaining data, if any
|
||||||
if (m_state == State::Running) {
|
auto data = m_reply->readAll();
|
||||||
auto data = m_reply->readAll();
|
if (data.size()) {
|
||||||
m_state = m_sink->write(data);
|
qCDebug(taskUploadLogC) << getUid().toString() << "Writing extra" << data.size() << "bytes";
|
||||||
}
|
m_state = m_sink->write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Upload::executeTask() {
|
// otherwise, finalize the whole graph
|
||||||
setStatus(tr("Uploading %1").arg(m_url.toString()));
|
m_state = m_sink->finalize(*m_reply.get());
|
||||||
|
if (m_state != State::Succeeded) {
|
||||||
|
qCDebug(taskUploadLogC) << getUid().toString() << "Upload failed to finalize:" << m_url.toString();
|
||||||
|
m_sink->abort();
|
||||||
|
m_reply.reset();
|
||||||
|
emit failed("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_reply.reset();
|
||||||
|
qCDebug(taskUploadLogC) << getUid().toString() << "Upload succeeded:" << m_url.toString();
|
||||||
|
emit succeeded();
|
||||||
|
}
|
||||||
|
|
||||||
if (m_state == State::AbortedByUser) {
|
void Upload::downloadReadyRead()
|
||||||
qCWarning(taskUploadLogC) << getUid().toString() << "Attempt to start an aborted Upload:" << m_url.toString();
|
{
|
||||||
emit aborted();
|
if (m_state == State::Running) {
|
||||||
|
auto data = m_reply->readAll();
|
||||||
|
m_state = m_sink->write(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Upload::executeTask()
|
||||||
|
{
|
||||||
|
setStatus(tr("Uploading %1").arg(m_url.toString()));
|
||||||
|
|
||||||
|
if (m_state == State::AbortedByUser) {
|
||||||
|
qCWarning(taskUploadLogC) << getUid().toString() << "Attempt to start an aborted Upload:" << m_url.toString();
|
||||||
|
emit aborted();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QNetworkRequest request(m_url);
|
||||||
|
m_state = m_sink->init(request);
|
||||||
|
switch (m_state) {
|
||||||
|
case State::Succeeded:
|
||||||
|
emitSucceeded();
|
||||||
|
qCDebug(taskUploadLogC) << getUid().toString() << "Upload cache hit " << m_url.toString();
|
||||||
return;
|
return;
|
||||||
}
|
case State::Running:
|
||||||
QNetworkRequest request(m_url);
|
qCDebug(taskUploadLogC) << getUid().toString() << "Uploading " << m_url.toString();
|
||||||
m_state = m_sink->init(request);
|
break;
|
||||||
switch (m_state) {
|
case State::Inactive:
|
||||||
case State::Succeeded:
|
case State::Failed:
|
||||||
emitSucceeded();
|
emitFailed("");
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Upload cache hit " << m_url.toString();
|
return;
|
||||||
return;
|
case State::AbortedByUser:
|
||||||
case State::Running:
|
emitAborted();
|
||||||
qCDebug(taskUploadLogC) << getUid().toString() << "Uploading " << m_url.toString();
|
return;
|
||||||
break;
|
}
|
||||||
case State::Inactive:
|
|
||||||
case State::Failed:
|
|
||||||
emitFailed("");
|
|
||||||
return;
|
|
||||||
case State::AbortedByUser:
|
|
||||||
emitAborted();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
request.setHeader(QNetworkRequest::UserAgentHeader, APPLICATION->getUserAgent().toUtf8());
|
request.setHeader(QNetworkRequest::UserAgentHeader, APPLICATION->getUserAgent().toUtf8());
|
||||||
// TODO remove duplication
|
// TODO remove duplication
|
||||||
if (APPLICATION->capabilities() & Application::SupportsFlame && request.url().host() == QUrl(BuildConfig.FLAME_BASE_URL).host()) {
|
if (APPLICATION->capabilities() & Application::SupportsFlame && request.url().host() == QUrl(BuildConfig.FLAME_BASE_URL).host()) {
|
||||||
request.setRawHeader("x-api-key", APPLICATION->getFlameAPIKey().toUtf8());
|
request.setRawHeader("x-api-key", APPLICATION->getFlameAPIKey().toUtf8());
|
||||||
} else if (request.url().host() == QUrl(BuildConfig.MODRINTH_PROD_URL).host() ||
|
} else if (request.url().host() == QUrl(BuildConfig.MODRINTH_PROD_URL).host() ||
|
||||||
request.url().host() == QUrl(BuildConfig.MODRINTH_STAGING_URL).host()) {
|
request.url().host() == QUrl(BuildConfig.MODRINTH_STAGING_URL).host()) {
|
||||||
QString token = APPLICATION->getModrinthAPIToken();
|
QString token = APPLICATION->getModrinthAPIToken();
|
||||||
if (!token.isNull())
|
if (!token.isNull())
|
||||||
request.setRawHeader("Authorization", token.toUtf8());
|
request.setRawHeader("Authorization", token.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO other types of post requests ?
|
// TODO other types of post requests ?
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||||
QNetworkReply* rep = m_network->post(request, m_post_data);
|
QNetworkReply* rep = m_network->post(request, m_post_data);
|
||||||
|
|
||||||
m_reply.reset(rep);
|
m_reply.reset(rep);
|
||||||
connect(rep, &QNetworkReply::downloadProgress, this, &Upload::downloadProgress);
|
connect(rep, &QNetworkReply::downloadProgress, this, &Upload::downloadProgress);
|
||||||
connect(rep, &QNetworkReply::finished, this, &Upload::downloadFinished);
|
connect(rep, &QNetworkReply::finished, this, &Upload::downloadFinished);
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15
|
||||||
connect(rep, &QNetworkReply::errorOccurred, this, &Upload::downloadError);
|
connect(rep, &QNetworkReply::errorOccurred, this, &Upload::downloadError);
|
||||||
#else
|
#else
|
||||||
connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &Upload::downloadError);
|
connect(rep, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &Upload::downloadError);
|
||||||
#endif
|
#endif
|
||||||
connect(rep, &QNetworkReply::sslErrors, this, &Upload::sslErrors);
|
connect(rep, &QNetworkReply::sslErrors, this, &Upload::sslErrors);
|
||||||
connect(rep, &QNetworkReply::readyRead, this, &Upload::downloadReadyRead);
|
connect(rep, &QNetworkReply::readyRead, this, &Upload::downloadReadyRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
Upload::Ptr Upload::makeByteArray(QUrl url, QByteArray *output, QByteArray m_post_data) {
|
Upload::Ptr Upload::makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, QByteArray m_post_data)
|
||||||
auto up = makeShared<Upload>();
|
{
|
||||||
up->m_url = std::move(url);
|
auto up = makeShared<Upload>();
|
||||||
up->m_sink.reset(new ByteArraySink(output));
|
up->m_url = std::move(url);
|
||||||
up->m_post_data = std::move(m_post_data);
|
up->m_sink.reset(new ByteArraySink(output));
|
||||||
return up;
|
up->m_post_data = std::move(m_post_data);
|
||||||
}
|
return up;
|
||||||
} // Net
|
}
|
||||||
|
} // namespace Net
|
||||||
|
@ -42,31 +42,31 @@
|
|||||||
|
|
||||||
namespace Net {
|
namespace Net {
|
||||||
|
|
||||||
class Upload : public NetAction {
|
class Upload : public NetAction {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Ptr = shared_qobject_ptr<Upload>;
|
using Ptr = shared_qobject_ptr<Upload>;
|
||||||
|
|
||||||
static Upload::Ptr makeByteArray(QUrl url, QByteArray *output, QByteArray m_post_data);
|
static Upload::Ptr makeByteArray(QUrl url, std::shared_ptr<QByteArray> output, QByteArray m_post_data);
|
||||||
auto abort() -> bool override;
|
auto abort() -> bool override;
|
||||||
auto canAbort() const -> bool override { return true; };
|
auto canAbort() const -> bool override { return true; };
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override;
|
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) override;
|
||||||
void downloadError(QNetworkReply::NetworkError error) override;
|
void downloadError(QNetworkReply::NetworkError error) override;
|
||||||
void sslErrors(const QList<QSslError> & errors) override;
|
void sslErrors(const QList<QSslError>& errors) override;
|
||||||
void downloadFinished() override;
|
void downloadFinished() override;
|
||||||
void downloadReadyRead() override;
|
void downloadReadyRead() override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
private:
|
|
||||||
std::unique_ptr<Sink> m_sink;
|
|
||||||
QByteArray m_post_data;
|
|
||||||
|
|
||||||
bool handleRedirect();
|
private:
|
||||||
};
|
std::unique_ptr<Sink> m_sink;
|
||||||
|
QByteArray m_post_data;
|
||||||
|
|
||||||
} // Net
|
bool handleRedirect();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Net
|
||||||
|
@ -58,7 +58,7 @@ void NewsChecker::reloadNews()
|
|||||||
qDebug() << "Reloading news.";
|
qDebug() << "Reloading news.";
|
||||||
|
|
||||||
NetJob::Ptr job{ new NetJob("News RSS Feed", m_network) };
|
NetJob::Ptr job{ new NetJob("News RSS Feed", m_network) };
|
||||||
job->addNetAction(Net::Download::makeByteArray(m_feedUrl, &newsData));
|
job->addNetAction(Net::Download::makeByteArray(m_feedUrl, newsData));
|
||||||
QObject::connect(job.get(), &NetJob::succeeded, this, &NewsChecker::rssDownloadFinished);
|
QObject::connect(job.get(), &NetJob::succeeded, this, &NewsChecker::rssDownloadFinished);
|
||||||
QObject::connect(job.get(), &NetJob::failed, this, &NewsChecker::rssDownloadFailed);
|
QObject::connect(job.get(), &NetJob::failed, this, &NewsChecker::rssDownloadFailed);
|
||||||
m_newsNetJob.reset(job);
|
m_newsNetJob.reset(job);
|
||||||
@ -79,32 +79,27 @@ void NewsChecker::rssDownloadFinished()
|
|||||||
int errorCol = -1;
|
int errorCol = -1;
|
||||||
|
|
||||||
// Parse the XML.
|
// Parse the XML.
|
||||||
if (!doc.setContent(newsData, false, &errorMsg, &errorLine, &errorCol))
|
if (!doc.setContent(*newsData, false, &errorMsg, &errorLine, &errorCol)) {
|
||||||
{
|
|
||||||
QString fullErrorMsg = QString("Error parsing RSS feed XML. %1 at %2:%3.").arg(errorMsg).arg(errorLine).arg(errorCol);
|
QString fullErrorMsg = QString("Error parsing RSS feed XML. %1 at %2:%3.").arg(errorMsg).arg(errorLine).arg(errorCol);
|
||||||
fail(fullErrorMsg);
|
fail(fullErrorMsg);
|
||||||
newsData.clear();
|
newsData->clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
newsData.clear();
|
newsData->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the parsing succeeded, read it.
|
// If the parsing succeeded, read it.
|
||||||
QDomNodeList items = doc.elementsByTagName("entry");
|
QDomNodeList items = doc.elementsByTagName("entry");
|
||||||
m_newsEntries.clear();
|
m_newsEntries.clear();
|
||||||
for (int i = 0; i < items.length(); i++)
|
for (int i = 0; i < items.length(); i++) {
|
||||||
{
|
|
||||||
QDomElement element = items.at(i).toElement();
|
QDomElement element = items.at(i).toElement();
|
||||||
NewsEntryPtr entry;
|
NewsEntryPtr entry;
|
||||||
entry.reset(new NewsEntry());
|
entry.reset(new NewsEntry());
|
||||||
QString errorMsg = "An unknown error occurred.";
|
QString errorMsg = "An unknown error occurred.";
|
||||||
if (NewsEntry::fromXmlElement(element, entry.get(), &errorMsg))
|
if (NewsEntry::fromXmlElement(element, entry.get(), &errorMsg)) {
|
||||||
{
|
|
||||||
qDebug() << "Loaded news entry" << entry->title;
|
qDebug() << "Loaded news entry" << entry->title;
|
||||||
m_newsEntries.append(entry);
|
m_newsEntries.append(entry);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
qWarning() << "Failed to load news entry at index" << i << ":" << errorMsg;
|
qWarning() << "Failed to load news entry at index" << i << ":" << errorMsg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ protected: /* data */
|
|||||||
//! True if news has been loaded.
|
//! True if news has been loaded.
|
||||||
bool m_loadedNews;
|
bool m_loadedNews;
|
||||||
|
|
||||||
QByteArray newsData;
|
std::shared_ptr<QByteArray> newsData = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Gets the error message that was given last time the news was loaded.
|
* Gets the error message that was given last time the news was loaded.
|
||||||
|
@ -32,7 +32,7 @@ NewsDialog::~NewsDialog()
|
|||||||
|
|
||||||
void NewsDialog::selectedArticleChanged(const QString& new_title)
|
void NewsDialog::selectedArticleChanged(const QString& new_title)
|
||||||
{
|
{
|
||||||
auto const& article_entry = m_entries.constFind(new_title).value();
|
auto article_entry = m_entries.constFind(new_title).value();
|
||||||
|
|
||||||
ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, new_title));
|
ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, new_title));
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ void ModrinthManagedPackPage::parseManagedPack()
|
|||||||
|
|
||||||
QString id = m_inst->getManagedPackID();
|
QString id = m_inst->getManagedPackID();
|
||||||
|
|
||||||
m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response.get()));
|
m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
|
||||||
|
|
||||||
QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] {
|
QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
@ -369,7 +369,7 @@ void FlameManagedPackPage::parseManagedPack()
|
|||||||
|
|
||||||
QString id = m_inst->getManagedPackID();
|
QString id = m_inst->getManagedPackID();
|
||||||
|
|
||||||
m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/mods/%2/files").arg(BuildConfig.FLAME_BASE_URL, id), response.get()));
|
m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/mods/%2/files").arg(BuildConfig.FLAME_BASE_URL, id), response));
|
||||||
|
|
||||||
QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] {
|
QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] {
|
||||||
QJsonParseError parse_error{};
|
QJsonParseError parse_error{};
|
||||||
|
@ -16,62 +16,49 @@
|
|||||||
|
|
||||||
#include "AtlListModel.h"
|
#include "AtlListModel.h"
|
||||||
|
|
||||||
#include <BuildConfig.h>
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
|
#include <BuildConfig.h>
|
||||||
#include <Json.h>
|
#include <Json.h>
|
||||||
|
|
||||||
namespace Atl {
|
namespace Atl {
|
||||||
|
|
||||||
ListModel::ListModel(QObject *parent) : QAbstractListModel(parent)
|
ListModel::ListModel(QObject* parent) : QAbstractListModel(parent) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ListModel::~ListModel()
|
ListModel::~ListModel() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
int ListModel::rowCount(const QModelIndex &parent) const
|
int ListModel::rowCount(const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : modpacks.size();
|
return parent.isValid() ? 0 : modpacks.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ListModel::columnCount(const QModelIndex &parent) const
|
int ListModel::columnCount(const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : 1;
|
return parent.isValid() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant ListModel::data(const QModelIndex &index, int role) const
|
QVariant ListModel::data(const QModelIndex& index, int role) const
|
||||||
{
|
{
|
||||||
int pos = index.row();
|
int pos = index.row();
|
||||||
if(pos >= modpacks.size() || pos < 0 || !index.isValid())
|
if (pos >= modpacks.size() || pos < 0 || !index.isValid()) {
|
||||||
{
|
|
||||||
return QString("INVALID INDEX %1").arg(pos);
|
return QString("INVALID INDEX %1").arg(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
ATLauncher::IndexedPack pack = modpacks.at(pos);
|
ATLauncher::IndexedPack pack = modpacks.at(pos);
|
||||||
if(role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole) {
|
||||||
{
|
|
||||||
return pack.name;
|
return pack.name;
|
||||||
}
|
} else if (role == Qt::ToolTipRole) {
|
||||||
else if (role == Qt::ToolTipRole)
|
|
||||||
{
|
|
||||||
return pack.name;
|
return pack.name;
|
||||||
}
|
} else if (role == Qt::DecorationRole) {
|
||||||
else if(role == Qt::DecorationRole)
|
if (m_logoMap.contains(pack.safeName)) {
|
||||||
{
|
|
||||||
if(m_logoMap.contains(pack.safeName))
|
|
||||||
{
|
|
||||||
return (m_logoMap.value(pack.safeName));
|
return (m_logoMap.value(pack.safeName));
|
||||||
}
|
}
|
||||||
auto icon = APPLICATION->getThemedIcon("atlauncher-placeholder");
|
auto icon = APPLICATION->getThemedIcon("atlauncher-placeholder");
|
||||||
|
|
||||||
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/images/%1.png").arg(pack.safeName.toLower());
|
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/images/%1.png").arg(pack.safeName.toLower());
|
||||||
((ListModel *)this)->requestLogo(pack.safeName, url);
|
((ListModel*)this)->requestLogo(pack.safeName, url);
|
||||||
|
|
||||||
return icon;
|
return icon;
|
||||||
}
|
} else if (role == Qt::UserRole) {
|
||||||
else if(role == Qt::UserRole)
|
|
||||||
{
|
|
||||||
QVariant v;
|
QVariant v;
|
||||||
v.setValue(pack);
|
v.setValue(pack);
|
||||||
return v;
|
return v;
|
||||||
@ -88,7 +75,7 @@ void ListModel::request()
|
|||||||
|
|
||||||
auto netJob = makeShared<NetJob>("Atl::Request", APPLICATION->network());
|
auto netJob = makeShared<NetJob>("Atl::Request", APPLICATION->network());
|
||||||
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/json/packsnew.json");
|
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/json/packsnew.json");
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), &response));
|
netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), response));
|
||||||
jobPtr = netJob;
|
jobPtr = netJob;
|
||||||
jobPtr->start();
|
jobPtr->start();
|
||||||
|
|
||||||
@ -101,36 +88,38 @@ void ListModel::requestFinished()
|
|||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
|
|
||||||
QJsonParseError parse_error;
|
QJsonParseError parse_error;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||||
if(parse_error.error != QJsonParseError::NoError) {
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Error while parsing JSON response from ATL at " << parse_error.offset << " reason: " << parse_error.errorString();
|
qWarning() << "Error while parsing JSON response from ATL at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||||
qWarning() << response;
|
qWarning() << *response;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ATLauncher::IndexedPack> newList;
|
QList<ATLauncher::IndexedPack> newList;
|
||||||
|
|
||||||
auto packs = doc.array();
|
auto packs = doc.array();
|
||||||
for(auto packRaw : packs) {
|
for (auto packRaw : packs) {
|
||||||
auto packObj = packRaw.toObject();
|
auto packObj = packRaw.toObject();
|
||||||
|
|
||||||
ATLauncher::IndexedPack pack;
|
ATLauncher::IndexedPack pack;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ATLauncher::loadIndexedPack(pack, packObj);
|
ATLauncher::loadIndexedPack(pack, packObj);
|
||||||
}
|
} catch (const JSONValidationError& e) {
|
||||||
catch (const JSONValidationError &e) {
|
qDebug() << QString::fromUtf8(*response);
|
||||||
qDebug() << QString::fromUtf8(response);
|
|
||||||
qWarning() << "Error while reading pack manifest from ATLauncher: " << e.cause();
|
qWarning() << "Error while reading pack manifest from ATLauncher: " << e.cause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore packs without a published version
|
// ignore packs without a published version
|
||||||
if(pack.versions.length() == 0) continue;
|
if (pack.versions.length() == 0)
|
||||||
|
continue;
|
||||||
// only display public packs (for now)
|
// only display public packs (for now)
|
||||||
if(pack.type != ATLauncher::PackType::Public) continue;
|
if (pack.type != ATLauncher::PackType::Public)
|
||||||
|
continue;
|
||||||
// ignore "system" packs (Vanilla, Vanilla with Forge, etc)
|
// ignore "system" packs (Vanilla, Vanilla with Forge, etc)
|
||||||
if(pack.system) continue;
|
if (pack.system)
|
||||||
|
continue;
|
||||||
|
|
||||||
newList.append(pack);
|
newList.append(pack);
|
||||||
}
|
}
|
||||||
@ -145,14 +134,12 @@ void ListModel::requestFailed(QString reason)
|
|||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback)
|
void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback)
|
||||||
{
|
{
|
||||||
if(m_logoMap.contains(logo))
|
if (m_logoMap.contains(logo)) {
|
||||||
{
|
callback(
|
||||||
callback(APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
|
APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
requestLogo(logo, logoUrl);
|
requestLogo(logo, logoUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,36 +155,34 @@ void ListModel::logoLoaded(QString logo, QIcon out)
|
|||||||
m_loadingLogos.removeAll(logo);
|
m_loadingLogos.removeAll(logo);
|
||||||
m_logoMap.insert(logo, out);
|
m_logoMap.insert(logo, out);
|
||||||
|
|
||||||
for(int i = 0; i < modpacks.size(); i++) {
|
for (int i = 0; i < modpacks.size(); i++) {
|
||||||
if(modpacks[i].safeName == logo) {
|
if (modpacks[i].safeName == logo) {
|
||||||
emit dataChanged(createIndex(i, 0), createIndex(i, 0), {Qt::DecorationRole});
|
emit dataChanged(createIndex(i, 0), createIndex(i, 0), { Qt::DecorationRole });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListModel::requestLogo(QString file, QString url)
|
void ListModel::requestLogo(QString file, QString url)
|
||||||
{
|
{
|
||||||
if(m_loadingLogos.contains(file) || m_failedLogos.contains(file))
|
if (m_loadingLogos.contains(file) || m_failedLogos.contains(file)) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
|
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
|
||||||
NetJob *job = new NetJob(QString("ATLauncher Icon Download %1").arg(file), APPLICATION->network());
|
auto job = new NetJob(QString("ATLauncher Icon Download %1").arg(file), APPLICATION->network());
|
||||||
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
|
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
|
||||||
|
|
||||||
auto fullPath = entry->getFullPath();
|
auto fullPath = entry->getFullPath();
|
||||||
QObject::connect(job, &NetJob::succeeded, this, [this, file, fullPath]
|
QObject::connect(job, &NetJob::succeeded, this, [this, file, fullPath, job] {
|
||||||
{
|
job->deleteLater();
|
||||||
emit logoLoaded(file, QIcon(fullPath));
|
emit logoLoaded(file, QIcon(fullPath));
|
||||||
if(waitingCallbacks.contains(file))
|
if (waitingCallbacks.contains(file)) {
|
||||||
{
|
|
||||||
waitingCallbacks.value(file)(fullPath);
|
waitingCallbacks.value(file)(fullPath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(job, &NetJob::failed, this, [this, file]
|
QObject::connect(job, &NetJob::failed, this, [this, file, job] {
|
||||||
{
|
job->deleteLater();
|
||||||
emit logoFailed(file);
|
emit logoFailed(file);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -206,4 +191,4 @@ void ListModel::requestLogo(QString file, QString url)
|
|||||||
m_loadingLogos.append(file);
|
m_loadingLogos.append(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Atl
|
||||||
|
@ -18,42 +18,41 @@
|
|||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include <QIcon>
|
|
||||||
#include <modplatform/atlauncher/ATLPackIndex.h>
|
#include <modplatform/atlauncher/ATLPackIndex.h>
|
||||||
|
#include <QIcon>
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
namespace Atl {
|
namespace Atl {
|
||||||
|
|
||||||
typedef QMap<QString, QIcon> LogoMap;
|
typedef QMap<QString, QIcon> LogoMap;
|
||||||
typedef std::function<void(QString)> LogoCallback;
|
typedef std::function<void(QString)> LogoCallback;
|
||||||
|
|
||||||
class ListModel : public QAbstractListModel
|
class ListModel : public QAbstractListModel {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ListModel(QObject *parent);
|
ListModel(QObject* parent);
|
||||||
virtual ~ListModel();
|
virtual ~ListModel();
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
int rowCount(const QModelIndex& parent) const override;
|
||||||
int columnCount(const QModelIndex &parent) const override;
|
int columnCount(const QModelIndex& parent) const override;
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex& index, int role) const override;
|
||||||
|
|
||||||
void request();
|
void request();
|
||||||
|
|
||||||
void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback);
|
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void requestFinished();
|
void requestFinished();
|
||||||
void requestFailed(QString reason);
|
void requestFailed(QString reason);
|
||||||
|
|
||||||
void logoFailed(QString logo);
|
void logoFailed(QString logo);
|
||||||
void logoLoaded(QString logo, QIcon out);
|
void logoLoaded(QString logo, QIcon out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void requestLogo(QString file, QString url);
|
void requestLogo(QString file, QString url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<ATLauncher::IndexedPack> modpacks;
|
QList<ATLauncher::IndexedPack> modpacks;
|
||||||
|
|
||||||
QStringList m_failedLogos;
|
QStringList m_failedLogos;
|
||||||
@ -62,7 +61,7 @@ private:
|
|||||||
QMap<QString, LogoCallback> waitingCallbacks;
|
QMap<QString, LogoCallback> waitingCallbacks;
|
||||||
|
|
||||||
NetJob::Ptr jobPtr;
|
NetJob::Ptr jobPtr;
|
||||||
QByteArray response;
|
std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace Atl
|
||||||
|
@ -152,7 +152,7 @@ Qt::ItemFlags AtlOptionalModListModel::flags(const QModelIndex &index) const {
|
|||||||
void AtlOptionalModListModel::useShareCode(const QString& code) {
|
void AtlOptionalModListModel::useShareCode(const QString& code) {
|
||||||
m_jobPtr.reset(new NetJob("Atl::Request", APPLICATION->network()));
|
m_jobPtr.reset(new NetJob("Atl::Request", APPLICATION->network()));
|
||||||
auto url = QString(BuildConfig.ATL_API_BASE_URL + "share-codes/" + code);
|
auto url = QString(BuildConfig.ATL_API_BASE_URL + "share-codes/" + code);
|
||||||
m_jobPtr->addNetAction(Net::Download::makeByteArray(QUrl(url), &m_response));
|
m_jobPtr->addNetAction(Net::Download::makeByteArray(QUrl(url), m_response));
|
||||||
|
|
||||||
connect(m_jobPtr.get(), &NetJob::succeeded,
|
connect(m_jobPtr.get(), &NetJob::succeeded,
|
||||||
this, &AtlOptionalModListModel::shareCodeSuccess);
|
this, &AtlOptionalModListModel::shareCodeSuccess);
|
||||||
@ -166,10 +166,10 @@ void AtlOptionalModListModel::shareCodeSuccess() {
|
|||||||
m_jobPtr.reset();
|
m_jobPtr.reset();
|
||||||
|
|
||||||
QJsonParseError parse_error {};
|
QJsonParseError parse_error {};
|
||||||
auto doc = QJsonDocument::fromJson(m_response, &parse_error);
|
auto doc = QJsonDocument::fromJson(*m_response, &parse_error);
|
||||||
if (parse_error.error != QJsonParseError::NoError) {
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Error while parsing JSON response from ATL at " << parse_error.offset << " reason: " << parse_error.errorString();
|
qWarning() << "Error while parsing JSON response from ATL at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||||
qWarning() << m_response;
|
qWarning() << *m_response;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto obj = doc.object();
|
auto obj = doc.object();
|
||||||
@ -179,7 +179,7 @@ void AtlOptionalModListModel::shareCodeSuccess() {
|
|||||||
ATLauncher::loadShareCodeResponse(response, obj);
|
ATLauncher::loadShareCodeResponse(response, obj);
|
||||||
}
|
}
|
||||||
catch (const JSONValidationError& e) {
|
catch (const JSONValidationError& e) {
|
||||||
qDebug() << QString::fromUtf8(m_response);
|
qDebug() << QString::fromUtf8(*m_response);
|
||||||
qWarning() << "Error while reading response from ATLauncher: " << e.cause();
|
qWarning() << "Error while reading response from ATLauncher: " << e.cause();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -82,9 +82,9 @@ private:
|
|||||||
void toggleMod(ATLauncher::VersionMod mod, int index);
|
void toggleMod(ATLauncher::VersionMod mod, int index);
|
||||||
void setMod(ATLauncher::VersionMod mod, int index, bool enable, bool shouldEmit = true);
|
void setMod(ATLauncher::VersionMod mod, int index, bool enable, bool shouldEmit = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NetJob::Ptr m_jobPtr;
|
NetJob::Ptr m_jobPtr;
|
||||||
QByteArray m_response;
|
std::shared_ptr<QByteArray> m_response = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
ATLauncher::PackVersion m_version;
|
ATLauncher::PackVersion m_version;
|
||||||
QVector<ATLauncher::VersionMod> m_mods;
|
QVector<ATLauncher::VersionMod> m_mods;
|
||||||
|
@ -42,15 +42,15 @@
|
|||||||
class AtlUserInteractionSupportImpl : public QObject, public ATLauncher::UserInteractionSupport {
|
class AtlUserInteractionSupportImpl : public QObject, public ATLauncher::UserInteractionSupport {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AtlUserInteractionSupportImpl(QWidget* parent);
|
AtlUserInteractionSupportImpl(QWidget* parent);
|
||||||
|
virtual ~AtlUserInteractionSupportImpl() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString chooseVersion(Meta::VersionList::Ptr vlist, QString minecraftVersion) override;
|
QString chooseVersion(Meta::VersionList::Ptr vlist, QString minecraftVersion) override;
|
||||||
std::optional<QVector<QString>> chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods) override;
|
std::optional<QVector<QString>> chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods) override;
|
||||||
void displayMessage(QString message) override;
|
void displayMessage(QString message) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget* m_parent;
|
QWidget* m_parent;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -171,7 +171,7 @@ void ListModel::performPaginatedSearch()
|
|||||||
.arg(currentSearchTerm)
|
.arg(currentSearchTerm)
|
||||||
.arg(currentSort + 1);
|
.arg(currentSort + 1);
|
||||||
|
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
|
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
|
||||||
jobPtr = netJob;
|
jobPtr = netJob;
|
||||||
jobPtr->start();
|
jobPtr->start();
|
||||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, &ListModel::searchRequestFinished);
|
QObject::connect(netJob.get(), &NetJob::succeeded, this, &ListModel::searchRequestFinished);
|
||||||
@ -204,11 +204,11 @@ void Flame::ListModel::searchRequestFinished()
|
|||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
|
|
||||||
QJsonParseError parse_error;
|
QJsonParseError parse_error;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||||
if (parse_error.error != QJsonParseError::NoError) {
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Error while parsing JSON response from CurseForge at " << parse_error.offset
|
qWarning() << "Error while parsing JSON response from CurseForge at " << parse_error.offset
|
||||||
<< " reason: " << parse_error.errorString();
|
<< " reason: " << parse_error.errorString();
|
||||||
qWarning() << response;
|
qWarning() << *response;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,46 +3,44 @@
|
|||||||
#include <RWStorage.h>
|
#include <RWStorage.h>
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QSortFilterProxyModel>
|
|
||||||
#include <QThreadPool>
|
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QStyledItemDelegate>
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QMetaType>
|
#include <QStyledItemDelegate>
|
||||||
|
#include <QThreadPool>
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <net/NetJob.h>
|
#include <net/NetJob.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include <modplatform/flame/FlamePackIndex.h>
|
#include <modplatform/flame/FlamePackIndex.h>
|
||||||
|
|
||||||
namespace Flame {
|
namespace Flame {
|
||||||
|
|
||||||
|
|
||||||
typedef QMap<QString, QIcon> LogoMap;
|
typedef QMap<QString, QIcon> LogoMap;
|
||||||
typedef std::function<void(QString)> LogoCallback;
|
typedef std::function<void(QString)> LogoCallback;
|
||||||
|
|
||||||
class ListModel : public QAbstractListModel
|
class ListModel : public QAbstractListModel {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ListModel(QObject *parent);
|
ListModel(QObject* parent);
|
||||||
virtual ~ListModel();
|
virtual ~ListModel();
|
||||||
|
|
||||||
int rowCount(const QModelIndex &parent) const override;
|
int rowCount(const QModelIndex& parent) const override;
|
||||||
int columnCount(const QModelIndex &parent) const override;
|
int columnCount(const QModelIndex& parent) const override;
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex& index, int role) const override;
|
||||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
|
||||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||||
bool canFetchMore(const QModelIndex & parent) const override;
|
bool canFetchMore(const QModelIndex& parent) const override;
|
||||||
void fetchMore(const QModelIndex & parent) override;
|
void fetchMore(const QModelIndex& parent) override;
|
||||||
|
|
||||||
void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback);
|
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
|
||||||
void searchWithTerm(const QString & term, const int sort);
|
void searchWithTerm(const QString& term, const int sort);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void performPaginatedSearch();
|
void performPaginatedSearch();
|
||||||
|
|
||||||
void logoFailed(QString logo);
|
void logoFailed(QString logo);
|
||||||
@ -51,10 +49,10 @@ private slots:
|
|||||||
void searchRequestFinished();
|
void searchRequestFinished();
|
||||||
void searchRequestFailed(QString reason);
|
void searchRequestFailed(QString reason);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void requestLogo(QString file, QString url);
|
void requestLogo(QString file, QString url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<IndexedPack> modpacks;
|
QList<IndexedPack> modpacks;
|
||||||
QStringList m_failedLogos;
|
QStringList m_failedLogos;
|
||||||
QStringList m_loadingLogos;
|
QStringList m_loadingLogos;
|
||||||
@ -64,14 +62,9 @@ private:
|
|||||||
QString currentSearchTerm;
|
QString currentSearchTerm;
|
||||||
int currentSort = 0;
|
int currentSort = 0;
|
||||||
int nextSearchOffset = 0;
|
int nextSearchOffset = 0;
|
||||||
enum SearchState {
|
enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None;
|
||||||
None,
|
|
||||||
CanPossiblyFetchMore,
|
|
||||||
ResetRequested,
|
|
||||||
Finished
|
|
||||||
} searchState = None;
|
|
||||||
NetJob::Ptr jobPtr;
|
NetJob::Ptr jobPtr;
|
||||||
QByteArray response;
|
std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace Flame
|
||||||
|
@ -130,7 +130,7 @@ void FlamePage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
|||||||
if (current.versionsLoaded == false) {
|
if (current.versionsLoaded == false) {
|
||||||
qDebug() << "Loading flame modpack versions";
|
qDebug() << "Loading flame modpack versions";
|
||||||
auto netJob = new NetJob(QString("Flame::PackVersions(%1)").arg(current.name), APPLICATION->network());
|
auto netJob = new NetJob(QString("Flame::PackVersions(%1)").arg(current.name), APPLICATION->network());
|
||||||
auto response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
int addonId = current.addonId;
|
int addonId = current.addonId;
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/files").arg(addonId), response));
|
netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/files").arg(addonId), response));
|
||||||
|
|
||||||
@ -170,10 +170,7 @@ void FlamePage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
|||||||
}
|
}
|
||||||
suggestCurrent();
|
suggestCurrent();
|
||||||
});
|
});
|
||||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
|
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); });
|
||||||
netJob->deleteLater();
|
|
||||||
delete response;
|
|
||||||
});
|
|
||||||
netJob->start();
|
netJob->start();
|
||||||
} else {
|
} else {
|
||||||
for (auto version : current.versions) {
|
for (auto version : current.versions) {
|
||||||
|
@ -38,11 +38,11 @@
|
|||||||
#include "net/HttpMetaCache.h"
|
#include "net/HttpMetaCache.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
#include "StringUtils.h"
|
|
||||||
#include <Version.h>
|
#include <Version.h>
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#include <QtMath>
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
|
#include <QtMath>
|
||||||
|
|
||||||
#include <RWStorage.h>
|
#include <RWStorage.h>
|
||||||
|
|
||||||
@ -50,33 +50,33 @@
|
|||||||
|
|
||||||
namespace LegacyFTB {
|
namespace LegacyFTB {
|
||||||
|
|
||||||
FilterModel::FilterModel(QObject *parent) : QSortFilterProxyModel(parent)
|
FilterModel::FilterModel(QObject* parent) : QSortFilterProxyModel(parent)
|
||||||
{
|
{
|
||||||
currentSorting = Sorting::ByGameVersion;
|
currentSorting = Sorting::ByGameVersion;
|
||||||
sortings.insert(tr("Sort by Name"), Sorting::ByName);
|
sortings.insert(tr("Sort by Name"), Sorting::ByName);
|
||||||
sortings.insert(tr("Sort by Game Version"), Sorting::ByGameVersion);
|
sortings.insert(tr("Sort by Game Version"), Sorting::ByGameVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
bool FilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
|
||||||
{
|
{
|
||||||
Modpack leftPack = sourceModel()->data(left, Qt::UserRole).value<Modpack>();
|
Modpack leftPack = sourceModel()->data(left, Qt::UserRole).value<Modpack>();
|
||||||
Modpack rightPack = sourceModel()->data(right, Qt::UserRole).value<Modpack>();
|
Modpack rightPack = sourceModel()->data(right, Qt::UserRole).value<Modpack>();
|
||||||
|
|
||||||
if(currentSorting == Sorting::ByGameVersion) {
|
if (currentSorting == Sorting::ByGameVersion) {
|
||||||
Version lv(leftPack.mcVersion);
|
Version lv(leftPack.mcVersion);
|
||||||
Version rv(rightPack.mcVersion);
|
Version rv(rightPack.mcVersion);
|
||||||
return lv < rv;
|
return lv < rv;
|
||||||
|
|
||||||
} else if(currentSorting == Sorting::ByName) {
|
} else if (currentSorting == Sorting::ByName) {
|
||||||
return StringUtils::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
return StringUtils::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//UHM, some inavlid value set?!
|
// UHM, some inavlid value set?!
|
||||||
qWarning() << "Invalid sorting set!";
|
qWarning() << "Invalid sorting set!";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
bool FilterModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -102,18 +102,13 @@ FilterModel::Sorting FilterModel::getCurrentSorting()
|
|||||||
return currentSorting;
|
return currentSorting;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListModel::ListModel(QObject *parent) : QAbstractListModel(parent)
|
ListModel::ListModel(QObject* parent) : QAbstractListModel(parent) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
ListModel::~ListModel()
|
ListModel::~ListModel() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ListModel::translatePackType(PackType type) const
|
QString ListModel::translatePackType(PackType type) const
|
||||||
{
|
{
|
||||||
switch(type)
|
switch (type) {
|
||||||
{
|
|
||||||
case PackType::Public:
|
case PackType::Public:
|
||||||
return tr("Public Modpack");
|
return tr("Public Modpack");
|
||||||
case PackType::ThirdParty:
|
case PackType::ThirdParty:
|
||||||
@ -125,67 +120,51 @@ QString ListModel::translatePackType(PackType type) const
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ListModel::rowCount(const QModelIndex &parent) const
|
int ListModel::rowCount(const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : modpacks.size();
|
return parent.isValid() ? 0 : modpacks.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ListModel::columnCount(const QModelIndex &parent) const
|
int ListModel::columnCount(const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : 1;
|
return parent.isValid() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant ListModel::data(const QModelIndex &index, int role) const
|
QVariant ListModel::data(const QModelIndex& index, int role) const
|
||||||
{
|
{
|
||||||
int pos = index.row();
|
int pos = index.row();
|
||||||
if(pos >= modpacks.size() || pos < 0 || !index.isValid())
|
if (pos >= modpacks.size() || pos < 0 || !index.isValid()) {
|
||||||
{
|
|
||||||
return QString("INVALID INDEX %1").arg(pos);
|
return QString("INVALID INDEX %1").arg(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
Modpack pack = modpacks.at(pos);
|
Modpack pack = modpacks.at(pos);
|
||||||
if(role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole) {
|
||||||
{
|
|
||||||
return pack.name + "\n" + translatePackType(pack.type);
|
return pack.name + "\n" + translatePackType(pack.type);
|
||||||
}
|
} else if (role == Qt::ToolTipRole) {
|
||||||
else if (role == Qt::ToolTipRole)
|
if (pack.description.length() > 100) {
|
||||||
{
|
// some magic to prevent to long tooltips and replace html linebreaks
|
||||||
if(pack.description.length() > 100)
|
|
||||||
{
|
|
||||||
//some magic to prevent to long tooltips and replace html linebreaks
|
|
||||||
QString edit = pack.description.left(97);
|
QString edit = pack.description.left(97);
|
||||||
edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
|
edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
|
||||||
return edit;
|
return edit;
|
||||||
|
|
||||||
}
|
}
|
||||||
return pack.description;
|
return pack.description;
|
||||||
}
|
} else if (role == Qt::DecorationRole) {
|
||||||
else if(role == Qt::DecorationRole)
|
if (m_logoMap.contains(pack.logo)) {
|
||||||
{
|
|
||||||
if(m_logoMap.contains(pack.logo))
|
|
||||||
{
|
|
||||||
return (m_logoMap.value(pack.logo));
|
return (m_logoMap.value(pack.logo));
|
||||||
}
|
}
|
||||||
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
||||||
((ListModel *)this)->requestLogo(pack.logo);
|
((ListModel*)this)->requestLogo(pack.logo);
|
||||||
return icon;
|
return icon;
|
||||||
}
|
} else if (role == Qt::ForegroundRole) {
|
||||||
else if(role == Qt::ForegroundRole)
|
if (pack.broken) {
|
||||||
{
|
// FIXME: Hardcoded color
|
||||||
if(pack.broken)
|
|
||||||
{
|
|
||||||
//FIXME: Hardcoded color
|
|
||||||
return QColor(255, 0, 50);
|
return QColor(255, 0, 50);
|
||||||
}
|
} else if (pack.bugged) {
|
||||||
else if(pack.bugged)
|
// FIXME: Hardcoded color
|
||||||
{
|
// bugged pack, currently only indicates bugged xml
|
||||||
//FIXME: Hardcoded color
|
|
||||||
//bugged pack, currently only indicates bugged xml
|
|
||||||
return QColor(244, 229, 66);
|
return QColor(244, 229, 66);
|
||||||
}
|
}
|
||||||
}
|
} else if (role == Qt::UserRole) {
|
||||||
else if(role == Qt::UserRole)
|
|
||||||
{
|
|
||||||
QVariant v;
|
QVariant v;
|
||||||
v.setValue(pack);
|
v.setValue(pack);
|
||||||
return v;
|
return v;
|
||||||
@ -222,8 +201,7 @@ Modpack ListModel::at(int row)
|
|||||||
|
|
||||||
void ListModel::remove(int row)
|
void ListModel::remove(int row)
|
||||||
{
|
{
|
||||||
if(row < 0 || row >= modpacks.size())
|
if (row < 0 || row >= modpacks.size()) {
|
||||||
{
|
|
||||||
qWarning() << "Attempt to remove FTB modpacks with invalid row" << row;
|
qWarning() << "Attempt to remove FTB modpacks with invalid row" << row;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -247,27 +225,25 @@ void ListModel::logoFailed(QString logo)
|
|||||||
|
|
||||||
void ListModel::requestLogo(QString file)
|
void ListModel::requestLogo(QString file)
|
||||||
{
|
{
|
||||||
if(m_loadingLogos.contains(file) || m_failedLogos.contains(file))
|
if (m_loadingLogos.contains(file) || m_failedLogos.contains(file)) {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
|
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
|
||||||
NetJob *job = new NetJob(QString("FTB Icon Download for %1").arg(file), APPLICATION->network());
|
NetJob* job = new NetJob(QString("FTB Icon Download for %1").arg(file), APPLICATION->network());
|
||||||
job->addNetAction(Net::Download::makeCached(QUrl(QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/%1").arg(file)), entry));
|
job->addNetAction(Net::Download::makeCached(QUrl(QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/%1").arg(file)), entry));
|
||||||
|
|
||||||
auto fullPath = entry->getFullPath();
|
auto fullPath = entry->getFullPath();
|
||||||
QObject::connect(job, &NetJob::finished, this, [this, file, fullPath]
|
QObject::connect(job, &NetJob::finished, this, [this, file, fullPath, job] {
|
||||||
{
|
job->deleteLater();
|
||||||
emit logoLoaded(file, QIcon(fullPath));
|
emit logoLoaded(file, QIcon(fullPath));
|
||||||
if(waitingCallbacks.contains(file))
|
if (waitingCallbacks.contains(file)) {
|
||||||
{
|
|
||||||
waitingCallbacks.value(file)(fullPath);
|
waitingCallbacks.value(file)(fullPath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(job, &NetJob::failed, this, [this, file]
|
QObject::connect(job, &NetJob::failed, this, [this, file, job] {
|
||||||
{
|
job->deleteLater();
|
||||||
emit logoFailed(file);
|
emit logoFailed(file);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -276,21 +252,18 @@ void ListModel::requestLogo(QString file)
|
|||||||
m_loadingLogos.append(file);
|
m_loadingLogos.append(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListModel::getLogo(const QString &logo, LogoCallback callback)
|
void ListModel::getLogo(const QString& logo, LogoCallback callback)
|
||||||
{
|
{
|
||||||
if(m_logoMap.contains(logo))
|
if (m_logoMap.contains(logo)) {
|
||||||
{
|
|
||||||
callback(APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
|
callback(APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
requestLogo(logo);
|
requestLogo(logo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::ItemFlags ListModel::flags(const QModelIndex &index) const
|
Qt::ItemFlags ListModel::flags(const QModelIndex& index) const
|
||||||
{
|
{
|
||||||
return QAbstractListModel::flags(index);
|
return QAbstractListModel::flags(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace LegacyFTB
|
||||||
|
@ -131,27 +131,27 @@ void ModpackListModel::performPaginatedSearch()
|
|||||||
// TODO: Move to standalone API
|
// TODO: Move to standalone API
|
||||||
auto netJob = makeShared<NetJob>("Modrinth::SearchModpack", APPLICATION->network());
|
auto netJob = makeShared<NetJob>("Modrinth::SearchModpack", APPLICATION->network());
|
||||||
auto searchAllUrl = QString(BuildConfig.MODRINTH_PROD_URL +
|
auto searchAllUrl = QString(BuildConfig.MODRINTH_PROD_URL +
|
||||||
"/search?"
|
"/search?"
|
||||||
"offset=%1&"
|
"offset=%1&"
|
||||||
"limit=%2&"
|
"limit=%2&"
|
||||||
"query=%3&"
|
"query=%3&"
|
||||||
"index=%4&"
|
"index=%4&"
|
||||||
"facets=[[\"project_type:modpack\"]]")
|
"facets=[[\"project_type:modpack\"]]")
|
||||||
.arg(nextSearchOffset)
|
.arg(nextSearchOffset)
|
||||||
.arg(m_modpacks_per_page)
|
.arg(m_modpacks_per_page)
|
||||||
.arg(currentSearchTerm)
|
.arg(currentSearchTerm)
|
||||||
.arg(currentSort);
|
.arg(currentSort);
|
||||||
|
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), &m_all_response));
|
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), m_all_response));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, [this] {
|
QObject::connect(netJob.get(), &NetJob::succeeded, this, [this] {
|
||||||
QJsonParseError parse_error_all{};
|
QJsonParseError parse_error_all{};
|
||||||
|
|
||||||
QJsonDocument doc_all = QJsonDocument::fromJson(m_all_response, &parse_error_all);
|
QJsonDocument doc_all = QJsonDocument::fromJson(*m_all_response, &parse_error_all);
|
||||||
if (parse_error_all.error != QJsonParseError::NoError) {
|
if (parse_error_all.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Error while parsing JSON response from " << debugName() << " at " << parse_error_all.offset
|
qWarning() << "Error while parsing JSON response from " << debugName() << " at " << parse_error_all.offset
|
||||||
<< " reason: " << parse_error_all.errorString();
|
<< " reason: " << parse_error_all.errorString();
|
||||||
qWarning() << m_all_response;
|
qWarning() << *m_all_response;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,9 +110,9 @@ class ModpackListModel : public QAbstractListModel {
|
|||||||
|
|
||||||
NetJob::Ptr jobPtr;
|
NetJob::Ptr jobPtr;
|
||||||
|
|
||||||
QByteArray m_all_response;
|
std::shared_ptr<QByteArray> m_all_response = std::make_shared<QByteArray>();
|
||||||
QByteArray m_specific_response;
|
QByteArray m_specific_response;
|
||||||
|
|
||||||
int m_modpacks_per_page = 20;
|
int m_modpacks_per_page = 20;
|
||||||
};
|
};
|
||||||
} // namespace ModPlatform
|
} // namespace Modrinth
|
||||||
|
@ -123,7 +123,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
|||||||
qDebug() << "Loading modrinth modpack information";
|
qDebug() << "Loading modrinth modpack information";
|
||||||
|
|
||||||
auto netJob = new NetJob(QString("Modrinth::PackInformation(%1)").arg(current.name), APPLICATION->network());
|
auto netJob = new NetJob(QString("Modrinth::PackInformation(%1)").arg(current.name), APPLICATION->network());
|
||||||
auto response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
QString id = current.id;
|
QString id = current.id;
|
||||||
|
|
||||||
@ -162,10 +162,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
|||||||
|
|
||||||
suggestCurrent();
|
suggestCurrent();
|
||||||
});
|
});
|
||||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
|
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); });
|
||||||
netJob->deleteLater();
|
|
||||||
delete response;
|
|
||||||
});
|
|
||||||
netJob->start();
|
netJob->start();
|
||||||
} else
|
} else
|
||||||
updateUI();
|
updateUI();
|
||||||
@ -174,7 +171,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
|||||||
qDebug() << "Loading modrinth modpack versions";
|
qDebug() << "Loading modrinth modpack versions";
|
||||||
|
|
||||||
auto netJob = new NetJob(QString("Modrinth::PackVersions(%1)").arg(current.name), APPLICATION->network());
|
auto netJob = new NetJob(QString("Modrinth::PackVersions(%1)").arg(current.name), APPLICATION->network());
|
||||||
auto response = new QByteArray();
|
auto response = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
QString id = current.id;
|
QString id = current.id;
|
||||||
|
|
||||||
@ -217,10 +214,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
|||||||
|
|
||||||
suggestCurrent();
|
suggestCurrent();
|
||||||
});
|
});
|
||||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
|
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); });
|
||||||
netJob->deleteLater();
|
|
||||||
delete response;
|
|
||||||
});
|
|
||||||
netJob->start();
|
netJob->start();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -260,10 +254,8 @@ void ModrinthPage::updateUI()
|
|||||||
text += donates.join(", ");
|
text += donates.join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!current.extra.issuesUrl.isEmpty()
|
if (!current.extra.issuesUrl.isEmpty() || !current.extra.sourceUrl.isEmpty() || !current.extra.wikiUrl.isEmpty() ||
|
||||||
|| !current.extra.sourceUrl.isEmpty()
|
!current.extra.discordUrl.isEmpty()) {
|
||||||
|| !current.extra.wikiUrl.isEmpty()
|
|
||||||
|| !current.extra.discordUrl.isEmpty()) {
|
|
||||||
text += "<br><br>" + tr("External links:") + "<br>";
|
text += "<br><br>" + tr("External links:") + "<br>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,39 +40,28 @@
|
|||||||
|
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
|
||||||
Technic::ListModel::ListModel(QObject *parent) : QAbstractListModel(parent)
|
Technic::ListModel::ListModel(QObject* parent) : QAbstractListModel(parent) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Technic::ListModel::~ListModel()
|
Technic::ListModel::~ListModel() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant Technic::ListModel::data(const QModelIndex& index, int role) const
|
QVariant Technic::ListModel::data(const QModelIndex& index, int role) const
|
||||||
{
|
{
|
||||||
int pos = index.row();
|
int pos = index.row();
|
||||||
if(pos >= modpacks.size() || pos < 0 || !index.isValid())
|
if (pos >= modpacks.size() || pos < 0 || !index.isValid()) {
|
||||||
{
|
|
||||||
return QString("INVALID INDEX %1").arg(pos);
|
return QString("INVALID INDEX %1").arg(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
Modpack pack = modpacks.at(pos);
|
Modpack pack = modpacks.at(pos);
|
||||||
if(role == Qt::DisplayRole)
|
if (role == Qt::DisplayRole) {
|
||||||
{
|
|
||||||
return pack.name;
|
return pack.name;
|
||||||
}
|
} else if (role == Qt::DecorationRole) {
|
||||||
else if(role == Qt::DecorationRole)
|
if (m_logoMap.contains(pack.logoName)) {
|
||||||
{
|
|
||||||
if(m_logoMap.contains(pack.logoName))
|
|
||||||
{
|
|
||||||
return (m_logoMap.value(pack.logoName));
|
return (m_logoMap.value(pack.logoName));
|
||||||
}
|
}
|
||||||
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
||||||
((ListModel *)this)->requestLogo(pack.logoName, pack.logoUrl);
|
((ListModel*)this)->requestLogo(pack.logoName, pack.logoUrl);
|
||||||
return icon;
|
return icon;
|
||||||
}
|
} else if (role == Qt::UserRole) {
|
||||||
else if(role == Qt::UserRole)
|
|
||||||
{
|
|
||||||
QVariant v;
|
QVariant v;
|
||||||
v.setValue(pack);
|
v.setValue(pack);
|
||||||
return v;
|
return v;
|
||||||
@ -92,16 +81,15 @@ int Technic::ListModel::rowCount(const QModelIndex& parent) const
|
|||||||
|
|
||||||
void Technic::ListModel::searchWithTerm(const QString& term)
|
void Technic::ListModel::searchWithTerm(const QString& term)
|
||||||
{
|
{
|
||||||
if(currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull()) {
|
if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentSearchTerm = term;
|
currentSearchTerm = term;
|
||||||
if(jobPtr) {
|
if (jobPtr) {
|
||||||
jobPtr->abort();
|
jobPtr->abort();
|
||||||
searchState = ResetRequested;
|
searchState = ResetRequested;
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
modpacks.clear();
|
modpacks.clear();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
@ -115,26 +103,20 @@ void Technic::ListModel::performSearch()
|
|||||||
auto netJob = makeShared<NetJob>("Technic::Search", APPLICATION->network());
|
auto netJob = makeShared<NetJob>("Technic::Search", APPLICATION->network());
|
||||||
QString searchUrl = "";
|
QString searchUrl = "";
|
||||||
if (currentSearchTerm.isEmpty()) {
|
if (currentSearchTerm.isEmpty()) {
|
||||||
searchUrl = QString("%1trending?build=%2")
|
searchUrl = QString("%1trending?build=%2").arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD);
|
||||||
.arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD);
|
|
||||||
searchMode = List;
|
searchMode = List;
|
||||||
}
|
} else if (currentSearchTerm.startsWith("http://api.technicpack.net/modpack/")) {
|
||||||
else if (currentSearchTerm.startsWith("http://api.technicpack.net/modpack/")) {
|
searchUrl = QString("https://%1?build=%2").arg(currentSearchTerm.mid(7), BuildConfig.TECHNIC_API_BUILD);
|
||||||
searchUrl = QString("https://%1?build=%2")
|
|
||||||
.arg(currentSearchTerm.mid(7), BuildConfig.TECHNIC_API_BUILD);
|
|
||||||
searchMode = Single;
|
searchMode = Single;
|
||||||
}
|
} else if (currentSearchTerm.startsWith("https://api.technicpack.net/modpack/")) {
|
||||||
else if (currentSearchTerm.startsWith("https://api.technicpack.net/modpack/")) {
|
|
||||||
searchUrl = QString("%1?build=%2").arg(currentSearchTerm, BuildConfig.TECHNIC_API_BUILD);
|
searchUrl = QString("%1?build=%2").arg(currentSearchTerm, BuildConfig.TECHNIC_API_BUILD);
|
||||||
searchMode = Single;
|
searchMode = Single;
|
||||||
}
|
} else {
|
||||||
else {
|
searchUrl =
|
||||||
searchUrl = QString(
|
QString("%1search?build=%2&q=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD, currentSearchTerm);
|
||||||
"%1search?build=%2&q=%3"
|
|
||||||
).arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD, currentSearchTerm);
|
|
||||||
searchMode = List;
|
searchMode = List;
|
||||||
}
|
}
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
|
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
|
||||||
jobPtr = netJob;
|
jobPtr = netJob;
|
||||||
jobPtr->start();
|
jobPtr->start();
|
||||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, &ListModel::searchRequestFinished);
|
QObject::connect(netJob.get(), &NetJob::succeeded, this, &ListModel::searchRequestFinished);
|
||||||
@ -146,11 +128,11 @@ void Technic::ListModel::searchRequestFinished()
|
|||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
|
|
||||||
QJsonParseError parse_error;
|
QJsonParseError parse_error;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||||
if(parse_error.error != QJsonParseError::NoError)
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
{
|
qWarning() << "Error while parsing JSON response from Technic at " << parse_error.offset
|
||||||
qWarning() << "Error while parsing JSON response from Technic at " << parse_error.offset << " reason: " << parse_error.errorString();
|
<< " reason: " << parse_error.errorString();
|
||||||
qWarning() << response;
|
qWarning() << *response;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +143,7 @@ void Technic::ListModel::searchRequestFinished()
|
|||||||
switch (searchMode) {
|
switch (searchMode) {
|
||||||
case List: {
|
case List: {
|
||||||
auto objs = Json::requireArray(root, "modpacks");
|
auto objs = Json::requireArray(root, "modpacks");
|
||||||
for (auto technicPack: objs) {
|
for (auto technicPack : objs) {
|
||||||
Modpack pack;
|
Modpack pack;
|
||||||
auto technicPackObject = Json::requireObject(technicPack);
|
auto technicPackObject = Json::requireObject(technicPack);
|
||||||
pack.name = Json::requireString(technicPackObject, "name");
|
pack.name = Json::requireString(technicPackObject, "name");
|
||||||
@ -170,11 +152,10 @@ void Technic::ListModel::searchRequestFinished()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto rawURL = Json::ensureString(technicPackObject, "iconUrl", "null");
|
auto rawURL = Json::ensureString(technicPackObject, "iconUrl", "null");
|
||||||
if(rawURL == "null") {
|
if (rawURL == "null") {
|
||||||
pack.logoUrl = "null";
|
pack.logoUrl = "null";
|
||||||
pack.logoName = "null";
|
pack.logoName = "null";
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
pack.logoUrl = rawURL;
|
pack.logoUrl = rawURL;
|
||||||
pack.logoName = rawURL.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0);
|
pack.logoName = rawURL.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0);
|
||||||
}
|
}
|
||||||
@ -199,8 +180,7 @@ void Technic::ListModel::searchRequestFinished()
|
|||||||
|
|
||||||
pack.logoUrl = iconUrl;
|
pack.logoUrl = iconUrl;
|
||||||
pack.logoName = iconUrl.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0);
|
pack.logoName = iconUrl.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
pack.logoUrl = "null";
|
pack.logoUrl = "null";
|
||||||
pack.logoName = "null";
|
pack.logoName = "null";
|
||||||
}
|
}
|
||||||
@ -210,10 +190,8 @@ void Technic::ListModel::searchRequestFinished()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (const JSONValidationError& err) {
|
||||||
catch (const JSONValidationError &err)
|
qCritical() << "Couldn't parse technic search results:" << err.cause();
|
||||||
{
|
|
||||||
qCritical() << "Couldn't parse technic search results:" << err.cause() ;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
searchState = Finished;
|
searchState = Finished;
|
||||||
@ -229,12 +207,9 @@ void Technic::ListModel::searchRequestFinished()
|
|||||||
|
|
||||||
void Technic::ListModel::getLogo(const QString& logo, const QString& logoUrl, Technic::LogoCallback callback)
|
void Technic::ListModel::getLogo(const QString& logo, const QString& logoUrl, Technic::LogoCallback callback)
|
||||||
{
|
{
|
||||||
if(m_logoMap.contains(logo))
|
if (m_logoMap.contains(logo)) {
|
||||||
{
|
|
||||||
callback(APPLICATION->metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo))->getFullPath());
|
callback(APPLICATION->metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo))->getFullPath());
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
requestLogo(logo, logoUrl);
|
requestLogo(logo, logoUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,30 +218,24 @@ void Technic::ListModel::searchRequestFailed()
|
|||||||
{
|
{
|
||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
|
|
||||||
if(searchState == ResetRequested)
|
if (searchState == ResetRequested) {
|
||||||
{
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
modpacks.clear();
|
modpacks.clear();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
|
||||||
performSearch();
|
performSearch();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
searchState = Finished;
|
searchState = Finished;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Technic::ListModel::logoLoaded(QString logo, QString out)
|
void Technic::ListModel::logoLoaded(QString logo, QString out)
|
||||||
{
|
{
|
||||||
m_loadingLogos.removeAll(logo);
|
m_loadingLogos.removeAll(logo);
|
||||||
m_logoMap.insert(logo, QIcon(out));
|
m_logoMap.insert(logo, QIcon(out));
|
||||||
for(int i = 0; i < modpacks.size(); i++)
|
for (int i = 0; i < modpacks.size(); i++) {
|
||||||
{
|
if (modpacks[i].logoName == logo) {
|
||||||
if(modpacks[i].logoName == logo)
|
emit dataChanged(createIndex(i, 0), createIndex(i, 0), { Qt::DecorationRole });
|
||||||
{
|
|
||||||
emit dataChanged(createIndex(i, 0), createIndex(i, 0), {Qt::DecorationRole});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,24 +248,23 @@ void Technic::ListModel::logoFailed(QString logo)
|
|||||||
|
|
||||||
void Technic::ListModel::requestLogo(QString logo, QString url)
|
void Technic::ListModel::requestLogo(QString logo, QString url)
|
||||||
{
|
{
|
||||||
if(m_loadingLogos.contains(logo) || m_failedLogos.contains(logo) || logo == "null")
|
if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo) || logo == "null") {
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo));
|
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo));
|
||||||
NetJob *job = new NetJob(QString("Technic Icon Download %1").arg(logo), APPLICATION->network());
|
auto job = new NetJob(QString("Technic Icon Download %1").arg(logo), APPLICATION->network());
|
||||||
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
|
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
|
||||||
|
|
||||||
auto fullPath = entry->getFullPath();
|
auto fullPath = entry->getFullPath();
|
||||||
|
|
||||||
QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath]
|
QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] {
|
||||||
{
|
job->deleteLater();
|
||||||
logoLoaded(logo, fullPath);
|
logoLoaded(logo, fullPath);
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(job, &NetJob::failed, this, [this, logo]
|
QObject::connect(job, &NetJob::failed, this, [this, logo, job] {
|
||||||
{
|
job->deleteLater();
|
||||||
logoFailed(logo);
|
logoFailed(logo);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -44,33 +44,32 @@ namespace Technic {
|
|||||||
|
|
||||||
typedef std::function<void(QString)> LogoCallback;
|
typedef std::function<void(QString)> LogoCallback;
|
||||||
|
|
||||||
class ListModel : public QAbstractListModel
|
class ListModel : public QAbstractListModel {
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ListModel(QObject *parent);
|
ListModel(QObject* parent);
|
||||||
virtual ~ListModel();
|
virtual ~ListModel();
|
||||||
|
|
||||||
virtual QVariant data(const QModelIndex& index, int role) const;
|
virtual QVariant data(const QModelIndex& index, int role) const;
|
||||||
virtual int columnCount(const QModelIndex& parent) const;
|
virtual int columnCount(const QModelIndex& parent) const;
|
||||||
virtual int rowCount(const QModelIndex& parent) const;
|
virtual int rowCount(const QModelIndex& parent) const;
|
||||||
|
|
||||||
void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback);
|
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
|
||||||
void searchWithTerm(const QString & term);
|
void searchWithTerm(const QString& term);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void searchRequestFinished();
|
void searchRequestFinished();
|
||||||
void searchRequestFailed();
|
void searchRequestFailed();
|
||||||
|
|
||||||
void logoFailed(QString logo);
|
void logoFailed(QString logo);
|
||||||
void logoLoaded(QString logo, QString out);
|
void logoLoaded(QString logo, QString out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void performSearch();
|
void performSearch();
|
||||||
void requestLogo(QString logo, QString url);
|
void requestLogo(QString logo, QString url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<Modpack> modpacks;
|
QList<Modpack> modpacks;
|
||||||
QStringList m_failedLogos;
|
QStringList m_failedLogos;
|
||||||
QStringList m_loadingLogos;
|
QStringList m_loadingLogos;
|
||||||
@ -78,17 +77,13 @@ private:
|
|||||||
QMap<QString, LogoCallback> waitingCallbacks;
|
QMap<QString, LogoCallback> waitingCallbacks;
|
||||||
|
|
||||||
QString currentSearchTerm;
|
QString currentSearchTerm;
|
||||||
enum SearchState {
|
enum SearchState { None, ResetRequested, Finished } searchState = None;
|
||||||
None,
|
|
||||||
ResetRequested,
|
|
||||||
Finished
|
|
||||||
} searchState = None;
|
|
||||||
enum SearchMode {
|
enum SearchMode {
|
||||||
List,
|
List,
|
||||||
Single,
|
Single,
|
||||||
} searchMode = List;
|
} searchMode = List;
|
||||||
NetJob::Ptr jobPtr;
|
NetJob::Ptr jobPtr;
|
||||||
QByteArray response;
|
std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace Technic
|
||||||
|
@ -143,7 +143,7 @@ void TechnicPage::suggestCurrent()
|
|||||||
|
|
||||||
auto netJob = makeShared<NetJob>(QString("Technic::PackMeta(%1)").arg(current.name), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Technic::PackMeta(%1)").arg(current.name), APPLICATION->network());
|
||||||
QString slug = current.slug;
|
QString slug = current.slug;
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QString("%1modpack/%2?build=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, slug, BuildConfig.TECHNIC_API_BUILD), &response));
|
netJob->addNetAction(Net::Download::makeByteArray(QString("%1modpack/%2?build=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, slug, BuildConfig.TECHNIC_API_BUILD), response));
|
||||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, [this, slug]
|
QObject::connect(netJob.get(), &NetJob::succeeded, this, [this, slug]
|
||||||
{
|
{
|
||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
@ -154,7 +154,7 @@ void TechnicPage::suggestCurrent()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QJsonParseError parse_error {};
|
QJsonParseError parse_error {};
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||||
QJsonObject obj = doc.object();
|
QJsonObject obj = doc.object();
|
||||||
if(parse_error.error != QJsonParseError::NoError)
|
if(parse_error.error != QJsonParseError::NoError)
|
||||||
{
|
{
|
||||||
@ -249,7 +249,7 @@ void TechnicPage::metadataLoaded()
|
|||||||
|
|
||||||
auto netJob = makeShared<NetJob>(QString("Technic::SolderMeta(%1)").arg(current.name), APPLICATION->network());
|
auto netJob = makeShared<NetJob>(QString("Technic::SolderMeta(%1)").arg(current.name), APPLICATION->network());
|
||||||
auto url = QString("%1/modpack/%2").arg(current.url, current.slug);
|
auto url = QString("%1/modpack/%2").arg(current.url, current.slug);
|
||||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), &response));
|
netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), response));
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, &TechnicPage::onSolderLoaded);
|
QObject::connect(netJob.get(), &NetJob::succeeded, this, &TechnicPage::onSolderLoaded);
|
||||||
|
|
||||||
@ -291,11 +291,11 @@ void TechnicPage::onSolderLoaded() {
|
|||||||
|
|
||||||
current.versions.clear();
|
current.versions.clear();
|
||||||
|
|
||||||
QJsonParseError parse_error {};
|
QJsonParseError parse_error{};
|
||||||
auto doc = QJsonDocument::fromJson(response, &parse_error);
|
auto doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||||
if (parse_error.error != QJsonParseError::NoError) {
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Error while parsing JSON response from Solder at " << parse_error.offset << " reason: " << parse_error.errorString();
|
qWarning() << "Error while parsing JSON response from Solder at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||||
qWarning() << response;
|
qWarning() << *response;
|
||||||
fallback();
|
fallback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -304,8 +304,7 @@ void TechnicPage::onSolderLoaded() {
|
|||||||
TechnicSolder::Pack pack;
|
TechnicSolder::Pack pack;
|
||||||
try {
|
try {
|
||||||
TechnicSolder::loadPack(pack, obj);
|
TechnicSolder::loadPack(pack, obj);
|
||||||
}
|
} catch (const JSONValidationError& err) {
|
||||||
catch (const JSONValidationError& err) {
|
|
||||||
qCritical() << "Couldn't parse Solder pack metadata:" << err.cause();
|
qCritical() << "Couldn't parse Solder pack metadata:" << err.cause();
|
||||||
fallback();
|
fallback();
|
||||||
return;
|
return;
|
||||||
|
@ -104,5 +104,5 @@ private:
|
|||||||
QString selectedVersion;
|
QString selectedVersion;
|
||||||
|
|
||||||
NetJob::Ptr jobPtr;
|
NetJob::Ptr jobPtr;
|
||||||
QByteArray response;
|
std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user