From c607bde0418d76c543f13e60a840bf02f967f7a2 Mon Sep 17 00:00:00 2001 From: EndrII Date: Tue, 3 Dec 2024 21:19:33 +0100 Subject: [PATCH 01/14] refactor sendRequestMethod to QPromisse --- src/qTbot/src/public/qTbot/httpexception.cpp | 33 +++++++++ src/qTbot/src/public/qTbot/httpexception.h | 36 ++++++++++ src/qTbot/src/public/qTbot/ibot.cpp | 74 +++++++++----------- src/qTbot/src/public/qTbot/ibot.h | 6 +- 4 files changed, 105 insertions(+), 44 deletions(-) create mode 100644 src/qTbot/src/public/qTbot/httpexception.cpp create mode 100644 src/qTbot/src/public/qTbot/httpexception.h 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 +#include + + +#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 +#include namespace qTbot { IBot::IBot() { _manager = new QNetworkAccessManager(); - _manager->setAutoDeleteReplies(false); + _manager->setAutoDeleteReplies(true); } IBot::~IBot() { @@ -48,12 +50,11 @@ void IBot::incomeNewUpdate(const QSharedPointer &message) { } } -QSharedPointer +QFuture IBot::sendRequest(const QSharedPointer &rquest) { - if (!rquest) - return nullptr; - doRemoveFinishedRequests(); + if (!rquest) + return {}; auto && url = makeUrl(rquest); @@ -61,17 +62,13 @@ IBot::sendRequest(const QSharedPointer &rquest) { qDebug() << url; #endif - QSharedPointer networkReplay; + QNetworkReply* networkReplay = nullptr; QSharedPointer 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 &rquest) { httpData = rquest->argsToMultipartFormData(); if (httpData) { - auto reply = _manager->post(netRequest, httpData.data()); - - // we control replay object wia shared pointers. - reply->setParent(nullptr); + networkReplay = _manager->post(netRequest, httpData.data()); - networkReplay.reset(reply); } else { - return nullptr; + return {}; } break; } - size_t address = reinterpret_cast(networkReplay.get()); - _replayStorage[address] = networkReplay; + if (!networkReplay) { + return {}; + } + + auto&& promise = QSharedPointer>::create(); + + networkReplay->connect(networkReplay, &QNetworkReply::finished, [networkReplay, promise](){ + promise->addResult(networkReplay->readAll()); + promise->finish(); + }); - connect(networkReplay.get(), &QNetworkReply::finished, this, - [this, address, httpData]() { - _toRemove.push_back(address); - }); + networkReplay->connect(networkReplay, &QNetworkReply::errorOccurred, [networkReplay, promise](QNetworkReply::NetworkError ){ + promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1())); + promise->finish(); + }); - 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(); - } + auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){ - _toRemove.push_back(address); - }); + if (promise->future().progressMaximum() != bytesTotal) + promise->setProgressRange(0, bytesTotal); - return networkReplay; + promise->setProgressValue(bytesCurrent); + }; + + networkReplay->connect(networkReplay, &QNetworkReply::downloadProgress, setProggress); + networkReplay->connect(networkReplay, &QNetworkReply::uploadProgress, setProggress); + + return promise->future(); } void IBot::markUpdateAsProcessed(const QSharedPointer &message) { @@ -139,14 +141,6 @@ void IBot::handleIncomeNewUpdate(const QSharedPointer & message) { emit sigReceiveUpdate(message); } -void IBot::doRemoveFinishedRequests() { - for (auto address: std::as_const(_toRemove)) { - _replayStorage.remove(address); - } - - _toRemove.clear(); -} - QSet 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 #include #include +#include namespace qTbot { @@ -177,7 +178,7 @@ class QTBOT_EXPORT IBot: public QObject * @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 + QFuture sendRequest(const QSharedPointer& rquest); /** @@ -234,7 +235,6 @@ class QTBOT_EXPORT IBot: public QObject void sigStopRequire(); private: - void doRemoveFinishedRequests(); QByteArray _token; QString _name; @@ -242,8 +242,6 @@ class QTBOT_EXPORT IBot: public QObject QSet _processed; QNetworkAccessManager *_manager = nullptr; - QMap> _replayStorage; - QList _toRemove; }; From 2dc94178214ada25754bb2c28d51ce6f7f02ec26 Mon Sep 17 00:00:00 2001 From: EndrII Date: Tue, 3 Dec 2024 22:49:45 +0100 Subject: [PATCH 02/14] continue to implement new sendRequest --- src/qTbot/src/public/qTbot/httpexception.cpp | 6 +++ src/qTbot/src/public/qTbot/httpexception.h | 3 ++ .../src/public/qTbot/telegramrestbot.cpp | 38 +++++++++---------- src/qTbot/src/public/qTbot/telegramrestbot.h | 2 +- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/qTbot/src/public/qTbot/httpexception.cpp b/src/qTbot/src/public/qTbot/httpexception.cpp index 9818efa..9d18db6 100644 --- a/src/qTbot/src/public/qTbot/httpexception.cpp +++ b/src/qTbot/src/public/qTbot/httpexception.cpp @@ -10,6 +10,8 @@ HttpException::HttpException(QNetworkReply::NetworkError code, const QByteArray &erroString) { + _code = code; + if (erroString.size()) { _errText = erroString; } else { @@ -31,3 +33,7 @@ QException *HttpException::clone() const { return new HttpException(QNetworkReply::NetworkError(0), _errText); } + +QNetworkReply::NetworkError HttpException::code() const { + return _code; +} diff --git a/src/qTbot/src/public/qTbot/httpexception.h b/src/qTbot/src/public/qTbot/httpexception.h index e8c1799..44038da 100644 --- a/src/qTbot/src/public/qTbot/httpexception.h +++ b/src/qTbot/src/public/qTbot/httpexception.h @@ -29,8 +29,11 @@ class HttpException: public QException void raise() const; QException *clone() const; + QNetworkReply::NetworkError code() const; + private: QByteArray _errText; + QNetworkReply::NetworkError _code; }; #endif // HTTPEXCEPTION_H diff --git a/src/qTbot/src/public/qTbot/telegramrestbot.cpp b/src/qTbot/src/public/qTbot/telegramrestbot.cpp index f550484..9b08ae8 100644 --- a/src/qTbot/src/public/qTbot/telegramrestbot.cpp +++ b/src/qTbot/src/public/qTbot/telegramrestbot.cpp @@ -5,6 +5,7 @@ //# of this license document, but changing it is not allowed. //# +#include "httpexception.h" #include "telegramrestbot.h" #include "qTbot/messages/telegramupdate.h" #include "qTbot/messages/telegramupdateanswer.h" @@ -13,7 +14,6 @@ #include #include #include -#include namespace qTbot { @@ -51,13 +51,12 @@ void TelegramRestBot::startUpdates() { if (delta >= _updateDelay) { auto&& replay = sendRequest(QSharedPointer::create(_lanstUpdateid + 1)); - connect(replay.get(), &QNetworkReply::finished, - this, std::bind(&TelegramRestBot::handleReceiveUpdates, this, replay.toWeakRef()), - Qt::DirectConnection); + replay.then([this](const QByteArray &result){ + handleReceiveUpdates(result); + }).onFailed([this](const HttpException &e){ + handleReceiveUpdatesErr(e.code()); - connect(replay.get(), &QNetworkReply::errorOccurred, - this, &TelegramRestBot::handleReceiveUpdatesErr, - Qt::DirectConnection); + } ); return; } else { @@ -82,22 +81,19 @@ void TelegramRestBot::setProcessed(const QSet &newProcessed) IBot::setProcessed(newProcessed); } -void TelegramRestBot::handleReceiveUpdates(const QWeakPointer &replay) { +void TelegramRestBot::handleReceiveUpdates(const QByteArray &replay) { + auto&& telegramMsg = makeMesasge(replay); + if (telegramMsg->isValid()) { - if (auto&& sharedReplay = replay.lock()) { - auto&& telegramMsg = makeMesasge(sharedReplay->readAll()); - if (telegramMsg->isValid()) { + _lanstUpdateTime = QDateTime::currentMSecsSinceEpoch(); - _lanstUpdateTime = QDateTime::currentMSecsSinceEpoch(); - - auto && resultArray = telegramMsg->result().toArray(); - for (const auto& ref: resultArray) { - auto&& update = IBot::makeMesasge(ref.toObject()); - incomeNewUpdate(update); - if (_lanstUpdateid < update->updateId()) { - _lanstUpdateid = update->updateId(); - }; - } + auto && resultArray = telegramMsg->result().toArray(); + for (const auto& ref: resultArray) { + auto&& update = IBot::makeMesasge(ref.toObject()); + incomeNewUpdate(update); + if (_lanstUpdateid < update->updateId()) { + _lanstUpdateid = update->updateId(); + }; } } diff --git a/src/qTbot/src/public/qTbot/telegramrestbot.h b/src/qTbot/src/public/qTbot/telegramrestbot.h index 4e42f66..ed7d75d 100644 --- a/src/qTbot/src/public/qTbot/telegramrestbot.h +++ b/src/qTbot/src/public/qTbot/telegramrestbot.h @@ -44,7 +44,7 @@ class QTBOT_EXPORT TelegramRestBot: public ITelegramBot void setProcessed(const QSet &newProcessed) override; private slots: - void handleReceiveUpdates(const QWeakPointer& replay); + void handleReceiveUpdates(const QByteArray &replay); void handleReceiveUpdatesErr(QNetworkReply::NetworkError err); private: From 45e9a26fbe13d7b297eb73e3a7642ed0f80d3c93 Mon Sep 17 00:00:00 2001 From: EndrII Date: Sat, 7 Dec 2024 11:29:08 +0100 Subject: [PATCH 03/14] tmp commmit of implementation --- src/qTbot/src/public/qTbot/ibot.cpp | 4 ++ src/qTbot/src/public/qTbot/ibot.h | 11 +++- src/qTbot/src/public/qTbot/ifile.cpp | 59 ++++++++++++--------- src/qTbot/src/public/qTbot/ifile.h | 11 ++-- src/qTbot/src/public/qTbot/itelegrambot.cpp | 47 ++++++++-------- src/qTbot/src/public/qTbot/itelegrambot.h | 3 +- 6 files changed, 76 insertions(+), 59 deletions(-) diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index 8855ac7..aa01cb8 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -121,6 +121,10 @@ IBot::sendRequest(const QSharedPointer &rquest) { return promise->future(); } +QFuture IBot::sendRawRequest(const QSharedPointer &rquest) { + +} + void IBot::markUpdateAsProcessed(const QSharedPointer &message) { _notProcessedUpdates.remove(message->updateId()); } diff --git a/src/qTbot/src/public/qTbot/ibot.h b/src/qTbot/src/public/qTbot/ibot.h index 56530ab..a0fbf49 100644 --- a/src/qTbot/src/public/qTbot/ibot.h +++ b/src/qTbot/src/public/qTbot/ibot.h @@ -175,12 +175,19 @@ class QTBOT_EXPORT IBot: public QObject /** * @brief sendRequest This method sent custom requests to the server. * @param rquest This is message that will be sent to server. - * @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. + * @return future pointer to the request replay. */ QFuture sendRequest(const QSharedPointer& rquest); + /** + * @brief sendRawRequest This method sent custom requests to the server but as a ansver return future to network replay. + * @param rquest This is message that will be sent to server. + * @return future pointer to the request replay. + */ + QFuture + sendRawRequest(const QSharedPointer& rquest); + /** * @brief setToken This is setter of the IBot::token value. * @param newToken This is new value of the token. diff --git a/src/qTbot/src/public/qTbot/ifile.cpp b/src/qTbot/src/public/qTbot/ifile.cpp index 2febf92..9562004 100644 --- a/src/qTbot/src/public/qTbot/ifile.cpp +++ b/src/qTbot/src/public/qTbot/ifile.cpp @@ -9,7 +9,7 @@ namespace qTbot { -iFile::iFile(const QSharedPointer& replay) { +iFile::iFile(const QFuture &replay) { setDownloadRequest(replay); } @@ -48,7 +48,7 @@ void iFile::setError(int newError) { emit errorChanged(); } -const QSharedPointer &iFile::replay() const { +const QFuture &iFile::replay() const { return _replay; } @@ -71,42 +71,51 @@ void iFile::handleDownloadProgressChanged(qint64 bytesReceived, qint64 bytesTota setDownloadProgress(bytesReceived / static_cast(bytesTotal)); } -void iFile::setDownloadRequest(const QSharedPointer &replay) { +void iFile::setDownloadRequest(const QFuture &replay) { - if (_replay) { - disconnect(_replay.get(), &QNetworkReply::finished, - this, &iFile::handleFinished); + if (_replay.isValid()) { + if (_replay.isRunning()) { + _replay.cancel(); + } - disconnect(_replay.get(), &QNetworkReply::errorOccurred, - this, &iFile::handleError); + // disconnect(_replay.get(), &QNetworkReply::finished, + // this, &iFile::handleFinished); - disconnect(_replay.get(), &QNetworkReply::readyRead, - this, &iFile::handleReadReady); + // disconnect(_replay.get(), &QNetworkReply::errorOccurred, + // this, &iFile::handleError); - disconnect(_replay.get(), &QNetworkReply::uploadProgress, - this, &iFile::handleUploadProgressChanged); + // disconnect(_replay.get(), &QNetworkReply::readyRead, + // this, &iFile::handleReadReady); - disconnect(_replay.get(), &QNetworkReply::downloadProgress, - this, &iFile::handleDownloadProgressChanged); + // disconnect(_replay.get(), &QNetworkReply::uploadProgress, + // this, &iFile::handleUploadProgressChanged); + + // disconnect(_replay.get(), &QNetworkReply::downloadProgress, + // this, &iFile::handleDownloadProgressChanged); } _replay = replay; - if (_replay) { - connect(replay.get(), &QNetworkReply::finished, - this, &iFile::handleFinished, Qt::DirectConnection); + if (_replay.isValid()) { + + _replay.then(this, [this](const QByteArray& data) { + handleReadReady(data); + handleFinished(); + }); + // connect(replay.get(), &QNetworkReply::finished, + // this, &iFile::handleFinished, Qt::DirectConnection); - connect(replay.get(), &QNetworkReply::errorOccurred, - this, &iFile::handleError, Qt::DirectConnection); + // connect(replay.get(), &QNetworkReply::errorOccurred, + // this, &iFile::handleError, Qt::DirectConnection); - connect(replay.get(), &QNetworkReply::readyRead, - this, &iFile::handleReadReady, Qt::DirectConnection); + // connect(replay.get(), &QNetworkReply::readyRead, + // this, &iFile::handleReadReady, Qt::DirectConnection); - connect(replay.get(), &QNetworkReply::uploadProgress, - this, &iFile::handleUploadProgressChanged, Qt::DirectConnection); + // connect(replay.get(), &QNetworkReply::uploadProgress, + // this, &iFile::handleUploadProgressChanged, Qt::DirectConnection); - connect(replay.get(), &QNetworkReply::downloadProgress, - this, &iFile::handleDownloadProgressChanged, Qt::DirectConnection); + // connect(replay.get(), &QNetworkReply::downloadProgress, + // this, &iFile::handleDownloadProgressChanged, Qt::DirectConnection); } } diff --git a/src/qTbot/src/public/qTbot/ifile.h b/src/qTbot/src/public/qTbot/ifile.h index 11fa5bb..6ec80ff 100644 --- a/src/qTbot/src/public/qTbot/ifile.h +++ b/src/qTbot/src/public/qTbot/ifile.h @@ -8,9 +8,10 @@ #ifndef IFILE_H #define IFILE_H -#include "qnetworkreply.h" #include #include +#include +#include namespace qTbot { @@ -32,7 +33,7 @@ class QTBOT_EXPORT iFile: public QObject Ram }; - iFile(const QSharedPointer& replay); + iFile(const QFuture& replay); /** * @brief Get the current upload progress. @@ -74,7 +75,7 @@ class QTBOT_EXPORT iFile: public QObject * @brief Get the shared pointer to the associated QNetworkReply. * @return A shared pointer to the associated QNetworkReply. */ - const QSharedPointer& replay() const; + const QFuture& replay() const; /** * @brief type This is type of the file object. @@ -92,7 +93,7 @@ class QTBOT_EXPORT iFile: public QObject * @brief setDownloadRequest This method sets replay for the file. * @param replay This is pointer to the replay. */ - void setDownloadRequest(const QSharedPointer& replay); + void setDownloadRequest(const QFuture &replay); protected: /** @@ -166,7 +167,7 @@ private slots: int _error = 0; bool _finished = false; - QSharedPointer _replay; + QFuture _replay; friend class ITelegramBot; }; diff --git a/src/qTbot/src/public/qTbot/itelegrambot.cpp b/src/qTbot/src/public/qTbot/itelegrambot.cpp index f1e617e..2aaeb75 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.cpp +++ b/src/qTbot/src/public/qTbot/itelegrambot.cpp @@ -12,6 +12,7 @@ #include "qdir.h" #include "requests/telegramsendcontact.h" #include "requests/telegramsenddocument.h" +#include "httpexception.h" #include "virtualfile.h" #include @@ -52,18 +53,16 @@ bool ITelegramBot::login(const QByteArray &token) { setToken(token); - _loginReplay = sendRequest(QSharedPointer::create()); - if (_loginReplay) { - connect(_loginReplay.get(), &QNetworkReply::finished, - this, &ITelegramBot::handleLogin, - Qt::DirectConnection); - connect(_loginReplay.get(), &QNetworkReply::errorOccurred, - this, &ITelegramBot::handleLoginErr, - Qt::DirectConnection); - return true; - } + QFuture loginFuture = sendRequest(QSharedPointer::create()); + loginFuture. + then(this, [this](const QByteArray& data) { + ITelegramBot::handleLogin(data); + } ). + onFailed(this, [this](const HttpException& exeption){ + handleLoginErr(exeption.code()); + }); - return false; + return loginFuture.isValid(); } bool ITelegramBot::sendMessage(const QVariant &chatId, const QString &text) { @@ -329,7 +328,8 @@ QSharedPointer ITelegramBot::getFile(const QString &fileId, iFile::Type f if (localFilePath.isEmpty()) return result; - if (auto &&replay = sendRequest(msg)) { + QFuture &&replay = sendRequest(msg); + if (replay.isValid()) { // here i must be receive responce and prepare new request to file from the call back function. if (fileType == iFile::Ram) { result = QSharedPointer::create(replay); @@ -554,23 +554,20 @@ bool ITelegramBot::sendMessageRequest(const QSharedPointer &rquest, return bool(reply); } -void ITelegramBot::handleLogin() { - - if (_loginReplay) { - auto&& ans = makeMesasge(_loginReplay->readAll()); +void ITelegramBot::handleLogin(const QByteArray&ansver) { - if (!ans->isValid()) { - qWarning() << "login error occured: "; - } + auto&& ans = makeMesasge(ansver); - auto&& result = ans->result().toObject(); + if (!ans->isValid()) { + qWarning() << "login error occured: "; + return; + } - setId(result.value("id").toInteger()); - setName( result.value("first_name").toString()); - setUsername( result.value("username").toString()); + auto&& result = ans->result().toObject(); - _loginReplay.reset(); - } + setId(result.value("id").toInteger()); + setName( result.value("first_name").toString()); + setUsername( result.value("username").toString()); } diff --git a/src/qTbot/src/public/qTbot/itelegrambot.h b/src/qTbot/src/public/qTbot/itelegrambot.h index 82e140b..6ff2b8b 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.h +++ b/src/qTbot/src/public/qTbot/itelegrambot.h @@ -389,7 +389,7 @@ class QTBOT_EXPORT ITelegramBot : public IBot const std::function& msgIdCB = {}); private slots: - void handleLogin(); + void handleLogin(const QByteArray &ansver); void handleLoginErr(QNetworkReply::NetworkError err); void handleFileHeader(const QWeakPointer& sender, const QWeakPointer &receiver); @@ -405,7 +405,6 @@ private slots: unsigned long long _id = 0; QString _username; - QSharedPointer _loginReplay; QMap> _handleButtons; QHash _lastMessageId; From 16367526d31bef4a558aa93bcad7245d41ddae5b Mon Sep 17 00:00:00 2001 From: EndrII Date: Sun, 8 Dec 2024 19:12:01 +0100 Subject: [PATCH 04/14] tmp coomit --- src/qTbot/src/public/qTbot/ibot.cpp | 11 +++++------ src/qTbot/src/public/qTbot/ibot.h | 8 -------- src/qTbot/src/public/qTbot/ifile.cpp | 8 ++++++-- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index aa01cb8..921a1e3 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -97,11 +97,14 @@ IBot::sendRequest(const QSharedPointer &rquest) { auto&& promise = QSharedPointer>::create(); - networkReplay->connect(networkReplay, &QNetworkReply::finished, [networkReplay, promise](){ - promise->addResult(networkReplay->readAll()); + networkReplay->connect(networkReplay, &QNetworkReply::finished, [promise](){ promise->finish(); }); + networkReplay->connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise](){ + promise->addResult(networkReplay->readAll()); + }); + networkReplay->connect(networkReplay, &QNetworkReply::errorOccurred, [networkReplay, promise](QNetworkReply::NetworkError ){ promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1())); promise->finish(); @@ -121,10 +124,6 @@ IBot::sendRequest(const QSharedPointer &rquest) { return promise->future(); } -QFuture IBot::sendRawRequest(const QSharedPointer &rquest) { - -} - void IBot::markUpdateAsProcessed(const QSharedPointer &message) { _notProcessedUpdates.remove(message->updateId()); } diff --git a/src/qTbot/src/public/qTbot/ibot.h b/src/qTbot/src/public/qTbot/ibot.h index a0fbf49..c249a24 100644 --- a/src/qTbot/src/public/qTbot/ibot.h +++ b/src/qTbot/src/public/qTbot/ibot.h @@ -180,14 +180,6 @@ class QTBOT_EXPORT IBot: public QObject QFuture sendRequest(const QSharedPointer& rquest); - /** - * @brief sendRawRequest This method sent custom requests to the server but as a ansver return future to network replay. - * @param rquest This is message that will be sent to server. - * @return future pointer to the request replay. - */ - QFuture - sendRawRequest(const QSharedPointer& rquest); - /** * @brief setToken This is setter of the IBot::token value. * @param newToken This is new value of the token. diff --git a/src/qTbot/src/public/qTbot/ifile.cpp b/src/qTbot/src/public/qTbot/ifile.cpp index 9562004..dd74315 100644 --- a/src/qTbot/src/public/qTbot/ifile.cpp +++ b/src/qTbot/src/public/qTbot/ifile.cpp @@ -7,6 +7,8 @@ #include "ifile.h" +#include + namespace qTbot { iFile::iFile(const QFuture &replay) { @@ -98,10 +100,12 @@ void iFile::setDownloadRequest(const QFuture &replay) { if (_replay.isValid()) { - _replay.then(this, [this](const QByteArray& data) { - handleReadReady(data); + _replay.then(this, [this](const QByteArray&) { handleFinished(); }); + + QFutureWatcher *watcher = new QFutureWatcher(); + watcher->setFuture(replay); // connect(replay.get(), &QNetworkReply::finished, // this, &iFile::handleFinished, Qt::DirectConnection); From 55ad2e962994425768d7061c4d5cfd5b7fcf72d8 Mon Sep 17 00:00:00 2001 From: EndrII Date: Sun, 8 Dec 2024 20:07:29 +0100 Subject: [PATCH 05/14] temp changes, --- src/qTbot/src/public/qTbot/ibot.cpp | 61 ++++++++++++++++++++++++++--- src/qTbot/src/public/qTbot/ibot.h | 12 +++++- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index 921a1e3..14e65d5 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -50,9 +50,7 @@ void IBot::incomeNewUpdate(const QSharedPointer &message) { } } -QFuture -IBot::sendRequest(const QSharedPointer &rquest) { - +QNetworkReply* IBot::sendRquestImpl(const QSharedPointer &rquest) { if (!rquest) return {}; @@ -73,10 +71,10 @@ IBot::sendRequest(const QSharedPointer &rquest) { } case iRequest::Post: -// req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); -// reply = m_nam.post(req, params.toByteArray()); + // req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + // reply = m_nam.post(req, params.toByteArray()); -// break; + // break; case iRequest::Upload: QNetworkRequest netRequest(url); @@ -91,6 +89,14 @@ IBot::sendRequest(const QSharedPointer &rquest) { break; } + return networkReplay; +} + +QFuture +IBot::sendRequest(const QSharedPointer &rquest) { + + + QNetworkReply* networkReplay = sendRquestImpl(rquest); if (!networkReplay) { return {}; } @@ -124,6 +130,49 @@ IBot::sendRequest(const QSharedPointer &rquest) { return promise->future(); } +QFuture IBot::sendRequest(const QSharedPointer &rquest, const QString &pathToResult) { + auto&& file = QSharedPointer::create(); + + file->open(QIODevice::WriteOnly | QIODevice::Truncate); + + + QNetworkReply* networkReplay = sendRquestImpl(rquest); + if (!networkReplay) { + return {}; + } + + + auto&& promise = QSharedPointer>::create(); + + networkReplay->connect(networkReplay, &QNetworkReply::finished, [promise, pathToResult](){ + + promise->addResult(pathToResult.toUtf8()); // wil not work with UTF 8 path names + promise->finish(); + }); + + networkReplay->connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise, pathToResult](){ + promise->addResult(networkReplay->readAll()); + }); + + networkReplay->connect(networkReplay, &QNetworkReply::errorOccurred, [networkReplay, promise](QNetworkReply::NetworkError ){ + promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1())); + promise->finish(); + }); + + 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 &message) { _notProcessedUpdates.remove(message->updateId()); } diff --git a/src/qTbot/src/public/qTbot/ibot.h b/src/qTbot/src/public/qTbot/ibot.h index c249a24..e82a12c 100644 --- a/src/qTbot/src/public/qTbot/ibot.h +++ b/src/qTbot/src/public/qTbot/ibot.h @@ -164,7 +164,6 @@ class QTBOT_EXPORT IBot: public QObject return ptr; } - /** * @brief makeUrl This method prepare a prefix url for http requests. * @param request - This is request object for that will be prepared url. @@ -180,6 +179,16 @@ class QTBOT_EXPORT IBot: public QObject QFuture sendRequest(const QSharedPointer& rquest); + /** + * @brief sendRequest This method sent custom requests to the server. + * @param rquest This is message that will be sent to server. + * @return future pointer to the request replay. + * @note This is same as a default implementaion execpt save data location, + * this method will create new file that located @a pathToResult and save all received data to this location. + */ + QFuture + sendRequest(const QSharedPointer& rquest, const QString& pathToResult); + /** * @brief setToken This is setter of the IBot::token value. * @param newToken This is new value of the token. @@ -234,6 +243,7 @@ class QTBOT_EXPORT IBot: public QObject void sigStopRequire(); private: + QNetworkReply *sendRquestImpl(const QSharedPointer &rquest); QByteArray _token; QString _name; From 40d4a47a006ff6a89daeff46598ecbc4ee757cd6 Mon Sep 17 00:00:00 2001 From: EndrII Date: Tue, 10 Dec 2024 15:51:28 +0100 Subject: [PATCH 06/14] itelegrambot fixes --- src/qTbot/src/public/qTbot/ibot.cpp | 11 +- src/qTbot/src/public/qTbot/ifile.cpp | 2 + src/qTbot/src/public/qTbot/itelegrambot.cpp | 113 ++++++++++---------- src/qTbot/src/public/qTbot/itelegrambot.h | 7 +- 4 files changed, 69 insertions(+), 64 deletions(-) diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index 14e65d5..9c1ceb6 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -133,15 +133,16 @@ IBot::sendRequest(const QSharedPointer &rquest) { QFuture IBot::sendRequest(const QSharedPointer &rquest, const QString &pathToResult) { auto&& file = QSharedPointer::create(); - file->open(QIODevice::WriteOnly | QIODevice::Truncate); - + if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qCritical() << "Fail to wrote data into " << pathToResult; + return {}; + } QNetworkReply* networkReplay = sendRquestImpl(rquest); if (!networkReplay) { return {}; } - auto&& promise = QSharedPointer>::create(); networkReplay->connect(networkReplay, &QNetworkReply::finished, [promise, pathToResult](){ @@ -150,8 +151,8 @@ QFuture IBot::sendRequest(const QSharedPointer &rquest, co promise->finish(); }); - networkReplay->connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise, pathToResult](){ - promise->addResult(networkReplay->readAll()); + networkReplay->connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise, pathToResult, file](){ + file->write(networkReplay->readAll()); }); networkReplay->connect(networkReplay, &QNetworkReply::errorOccurred, [networkReplay, promise](QNetworkReply::NetworkError ){ diff --git a/src/qTbot/src/public/qTbot/ifile.cpp b/src/qTbot/src/public/qTbot/ifile.cpp index dd74315..1c87bc6 100644 --- a/src/qTbot/src/public/qTbot/ifile.cpp +++ b/src/qTbot/src/public/qTbot/ifile.cpp @@ -106,6 +106,8 @@ void iFile::setDownloadRequest(const QFuture &replay) { QFutureWatcher *watcher = new QFutureWatcher(); watcher->setFuture(replay); + + // connect(replay.get(), &QNetworkReply::finished, // this, &iFile::handleFinished, Qt::DirectConnection); diff --git a/src/qTbot/src/public/qTbot/itelegrambot.cpp b/src/qTbot/src/public/qTbot/itelegrambot.cpp index 2aaeb75..dff1be8 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.cpp +++ b/src/qTbot/src/public/qTbot/itelegrambot.cpp @@ -349,21 +349,26 @@ QSharedPointer ITelegramBot::getFile(const QString &fileId, iFile::Type f result = QSharedPointer::create(localFilePath); } - auto&& metaReploay = getFileMeta(fileId, result.toWeakRef()); + auto&& future = getFileMeta(fileId, result.toWeakRef()); + if (!future.isValid()) { + return nullptr; + } + return result; } -QSharedPointer ITelegramBot::getFileMeta(const QString &fileId, const QWeakPointer& receiver) { +QFuture ITelegramBot::getFileMeta(const QString &fileId, const QWeakPointer& receiver) { auto msg = QSharedPointer::create(fileId); + auto && future = sendRequest(msg); + if (future.isValid()) { + future.then([this, receiver](const QByteArray&data){ + handleFileHeader(data, receiver); + }); - if (auto&& ptr = sendRequest(msg)) { - connect(ptr.get(), &QNetworkReply::finished, - this, std::bind(&ITelegramBot::handleFileHeader, this, ptr.toWeakRef(), receiver)); - - return ptr; + return future; } - return nullptr; + return {}; } bool ITelegramBot::sendFile(const QFileInfo &file, const QVariant &chatId) { @@ -479,9 +484,9 @@ bool ITelegramBot::sendContact(const TelegramArgs &args, return false; return sendMessageRequest(QSharedPointer::create(args, - firstName, - phone, - secondName)); + firstName, + phone, + secondName)); } int ITelegramBot::getFileSizeByUniqueId(const QString &id) const { @@ -520,38 +525,37 @@ void ITelegramBot::handleIncomeNewUpdate(const QSharedPointer & update) bool ITelegramBot::sendMessageRequest(const QSharedPointer &rquest, const std::function &msgIdCB) { - auto&& reply = IBot::sendRequest(rquest); - if (reply) { - connect(reply.get(), &QNetworkReply::finished, this, - [ reply, msgIdCB, this]() { - - if (reply->error() == QNetworkReply::NoError) { - QByteArray&& responseData = reply->readAll(); - QJsonDocument json = QJsonDocument::fromJson(responseData); - - const QJsonObject&& obj = json.object(); - if (obj.contains("result")) { - unsigned long long chatId = obj["result"]["chat"]["id"].toInteger(); - int messageID = obj["result"]["message_id"].toInt(); - if (msgIdCB) { - msgIdCB(messageID); - } - - if (chatId) { - _lastMessageId[chatId] = messageID; - } - - return; - } - } - - if (msgIdCB) { - msgIdCB(-1); - } - }); + auto&& future = IBot::sendRequest(rquest); + if (future.isValid()) { + future.then(this, [this, msgIdCB](const QByteArray& responseData){ + + QJsonDocument json = QJsonDocument::fromJson(responseData); + + const QJsonObject&& obj = json.object(); + if (obj.contains("result")) { + unsigned long long chatId = obj["result"]["chat"]["id"].toInteger(); + int messageID = obj["result"]["message_id"].toInt(); + if (msgIdCB) { + msgIdCB(messageID); + } + + if (chatId) { + _lastMessageId[chatId] = messageID; + } + + return; + } + }).onFailed([msgIdCB](){ + + if (msgIdCB) { + msgIdCB(-1); + } + }); + + return true; } - return bool(reply); + return false; } void ITelegramBot::handleLogin(const QByteArray&ansver) { @@ -573,29 +577,26 @@ void ITelegramBot::handleLogin(const QByteArray&ansver) { void ITelegramBot::handleLoginErr(QNetworkReply::NetworkError err) { if (err) { - qDebug() << "Network error occured. code: " << err; + qCritical() << "Network error occured. code: " << err; } - _loginReplay.reset(); } -void ITelegramBot::handleFileHeader(const QWeakPointer &sender, +void ITelegramBot::handleFileHeader(const QByteArray& header, const QWeakPointer& receiver) { - if (auto&& sharedPtr = sender.lock()) { - auto&& ansver = makeMesasge(sharedPtr->readAll()); + auto&& ansver = makeMesasge(header); - if (!ansver->isValid()) { - onRequestError(ansver); - return; - } + if (!ansver->isValid()) { + onRequestError(ansver); + return; + } - auto &&fileMetaInfo = makeMesasge(ansver->result().toObject()); + auto &&fileMetaInfo = makeMesasge(ansver->result().toObject()); - _filesMetaInfo.insert(fileMetaInfo->fileId(), fileMetaInfo); + _filesMetaInfo.insert(fileMetaInfo->fileId(), fileMetaInfo); - if (auto&& sharedPtr = receiver.lock()) { - auto&& downloadRequest = QSharedPointer::create(fileMetaInfo->takePath()); - sharedPtr->setDownloadRequest(sendRequest(downloadRequest)); - } + if (auto&& sharedPtr = receiver.lock()) { + auto&& downloadRequest = QSharedPointer::create(fileMetaInfo->takePath()); + sharedPtr->setDownloadRequest(sendRequest(downloadRequest)); } } diff --git a/src/qTbot/src/public/qTbot/itelegrambot.h b/src/qTbot/src/public/qTbot/itelegrambot.h index 6ff2b8b..c9ceb0b 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.h +++ b/src/qTbot/src/public/qTbot/itelegrambot.h @@ -194,9 +194,10 @@ class QTBOT_EXPORT ITelegramBot : public IBot * @brief getFileMeta This method receive meta information of the file. * @param fileId This is id of the file. * @param receiver this is wrapper of the file. Set to nullptr if you no need to wait a physical file. - * @return true if the reqests sents successful. + * @return future objectl with result. */ - QSharedPointer getFileMeta(const QString& fileId, + + QFuture getFileMeta(const QString& fileId, const QWeakPointer &receiver = {nullptr}); bool sendFile( const QFileInfo& file, const QVariant& chatId) override; @@ -391,7 +392,7 @@ class QTBOT_EXPORT ITelegramBot : public IBot private slots: void handleLogin(const QByteArray &ansver); void handleLoginErr(QNetworkReply::NetworkError err); - void handleFileHeader(const QWeakPointer& sender, + void handleFileHeader(const QByteArray &header, const QWeakPointer &receiver); private: From 06eff18b914d6df6ee3165a304cab64c39b6c224 Mon Sep 17 00:00:00 2001 From: EndrII Date: Tue, 10 Dec 2024 22:43:29 +0100 Subject: [PATCH 07/14] continue to refactor of qTbor library --- src/qTbot/src/public/qTbot/file.cpp | 56 ------- src/qTbot/src/public/qTbot/file.h | 40 ----- src/qTbot/src/public/qTbot/ifile.cpp | 140 ---------------- src/qTbot/src/public/qTbot/ifile.h | 175 -------------------- src/qTbot/src/public/qTbot/itelegrambot.cpp | 5 +- src/qTbot/src/public/qTbot/itelegrambot.h | 9 +- src/qTbot/src/public/qTbot/virtualfile.cpp | 46 ----- src/qTbot/src/public/qTbot/virtualfile.h | 39 ----- 8 files changed, 9 insertions(+), 501 deletions(-) delete mode 100644 src/qTbot/src/public/qTbot/file.cpp delete mode 100644 src/qTbot/src/public/qTbot/file.h delete mode 100644 src/qTbot/src/public/qTbot/ifile.cpp delete mode 100644 src/qTbot/src/public/qTbot/ifile.h delete mode 100644 src/qTbot/src/public/qTbot/virtualfile.cpp delete mode 100644 src/qTbot/src/public/qTbot/virtualfile.h diff --git a/src/qTbot/src/public/qTbot/file.cpp b/src/qTbot/src/public/qTbot/file.cpp deleted file mode 100644 index 9f8fab9..0000000 --- a/src/qTbot/src/public/qTbot/file.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//# -//# 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 "file.h" - -namespace qTbot { - - -File::File(const QSharedPointer &replay, const QString &filePath): iFile(replay) { - _localFile.setFileName(filePath); - - if (!_localFile.isOpen()) { - _localFile.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Append); - } - -} - -File::File(const QString &filePath):File(nullptr, filePath) { - -} - -const QFile & File::localFile() const { - return _localFile; -} - -iFile::Type File::type() const { - return Type::Local; -} - -void File::handleReadReady() { - auto&& bytes = replay()->readAll(); - - if (bytes.size()) { - _localFile.write(bytes); - _localFile.flush(); - } -} - -void File::handleFinished() { - handleReadReady(); - _localFile.close(); - iFile::handleFinished(); -} - -void File::handleError(QNetworkReply::NetworkError error) { - iFile::handleError(error); - _localFile.close(); - - _localFile.remove(); -} - -} diff --git a/src/qTbot/src/public/qTbot/file.h b/src/qTbot/src/public/qTbot/file.h deleted file mode 100644 index 7aa55a8..0000000 --- a/src/qTbot/src/public/qTbot/file.h +++ /dev/null @@ -1,40 +0,0 @@ -//# -//# 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. -//# - - -#ifndef FILE_H -#define FILE_H - -#include "ifile.h" - -namespace qTbot { - -/** - * @brief The File class is implementations for local files. - */ -class QTBOT_EXPORT File: public iFile -{ - Q_OBJECT -public: - File(const QSharedPointer& replay, const QString &filePath); - File(const QString &filePath); - - const QFile & localFile() const; - - Type type() const override; - - // iFile interface -protected slots: - void handleReadReady() override; - void handleFinished() override; - void handleError(QNetworkReply::NetworkError error) override; -private: - QFile _localFile; - -}; -} -#endif // FILE_H diff --git a/src/qTbot/src/public/qTbot/ifile.cpp b/src/qTbot/src/public/qTbot/ifile.cpp deleted file mode 100644 index 1c87bc6..0000000 --- a/src/qTbot/src/public/qTbot/ifile.cpp +++ /dev/null @@ -1,140 +0,0 @@ -//# -//# 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 "ifile.h" - -#include - -namespace qTbot { - -iFile::iFile(const QFuture &replay) { - setDownloadRequest(replay); -} - -float iFile::uploadProgress() const { - return _uploadProgress; -} - -void iFile::setUploadProgress(float newUploadProgress) { - if (qFuzzyCompare(_uploadProgress, newUploadProgress)) - return; - - _uploadProgress = newUploadProgress; - emit uploadProgressChanged(); -} - -float iFile::downloadProgress() const { - return _downloadProgress; -} - -void iFile::setDownloadProgress(float newDownloadProgress) { - if (qFuzzyCompare(_downloadProgress, newDownloadProgress)) - return; - - _downloadProgress = newDownloadProgress; - emit downloadProgressChanged(); -} - -int iFile::error() const { - return _error; -} - -void iFile::setError(int newError) { - if (_error == newError) - return; - _error = newError; - emit errorChanged(); -} - -const QFuture &iFile::replay() const { - return _replay; -} - -bool iFile::isFinished() const { - return _finished; -} - -void iFile::handleError(QNetworkReply::NetworkError error) { - setError(error); - setUploadProgress(0); - setDownloadProgress(0); - -} - -void iFile::handleUploadProgressChanged(qint64 bytesSent, qint64 bytesTotal) { - setUploadProgress(bytesSent / static_cast(bytesTotal)); -} - -void iFile::handleDownloadProgressChanged(qint64 bytesReceived, qint64 bytesTotal) { - setDownloadProgress(bytesReceived / static_cast(bytesTotal)); -} - -void iFile::setDownloadRequest(const QFuture &replay) { - - if (_replay.isValid()) { - if (_replay.isRunning()) { - _replay.cancel(); - } - - // disconnect(_replay.get(), &QNetworkReply::finished, - // this, &iFile::handleFinished); - - // disconnect(_replay.get(), &QNetworkReply::errorOccurred, - // this, &iFile::handleError); - - // disconnect(_replay.get(), &QNetworkReply::readyRead, - // this, &iFile::handleReadReady); - - // disconnect(_replay.get(), &QNetworkReply::uploadProgress, - // this, &iFile::handleUploadProgressChanged); - - // disconnect(_replay.get(), &QNetworkReply::downloadProgress, - // this, &iFile::handleDownloadProgressChanged); - } - - _replay = replay; - - if (_replay.isValid()) { - - _replay.then(this, [this](const QByteArray&) { - handleFinished(); - }); - - QFutureWatcher *watcher = new QFutureWatcher(); - watcher->setFuture(replay); - - - // connect(replay.get(), &QNetworkReply::finished, - // this, &iFile::handleFinished, Qt::DirectConnection); - - // connect(replay.get(), &QNetworkReply::errorOccurred, - // this, &iFile::handleError, Qt::DirectConnection); - - // connect(replay.get(), &QNetworkReply::readyRead, - // this, &iFile::handleReadReady, Qt::DirectConnection); - - // connect(replay.get(), &QNetworkReply::uploadProgress, - // this, &iFile::handleUploadProgressChanged, Qt::DirectConnection); - - // connect(replay.get(), &QNetworkReply::downloadProgress, - // this, &iFile::handleDownloadProgressChanged, Qt::DirectConnection); - } - -} - -void iFile::setFinished(bool newFinished) { - - if (newFinished != _finished) { - _finished = newFinished; - emit finishedChanged(); - } -} - -void iFile::handleFinished() { - setFinished(true); -} -} diff --git a/src/qTbot/src/public/qTbot/ifile.h b/src/qTbot/src/public/qTbot/ifile.h deleted file mode 100644 index 6ec80ff..0000000 --- a/src/qTbot/src/public/qTbot/ifile.h +++ /dev/null @@ -1,175 +0,0 @@ -//# -//# 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. -//# - -#ifndef IFILE_H -#define IFILE_H - -#include -#include -#include -#include - -namespace qTbot { - -/** - * @brief The iFile class This is main interface for all implementations of the files. - */ -class QTBOT_EXPORT iFile: public QObject -{ - Q_OBJECT -public: - - /** - * @brief The Type enum is type of the file object. - */ - enum Type { - /// This is local file, all receive bytes will be save directed into file. - Local, - /// This is memory saved file. All received bytes will be saved into QByteArray object. - Ram - }; - - iFile(const QFuture& replay); - - /** - * @brief Get the current upload progress. - * @return The current upload progress as a floating-point value. - */ - float uploadProgress() const; - - /** - * @brief Set the upload progress. - * @param newUploadProgress The new upload progress value to set. - */ - void setUploadProgress(float newUploadProgress); - - /** - * @brief Get the current download progress. - * @return The current download progress as a floating-point value. - */ - float downloadProgress() const; - - /** - * @brief Set the download progress. - * @param newDownloadProgress The new download progress value to set. - */ - void setDownloadProgress(float newDownloadProgress); - - /** - * @brief Get the error code associated with this file. - * @return The error code as an integer value. - */ - int error() const; - - /** - * @brief Set the error code for this file. - * @param newError The new error code to set. - */ - void setError(int newError); - - /** - * @brief Get the shared pointer to the associated QNetworkReply. - * @return A shared pointer to the associated QNetworkReply. - */ - const QFuture& replay() const; - - /** - * @brief type This is type of the file object. - * @return type of the file object. - */ - virtual Type type() const = 0; - - /** - * @brief finished return true if the request was finished else false. - * @return true if the request was finished else false - */ - bool isFinished() const; - - /** - * @brief setDownloadRequest This method sets replay for the file. - * @param replay This is pointer to the replay. - */ - void setDownloadRequest(const QFuture &replay); -protected: - - /** - * @brief setFinished monual sets finished flag. - * @param newFinished new value for the finished flag. - */ - void setFinished(bool newFinished); - -protected slots: - /** - * @brief Slot to handle when data is ready to be read. - */ - virtual void handleReadReady() = 0; - - /** - * @brief Slot to handle when the network operation is finished. - */ - virtual void handleFinished(); - - /** - * @brief Slot to handle errors in the network operation. - * @param error This is error code. - */ - virtual void handleError(QNetworkReply::NetworkError error); - -private slots: - - /** - * @brief Slot to handle changes in upload progress. - * @param bytesSent current snet bytes. - * @param bytesTotal total to sent bytes. - */ - void handleUploadProgressChanged(qint64 bytesSent, qint64 bytesTotal); - - /** - * @brief Slot to handle changes in download progress. - * @param bytesReceived current received bytes. - * @param bytesTotal total to receive bytes. - */ - void handleDownloadProgressChanged(qint64 bytesReceived, qint64 bytesTotal); - -signals: - /** - * @brief Signal emitted when the upload progress changes. - */ - void uploadProgressChanged(); - - /** - * @brief Signal emitted when the download progress changes. - */ - void downloadProgressChanged(); - - /** - * @brief Signal emitted when the error code changes. - */ - void errorChanged(); - - /** - * @brief Signal emitted when the associated QNetworkReply changes. - */ - void replayChanged(); - - /** - * @brief Signal emitted when the associated finished changes. - */ - void finishedChanged(); - -private: - float _uploadProgress = 0; - float _downloadProgress = 0; - int _error = 0; - bool _finished = false; - - QFuture _replay; - - friend class ITelegramBot; -}; -} -#endif // IFILE_H diff --git a/src/qTbot/src/public/qTbot/itelegrambot.cpp b/src/qTbot/src/public/qTbot/itelegrambot.cpp index dff1be8..95db260 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.cpp +++ b/src/qTbot/src/public/qTbot/itelegrambot.cpp @@ -283,12 +283,11 @@ bool ITelegramBot::sendSpecificMessageWithKeyboard(const TelegramArgs& args, return sendSpecificMessage(args, prepareKeyboard(autoResizeKeyboard, onTimeKeyboard, keyboard)); } -QSharedPointer ITelegramBot::getFile(const QString &fileId, iFile::Type fileType) { +QFuture ITelegramBot::getFile(const QString &fileId, iFile::Type fileType) { - QSharedPointer result = nullptr; if (fileId.isEmpty()) { - return result; + return {}; } auto localFilePath = findFileInlocatStorage(fileId); diff --git a/src/qTbot/src/public/qTbot/itelegrambot.h b/src/qTbot/src/public/qTbot/itelegrambot.h index c9ceb0b..300ec38 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.h +++ b/src/qTbot/src/public/qTbot/itelegrambot.h @@ -187,8 +187,13 @@ class QTBOT_EXPORT ITelegramBot : public IBot bool editSpecificMessage(const QVariant &messageId, const TelegramArgs& args); - [[nodiscard("do not forget to save shared pointer of file handler, because it's will not save inner bot object.")]] - QSharedPointer getFile(const QString& fileId, iFile::Type fileType = iFile::Type::Ram) override; + /** + * @brief getFile This method sent request to get a file by id. The files can be saved into local storage if the Type choosed as Local. + * @param fileId This is Telegram file id. + * @param fileType this is type of file. Depends of this argument future will be contains deffrent result if it is Local type then future will contains link to local file path else file source as bytes. + * @return futur with file source or path to file depends of type. + */ + QFuture getFile(const QString& fileId, iFile::Type fileType = iFile::Type::Ram) override; /** * @brief getFileMeta This method receive meta information of the file. diff --git a/src/qTbot/src/public/qTbot/virtualfile.cpp b/src/qTbot/src/public/qTbot/virtualfile.cpp deleted file mode 100644 index 35c8122..0000000 --- a/src/qTbot/src/public/qTbot/virtualfile.cpp +++ /dev/null @@ -1,46 +0,0 @@ -//# -//# 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 "virtualfile.h" - -namespace qTbot { - - -VirtualFile::VirtualFile(const QSharedPointer &replay): iFile(replay) { -} - -const QByteArray& VirtualFile::array() const { - return _array; -} - -iFile::Type VirtualFile::type() const { - return Type::Ram; -} - -void VirtualFile::handleReadReady() { - - _array.append(replay()->readAll()); - -} - -void VirtualFile::handleFinished() { - handleReadReady(); - iFile::handleFinished(); -} - -void VirtualFile::handleError(QNetworkReply::NetworkError error) { - iFile::handleError(error); - _array.clear(); - -} - -void VirtualFile::setArray(const QByteArray &newArray) { - _array = newArray; -} - - -} diff --git a/src/qTbot/src/public/qTbot/virtualfile.h b/src/qTbot/src/public/qTbot/virtualfile.h deleted file mode 100644 index 28c374a..0000000 --- a/src/qTbot/src/public/qTbot/virtualfile.h +++ /dev/null @@ -1,39 +0,0 @@ -//# -//# 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. -//# - -#ifndef VIRTUALFILE_H -#define VIRTUALFILE_H - -#include "ifile.h" - -namespace qTbot { - -/** - * @brief The VirtualFile class write and read data from the Ram. - */ -class QTBOT_EXPORT VirtualFile : public iFile -{ -public: - VirtualFile(const QSharedPointer& replay = nullptr); - - // iFile interface - const QByteArray &array() const; - Type type() const override; - - void setArray(const QByteArray &newArray); - -protected slots: - void handleReadReady() override; - void handleFinished() override; - void handleError(QNetworkReply::NetworkError error) override; - -private: - QByteArray _array; -}; - -} -#endif // VIRTUALFILE_H From 4479664879c8d46c72832bd9ccc595bcc94cb27c Mon Sep 17 00:00:00 2001 From: EndrII Date: Wed, 11 Dec 2024 00:03:44 +0100 Subject: [PATCH 08/14] remove deprecated code --- src/qTbot/src/public/qTbot/filewaiter.cpp | 34 --------- src/qTbot/src/public/qTbot/filewaiter.h | 43 ----------- src/qTbot/src/public/qTbot/ibot.h | 21 ++++-- src/qTbot/src/public/qTbot/itelegrambot.cpp | 81 +++++++++------------ src/qTbot/src/public/qTbot/itelegrambot.h | 10 +-- 5 files changed, 54 insertions(+), 135 deletions(-) delete mode 100644 src/qTbot/src/public/qTbot/filewaiter.cpp delete mode 100644 src/qTbot/src/public/qTbot/filewaiter.h diff --git a/src/qTbot/src/public/qTbot/filewaiter.cpp b/src/qTbot/src/public/qTbot/filewaiter.cpp deleted file mode 100644 index 72162f3..0000000 --- a/src/qTbot/src/public/qTbot/filewaiter.cpp +++ /dev/null @@ -1,34 +0,0 @@ -//# -//# 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 "filewaiter.h" -namespace qTbot { - -FileWaiter::FileWaiter() -{ - -} - -void FileWaiter::wait(const QSharedPointer &file) { - if (!file->isFinished()) { - auto address = reinterpret_cast(file.get()); - - _files[address] = file; - - - connect(file.get(), &qTbot::iFile::finishedChanged, this, &FileWaiter::handleFileFinished, - Qt::QueuedConnection); - } -} - -void FileWaiter::handleFileFinished() { - auto address = reinterpret_cast(sender()); - - _files.remove(address); - -} - -} diff --git a/src/qTbot/src/public/qTbot/filewaiter.h b/src/qTbot/src/public/qTbot/filewaiter.h deleted file mode 100644 index 4b0b9c3..0000000 --- a/src/qTbot/src/public/qTbot/filewaiter.h +++ /dev/null @@ -1,43 +0,0 @@ -//# -//# 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. -//# - - -#ifndef FILEWAITER_H -#define FILEWAITER_H - -#include "ifile.h" - -namespace qTbot { - -/** - * @brief The FileWaiter class. This is a simple storage for the shared pointer of files. - * All added files will be removed (shared object) after finish donwload or upload. - */ -class QTBOT_EXPORT FileWaiter: public QObject -{ - Q_OBJECT -public: - FileWaiter(); - - /** - * @brief wait This method add shared pointer of file in to local storage, and remove it from this when @a file change state to finish. - * @param file This is a processed file. - * @note The file will not added if the file alredey finished. - * @note This method not stop thread, it is just save a file until it is is progres - */ - void wait(const QSharedPointer& file); - -private slots: - void handleFileFinished(); - -private: - QHash> _files; - - -}; -} -#endif // FILEWAITER_H diff --git a/src/qTbot/src/public/qTbot/ibot.h b/src/qTbot/src/public/qTbot/ibot.h index e82a12c..835d1f5 100644 --- a/src/qTbot/src/public/qTbot/ibot.h +++ b/src/qTbot/src/public/qTbot/ibot.h @@ -13,12 +13,10 @@ #include "qTbot/iupdate.h" #include "qTbot/irequest.h" -#include "ifile.h" -#include "qfileinfo.h" - #include #include #include +#include #include #include @@ -39,6 +37,19 @@ class QTBOT_EXPORT IBot: public QObject IBot(); ~IBot(); + /** + * @brief The FileType enum is is file types, deffine how we should download a file - as a local object in file system or into virtual memory. + */ + enum FileType { + /// The Ram is a Virtual type of download files will save all file data into QFuture bytes array. + Ram, + + /// The Local file will saved in internal file storage. + /// This file type can use the filse system as cache. + /// and will doenload file with same id only one time. + Local + }; + /** * @brief login This method get bae information of the bot from remote server. * @param token This is token value for login @@ -75,10 +86,10 @@ class QTBOT_EXPORT IBot: public QObject * This function allows you to retrieve a file by its ID. * * @param fileId The ID of the file to retrieve. - * @param fileType This is a saving way, by Default will be used a iFile::Type::Ram + * @param fileType This is a saving way, by Default will be used a FileType::Ram * @return Returns true if the file retrieval operation was successfully initiated and false in case of an error. */ - virtual QSharedPointer getFile(const QString& fileId, iFile::Type fileType = iFile::Type::Ram) = 0; + virtual QFuture getFile(const QString& fileId, FileType fileType = Ram) = 0; /** * @brief send @a file . diff --git a/src/qTbot/src/public/qTbot/itelegrambot.cpp b/src/qTbot/src/public/qTbot/itelegrambot.cpp index 95db260..1be1214 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.cpp +++ b/src/qTbot/src/public/qTbot/itelegrambot.cpp @@ -7,13 +7,11 @@ #include "itelegrambot.h" #include "qTbot/messages/telegramupdateanswer.h" -#include "file.h" #include "requests/telegrammdownloadfile.h" #include "qdir.h" #include "requests/telegramsendcontact.h" #include "requests/telegramsenddocument.h" #include "httpexception.h" -#include "virtualfile.h" #include #include @@ -283,7 +281,7 @@ bool ITelegramBot::sendSpecificMessageWithKeyboard(const TelegramArgs& args, return sendSpecificMessage(args, prepareKeyboard(autoResizeKeyboard, onTimeKeyboard, keyboard)); } -QFuture ITelegramBot::getFile(const QString &fileId, iFile::Type fileType) { +QFuture ITelegramBot::getFile(const QString &fileId, FileType fileType) { if (fileId.isEmpty()) { @@ -293,24 +291,26 @@ QFuture ITelegramBot::getFile(const QString &fileId, iFile::Type fil auto localFilePath = findFileInlocatStorage(fileId); if (!localFilePath.isEmpty()) { + QPromise fileDataResult; - if (fileType == iFile::Ram) { + if (fileType == FileType::Ram) { QFile localFile(localFilePath); if (localFile.open(QIODevice::ReadOnly)) { - auto&& virtualFile = QSharedPointer::create(nullptr); - virtualFile->setArray(localFile.readAll()); + QPromise fileDataResult; + fileDataResult.addResult(localFile.readAll()); localFile.close(); - - result = virtualFile; } - } else if (fileType == iFile::Local) { - result = QSharedPointer::create(nullptr, localFilePath); + } else if (fileType == FileType::Local) { + fileDataResult.addResult(localFilePath.toUtf8()); } - result->setDownloadProgress(1); - result->setFinished(true); - return result; + fileDataResult.setProgressRange(0,1); + fileDataResult.setProgressValue(1); + + fileDataResult.finish(); + + return fileDataResult.future(); } auto&& metaInfo = getFileInfoByUniqueId(fileId); @@ -325,45 +325,40 @@ QFuture ITelegramBot::getFile(const QString &fileId, iFile::Type fil if (localFilePath.isEmpty()) - return result; - - QFuture &&replay = sendRequest(msg); - if (replay.isValid()) { - // here i must be receive responce and prepare new request to file from the call back function. - if (fileType == iFile::Ram) { - result = QSharedPointer::create(replay); - } else if (fileType == iFile::Local) { - result = QSharedPointer::create(replay, localFilePath); - } + return {}; + + QFuture replay; + if (fileType == FileType::Ram) { + replay = sendRequest(msg); + } else { + replay = sendRequest(msg, localFilePath); } - return result; + return replay; } } - - if (fileType == iFile::Ram) { - result = QSharedPointer::create(); - } else if (fileType == iFile::Local) { - result = QSharedPointer::create(localFilePath); - } - - auto&& future = getFileMeta(fileId, result.toWeakRef()); + auto longWay = QSharedPointer>::create(); + auto&& future = getFileMeta(fileId); if (!future.isValid()) { - return nullptr; + return {}; } - return result; + future.then([this, fileId, fileType, longWay](const QByteArray& header){ + handleFileHeader(header); + + getFile(fileId, fileType).then([longWay](const QByteArray& data){ + longWay->addResult(data); + }); + }); + + return longWay->future(); } -QFuture ITelegramBot::getFileMeta(const QString &fileId, const QWeakPointer& receiver) { +QFuture ITelegramBot::getFileMeta(const QString &fileId) { auto msg = QSharedPointer::create(fileId); auto && future = sendRequest(msg); if (future.isValid()) { - future.then([this, receiver](const QByteArray&data){ - handleFileHeader(data, receiver); - }); - return future; } @@ -580,8 +575,7 @@ void ITelegramBot::handleLoginErr(QNetworkReply::NetworkError err) { } } -void ITelegramBot::handleFileHeader(const QByteArray& header, - const QWeakPointer& receiver) { +void ITelegramBot::handleFileHeader(const QByteArray& header) { auto&& ansver = makeMesasge(header); if (!ansver->isValid()) { @@ -592,11 +586,6 @@ void ITelegramBot::handleFileHeader(const QByteArray& header, auto &&fileMetaInfo = makeMesasge(ansver->result().toObject()); _filesMetaInfo.insert(fileMetaInfo->fileId(), fileMetaInfo); - - if (auto&& sharedPtr = receiver.lock()) { - auto&& downloadRequest = QSharedPointer::create(fileMetaInfo->takePath()); - sharedPtr->setDownloadRequest(sendRequest(downloadRequest)); - } } QString ITelegramBot::findFileInlocatStorage(const QString &fileId) const { diff --git a/src/qTbot/src/public/qTbot/itelegrambot.h b/src/qTbot/src/public/qTbot/itelegrambot.h index 300ec38..873f9b1 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.h +++ b/src/qTbot/src/public/qTbot/itelegrambot.h @@ -193,17 +193,14 @@ class QTBOT_EXPORT ITelegramBot : public IBot * @param fileType this is type of file. Depends of this argument future will be contains deffrent result if it is Local type then future will contains link to local file path else file source as bytes. * @return futur with file source or path to file depends of type. */ - QFuture getFile(const QString& fileId, iFile::Type fileType = iFile::Type::Ram) override; + QFuture getFile(const QString& fileId, FileType fileType = FileType::Ram) override; /** * @brief getFileMeta This method receive meta information of the file. * @param fileId This is id of the file. - * @param receiver this is wrapper of the file. Set to nullptr if you no need to wait a physical file. * @return future objectl with result. */ - - QFuture getFileMeta(const QString& fileId, - const QWeakPointer &receiver = {nullptr}); + QFuture getFileMeta(const QString& fileId); bool sendFile( const QFileInfo& file, const QVariant& chatId) override; @@ -397,8 +394,7 @@ class QTBOT_EXPORT ITelegramBot : public IBot private slots: void handleLogin(const QByteArray &ansver); void handleLoginErr(QNetworkReply::NetworkError err); - void handleFileHeader(const QByteArray &header, - const QWeakPointer &receiver); + void handleFileHeader(const QByteArray &header); private: From 5a874398b57b9b57cb347b49cac42603848542e2 Mon Sep 17 00:00:00 2001 From: EndrII Date: Wed, 11 Dec 2024 21:47:17 +0100 Subject: [PATCH 09/14] fix build of library --- src/example/main.cpp | 20 ++++++++++++++------ src/qTbot/src/public/qTbot/ibot.cpp | 2 ++ src/qTbot/src/public/qTbot/itelegrambot.cpp | 3 ++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/example/main.cpp b/src/example/main.cpp index 2000b4e..2c2301e 100644 --- a/src/example/main.cpp +++ b/src/example/main.cpp @@ -26,8 +26,7 @@ int main(int argc, char *argv[]) { srand(time(0)); - QList > filesStack; - QObject::connect(&bot, &qTbot::TelegramRestBot::sigReceiveUpdate, [&bot, &filesStack](auto){ + QObject::connect(&bot, &qTbot::TelegramRestBot::sigReceiveUpdate, [&bot](auto){ while(auto&& update = bot.takeNextUnreadUpdate()) { if (auto&& tupdate = update.dynamicCast()) { @@ -36,15 +35,21 @@ int main(int argc, char *argv[]) { if (auto&& tmsg = tupdate->message()) { if (tmsg->contains(tmsg->Document)) { - filesStack.push_back(bot.getFile(tmsg->documents()->fileId(), qTbot::iFile::Local)); + bot.getFile(tmsg->documents()->fileId(), qTbot::ITelegramBot::Local).then([](const QByteArray& path){ + qInfo() << "fole save into " << path; + }); } if (tmsg->contains(tmsg->Image)) { - filesStack.push_back(bot.getFile(tmsg->image()->fileId(), qTbot::iFile::Local)); + bot.getFile(tmsg->image()->fileId(), qTbot::ITelegramBot::Local).then([](const QByteArray& path){ + qInfo() << "fole save into " << path; + }); } if (tmsg->contains(tmsg->Audio)) { - filesStack.push_back(bot.getFile(tmsg->audio()->fileId(), qTbot::iFile::Local)); + bot.getFile(tmsg->audio()->fileId(), qTbot::ITelegramBot::Local).then([](const QByteArray& path){ + qInfo() << "fole save into " << path; + }); } bot.sendSpecificMessageWithKeyboard(qTbot::TelegramArgs{tmsg->chatId(), "I see it", tmsg->messageId()}, @@ -78,6 +83,9 @@ int main(int argc, char *argv[]) { } }); - bot.login("6349356184:AAFotw9EC46sgAQrkGQ_jeHPyv3EAapZXcM"); + if (!bot.login("6349356184:AAFotw9EC46sgAQrkGQ_jeHPyv3EAapZXcM")) { + qCritical() << "failed to login!"; + return 1; + } return app.exec(); } diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index 9c1ceb6..53000ac 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -102,6 +102,7 @@ IBot::sendRequest(const QSharedPointer &rquest) { } auto&& promise = QSharedPointer>::create(); + promise->start(); networkReplay->connect(networkReplay, &QNetworkReply::finished, [promise](){ promise->finish(); @@ -144,6 +145,7 @@ QFuture IBot::sendRequest(const QSharedPointer &rquest, co } auto&& promise = QSharedPointer>::create(); + promise->start(); networkReplay->connect(networkReplay, &QNetworkReply::finished, [promise, pathToResult](){ diff --git a/src/qTbot/src/public/qTbot/itelegrambot.cpp b/src/qTbot/src/public/qTbot/itelegrambot.cpp index 1be1214..7ec1b97 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.cpp +++ b/src/qTbot/src/public/qTbot/itelegrambot.cpp @@ -296,7 +296,6 @@ QFuture ITelegramBot::getFile(const QString &fileId, FileType fileTy if (fileType == FileType::Ram) { QFile localFile(localFilePath); if (localFile.open(QIODevice::ReadOnly)) { - QPromise fileDataResult; fileDataResult.addResult(localFile.readAll()); localFile.close(); } @@ -339,6 +338,8 @@ QFuture ITelegramBot::getFile(const QString &fileId, FileType fileTy } auto longWay = QSharedPointer>::create(); + longWay->start(); + auto&& future = getFileMeta(fileId); if (!future.isValid()) { return {}; From ea37b442e66380a05f1971614519562226483893 Mon Sep 17 00:00:00 2001 From: EndrII Date: Sat, 14 Dec 2024 13:07:49 +0100 Subject: [PATCH 10/14] move to qfuture --- CMakeLists.txt | 2 +- src/example/main.cpp | 22 +++++++--- src/qTbot/src/public/qTbot/httpexception.cpp | 5 ++- src/qTbot/src/public/qTbot/httpexception.h | 10 +++-- src/qTbot/src/public/qTbot/ibot.cpp | 40 +++++++++---------- .../src/public/qTbot/internalexception.cpp | 28 +++++++++++++ .../src/public/qTbot/internalexception.h | 39 ++++++++++++++++++ src/qTbot/src/public/qTbot/itelegrambot.cpp | 16 +++++++- 8 files changed, 128 insertions(+), 34 deletions(-) create mode 100644 src/qTbot/src/public/qTbot/internalexception.cpp create mode 100644 src/qTbot/src/public/qTbot/internalexception.h diff --git a/CMakeLists.txt b/CMakeLists.txt index acaf411..85c7c2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ find_package(Qt6 COMPONENTS Test QUIET) include(submodules/CMake/QuasarApp.cmake) updateGitVars() -set(QTBOT_VERSION "0.${GIT_COMMIT_COUNT}.${GIT_COMMIT_HASH}") +set(QTBOT_VERSION "0.2.${GIT_COMMIT_COUNT}.${GIT_COMMIT_HASH}") set(QTBOT_PACKAGE_ID "quasarapp.core.qTbot") option(QTBOT_TESTS "This option disables or enables tests of the ${PROJECT_NAME} project" ON) diff --git a/src/example/main.cpp b/src/example/main.cpp index 2c2301e..f338866 100644 --- a/src/example/main.cpp +++ b/src/example/main.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -36,20 +37,29 @@ int main(int argc, char *argv[]) { if (auto&& tmsg = tupdate->message()) { if (tmsg->contains(tmsg->Document)) { bot.getFile(tmsg->documents()->fileId(), qTbot::ITelegramBot::Local).then([](const QByteArray& path){ - qInfo() << "fole save into " << path; - }); + qInfo() << "file save into " << path; + }).onFailed([](const std::exception& exception){ + + qCritical() << "exception :" << exception.what(); + }); } if (tmsg->contains(tmsg->Image)) { bot.getFile(tmsg->image()->fileId(), qTbot::ITelegramBot::Local).then([](const QByteArray& path){ - qInfo() << "fole save into " << path; - }); + qInfo() << "file save into " << path; + }).onFailed([](const std::exception& exception){ + + qCritical() << "exception :" << exception.what(); + });; } if (tmsg->contains(tmsg->Audio)) { bot.getFile(tmsg->audio()->fileId(), qTbot::ITelegramBot::Local).then([](const QByteArray& path){ - qInfo() << "fole save into " << path; - }); + qInfo() << "file save into " << path; + }).onFailed([](const std::exception& exception){ + + qCritical() << "exception :" << exception.what(); + });; } bot.sendSpecificMessageWithKeyboard(qTbot::TelegramArgs{tmsg->chatId(), "I see it", tmsg->messageId()}, diff --git a/src/qTbot/src/public/qTbot/httpexception.cpp b/src/qTbot/src/public/qTbot/httpexception.cpp index 9d18db6..1c6fd24 100644 --- a/src/qTbot/src/public/qTbot/httpexception.cpp +++ b/src/qTbot/src/public/qTbot/httpexception.cpp @@ -7,6 +7,8 @@ #include "httpexception.h" +namespace qTbot { + HttpException::HttpException(QNetworkReply::NetworkError code, const QByteArray &erroString) { @@ -16,7 +18,7 @@ HttpException::HttpException(QNetworkReply::NetworkError code, _errText = erroString; } else { - _errText = QByteArray("Http request fonoshed with code: "). + _errText = QByteArray("Http request finished with code: "). append(QString::number(code).toLatin1()); } } @@ -37,3 +39,4 @@ QException *HttpException::clone() const { QNetworkReply::NetworkError HttpException::code() const { return _code; } +} diff --git a/src/qTbot/src/public/qTbot/httpexception.h b/src/qTbot/src/public/qTbot/httpexception.h index 44038da..e1d7e0a 100644 --- a/src/qTbot/src/public/qTbot/httpexception.h +++ b/src/qTbot/src/public/qTbot/httpexception.h @@ -12,6 +12,8 @@ #ifndef HTTPEXCEPTION_H #define HTTPEXCEPTION_H +namespace qTbot { + /** * @brief The HttpException class is base exaption that will raise on all errors of the HTTP protocol, */ @@ -22,12 +24,12 @@ class HttpException: public QException // exception interface public: - const char *what() const noexcept; + const char *what() const noexcept override; // QException interface public: - void raise() const; - QException *clone() const; + void raise() const override; + QException *clone() const override; QNetworkReply::NetworkError code() const; @@ -35,5 +37,5 @@ class HttpException: public QException QByteArray _errText; QNetworkReply::NetworkError _code; }; - +} #endif // HTTPEXCEPTION_H diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index 53000ac..a4b3334 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -104,17 +104,14 @@ IBot::sendRequest(const QSharedPointer &rquest) { auto&& promise = QSharedPointer>::create(); promise->start(); - networkReplay->connect(networkReplay, &QNetworkReply::finished, [promise](){ - promise->finish(); - }); - - networkReplay->connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise](){ - promise->addResult(networkReplay->readAll()); - }); + networkReplay->connect(networkReplay, &QNetworkReply::finished, [networkReplay, promise](){ + if (networkReplay->error() == QNetworkReply::NoError) { + promise->addResult(networkReplay->readAll()); + promise->finish(); - networkReplay->connect(networkReplay, &QNetworkReply::errorOccurred, [networkReplay, promise](QNetworkReply::NetworkError ){ - promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1())); - promise->finish(); + } else { + promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1() + networkReplay->readAll())); + } }); auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){ @@ -132,9 +129,9 @@ IBot::sendRequest(const QSharedPointer &rquest) { } QFuture IBot::sendRequest(const QSharedPointer &rquest, const QString &pathToResult) { - auto&& file = QSharedPointer::create(); + auto&& file = QSharedPointer::create(pathToResult); - if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) { + if (!file->open(QIODeviceBase::WriteOnly | QIODevice::Truncate)) { qCritical() << "Fail to wrote data into " << pathToResult; return {}; } @@ -147,19 +144,22 @@ QFuture IBot::sendRequest(const QSharedPointer &rquest, co auto&& promise = QSharedPointer>::create(); promise->start(); - networkReplay->connect(networkReplay, &QNetworkReply::finished, [promise, pathToResult](){ + networkReplay->connect(networkReplay, &QNetworkReply::finished, [promise, networkReplay, pathToResult](){ + + if (networkReplay->error() == QNetworkReply::NoError) { + promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1())); + } else { + promise->addResult(pathToResult.toUtf8()); // wil not work with UTF 8 path names + promise->finish(); + } - promise->addResult(pathToResult.toUtf8()); // wil not work with UTF 8 path names - promise->finish(); }); networkReplay->connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise, pathToResult, file](){ - file->write(networkReplay->readAll()); - }); + if (networkReplay->error() == QNetworkReply::NoError) { + file->write(networkReplay->readAll()); + } - networkReplay->connect(networkReplay, &QNetworkReply::errorOccurred, [networkReplay, promise](QNetworkReply::NetworkError ){ - promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1())); - promise->finish(); }); auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){ diff --git a/src/qTbot/src/public/qTbot/internalexception.cpp b/src/qTbot/src/public/qTbot/internalexception.cpp new file mode 100644 index 0000000..5a22334 --- /dev/null +++ b/src/qTbot/src/public/qTbot/internalexception.cpp @@ -0,0 +1,28 @@ +//# +//# 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 "internalexception.h" +namespace qTbot { + + +InternalException::InternalException(const QByteArray &erroString) { + _errText = erroString; + +} + +const char *InternalException::what() const noexcept { + return _errText.constData(); +} + +void InternalException::raise() const { + throw *this; +} + +QException *InternalException::clone() const { + return new InternalException(_errText); +} +} diff --git a/src/qTbot/src/public/qTbot/internalexception.h b/src/qTbot/src/public/qTbot/internalexception.h new file mode 100644 index 0000000..0b05ad8 --- /dev/null +++ b/src/qTbot/src/public/qTbot/internalexception.h @@ -0,0 +1,39 @@ +//# +//# 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 +#include + +#ifndef INTERNALEXCEPTION_H +#define INTERNALEXCEPTION_H + + +namespace qTbot { + +/** + * @brief The InternalException class contais string value to describe what happened. + */ +class InternalException: public QException +{ + // exception interface +public: + InternalException(const QByteArray& erroString = {}); + + const char *what() const noexcept override; + + // QException interface +public: + void raise() const override; + QException *clone() const override; + +private: + QByteArray _errText; +}; +} +#endif // INTERNALEXCEPTION_H + + diff --git a/src/qTbot/src/public/qTbot/itelegrambot.cpp b/src/qTbot/src/public/qTbot/itelegrambot.cpp index 7ec1b97..752a05c 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.cpp +++ b/src/qTbot/src/public/qTbot/itelegrambot.cpp @@ -12,6 +12,7 @@ #include "requests/telegramsendcontact.h" #include "requests/telegramsenddocument.h" #include "httpexception.h" +#include "internalexception.h" #include #include @@ -348,10 +349,21 @@ QFuture ITelegramBot::getFile(const QString &fileId, FileType fileTy future.then([this, fileId, fileType, longWay](const QByteArray& header){ handleFileHeader(header); - getFile(fileId, fileType).then([longWay](const QByteArray& data){ + auto&& future = getFile(fileId, fileType); + + if (!future.isValid()) { + longWay->setException(InternalException("Failed to wrote file into internal cache!")); + return; + }; + + future.then([longWay](const QByteArray& data){ longWay->addResult(data); }); - }); + + + }).onFailed([longWay](const QException& exep){ + longWay->setException(exep); + }); return longWay->future(); } From 5390532c5d5d43fcc0e2ecedea5a56f591c9cec0 Mon Sep 17 00:00:00 2001 From: EndrII Date: Sat, 14 Dec 2024 14:50:47 +0100 Subject: [PATCH 11/14] added queries --- src/qTbot/src/public/qTbot/ibot.cpp | 69 ++++++++++++++++++++--------- src/qTbot/src/public/qTbot/ibot.h | 42 ++++++++++++++++++ 2 files changed, 90 insertions(+), 21 deletions(-) diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index a4b3334..cd58909 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -92,9 +92,55 @@ QNetworkReply* IBot::sendRquestImpl(const QSharedPointer &rquest) { return networkReplay; } +int IBot::reqestLimitPerSecond() const { + return _reqestLimitPerSecond; +} + +void IBot::setReqestLimitPerSecond(int newReqestLimitPerSecond) { + _reqestLimitPerSecond = newReqestLimitPerSecond; +} + QFuture IBot::sendRequest(const QSharedPointer &rquest) { + auto&& responce = QSharedPointer>::create(); + responce->start(); + _requestQueue.push_back(RequestData{rquest, "", responce}); + + return responce->future(); +} + +QFuture +IBot::sendRequest(const QSharedPointer &rquest, + const QString &pathToResult) { + auto&& responce = QSharedPointer>::create(); + responce->start(); + _requestQueue.push_back(RequestData{rquest, pathToResult, responce}); + + return responce->future(); + +} + +void IBot::markUpdateAsProcessed(const QSharedPointer &message) { + _notProcessedUpdates.remove(message->updateId()); +} +void IBot::markUpdateAsUnprocessed(const QSharedPointer &message) { + return markUpdateAsUnprocessed(message->updateId()); +} + +void IBot::markUpdateAsUnprocessed(unsigned long long messageID) { + _processed.remove(messageID); +} + +QString IBot::defaultFileStorageLocation() const { + return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); +} + +void IBot::handleIncomeNewUpdate(const QSharedPointer & message) { + emit sigReceiveUpdate(message); +} + +QFuture IBot::sendRequestPrivate(const QSharedPointer &rquest) { QNetworkReply* networkReplay = sendRquestImpl(rquest); if (!networkReplay) { @@ -128,7 +174,8 @@ IBot::sendRequest(const QSharedPointer &rquest) { return promise->future(); } -QFuture IBot::sendRequest(const QSharedPointer &rquest, const QString &pathToResult) { +QFuture IBot::sendRequestPrivate(const QSharedPointer &rquest, + const QString &pathToResult) { auto&& file = QSharedPointer::create(pathToResult); if (!file->open(QIODeviceBase::WriteOnly | QIODevice::Truncate)) { @@ -176,26 +223,6 @@ QFuture IBot::sendRequest(const QSharedPointer &rquest, co return promise->future(); } -void IBot::markUpdateAsProcessed(const QSharedPointer &message) { - _notProcessedUpdates.remove(message->updateId()); -} - -void IBot::markUpdateAsUnprocessed(const QSharedPointer &message) { - return markUpdateAsUnprocessed(message->updateId()); -} - -void IBot::markUpdateAsUnprocessed(unsigned long long messageID) { - _processed.remove(messageID); -} - -QString IBot::defaultFileStorageLocation() const { - return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); -} - -void IBot::handleIncomeNewUpdate(const QSharedPointer & message) { - emit sigReceiveUpdate(message); -} - QSet IBot::processed() const { return _processed; } diff --git a/src/qTbot/src/public/qTbot/ibot.h b/src/qTbot/src/public/qTbot/ibot.h index 835d1f5..1e6af4a 100644 --- a/src/qTbot/src/public/qTbot/ibot.h +++ b/src/qTbot/src/public/qTbot/ibot.h @@ -50,6 +50,27 @@ class QTBOT_EXPORT IBot: public QObject Local }; + /** + * @brief The RequestData class is simple wrapper of request object with path of responce. + * If Path of responce is empty then responce will saved in RAM. + */ + struct RequestData { + /** + * @brief request saved request object. + */ + QSharedPointer request; + + /** + * @brief responceFilePath path to responce. + */ + QString responceFilePath = ""; + + /** + * @brief responce This is promise to responce of this requests that will sets back. + */ + QSharedPointer> responce; + }; + /** * @brief login This method get bae information of the bot from remote server. * @param token This is token value for login @@ -145,6 +166,18 @@ class QTBOT_EXPORT IBot: public QObject */ virtual void setProcessed(const QSet &newProcessed); + /** + * @brief reqestLimitPerSecond this is request performence limitation. by default is 20 requests per second + * @return + */ + int reqestLimitPerSecond() const; + + /** + * @brief setReqestLimitPerSecond this method sets new limitation of bot performance. + * @param newReqestLimitPerSecond this is a new value of performance. + */ + void setReqestLimitPerSecond(int newReqestLimitPerSecond); + protected: /** @@ -254,6 +287,13 @@ class QTBOT_EXPORT IBot: public QObject void sigStopRequire(); private: + QFuture + sendRequestPrivate(const QSharedPointer& rquest); + + QFuture + sendRequestPrivate(const QSharedPointer& rquest, + const QString& pathToResult); + QNetworkReply *sendRquestImpl(const QSharedPointer &rquest); QByteArray _token; @@ -261,6 +301,8 @@ class QTBOT_EXPORT IBot: public QObject QMap> _notProcessedUpdates; QSet _processed; QNetworkAccessManager *_manager = nullptr; + int _reqestLimitPerSecond = 20; + QList _requestQueue; }; From f2cf4b0442f33e19f655089482434a1a34d45e3b Mon Sep 17 00:00:00 2001 From: EndrII Date: Sat, 14 Dec 2024 18:39:06 +0100 Subject: [PATCH 12/14] added parallel connection limit --- src/example/main.cpp | 57 +++++++++++-------- src/qTbot/src/public/qTbot/ibot.cpp | 88 +++++++++++++++++++++-------- src/qTbot/src/public/qTbot/ibot.h | 23 ++++++-- 3 files changed, 114 insertions(+), 54 deletions(-) diff --git a/src/example/main.cpp b/src/example/main.cpp index f338866..8ed0639 100644 --- a/src/example/main.cpp +++ b/src/example/main.cpp @@ -24,6 +24,7 @@ int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); qTbot::TelegramRestBot bot; + bot.setReqestLimitPerSecond(10); srand(time(0)); @@ -62,30 +63,38 @@ int main(int argc, char *argv[]) { });; } - bot.sendSpecificMessageWithKeyboard(qTbot::TelegramArgs{tmsg->chatId(), "I see it", tmsg->messageId()}, - {{{"test_button", [tmsg, &bot](const QString& queryId, const QVariant& msgId){ - static int index = 0; - - auto&& args = qTbot::TelegramArgs{tmsg->chatId(), - "I see it. Presed count: " + QString::number(index++), - tmsg->messageId(), - "", - false, - queryId}; - - auto&& keyboard = qTbot::KeyboardOnMessage{ - {{"test_button", [](auto , auto ){}}, - {"test_button 2", [](auto , auto ){}}}}; - - bot.editSpecificMessageWithKeyboard(msgId, - args, - keyboard - ); - }}}}); - - bot.sendSpecificMessageWithKeyboard(qTbot::TelegramArgs{tmsg->chatId(), "I see it", tmsg->messageId()}, - {{{"test_button"}, - {"test_button"},}}, true, true); + if (tmsg->text() == "spam") { + for (int i = 0 ; i < 1000; i++) { + bot.sendMessage(tmsg->chatId(), QString(" message N %0").arg(i)); + } + } else { + bot.sendSpecificMessageWithKeyboard(qTbot::TelegramArgs{tmsg->chatId(), "I see it", tmsg->messageId()}, + {{{"test_button", [tmsg, &bot](const QString& queryId, const QVariant& msgId){ + static int index = 0; + + auto&& args = qTbot::TelegramArgs{tmsg->chatId(), + "I see it. Presed count: " + QString::number(index++), + tmsg->messageId(), + "", + false, + queryId}; + + auto&& keyboard = qTbot::KeyboardOnMessage{ + {{"test_button", [](auto , auto ){}}, + {"test_button 2", [](auto , auto ){}}}}; + + bot.editSpecificMessageWithKeyboard(msgId, + args, + keyboard + ); + }}}}); + + bot.sendSpecificMessageWithKeyboard(qTbot::TelegramArgs{tmsg->chatId(), "I see it", tmsg->messageId()}, + {{{"test_button"}, + {"test_button"},}}, true, true); + } + + } } diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index cd58909..9f6d70c 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -17,6 +17,10 @@ namespace qTbot { IBot::IBot() { _manager = new QNetworkAccessManager(); _manager->setAutoDeleteReplies(true); + _requestExecutor = new QTimer(this); + _requestExecutor->setInterval(1000 / 20); // 20 times per second. + + connect(_requestExecutor, &QTimer::timeout, this , &IBot::handleEcxecuteRequest); } IBot::~IBot() { @@ -92,12 +96,25 @@ QNetworkReply* IBot::sendRquestImpl(const QSharedPointer &rquest) { return networkReplay; } +int IBot::parallelActiveNetworkThreads() const { + return _parallelActiveNetworkThreads; +} + +void IBot::setParallelActiveNetworkThreads(int newParallelActiveNetworkThreads) { + _parallelActiveNetworkThreads = newParallelActiveNetworkThreads; +} + +void IBot::setCurrentParallelActiveNetworkThreads(int newParallelActiveNetworkThreads) { + _currentParallelActiveNetworkThreads = newParallelActiveNetworkThreads; + qDebug () << "current network active requests count : " << _currentParallelActiveNetworkThreads; +} + int IBot::reqestLimitPerSecond() const { - return _reqestLimitPerSecond; + return _requestExecutor->interval() * 1000; } void IBot::setReqestLimitPerSecond(int newReqestLimitPerSecond) { - _reqestLimitPerSecond = newReqestLimitPerSecond; + _requestExecutor->setInterval(1000 / newReqestLimitPerSecond); } QFuture @@ -106,6 +123,8 @@ IBot::sendRequest(const QSharedPointer &rquest) { responce->start(); _requestQueue.push_back(RequestData{rquest, "", responce}); + _requestExecutor->start(); + return responce->future(); } @@ -116,6 +135,8 @@ IBot::sendRequest(const QSharedPointer &rquest, responce->start(); _requestQueue.push_back(RequestData{rquest, pathToResult, responce}); + _requestExecutor->start(); + return responce->future(); } @@ -140,17 +161,37 @@ void IBot::handleIncomeNewUpdate(const QSharedPointer & message) { emit sigReceiveUpdate(message); } -QFuture IBot::sendRequestPrivate(const QSharedPointer &rquest) { +void IBot::handleEcxecuteRequest() { + if (!_requestQueue.size()) { + _requestExecutor->stop(); + return; + } + + if (_currentParallelActiveNetworkThreads > _parallelActiveNetworkThreads) { + return; + } + + auto&& requestData = _requestQueue.takeFirst(); + + if (requestData.responceFilePath.size()) { + sendRequestPrivate(requestData.request, requestData.responceFilePath, requestData.responce); + return; + } + + sendRequestPrivate(requestData.request, requestData.responce); +} + +void IBot::sendRequestPrivate(const QSharedPointer &rquest, + const QSharedPointer > &promise) { QNetworkReply* networkReplay = sendRquestImpl(rquest); if (!networkReplay) { - return {}; + return; } - auto&& promise = QSharedPointer>::create(); - promise->start(); + setParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1); - networkReplay->connect(networkReplay, &QNetworkReply::finished, [networkReplay, promise](){ + connect(networkReplay, &QNetworkReply::finished, [this, networkReplay, promise](){ if (networkReplay->error() == QNetworkReply::NoError) { promise->addResult(networkReplay->readAll()); promise->finish(); @@ -158,6 +199,9 @@ QFuture IBot::sendRequestPrivate(const QSharedPointer &rqu } else { promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1() + networkReplay->readAll())); } + + setParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1); + }); auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){ @@ -168,30 +212,27 @@ QFuture IBot::sendRequestPrivate(const QSharedPointer &rqu promise->setProgressValue(bytesCurrent); }; - networkReplay->connect(networkReplay, &QNetworkReply::downloadProgress, setProggress); - networkReplay->connect(networkReplay, &QNetworkReply::uploadProgress, setProggress); - - return promise->future(); + connect(networkReplay, &QNetworkReply::downloadProgress, setProggress); + connect(networkReplay, &QNetworkReply::uploadProgress, setProggress); } -QFuture IBot::sendRequestPrivate(const QSharedPointer &rquest, - const QString &pathToResult) { +void IBot::sendRequestPrivate(const QSharedPointer &rquest, + const QString &pathToResult, + const QSharedPointer> & promise) { auto&& file = QSharedPointer::create(pathToResult); if (!file->open(QIODeviceBase::WriteOnly | QIODevice::Truncate)) { qCritical() << "Fail to wrote data into " << pathToResult; - return {}; + return; } QNetworkReply* networkReplay = sendRquestImpl(rquest); if (!networkReplay) { - return {}; + return; } - auto&& promise = QSharedPointer>::create(); - promise->start(); - - networkReplay->connect(networkReplay, &QNetworkReply::finished, [promise, networkReplay, pathToResult](){ + setParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1); + connect(networkReplay, &QNetworkReply::finished, [this, promise, networkReplay, pathToResult](){ if (networkReplay->error() == QNetworkReply::NoError) { promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1())); @@ -199,10 +240,10 @@ QFuture IBot::sendRequestPrivate(const QSharedPointer &rqu promise->addResult(pathToResult.toUtf8()); // wil not work with UTF 8 path names promise->finish(); } - + setParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1); }); - networkReplay->connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise, pathToResult, file](){ + connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise, pathToResult, file](){ if (networkReplay->error() == QNetworkReply::NoError) { file->write(networkReplay->readAll()); } @@ -217,10 +258,9 @@ QFuture IBot::sendRequestPrivate(const QSharedPointer &rqu promise->setProgressValue(bytesCurrent); }; - networkReplay->connect(networkReplay, &QNetworkReply::downloadProgress, setProggress); - networkReplay->connect(networkReplay, &QNetworkReply::uploadProgress, setProggress); + connect(networkReplay, &QNetworkReply::downloadProgress, setProggress); + connect(networkReplay, &QNetworkReply::uploadProgress, setProggress); - return promise->future(); } QSet IBot::processed() const { diff --git a/src/qTbot/src/public/qTbot/ibot.h b/src/qTbot/src/public/qTbot/ibot.h index 1e6af4a..2bcb279 100644 --- a/src/qTbot/src/public/qTbot/ibot.h +++ b/src/qTbot/src/public/qTbot/ibot.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -178,6 +179,9 @@ class QTBOT_EXPORT IBot: public QObject */ void setReqestLimitPerSecond(int newReqestLimitPerSecond); + int parallelActiveNetworkThreads() const; + void setParallelActiveNetworkThreads(int newParallelActiveNetworkThreads); + protected: /** @@ -286,13 +290,17 @@ class QTBOT_EXPORT IBot: public QObject */ void sigStopRequire(); +private slots: + void handleEcxecuteRequest(); private: - QFuture - sendRequestPrivate(const QSharedPointer& rquest); + void setCurrentParallelActiveNetworkThreads(int newParallelActiveNetworkThreads); - QFuture - sendRequestPrivate(const QSharedPointer& rquest, - const QString& pathToResult); + void sendRequestPrivate(const QSharedPointer& rquest, + const QSharedPointer> & promiseResult); + + void sendRequestPrivate(const QSharedPointer& rquest, + const QString& pathToResult, + const QSharedPointer > &promiseResult); QNetworkReply *sendRquestImpl(const QSharedPointer &rquest); @@ -301,8 +309,11 @@ class QTBOT_EXPORT IBot: public QObject QMap> _notProcessedUpdates; QSet _processed; QNetworkAccessManager *_manager = nullptr; - int _reqestLimitPerSecond = 20; + QTimer* _requestExecutor = nullptr; QList _requestQueue; + int _currentParallelActiveNetworkThreads = 0; + int _parallelActiveNetworkThreads = 10; + }; From f8c04492fae1101f84257f592f05808b8123f7bf Mon Sep 17 00:00:00 2001 From: EndrII Date: Sun, 15 Dec 2024 00:52:45 +0100 Subject: [PATCH 13/14] added priority --- src/example/main.cpp | 2 +- .../private/requests/telegramgetupdate.cpp | 1 + .../src/private/requests/telegramsendmsg.cpp | 1 + src/qTbot/src/public/qTbot/ibot.cpp | 16 +++++++------ src/qTbot/src/public/qTbot/ibot.h | 6 ++--- src/qTbot/src/public/qTbot/irequest.cpp | 8 +++++++ src/qTbot/src/public/qTbot/irequest.h | 23 +++++++++++++++++++ src/qTbot/src/public/qTbot/itelegrambot.cpp | 12 +++++++--- src/qTbot/src/public/qTbot/itelegrambot.h | 4 +++- src/qTbot/src/public/qTbot/telegramargs.cpp | 4 +++- src/qTbot/src/public/qTbot/telegramargs.h | 6 ++++- 11 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/example/main.cpp b/src/example/main.cpp index 8ed0639..a4234ce 100644 --- a/src/example/main.cpp +++ b/src/example/main.cpp @@ -65,7 +65,7 @@ int main(int argc, char *argv[]) { if (tmsg->text() == "spam") { for (int i = 0 ; i < 1000; i++) { - bot.sendMessage(tmsg->chatId(), QString(" message N %0").arg(i)); + bot.sendMessage(tmsg->chatId(), QString(" message N %0").arg(i), qTbot::iRequest::LowPriority); } } else { bot.sendSpecificMessageWithKeyboard(qTbot::TelegramArgs{tmsg->chatId(), "I see it", tmsg->messageId()}, diff --git a/src/qTbot/src/private/requests/telegramgetupdate.cpp b/src/qTbot/src/private/requests/telegramgetupdate.cpp index 069e085..29d82eb 100644 --- a/src/qTbot/src/private/requests/telegramgetupdate.cpp +++ b/src/qTbot/src/private/requests/telegramgetupdate.cpp @@ -13,6 +13,7 @@ namespace qTbot { TelegramGetUpdate::TelegramGetUpdate(unsigned long long offset): TelegramSingleRquest("getUpdates"){ addArg("offset", offset); addArg("timeout", 30); + setPriority(UngeredPriority); } } diff --git a/src/qTbot/src/private/requests/telegramsendmsg.cpp b/src/qTbot/src/private/requests/telegramsendmsg.cpp index 3867c26..d840885 100644 --- a/src/qTbot/src/private/requests/telegramsendmsg.cpp +++ b/src/qTbot/src/private/requests/telegramsendmsg.cpp @@ -18,6 +18,7 @@ TelegramSendMsg::TelegramSendMsg(const TelegramArgs& generalArgs, { QMap&& args = generalArgs.toMap(); + setPriority(generalArgs.requestPriority); for (auto it = extraObjects.begin(); it != extraObjects.end(); it = std::next(it)) { args[it.key()] = QJsonDocument(*it.value()).toJson(QJsonDocument::Compact); diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index 9f6d70c..b2da6ed 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -121,7 +121,8 @@ QFuture IBot::sendRequest(const QSharedPointer &rquest) { auto&& responce = QSharedPointer>::create(); responce->start(); - _requestQueue.push_back(RequestData{rquest, "", responce}); + _requestQueue.insert(rquest->priority(), + RequestData{rquest, "", responce}); _requestExecutor->start(); @@ -133,7 +134,8 @@ IBot::sendRequest(const QSharedPointer &rquest, const QString &pathToResult) { auto&& responce = QSharedPointer>::create(); responce->start(); - _requestQueue.push_back(RequestData{rquest, pathToResult, responce}); + _requestQueue.insert(rquest->priority(), + RequestData{rquest, pathToResult, responce}); _requestExecutor->start(); @@ -171,7 +173,7 @@ void IBot::handleEcxecuteRequest() { return; } - auto&& requestData = _requestQueue.takeFirst(); + auto&& requestData = _requestQueue.take(_requestQueue.lastKey()); if (requestData.responceFilePath.size()) { sendRequestPrivate(requestData.request, requestData.responceFilePath, requestData.responce); @@ -189,7 +191,7 @@ void IBot::sendRequestPrivate(const QSharedPointer &rquest, return; } - setParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1); + setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1); connect(networkReplay, &QNetworkReply::finished, [this, networkReplay, promise](){ if (networkReplay->error() == QNetworkReply::NoError) { @@ -200,7 +202,7 @@ void IBot::sendRequestPrivate(const QSharedPointer &rquest, promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1() + networkReplay->readAll())); } - setParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1); + setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1); }); @@ -231,7 +233,7 @@ void IBot::sendRequestPrivate(const QSharedPointer &rquest, return; } - setParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1); + setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1); connect(networkReplay, &QNetworkReply::finished, [this, promise, networkReplay, pathToResult](){ if (networkReplay->error() == QNetworkReply::NoError) { @@ -240,7 +242,7 @@ void IBot::sendRequestPrivate(const QSharedPointer &rquest, promise->addResult(pathToResult.toUtf8()); // wil not work with UTF 8 path names promise->finish(); } - setParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1); + setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1); }); connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise, pathToResult, file](){ diff --git a/src/qTbot/src/public/qTbot/ibot.h b/src/qTbot/src/public/qTbot/ibot.h index 2bcb279..28b06a7 100644 --- a/src/qTbot/src/public/qTbot/ibot.h +++ b/src/qTbot/src/public/qTbot/ibot.h @@ -92,7 +92,7 @@ class QTBOT_EXPORT IBot: public QObject * * @note the specific implementations of this interface can have a different method for sending. */ - virtual bool sendMessage(const QVariant& chatId, const QString& text) = 0; + virtual bool sendMessage(const QVariant& chatId, const QString& text, iRequest::RequestPriority priority = iRequest::NormalPriority) = 0; /** * @brief deleteMessage This is main method to delete messages. @@ -310,9 +310,9 @@ private slots: QSet _processed; QNetworkAccessManager *_manager = nullptr; QTimer* _requestExecutor = nullptr; - QList _requestQueue; + QMultiMap _requestQueue; int _currentParallelActiveNetworkThreads = 0; - int _parallelActiveNetworkThreads = 10; + int _parallelActiveNetworkThreads = 5; diff --git a/src/qTbot/src/public/qTbot/irequest.cpp b/src/qTbot/src/public/qTbot/irequest.cpp index 79bf2d8..be6e19a 100644 --- a/src/qTbot/src/public/qTbot/irequest.cpp +++ b/src/qTbot/src/public/qTbot/irequest.cpp @@ -91,6 +91,14 @@ QSharedPointer iRequest::argsToMultipartFormData() const { return multiPart; } +iRequest::RequestPriority iRequest::priority() const { + return _priority; +} + +void iRequest::setPriority(RequestPriority newPriority) { + _priority = newPriority; +} + const QString& iRequest::request() const { return _request; } diff --git a/src/qTbot/src/public/qTbot/irequest.h b/src/qTbot/src/public/qTbot/irequest.h index 481b8e5..0537ab1 100644 --- a/src/qTbot/src/public/qTbot/irequest.h +++ b/src/qTbot/src/public/qTbot/irequest.h @@ -46,6 +46,19 @@ class QTBOT_EXPORT iRequest Upload }; + /** + * @brief The RequestPriority enum + */ + enum RequestPriority { + NoPriority = 0, + LowPriority = 1, + NormalPriority = 2, + HighPriority = 3, + UngeredPriority = 4, + + MaxPriorityValue = 0xff + }; + /** * @brief makeUpload This method prepare data to upload; * @return data array prepared to sending. @@ -109,9 +122,19 @@ class QTBOT_EXPORT iRequest * @return QHttpMultiPart - A QHttpMultiPart object containing multipart/form-data request data. */ QSharedPointer argsToMultipartFormData() const; + + /** + * @brief priority This is priority of executabel this request on client. + * @return + */ + RequestPriority priority() const; + + void setPriority(RequestPriority newPriority); + private: QString _request; QMap _args; + RequestPriority _priority = RequestPriority::NormalPriority; }; diff --git a/src/qTbot/src/public/qTbot/itelegrambot.cpp b/src/qTbot/src/public/qTbot/itelegrambot.cpp index 752a05c..0a4a4b8 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.cpp +++ b/src/qTbot/src/public/qTbot/itelegrambot.cpp @@ -64,11 +64,17 @@ bool ITelegramBot::login(const QByteArray &token) { return loginFuture.isValid(); } -bool ITelegramBot::sendMessage(const QVariant &chatId, const QString &text) { - return sendSpecificMessage(TelegramArgs{chatId, text}); +bool ITelegramBot::sendMessage(const QVariant &chatId, + const QString &text, + iRequest::RequestPriority priority) { + TelegramArgs arg{chatId, text}; + arg.requestPriority = priority; + return sendSpecificMessage(arg); } -bool ITelegramBot::sendLocationRequest(const QVariant &chatId, const QString &text, const QString &buttonText, +bool ITelegramBot::sendLocationRequest(const QVariant &chatId, + const QString &text, + const QString &buttonText, bool onetimeKeyboard) { auto replyMarkup = QSharedPointer::create(); diff --git a/src/qTbot/src/public/qTbot/itelegrambot.h b/src/qTbot/src/public/qTbot/itelegrambot.h index 873f9b1..2baad29 100644 --- a/src/qTbot/src/public/qTbot/itelegrambot.h +++ b/src/qTbot/src/public/qTbot/itelegrambot.h @@ -40,7 +40,9 @@ class QTBOT_EXPORT ITelegramBot : public IBot bool login(const QByteArray &token) override; - bool sendMessage(const QVariant &chatId, const QString& text) override; + bool sendMessage(const QVariant &chatId, + const QString& text, + iRequest::RequestPriority priority = iRequest::NormalPriority) override; /** * @brief sendLocationRequest This method setn into chat button that will automaticaly sent geo location to bot. diff --git a/src/qTbot/src/public/qTbot/telegramargs.cpp b/src/qTbot/src/public/qTbot/telegramargs.cpp index 0fb7fd3..a9c9109 100644 --- a/src/qTbot/src/public/qTbot/telegramargs.cpp +++ b/src/qTbot/src/public/qTbot/telegramargs.cpp @@ -13,7 +13,8 @@ TelegramArgs::TelegramArgs(const QVariant &id, unsigned long long replyToMessageId, const QString &parseMode, bool disableWebPagePreview, - const QString &callBackQueryId, const std::function &msgIdCB) + const QString &callBackQueryId, const std::function &msgIdCB, + iRequest::RequestPriority priority) { this->chatId = id; @@ -23,6 +24,7 @@ TelegramArgs::TelegramArgs(const QVariant &id, this->replyToMessageId = replyToMessageId; this->parseMode = parseMode; this->msgIdCB = msgIdCB; + this->requestPriority = priority; } QMap TelegramArgs::toMap(bool textAsCaption) const { diff --git a/src/qTbot/src/public/qTbot/telegramargs.h b/src/qTbot/src/public/qTbot/telegramargs.h index 9654ee7..a597cf8 100644 --- a/src/qTbot/src/public/qTbot/telegramargs.h +++ b/src/qTbot/src/public/qTbot/telegramargs.h @@ -10,6 +10,7 @@ #include #include "global.h" +#include "irequest.h" namespace qTbot { @@ -24,7 +25,8 @@ struct QTBOT_EXPORT TelegramArgs const QString& parseMode = "html", bool disableWebPagePreview = false, const QString& callBackQueryId = "", - const std::function& msgIdCB = {} + const std::function& msgIdCB = {}, + iRequest::RequestPriority priority = iRequest::RequestPriority::NormalPriority ); /** @@ -74,6 +76,8 @@ struct QTBOT_EXPORT TelegramArgs * @brief msgIdCB This is id message call bak function. Will be inwoked when request finished successful. */ std::function msgIdCB = {}; + + iRequest::RequestPriority requestPriority = iRequest::RequestPriority::NormalPriority; }; } From bb22a699215eb8583a361de2fc0c6773c2e36087 Mon Sep 17 00:00:00 2001 From: EndrII Date: Sun, 15 Dec 2024 11:15:15 +0100 Subject: [PATCH 14/14] added priority sustem --- src/qTbot/src/public/qTbot/ibot.cpp | 25 ++++++++++++++++++++++--- src/qTbot/src/public/qTbot/ibot.h | 27 ++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/qTbot/src/public/qTbot/ibot.cpp b/src/qTbot/src/public/qTbot/ibot.cpp index b2da6ed..9bd1828 100644 --- a/src/qTbot/src/public/qTbot/ibot.cpp +++ b/src/qTbot/src/public/qTbot/ibot.cpp @@ -37,6 +37,8 @@ const QByteArray &IBot::token() const { void IBot::setToken(const QByteArray &newToken) { _token = newToken; + _startTime = QDateTime::currentDateTime(); + } void IBot::incomeNewUpdate(const QSharedPointer &message) { @@ -96,6 +98,14 @@ QNetworkReply* IBot::sendRquestImpl(const QSharedPointer &rquest) { return networkReplay; } +QDateTime IBot::startTime() const { + return _startTime; +} + +unsigned long long IBot::totalSentRequests() const { + return _totalRequest; +} + int IBot::parallelActiveNetworkThreads() const { return _parallelActiveNetworkThreads; } @@ -121,7 +131,9 @@ QFuture IBot::sendRequest(const QSharedPointer &rquest) { auto&& responce = QSharedPointer>::create(); responce->start(); - _requestQueue.insert(rquest->priority(), + + + _requestQueue.insert(makeKey(rquest->priority()), RequestData{rquest, "", responce}); _requestExecutor->start(); @@ -134,7 +146,7 @@ IBot::sendRequest(const QSharedPointer &rquest, const QString &pathToResult) { auto&& responce = QSharedPointer>::create(); responce->start(); - _requestQueue.insert(rquest->priority(), + _requestQueue.insert(makeKey(rquest->priority()), RequestData{rquest, pathToResult, responce}); _requestExecutor->start(); @@ -173,7 +185,7 @@ void IBot::handleEcxecuteRequest() { return; } - auto&& requestData = _requestQueue.take(_requestQueue.lastKey()); + auto&& requestData = _requestQueue.take(_requestQueue.firstKey()); if (requestData.responceFilePath.size()) { sendRequestPrivate(requestData.request, requestData.responceFilePath, requestData.responce); @@ -183,6 +195,13 @@ void IBot::handleEcxecuteRequest() { sendRequestPrivate(requestData.request, requestData.responce); } +unsigned long long IBot::makeKey(iRequest::RequestPriority priority) { + unsigned long long key = _totalRequest; + _totalRequest++; + key = key | (static_cast(iRequest::RequestPriority::MaxPriorityValue - priority) << 56); + return key; +} + void IBot::sendRequestPrivate(const QSharedPointer &rquest, const QSharedPointer > &promise) { diff --git a/src/qTbot/src/public/qTbot/ibot.h b/src/qTbot/src/public/qTbot/ibot.h index 28b06a7..e89bd5e 100644 --- a/src/qTbot/src/public/qTbot/ibot.h +++ b/src/qTbot/src/public/qTbot/ibot.h @@ -179,9 +179,31 @@ class QTBOT_EXPORT IBot: public QObject */ void setReqestLimitPerSecond(int newReqestLimitPerSecond); + /** + * @brief parallelActiveNetworkThreads + * @return + */ int parallelActiveNetworkThreads() const; + + /** + * @brief setParallelActiveNetworkThreads + * @param newParallelActiveNetworkThreads + */ void setParallelActiveNetworkThreads(int newParallelActiveNetworkThreads); + /** + * @brief totalSentRequests This is total prepared requests count of bot from the start. + * @see startTime method to get start date time. + * @return requests count. + */ + unsigned long long totalSentRequests() const; + + /** + * @brief startTime this is time when bol wil started. + * @return + */ + QDateTime startTime() const; + protected: /** @@ -293,6 +315,7 @@ class QTBOT_EXPORT IBot: public QObject private slots: void handleEcxecuteRequest(); private: + unsigned long long makeKey(iRequest::RequestPriority priority); void setCurrentParallelActiveNetworkThreads(int newParallelActiveNetworkThreads); void sendRequestPrivate(const QSharedPointer& rquest, @@ -310,7 +333,9 @@ private slots: QSet _processed; QNetworkAccessManager *_manager = nullptr; QTimer* _requestExecutor = nullptr; - QMultiMap _requestQueue; + unsigned long long _totalRequest = 0; + QDateTime _startTime; + QMap _requestQueue; int _currentParallelActiveNetworkThreads = 0; int _parallelActiveNetworkThreads = 5;