10#include "qstandardpaths.h"
12#include <QNetworkReply>
18 _manager =
new QNetworkAccessManager();
19 _manager->setAutoDeleteReplies(
true);
20 _manager->setTransferTimeout(60000);
22 _requestExecutor =
new QTimer(
this);
23 _requestExecutor->setInterval(1000 / 20);
25 connect(_requestExecutor, &QTimer::timeout,
this , &IBot::handleEcxecuteRequest);
42 _startTime = QDateTime::currentDateTime();
47 if (!message->isValid())
50 auto id = message->updateId();
52 if (!_processed.contains(
id)) {
54 _processed.insert(
id);
55 _notProcessedUpdates[id] = message;
61QNetworkReply* IBot::sendRquestImpl(
const QSharedPointer<iRequest> &rquest) {
67#ifdef QTBOT_PRINT_RQUESTS
71 QNetworkReply* networkReplay =
nullptr;
73 switch (rquest->method()) {
75 networkReplay = _manager->get(QNetworkRequest(url));
86 QNetworkRequest netRequest(url);
88 auto httpData = rquest->argsToMultipartFormData();
90 networkReplay = _manager->post(netRequest, httpData.data());
91 connect(networkReplay, &QNetworkReply::destroyed, [httpData](){});
100 return networkReplay;
108 return _totalRequest;
112 return _parallelActiveNetworkThreads;
116 _parallelActiveNetworkThreads = newParallelActiveNetworkThreads;
119void IBot::setCurrentParallelActiveNetworkThreads(
int newParallelActiveNetworkThreads) {
120 bool wasBusy = _currentParallelActiveNetworkThreads == _parallelActiveNetworkThreads;
121 static bool lastMessageWasFree =
false;
124 _currentParallelActiveNetworkThreads = newParallelActiveNetworkThreads;
126 if (_currentParallelActiveNetworkThreads == _parallelActiveNetworkThreads) {
127 qInfo() <<
"All network threads are busy!";
128 lastMessageWasFree =
false;
130 }
else if (wasBusy) {
131 qInfo() <<
"Network threads are free! available: " << _currentParallelActiveNetworkThreads <<
" from " << _parallelActiveNetworkThreads;
132 lastMessageWasFree =
false;
134 }
else if (_currentParallelActiveNetworkThreads == 0 && !lastMessageWasFree) {
135 qInfo() <<
"All network threads are free!";
136 lastMessageWasFree =
true;
141 return _requestExecutor->interval() * 1000;
145 _requestExecutor->setInterval(1000 / newReqestLimitPerSecond);
150 auto&& responce = QSharedPointer<QPromise<QByteArray>>::create();
154 QMutexLocker lock(&_mutex);
155 _requestQueue.insert(makeKey(rquest->priority()),
159 if (!_requestExecutor->isActive()) {
160 handleEcxecuteRequest();
161 _requestExecutor->start();
165 return responce->future();
170 const QString &pathToResult) {
171 auto&& responce = QSharedPointer<QPromise<QByteArray>>::create();
175 QMutexLocker lock(&_mutex);
176 _requestQueue.insert(makeKey(rquest->priority()),
181 if (!_requestExecutor->isActive()) {
182 handleEcxecuteRequest();
183 _requestExecutor->start();
187 return responce->future();
192 _notProcessedUpdates.remove(message->updateId());
200 _processed.remove(messageID);
204 return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
211void IBot::handleEcxecuteRequest() {
212 QMutexLocker lock(&_mutex);
214 if (!_requestQueue.size()) {
215 _requestExecutor->stop();
219 if (_currentParallelActiveNetworkThreads > _parallelActiveNetworkThreads) {
223 auto&& requestData = _requestQueue.take(_requestQueue.firstKey());
225 if (requestData.responceFilePath.size()) {
226 sendRequestPrivate(requestData.request, requestData.responceFilePath, requestData.responce);
230 sendRequestPrivate(requestData.request, requestData.responce);
234 unsigned long long key = _totalRequest;
240void IBot::sendRequestPrivate(
const QSharedPointer<iRequest> &rquest,
241 const QSharedPointer<QPromise<QByteArray> > &promise) {
243 QNetworkReply* networkReplay = sendRquestImpl(rquest);
244 if (!networkReplay) {
248 setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1);
250 connect(networkReplay, &QNetworkReply::finished, [
this, networkReplay, promise](){
251 if (networkReplay->error() == QNetworkReply::NoError) {
252 promise->addResult(networkReplay->readAll());
256 QByteArray msg = networkReplay->errorString().toLatin1() + networkReplay->readAll();
257 promise->setException(HttpException(networkReplay->error(), msg));
258#ifdef QTBOT_PRINT_ERRORS
264 setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1);
268 auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){
270 if (promise->future().progressMaximum() != bytesTotal)
271 promise->setProgressRange(0, bytesTotal);
273 promise->setProgressValue(bytesCurrent);
276 connect(networkReplay, &QNetworkReply::downloadProgress, setProggress);
277 connect(networkReplay, &QNetworkReply::uploadProgress, setProggress);
280void IBot::sendRequestPrivate(
const QSharedPointer<iRequest> &rquest,
281 const QString &pathToResult,
282 const QSharedPointer<QPromise<QByteArray>> & promise) {
283 auto&& file = QSharedPointer<QFile>::create(pathToResult);
285 if (!file->open(QIODeviceBase::WriteOnly | QIODevice::Truncate)) {
286 qCritical() <<
"Fail to wrote data into " << pathToResult;
290 QNetworkReply* networkReplay = sendRquestImpl(rquest);
291 if (!networkReplay) {
295 setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1);
296 connect(networkReplay, &QNetworkReply::finished, [
this, promise, networkReplay, pathToResult](){
298 if (networkReplay->error() == QNetworkReply::NoError) {
299 QByteArray msg = networkReplay->errorString().toLatin1();
300 promise->setException(HttpException(networkReplay->error(), msg));
301#ifdef QTBOT_PRINT_ERRORS
305 promise->addResult(pathToResult.toUtf8());
308 setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1);
311 connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise, pathToResult, file](){
312 if (networkReplay->error() == QNetworkReply::NoError) {
313 file->write(networkReplay->readAll());
318 auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){
320 if (promise->future().progressMaximum() != bytesTotal)
321 promise->setProgressRange(0, bytesTotal);
323 promise->setProgressValue(bytesCurrent);
326 connect(networkReplay, &QNetworkReply::downloadProgress, setProggress);
327 connect(networkReplay, &QNetworkReply::uploadProgress, setProggress);
336 _processed = newProcessed;
348 if (_notProcessedUpdates.size()) {
349 auto toRemove = std::move(*_notProcessedUpdates.begin());
350 _notProcessedUpdates.erase(_notProcessedUpdates.cbegin());
virtual QString makeUrl(const QSharedPointer< iRequest > &request) const =0
makeUrl This method prepare a prefix url for http requests.
void setName(const QString &newName)
setName This method sets new value for the IBot::name field.
void sigReceiveUpdate(const QSharedPointer< qTbot::iUpdate > &)
sigReceiveUpdate emit when but receive any updates from users.
const QString & name() const
name This is name of the bot. usualy it fields will be received from the server after autication.
unsigned long long totalSentRequests() const
totalSentRequests This is total prepared requests count of bot from the start.
void markUpdateAsUnprocessed(const QSharedPointer< iUpdate > &message)
markMessageAsUnprocessed This method add the message into a not processed messages store.
void markUpdateAsProcessed(const QSharedPointer< iUpdate > &message)
markMessageAsProcessed This method remove message from the not processed messages store.
const QByteArray & token() const
token This is token value for authication on the remote server (bot)
int parallelActiveNetworkThreads() const
parallelActiveNetworkThreads
virtual void handleIncomeNewUpdate(const QSharedPointer< iUpdate > &)
handleIncomeNewUpdate This method just emit the sigReceiveUpdate signal.
int reqestLimitPerSecond() const
reqestLimitPerSecond this is request performence limitation. by default is 20 requests per second
void setReqestLimitPerSecond(int newReqestLimitPerSecond)
setReqestLimitPerSecond this method sets new limitation of bot performance.
virtual QString defaultFileStorageLocation() const
defaultFileStorageLocation This method return default file storage location.
void incomeNewUpdate(const QSharedPointer< iUpdate > &message)
incomeNewUpdate This method save incomed messages into store.
void setParallelActiveNetworkThreads(int newParallelActiveNetworkThreads)
setParallelActiveNetworkThreads
QSet< unsigned long long > processed() const
processed This method return list of processed mesages.
QFuture< QByteArray > sendRequest(const QSharedPointer< iRequest > &rquest)
sendRequest This method sent custom requests to the server.
virtual void setProcessed(const QSet< unsigned long long > &newProcessed)
setProcessed This method sets new list of processed mesages.
void setToken(const QByteArray &newToken)
setToken This is setter of the IBot::token value.
virtual void logout()
login This method remove login token of bot.
QDateTime startTime() const
startTime this is time when bol wil started.
QSharedPointer< iUpdate > takeNextUnreadUpdate()
takeNextUnreadUpdate This method take a unread update and mark them as read.
@ Post
general post request
@ Upload
this is post request to upload a big data to telegram
@ Get
general ger request, all request data sent as a url line
RequestPriority
The RequestPriority enum.
The RequestData class is simple wrapper of request object with path of responce. If Path of responce ...