diff options
author | Oleg Morozenkov <omorozenkov@gmail.com> | 2015-08-11 22:13:23 +0300 |
---|---|---|
committer | Oleg Morozenkov <omorozenkov@gmail.com> | 2015-08-11 22:13:23 +0300 |
commit | 376b88ec09ef8cf71dd823467406c58204485fcc (patch) | |
tree | 9ca599b854d18006c65b26003ce7dbdd416fdf18 /src | |
parent | d7fbf7149d0e0c1c30972dab68d510ef6ac377dd (diff) |
Fixed compiler's errors in TgTypeParser + fixed indentation + some other fixes
Diffstat (limited to 'src')
-rw-r--r-- | src/Api.cpp | 346 | ||||
-rw-r--r-- | src/TgTypeParser.cpp | 792 | ||||
-rw-r--r-- | src/net/HttpClient.cpp | 42 | ||||
-rw-r--r-- | src/net/HttpParser.cpp | 292 | ||||
-rw-r--r-- | src/net/TgLongPoll.cpp | 14 | ||||
-rw-r--r-- | src/net/Url.cpp | 88 | ||||
-rw-r--r-- | src/tools/Api.cpp | 279 | ||||
-rw-r--r-- | src/tools/StringTools.cpp | 118 | ||||
-rw-r--r-- | src/tools/TgException.cpp | 30 | ||||
-rw-r--r-- | src/tools/TgTypeParser.cpp | 490 | ||||
-rw-r--r-- | src/tools/net/HttpClient.cpp | 67 | ||||
-rw-r--r-- | src/tools/net/HttpParser.cpp | 204 | ||||
-rw-r--r-- | src/tools/net/TgLongPoll.cpp | 43 | ||||
-rw-r--r-- | src/tools/net/Url.cpp | 85 | ||||
-rw-r--r-- | src/tools/tools/StringTools.cpp | 119 |
15 files changed, 2163 insertions, 846 deletions
diff --git a/src/Api.cpp b/src/Api.cpp index 0c04081..da0aa7b 100644 --- a/src/Api.cpp +++ b/src/Api.cpp @@ -31,234 +31,234 @@ using namespace boost::property_tree; namespace TgBot { -Api::Api(const std::string& token) : _token(token) { +Api::Api(const string& token) : _token(token) { } User::Ptr Api::getMe() const { - return TgTypeParser::getInstance().parseUser(sendRequest("getMe").find("result")->second); + return TgTypeParser::getInstance().parseJsonAndGetUser(sendRequest("getMe")); } Message::Ptr Api::sendMessage(int32_t chatId, const string& text, bool disableWebPagePreview, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("text", text)); - if (disableWebPagePreview) { - args.push_back(HttpReqArg("disable_web_page_preview", disableWebPagePreview)); - } - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendMessage", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("text", text)); + if (disableWebPagePreview) { + args.push_back(HttpReqArg("disable_web_page_preview", disableWebPagePreview)); + } + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendMessage", args)); } Message::Ptr Api::forwardMessage(int32_t chatId, int32_t fromChatId, int32_t messageId) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("from_chat_id", fromChatId)); - args.push_back(HttpReqArg("message_id", messageId)); - return TgTypeParser::getInstance().parseMessage(sendRequest("forwardMessage", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("from_chat_id", fromChatId)); + args.push_back(HttpReqArg("message_id", messageId)); + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("forwardMessage", args)); } Message::Ptr Api::sendPhoto(int32_t chatId, const InputFile::Ptr& photo, const string& caption, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("photo", photo->data, true, photo->mimeType)); - if (!caption.empty()) { - args.push_back(HttpReqArg("caption", caption)); - } - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendPhoto", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("photo", photo->data, true, photo->mimeType)); + if (!caption.empty()) { + args.push_back(HttpReqArg("caption", caption)); + } + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendPhoto", args)); } Message::Ptr Api::sendPhoto(int32_t chatId, const string& photo, const string& caption, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("photo", photo)); - if (!caption.empty()) { - args.push_back(HttpReqArg("caption", caption)); - } - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendPhoto", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("photo", photo)); + if (!caption.empty()) { + args.push_back(HttpReqArg("caption", caption)); + } + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendPhoto", args)); } Message::Ptr Api::sendAudio(int32_t chatId, const InputFile::Ptr& audio, int32_t duration, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("audio", audio->data, true, audio->mimeType)); - if (duration) { - args.push_back(HttpReqArg("duration", duration)); - } - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendAudio", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("audio", audio->data, true, audio->mimeType)); + if (duration) { + args.push_back(HttpReqArg("duration", duration)); + } + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendAudio", args)); } Message::Ptr Api::sendAudio(int32_t chatId, const string& audio, int32_t duration, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("audio", audio)); - if (duration) { - args.push_back(HttpReqArg("duration", duration)); - } - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendAudio", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("audio", audio)); + if (duration) { + args.push_back(HttpReqArg("duration", duration)); + } + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendAudio", args)); } Message::Ptr Api::sendDocument(int32_t chatId, const InputFile::Ptr& document, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("document", document->data, true, document->mimeType)); - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendDocument", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("document", document->data, true, document->mimeType)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendDocument", args)); } Message::Ptr Api::sendDocument(int32_t chatId, const string& document, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("document", document)); - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendDocument", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("document", document)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendDocument", args)); } Message::Ptr Api::sendSticker(int32_t chatId, const InputFile::Ptr& sticker, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("sticker", sticker->data, true, sticker->mimeType)); - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendSticker", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("sticker", sticker->data, true, sticker->mimeType)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendSticker", args)); } Message::Ptr Api::sendSticker(int32_t chatId, const string& sticker, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("sticker", sticker)); - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendSticker", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("sticker", sticker)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendSticker", args)); } Message::Ptr Api::sendVideo(int32_t chatId, const InputFile::Ptr& video, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("video", video->data, true, video->mimeType)); - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendVideo", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("video", video->data, true, video->mimeType)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendVideo", args)); } Message::Ptr Api::sendVideo(int32_t chatId, const string& video, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("video", video)); - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendVideo", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("video", video)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendVideo", args)); } Message::Ptr Api::sendLocation(int32_t chatId, float latitude, float longitude, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("latitude", latitude)); - args.push_back(HttpReqArg("longitude", longitude)); - if (replyToMessageId) { - args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); - } - if (replyMarkup) { - args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); - } - return TgTypeParser::getInstance().parseMessage(sendRequest("sendLocation", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("latitude", latitude)); + args.push_back(HttpReqArg("longitude", longitude)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseJsonAndGetMessage(sendRequest("sendLocation", args)); } void Api::sendChatAction(int32_t chatId, const string& action) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("chat_id", chatId)); - args.push_back(HttpReqArg("action", action)); - sendRequest("sendChatAction", args); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("action", action)); + sendRequest("sendChatAction", args); } UserProfilePhotos::Ptr Api::getUserProfilePhotos(int32_t userId, int32_t offset, int32_t limit) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("user_id", userId)); - if (offset) { - args.push_back(HttpReqArg("offset", offset)); - } - limit = max(1, min(100, limit)); - args.push_back(HttpReqArg("limit", limit)); - return TgTypeParser::getInstance().parseUserProfilePhotos(sendRequest("getUserProfilePhotos", args).find("result")->second); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("user_id", userId)); + if (offset) { + args.push_back(HttpReqArg("offset", offset)); + } + limit = max(1, min(100, limit)); + args.push_back(HttpReqArg("limit", limit)); + return TgTypeParser::getInstance().parseJsonAndGetUserProfilePhotos(sendRequest("getUserProfilePhotos", args)); } vector<Update::Ptr> Api::getUpdates(int32_t offset, int32_t limit, int32_t timeout) const { - vector<HttpReqArg> args; - if (offset) { - args.push_back(HttpReqArg("offset", offset)); - } - limit = max(1, min(100, limit)); - args.push_back(HttpReqArg("limit", limit)); - if (timeout) { - args.push_back(HttpReqArg("timeout", timeout)); - } - return TgTypeParser::getInstance().parseArray<Update>(TgTypeParser::getInstance().parseUpdate, sendRequest("getUpdates", args), "result"); + vector<HttpReqArg> args; + if (offset) { + args.push_back(HttpReqArg("offset", offset)); + } + limit = max(1, min(100, limit)); + args.push_back(HttpReqArg("limit", limit)); + if (timeout) { + args.push_back(HttpReqArg("timeout", timeout)); + } + return TgTypeParser::getInstance().parseJsonAndGetArray<Update>(&TgTypeParser::parseJsonAndGetUpdate, sendRequest("getUpdates", args), "result"); } void Api::setWebhook(const string& url) const { - vector<HttpReqArg> args; - args.push_back(HttpReqArg("url", url)); - sendRequest("setWebhook", args); + vector<HttpReqArg> args; + args.push_back(HttpReqArg("url", url)); + sendRequest("setWebhook", args); } -boost::property_tree::ptree Api::sendRequest(const std::string& method, const std::vector<HttpReqArg>& args) const { - std::string url = "https://api.telegram.org/bot"; - url += _token; - url += "/"; +ptree Api::sendRequest(const string& method, const vector<HttpReqArg>& args) const { + string url = "https://api.telegram.org/bot"; + url += _token; + url += "/"; url += method; string serverResponse = HttpClient::getInstance().makeRequest(url, args); if (serverResponse.find("<html>") != serverResponse.npos) { @@ -267,7 +267,7 @@ boost::property_tree::ptree Api::sendRequest(const std::string& method, const st ptree result = TgTypeParser::getInstance().parseJson(serverResponse); try { if (result.get<bool>("ok")) { - return result; + return result.find("result")->second; } else { throw TgException(result.get("description", "")); } diff --git a/src/TgTypeParser.cpp b/src/TgTypeParser.cpp index 9a1f93a..81d2119 100644 --- a/src/TgTypeParser.cpp +++ b/src/TgTypeParser.cpp @@ -28,463 +28,463 @@ using namespace boost::property_tree; namespace TgBot { TgTypeParser& TgTypeParser::getInstance() { - static TgTypeParser result; - return result; + static TgTypeParser result; + return result; } -User::Ptr TgTypeParser::parseUser(const ptree& data) const { - User::Ptr result(new User); - result->id = data.get<int32_t>("id"); - result->firstName = data.get<string>("first_name"); - result->lastName = data.get("last_name", ""); - result->username = data.get("username", ""); - return result; +User::Ptr TgTypeParser::parseJsonAndGetUser(const ptree& data) const { + User::Ptr result(new User); + result->id = data.get<int32_t>("id"); + result->firstName = data.get<string>("first_name"); + result->lastName = data.get("last_name", ""); + result->username = data.get("username", ""); + return result; } string TgTypeParser::parseUser(const User::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "id", object->id); - appendToJson(result, "first_name", object->firstName); - appendToJson(result, "last_name", object->lastName); - appendToJson(result, "username", object->username); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -GroupChat::Ptr TgTypeParser::parseGroupChat(const ptree& data) const { - GroupChat::Ptr result(new GroupChat); - result->id = data.get<int32_t>("id"); - result->title = data.get<string>("title"); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "id", object->id); + appendToJson(result, "first_name", object->firstName); + appendToJson(result, "last_name", object->lastName); + appendToJson(result, "username", object->username); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +GroupChat::Ptr TgTypeParser::parseJsonAndGetGroupChat(const ptree& data) const { + GroupChat::Ptr result(new GroupChat); + result->id = data.get<int32_t>("id"); + result->title = data.get<string>("title"); + return result; } string TgTypeParser::parseGroupChat(const GroupChat::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "id", object->id); - appendToJson(result, "title", object->title); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -Message::Ptr TgTypeParser::parseMessage(const ptree& data) const { - Message::Ptr result(new Message); - result->messageId = data.get<int32_t>("message_id"); - result->from = parseUser(data.find("from")->second); - result->date = data.get<int32_t>("date"); - result->chat = parseGenericChat(data.find("chat")->second); - result->forwardFrom = tryParse<User>(parseUser, data, "forward_from"); - result->forwardDate = data.get("forward_date", 0); - result->replyToMessage = tryParse<Message>(parseMessage, data, "reply_to_message"); - result->text = data.get("text", ""); - result->audio = tryParse<Audio>(parseAudio, data, "audio"); - result->document = tryParse<Document>(parseDocument, data, "document"); - result->photo = parseArray<PhotoSize>(parsePhotoSize, data, "photo"); - result->sticker = tryParse<Sticker>(parseSticker, data, "sticker"); - result->video = tryParse<Video>(parseVideo, data, "video"); - result->contact = tryParse<Contact>(parseContact, data, "contact"); - result->location = tryParse<Location>(parseLocation, data, "location"); - result->newChatParticipant = tryParse<User>(parseUser, data, "new_chat_participant"); - result->leftChatParticipant = tryParse<User>(parseUser, data, "left_chat_participant"); - result->newChatTitle = data.get("new_chat_title", ""); - result->newChatPhoto = parseArray<PhotoSize>(parsePhotoSize, data, "new_chat_photo"); - result->deleteChatPhoto = data.get("delete_chat_photo", false); - result->groupChatCreated = data.get("group_chat_created", false); - result->caption = data.get("caption", false); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "id", object->id); + appendToJson(result, "title", object->title); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Message::Ptr TgTypeParser::parseJsonAndGetMessage(const ptree& data) const { + Message::Ptr result(new Message); + result->messageId = data.get<int32_t>("message_id"); + result->from = parseJsonAndGetUser(data.find("from")->second); + result->date = data.get<int32_t>("date"); + result->chat = parseJsonAndGetGenericChat(data.find("chat")->second); + result->forwardFrom = tryParseJson<User>(&TgTypeParser::parseJsonAndGetUser, data, "forward_from"); + result->forwardDate = data.get("forward_date", 0); + result->replyToMessage = tryParseJson<Message>(&TgTypeParser::parseJsonAndGetMessage, data, "reply_to_message"); + result->text = data.get("text", ""); + result->audio = tryParseJson<Audio>(&TgTypeParser::parseJsonAndGetAudio, data, "audio"); + result->document = tryParseJson<Document>(&TgTypeParser::parseJsonAndGetDocument, data, "document"); + result->photo = parseJsonAndGetArray<PhotoSize>(&TgTypeParser::parseJsonAndGetPhotoSize, data, "photo"); + result->sticker = tryParseJson<Sticker>(&TgTypeParser::parseJsonAndGetSticker, data, "sticker"); + result->video = tryParseJson<Video>(&TgTypeParser::parseJsonAndGetVideo, data, "video"); + result->contact = tryParseJson<Contact>(&TgTypeParser::parseJsonAndGetContact, data, "contact"); + result->location = tryParseJson<Location>(&TgTypeParser::parseJsonAndGetLocation, data, "location"); + result->newChatParticipant = tryParseJson<User>(&TgTypeParser::parseJsonAndGetUser, data, "new_chat_participant"); + result->leftChatParticipant = tryParseJson<User>(&TgTypeParser::parseJsonAndGetUser, data, "left_chat_participant"); + result->newChatTitle = data.get("new_chat_title", ""); + result->newChatPhoto = parseJsonAndGetArray<PhotoSize>(&TgTypeParser::parseJsonAndGetPhotoSize, data, "new_chat_photo"); + result->deleteChatPhoto = data.get("delete_chat_photo", false); + result->groupChatCreated = data.get("group_chat_created", false); + result->caption = data.get("caption", false); + return result; } string TgTypeParser::parseMessage(const Message::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "message_id", object->messageId); - appendToJson(result, "from", parseUser(object->from)); - appendToJson(result, "date", object->date); - appendToJson(result, "chat", parseGenericChat(object->chat)); - appendToJson(result, "forward_from", parseUser(object->forwardFrom)); - appendToJson(result, "forward_date", object->forwardDate); - appendToJson(result, "reply_to_message", parseMessage(object->replyToMessage)); - appendToJson(result, "text", object->text); - appendToJson(result, "audio", parseAudio(object->audio)); - appendToJson(result, "document", parseDocument(object->document)); - appendToJson(result, "photo", parseArray(parsePhotoSize, object->photo)); - appendToJson(result, "sticker", parseSticker(object->sticker)); - appendToJson(result, "video", parseVideo(object->video)); - appendToJson(result, "contact", parseContact(object->contact)); - appendToJson(result, "location", parseLocation(object->location)); - appendToJson(result, "new_chat_participant", parseUser(object->newChatParticipant)); - appendToJson(result, "left_chat_participant", parseUser(object->leftChatParticipant)); - appendToJson(result, "new_chat_title", object->newChatTitle); - appendToJson(result, "new_chat_photo", parseArray(parsePhotoSize, object->newChatPhoto)); - appendToJson(result, "delete_chat_photo", object->deleteChatPhoto); - appendToJson(result, "group_chat_created", object->groupChatCreated); - appendToJson(result, "caption", object->caption); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -PhotoSize::Ptr TgTypeParser::parsePhotoSize(const ptree& data) const { - PhotoSize::Ptr result(new PhotoSize); - result->fileId = data.get<string>("file_id"); - result->width = data.get<int32_t>("width"); - result->height = data.get<int32_t>("height"); - result->fileSize = data.get("file_size", 0); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "message_id", object->messageId); + appendToJson(result, "from", parseUser(object->from)); + appendToJson(result, "date", object->date); + appendToJson(result, "chat", parseGenericChat(object->chat)); + appendToJson(result, "forward_from", parseUser(object->forwardFrom)); + appendToJson(result, "forward_date", object->forwardDate); + appendToJson(result, "reply_to_message", parseMessage(object->replyToMessage)); + appendToJson(result, "text", object->text); + appendToJson(result, "audio", parseAudio(object->audio)); + appendToJson(result, "document", parseDocument(object->document)); + appendToJson(result, "photo", parseArray(&TgTypeParser::parsePhotoSize, object->photo)); + appendToJson(result, "sticker", parseSticker(object->sticker)); + appendToJson(result, "video", parseVideo(object->video)); + appendToJson(result, "contact", parseContact(object->contact)); + appendToJson(result, "location", parseLocation(object->location)); + appendToJson(result, "new_chat_participant", parseUser(object->newChatParticipant)); + appendToJson(result, "left_chat_participant", parseUser(object->leftChatParticipant)); + appendToJson(result, "new_chat_title", object->newChatTitle); + appendToJson(result, "new_chat_photo", parseArray(&TgTypeParser::parsePhotoSize, object->newChatPhoto)); + appendToJson(result, "delete_chat_photo", object->deleteChatPhoto); + appendToJson(result, "group_chat_created", object->groupChatCreated); + appendToJson(result, "caption", object->caption); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +PhotoSize::Ptr TgTypeParser::parseJsonAndGetPhotoSize(const ptree& data) const { + PhotoSize::Ptr result(new PhotoSize); + result->fileId = data.get<string>("file_id"); + result->width = data.get<int32_t>("width"); + result->height = data.get<int32_t>("height"); + result->fileSize = data.get("file_size", 0); + return result; } string TgTypeParser::parsePhotoSize(const PhotoSize::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "file_id", object->fileId); - appendToJson(result, "width", object->width); - appendToJson(result, "height", object->height); - appendToJson(result, "file_size", object->fileSize); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -Audio::Ptr TgTypeParser::parseAudio(const ptree& data) const { - Audio::Ptr result(new Audio); - result->fileId = data.get<string>("file_id"); - result->duration = data.get<int32_t>("duration"); - result->mimeType = data.get("mime_type", ""); - result->fileSize = data.get("file_size", 0); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "file_id", object->fileId); + appendToJson(result, "width", object->width); + appendToJson(result, "height", object->height); + appendToJson(result, "file_size", object->fileSize); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Audio::Ptr TgTypeParser::parseJsonAndGetAudio(const ptree& data) const { + Audio::Ptr result(new Audio); + result->fileId = data.get<string>("file_id"); + result->duration = data.get<int32_t>("duration"); + result->mimeType = data.get("mime_type", ""); + result->fileSize = data.get("file_size", 0); + return result; } string TgTypeParser::parseAudio(const Audio::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "file_id", object->fileId); - appendToJson(result, "duration", object->duration); - appendToJson(result, "mime_type", object->mimeType); - appendToJson(result, "file_size", object->fileSize); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -Document::Ptr TgTypeParser::parseDocument(const ptree& data) const { - Document::Ptr result(new Document); - result->fileId = data.get<string>("file_id"); - result->thumb = parsePhotoSize(data.find("thumb")->second); - result->fileName = data.get("file_name", ""); - result->mimeType = data.get("mime_type", ""); - result->fileSize = data.get("file_size", 0); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "file_id", object->fileId); + appendToJson(result, "duration", object->duration); + appendToJson(result, "mime_type", object->mimeType); + appendToJson(result, "file_size", object->fileSize); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Document::Ptr TgTypeParser::parseJsonAndGetDocument(const ptree& data) const { + Document::Ptr result(new Document); + result->fileId = data.get<string>("file_id"); + result->thumb = parseJsonAndGetPhotoSize(data.find("thumb")->second); + result->fileName = data.get("file_name", ""); + result->mimeType = data.get("mime_type", ""); + result->fileSize = data.get("file_size", 0); + return result; } string TgTypeParser::parseDocument(const Document::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "file_id", object->fileId); - appendToJson(result, "thumb", parsePhotoSize(object->thumb)); - appendToJson(result, "file_name", object->fileName); - appendToJson(result, "mime_type", object->mimeType); - appendToJson(result, "file_size", object->fileSize); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -Sticker::Ptr TgTypeParser::parseSticker(const ptree& data) const { - Sticker::Ptr result(new Sticker); - result->fileId = data.get<string>("file_id"); - result->width = data.get<int32_t>("width"); - result->height = data.get<int32_t>("height"); - result->thumb = parsePhotoSize(data.find("thumb")->second); - result->fileSize = data.get("file_size", 0); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "file_id", object->fileId); + appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "file_name", object->fileName); + appendToJson(result, "mime_type", object->mimeType); + appendToJson(result, "file_size", object->fileSize); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Sticker::Ptr TgTypeParser::parseJsonAndGetSticker(const ptree& data) const { + Sticker::Ptr result(new Sticker); + result->fileId = data.get<string>("file_id"); + result->width = data.get<int32_t>("width"); + result->height = data.get<int32_t>("height"); + result->thumb = parseJsonAndGetPhotoSize(data.find("thumb")->second); + result->fileSize = data.get("file_size", 0); + return result; } string TgTypeParser::parseSticker(const Sticker::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "file_id", object->fileId); - appendToJson(result, "width", object->width); - appendToJson(result, "height", object->height); - appendToJson(result, "thumb", parsePhotoSize(object->thumb)); - appendToJson(result, "file_size", object->fileSize); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -Video::Ptr TgTypeParser::parseVideo(const ptree& data) const { - Video::Ptr result(new Video); - result->fileId = data.get<string>("file_id"); - result->width = data.get<int32_t>("width"); - result->height = data.get<int32_t>("height"); - result->duration = data.get<int32_t>("duration"); - result->thumb = parsePhotoSize(data.find("thumb")->second); - result->mimeType = data.get("mime_type", ""); - result->fileSize = data.get("file_size", 0); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "file_id", object->fileId); + appendToJson(result, "width", object->width); + appendToJson(result, "height", object->height); + appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "file_size", object->fileSize); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Video::Ptr TgTypeParser::parseJsonAndGetVideo(const ptree& data) const { + Video::Ptr result(new Video); + result->fileId = data.get<string>("file_id"); + result->width = data.get<int32_t>("width"); + result->height = data.get<int32_t>("height"); + result->duration = data.get<int32_t>("duration"); + result->thumb = parseJsonAndGetPhotoSize(data.find("thumb")->second); + result->mimeType = data.get("mime_type", ""); + result->fileSize = data.get("file_size", 0); + return result; } string TgTypeParser::parseVideo(const Video::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "file_id", object->fileId); - appendToJson(result, "width", object->width); - appendToJson(result, "height", object->height); - appendToJson(result, "duration", object->duration); - appendToJson(result, "thumb", parsePhotoSize(object->thumb)); - appendToJson(result, "mime_type", object->mimeType); - appendToJson(result, "file_size", object->fileSize); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -Contact::Ptr TgTypeParser::parseContact(const ptree& data) const { - Contact::Ptr result(new Contact); - result->phoneNumber = data.get<string>("phone_number"); - result->firstName = data.get<string>("first_name"); - result->lastName = data.get("last_name", ""); - result->userId = data.get("user_id", ""); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "file_id", object->fileId); + appendToJson(result, "width", object->width); + appendToJson(result, "height", object->height); + appendToJson(result, "duration", object->duration); + appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "mime_type", object->mimeType); + appendToJson(result, "file_size", object->fileSize); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Contact::Ptr TgTypeParser::parseJsonAndGetContact(const ptree& data) const { + Contact::Ptr result(new Contact); + result->phoneNumber = data.get<string>("phone_number"); + result->firstName = data.get<string>("first_name"); + result->lastName = data.get("last_name", ""); + result->userId = data.get("user_id", ""); + return result; } string TgTypeParser::parseContact(const Contact::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "phone_number", object->phoneNumber); - appendToJson(result, "first_name", object->firstName); - appendToJson(result, "last_name", object->lastName); - appendToJson(result, "user_id", object->userId); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -Location::Ptr TgTypeParser::parseLocation(const ptree& data) const { - Location::Ptr result(new Location); - result->longitude = data.get<float>("longitude"); - result->latitude = data.get<float>("latitude"); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "phone_number", object->phoneNumber); + appendToJson(result, "first_name", object->firstName); + appendToJson(result, "last_name", object->lastName); + appendToJson(result, "user_id", object->userId); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Location::Ptr TgTypeParser::parseJsonAndGetLocation(const ptree& data) const { + Location::Ptr result(new Location); + result->longitude = data.get<float>("longitude"); + result->latitude = data.get<float>("latitude"); + return result; } string TgTypeParser::parseLocation(const Location::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "longitude", object->longitude); - appendToJson(result, "latitude", object->latitude); - result.erase(result.length() - 1); - result += '}'; - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "longitude", object->longitude); + appendToJson(result, "latitude", object->latitude); + result.erase(result.length() - 1); + result += '}'; + return result; } -Update::Ptr TgTypeParser::parseUpdate(const ptree& data) const { - Update::Ptr result(new Update); - result->updateId = data.get<int32_t>("update_id"); - result->message = parseMessage(data.find("message")->second); - return result; +Update::Ptr TgTypeParser::parseJsonAndGetUpdate(const ptree& data) const { + Update::Ptr result(new Update); + result->updateId = data.get<int32_t>("update_id"); + result->message = parseJsonAndGetMessage(data.find("message")->second); + return result; } string TgTypeParser::parseUpdate(const Update::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "update_id", object->updateId); - appendToJson(result, "message", parseMessage(object->message)); - result.erase(result.length() - 1); - result += '}'; - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "update_id", object->updateId); + appendToJson(result, "message", parseMessage(object->message)); + result.erase(result.length() - 1); + result += '}'; + return result; } -UserProfilePhotos::Ptr TgTypeParser::parseUserProfilePhotos(const ptree& data) const { - UserProfilePhotos::Ptr result(new UserProfilePhotos); - result->totalCount = data.get<int32_t>("total_count"); - result->photos = parse2DArray<PhotoSize>(parsePhotoSize, data, "photos"); - return result; +UserProfilePhotos::Ptr TgTypeParser::parseJsonAndGetUserProfilePhotos(const ptree& data) const { + UserProfilePhotos::Ptr result(new UserProfilePhotos); + result->totalCount = data.get<int32_t>("total_count"); + result->photos = parseJsonAndGet2DArray<PhotoSize>(&TgTypeParser::parseJsonAndGetPhotoSize, data, "photos"); + return result; } string TgTypeParser::parseUserProfilePhotos(const UserProfilePhotos::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "total_count", object->totalCount); - appendToJson(result, "photos", parse2DArray(parsePhotoSize, object->photos)); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -ReplyKeyboardMarkup::Ptr TgTypeParser::parseReplyKeyboardMarkup(const boost::property_tree::ptree& data) const { - ReplyKeyboardMarkup::Ptr result(new ReplyKeyboardMarkup); - for (const pair<const string, ptree>& item : data.find("keyboard")->second) { - vector<string> array; - for (const pair<const string, ptree>& innerItem : item.second) { - array.push_back(innerItem.second.data()); - } - result->keyboard.push_back(array); - } - result->resizeKeyboard = data.get<bool>("resize_keyboard"); - result->oneTimeKeyboard = data.get<bool>("one_time_keyboard"); - result->selective = data.get<bool>("selective"); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "total_count", object->totalCount); + appendToJson(result, "photos", parse2DArray(&TgTypeParser::parsePhotoSize, object->photos)); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +ReplyKeyboardMarkup::Ptr TgTypeParser::parseJsonAndGetReplyKeyboardMarkup(const boost::property_tree::ptree& data) const { + ReplyKeyboardMarkup::Ptr result(new ReplyKeyboardMarkup); + for (const pair<const string, ptree>& item : data.find("keyboard")->second) { + vector<string> array; + for (const pair<const string, ptree>& innerItem : item.second) { + array.push_back(innerItem.second.data()); + } + result->keyboard.push_back(array); + } + result->resizeKeyboard = data.get<bool>("resize_keyboard"); + result->oneTimeKeyboard = data.get<bool>("one_time_keyboard"); + result->selective = data.get<bool>("selective"); + return result; } std::string TgTypeParser::parseReplyKeyboardMarkup(const ReplyKeyboardMarkup::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - result += "\"keyboard\":["; - for (vector<string>& item : object->keyboard) { - result += '['; - for (string& innerItem : item) { - result += '"'; - result += innerItem; - result += "\","; - } - result.erase(result.length() - 1); - result += "],"; - } - result.erase(result.length() - 1); - result += "],"; - appendToJson(result, "resize_keyboard", object->resizeKeyboard); - appendToJson(result, "one_time_keyboard", object->oneTimeKeyboard); - appendToJson(result, "selective", object->selective); - result.erase(result.length() - 1); - result += '}'; - return result; -} - -ReplyKeyboardHide::Ptr TgTypeParser::parseReplyKeyboardHide(const boost::property_tree::ptree& data) const { - ReplyKeyboardHide::Ptr result(new ReplyKeyboardHide); - result->selective = data.get<bool>("selective"); - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + result += "\"keyboard\":["; + for (vector<string>& item : object->keyboard) { + result += '['; + for (string& innerItem : item) { + result += '"'; + result += innerItem; + result += "\","; + } + result.erase(result.length() - 1); + result += "],"; + } + result.erase(result.length() - 1); + result += "],"; + appendToJson(result, "resize_keyboard", object->resizeKeyboard); + appendToJson(result, "one_time_keyboard", object->oneTimeKeyboard); + appendToJson(result, "selective", object->selective); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +ReplyKeyboardHide::Ptr TgTypeParser::parseJsonAndGetReplyKeyboardHide(const boost::property_tree::ptree& data) const { + ReplyKeyboardHide::Ptr result(new ReplyKeyboardHide); + result->selective = data.get<bool>("selective"); + return result; } std::string TgTypeParser::parseReplyKeyboardHide(const ReplyKeyboardHide::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "selective", object->selective); - result.erase(result.length() - 1); - result += '}'; - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "selective", object->selective); + result.erase(result.length() - 1); + result += '}'; + return result; } -ForceReply::Ptr TgTypeParser::parseForceReply(const boost::property_tree::ptree& data) const { - ForceReply::Ptr result(new ForceReply); - result->selective = data.get<bool>("selective"); - return result; +ForceReply::Ptr TgTypeParser::parseJsonAndGetForceReply(const boost::property_tree::ptree& data) const { + ForceReply::Ptr result(new ForceReply); + result->selective = data.get<bool>("selective"); + return result; } std::string TgTypeParser::parseForceReply(const ForceReply::Ptr& object) const { - if (!object) { - return ""; - } - string result; - result += '{'; - appendToJson(result, "selective", object->selective); - result.erase(result.length() - 1); - result += '}'; - return result; + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "selective", object->selective); + result.erase(result.length() - 1); + result += '}'; + return result; } -GenericChat::Ptr TgTypeParser::parseGenericChat(const ptree& data) const { - if (data.find("first_name") == data.not_found()) { - return static_pointer_cast<GenericChat>(parseGroupChat(data)); - } else { - return static_pointer_cast<GenericChat>(parseUser(data)); - } +GenericChat::Ptr TgTypeParser::parseJsonAndGetGenericChat(const ptree& data) const { + if (data.find("first_name") == data.not_found()) { + return static_pointer_cast<GenericChat>(parseJsonAndGetGroupChat(data)); + } else { + return static_pointer_cast<GenericChat>(parseJsonAndGetUser(data)); + } } string TgTypeParser::parseGenericChat(const GenericChat::Ptr& object) const { - if (!object) { - return ""; - } - if (dynamic_pointer_cast<User>(object) == nullptr) { - return parseGroupChat(static_pointer_cast<GroupChat>(object)); - } else { - return parseUser(static_pointer_cast<User>(object)); - } -} - -GenericReply::Ptr TgTypeParser::parseGenericReply(const boost::property_tree::ptree& data) const { - if (data.find("force_reply") != data.not_found()) { - return static_pointer_cast<GenericReply>(parseForceReply(data)); - } else if (data.find("hide_keyboard") != data.not_found()) { - return static_pointer_cast<GenericReply>(parseReplyKeyboardHide(data)); - } else { - return static_pointer_cast<GenericReply>(parseReplyKeyboardMarkup(data)); - } + if (!object) { + return ""; + } + if (dynamic_pointer_cast<User>(object) == nullptr) { + return parseGroupChat(static_pointer_cast<GroupChat>(object)); + } else { + return parseUser(static_pointer_cast<User>(object)); + } +} + +GenericReply::Ptr TgTypeParser::parseJsonAndGetGenericReply(const boost::property_tree::ptree& data) const { + if (data.find("force_reply") != data.not_found()) { + return static_pointer_cast<GenericReply>(parseJsonAndGetForceReply(data)); + } else if (data.find("hide_keyboard") != data.not_found()) { + return static_pointer_cast<GenericReply>(parseJsonAndGetReplyKeyboardHide(data)); + } else { + return static_pointer_cast<GenericReply>(parseJsonAndGetReplyKeyboardMarkup(data)); + } } std::string TgTypeParser::parseGenericReply(const GenericReply::Ptr& object) const { - if (!object) { - return ""; - } - if (dynamic_pointer_cast<ForceReply>(object) != nullptr) { - return parseForceReply(static_pointer_cast<ForceReply>(object)); - } else if (dynamic_pointer_cast<ReplyKeyboardHide>(object) != nullptr) { - return parseReplyKeyboardHide(static_pointer_cast<ReplyKeyboardHide>(object)); - } else { - return parseReplyKeyboardMarkup(static_pointer_cast<ReplyKeyboardMarkup>(object)); - } + if (!object) { + return ""; + } + if (dynamic_pointer_cast<ForceReply>(object) != nullptr) { + return parseForceReply(static_pointer_cast<ForceReply>(object)); + } else if (dynamic_pointer_cast<ReplyKeyboardHide>(object) != nullptr) { + return parseReplyKeyboardHide(static_pointer_cast<ReplyKeyboardHide>(object)); + } else { + return parseReplyKeyboardMarkup(static_pointer_cast<ReplyKeyboardMarkup>(object)); + } } void TgTypeParser::appendToJson(string& json, const string& varName, const string& value) const { - if (value.empty()) { - return; - } - json += '"'; - json += varName; - json += "\":"; - if (value.front() != '{') { - json += '"'; - } - json += value; - if (value.back() != '}') { - json += '"'; - } - json += ','; -} - -}
\ No newline at end of file + if (value.empty()) { + return; + } + json += '"'; + json += varName; + json += "\":"; + if (value.front() != '{') { + json += '"'; + } + json += value; + if (value.back() != '}') { + json += '"'; + } + json += ','; +} + +} diff --git a/src/net/HttpClient.cpp b/src/net/HttpClient.cpp index 5027b09..b9813ad 100644 --- a/src/net/HttpClient.cpp +++ b/src/net/HttpClient.cpp @@ -32,36 +32,36 @@ using namespace boost::asio::local; namespace TgBot { HttpClient& HttpClient::getInstance() { - static HttpClient result; - return result; + static HttpClient result; + return result; } string HttpClient::makeRequest(const Url& url, const vector<HttpReqArg>& args) { - ssl::context context(ssl::context::sslv23); - context.set_default_verify_paths(); + ssl::context context(ssl::context::sslv23); + context.set_default_verify_paths(); - ssl::stream<tcp::socket> socket(_ioService, context); - tcp::resolver resolver(_ioService); - tcp::resolver::query query(url.host, url.protocol); + ssl::stream<tcp::socket> socket(_ioService, context); + tcp::resolver resolver(_ioService); + tcp::resolver::query query(url.host, url.protocol); - connect(socket.lowest_layer(), resolver.resolve(query)); + connect(socket.lowest_layer(), resolver.resolve(query)); - socket.set_verify_mode(ssl::verify_none); - socket.set_verify_callback(ssl::rfc2818_verification(url.host)); - socket.handshake(ssl::stream<tcp::socket>::client); + socket.set_verify_mode(ssl::verify_none); + socket.set_verify_callback(ssl::rfc2818_verification(url.host)); + socket.handshake(ssl::stream<tcp::socket>::client); - string requestText = HttpParser::getInstance().generateRequest(url, args, false); - write(socket, buffer(requestText.c_str(), requestText.length())); + string requestText = HttpParser::getInstance().generateRequest(url, args, false); + write(socket, buffer(requestText.c_str(), requestText.length())); - string response; - char buff[1024]; - boost::system::error_code error; - while (!error) { - size_t bytes = read(socket, buffer(buff), error); - response += string(buff, bytes); - } + string response; + char buff[1024]; + boost::system::error_code error; + while (!error) { + size_t bytes = read(socket, buffer(buff), error); + response += string(buff, bytes); + } - return HttpParser::getInstance().parseResponse(response); + return HttpParser::getInstance().parseResponse(response); } } diff --git a/src/net/HttpParser.cpp b/src/net/HttpParser.cpp index ae9de62..a2d9108 100644 --- a/src/net/HttpParser.cpp +++ b/src/net/HttpParser.cpp @@ -32,173 +32,173 @@ using namespace boost; namespace TgBot { HttpParser& HttpParser::getInstance() { - static HttpParser result; - return result; + static HttpParser result; + return result; } string HttpParser::generateRequest(const Url& url, const vector<HttpReqArg>& args, bool isKeepAlive) { - string result; - if (args.empty()) { - result += "GET "; - } else { - result += "POST "; - } - result += url.path; - result += url.query.empty() ? "" : "?" + url.query; - result += " HTTP/1.1\r\n"; - result += "Host: "; - result += url.host; - result += "\r\nConnection: "; - if (isKeepAlive) { - result += "keep-alive"; - } else { - result += "close"; - } - result += "\r\n"; - if (args.empty()) { - result += "\r\n"; - } else { - string requestData; - - string bondary = generateMultipartBoundary(args); - if (bondary.empty()) { - result += "Content-Type: application/x-www-form-urlencoded\r\n"; - requestData = generateWwwFormUrlencoded(args); - } else { - result += "Content-Type: multipart/form-data; boundary="; - result += bondary; - result += "\r\n"; - requestData = generateMultipartFormData(args, bondary); - } - - result += "Content-Length: "; - result += lexical_cast<string>(requestData.length()); - result += "\r\n\r\n"; - result += requestData; - } - return result; + string result; + if (args.empty()) { + result += "GET "; + } else { + result += "POST "; + } + result += url.path; + result += url.query.empty() ? "" : "?" + url.query; + result += " HTTP/1.1\r\n"; + result += "Host: "; + result += url.host; + result += "\r\nConnection: "; + if (isKeepAlive) { + result += "keep-alive"; + } else { + result += "close"; + } + result += "\r\n"; + if (args.empty()) { + result += "\r\n"; + } else { + string requestData; + + string bondary = generateMultipartBoundary(args); + if (bondary.empty()) { + result += "Content-Type: application/x-www-form-urlencoded\r\n"; + requestData = generateWwwFormUrlencoded(args); + } else { + result += "Content-Type: multipart/form-data; boundary="; + result += bondary; + result += "\r\n"; + requestData = generateMultipartFormData(args, bondary); + } + + result += "Content-Length: "; + result += lexical_cast<string>(requestData.length()); + result += "\r\n\r\n"; + result += requestData; + } + return result; } string HttpParser::generateMultipartFormData(const vector<HttpReqArg>& args, const string& bondary) { - string result; - for (const HttpReqArg& item : args) { - result += "--"; - result += bondary; - result += "\r\nContent-Disposition: form-data; name=\""; - result += item.name; - result += "\"\r\n"; - if (item.isFile) { - result += "Content-Type: "; - result += item.mimeType; - result += "\r\n"; - } - result += "\r\n"; - result += item.value; - result += "\r\n"; - } - return result; + string result; + for (const HttpReqArg& item : args) { + result += "--"; + result += bondary; + result += "\r\nContent-Disposition: form-data; name=\""; + result += item.name; + result += "\"\r\n"; + if (item.isFile) { + result += "Content-Type: "; + result += item.mimeType; + result += "\r\n"; + } + result += "\r\n"; + result += item.value; + result += "\r\n"; + } + return result; } string HttpParser::generateMultipartBoundary(const vector<HttpReqArg>& args) { - string result; - srand((unsigned int) time(nullptr)); - for (const HttpReqArg& item : args) { - if (item.isFile) { - while (result.empty() || item.value.find(result) != item.value.npos) { - result += StringTools::generateRandomString(4); - } - } - } - return result; + string result; + srand((unsigned int) time(nullptr)); + for (const HttpReqArg& item : args) { + if (item.isFile) { + while (result.empty() || item.value.find(result) != item.value.npos) { + result += StringTools::generateRandomString(4); + } + } + } + return result; } string HttpParser::generateWwwFormUrlencoded(const vector<HttpReqArg>& args) { - string result; - - bool firstRun = true; - for (const HttpReqArg& item : args) { - if (firstRun) { - firstRun = false; - } else { - result += '&'; - } - result += StringTools::urlEncode(item.name); - result += '='; - result += StringTools::urlEncode(item.value); - } - - return result; + string result; + + bool firstRun = true; + for (const HttpReqArg& item : args) { + if (firstRun) { + firstRun = false; + } else { + result += '&'; + } + result += StringTools::urlEncode(item.name); + result += '='; + result += StringTools::urlEncode(item.value); + } + + return result; } string HttpParser::generateResponse(const string& data, const string& mimeType, unsigned short statusCode, const string& statusStr, bool isKeepAlive) { - string result; - result += "HTTP/1.1 "; - result += lexical_cast<string>(statusCode); - result += ' '; - result += statusStr; - result += "\r\nContent-Type: "; - result += mimeType; - result += "\r\nContent-Length: "; - result += lexical_cast<string>(data.length()); - result += "\r\n\r\n"; - result += data; - return result; + string result; + result += "HTTP/1.1 "; + result += lexical_cast<string>(statusCode); + result += ' '; + result += statusStr; + result += "\r\nContent-Type: "; + result += mimeType; + result += "\r\nContent-Length: "; + result += lexical_cast<string>(data.length()); + result += "\r\n\r\n"; + result += data; + return result; } string HttpParser::parseHttp(bool isRequest, const string& data, map<string, string>& headers) { - bool onlyNewLineChar = false; - size_t headerEnd = data.find("\r\n\r\n"); - if (headerEnd == data.npos) { - headerEnd = data.find("\n\n"); - if (headerEnd != data.npos) { - onlyNewLineChar = true; - headerEnd += 2; - } - } else { - headerEnd += 4; - } - - size_t lineStart = 0; - size_t lineEnd = 0; - size_t lineSepPos = 0; - size_t lastLineEnd = data.npos; - while (lastLineEnd != lineEnd) { - lastLineEnd = lineEnd; - if (lineEnd == 0) { - if (isRequest) { - lineSepPos = data.find(' '); - lineEnd = data.find(onlyNewLineChar ? "\n" : "\r\n"); - headers["method"] = data.substr(0, lineSepPos); - headers["path"] = data.substr(lineSepPos + 1, data.find(' ', lineSepPos + 1) - lineSepPos - 1); - } else { - lineSepPos = data.find(' '); - lineEnd = data.find(onlyNewLineChar ? "\n" : "\r\n"); - headers["status"] = data.substr(lineSepPos + 1, data.find(' ', lineSepPos + 1) - lineSepPos - 1); - } - } else { - lineStart = lineEnd; - lineStart += onlyNewLineChar ? 1 : 2; - lineEnd = data.find(onlyNewLineChar ? "\n" : "\r\n", lineStart); - lineSepPos = data.find(':', lineStart); - if (lineEnd >= headerEnd || lastLineEnd == lineEnd || lineSepPos >= headerEnd) { - break; - } - headers[to_lower_copy(data.substr(lineStart, lineSepPos - lineStart))] = trim_copy(data.substr(lineSepPos + 1, lineEnd - lineSepPos - 1)); - } - } - - return headerEnd == data.npos ? "" : data.substr(headerEnd); + bool onlyNewLineChar = false; + size_t headerEnd = data.find("\r\n\r\n"); + if (headerEnd == data.npos) { + headerEnd = data.find("\n\n"); + if (headerEnd != data.npos) { + onlyNewLineChar = true; + headerEnd += 2; + } + } else { + headerEnd += 4; + } + + size_t lineStart = 0; + size_t lineEnd = 0; + size_t lineSepPos = 0; + size_t lastLineEnd = data.npos; + while (lastLineEnd != lineEnd) { + lastLineEnd = lineEnd; + if (lineEnd == 0) { + if (isRequest) { + lineSepPos = data.find(' '); + lineEnd = data.find(onlyNewLineChar ? "\n" : "\r\n"); + headers["method"] = data.substr(0, lineSepPos); + headers["path"] = data.substr(lineSepPos + 1, data.find(' ', lineSepPos + 1) - lineSepPos - 1); + } else { + lineSepPos = data.find(' '); + lineEnd = data.find(onlyNewLineChar ? "\n" : "\r\n"); + headers["status"] = data.substr(lineSepPos + 1, data.find(' ', lineSepPos + 1) - lineSepPos - 1); + } + } else { + lineStart = lineEnd; + lineStart += onlyNewLineChar ? 1 : 2; + lineEnd = data.find(onlyNewLineChar ? "\n" : "\r\n", lineStart); + lineSepPos = data.find(':', lineStart); + if (lineEnd >= headerEnd || lastLineEnd == lineEnd || lineSepPos >= headerEnd) { + break; + } + headers[to_lower_copy(data.substr(lineStart, lineSepPos - lineStart))] = trim_copy(data.substr(lineSepPos + 1, lineEnd - lineSepPos - 1)); + } + } + + return headerEnd == data.npos ? "" : data.substr(headerEnd); } string HttpParser::parseHttp(bool isRequest, const string& data) { - size_t headerEnd = data.find("\r\n\r\n"); - if (headerEnd == data.npos) { - headerEnd = data.find("\n\n"); - } - if (headerEnd == data.npos) { - headerEnd = 0; - } - return data.substr(headerEnd); + size_t headerEnd = data.find("\r\n\r\n"); + if (headerEnd == data.npos) { + headerEnd = data.find("\n\n"); + } + if (headerEnd == data.npos) { + headerEnd = 0; + } + return data.substr(headerEnd); } } diff --git a/src/net/TgLongPoll.cpp b/src/net/TgLongPoll.cpp index f420e92..91bf058 100644 --- a/src/net/TgLongPoll.cpp +++ b/src/net/TgLongPoll.cpp @@ -31,13 +31,13 @@ TgLongPoll::TgLongPoll(const Bot& bot) : TgLongPoll(&bot.getApi(), &bot.getEvent } void TgLongPoll::start() { - std::vector<Update::Ptr> updates = _api->getUpdates(_lastUpdateId, 100, 60); - for (Update::Ptr& item : updates) { - if (item->updateId >= _lastUpdateId) { - _lastUpdateId = item->updateId + 1; - } - _eventHandler->handleUpdate(item); - } + std::vector<Update::Ptr> updates = _api->getUpdates(_lastUpdateId, 100, 60); + for (Update::Ptr& item : updates) { + if (item->updateId >= _lastUpdateId) { + _lastUpdateId = item->updateId + 1; + } + _eventHandler->handleUpdate(item); + } } } diff --git a/src/net/Url.cpp b/src/net/Url.cpp index c773f3b..44d9089 100644 --- a/src/net/Url.cpp +++ b/src/net/Url.cpp @@ -29,52 +29,52 @@ using namespace std; namespace TgBot { Url::Url(const string& url) { - bool isProtocolParsed = false; - bool isHostParsed = false; - bool isPathParsed = false; - bool isQueryParsed = false; + bool isProtocolParsed = false; + bool isHostParsed = false; + bool isPathParsed = false; + bool isQueryParsed = false; - for (size_t i = 0, count = url.length(); i < count; ++i) { - char c = url[i]; + for (size_t i = 0, count = url.length(); i < count; ++i) { + char c = url[i]; - if (!isProtocolParsed) { - if (c == ':') { - isProtocolParsed = true; - i += 2; - } else { - protocol += c; - } - } else if (!isHostParsed) { - if (c == '/') { - isHostParsed = true; - path += '/'; - } else if (c == '?') { - isHostParsed = isPathParsed = true; - path += '/'; - } else if (c == '#') { - isHostParsed = isPathParsed = isQueryParsed = true; - path += '/'; - } else { - host += c; - } - } else if (!isPathParsed) { - if (c == '?') { - isPathParsed = true; - } else if (c == '#') { - isPathParsed = isQueryParsed = true; - } else { - path += c; - } - } else if (!isQueryParsed) { - if (c == '#') { - isQueryParsed = true; - } else { - query += c; - } - } else { - fragment += c; - } - } + if (!isProtocolParsed) { + if (c == ':') { + isProtocolParsed = true; + i += 2; + } else { + protocol += c; + } + } else if (!isHostParsed) { + if (c == '/') { + isHostParsed = true; + path += '/'; + } else if (c == '?') { + isHostParsed = isPathParsed = true; + path += '/'; + } else if (c == '#') { + isHostParsed = isPathParsed = isQueryParsed = true; + path += '/'; + } else { + host += c; + } + } else if (!isPathParsed) { + if (c == '?') { + isPathParsed = true; + } else if (c == '#') { + isPathParsed = isQueryParsed = true; + } else { + path += c; + } + } else if (!isQueryParsed) { + if (c == '#') { + isQueryParsed = true; + } else { + query += c; + } + } else { + fragment += c; + } + } host = StringTools::urlEncode(host, "."); path = StringTools::urlEncode(path, "/"); diff --git a/src/tools/Api.cpp b/src/tools/Api.cpp new file mode 100644 index 0000000..0bd970c --- /dev/null +++ b/src/tools/Api.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2015 Oleg Morozenkov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tgbot/Api.h" + +#include "tgbot/TgTypeParser.h" +#include "tgbot/TgException.h" +#include "tgbot/net/HttpClient.h" + +using namespace std; +using namespace boost::property_tree; + +namespace TgBot { + +Api::Api(const std::string& token) : _token(token) { +} + +User::Ptr Api::getMe() const { + return TgTypeParser::getInstance().parseUser(sendRequest("getMe").find("result")->second); +} + +Message::Ptr Api::sendMessage(int32_t chatId, const string& text, bool disableWebPagePreview, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("text", text)); + if (disableWebPagePreview) { + args.push_back(HttpReqArg("disable_web_page_preview", disableWebPagePreview)); + } + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendMessage", args).find("result")->second); +} + +Message::Ptr Api::forwardMessage(int32_t chatId, int32_t fromChatId, int32_t messageId) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("from_chat_id", fromChatId)); + args.push_back(HttpReqArg("message_id", messageId)); + return TgTypeParser::getInstance().parseMessage(sendRequest("forwardMessage", args).find("result")->second); +} + +Message::Ptr Api::sendPhoto(int32_t chatId, const InputFile::Ptr& photo, const string& caption, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("photo", photo->data, true, photo->mimeType)); + if (!caption.empty()) { + args.push_back(HttpReqArg("caption", caption)); + } + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendPhoto", args).find("result")->second); +} + +Message::Ptr Api::sendPhoto(int32_t chatId, const string& photo, const string& caption, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("photo", photo)); + if (!caption.empty()) { + args.push_back(HttpReqArg("caption", caption)); + } + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendPhoto", args).find("result")->second); +} + +Message::Ptr Api::sendAudio(int32_t chatId, const InputFile::Ptr& audio, int32_t duration, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("audio", audio->data, true, audio->mimeType)); + if (duration) { + args.push_back(HttpReqArg("duration", duration)); + } + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendAudio", args).find("result")->second); +} + +Message::Ptr Api::sendAudio(int32_t chatId, const string& audio, int32_t duration, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("audio", audio)); + if (duration) { + args.push_back(HttpReqArg("duration", duration)); + } + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendAudio", args).find("result")->second); +} + +Message::Ptr Api::sendDocument(int32_t chatId, const InputFile::Ptr& document, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("document", document->data, true, document->mimeType)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendDocument", args).find("result")->second); +} + +Message::Ptr Api::sendDocument(int32_t chatId, const string& document, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("document", document)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendDocument", args).find("result")->second); +} + +Message::Ptr Api::sendSticker(int32_t chatId, const InputFile::Ptr& sticker, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("sticker", sticker->data, true, sticker->mimeType)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendSticker", args).find("result")->second); +} + +Message::Ptr Api::sendSticker(int32_t chatId, const string& sticker, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("sticker", sticker)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendSticker", args).find("result")->second); +} + +Message::Ptr Api::sendVideo(int32_t chatId, const InputFile::Ptr& video, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("video", video->data, true, video->mimeType)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendVideo", args).find("result")->second); +} + +Message::Ptr Api::sendVideo(int32_t chatId, const string& video, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("video", video)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendVideo", args).find("result")->second); +} + +Message::Ptr Api::sendLocation(int32_t chatId, float latitude, float longitude, int32_t replyToMessageId, const GenericReply::Ptr& replyMarkup) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("latitude", latitude)); + args.push_back(HttpReqArg("longitude", longitude)); + if (replyToMessageId) { + args.push_back(HttpReqArg("reply_to_message_id", replyToMessageId)); + } + if (replyMarkup) { + args.push_back(HttpReqArg("reply_markup", TgTypeParser::getInstance().parseGenericReply(replyMarkup))); + } + return TgTypeParser::getInstance().parseMessage(sendRequest("sendLocation", args).find("result")->second); +} + +void Api::sendChatAction(int32_t chatId, const string& action) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("chat_id", chatId)); + args.push_back(HttpReqArg("action", action)); + sendRequest("sendChatAction", args); +} + +UserProfilePhotos::Ptr Api::getUserProfilePhotos(int32_t userId, int32_t offset, int32_t limit) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("user_id", userId)); + if (offset) { + args.push_back(HttpReqArg("offset", offset)); + } + limit = max(1, min(100, limit)); + args.push_back(HttpReqArg("limit", limit)); + return TgTypeParser::getInstance().parseUserProfilePhotos(sendRequest("getUserProfilePhotos", args).find("result")->second); +} + +vector<Update::Ptr> Api::getUpdates(int32_t offset, int32_t limit, int32_t timeout) const { + vector<HttpReqArg> args; + if (offset) { + args.push_back(HttpReqArg("offset", offset)); + } + limit = max(1, min(100, limit)); + args.push_back(HttpReqArg("limit", limit)); + if (timeout) { + args.push_back(HttpReqArg("timeout", timeout)); + } + return TgTypeParser::getInstance().parseArray<Update>(TgTypeParser::getInstance().parseUpdate, sendRequest("getUpdates", args), "result"); +} + +void Api::setWebhook(const string& url) const { + vector<HttpReqArg> args; + args.push_back(HttpReqArg("url", url)); + sendRequest("setWebhook", args); +} + +boost::property_tree::ptree Api::sendRequest(const std::string& method, const std::vector<HttpReqArg>& args) const { + std::string url = "https://api.telegram.org/bot"; + url += _token; + url += "/"; + url += method; + string serverResponse = HttpClient::getInstance().makeRequest(url, args); + if (serverResponse.find("<html>") != serverResponse.npos) { + throw TgException("Bad request"); + } + ptree result = TgTypeParser::getInstance().parseJson(serverResponse); + try { + if (result.get<bool>("ok")) { + return result; + } else { + throw TgException(result.get("description", "")); + } + } catch (boost::property_tree::ptree_error& e) { + throw TgException(""); + } +} + +} diff --git a/src/tools/StringTools.cpp b/src/tools/StringTools.cpp index deb8fa1..0a6dbc3 100644 --- a/src/tools/StringTools.cpp +++ b/src/tools/StringTools.cpp @@ -35,17 +35,17 @@ bool startsWith(const string& str1, const string& str2) { return false; } string::const_iterator it1(str1.begin()); - string::const_iterator end1(str1.end()); - string::const_iterator it2(str2.begin()); - string::const_iterator end2(str2.end()); - while (it1 != end1 && it2 != end2) { - if (*it1 != *it2) { - return false; - } - ++it1; - ++it2; - } - return true; + string::const_iterator end1(str1.end()); + string::const_iterator it2(str2.begin()); + string::const_iterator end2(str2.end()); + while (it1 != end1 && it2 != end2) { + if (*it1 != *it2) { + return false; + } + ++it1; + ++it2; + } + return true; } bool endsWith(const string& str1, const string& str2) { @@ -53,67 +53,67 @@ bool endsWith(const string& str1, const string& str2) { return false; } string::const_iterator it1(str1.end()); - string::const_iterator begin1(str1.begin()); - string::const_iterator it2(str2.end()); - string::const_iterator begin2(str2.begin()); - while (it1 != begin1 && it2 != begin2) { - if (*it1 != *it2) { - return false; - } - --it1; - --it2; - } - return true; + string::const_iterator begin1(str1.begin()); + string::const_iterator it2(str2.end()); + string::const_iterator begin2(str2.begin()); + while (it1 != begin1 && it2 != begin2) { + if (*it1 != *it2) { + return false; + } + --it1; + --it2; + } + return true; } void split(const string& str, char delimiter, vector<string>& dest) { - istringstream stream(str); - string s; - while (getline(stream, s, delimiter)) { - dest.push_back(s); - } + istringstream stream(str); + string s; + while (getline(stream, s, delimiter)) { + dest.push_back(s); + } } string generateRandomString(size_t length) { - static const string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890-=[]\\;',./!@#$%^&*()_+{}|:\"<>?`~"); - static const size_t charsLen = chars.length(); - string result; - for (int i = 0; i < length; ++i) { - result += chars[rand() % charsLen]; - } - return result; + static const string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890-=[]\\;',./!@#$%^&*()_+{}|:\"<>?`~"); + static const size_t charsLen = chars.length(); + string result; + for (int i = 0; i < length; ++i) { + result += chars[rand() % charsLen]; + } + return result; } string urlEncode(const string& value, const std::string additionalLegitChars) { - static const string legitPunctuation = "-_.~"; - ostringstream result; - result.fill('0'); - result << hex; - for (const char& c : value) { - if (isalnum(c) || legitPunctuation.find(c) != legitPunctuation.npos || additionalLegitChars.find(c) != additionalLegitChars.npos) { - result << c; - } else { - result << '%' << setw(2) << int((unsigned char) c); - } - } + static const string legitPunctuation = "-_.~"; + ostringstream result; + result.fill('0'); + result << hex; + for (const char& c : value) { + if (isalnum(c) || legitPunctuation.find(c) != legitPunctuation.npos || additionalLegitChars.find(c) != additionalLegitChars.npos) { + result << c; + } else { + result << '%' << setw(2) << int((unsigned char) c); + } + } - return result.str(); + return result.str(); } string urlDecode(const string& value) { - string result; - for (size_t i = 0, count = value.length(); i < count; ++i) { - const char c = value[i]; - if (c == '%') { - int t = 0; - sscanf(value.substr(i + 1, 2).c_str(), "%x", &t); - result += (char) t; - i += 2; - } else { - result += c; - } - } - return result; + string result; + for (size_t i = 0, count = value.length(); i < count; ++i) { + const char c = value[i]; + if (c == '%') { + int t = 0; + sscanf(value.substr(i + 1, 2).c_str(), "%x", &t); + result += (char) t; + i += 2; + } else { + result += c; + } + } + return result; } } diff --git a/src/tools/TgException.cpp b/src/tools/TgException.cpp new file mode 100644 index 0000000..0c118ec --- /dev/null +++ b/src/tools/TgException.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015 Oleg Morozenkov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tgbot/TgException.h" + +namespace TgBot { + +TgBot::TgException::TgException(const std::string description) : runtime_error(description) { +} + +} diff --git a/src/tools/TgTypeParser.cpp b/src/tools/TgTypeParser.cpp new file mode 100644 index 0000000..a9c6812 --- /dev/null +++ b/src/tools/TgTypeParser.cpp @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2015 Oleg Morozenkov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software", "to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tgbot/TgTypeParser.h" + +using namespace std; +using namespace boost::property_tree; + +namespace TgBot { + +TgTypeParser& TgTypeParser::getInstance() { + static TgTypeParser result; + return result; +} + +User::Ptr TgTypeParser::parseJsonAndGetUser(const ptree& data) const { + User::Ptr result(new User); + result->id = data.get<int32_t>("id"); + result->firstName = data.get<string>("first_name"); + result->lastName = data.get("last_name", ""); + result->username = data.get("username", ""); + return result; +} + +string TgTypeParser::parseUser(const User::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "id", object->id); + appendToJson(result, "first_name", object->firstName); + appendToJson(result, "last_name", object->lastName); + appendToJson(result, "username", object->username); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +GroupChat::Ptr TgTypeParser::parseJsonAndGetGroupChat(const ptree& data) const { + GroupChat::Ptr result(new GroupChat); + result->id = data.get<int32_t>("id"); + result->title = data.get<string>("title"); + return result; +} + +string TgTypeParser::parseGroupChat(const GroupChat::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "id", object->id); + appendToJson(result, "title", object->title); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Message::Ptr TgTypeParser::parseJsonAndGetMessage(const ptree& data) const { + Message::Ptr result(new Message); + result->messageId = data.get<int32_t>("message_id"); + result->from = parseJsonAndGetUser(data.find("from")->second); + result->date = data.get<int32_t>("date"); + result->chat = parseJsonAndGetGenericChat(data.find("chat")->second); + result->forwardFrom = tryParseJson<User>(&TgTypeParser::parseJsonAndGetUser, data, "forward_from"); + result->forwardDate = data.get("forward_date", 0); + result->replyToMessage = tryParseJson<Message>(parseJsonAndGetMessage, data, "reply_to_message"); + result->text = data.get("text", ""); + result->audio = tryParseJson<Audio>(parseJsonAndGetAudio, data, "audio"); + result->document = tryParseJson<Document>(parseJsonAndGetDocument, data, "document"); + result->photo = parseArray<PhotoSize>(parseJsonAndGetPhotoSize, data, "photo"); + result->sticker = tryParseJson<Sticker>(parseJsonAndGetSticker, data, "sticker"); + result->video = tryParseJson<Video>(parseJsonAndGetVideo, data, "video"); + result->contact = tryParseJson<Contact>(parseJsonAndGetContact, data, "contact"); + result->location = tryParseJson<Location>(parseJsonAndGetLocation, data, "location"); + result->newChatParticipant = tryParseJson<User>(parseJsonAndGetUser, data, "new_chat_participant"); + result->leftChatParticipant = tryParseJson<User>(parseJsonAndGetUser, data, "left_chat_participant"); + result->newChatTitle = data.get("new_chat_title", ""); + result->newChatPhoto = parseJsonAndGetArray<PhotoSize>(parseJsonAndGetPhotoSize, data, "new_chat_photo"); + result->deleteChatPhoto = data.get("delete_chat_photo", false); + result->groupChatCreated = data.get("group_chat_created", false); + result->caption = data.get("caption", false); + return result; +} + +string TgTypeParser::parseMessage(const Message::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "message_id", object->messageId); + appendToJson(result, "from", parseUser(object->from)); + appendToJson(result, "date", object->date); + appendToJson(result, "chat", parseGenericChat(object->chat)); + appendToJson(result, "forward_from", parseUser(object->forwardFrom)); + appendToJson(result, "forward_date", object->forwardDate); + appendToJson(result, "reply_to_message", parseMessage(object->replyToMessage)); + appendToJson(result, "text", object->text); + appendToJson(result, "audio", parseAudio(object->audio)); + appendToJson(result, "document", parseDocument(object->document)); + appendToJson(result, "photo", parseArray(parsePhotoSize, object->photo)); + appendToJson(result, "sticker", parseSticker(object->sticker)); + appendToJson(result, "video", parseVideo(object->video)); + appendToJson(result, "contact", parseContact(object->contact)); + appendToJson(result, "location", parseLocation(object->location)); + appendToJson(result, "new_chat_participant", parseUser(object->newChatParticipant)); + appendToJson(result, "left_chat_participant", parseUser(object->leftChatParticipant)); + appendToJson(result, "new_chat_title", object->newChatTitle); + appendToJson(result, "new_chat_photo", parseArray(parsePhotoSize, object->newChatPhoto)); + appendToJson(result, "delete_chat_photo", object->deleteChatPhoto); + appendToJson(result, "group_chat_created", object->groupChatCreated); + appendToJson(result, "caption", object->caption); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +PhotoSize::Ptr TgTypeParser::parseJsonAndGetPhotoSize(const ptree& data) const { + PhotoSize::Ptr result(new PhotoSize); + result->fileId = data.get<string>("file_id"); + result->width = data.get<int32_t>("width"); + result->height = data.get<int32_t>("height"); + result->fileSize = data.get("file_size", 0); + return result; +} + +string TgTypeParser::parsePhotoSize(const PhotoSize::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "file_id", object->fileId); + appendToJson(result, "width", object->width); + appendToJson(result, "height", object->height); + appendToJson(result, "file_size", object->fileSize); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Audio::Ptr TgTypeParser::parseJsonAndGetAudio(const ptree& data) const { + Audio::Ptr result(new Audio); + result->fileId = data.get<string>("file_id"); + result->duration = data.get<int32_t>("duration"); + result->mimeType = data.get("mime_type", ""); + result->fileSize = data.get("file_size", 0); + return result; +} + +string TgTypeParser::parseAudio(const Audio::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "file_id", object->fileId); + appendToJson(result, "duration", object->duration); + appendToJson(result, "mime_type", object->mimeType); + appendToJson(result, "file_size", object->fileSize); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Document::Ptr TgTypeParser::parseJsonAndGetDocument(const ptree& data) const { + Document::Ptr result(new Document); + result->fileId = data.get<string>("file_id"); + result->thumb = parseJsonAndGetPhotoSize(data.find("thumb")->second); + result->fileName = data.get("file_name", ""); + result->mimeType = data.get("mime_type", ""); + result->fileSize = data.get("file_size", 0); + return result; +} + +string TgTypeParser::parseDocument(const Document::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "file_id", object->fileId); + appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "file_name", object->fileName); + appendToJson(result, "mime_type", object->mimeType); + appendToJson(result, "file_size", object->fileSize); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Sticker::Ptr TgTypeParser::parseJsonAndGetSticker(const ptree& data) const { + Sticker::Ptr result(new Sticker); + result->fileId = data.get<string>("file_id"); + result->width = data.get<int32_t>("width"); + result->height = data.get<int32_t>("height"); + result->thumb = parseJsonAndGetPhotoSize(data.find("thumb")->second); + result->fileSize = data.get("file_size", 0); + return result; +} + +string TgTypeParser::parseSticker(const Sticker::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "file_id", object->fileId); + appendToJson(result, "width", object->width); + appendToJson(result, "height", object->height); + appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "file_size", object->fileSize); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Video::Ptr TgTypeParser::parseJsonAndGetVideo(const ptree& data) const { + Video::Ptr result(new Video); + result->fileId = data.get<string>("file_id"); + result->width = data.get<int32_t>("width"); + result->height = data.get<int32_t>("height"); + result->duration = data.get<int32_t>("duration"); + result->thumb = parseJsonAndGetPhotoSize(data.find("thumb")->second); + result->mimeType = data.get("mime_type", ""); + result->fileSize = data.get("file_size", 0); + return result; +} + +string TgTypeParser::parseVideo(const Video::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "file_id", object->fileId); + appendToJson(result, "width", object->width); + appendToJson(result, "height", object->height); + appendToJson(result, "duration", object->duration); + appendToJson(result, "thumb", parsePhotoSize(object->thumb)); + appendToJson(result, "mime_type", object->mimeType); + appendToJson(result, "file_size", object->fileSize); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Contact::Ptr TgTypeParser::parseJsonAndGetContact(const ptree& data) const { + Contact::Ptr result(new Contact); + result->phoneNumber = data.get<string>("phone_number"); + result->firstName = data.get<string>("first_name"); + result->lastName = data.get("last_name", ""); + result->userId = data.get("user_id", ""); + return result; +} + +string TgTypeParser::parseContact(const Contact::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "phone_number", object->phoneNumber); + appendToJson(result, "first_name", object->firstName); + appendToJson(result, "last_name", object->lastName); + appendToJson(result, "user_id", object->userId); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Location::Ptr TgTypeParser::parseJsonAndGetLocation(const ptree& data) const { + Location::Ptr result(new Location); + result->longitude = data.get<float>("longitude"); + result->latitude = data.get<float>("latitude"); + return result; +} + +string TgTypeParser::parseLocation(const Location::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "longitude", object->longitude); + appendToJson(result, "latitude", object->latitude); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +Update::Ptr TgTypeParser::parseJsonAndGetUpdate(const ptree& data) const { + Update::Ptr result(new Update); + result->updateId = data.get<int32_t>("update_id"); + result->message = parseJsonAndGetMessage(data.find("message")->second); + return result; +} + +string TgTypeParser::parseUpdate(const Update::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "update_id", object->updateId); + appendToJson(result, "message", parseMessage(object->message)); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +UserProfilePhotos::Ptr TgTypeParser::parseJsonAndGetUserProfilePhotos(const ptree& data) const { + UserProfilePhotos::Ptr result(new UserProfilePhotos); + result->totalCount = data.get<int32_t>("total_count"); + result->photos = parseJsonAndGet2DArray<PhotoSize>(parseJsonAndGetPhotoSize, data, "photos"); + return result; +} + +string TgTypeParser::parseUserProfilePhotos(const UserProfilePhotos::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "total_count", object->totalCount); + appendToJson(result, "photos", parse2DArray(parsePhotoSize, object->photos)); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +ReplyKeyboardMarkup::Ptr TgTypeParser::parseJsonAndGetReplyKeyboardMarkup(const boost::property_tree::ptree& data) const { + ReplyKeyboardMarkup::Ptr result(new ReplyKeyboardMarkup); + for (const pair<const string, ptree>& item : data.find("keyboard")->second) { + vector<string> array; + for (const pair<const string, ptree>& innerItem : item.second) { + array.push_back(innerItem.second.data()); + } + result->keyboard.push_back(array); + } + result->resizeKeyboard = data.get<bool>("resize_keyboard"); + result->oneTimeKeyboard = data.get<bool>("one_time_keyboard"); + result->selective = data.get<bool>("selective"); + return result; +} + +std::string TgTypeParser::parseReplyKeyboardMarkup(const ReplyKeyboardMarkup::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + result += "\"keyboard\":["; + for (vector<string>& item : object->keyboard) { + result += '['; + for (string& innerItem : item) { + result += '"'; + result += innerItem; + result += "\","; + } + result.erase(result.length() - 1); + result += "],"; + } + result.erase(result.length() - 1); + result += "],"; + appendToJson(result, "resize_keyboard", object->resizeKeyboard); + appendToJson(result, "one_time_keyboard", object->oneTimeKeyboard); + appendToJson(result, "selective", object->selective); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +ReplyKeyboardHide::Ptr TgTypeParser::parseJsonAndGetReplyKeyboardHide(const boost::property_tree::ptree& data) const { + ReplyKeyboardHide::Ptr result(new ReplyKeyboardHide); + result->selective = data.get<bool>("selective"); + return result; +} + +std::string TgTypeParser::parseReplyKeyboardHide(const ReplyKeyboardHide::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "selective", object->selective); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +ForceReply::Ptr TgTypeParser::parseJsonAndGetForceReply(const boost::property_tree::ptree& data) const { + ForceReply::Ptr result(new ForceReply); + result->selective = data.get<bool>("selective"); + return result; +} + +std::string TgTypeParser::parseForceReply(const ForceReply::Ptr& object) const { + if (!object) { + return ""; + } + string result; + result += '{'; + appendToJson(result, "selective", object->selective); + result.erase(result.length() - 1); + result += '}'; + return result; +} + +GenericChat::Ptr TgTypeParser::parseJsonAndGetGenericChat(const ptree& data) const { + if (data.find("first_name") == data.not_found()) { + return static_pointer_cast<GenericChat>(parseJsonAndGetGroupChat(data)); + } else { + return static_pointer_cast<GenericChat>(parseJsonAndGetUser(data)); + } +} + +string TgTypeParser::parseGenericChat(const GenericChat::Ptr& object) const { + if (!object) { + return ""; + } + if (dynamic_pointer_cast<User>(object) == nullptr) { + return parseGroupChat(static_pointer_cast<GroupChat>(object)); + } else { + return parseUser(static_pointer_cast<User>(object)); + } +} + +GenericReply::Ptr TgTypeParser::parseJsonAndGetGenericReply(const boost::property_tree::ptree& data) const { + if (data.find("force_reply") != data.not_found()) { + return static_pointer_cast<GenericReply>(parseJsonAndGetForceReply(data)); + } else if (data.find("hide_keyboard") != data.not_found()) { + return static_pointer_cast<GenericReply>(parseJsonAndGetReplyKeyboardHide(data)); + } else { + return static_pointer_cast<GenericReply>(parseJsonAndGetReplyKeyboardMarkup(data)); + } +} + +std::string TgTypeParser::parseGenericReply(const GenericReply::Ptr& object) const { + if (!object) { + return ""; + } + if (dynamic_pointer_cast<ForceReply>(object) != nullptr) { + return parseForceReply(static_pointer_cast<ForceReply>(object)); + } else if (dynamic_pointer_cast<ReplyKeyboardHide>(object) != nullptr) { + return parseReplyKeyboardHide(static_pointer_cast<ReplyKeyboardHide>(object)); + } else { + return parseReplyKeyboardMarkup(static_pointer_cast<ReplyKeyboardMarkup>(object)); + } +} + +void TgTypeParser::appendToJson(string& json, const string& varName, const string& value) const { + if (value.empty()) { + return; + } + json += '"'; + json += varName; + json += "\":"; + if (value.front() != '{') { + json += '"'; + } + json += value; + if (value.back() != '}') { + json += '"'; + } + json += ','; +} + +} diff --git a/src/tools/net/HttpClient.cpp b/src/tools/net/HttpClient.cpp new file mode 100644 index 0000000..b9813ad --- /dev/null +++ b/src/tools/net/HttpClient.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 Oleg Morozenkov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tgbot/net/HttpClient.h" + +#include <boost/asio/ssl.hpp> + +using namespace std; +using namespace boost::asio; +using namespace boost::asio::ip; +using namespace boost::asio::local; + +namespace TgBot { + +HttpClient& HttpClient::getInstance() { + static HttpClient result; + return result; +} + +string HttpClient::makeRequest(const Url& url, const vector<HttpReqArg>& args) { + ssl::context context(ssl::context::sslv23); + context.set_default_verify_paths(); + + ssl::stream<tcp::socket> socket(_ioService, context); + tcp::resolver resolver(_ioService); + tcp::resolver::query query(url.host, url.protocol); + + connect(socket.lowest_layer(), resolver.resolve(query)); + + socket.set_verify_mode(ssl::verify_none); + socket.set_verify_callback(ssl::rfc2818_verification(url.host)); + socket.handshake(ssl::stream<tcp::socket>::client); + + string requestText = HttpParser::getInstance().generateRequest(url, args, false); + write(socket, buffer(requestText.c_str(), requestText.length())); + + string response; + char buff[1024]; + boost::system::error_code error; + while (!error) { + size_t bytes = read(socket, buffer(buff), error); + response += string(buff, bytes); + } + + return HttpParser::getInstance().parseResponse(response); +} + +} diff --git a/src/tools/net/HttpParser.cpp b/src/tools/net/HttpParser.cpp new file mode 100644 index 0000000..a2d9108 --- /dev/null +++ b/src/tools/net/HttpParser.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2015 Oleg Morozenkov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tgbot/net/HttpParser.h" + +#include <boost/algorithm/string.hpp> + +#include "tgbot/tools/StringTools.h" + +using namespace std; +using namespace boost; + +namespace TgBot { + +HttpParser& HttpParser::getInstance() { + static HttpParser result; + return result; +} + +string HttpParser::generateRequest(const Url& url, const vector<HttpReqArg>& args, bool isKeepAlive) { + string result; + if (args.empty()) { + result += "GET "; + } else { + result += "POST "; + } + result += url.path; + result += url.query.empty() ? "" : "?" + url.query; + result += " HTTP/1.1\r\n"; + result += "Host: "; + result += url.host; + result += "\r\nConnection: "; + if (isKeepAlive) { + result += "keep-alive"; + } else { + result += "close"; + } + result += "\r\n"; + if (args.empty()) { + result += "\r\n"; + } else { + string requestData; + + string bondary = generateMultipartBoundary(args); + if (bondary.empty()) { + result += "Content-Type: application/x-www-form-urlencoded\r\n"; + requestData = generateWwwFormUrlencoded(args); + } else { + result += "Content-Type: multipart/form-data; boundary="; + result += bondary; + result += "\r\n"; + requestData = generateMultipartFormData(args, bondary); + } + + result += "Content-Length: "; + result += lexical_cast<string>(requestData.length()); + result += "\r\n\r\n"; + result += requestData; + } + return result; +} + +string HttpParser::generateMultipartFormData(const vector<HttpReqArg>& args, const string& bondary) { + string result; + for (const HttpReqArg& item : args) { + result += "--"; + result += bondary; + result += "\r\nContent-Disposition: form-data; name=\""; + result += item.name; + result += "\"\r\n"; + if (item.isFile) { + result += "Content-Type: "; + result += item.mimeType; + result += "\r\n"; + } + result += "\r\n"; + result += item.value; + result += "\r\n"; + } + return result; +} + +string HttpParser::generateMultipartBoundary(const vector<HttpReqArg>& args) { + string result; + srand((unsigned int) time(nullptr)); + for (const HttpReqArg& item : args) { + if (item.isFile) { + while (result.empty() || item.value.find(result) != item.value.npos) { + result += StringTools::generateRandomString(4); + } + } + } + return result; +} + +string HttpParser::generateWwwFormUrlencoded(const vector<HttpReqArg>& args) { + string result; + + bool firstRun = true; + for (const HttpReqArg& item : args) { + if (firstRun) { + firstRun = false; + } else { + result += '&'; + } + result += StringTools::urlEncode(item.name); + result += '='; + result += StringTools::urlEncode(item.value); + } + + return result; +} + +string HttpParser::generateResponse(const string& data, const string& mimeType, unsigned short statusCode, const string& statusStr, bool isKeepAlive) { + string result; + result += "HTTP/1.1 "; + result += lexical_cast<string>(statusCode); + result += ' '; + result += statusStr; + result += "\r\nContent-Type: "; + result += mimeType; + result += "\r\nContent-Length: "; + result += lexical_cast<string>(data.length()); + result += "\r\n\r\n"; + result += data; + return result; +} + +string HttpParser::parseHttp(bool isRequest, const string& data, map<string, string>& headers) { + bool onlyNewLineChar = false; + size_t headerEnd = data.find("\r\n\r\n"); + if (headerEnd == data.npos) { + headerEnd = data.find("\n\n"); + if (headerEnd != data.npos) { + onlyNewLineChar = true; + headerEnd += 2; + } + } else { + headerEnd += 4; + } + + size_t lineStart = 0; + size_t lineEnd = 0; + size_t lineSepPos = 0; + size_t lastLineEnd = data.npos; + while (lastLineEnd != lineEnd) { + lastLineEnd = lineEnd; + if (lineEnd == 0) { + if (isRequest) { + lineSepPos = data.find(' '); + lineEnd = data.find(onlyNewLineChar ? "\n" : "\r\n"); + headers["method"] = data.substr(0, lineSepPos); + headers["path"] = data.substr(lineSepPos + 1, data.find(' ', lineSepPos + 1) - lineSepPos - 1); + } else { + lineSepPos = data.find(' '); + lineEnd = data.find(onlyNewLineChar ? "\n" : "\r\n"); + headers["status"] = data.substr(lineSepPos + 1, data.find(' ', lineSepPos + 1) - lineSepPos - 1); + } + } else { + lineStart = lineEnd; + lineStart += onlyNewLineChar ? 1 : 2; + lineEnd = data.find(onlyNewLineChar ? "\n" : "\r\n", lineStart); + lineSepPos = data.find(':', lineStart); + if (lineEnd >= headerEnd || lastLineEnd == lineEnd || lineSepPos >= headerEnd) { + break; + } + headers[to_lower_copy(data.substr(lineStart, lineSepPos - lineStart))] = trim_copy(data.substr(lineSepPos + 1, lineEnd - lineSepPos - 1)); + } + } + + return headerEnd == data.npos ? "" : data.substr(headerEnd); +} + +string HttpParser::parseHttp(bool isRequest, const string& data) { + size_t headerEnd = data.find("\r\n\r\n"); + if (headerEnd == data.npos) { + headerEnd = data.find("\n\n"); + } + if (headerEnd == data.npos) { + headerEnd = 0; + } + return data.substr(headerEnd); +} + +} diff --git a/src/tools/net/TgLongPoll.cpp b/src/tools/net/TgLongPoll.cpp new file mode 100644 index 0000000..91bf058 --- /dev/null +++ b/src/tools/net/TgLongPoll.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015 Oleg Morozenkov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tgbot/net/TgLongPoll.h" + +namespace TgBot { + +TgLongPoll::TgLongPoll(const Api* api, const EventHandler* eventHandler) : _api(api), _eventHandler(eventHandler) { +} + +TgLongPoll::TgLongPoll(const Bot& bot) : TgLongPoll(&bot.getApi(), &bot.getEventHandler()) { +} + +void TgLongPoll::start() { + std::vector<Update::Ptr> updates = _api->getUpdates(_lastUpdateId, 100, 60); + for (Update::Ptr& item : updates) { + if (item->updateId >= _lastUpdateId) { + _lastUpdateId = item->updateId + 1; + } + _eventHandler->handleUpdate(item); + } +} + +} diff --git a/src/tools/net/Url.cpp b/src/tools/net/Url.cpp new file mode 100644 index 0000000..44d9089 --- /dev/null +++ b/src/tools/net/Url.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015 Oleg Morozenkov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tgbot/net/Url.h" + +#include "tgbot/tools/StringTools.h" + +using namespace std; + +namespace TgBot { + +Url::Url(const string& url) { + bool isProtocolParsed = false; + bool isHostParsed = false; + bool isPathParsed = false; + bool isQueryParsed = false; + + for (size_t i = 0, count = url.length(); i < count; ++i) { + char c = url[i]; + + if (!isProtocolParsed) { + if (c == ':') { + isProtocolParsed = true; + i += 2; + } else { + protocol += c; + } + } else if (!isHostParsed) { + if (c == '/') { + isHostParsed = true; + path += '/'; + } else if (c == '?') { + isHostParsed = isPathParsed = true; + path += '/'; + } else if (c == '#') { + isHostParsed = isPathParsed = isQueryParsed = true; + path += '/'; + } else { + host += c; + } + } else if (!isPathParsed) { + if (c == '?') { + isPathParsed = true; + } else if (c == '#') { + isPathParsed = isQueryParsed = true; + } else { + path += c; + } + } else if (!isQueryParsed) { + if (c == '#') { + isQueryParsed = true; + } else { + query += c; + } + } else { + fragment += c; + } + } + + host = StringTools::urlEncode(host, "."); + path = StringTools::urlEncode(path, "/"); + query = StringTools::urlEncode(query, "&"); + fragment = StringTools::urlEncode(fragment); +} + +} diff --git a/src/tools/tools/StringTools.cpp b/src/tools/tools/StringTools.cpp new file mode 100644 index 0000000..0a6dbc3 --- /dev/null +++ b/src/tools/tools/StringTools.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015 Oleg Morozenkov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tgbot/tools/StringTools.h" + +#include <stdlib.h> +#include <iomanip> +#include <stdio.h> + +using namespace std; + +namespace StringTools { + +bool startsWith(const string& str1, const string& str2) { + if (str1.length() < str2.length()) { + return false; + } + string::const_iterator it1(str1.begin()); + string::const_iterator end1(str1.end()); + string::const_iterator it2(str2.begin()); + string::const_iterator end2(str2.end()); + while (it1 != end1 && it2 != end2) { + if (*it1 != *it2) { + return false; + } + ++it1; + ++it2; + } + return true; +} + +bool endsWith(const string& str1, const string& str2) { + if (str1.length() < str2.length()) { + return false; + } + string::const_iterator it1(str1.end()); + string::const_iterator begin1(str1.begin()); + string::const_iterator it2(str2.end()); + string::const_iterator begin2(str2.begin()); + while (it1 != begin1 && it2 != begin2) { + if (*it1 != *it2) { + return false; + } + --it1; + --it2; + } + return true; +} + +void split(const string& str, char delimiter, vector<string>& dest) { + istringstream stream(str); + string s; + while (getline(stream, s, delimiter)) { + dest.push_back(s); + } +} + +string generateRandomString(size_t length) { + static const string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890-=[]\\;',./!@#$%^&*()_+{}|:\"<>?`~"); + static const size_t charsLen = chars.length(); + string result; + for (int i = 0; i < length; ++i) { + result += chars[rand() % charsLen]; + } + return result; +} + +string urlEncode(const string& value, const std::string additionalLegitChars) { + static const string legitPunctuation = "-_.~"; + ostringstream result; + result.fill('0'); + result << hex; + for (const char& c : value) { + if (isalnum(c) || legitPunctuation.find(c) != legitPunctuation.npos || additionalLegitChars.find(c) != additionalLegitChars.npos) { + result << c; + } else { + result << '%' << setw(2) << int((unsigned char) c); + } + } + + return result.str(); +} + +string urlDecode(const string& value) { + string result; + for (size_t i = 0, count = value.length(); i < count; ++i) { + const char c = value[i]; + if (c == '%') { + int t = 0; + sscanf(value.substr(i + 1, 2).c_str(), "%x", &t); + result += (char) t; + i += 2; + } else { + result += c; + } + } + return result; +} + +} |