//SPDX-FileCopyrightText: 2023 Yury Gubich //SPDX-License-Identifier: GPL-3.0-or-later #include "request.h" #include #include const std::map Request::Request::resultStructure({ {"result", QMetaType::LongLong}, }); Request::Request::Request (const QUrl& url): state(State::initial), request(url), reply(), emptyResult(false) {} Request::Request::~Request () { cancel(); } void Request::Request::send (QNetworkAccessManager& manager) { if (state != State::initial) throw new std::runtime_error("An attempt to send a request in a wrong state"); initializeRequest(); aquireRequest(manager); connect(reply.get(), &QNetworkReply::finished, this, &Request::onFinished, Qt::QueuedConnection); state = State::sent; } void Request::Request::cancel () { if (stateTerminal()) return; state = State::cancelled; if (reply) reply->abort(); } void Request::Request::setAuthorizationToken (const QString& token) { request.setRawHeader("Authorization", "Bearer " + token.toUtf8()); } void Request::Request::aquireRequest (QNetworkAccessManager& manager) { reply = std::unique_ptr(manager.get(request)); } void Request::Request::initializeRequest () { request.setHeader(QNetworkRequest::ContentTypeHeader, json); } std::optional Request::Request::validate () { QNetworkReply::NetworkError error = reply->error(); if (error != QNetworkReply::NoError) return reply->errorString(); else return std::nullopt; } std::optional Request::Request::readResult () { QVariant contentType = reply->header(QNetworkRequest::ContentTypeHeader); if (!contentType.isValid() || !contentType.canConvert() || contentType.toString() != json) return std::nullopt; QByteArray data = reply->readAll(); QJsonDocument document = QJsonDocument::fromJson(data); if (!document.isObject()) return std::nullopt; QJsonObject object = document.object(); return object.toVariantMap(); } void Request::Request::onSuccess (const QVariantMap& data) { emit success(data); emit done(); } void Request::Request::onError (const QString& err, const std::optional& data) { emit error(err, data); emit done(); } bool Request::Request::validateResponse (const std::optional& data, const std::map& structure) { if (!data.has_value()) return false; for (const std::pair& pair : structure) { QVariantMap::ConstIterator itr = data->find(pair.first); if (itr == data->end()) return false; if (itr->userType() != pair.second) return false; } return true; } QUrl Request::Request::createUrl (QUrl base, const QString& path) { QString startingPath = base.path(); base.setPath(startingPath + path); return base; } bool Request::Request::stateTerminal () const { return state == State::responded || state == State::cancelled; } void Request::Request::onFinished () { if (state != State::sent) return; state = State::responded; std::optional err = validate(); std::optional data; if (!emptyResult) data = readResult(); if (err) return onError(err.value(), data); if (emptyResult) return onSuccess({}); if (data) return onSuccess(data.value()); else return onError("Error reading request result", data); }