10#include "qstandardpaths.h"
12#include <QNetworkReply>
18 _manager =
new QNetworkAccessManager();
19 _manager->setAutoDeleteReplies(
true);
20 _requestExecutor =
new QTimer(
this);
21 _requestExecutor->setInterval(1000 / 20);
23 connect(_requestExecutor, &QTimer::timeout,
this , &IBot::handleEcxecuteRequest);
40 _startTime = QDateTime::currentDateTime();
45 if (!message->isValid())
48 auto id = message->updateId();
50 if (!_processed.contains(
id)) {
52 _processed.insert(
id);
53 _notProcessedUpdates[id] = message;
59QNetworkReply* IBot::sendRquestImpl(
const QSharedPointer<iRequest> &rquest) {
65#ifdef QTBOT_PRINT_RQUESTS
69 QNetworkReply* networkReplay =
nullptr;
71 switch (rquest->method()) {
73 networkReplay = _manager->get(QNetworkRequest(url));
84 QNetworkRequest netRequest(url);
86 auto httpData = rquest->argsToMultipartFormData();
88 networkReplay = _manager->post(netRequest, httpData.data());
89 connect(networkReplay, &QNetworkReply::destroyed, [httpData](){});
106 return _totalRequest;
110 return _parallelActiveNetworkThreads;
114 _parallelActiveNetworkThreads = newParallelActiveNetworkThreads;
117void IBot::setCurrentParallelActiveNetworkThreads(
int newParallelActiveNetworkThreads) {
118 bool wasBusy = _currentParallelActiveNetworkThreads == _parallelActiveNetworkThreads;
119 static bool lastMessageWasFree =
false;
121 _currentParallelActiveNetworkThreads = newParallelActiveNetworkThreads;
123 if (_currentParallelActiveNetworkThreads == _parallelActiveNetworkThreads) {
124 qInfo() <<
"All network threads are busy!";
125 lastMessageWasFree =
false;
127 }
else if (wasBusy) {
128 qInfo() <<
"Network threads are free! available: " << _currentParallelActiveNetworkThreads <<
" from " << _parallelActiveNetworkThreads;
129 lastMessageWasFree =
false;
131 }
else if (_currentParallelActiveNetworkThreads == 0 && !lastMessageWasFree) {
132 qInfo() <<
"All network threads are free!";
133 lastMessageWasFree =
true;
138 return _requestExecutor->interval() * 1000;
142 _requestExecutor->setInterval(1000 / newReqestLimitPerSecond);
147 auto&& responce = QSharedPointer<QPromise<QByteArray>>::create();
151 QMutexLocker lock(&_mutex);
152 _requestQueue.insert(makeKey(rquest->priority()),
156 if (!_requestExecutor->isActive()) {
157 handleEcxecuteRequest();
158 _requestExecutor->start();
162 return responce->future();
167 const QString &pathToResult) {
168 auto&& responce = QSharedPointer<QPromise<QByteArray>>::create();
172 QMutexLocker lock(&_mutex);
173 _requestQueue.insert(makeKey(rquest->priority()),
178 if (!_requestExecutor->isActive()) {
179 handleEcxecuteRequest();
180 _requestExecutor->start();
184 return responce->future();
189 _notProcessedUpdates.remove(message->updateId());
197 _processed.remove(messageID);
201 return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
208void IBot::handleEcxecuteRequest() {
209 QMutexLocker lock(&_mutex);
211 if (!_requestQueue.size()) {
212 _requestExecutor->stop();
216 if (_currentParallelActiveNetworkThreads > _parallelActiveNetworkThreads) {
220 auto&& requestData = _requestQueue.take(_requestQueue.firstKey());
222 if (requestData.responceFilePath.size()) {
223 sendRequestPrivate(requestData.request, requestData.responceFilePath, requestData.responce);
227 sendRequestPrivate(requestData.request, requestData.responce);
231 unsigned long long key = _totalRequest;
237void IBot::sendRequestPrivate(
const QSharedPointer<iRequest> &rquest,
238 const QSharedPointer<QPromise<QByteArray> > &promise) {
240 QNetworkReply* networkReplay = sendRquestImpl(rquest);
241 if (!networkReplay) {
245 setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1);
247 connect(networkReplay, &QNetworkReply::finished, [
this, networkReplay, promise](){
248 if (networkReplay->error() == QNetworkReply::NoError) {
249 promise->addResult(networkReplay->readAll());
253 QByteArray msg = networkReplay->errorString().toLatin1() + networkReplay->readAll();
254 promise->setException(HttpException(networkReplay->error(), msg));
255#ifdef QTBOT_PRINT_ERRORS
261 setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1);
265 auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){
267 if (promise->future().progressMaximum() != bytesTotal)
268 promise->setProgressRange(0, bytesTotal);
270 promise->setProgressValue(bytesCurrent);
273 connect(networkReplay, &QNetworkReply::downloadProgress, setProggress);
274 connect(networkReplay, &QNetworkReply::uploadProgress, setProggress);
277void IBot::sendRequestPrivate(
const QSharedPointer<iRequest> &rquest,
278 const QString &pathToResult,
279 const QSharedPointer<QPromise<QByteArray>> & promise) {
280 auto&& file = QSharedPointer<QFile>::create(pathToResult);
282 if (!file->open(QIODeviceBase::WriteOnly | QIODevice::Truncate)) {
283 qCritical() <<
"Fail to wrote data into " << pathToResult;
287 QNetworkReply* networkReplay = sendRquestImpl(rquest);
288 if (!networkReplay) {
292 setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads + 1);
293 connect(networkReplay, &QNetworkReply::finished, [
this, promise, networkReplay, pathToResult](){
295 if (networkReplay->error() == QNetworkReply::NoError) {
296 QByteArray msg = networkReplay->errorString().toLatin1();
297 promise->setException(HttpException(networkReplay->error(), msg));
298#ifdef QTBOT_PRINT_ERRORS
302 promise->addResult(pathToResult.toUtf8());
305 setCurrentParallelActiveNetworkThreads(_currentParallelActiveNetworkThreads - 1);
308 connect(networkReplay, &QNetworkReply::readyRead, [networkReplay, promise, pathToResult, file](){
309 if (networkReplay->error() == QNetworkReply::NoError) {
310 file->write(networkReplay->readAll());
315 auto && setProggress = [promise](qint64 bytesCurrent, qint64 bytesTotal){
317 if (promise->future().progressMaximum() != bytesTotal)
318 promise->setProgressRange(0, bytesTotal);
320 promise->setProgressValue(bytesCurrent);
323 connect(networkReplay, &QNetworkReply::downloadProgress, setProggress);
324 connect(networkReplay, &QNetworkReply::uploadProgress, setProggress);
333 _processed = newProcessed;
345 if (_notProcessedUpdates.size()) {
346 auto toRemove = std::move(*_notProcessedUpdates.begin());
347 _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 ...