mirror of
https://github.com/QuasarApp/qTbot.git
synced 2025-04-27 06:14:32 +00:00
Merge pull request #19 from QuasarApp/requestPerformanceLimit
Request performance limit
This commit is contained in:
commit
24c8b4eec0
@ -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)
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <qTbot/telegramrestbot.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <qTbot/httpexception.h>
|
||||
#include <qTbot/messages/telegrammsg.h>
|
||||
#include <qTbot/messages/telegramupdate.h>
|
||||
|
||||
@ -23,11 +24,11 @@ int main(int argc, char *argv[]) {
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
qTbot::TelegramRestBot bot;
|
||||
bot.setReqestLimitPerSecond(10);
|
||||
|
||||
srand(time(0));
|
||||
|
||||
QList<QSharedPointer<qTbot::iFile> > 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<qTbot::TelegramUpdate>()) {
|
||||
@ -36,41 +37,64 @@ 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() << "file save into " << path;
|
||||
}).onFailed([](const std::exception& exception){
|
||||
|
||||
qCritical() << "exception :" << exception.what();
|
||||
});
|
||||
}
|
||||
|
||||
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() << "file save into " << path;
|
||||
}).onFailed([](const std::exception& exception){
|
||||
|
||||
qCritical() << "exception :" << exception.what();
|
||||
});;
|
||||
}
|
||||
|
||||
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() << "file save into " << path;
|
||||
}).onFailed([](const std::exception& exception){
|
||||
|
||||
qCritical() << "exception :" << exception.what();
|
||||
});;
|
||||
}
|
||||
|
||||
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;
|
||||
if (tmsg->text() == "spam") {
|
||||
for (int i = 0 ; i < 1000; 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()},
|
||||
{{{"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&& 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 ){}}}};
|
||||
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);
|
||||
}
|
||||
|
||||
bot.editSpecificMessageWithKeyboard(msgId,
|
||||
args,
|
||||
keyboard
|
||||
);
|
||||
}}}});
|
||||
|
||||
bot.sendSpecificMessageWithKeyboard(qTbot::TelegramArgs{tmsg->chatId(), "I see it", tmsg->messageId()},
|
||||
{{{"test_button"},
|
||||
{"test_button"},}}, true, true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -78,6 +102,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();
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ namespace qTbot {
|
||||
TelegramGetUpdate::TelegramGetUpdate(unsigned long long offset): TelegramSingleRquest("getUpdates"){
|
||||
addArg("offset", offset);
|
||||
addArg("timeout", 30);
|
||||
setPriority(UngeredPriority);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ TelegramSendMsg::TelegramSendMsg(const TelegramArgs& generalArgs,
|
||||
{
|
||||
|
||||
QMap<QString, QVariant>&& 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);
|
||||
|
@ -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<QNetworkReply> &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();
|
||||
}
|
||||
|
||||
}
|
@ -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<QNetworkReply>& 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
|
@ -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<iFile> &file) {
|
||||
if (!file->isFinished()) {
|
||||
auto address = reinterpret_cast<size_t>(file.get());
|
||||
|
||||
_files[address] = file;
|
||||
|
||||
|
||||
connect(file.get(), &qTbot::iFile::finishedChanged, this, &FileWaiter::handleFileFinished,
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void FileWaiter::handleFileFinished() {
|
||||
auto address = reinterpret_cast<size_t>(sender());
|
||||
|
||||
_files.remove(address);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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<iFile>& file);
|
||||
|
||||
private slots:
|
||||
void handleFileFinished();
|
||||
|
||||
private:
|
||||
QHash<size_t, QSharedPointer<iFile>> _files;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
#endif // FILEWAITER_H
|
42
src/qTbot/src/public/qTbot/httpexception.cpp
Normal file
42
src/qTbot/src/public/qTbot/httpexception.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
//#
|
||||
//# 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"
|
||||
|
||||
namespace qTbot {
|
||||
|
||||
HttpException::HttpException(QNetworkReply::NetworkError code,
|
||||
const QByteArray &erroString) {
|
||||
|
||||
_code = code;
|
||||
|
||||
if (erroString.size()) {
|
||||
_errText = erroString;
|
||||
} else {
|
||||
|
||||
_errText = QByteArray("Http request finished 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);
|
||||
}
|
||||
|
||||
QNetworkReply::NetworkError HttpException::code() const {
|
||||
return _code;
|
||||
}
|
||||
}
|
41
src/qTbot/src/public/qTbot/httpexception.h
Normal file
41
src/qTbot/src/public/qTbot/httpexception.h
Normal file
@ -0,0 +1,41 @@
|
||||
//#
|
||||
//# Copyright (C) 2023-2024 QuasarApp.
|
||||
//# Distributed under the GPLv3 software license, see the accompanying
|
||||
//# Everyone is permitted to copy and distribute verbatim copies
|
||||
//# of this license document, but changing it is not allowed.
|
||||
//#
|
||||
|
||||
#include <QException>
|
||||
#include <QNetworkReply>
|
||||
|
||||
|
||||
#ifndef HTTPEXCEPTION_H
|
||||
#define HTTPEXCEPTION_H
|
||||
|
||||
namespace qTbot {
|
||||
|
||||
/**
|
||||
* @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 override;
|
||||
|
||||
// QException interface
|
||||
public:
|
||||
void raise() const override;
|
||||
QException *clone() const override;
|
||||
|
||||
QNetworkReply::NetworkError code() const;
|
||||
|
||||
private:
|
||||
QByteArray _errText;
|
||||
QNetworkReply::NetworkError _code;
|
||||
};
|
||||
}
|
||||
#endif // HTTPEXCEPTION_H
|
@ -5,16 +5,22 @@
|
||||
//# of this license document, but changing it is not allowed.
|
||||
//#
|
||||
|
||||
#include "httpexception.h"
|
||||
#include "ibot.h"
|
||||
#include "qstandardpaths.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QPromise>
|
||||
|
||||
namespace qTbot {
|
||||
|
||||
IBot::IBot() {
|
||||
_manager = new QNetworkAccessManager();
|
||||
_manager->setAutoDeleteReplies(false);
|
||||
_manager->setAutoDeleteReplies(true);
|
||||
_requestExecutor = new QTimer(this);
|
||||
_requestExecutor->setInterval(1000 / 20); // 20 times per second.
|
||||
|
||||
connect(_requestExecutor, &QTimer::timeout, this , &IBot::handleEcxecuteRequest);
|
||||
}
|
||||
|
||||
IBot::~IBot() {
|
||||
@ -31,6 +37,8 @@ const QByteArray &IBot::token() const {
|
||||
|
||||
void IBot::setToken(const QByteArray &newToken) {
|
||||
_token = newToken;
|
||||
_startTime = QDateTime::currentDateTime();
|
||||
|
||||
}
|
||||
|
||||
void IBot::incomeNewUpdate(const QSharedPointer<iUpdate> &message) {
|
||||
@ -48,12 +56,9 @@ void IBot::incomeNewUpdate(const QSharedPointer<iUpdate> &message) {
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<QNetworkReply>
|
||||
IBot::sendRequest(const QSharedPointer<iRequest> &rquest) {
|
||||
QNetworkReply* IBot::sendRquestImpl(const QSharedPointer<iRequest> &rquest) {
|
||||
if (!rquest)
|
||||
return nullptr;
|
||||
|
||||
doRemoveFinishedRequests();
|
||||
return {};
|
||||
|
||||
auto && url = makeUrl(rquest);
|
||||
|
||||
@ -61,64 +66,95 @@ IBot::sendRequest(const QSharedPointer<iRequest> &rquest) {
|
||||
qDebug() << url;
|
||||
#endif
|
||||
|
||||
QSharedPointer<QNetworkReply> networkReplay;
|
||||
QNetworkReply* networkReplay = nullptr;
|
||||
QSharedPointer<QHttpMultiPart> httpData;
|
||||
|
||||
switch (rquest->method()) {
|
||||
case iRequest::Get: {
|
||||
auto reply = _manager->get(QNetworkRequest(url));
|
||||
networkReplay = _manager->get(QNetworkRequest(url));
|
||||
|
||||
// we control replay object wia shared pointers.
|
||||
reply->setParent(nullptr);
|
||||
|
||||
networkReplay.reset(reply);
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
httpData = rquest->argsToMultipartFormData();
|
||||
if (httpData) {
|
||||
auto reply = _manager->post(netRequest, httpData.data());
|
||||
networkReplay = _manager->post(netRequest, httpData.data());
|
||||
|
||||
// we control replay object wia shared pointers.
|
||||
reply->setParent(nullptr);
|
||||
|
||||
networkReplay.reset(reply);
|
||||
} else {
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
size_t address = reinterpret_cast<size_t>(networkReplay.get());
|
||||
_replayStorage[address] = networkReplay;
|
||||
|
||||
connect(networkReplay.get(), &QNetworkReply::finished, this,
|
||||
[this, address, httpData]() {
|
||||
_toRemove.push_back(address);
|
||||
});
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
_toRemove.push_back(address);
|
||||
});
|
||||
|
||||
return networkReplay;
|
||||
}
|
||||
|
||||
QDateTime IBot::startTime() const {
|
||||
return _startTime;
|
||||
}
|
||||
|
||||
unsigned long long IBot::totalSentRequests() const {
|
||||
return _totalRequest;
|
||||
}
|
||||
|
||||
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 _requestExecutor->interval() * 1000;
|
||||
}
|
||||
|
||||
void IBot::setReqestLimitPerSecond(int newReqestLimitPerSecond) {
|
||||
_requestExecutor->setInterval(1000 / newReqestLimitPerSecond);
|
||||
}
|
||||
|
||||
QFuture<QByteArray>
|
||||
IBot::sendRequest(const QSharedPointer<iRequest> &rquest) {
|
||||
auto&& responce = QSharedPointer<QPromise<QByteArray>>::create();
|
||||
responce->start();
|
||||
|
||||
|
||||
_requestQueue.insert(makeKey(rquest->priority()),
|
||||
RequestData{rquest, "", responce});
|
||||
|
||||
_requestExecutor->start();
|
||||
|
||||
return responce->future();
|
||||
}
|
||||
|
||||
QFuture<QByteArray>
|
||||
IBot::sendRequest(const QSharedPointer<iRequest> &rquest,
|
||||
const QString &pathToResult) {
|
||||
auto&& responce = QSharedPointer<QPromise<QByteArray>>::create();
|
||||
responce->start();
|
||||
_requestQueue.insert(makeKey(rquest->priority()),
|
||||
RequestData{rquest, pathToResult, responce});
|
||||
|
||||
_requestExecutor->start();
|
||||
|
||||
return responce->future();
|
||||
|
||||
}
|
||||
|
||||
void IBot::markUpdateAsProcessed(const QSharedPointer<iUpdate> &message) {
|
||||
_notProcessedUpdates.remove(message->updateId());
|
||||
}
|
||||
@ -139,12 +175,113 @@ void IBot::handleIncomeNewUpdate(const QSharedPointer<iUpdate> & message) {
|
||||
emit sigReceiveUpdate(message);
|
||||
}
|
||||
|
||||
void IBot::doRemoveFinishedRequests() {
|
||||
for (auto address: std::as_const(_toRemove)) {
|
||||
_replayStorage.remove(address);
|
||||
void IBot::handleEcxecuteRequest() {
|
||||
if (!_requestQueue.size()) {
|
||||
_requestExecutor->stop();
|
||||
return;
|
||||
}
|
||||
|
||||
_toRemove.clear();
|
||||
if (_currentParallelActiveNetworkThreads > _parallelActiveNetworkThreads) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto&& requestData = _requestQueue.take(_requestQueue.firstKey());
|
||||
|
||||
if (requestData.responceFilePath.size()) {
|
||||
sendRequestPrivate(requestData.request, requestData.responceFilePath, requestData.responce);
|
||||
return;
|
||||
}
|
||||
|
||||
sendRequestPrivate(requestData.request, requestData.responce);
|
||||
}
|
||||
|
||||
unsigned long long IBot::makeKey(iRequest::RequestPriority priority) {
|
||||
unsigned long long key = _totalRequest;
|
||||
_totalRequest++;
|
||||
key = key | (static_cast<unsigned long long>(iRequest::RequestPriority::MaxPriorityValue - priority) << 56);
|
||||
return key;
|
||||
}
|
||||
|
||||
void IBot::sendRequestPrivate(const QSharedPointer<iRequest> &rquest,
|
||||
const QSharedPointer<QPromise<QByteArray> > &promise) {
|
||||
|
||||
QNetworkReply* networkReplay = sendRquestImpl(rquest);
|
||||
if (!networkReplay) {
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1);
|
||||
|
||||
connect(networkReplay, &QNetworkReply::finished, [this, networkReplay, promise](){
|
||||
if (networkReplay->error() == QNetworkReply::NoError) {
|
||||
promise->addResult(networkReplay->readAll());
|
||||
promise->finish();
|
||||
|
||||
} else {
|
||||
promise->setException(HttpException(networkReplay->error(), networkReplay->errorString().toLatin1() + networkReplay->readAll()));
|
||||
}
|
||||
|
||||
setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1);
|
||||
|
||||
});
|
||||
|
||||
auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){
|
||||
|
||||
if (promise->future().progressMaximum() != bytesTotal)
|
||||
promise->setProgressRange(0, bytesTotal);
|
||||
|
||||
promise->setProgressValue(bytesCurrent);
|
||||
};
|
||||
|
||||
connect(networkReplay, &QNetworkReply::downloadProgress, setProggress);
|
||||
connect(networkReplay, &QNetworkReply::uploadProgress, setProggress);
|
||||
}
|
||||
|
||||
void IBot::sendRequestPrivate(const QSharedPointer<iRequest> &rquest,
|
||||
const QString &pathToResult,
|
||||
const QSharedPointer<QPromise<QByteArray>> & promise) {
|
||||
auto&& file = QSharedPointer<QFile>::create(pathToResult);
|
||||
|
||||
if (!file->open(QIODeviceBase::WriteOnly | QIODevice::Truncate)) {
|
||||
qCritical() << "Fail to wrote data into " << pathToResult;
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkReply* networkReplay = sendRquestImpl(rquest);
|
||||
if (!networkReplay) {
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1);
|
||||
connect(networkReplay, &QNetworkReply::finished, [this, 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();
|
||||
}
|
||||
setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1);
|
||||
});
|
||||
|
||||
connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise, pathToResult, file](){
|
||||
if (networkReplay->error() == QNetworkReply::NoError) {
|
||||
file->write(networkReplay->readAll());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){
|
||||
|
||||
if (promise->future().progressMaximum() != bytesTotal)
|
||||
promise->setProgressRange(0, bytesTotal);
|
||||
|
||||
promise->setProgressValue(bytesCurrent);
|
||||
};
|
||||
|
||||
connect(networkReplay, &QNetworkReply::downloadProgress, setProggress);
|
||||
connect(networkReplay, &QNetworkReply::uploadProgress, setProggress);
|
||||
|
||||
}
|
||||
|
||||
QSet<unsigned long long> IBot::processed() const {
|
||||
|
@ -13,16 +13,16 @@
|
||||
#include "qTbot/iupdate.h"
|
||||
#include "qTbot/irequest.h"
|
||||
|
||||
#include "ifile.h"
|
||||
#include "qfileinfo.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QHash>
|
||||
#include <QSet>
|
||||
#include <QFileInfo>
|
||||
#include <QTimer>
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <qfuture.h>
|
||||
|
||||
namespace qTbot {
|
||||
|
||||
@ -38,6 +38,40 @@ public:
|
||||
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 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<iRequest> request;
|
||||
|
||||
/**
|
||||
* @brief responceFilePath path to responce.
|
||||
*/
|
||||
QString responceFilePath = "";
|
||||
|
||||
/**
|
||||
* @brief responce This is promise to responce of this requests that will sets back.
|
||||
*/
|
||||
QSharedPointer<QPromise<QByteArray>> responce;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief login This method get bae information of the bot from remote server.
|
||||
* @param token This is token value for login
|
||||
@ -58,7 +92,7 @@ public:
|
||||
*
|
||||
* @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.
|
||||
@ -74,10 +108,10 @@ public:
|
||||
* 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<iFile> getFile(const QString& fileId, iFile::Type fileType = iFile::Type::Ram) = 0;
|
||||
virtual QFuture<QByteArray> getFile(const QString& fileId, FileType fileType = Ram) = 0;
|
||||
|
||||
/**
|
||||
* @brief send @a file .
|
||||
@ -133,6 +167,43 @@ public:
|
||||
*/
|
||||
virtual void setProcessed(const QSet<unsigned long long> &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);
|
||||
|
||||
/**
|
||||
* @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:
|
||||
|
||||
/**
|
||||
@ -163,7 +234,6 @@ protected:
|
||||
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.
|
||||
@ -174,12 +244,21 @@ protected:
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
QSharedPointer<QNetworkReply>
|
||||
QFuture<QByteArray>
|
||||
sendRequest(const QSharedPointer<iRequest>& 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<QByteArray>
|
||||
sendRequest(const QSharedPointer<iRequest>& rquest, const QString& pathToResult);
|
||||
|
||||
/**
|
||||
* @brief setToken This is setter of the IBot::token value.
|
||||
* @param newToken This is new value of the token.
|
||||
@ -233,17 +312,34 @@ signals:
|
||||
*/
|
||||
void sigStopRequire();
|
||||
|
||||
private slots:
|
||||
void handleEcxecuteRequest();
|
||||
private:
|
||||
void doRemoveFinishedRequests();
|
||||
unsigned long long makeKey(iRequest::RequestPriority priority);
|
||||
void setCurrentParallelActiveNetworkThreads(int newParallelActiveNetworkThreads);
|
||||
|
||||
void sendRequestPrivate(const QSharedPointer<iRequest>& rquest,
|
||||
const QSharedPointer<QPromise<QByteArray>> & promiseResult);
|
||||
|
||||
void sendRequestPrivate(const QSharedPointer<iRequest>& rquest,
|
||||
const QString& pathToResult,
|
||||
const QSharedPointer<QPromise<QByteArray> > &promiseResult);
|
||||
|
||||
QNetworkReply *sendRquestImpl(const QSharedPointer<iRequest> &rquest);
|
||||
|
||||
QByteArray _token;
|
||||
QString _name;
|
||||
QMap<unsigned long long, QSharedPointer<iUpdate>> _notProcessedUpdates;
|
||||
QSet<unsigned long long> _processed;
|
||||
QNetworkAccessManager *_manager = nullptr;
|
||||
QTimer* _requestExecutor = nullptr;
|
||||
unsigned long long _totalRequest = 0;
|
||||
QDateTime _startTime;
|
||||
QMap<unsigned long long, RequestData> _requestQueue;
|
||||
int _currentParallelActiveNetworkThreads = 0;
|
||||
int _parallelActiveNetworkThreads = 5;
|
||||
|
||||
|
||||
QMap<size_t,QSharedPointer<QNetworkReply>> _replayStorage;
|
||||
QList<size_t> _toRemove;
|
||||
|
||||
};
|
||||
|
||||
|
@ -1,125 +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"
|
||||
|
||||
namespace qTbot {
|
||||
|
||||
iFile::iFile(const QSharedPointer<QNetworkReply>& 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 QSharedPointer<QNetworkReply> &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<float>(bytesTotal));
|
||||
}
|
||||
|
||||
void iFile::handleDownloadProgressChanged(qint64 bytesReceived, qint64 bytesTotal) {
|
||||
setDownloadProgress(bytesReceived / static_cast<float>(bytesTotal));
|
||||
}
|
||||
|
||||
void iFile::setDownloadRequest(const QSharedPointer<QNetworkReply> &replay) {
|
||||
|
||||
if (_replay) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,174 +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 "qnetworkreply.h"
|
||||
#include <qTbot/global.h>
|
||||
#include <QFile>
|
||||
|
||||
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 QSharedPointer<QNetworkReply>& 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 QSharedPointer<QNetworkReply>& 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 QSharedPointer<QNetworkReply>& 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;
|
||||
|
||||
QSharedPointer<QNetworkReply> _replay;
|
||||
|
||||
friend class ITelegramBot;
|
||||
};
|
||||
}
|
||||
#endif // IFILE_H
|
28
src/qTbot/src/public/qTbot/internalexception.cpp
Normal file
28
src/qTbot/src/public/qTbot/internalexception.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
39
src/qTbot/src/public/qTbot/internalexception.h
Normal file
39
src/qTbot/src/public/qTbot/internalexception.h
Normal file
@ -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 <QException>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#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
|
||||
|
||||
|
@ -91,6 +91,14 @@ QSharedPointer<QHttpMultiPart> 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;
|
||||
}
|
||||
|
@ -46,6 +46,19 @@ public:
|
||||
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 @@ public:
|
||||
* @return QHttpMultiPart - A QHttpMultiPart object containing multipart/form-data request data.
|
||||
*/
|
||||
QSharedPointer<QHttpMultiPart> 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<QString, QVariant> _args;
|
||||
RequestPriority _priority = RequestPriority::NormalPriority;
|
||||
|
||||
};
|
||||
|
||||
|
@ -7,12 +7,12 @@
|
||||
|
||||
#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 "virtualfile.h"
|
||||
#include "httpexception.h"
|
||||
#include "internalexception.h"
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#include <requests/telegramgetfile.h>
|
||||
@ -52,25 +52,29 @@ bool ITelegramBot::login(const QByteArray &token) {
|
||||
|
||||
setToken(token);
|
||||
|
||||
_loginReplay = sendRequest(QSharedPointer<TelegramGetMe>::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<QByteArray> loginFuture = sendRequest(QSharedPointer<TelegramGetMe>::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) {
|
||||
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<QJsonObject>::create();
|
||||
@ -284,35 +288,35 @@ bool ITelegramBot::sendSpecificMessageWithKeyboard(const TelegramArgs& args,
|
||||
return sendSpecificMessage(args, prepareKeyboard(autoResizeKeyboard, onTimeKeyboard, keyboard));
|
||||
}
|
||||
|
||||
QSharedPointer<iFile> ITelegramBot::getFile(const QString &fileId, iFile::Type fileType) {
|
||||
QFuture<QByteArray> ITelegramBot::getFile(const QString &fileId, FileType fileType) {
|
||||
|
||||
QSharedPointer<iFile> result = nullptr;
|
||||
|
||||
if (fileId.isEmpty()) {
|
||||
return result;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto localFilePath = findFileInlocatStorage(fileId);
|
||||
|
||||
if (!localFilePath.isEmpty()) {
|
||||
QPromise<QByteArray> fileDataResult;
|
||||
|
||||
if (fileType == iFile::Ram) {
|
||||
if (fileType == FileType::Ram) {
|
||||
QFile localFile(localFilePath);
|
||||
if (localFile.open(QIODevice::ReadOnly)) {
|
||||
auto&& virtualFile = QSharedPointer<VirtualFile>::create(nullptr);
|
||||
virtualFile->setArray(localFile.readAll());
|
||||
fileDataResult.addResult(localFile.readAll());
|
||||
localFile.close();
|
||||
|
||||
result = virtualFile;
|
||||
}
|
||||
|
||||
} else if (fileType == iFile::Local) {
|
||||
result = QSharedPointer<File>::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);
|
||||
@ -327,43 +331,57 @@ QSharedPointer<iFile> ITelegramBot::getFile(const QString &fileId, iFile::Type f
|
||||
|
||||
|
||||
if (localFilePath.isEmpty())
|
||||
return result;
|
||||
return {};
|
||||
|
||||
if (auto &&replay = sendRequest(msg)) {
|
||||
// here i must be receive responce and prepare new request to file from the call back function.
|
||||
if (fileType == iFile::Ram) {
|
||||
result = QSharedPointer<VirtualFile>::create(replay);
|
||||
} else if (fileType == iFile::Local) {
|
||||
result = QSharedPointer<File>::create(replay, localFilePath);
|
||||
}
|
||||
QFuture<QByteArray> replay;
|
||||
if (fileType == FileType::Ram) {
|
||||
replay = sendRequest(msg);
|
||||
} else {
|
||||
replay = sendRequest(msg, localFilePath);
|
||||
}
|
||||
|
||||
return result;
|
||||
return replay;
|
||||
}
|
||||
}
|
||||
|
||||
auto longWay = QSharedPointer<QPromise<QByteArray>>::create();
|
||||
longWay->start();
|
||||
|
||||
if (fileType == iFile::Ram) {
|
||||
result = QSharedPointer<VirtualFile>::create();
|
||||
} else if (fileType == iFile::Local) {
|
||||
result = QSharedPointer<File>::create(localFilePath);
|
||||
auto&& future = getFileMeta(fileId);
|
||||
if (!future.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto&& metaReploay = getFileMeta(fileId, result.toWeakRef());
|
||||
return result;
|
||||
future.then([this, fileId, fileType, longWay](const QByteArray& header){
|
||||
handleFileHeader(header);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
QSharedPointer<QNetworkReply> ITelegramBot::getFileMeta(const QString &fileId, const QWeakPointer<iFile>& receiver) {
|
||||
QFuture<QByteArray> ITelegramBot::getFileMeta(const QString &fileId) {
|
||||
auto msg = QSharedPointer<TelegramGetFile>::create(fileId);
|
||||
|
||||
if (auto&& ptr = sendRequest(msg)) {
|
||||
connect(ptr.get(), &QNetworkReply::finished,
|
||||
this, std::bind(&ITelegramBot::handleFileHeader, this, ptr.toWeakRef(), receiver));
|
||||
|
||||
return ptr;
|
||||
auto && future = sendRequest(msg);
|
||||
if (future.isValid()) {
|
||||
return future;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ITelegramBot::sendFile(const QFileInfo &file, const QVariant &chatId) {
|
||||
@ -479,9 +497,9 @@ bool ITelegramBot::sendContact(const TelegramArgs &args,
|
||||
return false;
|
||||
|
||||
return sendMessageRequest(QSharedPointer<TelegramSendContact>::create(args,
|
||||
firstName,
|
||||
phone,
|
||||
secondName));
|
||||
firstName,
|
||||
phone,
|
||||
secondName));
|
||||
}
|
||||
|
||||
int ITelegramBot::getFileSizeByUniqueId(const QString &id) const {
|
||||
@ -520,86 +538,73 @@ void ITelegramBot::handleIncomeNewUpdate(const QSharedPointer<iUpdate> & update)
|
||||
|
||||
bool ITelegramBot::sendMessageRequest(const QSharedPointer<iRequest> &rquest,
|
||||
const std::function<void (int)> &msgIdCB) {
|
||||
auto&& reply = IBot::sendRequest(rquest);
|
||||
if (reply) {
|
||||
connect(reply.get(), &QNetworkReply::finished, this,
|
||||
[ reply, msgIdCB, this]() {
|
||||
auto&& future = IBot::sendRequest(rquest);
|
||||
if (future.isValid()) {
|
||||
future.then(this, [this, msgIdCB](const QByteArray& responseData){
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QByteArray&& responseData = reply->readAll();
|
||||
QJsonDocument json = QJsonDocument::fromJson(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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (chatId) {
|
||||
_lastMessageId[chatId] = messageID;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}).onFailed([msgIdCB](){
|
||||
|
||||
if (msgIdCB) {
|
||||
msgIdCB(-1);
|
||||
}
|
||||
});
|
||||
if (msgIdCB) {
|
||||
msgIdCB(-1);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return bool(reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
void ITelegramBot::handleLogin() {
|
||||
void ITelegramBot::handleLogin(const QByteArray&ansver) {
|
||||
|
||||
if (_loginReplay) {
|
||||
auto&& ans = makeMesasge<TelegramUpdateAnswer>(_loginReplay->readAll());
|
||||
auto&& ans = makeMesasge<TelegramUpdateAnswer>(ansver);
|
||||
|
||||
if (!ans->isValid()) {
|
||||
qWarning() << "login error occured: ";
|
||||
}
|
||||
|
||||
auto&& result = ans->result().toObject();
|
||||
|
||||
setId(result.value("id").toInteger());
|
||||
setName( result.value("first_name").toString());
|
||||
setUsername( result.value("username").toString());
|
||||
|
||||
_loginReplay.reset();
|
||||
if (!ans->isValid()) {
|
||||
qWarning() << "login error occured: ";
|
||||
return;
|
||||
}
|
||||
|
||||
auto&& result = ans->result().toObject();
|
||||
|
||||
setId(result.value("id").toInteger());
|
||||
setName( result.value("first_name").toString());
|
||||
setUsername( result.value("username").toString());
|
||||
|
||||
}
|
||||
|
||||
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<QNetworkReply> &sender,
|
||||
const QWeakPointer<iFile>& receiver) {
|
||||
if (auto&& sharedPtr = sender.lock()) {
|
||||
auto&& ansver = makeMesasge<TelegramUpdateAnswer>(sharedPtr->readAll());
|
||||
void ITelegramBot::handleFileHeader(const QByteArray& header) {
|
||||
auto&& ansver = makeMesasge<TelegramUpdateAnswer>(header);
|
||||
|
||||
if (!ansver->isValid()) {
|
||||
onRequestError(ansver);
|
||||
return;
|
||||
}
|
||||
|
||||
auto &&fileMetaInfo = makeMesasge<TelegramFile>(ansver->result().toObject());
|
||||
|
||||
_filesMetaInfo.insert(fileMetaInfo->fileId(), fileMetaInfo);
|
||||
|
||||
if (auto&& sharedPtr = receiver.lock()) {
|
||||
auto&& downloadRequest = QSharedPointer<TelegrammDownloadFile>::create(fileMetaInfo->takePath());
|
||||
sharedPtr->setDownloadRequest(sendRequest(downloadRequest));
|
||||
}
|
||||
if (!ansver->isValid()) {
|
||||
onRequestError(ansver);
|
||||
return;
|
||||
}
|
||||
|
||||
auto &&fileMetaInfo = makeMesasge<TelegramFile>(ansver->result().toObject());
|
||||
|
||||
_filesMetaInfo.insert(fileMetaInfo->fileId(), fileMetaInfo);
|
||||
}
|
||||
|
||||
QString ITelegramBot::findFileInlocatStorage(const QString &fileId) const {
|
||||
|
@ -40,7 +40,9 @@ public:
|
||||
|
||||
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.
|
||||
@ -187,17 +189,20 @@ public:
|
||||
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<iFile> 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<QByteArray> 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 true if the reqests sents successful.
|
||||
* @return future objectl with result.
|
||||
*/
|
||||
QSharedPointer<QNetworkReply> getFileMeta(const QString& fileId,
|
||||
const QWeakPointer<iFile> &receiver = {nullptr});
|
||||
QFuture<QByteArray> getFileMeta(const QString& fileId);
|
||||
|
||||
bool sendFile( const QFileInfo& file, const QVariant& chatId) override;
|
||||
|
||||
@ -389,10 +394,9 @@ protected:
|
||||
const std::function<void(int msgId)>& msgIdCB = {});
|
||||
|
||||
private slots:
|
||||
void handleLogin();
|
||||
void handleLogin(const QByteArray &ansver);
|
||||
void handleLoginErr(QNetworkReply::NetworkError err);
|
||||
void handleFileHeader(const QWeakPointer<QNetworkReply>& sender,
|
||||
const QWeakPointer<iFile> &receiver);
|
||||
void handleFileHeader(const QByteArray &header);
|
||||
|
||||
private:
|
||||
|
||||
@ -405,7 +409,6 @@ private:
|
||||
|
||||
unsigned long long _id = 0;
|
||||
QString _username;
|
||||
QSharedPointer<QNetworkReply> _loginReplay;
|
||||
QMap<QString, std::function<void(const QString&, const QVariant&)>> _handleButtons;
|
||||
|
||||
QHash<unsigned long long, int> _lastMessageId;
|
||||
|
@ -13,7 +13,8 @@ TelegramArgs::TelegramArgs(const QVariant &id,
|
||||
unsigned long long replyToMessageId,
|
||||
const QString &parseMode,
|
||||
bool disableWebPagePreview,
|
||||
const QString &callBackQueryId, const std::function<void (int)> &msgIdCB)
|
||||
const QString &callBackQueryId, const std::function<void (int)> &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<QString, QVariant> TelegramArgs::toMap(bool textAsCaption) const {
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <QVariant>
|
||||
#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<void(int msgId)>& msgIdCB = {}
|
||||
const std::function<void(int msgId)>& 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<void(int msgId)> msgIdCB = {};
|
||||
|
||||
iRequest::RequestPriority requestPriority = iRequest::RequestPriority::NormalPriority;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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 <QJsonArray>
|
||||
#include <QTimer>
|
||||
#include <qTbot/messages/telegrammsg.h>
|
||||
#include <limits>
|
||||
|
||||
namespace qTbot {
|
||||
|
||||
@ -51,13 +51,12 @@ void TelegramRestBot::startUpdates() {
|
||||
if (delta >= _updateDelay) {
|
||||
auto&& replay = sendRequest(QSharedPointer<TelegramGetUpdate>::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<unsigned long long> &newProcessed)
|
||||
IBot::setProcessed(newProcessed);
|
||||
}
|
||||
|
||||
void TelegramRestBot::handleReceiveUpdates(const QWeakPointer<QNetworkReply> &replay) {
|
||||
void TelegramRestBot::handleReceiveUpdates(const QByteArray &replay) {
|
||||
auto&& telegramMsg = makeMesasge<TelegramUpdateAnswer>(replay);
|
||||
if (telegramMsg->isValid()) {
|
||||
|
||||
if (auto&& sharedReplay = replay.lock()) {
|
||||
auto&& telegramMsg = makeMesasge<TelegramUpdateAnswer>(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<TelegramUpdate>(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<TelegramUpdate>(ref.toObject());
|
||||
incomeNewUpdate(update);
|
||||
if (_lanstUpdateid < update->updateId()) {
|
||||
_lanstUpdateid = update->updateId();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
|
||||
void setProcessed(const QSet<unsigned long long> &newProcessed) override;
|
||||
private slots:
|
||||
void handleReceiveUpdates(const QWeakPointer<QNetworkReply>& replay);
|
||||
void handleReceiveUpdates(const QByteArray &replay);
|
||||
void handleReceiveUpdatesErr(QNetworkReply::NetworkError err);
|
||||
|
||||
private:
|
||||
|
@ -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<QNetworkReply> &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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<QNetworkReply>& 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
|
Loading…
x
Reference in New Issue
Block a user