git-svn-id: svn://db.shs.com.ru/libs@132 a8b55f48-bf90-11e4-a774-851b48703e85
This commit is contained in:
358
telegram_bot/telegrambotapi.cpp
Normal file
358
telegram_bot/telegrambotapi.cpp
Normal file
@@ -0,0 +1,358 @@
|
||||
#include "telegrambotapi.h"
|
||||
//#include <QMessageBox>
|
||||
#include <QSslError>
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
#include <QDateTime>
|
||||
#include <QHttpMultiPart>
|
||||
#include "json.h"
|
||||
|
||||
|
||||
const char * TelegramBotAPI::send_methods[] = {
|
||||
"sendMessage",
|
||||
"sendPhoto",
|
||||
"sendDocument",
|
||||
};
|
||||
const char * TelegramBotAPI::param_filename = "__filename";
|
||||
|
||||
TelegramBotAPI::TelegramBotAPI(QObject *parent) : QObject(parent) {
|
||||
is_connected = false;
|
||||
wait_server = false;
|
||||
has_stop = false;
|
||||
qRegisterMetaType<TelegramBotAPI::Message>("TelegramBotAPI::Message");
|
||||
qnam = new QNetworkAccessManager();
|
||||
// connect(qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(httpFinished(QNetworkReply*)));
|
||||
connect(qnam, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
|
||||
}
|
||||
|
||||
|
||||
TelegramBotAPI::~TelegramBotAPI() {
|
||||
has_stop = true;
|
||||
// msleep(60);
|
||||
}
|
||||
|
||||
|
||||
void TelegramBotAPI::setBotToken(QString arg) {
|
||||
if (m_botToken == arg) {
|
||||
checkBot();
|
||||
return;
|
||||
}
|
||||
is_connected = false;
|
||||
m_botToken = arg;
|
||||
botUrl = "https://api.telegram.org/bot"+m_botToken+"/";
|
||||
checkBot();
|
||||
}
|
||||
|
||||
|
||||
bool TelegramBotAPI::sendMessage(uint chat_id, TelegramBotAPI::MessageType mtype, QByteArray data, QString filename) {
|
||||
if (!is_connected || chat_id == 0 || data.isEmpty()) return false;
|
||||
SendQuery sq;
|
||||
sq.params["chat_id"] = chat_id;
|
||||
sq.method = send_methods[mtype];
|
||||
bool ok = false;
|
||||
switch (mtype) {
|
||||
case Text:
|
||||
sq.params["text"] = QString::fromUtf8(data.data(), data.size());
|
||||
ok = true;
|
||||
break;
|
||||
case Photo:
|
||||
if (!filename.isEmpty()) {
|
||||
sq.params[param_filename] = filename;
|
||||
sq.params["photo"] = data;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
case Document:
|
||||
if (!filename.isEmpty()) {
|
||||
sq.params[param_filename] = filename;
|
||||
sq.params["document"] = data;
|
||||
ok = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ok) {
|
||||
sendmsg_que.enqueue(sq);
|
||||
if (wait_server) {
|
||||
if (reply->url().toString().split("/").last() == "getUpdates") reply->abort();
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
//void TelegramBot::run() {
|
||||
// while (!has_stop) {
|
||||
// mutex.lock();
|
||||
// if (qnam == 0) {
|
||||
// qnam = new QNetworkAccessManager();
|
||||
// connect(qnam, SIGNAL(finished(QNetworkReply*)),
|
||||
// this, SLOT(httpFinished(QNetworkReply*)));
|
||||
// connect(qnam, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
|
||||
// }
|
||||
// if (!wait_server) {
|
||||
// if (!is_connected) checkBot();
|
||||
// updateBot();
|
||||
// }
|
||||
// mutex.unlock();
|
||||
// msleep(50);
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
void TelegramBotAPI::updateBot() {
|
||||
if (!is_connected) return;
|
||||
QVariantMap vm;
|
||||
vm["timeout"] = 50;
|
||||
vm["offset"] = last_update;
|
||||
sendRequest("getUpdates", vm);
|
||||
}
|
||||
|
||||
|
||||
bool TelegramBotAPI::fileDownload() {
|
||||
if (download_list.isEmpty()) return false;
|
||||
bool ok = false;
|
||||
int rm = -1;
|
||||
for(int i=0; i<download_list.size(); i++) {
|
||||
DownloadFile & df = download_list[i];
|
||||
qDebug() << df.id << df.url << df.filename;
|
||||
if (df.url.isEmpty()) {
|
||||
QVariantMap fm;
|
||||
fm["file_id"] = df.id;
|
||||
sendRequest("getFile", fm);
|
||||
return true;
|
||||
} else {
|
||||
if (!df.downloaded) {
|
||||
QNetworkRequest nr;
|
||||
nr.setUrl(df.url);
|
||||
reply = qnam->get(nr);
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(httpFinished()));
|
||||
return true;
|
||||
} else {
|
||||
File f;
|
||||
f.chat_id = df.chat_id;
|
||||
f.filename = df.filename;
|
||||
f.data = df.data;
|
||||
emit newFile(f);
|
||||
rm = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rm >= 0) download_list.removeAt(rm);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
void TelegramBotAPI::checkBot() {
|
||||
sendRequest("getMe", QVariantMap());
|
||||
}
|
||||
|
||||
|
||||
bool TelegramBotAPI::parseHeader(QString json, QVariant & res) {
|
||||
bool ok;
|
||||
QVariantMap map = QtJson::parse(json, ok).toMap();
|
||||
if (!ok) {
|
||||
emit errorOccured("parse JSON error");
|
||||
return false;
|
||||
}
|
||||
if (!map.value("ok").toBool()) {
|
||||
emit errorOccured("query error");
|
||||
return false;
|
||||
}
|
||||
res = map.value("result");
|
||||
return !res.isNull() && res.isValid();
|
||||
}
|
||||
|
||||
|
||||
void TelegramBotAPI::parseCheckBot(QString json) {
|
||||
QVariant res;
|
||||
if (!parseHeader(json, res)) {
|
||||
is_connected = false;
|
||||
emit botFail();
|
||||
return;
|
||||
}
|
||||
QVariantMap resm = res.toMap();
|
||||
m_botID = resm.value("id").toUInt();
|
||||
m_botName = resm.value("username").toString();
|
||||
is_connected = true;
|
||||
last_update = 0;
|
||||
emit botOK();
|
||||
}
|
||||
|
||||
|
||||
void TelegramBotAPI::parseFile(QString json) {
|
||||
QVariant res;
|
||||
if (!parseHeader(json, res)) {
|
||||
emit errorOccured("can't get file");
|
||||
return;
|
||||
}
|
||||
QVariantMap resm = res.toMap();
|
||||
QString fpath = resm["file_path"].toString();
|
||||
QString fid = resm["file_id"].toString();
|
||||
if (fpath.isEmpty()) return;
|
||||
QUrl furl = QUrl("https://api.telegram.org/file/bot"+m_botToken+"/"+fpath);
|
||||
qDebug() << "new file :" << furl;
|
||||
for (int i=0; i<download_list.size(); i++) {
|
||||
if (download_list[i].id == fid) {
|
||||
download_list[i].url = furl;
|
||||
if (download_list[i].filename.isEmpty())
|
||||
download_list[i].filename = fpath.split("/").last();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TelegramBotAPI::parseMessages(QString json) {
|
||||
QVariant res;
|
||||
if (!parseHeader(json, res)) {
|
||||
emit errorOccured("can't update");
|
||||
return;
|
||||
}
|
||||
QVariantList resm = res.toList();
|
||||
foreach (QVariant v, resm) {
|
||||
QVariantMap mm = v.toMap();
|
||||
last_update = mm.value("update_id").toInt();
|
||||
Message m = parseMessage(mm.value("message"));
|
||||
if (m.id > 0 && !m.text.isEmpty()) {
|
||||
emit newMessage(m);
|
||||
emit newMessage(m.chat_id, m.text);
|
||||
}
|
||||
}
|
||||
last_update++;
|
||||
//qDebug() << "update_id" << last_update;
|
||||
}
|
||||
|
||||
|
||||
void TelegramBotAPI::startDownloadFile(uint chat_id, QVariantMap file) {
|
||||
if (!file.isEmpty()) {
|
||||
DownloadFile df;
|
||||
df.downloaded = false;
|
||||
df.id = file["file_id"].toString();
|
||||
df.chat_id = chat_id;
|
||||
df.filename = file["file_name"].toString();
|
||||
qDebug() << "new incomming file" << df.id;
|
||||
download_list << df;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TelegramBotAPI::Message TelegramBotAPI::parseMessage(QVariant msg) {
|
||||
Message ret;
|
||||
QVariantMap map = msg.toMap();
|
||||
ret.id = map.value("message_id", 0).toUInt();
|
||||
QVariantMap chat = map.value("chat").toMap();
|
||||
ret.chat_id = chat.value("id", 0).toUInt();
|
||||
QVariantMap user = map.value("from").toMap();
|
||||
ret.user_id = user.value("id", 0).toUInt();
|
||||
ret.user_name = user.value("first_name").toString();
|
||||
ret.text = map.value("text").toString();
|
||||
ret.time = QDateTime::fromTime_t(map.value("date").toUInt());
|
||||
QVariantMap file;
|
||||
QVariantList photo = map.value("photo").toList();
|
||||
if (!photo.isEmpty()) {
|
||||
startDownloadFile(ret.chat_id, photo.last().toMap());
|
||||
}
|
||||
QVariantMap docum = map.value("document").toMap();
|
||||
startDownloadFile(ret.chat_id, docum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void TelegramBotAPI::sslErrors(QNetworkReply*,const QList<QSslError> &errors) {
|
||||
QString errorString;
|
||||
foreach (const QSslError &error, errors) {
|
||||
if (!errorString.isEmpty())
|
||||
errorString += ", ";
|
||||
errorString += error.errorString();
|
||||
}
|
||||
emit errorOccured(errorString);
|
||||
// if (QMessageBox::warning(0, QString("HTTP"), QString("One or more SSL errors has occurred: %1").arg(errorString),
|
||||
// QMessageBox::Ignore | QMessageBox::Abort, QMessageBox::Ignore)
|
||||
// == QMessageBox::Ignore) {
|
||||
// reply->ignoreSslErrors();
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
void TelegramBotAPI::httpFinished() {
|
||||
// qDebug() << "reply finished";
|
||||
// mutex.lock();
|
||||
QByteArray ba = reply->readAll();
|
||||
QStringList quest_path = reply->url().toString().split("/");
|
||||
// qDebug() << "quest list =" << quest_path.size();
|
||||
QString quest = quest_path.last();
|
||||
reply->deleteLater();
|
||||
wait_server = false;
|
||||
// mutex.unlock();
|
||||
if (quest_path.size() == 5) {
|
||||
QString s = QString::fromUtf8(ba.data(), ba.size());
|
||||
// qDebug() << quest << s;
|
||||
// if (quest.indexOf("?") > 0)
|
||||
// quest.resize(quest.indexOf('?'));
|
||||
QVariant tmp;
|
||||
if (quest == "getMe") parseCheckBot(s);
|
||||
if (quest == "getFile") parseFile(s);
|
||||
if (quest == "getUpdates") parseMessages(s);
|
||||
if (quest == "sendMessage") parseHeader(s, tmp);
|
||||
qDebug() << "parse done" << quest << s;
|
||||
} else {
|
||||
for (int i=0; i<download_list.size(); ++i) {
|
||||
if (download_list[i].url == reply->url()) {
|
||||
download_list[i].data = ba;
|
||||
download_list[i].downloaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_connected) {
|
||||
if (!fileDownload()) {
|
||||
if (sendmsg_que.isEmpty()) updateBot();
|
||||
else {
|
||||
SendQuery sq = sendmsg_que.dequeue();
|
||||
sendRequest(sq.method, sq.params);
|
||||
}
|
||||
}
|
||||
} else checkBot();
|
||||
}
|
||||
|
||||
|
||||
//void TelegramBot::httpFinished(QNetworkReply *) {
|
||||
// qDebug() << "get finished";
|
||||
//}
|
||||
|
||||
|
||||
void TelegramBotAPI::sendRequest(QString method, QVariantMap params) {
|
||||
wait_server = true;
|
||||
qDebug() << "startRequest:" << method;
|
||||
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
QString filename = params.take(param_filename).toString();
|
||||
QMapIterator<QString, QVariant> it(params);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
QHttpPart part;
|
||||
if (it.value().type() == QVariant::ByteArray) {
|
||||
part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; filename=\""+filename+"\"; name=\""+it.key()+"\""));
|
||||
qDebug() << "sending file" << double(it.value().toByteArray().size()) / (1024*1024) << "Mb";
|
||||
part.setBody(it.value().toByteArray());
|
||||
} else {
|
||||
part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\""+it.key()+"\""));
|
||||
part.setBody(it.value().toString().toUtf8());
|
||||
}
|
||||
multiPart->append(part);
|
||||
}
|
||||
if (params.isEmpty()) {
|
||||
QHttpPart part;
|
||||
part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\""));
|
||||
multiPart->append(part);
|
||||
}
|
||||
QNetworkRequest nr;
|
||||
nr.setUrl(QUrl(botUrl + method));
|
||||
reply = qnam->post(nr, multiPart);
|
||||
multiPart->setParent(reply); // delete the multiPart with the reply
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(httpFinished()));
|
||||
// connect(reply, SIGNAL(readyRead()), this, SLOT(httpReadyRead()));
|
||||
// connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDataReadProgress(qint64,qint64)));
|
||||
}
|
||||
Reference in New Issue
Block a user