From 9e63d9f34780c1758f1a45e0ac9fdfa0fa25ad05 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 11 Sep 2026 12:05:25 +0300 Subject: [PATCH 1/4] refactor(net): use expected in validator interface Signed-off-by: Trial97 --- launcher/meta/BaseEntity.cpp | 46 +++++++++++---------------- launcher/net/ByteArraySink.h | 27 +++++++--------- launcher/net/ChecksumValidator.h | 39 ++++++++--------------- launcher/net/DummySink.h | 2 +- launcher/net/FileSink.cpp | 54 ++++++++++++++++---------------- launcher/net/FileSink.h | 10 +++--- launcher/net/MetaCacheSink.cpp | 6 ++-- launcher/net/MetaCacheSink.h | 6 ++-- launcher/net/RPCSink.h | 37 +++++++++++----------- launcher/net/Sink.h | 46 +++++++++++++-------------- launcher/net/Validator.h | 15 +++++---- 11 files changed, 132 insertions(+), 156 deletions(-) diff --git a/launcher/meta/BaseEntity.cpp b/launcher/meta/BaseEntity.cpp index 65d905984..0df5047c9 100644 --- a/launcher/meta/BaseEntity.cpp +++ b/launcher/meta/BaseEntity.cpp @@ -14,6 +14,8 @@ */ #include "BaseEntity.h" +#include +#include #include "Exception.h" #include "FileSystem.h" @@ -26,55 +28,44 @@ #include "net/NetJob.h" #include "Application.h" -#include "settings/SettingsObject.h" #include "BuildConfig.h" +#include "settings/SettingsObject.h" #include "tasks/Task.h" -namespace Meta { +namespace { class ParsingValidator : public Net::Validator { public: /* con/des */ - ParsingValidator(BaseEntity* entity) : m_entity(entity) {}; - virtual ~ParsingValidator() = default; + explicit ParsingValidator(Meta::BaseEntity* entity) : m_entity(entity) {}; + ~ParsingValidator() override = default; public: /* methods */ - bool init(QNetworkRequest&) override - { - m_data.clear(); - return true; - } - bool write(QByteArray& data) override - { - this->m_data.append(data); - return true; - } - bool abort() override - { - m_data.clear(); - return true; - } - bool validate(QNetworkReply&) override + void init() override { m_data.clear(); } + void write(const QByteArray& data) override { this->m_data.append(data); } + void abort() override { m_data.clear(); } + Result validate() override { auto fname = m_entity->localFilename(); try { auto doc = Json::requireDocument(m_data, fname); auto obj = Json::requireObject(doc, fname); m_entity->parse(obj); - return true; + return {}; } catch (const Exception& e) { - qWarning() << "Unable to parse response:" << e.cause(); - return false; + return std::unexpected("Unable to parse response:" + e.cause()); } } private: /* data */ QByteArray m_data; - BaseEntity* m_entity; + Meta::BaseEntity* m_entity; }; +} // namespace +namespace Meta { QUrl BaseEntity::url() const { - auto s = APPLICATION->settings(); + auto* s = APPLICATION->settings(); QString metaOverride = s->get("MetaURLOverride").toString(); if (metaOverride.isEmpty()) { return QUrl(BuildConfig.META_URL).resolved(localFilename()); @@ -99,7 +90,7 @@ bool BaseEntity::isLoaded() const void BaseEntity::setSha256(QString sha256) { - m_sha256 = sha256; + m_sha256 = std::move(sha256); } BaseEntity::LoadStatus BaseEntity::status() const @@ -171,8 +162,9 @@ void BaseEntityLoadTask::executeTask() * The validator parses the file and loads it into the object. * If that fails, the file is not written to storage. */ - if (!m_entity->m_sha256.isEmpty()) + if (!m_entity->m_sha256.isEmpty()) { dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Algorithm::Sha256, m_entity->m_sha256)); + } dl->addValidator(new ParsingValidator(m_entity)); m_task->addNetAction(dl); m_task->setAskRetry(false); diff --git a/launcher/net/ByteArraySink.h b/launcher/net/ByteArraySink.h index fcb29c67a..4654a064c 100644 --- a/launcher/net/ByteArraySink.h +++ b/launcher/net/ByteArraySink.h @@ -48,39 +48,34 @@ class ByteArraySink : public Sink { ~ByteArraySink() override = default; public: - auto init(QNetworkRequest& request) -> Task::State override + auto init(QNetworkRequest& /*request*/) -> Task::State override { m_output.clear(); - if (initAllValidators(request)) { - return Task::State::Running; - } - m_fail_reason = "Failed to initialize validators"; - return Task::State::Failed; + initAllValidators(); + return Task::State::Running; }; - auto write(QByteArray& data) -> Task::State override + auto write(const QByteArray& data) -> Task::State override { m_output.append(data); - if (writeAllValidators(data)) { - return Task::State::Running; - } - m_fail_reason = "Failed to write validators"; - return Task::State::Failed; + writeAllValidators(data); + return Task::State::Running; } auto abort() -> Task::State override { failAllValidators(); - m_fail_reason = "Aborted"; + m_failReason = "Aborted"; return Task::State::Failed; } - auto finalize(QNetworkReply& reply) -> Task::State override + auto finalize(QNetworkReply& /*reply*/) -> Task::State override { - if (finalizeAllValidators(reply)) { + auto result = finalizeAllValidators(); + if (result) { return Task::State::Succeeded; } - m_fail_reason = "Failed to finalize validators"; + m_failReason = result.error(); return Task::State::Failed; } diff --git a/launcher/net/ChecksumValidator.h b/launcher/net/ChecksumValidator.h index c7906cc13..cac343f3c 100644 --- a/launcher/net/ChecksumValidator.h +++ b/launcher/net/ChecksumValidator.h @@ -38,48 +38,35 @@ #include "Validator.h" #include +#include +#include namespace Net { class ChecksumValidator : public Validator { public: - ChecksumValidator(QCryptographicHash::Algorithm algorithm, QString expectedHex) + ChecksumValidator(QCryptographicHash::Algorithm algorithm, const QString& expectedHex) : Net::ChecksumValidator(algorithm, QByteArray::fromHex(expectedHex.toLatin1())) {} - ChecksumValidator(QCryptographicHash::Algorithm algorithm, QByteArray expected = QByteArray()) - : m_checksum(algorithm), m_expected(expected) {}; - virtual ~ChecksumValidator() = default; + explicit ChecksumValidator(QCryptographicHash::Algorithm algorithm, QByteArray expected = QByteArray()) + : m_checksum(algorithm), m_expected(std::move(expected)) {}; + ~ChecksumValidator() override = default; public: - auto init(QNetworkRequest&) -> bool override - { - m_checksum.reset(); - return true; - } + void init() override { m_checksum.reset(); } + void write(const QByteArray& data) override { m_checksum.addData(data); } + void abort() override { m_checksum.reset(); } - auto write(QByteArray& data) -> bool override - { - m_checksum.addData(data); - return true; - } - - auto abort() -> bool override - { - m_checksum.reset(); - return true; - } - - auto validate(QNetworkReply& reply) -> bool override + Result validate() override { if (!m_expected.isEmpty() && m_expected != hash()) { - qWarning() << "Checksum mismatch for URL:" << reply.url().toString() << "expected:" << m_expected << "got:" << hash(); - return false; + return std::unexpected(QString("Checksum mismatch: expected %1, got %2").arg(m_expected.toHex(), hash().toHex())); } - return true; + return {}; } auto hash() -> QByteArray { return m_checksum.result(); } - void setExpected(QByteArray expected) { m_expected = expected; } + void setExpected(QByteArray expected) { m_expected = std::move(expected); } private: QCryptographicHash m_checksum; diff --git a/launcher/net/DummySink.h b/launcher/net/DummySink.h index 1f51f9b04..3ea255193 100644 --- a/launcher/net/DummySink.h +++ b/launcher/net/DummySink.h @@ -26,7 +26,7 @@ class DummySink : public Sink { explicit DummySink() = default; ~DummySink() override = default; auto init(QNetworkRequest& /*request*/) -> Task::State override { return Task::State::Running; } - auto write(QByteArray& /*data*/) -> Task::State override { return Task::State::Succeeded; } + auto write(const QByteArray& /*data*/) -> Task::State override { return Task::State::Succeeded; } auto abort() -> Task::State override { return Task::State::AbortedByUser; } auto finalize(QNetworkReply& /*reply*/) -> Task::State override { return Task::State::Succeeded; } auto hasLocalData() -> bool override { return false; } diff --git a/launcher/net/FileSink.cpp b/launcher/net/FileSink.cpp index 47838f62c..59c208a49 100644 --- a/launcher/net/FileSink.cpp +++ b/launcher/net/FileSink.cpp @@ -51,38 +51,37 @@ Task::State FileSink::init(QNetworkRequest& request) // create a new save file and open it for writing if (!FS::ensureFilePathExists(m_filename)) { qCCritical(taskNetLogC) << "Could not create folder for " + m_filename; - m_fail_reason = "Could not create folder"; + m_failReason = "Could not create folder"; return Task::State::Failed; } m_wroteAnyData = false; - m_output_file.reset(new PSaveFile(m_filename)); - if (!m_output_file->open(QIODevice::WriteOnly)) { - const auto error = QString("Could not open %1 for writing: %2").arg(m_filename).arg(m_output_file->errorString()); + m_outputFile.reset(new PSaveFile(m_filename)); + if (!m_outputFile->open(QIODevice::WriteOnly)) { + const auto error = QString("Could not open %1 for writing: %2").arg(m_filename).arg(m_outputFile->errorString()); qCCritical(taskNetLogC) << error; - m_fail_reason = error; + m_failReason = error; return Task::State::Failed; } - if (initAllValidators(request)) - return Task::State::Running; - m_fail_reason = "Failed to initialize validators"; - return Task::State::Failed; + initAllValidators(); + return Task::State::Running; } -Task::State FileSink::write(QByteArray& data) +Task::State FileSink::write(const QByteArray& data) { - if (!writeAllValidators(data) || m_output_file->write(data) != data.size()) { + writeAllValidators(data); + if (m_outputFile->write(data) != data.size()) { QString error = QString("Failed writing into %1: %2").arg(m_filename); - if (m_output_file->error() == QFileDevice::NoError) { + if (m_outputFile->error() == QFileDevice::NoError) { error = error.arg("Validators failed"); } else { - error = error.arg(m_output_file->errorString()); + error = error.arg(m_outputFile->errorString()); } qCCritical(taskNetLogC) << error; - m_fail_reason = error; - m_output_file->cancelWriting(); - m_output_file.reset(); + m_failReason = error; + m_outputFile->cancelWriting(); + m_outputFile.reset(); m_wroteAnyData = false; return Task::State::Failed; } @@ -93,8 +92,8 @@ Task::State FileSink::write(QByteArray& data) Task::State FileSink::abort() { - if (m_output_file) { - m_output_file->cancelWriting(); + if (m_outputFile) { + m_outputFile->cancelWriting(); } failAllValidators(); return Task::State::Failed; @@ -116,33 +115,34 @@ Task::State FileSink::finalize(QNetworkReply& reply) if (gotFile || m_wroteAnyData) { // ask validators for data consistency // we only do this for actual downloads, not 'your data is still the same' cache hits - if (!finalizeAllValidators(reply)) { - m_fail_reason = "Failed to finalize validators"; + auto result = finalizeAllValidators(); + if (!result) { + m_failReason = result.error(); return Task::State::Failed; } // nothing went wrong... - if (!m_output_file->commit()) { - const auto error = QString("Failed to commit changes to %1: %2").arg(m_filename).arg(m_output_file->errorString()); + if (!m_outputFile->commit()) { + const auto error = QString("Failed to commit changes to %1: %2").arg(m_filename).arg(m_outputFile->errorString()); qCCritical(taskNetLogC) << error; - m_fail_reason = error; - m_output_file->cancelWriting(); + m_failReason = error; + m_outputFile->cancelWriting(); return Task::State::Failed; } } // then get rid of the save file - m_output_file.reset(); + m_outputFile.reset(); return finalizeCache(reply); } -Task::State FileSink::initCache(QNetworkRequest&) +Task::State FileSink::initCache(QNetworkRequest& /*unused*/) { return Task::State::Running; } -Task::State FileSink::finalizeCache(QNetworkReply&) +Task::State FileSink::finalizeCache(QNetworkReply& /*unused*/) { return Task::State::Succeeded; } diff --git a/launcher/net/FileSink.h b/launcher/net/FileSink.h index 67c25361c..c20d71144 100644 --- a/launcher/net/FileSink.h +++ b/launcher/net/FileSink.h @@ -38,15 +38,17 @@ #include "PSaveFile.h" #include "Sink.h" +#include + namespace Net { class FileSink : public Sink { public: - FileSink(QString filename) : m_filename(filename) {}; - virtual ~FileSink() = default; + explicit FileSink(QString filename) : m_filename(std::move(filename)) {}; + ~FileSink() override = default; public: auto init(QNetworkRequest& request) -> Task::State override; - auto write(QByteArray& data) -> Task::State override; + auto write(const QByteArray& data) -> Task::State override; auto abort() -> Task::State override; auto finalize(QNetworkReply& reply) -> Task::State override; @@ -59,6 +61,6 @@ class FileSink : public Sink { protected: QString m_filename; bool m_wroteAnyData = false; - std::unique_ptr m_output_file; + std::unique_ptr m_outputFile; }; } // namespace Net diff --git a/launcher/net/MetaCacheSink.cpp b/launcher/net/MetaCacheSink.cpp index 8896f10e3..e84c9406b 100644 --- a/launcher/net/MetaCacheSink.cpp +++ b/launcher/net/MetaCacheSink.cpp @@ -48,8 +48,8 @@ namespace Net { */ #define MAX_TIME_TO_EXPIRE 1 * 7 * 24 * 60 * 60 -MetaCacheSink::MetaCacheSink(MetaEntryPtr entry, ChecksumValidator* md5sum, bool is_eternal) - : Net::FileSink(entry->getFullPath()), m_entry(entry), m_md5Node(md5sum), m_is_eternal(is_eternal) +MetaCacheSink::MetaCacheSink(MetaEntryPtr entry, ChecksumValidator* md5sum, bool isEternal) + : Net::FileSink(entry->getFullPath()), m_entry(entry), m_md5Node(md5sum), m_isEternal(isEternal) { addValidator(md5sum); } @@ -91,7 +91,7 @@ Task::State MetaCacheSink::finalizeCache(QNetworkReply& reply) m_entry->setLocalChangedTimestamp(output_file_info.lastModified().toUTC().toMSecsSinceEpoch()); { // Cache lifetime - if (m_is_eternal) { + if (m_isEternal) { qCDebug(taskMetaCacheLogC) << "Adding eternal cache entry:" << m_entry->getFullPath(); m_entry->makeEternal(true); } else if (reply.hasRawHeader("Cache-Control")) { diff --git a/launcher/net/MetaCacheSink.h b/launcher/net/MetaCacheSink.h index f9f7d2337..24c078c2e 100644 --- a/launcher/net/MetaCacheSink.h +++ b/launcher/net/MetaCacheSink.h @@ -42,8 +42,8 @@ namespace Net { class MetaCacheSink : public FileSink { public: - MetaCacheSink(MetaEntryPtr entry, ChecksumValidator* md5sum, bool is_eternal = false); - virtual ~MetaCacheSink() = default; + MetaCacheSink(MetaEntryPtr entry, ChecksumValidator* md5sum, bool isEternal = false); + ~MetaCacheSink() override = default; auto hasLocalData() -> bool override; @@ -54,6 +54,6 @@ class MetaCacheSink : public FileSink { private: MetaEntryPtr m_entry; ChecksumValidator* m_md5Node; - bool m_is_eternal; + bool m_isEternal; }; } // namespace Net diff --git a/launcher/net/RPCSink.h b/launcher/net/RPCSink.h index e7d6d7f88..4ed70cddb 100644 --- a/launcher/net/RPCSink.h +++ b/launcher/net/RPCSink.h @@ -35,28 +35,29 @@ class Sink : public ByteArraySink { ~Sink() override = default; public: - auto finalize(QNetworkReply& reply) -> Task::State override + auto finalize(QNetworkReply& /*reply*/) -> Task::State override { - if (finalizeAllValidators(reply)) { - try { - auto result = m_parseFunc(m_output); - if (!result.has_value()) { - m_fail_reason = result.error(); - return Task::State::Failed; - } - m_result = *result; - } catch (const std::exception& e) { - m_fail_reason = QString::fromUtf8(e.what()); - return Task::State::Failed; - // ToDo: make this suppport QJsonException - } catch (...) { - m_fail_reason = QObject::tr("Unknown error while parsing RPC response"); + auto result = finalizeAllValidators(); + if (!result) { + m_failReason = result.error(); + return Task::State::Failed; + } + try { + auto result = m_parseFunc(m_output); + if (!result.has_value()) { + m_failReason = result.error(); return Task::State::Failed; } - return Task::State::Succeeded; + m_result = *result; + } catch (const std::exception& e) { + m_failReason = QString::fromUtf8(e.what()); + return Task::State::Failed; + // ToDo: make this suppport QJsonException + } catch (...) { + m_failReason = QObject::tr("Unknown error while parsing RPC response"); + return Task::State::Failed; } - m_fail_reason = "Failed to finalize validators"; - return Task::State::Failed; + return Task::State::Succeeded; } T* result() { return &m_result; } diff --git a/launcher/net/Sink.h b/launcher/net/Sink.h index 3f04cbd82..167504fa1 100644 --- a/launcher/net/Sink.h +++ b/launcher/net/Sink.h @@ -46,57 +46,53 @@ class Sink { public: virtual auto init(QNetworkRequest& request) -> Task::State = 0; - virtual auto write(QByteArray& data) -> Task::State = 0; + virtual auto write(const QByteArray& data) -> Task::State = 0; virtual auto abort() -> Task::State = 0; virtual auto finalize(QNetworkReply& reply) -> Task::State = 0; virtual auto hasLocalData() -> bool = 0; - QString failReason() const { return m_fail_reason; } + QString failReason() const { return m_failReason; } void addValidator(Validator* validator) { if (validator) { - validators.push_back(std::shared_ptr(validator)); + m_validators.push_back(std::shared_ptr(validator)); } } protected: - bool initAllValidators(QNetworkRequest& request) + void initAllValidators() { - for (auto& validator : validators) { - if (!validator->init(request)) - return false; + for (auto& validator : m_validators) { + validator->init(); } - return true; } - bool finalizeAllValidators(QNetworkReply& reply) + void writeAllValidators(const QByteArray& data) { - for (auto& validator : validators) { - if (!validator->validate(reply)) - return false; + for (auto& validator : m_validators) { + validator->write(data); } - return true; } - bool failAllValidators() + void failAllValidators() { - bool success = true; - for (auto& validator : validators) { - success &= validator->abort(); + for (auto& validator : m_validators) { + validator->abort(); } - return success; } - bool writeAllValidators(QByteArray& data) + Validator::Result finalizeAllValidators() { - for (auto& validator : validators) { - if (!validator->write(data)) - return false; + for (auto& validator : m_validators) { + auto result = validator->validate(); + if (!result) { + return result; + } } - return true; + return {}; } protected: - std::vector> validators; - QString m_fail_reason; + std::vector> m_validators; + QString m_failReason; }; } // namespace Net diff --git a/launcher/net/Validator.h b/launcher/net/Validator.h index 6d1945ee6..6778241fd 100644 --- a/launcher/net/Validator.h +++ b/launcher/net/Validator.h @@ -35,17 +35,20 @@ #pragma once #include +#include namespace Net { class Validator { public: /* con/des */ - Validator() {} - virtual ~Validator() {} + Validator() = default; + virtual ~Validator() = default; + using Error = QString; + using Result = std::expected; public: /* methods */ - virtual bool init(QNetworkRequest& request) = 0; - virtual bool write(QByteArray& data) = 0; - virtual bool abort() = 0; - virtual bool validate(QNetworkReply& reply) = 0; + virtual void init() = 0; + virtual void write(const QByteArray& data) = 0; + virtual void abort() = 0; + virtual Result validate() = 0; }; } // namespace Net From bb27d2e13f331885a05e14b3cc86f1606008a1ce Mon Sep 17 00:00:00 2001 From: Trial97 Date: Fri, 11 Sep 2026 14:16:14 +0300 Subject: [PATCH 2/4] refactor(net): use std::expected in sink interface Signed-off-by: Trial97 --- launcher/net/ByteArraySink.h | 25 ++++----------- launcher/net/DummySink.h | 8 ++--- launcher/net/FileSink.cpp | 41 ++++++++---------------- launcher/net/FileSink.h | 12 +++---- launcher/net/MetaCacheSink.cpp | 44 +++++++++++++------------- launcher/net/MetaCacheSink.h | 4 +-- launcher/net/RPCSink.h | 20 +++++------- launcher/net/Request.cpp | 57 ++++++++++++++++++---------------- launcher/net/Request.h | 6 ++-- launcher/net/Sink.h | 19 +++++++----- 10 files changed, 104 insertions(+), 132 deletions(-) diff --git a/launcher/net/ByteArraySink.h b/launcher/net/ByteArraySink.h index 4654a064c..8c458021d 100644 --- a/launcher/net/ByteArraySink.h +++ b/launcher/net/ByteArraySink.h @@ -48,36 +48,23 @@ class ByteArraySink : public Sink { ~ByteArraySink() override = default; public: - auto init(QNetworkRequest& /*request*/) -> Task::State override + InitResult init(QNetworkRequest& /*request*/) override { m_output.clear(); initAllValidators(); - return Task::State::Running; + return InitType::Ok; }; - auto write(const QByteArray& data) -> Task::State override + Result write(const QByteArray& data) override { m_output.append(data); writeAllValidators(data); - return Task::State::Running; + return {}; } - auto abort() -> Task::State override - { - failAllValidators(); - m_failReason = "Aborted"; - return Task::State::Failed; - } + void abort() override { failAllValidators(); } - auto finalize(QNetworkReply& /*reply*/) -> Task::State override - { - auto result = finalizeAllValidators(); - if (result) { - return Task::State::Succeeded; - } - m_failReason = result.error(); - return Task::State::Failed; - } + Result finalize(QNetworkReply& /*reply*/) override { return finalizeAllValidators(); } auto hasLocalData() -> bool override { return false; } diff --git a/launcher/net/DummySink.h b/launcher/net/DummySink.h index 3ea255193..76686b46f 100644 --- a/launcher/net/DummySink.h +++ b/launcher/net/DummySink.h @@ -25,10 +25,10 @@ class DummySink : public Sink { public: explicit DummySink() = default; ~DummySink() override = default; - auto init(QNetworkRequest& /*request*/) -> Task::State override { return Task::State::Running; } - auto write(const QByteArray& /*data*/) -> Task::State override { return Task::State::Succeeded; } - auto abort() -> Task::State override { return Task::State::AbortedByUser; } - auto finalize(QNetworkReply& /*reply*/) -> Task::State override { return Task::State::Succeeded; } + InitResult init(QNetworkRequest& /*request*/) override { return InitType::Ok; } + Result write(const QByteArray& /*data*/) override { return {}; } + Result finalize(QNetworkReply& /*reply*/) override { return {}; } + void abort() override {} auto hasLocalData() -> bool override { return false; } }; diff --git a/launcher/net/FileSink.cpp b/launcher/net/FileSink.cpp index 59c208a49..30e256223 100644 --- a/launcher/net/FileSink.cpp +++ b/launcher/net/FileSink.cpp @@ -34,6 +34,7 @@ */ #include "FileSink.h" +#include #include "FileSystem.h" @@ -41,18 +42,17 @@ namespace Net { -Task::State FileSink::init(QNetworkRequest& request) +auto FileSink::init(QNetworkRequest& request) -> InitResult { auto result = initCache(request); - if (result != Task::State::Running) { + if (!result || *result != InitType::Ok) { return result; } // create a new save file and open it for writing if (!FS::ensureFilePathExists(m_filename)) { qCCritical(taskNetLogC) << "Could not create folder for " + m_filename; - m_failReason = "Could not create folder"; - return Task::State::Failed; + return std::unexpected("Could not create folder"); } m_wroteAnyData = false; @@ -60,15 +60,14 @@ Task::State FileSink::init(QNetworkRequest& request) if (!m_outputFile->open(QIODevice::WriteOnly)) { const auto error = QString("Could not open %1 for writing: %2").arg(m_filename).arg(m_outputFile->errorString()); qCCritical(taskNetLogC) << error; - m_failReason = error; - return Task::State::Failed; + return std::unexpected(error); } initAllValidators(); - return Task::State::Running; + return InitType::Ok; } -Task::State FileSink::write(const QByteArray& data) +auto FileSink::write(const QByteArray& data) -> Result { writeAllValidators(data); if (m_outputFile->write(data) != data.size()) { @@ -79,27 +78,25 @@ Task::State FileSink::write(const QByteArray& data) error = error.arg(m_outputFile->errorString()); } qCCritical(taskNetLogC) << error; - m_failReason = error; m_outputFile->cancelWriting(); m_outputFile.reset(); m_wroteAnyData = false; - return Task::State::Failed; + return std::unexpected(error); } m_wroteAnyData = true; - return Task::State::Running; + return {}; } -Task::State FileSink::abort() +void FileSink::abort() { if (m_outputFile) { m_outputFile->cancelWriting(); } failAllValidators(); - return Task::State::Failed; } -Task::State FileSink::finalize(QNetworkReply& reply) +auto FileSink::finalize(QNetworkReply& reply) -> Result { bool gotFile = false; QVariant statusCodeV = reply.attribute(QNetworkRequest::HttpStatusCodeAttribute); @@ -117,17 +114,15 @@ Task::State FileSink::finalize(QNetworkReply& reply) // we only do this for actual downloads, not 'your data is still the same' cache hits auto result = finalizeAllValidators(); if (!result) { - m_failReason = result.error(); - return Task::State::Failed; + return result; } // nothing went wrong... if (!m_outputFile->commit()) { const auto error = QString("Failed to commit changes to %1: %2").arg(m_filename).arg(m_outputFile->errorString()); qCCritical(taskNetLogC) << error; - m_failReason = error; m_outputFile->cancelWriting(); - return Task::State::Failed; + return std::unexpected(error); } } @@ -137,16 +132,6 @@ Task::State FileSink::finalize(QNetworkReply& reply) return finalizeCache(reply); } -Task::State FileSink::initCache(QNetworkRequest& /*unused*/) -{ - return Task::State::Running; -} - -Task::State FileSink::finalizeCache(QNetworkReply& /*unused*/) -{ - return Task::State::Succeeded; -} - bool FileSink::hasLocalData() { QFileInfo info(m_filename); diff --git a/launcher/net/FileSink.h b/launcher/net/FileSink.h index c20d71144..17ad54579 100644 --- a/launcher/net/FileSink.h +++ b/launcher/net/FileSink.h @@ -47,16 +47,16 @@ class FileSink : public Sink { ~FileSink() override = default; public: - auto init(QNetworkRequest& request) -> Task::State override; - auto write(const QByteArray& data) -> Task::State override; - auto abort() -> Task::State override; - auto finalize(QNetworkReply& reply) -> Task::State override; + InitResult init(QNetworkRequest& request) override; + Result write(const QByteArray& data) override; + Result finalize(QNetworkReply& reply) override; + void abort() override; auto hasLocalData() -> bool override; protected: - virtual auto initCache(QNetworkRequest&) -> Task::State; - virtual auto finalizeCache(QNetworkReply& reply) -> Task::State; + virtual InitResult initCache(QNetworkRequest&) { return InitType::Ok; } + virtual Result finalizeCache(QNetworkReply& /*reply*/) { return {}; } protected: QString m_filename; diff --git a/launcher/net/MetaCacheSink.cpp b/launcher/net/MetaCacheSink.cpp index e84c9406b..1202d049e 100644 --- a/launcher/net/MetaCacheSink.cpp +++ b/launcher/net/MetaCacheSink.cpp @@ -46,7 +46,7 @@ namespace Net { /** Maximum time to hold a cache entry * = 1 week in seconds */ -#define MAX_TIME_TO_EXPIRE 1 * 7 * 24 * 60 * 60 +#define MAX_TIME_TO_EXPIRE (1 * 7 * 24 * 60 * 60) MetaCacheSink::MetaCacheSink(MetaEntryPtr entry, ChecksumValidator* md5sum, bool isEternal) : Net::FileSink(entry->getFullPath()), m_entry(entry), m_md5Node(md5sum), m_isEternal(isEternal) @@ -54,29 +54,29 @@ MetaCacheSink::MetaCacheSink(MetaEntryPtr entry, ChecksumValidator* md5sum, bool addValidator(md5sum); } -Task::State MetaCacheSink::initCache(QNetworkRequest& request) +auto MetaCacheSink::initCache(QNetworkRequest& request) -> InitResult { if (!m_entry->isStale()) { - return Task::State::Succeeded; + return InitType::CacheHit; } // check if file exists, if it does, use its information for the request QFile current(m_filename); if (current.exists() && current.size() != 0) { - if (m_entry->getRemoteChangedTimestamp().size()) { + if (!m_entry->getRemoteChangedTimestamp().isEmpty()) { request.setRawHeader(QString("If-Modified-Since").toLatin1(), m_entry->getRemoteChangedTimestamp().toLatin1()); } - if (m_entry->getETag().size()) { + if (!m_entry->getETag().isEmpty()) { request.setRawHeader(QString("If-None-Match").toLatin1(), m_entry->getETag().toLatin1()); } } - return Task::State::Running; + return InitType::Ok; } -Task::State MetaCacheSink::finalizeCache(QNetworkReply& reply) +auto MetaCacheSink::finalizeCache(QNetworkReply& reply) -> Result { - QFileInfo output_file_info(m_filename); + QFileInfo outputFileInfo(m_filename); if (m_wroteAnyData) { m_entry->setMD5Sum(m_md5Node->hash().toHex().constData()); @@ -88,36 +88,36 @@ Task::State MetaCacheSink::finalizeCache(QNetworkReply& reply) m_entry->setRemoteChangedTimestamp(reply.rawHeader("Last-Modified").constData()); } - m_entry->setLocalChangedTimestamp(output_file_info.lastModified().toUTC().toMSecsSinceEpoch()); + m_entry->setLocalChangedTimestamp(outputFileInfo.lastModified().toUTC().toMSecsSinceEpoch()); { // Cache lifetime if (m_isEternal) { qCDebug(taskMetaCacheLogC) << "Adding eternal cache entry:" << m_entry->getFullPath(); m_entry->makeEternal(true); } else if (reply.hasRawHeader("Cache-Control")) { - auto cache_control_header = reply.rawHeader("Cache-Control"); - qCDebug(taskMetaCacheLogC) << "Parsing 'Cache-Control' header with" << cache_control_header; + auto cacheControlHeader = reply.rawHeader("Cache-Control"); + qCDebug(taskMetaCacheLogC) << "Parsing 'Cache-Control' header with" << cacheControlHeader; static const QRegularExpression s_maxAgeExpr("max-age=([0-9]+)"); - qint64 max_age = s_maxAgeExpr.match(cache_control_header).captured(1).toLongLong(); - m_entry->setMaximumAge(max_age); + qint64 maxAge = s_maxAgeExpr.match(cacheControlHeader).captured(1).toLongLong(); + m_entry->setMaximumAge(maxAge); } else if (reply.hasRawHeader("Expires")) { - auto expires_header = reply.rawHeader("Expires"); - qCDebug(taskMetaCacheLogC) << "Parsing 'Expires' header with" << expires_header; + auto expiresHeader = reply.rawHeader("Expires"); + qCDebug(taskMetaCacheLogC) << "Parsing 'Expires' header with" << expiresHeader; - qint64 max_age = QDateTime::fromString(expires_header).toSecsSinceEpoch() - QDateTime::currentSecsSinceEpoch(); - m_entry->setMaximumAge(max_age); + qint64 maxAge = QDateTime::fromString(expiresHeader).toSecsSinceEpoch() - QDateTime::currentSecsSinceEpoch(); + m_entry->setMaximumAge(maxAge); } else { m_entry->setMaximumAge(MAX_TIME_TO_EXPIRE); } if (reply.hasRawHeader("Age")) { - auto age_header = reply.rawHeader("Age"); - qCDebug(taskMetaCacheLogC) << "Parsing 'Age' header with" << age_header; + auto ageHeader = reply.rawHeader("Age"); + qCDebug(taskMetaCacheLogC) << "Parsing 'Age' header with" << ageHeader; - qint64 current_age = age_header.toLongLong(); - m_entry->setCurrentAge(current_age); + qint64 currentAge = ageHeader.toLongLong(); + m_entry->setCurrentAge(currentAge); } else { m_entry->setCurrentAge(0); } @@ -126,7 +126,7 @@ Task::State MetaCacheSink::finalizeCache(QNetworkReply& reply) m_entry->setStale(false); APPLICATION->metacache()->updateEntry(m_entry); - return Task::State::Succeeded; + return {}; } bool MetaCacheSink::hasLocalData() diff --git a/launcher/net/MetaCacheSink.h b/launcher/net/MetaCacheSink.h index 24c078c2e..069baaaf2 100644 --- a/launcher/net/MetaCacheSink.h +++ b/launcher/net/MetaCacheSink.h @@ -48,8 +48,8 @@ class MetaCacheSink : public FileSink { auto hasLocalData() -> bool override; protected: - auto initCache(QNetworkRequest& request) -> Task::State override; - auto finalizeCache(QNetworkReply& reply) -> Task::State override; + InitResult initCache(QNetworkRequest& request) override; + Result finalizeCache(QNetworkReply& reply) override; private: MetaEntryPtr m_entry; diff --git a/launcher/net/RPCSink.h b/launcher/net/RPCSink.h index 4ed70cddb..6fc7736b0 100644 --- a/launcher/net/RPCSink.h +++ b/launcher/net/RPCSink.h @@ -35,29 +35,25 @@ class Sink : public ByteArraySink { ~Sink() override = default; public: - auto finalize(QNetworkReply& /*reply*/) -> Task::State override + Result finalize(QNetworkReply& /*reply*/) override { - auto result = finalizeAllValidators(); - if (!result) { - m_failReason = result.error(); - return Task::State::Failed; + auto validatorResult = finalizeAllValidators(); + if (!validatorResult) { + return validatorResult; } try { auto result = m_parseFunc(m_output); if (!result.has_value()) { - m_failReason = result.error(); - return Task::State::Failed; + return std::unexpected(result.error()); } m_result = *result; } catch (const std::exception& e) { - m_failReason = QString::fromUtf8(e.what()); - return Task::State::Failed; + return std::unexpected(QString::fromUtf8(e.what())); // ToDo: make this suppport QJsonException } catch (...) { - m_failReason = QObject::tr("Unknown error while parsing RPC response"); - return Task::State::Failed; + return std::unexpected(QObject::tr("Unknown error while parsing RPC response")); } - return Task::State::Succeeded; + return {}; } T* result() { return &m_result; } diff --git a/launcher/net/Request.cpp b/launcher/net/Request.cpp index cb569b165..b29596153 100644 --- a/launcher/net/Request.cpp +++ b/launcher/net/Request.cpp @@ -64,6 +64,7 @@ #include "net/ByteArraySink.h" #include "net/FileSink.h" #include "net/Logging.h" +#include "tasks/Task.h" #include "MMCTime.h" #include "StringUtils.h" @@ -139,24 +140,22 @@ void Request::executeTask() } QNetworkRequest request(m_url); - m_state = m_sink->init(request); - switch (m_state) { - case State::Succeeded: - qCDebug(m_logCat) << getUid().toString() << "Request cache hit" << m_url.toString(); - emit succeeded(); - emit finished(); - return; - case State::Running: + auto result = m_sink->init(request); + if (!result) { + m_state = Task::State::Failed; + m_failReason = result.error(); + emit failed(m_failReason); + emit finished(); + return; + } + switch (*result) { + case Sink::Ok: qCDebug(m_logCat) << getUid().toString() << "Running" << m_url.toString(); break; - case State::Inactive: - case State::Failed: - m_failReason = m_sink->failReason(); - emit failed(m_sink->failReason()); - emit finished(); - return; - case State::AbortedByUser: - emit aborted(); + case Sink::CacheHit: + m_state = Task::State::Succeeded; + qCDebug(m_logCat) << getUid().toString() << "Request cache hit" << m_url.toString(); + emit succeeded(); emit finished(); return; } @@ -404,24 +403,26 @@ void Request::downloadFinished() auto data = m_reply->readAll(); if (!data.isEmpty()) { qCDebug(m_logCat) << getUid().toString() << "Writing extra" << data.size() << "bytes"; - m_state = m_sink->write(data); - if (m_state != State::Succeeded) { + auto result = m_sink->write(data); + if (!result) { + m_state = Task::State::Failed; qCDebug(m_logCat) << getUid().toString() << "Request failed to write:" << m_url.toString(); m_sink->abort(); - m_failReason = m_sink->failReason(); - emit failed(m_sink->failReason()); + m_failReason = result.error(); + emit failed(m_failReason); emit finished(); return; } } // otherwise, finalize the whole graph - m_state = m_sink->finalize(*m_reply); - if (m_state != State::Succeeded) { + auto result = m_sink->finalize(*m_reply); + if (!result) { + m_state = Task::State::Failed; qCDebug(m_logCat) << getUid().toString() << "Request failed to finalize:" << m_url.toString(); m_sink->abort(); - m_failReason = m_sink->failReason(); - emit failed(m_sink->failReason()); + m_failReason = result.error(); + emit failed(m_failReason); emit finished(); return; } @@ -435,12 +436,14 @@ void Request::downloadReadyRead() { if (m_state == State::Running) { auto data = m_reply->readAll(); - m_state = m_sink->write(data); + auto result = m_sink->write(data); if (replyStatusCode() >= 400) { m_errorResponse.append(data); } - if (m_state == State::Failed) { - qCCritical(m_logCat) << getUid().toString() << "Failed to process response chunk:" << m_sink->failReason(); + if (!result) { + m_state = Task::State::Failed; + m_failReason = result.error(); + qCCritical(m_logCat) << getUid().toString() << "Failed to process response chunk:" << m_failReason; } // qDebug() << "Request" << m_url.toString() << "gained" << data.size() << "bytes"; } else { diff --git a/launcher/net/Request.h b/launcher/net/Request.h index 9bf4c9852..7ac194440 100644 --- a/launcher/net/Request.h +++ b/launcher/net/Request.h @@ -53,11 +53,9 @@ #include "EnumWrapper.h" #include "HeaderProxy.h" #include "HttpMetaCache.h" +#include "QObjectPtr.h" #include "Sink.h" #include "Validator.h" - -#include "QObjectPtr.h" - #include "tasks/Task.h" class QIODevice; @@ -195,7 +193,7 @@ class Request : public Task { int m_redirectCount = 0; HttpMethod m_httpMethod = HttpMethod::Get; - PostData m_postData{}; + PostData m_postData; }; } // namespace Net diff --git a/launcher/net/Sink.h b/launcher/net/Sink.h index 167504fa1..0c980d8f3 100644 --- a/launcher/net/Sink.h +++ b/launcher/net/Sink.h @@ -35,8 +35,8 @@ #pragma once +#include #include "Validator.h" -#include "tasks/Task.h" namespace Net { class Sink { @@ -44,16 +44,20 @@ class Sink { Sink() = default; virtual ~Sink() = default; + using Error = Validator::Error; + using Result = Validator::Result; + + enum InitType : std::uint8_t { Ok, CacheHit }; + using InitResult = std::expected; + public: - virtual auto init(QNetworkRequest& request) -> Task::State = 0; - virtual auto write(const QByteArray& data) -> Task::State = 0; - virtual auto abort() -> Task::State = 0; - virtual auto finalize(QNetworkReply& reply) -> Task::State = 0; + virtual InitResult init(QNetworkRequest& request) = 0; + virtual Result write(const QByteArray& data) = 0; + virtual Result finalize(QNetworkReply& reply) = 0; + virtual void abort() = 0; virtual auto hasLocalData() -> bool = 0; - QString failReason() const { return m_failReason; } - void addValidator(Validator* validator) { if (validator) { @@ -93,6 +97,5 @@ class Sink { protected: std::vector> m_validators; - QString m_failReason; }; } // namespace Net From ebca9f4254f47acb94d2286ad240afdd652daf43 Mon Sep 17 00:00:00 2001 From: Alexandru Ionut Tripon Date: Sun, 13 Sep 2026 15:54:12 +0300 Subject: [PATCH 3/4] Update launcher/net/Sink.h Co-authored-by: Octol1ttle Signed-off-by: Alexandru Ionut Tripon --- launcher/net/Sink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/net/Sink.h b/launcher/net/Sink.h index 0c980d8f3..4fc596caa 100644 --- a/launcher/net/Sink.h +++ b/launcher/net/Sink.h @@ -47,7 +47,7 @@ class Sink { using Error = Validator::Error; using Result = Validator::Result; - enum InitType : std::uint8_t { Ok, CacheHit }; + enum class InitType : std::uint8_t { Ok, CacheHit }; using InitResult = std::expected; public: From e109b6de7e430b3eab6da8782fd202b238bf827f Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Sun, 13 Sep 2026 18:13:32 +0500 Subject: [PATCH 4/4] fix build Signed-off-by: Octol1ttle --- launcher/net/Request.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/net/Request.cpp b/launcher/net/Request.cpp index b29596153..a8d8ae8a2 100644 --- a/launcher/net/Request.cpp +++ b/launcher/net/Request.cpp @@ -149,10 +149,10 @@ void Request::executeTask() return; } switch (*result) { - case Sink::Ok: + case Sink::InitType::Ok: qCDebug(m_logCat) << getUid().toString() << "Running" << m_url.toString(); break; - case Sink::CacheHit: + case Sink::InitType::CacheHit: m_state = Task::State::Succeeded; qCDebug(m_logCat) << getUid().toString() << "Request cache hit" << m_url.toString(); emit succeeded();