diff --git a/src/qTbot/src/public/qTbot/httpexception.cpp b/src/qTbot/src/public/qTbot/httpexception.cpp new file mode 100644 index 0000000..9818efa --- /dev/null +++ b/src/qTbot/src/public/qTbot/httpexception.cpp @@ -0,0 +1,33 @@ +//# +//# Copyright (C) 2023-2024 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include "httpexception.h" + +HttpException::HttpException(QNetworkReply::NetworkError code, + const QByteArray &erroString) { + + if (erroString.size()) { + _errText = erroString; + } else { + + _errText = QByteArray("Http request fonoshed with code: "). + append(QString::number(code).toLatin1()); + } +} + +const char *HttpException::what() const noexcept { + return _errText.constData(); +} + +void HttpException::raise() const { + throw *this; +} + +QException *HttpException::clone() const { + return new HttpException(QNetworkReply::NetworkError(0), + _errText); +} diff --git a/src/qTbot/src/public/qTbot/httpexception.h b/src/qTbot/src/public/qTbot/httpexception.h new file mode 100644 index 0000000..e8c1799 --- /dev/null +++ b/src/qTbot/src/public/qTbot/httpexception.h @@ -0,0 +1,36 @@ +//# +//# Copyright (C) 2023-2024 QuasarApp. +//# Distributed under the GPLv3 software license, see the accompanying +//# Everyone is permitted to copy and distribute verbatim copies +//# of this license document, but changing it is not allowed. +//# + +#include <QException> +#include <QNetworkReply> + + +#ifndef HTTPEXCEPTION_H +#define HTTPEXCEPTION_H + +/** + * @brief The HttpException class is base exaption that will raise on all errors of the HTTP protocol, + */ +class HttpException: public QException +{ +public: + HttpException(QNetworkReply::NetworkError code, const QByteArray& erroString = {}); + + // exception interface +public: + const char *what() const noexcept; + + // QException interface +public: + void raise() const; + QException *clone() const; + +private: + QByteArray _errText; +}; + +#endif // HTTPEXCEPTION_H diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index a1b72f2..8855ac7 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -5,16 +5,18 @@ //# of this license document, but changing it is not allowed. //# +#include "httpexception.h" #include "ibot.h" #include "qstandardpaths.h" #include <QNetworkReply> +#include <QPromise> namespace qTbot { IBot::IBot() { _manager = new QNetworkAccessManager(); - _manager->setAutoDeleteReplies(false); + _manager->setAutoDeleteReplies(true); } IBot::~IBot() { @@ -48,12 +50,11 @@ void IBot::incomeNewUpdate(const QSharedPointer<iUpdate> &message) { } } -QSharedPointer<QNetworkReply> +QFuture<QByteArray> IBot::sendRequest(const QSharedPointer<iRequest> &rquest) { - if (!rquest) - return nullptr; - doRemoveFinishedRequests(); + if (!rquest) + return {}; auto && url = makeUrl(rquest); @@ -61,17 +62,13 @@ IBot::sendRequest(const QSharedPointer<iRequest> &rquest) { qDebug() << url; #endif - QSharedPointer<QNetworkReply> networkReplay; + QNetworkReply* networkReplay = nullptr; QSharedPointer<QHttpMultiPart> httpData; switch (rquest->method()) { case iRequest::Get: { - auto reply = _manager->get(QNetworkRequest(url)); + networkReplay = _manager->get(QNetworkRequest(url)); - // we control replay object wia shared pointers. - reply->setParent(nullptr); - - networkReplay.reset(reply); break; } @@ -85,38 +82,43 @@ IBot::sendRequest(const QSharedPointer<iRequest> &rquest) { httpData = rquest->argsToMultipartFormData(); if (httpData) { - auto reply = _manager->post(netRequest, httpData.data()); + networkReplay = _manager->post(netRequest, httpData.data()); - // we control replay object wia shared pointers. - reply->setParent(nullptr); - - networkReplay.reset(reply); } else { - return nullptr; + return {}; } break; } - size_t address = reinterpret_cast<size_t>(networkReplay.get()); - _replayStorage[address] = networkReplay; + if (!networkReplay) { + return {}; + } - connect(networkReplay.get(), &QNetworkReply::finished, this, - [this, address, httpData]() { - _toRemove.push_back(address); - }); + auto&& promise = QSharedPointer<QPromise<QByteArray>>::create(); - connect(networkReplay.get(), &QNetworkReply::errorOccurred, this, - [this, address](QNetworkReply::NetworkError err){ - qWarning() << "The reqeust " << address << " finished with error code : " << err; - if (auto&& replay = _replayStorage.value(address)) { - qWarning() << replay->errorString(); - } + networkReplay->connect(networkReplay, &QNetworkReply::finished, [networkReplay, promise](){ + promise->addResult(networkReplay->readAll()); + promise->finish(); + }); - _toRemove.push_back(address); - }); + networkReplay->connect(networkReplay, &QNetworkReply::errorOccurred, [networkReplay, promise](QNetworkReply::NetworkError ){ + promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1())); + promise->finish(); + }); - return networkReplay; + auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){ + + if (promise->future().progressMaximum() != bytesTotal) + promise->setProgressRange(0, bytesTotal); + + promise->setProgressValue(bytesCurrent); + }; + + networkReplay->connect(networkReplay, &QNetworkReply::downloadProgress, setProggress); + networkReplay->connect(networkReplay, &QNetworkReply::uploadProgress, setProggress); + + return promise->future(); } void IBot::markUpdateAsProcessed(const QSharedPointer<iUpdate> &message) { @@ -139,14 +141,6 @@ void IBot::handleIncomeNewUpdate(const QSharedPointer<iUpdate> & message) { emit sigReceiveUpdate(message); } -void IBot::doRemoveFinishedRequests() { - for (auto address: std::as_const(_toRemove)) { - _replayStorage.remove(address); - } - - _toRemove.clear(); -} - QSet<unsigned long long> IBot::processed() const { return _processed; } diff --git a/src/qTbot/src/public/qTbot/ibot.h b/src/qTbot/src/public/qTbot/ibot.h index e89d900..56530ab 100644 --- a/src/qTbot/src/public/qTbot/ibot.h +++ b/src/qTbot/src/public/qTbot/ibot.h @@ -23,6 +23,7 @@ #include <QNetworkReply> #include <QObject> #include <QSharedPointer> +#include <qfuture.h> namespace qTbot { @@ -177,7 +178,7 @@ protected: * @return shared pointer to the request replay. * @note The raplay will be removed from local storage only after error or finishing, If you want to save replay just make local copy of the shared pointer. */ - QSharedPointer<QNetworkReply> + QFuture<QByteArray> sendRequest(const QSharedPointer<iRequest>& rquest); /** @@ -234,7 +235,6 @@ signals: void sigStopRequire(); private: - void doRemoveFinishedRequests(); QByteArray _token; QString _name; @@ -242,8 +242,6 @@ private: QSet<unsigned long long> _processed; QNetworkAccessManager *_manager = nullptr; - QMap<size_t,QSharedPointer<QNetworkReply>> _replayStorage; - QList<size_t> _toRemove; };