qTbot 0.2.106.03782ba
qTbot is base back end library for your c++ Qt projects.
itelegrambot.cpp
Go to the documentation of this file.
1//#
2//# Copyright (C) 2018-2024 QuasarApp.
3//# Distributed under the GPLv3 software license, see the accompanying
4//# Everyone is permitted to copy and distribute verbatim copies
5//# of this license document, but changing it is not allowed.
6//#
7
8#include "itelegrambot.h"
11#include "qdir.h"
14#include "httpexception.h"
15#include "internalexception.h"
16#include <QNetworkAccessManager>
17
26
27#include <QNetworkReply>
28#include <QSharedPointer>
29#include <QDebug>
30#include <QJsonArray>
31#include <QJsonObject>
32#include <QJsonDocument>
33
37
38
39namespace qTbot {
40
44
47
48bool ITelegramBot::login(const QByteArray &token) {
49 if (token.isEmpty()) {
50 return false;
51 }
52
54
55 QFuture<QByteArray> loginFuture = sendRequest(QSharedPointer<TelegramGetMe>::create());
56 loginFuture.
57 then(this, [this](const QByteArray& data) {
58 ITelegramBot::handleLogin(data);
59 } ).
60 onFailed(this, [this](const HttpException& exeption){
61 handleLoginErr(exeption.code());
62 });
63
64 return loginFuture.isValid();
65}
66
67bool ITelegramBot::sendMessage(const QVariant &chatId,
68 const QString &text,
70 TelegramArgs arg{chatId, text};
71 arg.requestPriority = priority;
72 return sendSpecificMessage(arg);
73}
74
75bool ITelegramBot::sendLocationRequest(const QVariant &chatId,
76 const QString &text,
77 const QString &buttonText,
78 bool onetimeKeyboard) {
79
80 auto replyMarkup = QSharedPointer<QJsonObject>::create();
81 QJsonArray keyboard;
82 QJsonObject contactButton;
83 contactButton["text"] = buttonText;
84 contactButton["request_location"] = true;
85 QJsonArray row;
86 row.append(contactButton);
87 keyboard.append(row);
88 replyMarkup->insert("keyboard", keyboard);
89 replyMarkup->insert("resize_keyboard", true);
90 replyMarkup->insert("one_time_keyboard", onetimeKeyboard);
91
92 return sendSpecificMessage(TelegramArgs{chatId, text}, {{"reply_markup", replyMarkup}});
93}
94
95bool ITelegramBot::sendSelfContactRequest(const QVariant &chatId, const QString &text, const QString &buttonText,
96 bool onetimeKeyboard) {
97 auto replyMarkup = QSharedPointer<QJsonObject>::create();
98 QJsonArray keyboard;
99 QJsonObject contactButton;
100 contactButton["text"] = buttonText;
101 contactButton["request_contact"] = true;
102 QJsonArray row;
103 row.append(contactButton);
104 keyboard.append(row);
105 replyMarkup->insert("keyboard", keyboard);
106 replyMarkup->insert("resize_keyboard", true);
107 replyMarkup->insert("one_time_keyboard", onetimeKeyboard);
108
109 return sendSpecificMessage(TelegramArgs{chatId, text}, {{"reply_markup", replyMarkup}});
110}
111
113 const ExtraJsonObjects &extraObjects) {
114
115 if (!args.chatId.isValid() || args.chatId.isNull())
116 return false;
117
118 if (args.text.isEmpty()) {
119 return false;
120 }
121
122 auto msg = QSharedPointer<TelegramSendMsg>::create(args, extraObjects);
123
124 return sendMessageRequest(msg, args.msgIdCB);
125}
126
128 const KeyboardOnMessage &keyboard) {
129 return sendSpecificMessage(args, prepareInlineKeyBoard(keyboard));
130}
131
132bool ITelegramBot::deleteMessage(const QVariant &chatId, const QVariant &messageId) {
133 if (!chatId.isValid() || chatId.isNull())
134 return false;
135
136 if (!messageId.isValid() || messageId.isNull())
137 return false;
138
139 auto msg = QSharedPointer<TelegramDeleteMessage>::create(chatId,
140 messageId);
141
142 return sendMessageRequest(msg);
143}
144
146 const TelegramArgs& args,
147 const QList<QList<QString> > &keyboard,
148 bool onTimeKeyboard,
149 bool autoResizeKeyboard) {
150
151 if (!args.chatId.isValid() || args.chatId.isNull())
152 return false;
153
154 if (!messageId.isValid() || messageId.isNull())
155 return false;
156
157 auto msg = QSharedPointer<TelegramEditMessage>::create(messageId,
158 args,
159 prepareKeyboard(autoResizeKeyboard,
160 onTimeKeyboard,
161 keyboard));
162
163 return sendMessageRequest(msg, args.msgIdCB);
164}
165
167qTbot::ITelegramBot::prepareInlineKeyBoard(const KeyboardOnMessage &keyboard)
168{
169 ExtraJsonObjects extraObjects;
170 auto&& keyboardJson = QSharedPointer<QJsonObject>::create();
171 QJsonArray keyboardArray;
172
173 for (const auto& map : keyboard) {
174 QJsonArray keyboardLineArray;
175 for (auto it = map.begin(); it != map.end(); it = std::next(it)) {
176 auto&& callBackKey = QString("callback_data_%0").arg(rand());
177 keyboardLineArray.push_back(QJsonObject{ {"text", it.key()}, {"callback_data", callBackKey } });
178 _handleButtons[callBackKey] = {it.value()};
179 }
180 keyboardArray.push_back(keyboardLineArray);
181 }
182
183
184 (*keyboardJson)["inline_keyboard"] = keyboardArray;
185
186 extraObjects["reply_markup"] = keyboardJson;
187
188 return extraObjects;
189}
190
192qTbot::ITelegramBot::prepareKeyboard(bool autoResizeKeyboard,
193 bool onTimeKeyboard,
194 const QList<QList<QString>> &keyboard) {
195 ExtraJsonObjects extraObjects;
196 auto&& keyboardJson = QSharedPointer<QJsonObject>::create();
197 QJsonArray keyboardArray;
198
199 for (const auto &row :keyboard) {
200 QJsonArray keyboardLineArray;
201
202 for (auto it = row.begin(); it != row.end(); it = std::next(it)) {
203 keyboardLineArray.push_back(QJsonObject{ {"text", *it} });
204 }
205 keyboardArray.push_back(keyboardLineArray);
206
207 }
208
209 (*keyboardJson)["keyboard"] = keyboardArray;
210
211 (*keyboardJson)["resize_keyboard"] = autoResizeKeyboard;
212 (*keyboardJson)["one_time_keyboard"] = onTimeKeyboard;
213
214 extraObjects["reply_markup"] = keyboardJson;
215
216 return extraObjects;
217}
218
220 const TelegramArgs& args,
221
222 const KeyboardOnMessage &keyboard ) {
223
224 if (!args.chatId.isValid() || args.chatId.isNull())
225 return false;
226
227 if (!messageId.isValid() || messageId.isNull())
228 return false;
229
230 auto msg = QSharedPointer<TelegramEditMessage>::create(messageId,
231 args,
232 prepareInlineKeyBoard(keyboard));
233
234
235 return sendMessageRequest(msg);
236}
237
238bool ITelegramBot::editMessageKeyboard(const QVariant &messageId,
239 const QVariant &chatId,
240 const KeyboardOnMessage &keyboard,
241 const QString &callBackQueryId) {
242 if (!chatId.isValid() || chatId.isNull())
243 return false;
244
245 if (!messageId.isValid() || messageId.isNull())
246 return false;
247
248 auto msg = QSharedPointer<TelegramEditMessageReplyMarkup>::create(messageId,
249 TelegramArgs(chatId, "", 0, "html", false, callBackQueryId),
250 prepareInlineKeyBoard(keyboard));
251
252
253 return sendMessageRequest(msg);
254}
255
256bool ITelegramBot::editSpecificMessage(const QVariant &messageId,
257 const TelegramArgs& args) {
258
259 if (!args.chatId.isValid() || args.chatId.isNull())
260 return false;
261
262 if (!messageId.isValid() || messageId.isNull())
263 return false;
264
265 if (args.text.isEmpty())
266 return false;
267
268 auto msg = QSharedPointer<TelegramEditMessage>::create(messageId,
269 args
270 );
271
272
273 return sendMessageRequest(msg);
274}
275
277 const QList<QList<QString> > &keyboard,
278 bool onTimeKeyboard,
279 bool autoResizeKeyboard) {
280
281 if (!args.chatId.isValid() || args.chatId.isNull())
282 return false;
283
284 if (args.text.isEmpty()) {
285 return false;
286 }
287
288 return sendSpecificMessage(args, prepareKeyboard(autoResizeKeyboard, onTimeKeyboard, keyboard));
289}
290
291QFuture<QByteArray> ITelegramBot::getFile(const QString &fileId, FileType fileType) {
292
293
294 if (fileId.isEmpty()) {
295 return {};
296 }
297
298 auto localFilePath = findFileInlocatStorage(fileId);
299
300 if (!localFilePath.isEmpty()) {
301 QPromise<QByteArray> fileDataResult;
302 fileDataResult.start();
303
304 if (fileType == FileType::Ram) {
305 QFile localFile(localFilePath);
306 if (localFile.open(QIODevice::ReadOnly)) {
307 fileDataResult.addResult(localFile.readAll());
308 localFile.close();
309 }
310
311 } else if (fileType == FileType::Local) {
312 fileDataResult.addResult(localFilePath.toUtf8());
313 }
314
315 fileDataResult.setProgressRange(0,1);
316 fileDataResult.setProgressValue(1);
317
318 fileDataResult.finish();
319
320 return fileDataResult.future();
321 }
322
323 auto&& metaInfo = getFileInfoByUniqueId(fileId);
324 localFilePath = defaultFileStorageLocation() + "/" + fileId;
325
326 if (metaInfo) {
327 auto&& path = metaInfo->takePath();
328 if (path.size()) {
329 auto&& msg = QSharedPointer<TelegrammDownloadFile>::create(path);
330
331 QDir().mkpath(defaultFileStorageLocation());
332
333
334 if (localFilePath.isEmpty())
335 return {};
336
337 QFuture<QByteArray> replay;
338 if (fileType == FileType::Ram) {
339 replay = sendRequest(msg);
340 } else {
341 replay = sendRequest(msg, localFilePath);
342 }
343
344 return replay;
345 }
346 }
347
348 auto longWay = QSharedPointer<QPromise<QByteArray>>::create();
349 longWay->start();
350
351 auto&& future = getFileMeta(fileId);
352 if (!future.isValid()) {
353 return {};
354 }
355
356 future.then([this, fileId, fileType, longWay](const QByteArray& header){
357 handleFileHeader(header);
358
359 auto&& future = getFile(fileId, fileType);
360
361 if (!future.isValid()) {
362 longWay->setException(InternalException("Failed to wrote file into internal cache!"));
363 return;
364 };
365
366 future.then([longWay](const QByteArray& data){
367 longWay->addResult(data);
368 longWay->finish();
369 }).onFailed([longWay](const QException& exep){
370 longWay->setException(exep);
371 });
372
373
374 }).onFailed([longWay](const QException& exep){
375 longWay->setException(exep);
376 });
377
378 return longWay->future();
379}
380
381QFuture<QByteArray> ITelegramBot::getFileMeta(const QString &fileId) {
382 auto msg = QSharedPointer<TelegramGetFile>::create(fileId);
383 auto && future = sendRequest(msg);
384 if (future.isValid()) {
385 return future;
386 }
387
388 return {};
389}
390
391bool ITelegramBot::sendFile(const QFileInfo &file, const QVariant &chatId) {
392 return sendFileMessage({chatId}, file);
393}
394
395bool ITelegramBot::sendFile(const QByteArray &file, const QString &fileName, const QVariant &chatId) {
396 return sendFileMessage({chatId}, file, fileName);
397}
398
399bool ITelegramBot::sendFileMessage(const TelegramArgs &args, const QFileInfo &file) {
400 if (!args.chatId.isValid() || args.chatId.isNull())
401 return false;
402
403 if (!file.isReadable()) {
404 return false;
405 }
406
407 return sendMessageRequest(
408 QSharedPointer<TelegramSendPhoto>::create(args,
409 file), args.msgIdCB);
410}
411
412bool ITelegramBot::sendFileMessage(const TelegramArgs &args, const QByteArray &file, const QString &fileName) {
413 if (!args.chatId.isValid() || args.chatId.isNull())
414 return false;
415
416 if (!fileName.size()) {
417 return false;
418 }
419
420 if (!file.size()) {
421 return false;
422 }
423
424 return sendMessageRequest(QSharedPointer<TelegramSendDocument>::create(args, fileName, file), args.msgIdCB);
425}
426
428 const QFileInfo &photo,
429 const KeyboardOnMessage &keyboard) {
430 if (!args.chatId.isValid() || args.chatId.isNull())
431 return false;
432
433 if (!photo.isReadable()) {
434 return false;
435 }
436
437 return sendMessageRequest(
438 QSharedPointer<TelegramSendPhoto>::create(args,
439 photo,
440 prepareInlineKeyBoard(keyboard)), args.msgIdCB);
441}
442
444 const QByteArray &photo,
445 const QString &fileName,
446 const KeyboardOnMessage &keyboard) {
447
448 if (!args.chatId.isValid() || args.chatId.isNull()) {
449 return false;
450 }
451
452 if (!fileName.size()) {
453 return false;
454 }
455
456 if (!photo.size()) {
457 return false;
458 }
459
460 return sendMessageRequest(
461 QSharedPointer<TelegramSendPhoto>::create(args,
462 fileName,
463 photo,
464 prepareInlineKeyBoard(keyboard)),
465 args.msgIdCB);
466}
467
468bool ITelegramBot::sendFileById(const QString &fileID, const QVariant &chatId) {
469 Q_UNUSED(fileID)
470 Q_UNUSED(chatId)
471
472 throw "the sendFileById is not implemented";
473
474 return false;
475
476}
477
479 float latitude,
480 float longitude,
481 const KeyboardOnMessage &keyboard) {
482
483 if (!args.chatId.isValid() || args.chatId.isNull())
484 return false;
485
486 if (!(longitude && latitude)) {
487 return false;
488 }
489
490 return sendMessageRequest(QSharedPointer<TelegramSendLocation>::create(args,
491 latitude,
492 longitude,
493 prepareInlineKeyBoard(keyboard)));
494}
495
497 const QString &phone,
498 const QString &firstName,
499 const QString &secondName) {
500 if (!args.chatId.isValid() || args.chatId.isNull())
501 return false;
502
503 return sendMessageRequest(QSharedPointer<TelegramSendContact>::create(args,
504 firstName,
505 phone,
506 secondName));
507}
508
509int ITelegramBot::getFileSizeByUniqueId(const QString &id) const {
510 if (auto && file = _filesMetaInfo.value(id)) {
511 return file->fileSize();
512 }
513
514 return 0;
515}
516
517QSharedPointer<TelegramFile> ITelegramBot::getFileInfoByUniqueId(const QString &id) const {
518 return _filesMetaInfo.value(id, nullptr);
519}
520
521void ITelegramBot::onRequestError(const QSharedPointer<TelegramUpdateAnswer> &ansverWithError) const {
522 qWarning() << QString("code: %0 - %1").
523 arg(ansverWithError->errorCode()).
524 arg(ansverWithError->errorDescription());
525}
526
527void ITelegramBot::handleIncomeNewUpdate(const QSharedPointer<iUpdate> & update) {
529
530
531 if (auto&& tupdate = update.dynamicCast<TelegramUpdate>()) {
532
533 if (auto&& queryUpd = tupdate->callbackQueryUpdate()) {
534 auto &&handleButtonKey = queryUpd->callBackData();
535
536 if (auto&& cb = _handleButtons.value(handleButtonKey)) {
537 cb(handleButtonKey, queryUpd->messageId());
538 }
539 }
540 }
541}
542
543bool ITelegramBot::sendMessageRequest(const QSharedPointer<iRequest> &rquest,
544 const std::function<void (int)> &msgIdCB) {
545 auto&& future = IBot::sendRequest(rquest);
546 if (future.isValid()) {
547 future.then(this, [this, msgIdCB](const QByteArray& responseData){
548
549 QJsonDocument json = QJsonDocument::fromJson(responseData);
550
551 const QJsonObject&& obj = json.object();
552 if (obj.contains("result")) {
553 unsigned long long chatId = obj["result"]["chat"]["id"].toInteger();
554 int messageID = obj["result"]["message_id"].toInt();
555 if (msgIdCB) {
556 msgIdCB(messageID);
557 }
558
559 if (chatId) {
560 _lastMessageId[chatId] = messageID;
561 }
562
563 return;
564 }
565 }).onFailed([msgIdCB](){
566
567 if (msgIdCB) {
568 msgIdCB(-1);
569 }
570 });
571
572 return true;
573 }
574
575 return false;
576}
577
578void ITelegramBot::handleLogin(const QByteArray&ansver) {
579
581
582 if (!ans->isValid()) {
583 qWarning() << "login error occured: ";
584 return;
585 }
586
587 auto&& result = ans->result().toObject();
588
589 setId(result.value("id").toInteger());
590 setName( result.value("first_name").toString());
591 setUsername( result.value("username").toString());
592
593}
594
595void ITelegramBot::handleLoginErr(QNetworkReply::NetworkError err) {
596 if (err) {
597 qCritical() << "Network error occured. code: " << err;
598 }
599}
600
601void ITelegramBot::handleFileHeader(const QByteArray& header) {
603
604 if (!ansver->isValid()) {
606 return;
607 }
608
609 auto &&fileMetaInfo = makeMesasge<TelegramFile>(ansver->result().toObject());
610
611 _filesMetaInfo.insert(fileMetaInfo->fileId(), fileMetaInfo);
612}
613
614QString ITelegramBot::findFileInlocatStorage(const QString &fileId) const {
616
617 auto &&localStorageList = defaultFileDir.entryInfoList(QDir::Filter::NoDotAndDotDot | QDir::Files);
618 for (const auto& file: localStorageList) {
619 int size = file.size();
620 if (file.fileName().contains(fileId) && size && size == getFileSizeByUniqueId(fileId)) {
621 return file.absoluteFilePath();
622 }
623 }
624
625 return "";
626}
627
628void ITelegramBot::setUsername(const QString &newUsername) {
629 _username = newUsername;
630}
631
632QString ITelegramBot::makeUrl(const QSharedPointer<iRequest> &request) const {
633 return request->baseAddress() + "/bot" + token() + request->makeUpload();
634}
635
636void ITelegramBot::setId(unsigned long long newId) {
637 _id = newId;
638}
639
640const QString &ITelegramBot::username() const {
641 return _username;
642}
643
644int ITelegramBot::gelLastMessageId(unsigned long long &chatId) const {
645 return _lastMessageId.value(chatId, 0);
646}
647
648unsigned long long ITelegramBot::id() const {
649 return _id;
650}
651
652} // namespace qTbot
The HttpException class is base exaption that will raise on all errors of the HTTP protocol,...
QNetworkReply::NetworkError code() const
void setName(const QString &newName)
setName This method sets new value for the IBot::name field.
Definition ibot.cpp:316
static QSharedPointer< MessageType > makeMesasge(const QByteArray &data, Args &&...args)
makeMesasge This is factory method tha can create a messages types.
Definition ibot.h:216
FileType
The FileType enum is is file types, deffine how we should download a file - as a local object in file...
Definition ibot.h:44
@ Local
Definition ibot.h:51
@ Ram
The Ram is a Virtual type of download files will save all file data into QFuture bytes array.
Definition ibot.h:46
const QByteArray & token() const
token This is token value for authication on the remote server (bot)
Definition ibot.cpp:34
virtual void handleIncomeNewUpdate(const QSharedPointer< iUpdate > &)
handleIncomeNewUpdate This method just emit the sigReceiveUpdate signal.
Definition ibot.cpp:182
virtual QString defaultFileStorageLocation() const
defaultFileStorageLocation This method return default file storage location.
Definition ibot.cpp:178
QFuture< QByteArray > sendRequest(const QSharedPointer< iRequest > &rquest)
sendRequest This method sent custom requests to the server.
Definition ibot.cpp:130
void setToken(const QByteArray &newToken)
setToken This is setter of the IBot::token value.
Definition ibot.cpp:38
bool sendFile(const QFileInfo &file, const QVariant &chatId) override
send file .
bool sendFileById(const QString &fileID, const QVariant &chatId)
sendFileById This is specific method of the telegram bot. sents file by id.
int getFileSizeByUniqueId(const QString &id) const
getFileSizeByUniqueId This method return size of the file by id
bool editMessageKeyboard(const QVariant &messageId, const QVariant &chatId, const KeyboardOnMessage &keyboard={}, const QString &callBackQueryId="")
Edits a keyboard of message in a chat.
const QString & username() const
username This is bots login
void setId(unsigned long long newId)
setId This method sets new value for the ITelegramBot::id property.
int gelLastMessageId(unsigned long long &chatId) const
gelLastMessageId this method returns last sendet message id.
QFuture< QByteArray > getFile(const QString &fileId, FileType fileType=FileType::Ram) override
getFile This method sent request to get a file by id. The files can be saved into local storage if th...
QSharedPointer< TelegramFile > getFileInfoByUniqueId(const QString &id) const
getFileInfoByUniqueId return a local saved meta information about the file.
QFuture< QByteArray > getFileMeta(const QString &fileId)
getFileMeta This method receive meta information of the file.
bool sendFileMessage(const TelegramArgs &args, const QFileInfo &file)
sendFileMessage This method sents a message with file.
virtual void onRequestError(const QSharedPointer< TelegramUpdateAnswer > &ansverWithError) const
onRequestError This method invokent when telegram server sent error responce. Default implementation ...
bool editSpecificMessage(const QVariant &messageId, const TelegramArgs &args)
Edits a specific message in a chat.
bool sendSpecificMessageWithKeyboard(const TelegramArgs &args, const KeyboardOnMessage &keyboard)
Sends a specific message with a custom keyboard to a chat. This function sends a specific message to ...
void handleIncomeNewUpdate(const QSharedPointer< iUpdate > &) override
handleIncomeNewUpdate This method just emit the sigReceiveUpdate signal.
bool sendLocation(const TelegramArgs &args, float latitude, float longitude, const KeyboardOnMessage &keyboard={})
sendLocation This method sents locatin to user.
unsigned long long id() const
id This method return bots id number.
bool sendLocationRequest(const QVariant &chatId, const QString &text, const QString &buttonText, bool onetimeKeyboard)
sendLocationRequest This method setn into chat button that will automaticaly sent geo location to bot...
bool sendSelfContactRequest(const QVariant &chatId, const QString &text, const QString &buttonText, bool onetimeKeyboard)
sendSelfContactRequest This method sent into chat button that will automaticaly sent self contact inf...
bool sendMessage(const QVariant &chatId, const QString &text, iRequest::RequestPriority priority=iRequest::NormalPriority) override
sendMessage This method sents text to the selected chat.
virtual bool sendMessageRequest(const QSharedPointer< iRequest > &rquest, const std::function< void(int msgId)> &msgIdCB={})
sendMessageRequest This method invoke when bot will be sent eny messages into chat.
void setUsername(const QString &newUsername)
setUsername This method sets new value for the ITelegramBot::username property.
QString makeUrl(const QSharedPointer< iRequest > &request) const override
makeUrl This method prepare a prefix url for http requests.
bool sendContact(const TelegramArgs &args, const QString &phone, const QString &firstName, const QString &secondName="")
sendContact This method sents a contact data.
bool sendPhoto(const TelegramArgs &args, const QFileInfo &photo, const KeyboardOnMessage &keyboard={})
sendPhoto This method will send image into chat with chatId
bool login(const QByteArray &token) override
login This method get bae information of the bot from remote server.
bool sendSpecificMessage(const TelegramArgs &args, const qTbot::ExtraJsonObjects &extraObjects={})
Sends a specific message to a chat.
bool deleteMessage(const QVariant &chatId, const QVariant &messageId) override
deleteMessage This is main method to delete messages.
bool editSpecificMessageWithKeyboard(const QVariant &messageId, const TelegramArgs &args, const QList< QList< QString > > &keyboard={}, bool onTimeKeyboard=false, bool autoResizeKeyboard=false)
Edits a specific message with a custom keyboard in a chat.
The InternalException class contais string value to describe what happened.
The TelegramUpdate class contains base information about updates from telegram.
RequestPriority
The RequestPriority enum.
Definition irequest.h:52
QHash< QString, QSharedPointer< QJsonObject > > ExtraJsonObjects
ExtraJsonObjects hash map of the extra objects of the message.
Definition irequest.h:26
QList< QHash< QString, ButtonCB > > KeyboardOnMessage
The TelegramArgs class is base structure for the all tellegram message arguments.
iRequest::RequestPriority requestPriority
std::function< void(int msgId)> msgIdCB
msgIdCB This is id message call bak function. Will be inwoked when request finished successful.
QVariant chatId
Chat ID where the message will be sent. Default: {}.
QString text
Text of the message. Default: "".