From d8166a558dd1c75c585bc1a19a6ba51b2c7d284f Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 15 Mar 2022 20:28:51 +0300 Subject: [PATCH 01/17] Update TDLib to 1.8.2. --- td | 2 +- telegram-bot-api/Client.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/td b/td index 92c2a9c..3f54c30 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 92c2a9c4e521df720abeaa9872e1c2b797d5c93f +Subproject commit 3f54c301ead1bbe6529df4ecfb63c7f645dd181c diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 87d11e6..515d42b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6899,7 +6899,7 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { send_request( make_object(chat_id, 0, reply_to_message_id, get_message_send_options(disable_notification, protect_content), - std::move(input_message_contents)), + std::move(input_message_contents), false), std::make_unique(this, std::move(query))); }; check_message(chat_id, reply_to_message_id, reply_to_message_id <= 0 || allow_sending_without_reply, From 3e9da685379ad4656fc8cbf094a4eda3b3c190fd Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 16 Mar 2022 12:41:12 +0300 Subject: [PATCH 02/17] Use td::FlatHashTable instead of std::unordered_map/set. --- telegram-bot-api/Client.cpp | 128 +++++++++++++++++------------ telegram-bot-api/Client.h | 56 +++++++------ telegram-bot-api/ClientManager.cpp | 9 +- telegram-bot-api/ClientManager.h | 8 +- telegram-bot-api/Query.cpp | 4 +- telegram-bot-api/Query.h | 14 ++-- telegram-bot-api/WebhookActor.cpp | 35 +++++--- telegram-bot-api/WebhookActor.h | 6 +- 8 files changed, 151 insertions(+), 109 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 515d42b..025fce3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3760,7 +3760,7 @@ void Client::check_chat_access(int64 chat_id, AccessRights access_rights, const CHECK(group_info != nullptr); if (!group_info->is_active && need_write_access) { if (group_info->upgraded_to_supergroup_id != 0) { - std::unordered_map> parameters; + td::FlatHashMap> parameters; auto updagraded_to_chat_id = get_supergroup_chat_id(group_info->upgraded_to_supergroup_id); parameters.emplace("migrate_to_chat_id", std::make_unique(updagraded_to_chat_id)); return fail_query(400, "Bad Request: group chat was upgraded to a supergroup chat", std::move(query), @@ -4398,7 +4398,8 @@ void Client::on_update(object_ptr result) { } case td_api::updateUser::ID: { auto update = move_object_as(result); - add_user(users_, std::move(update->user_)); + auto *user_info = add_user_info(update->user_->id_); + add_user(user_info, std::move(update->user_)); break; } case td_api::updateUserFullInfo::ID: { @@ -4410,7 +4411,8 @@ void Client::on_update(object_ptr result) { } case td_api::updateBasicGroup::ID: { auto update = move_object_as(result); - add_group(groups_, std::move(update->basic_group_)); + auto *group_info = add_group_info(update->basic_group_->id_); + add_group(group_info, std::move(update->basic_group_)); break; } case td_api::updateBasicGroupFullInfo::ID: { @@ -4425,7 +4427,8 @@ void Client::on_update(object_ptr result) { } case td_api::updateSupergroup::ID: { auto update = move_object_as(result); - add_supergroup(supergroups_, std::move(update->supergroup_)); + auto *supergroup_info = add_supergroup_info(update->supergroup_->id_); + add_supergroup(supergroup_info, std::move(update->supergroup_)); break; } case td_api::updateSupergroupFullInfo::ID: { @@ -6392,7 +6395,7 @@ void Client::on_message_send_succeeded(object_ptr &&message, in auto query_id = extract_yet_unsent_message_query_id(chat_id, old_message_id, &message_info->is_reply_to_message_deleted); - auto &query = pending_send_message_queries_[query_id]; + auto &query = *pending_send_message_queries_[query_id]; if (query.is_multisend) { query.messages.push_back(td::json_encode(JsonMessage(message_info, true, "sent message", this))); query.awaited_message_count--; @@ -6420,7 +6423,7 @@ void Client::on_message_send_failed(int64 chat_id, int64 old_message_id, int64 n auto error = make_object(result.code(), result.message().str()); auto query_id = extract_yet_unsent_message_query_id(chat_id, old_message_id, nullptr); - auto &query = pending_send_message_queries_[query_id]; + auto &query = *pending_send_message_queries_[query_id]; if (query.is_multisend) { if (query.error == nullptr) { query.error = std::move(error); @@ -8253,8 +8256,10 @@ void Client::do_send_message(object_ptr input_messa td::int64 Client::get_send_message_query_id(PromisedQueryPtr query, bool is_multisend) { auto query_id = current_send_message_query_id_++; auto &pending_query = pending_send_message_queries_[query_id]; - pending_query.query = std::move(query); - pending_query.is_multisend = is_multisend; + CHECK(pending_query == nullptr); + pending_query = td::make_unique(); + pending_query->query = std::move(query); + pending_query->is_multisend = is_multisend; return query_id; } @@ -8276,7 +8281,7 @@ void Client::on_sent_message(object_ptr &&message, int64 query_ auto emplace_result = yet_unsent_messages_.emplace(yet_unsent_message_id, yet_unsent_message); CHECK(emplace_result.second); yet_unsent_message_count_[chat_id]++; - pending_send_message_queries_[query_id].awaited_message_count++; + pending_send_message_queries_[query_id]->awaited_message_count++; } void Client::abort_long_poll(bool from_set_webhook) { @@ -8442,8 +8447,7 @@ void Client::long_poll_wakeup(bool force_flag) { } } -void Client::add_user(std::unordered_map &users, object_ptr &&user) { - auto user_info = &users[user->id_]; +void Client::add_user(UserInfo *user_info, object_ptr &&user) { user_info->first_name = std::move(user->first_name_); user_info->last_name = std::move(user->last_name_); user_info->username = std::move(user->username_); @@ -8475,23 +8479,31 @@ void Client::add_user(std::unordered_map &users, object_ptrsecond; + if (emplace_result.second) { + user_info = td::make_unique(); + } else { + CHECK(user_info != nullptr); + } + return user_info.get(); +} + const Client::UserInfo *Client::get_user_info(int64 user_id) const { auto it = users_.find(user_id); - return it == users_.end() ? nullptr : &it->second; + return it == users_.end() ? nullptr : it->second.get(); } void Client::set_user_bio(int64 user_id, td::string &&bio) { - auto user_info = &users_[user_id]; - user_info->bio = std::move(bio); + add_user_info(user_id)->bio = std::move(bio); } void Client::set_user_has_private_forwards(int64 user_id, bool has_private_forwards) { - auto user_info = &users_[user_id]; - user_info->has_private_forwards = has_private_forwards; + add_user_info(user_id)->has_private_forwards = has_private_forwards; } -void Client::add_group(std::unordered_map &groups, object_ptr &&group) { - auto group_info = &groups[group->id_]; +void Client::add_group(GroupInfo *group_info, object_ptr &&group) { group_info->member_count = group->member_count_; group_info->left = group->status_->get_id() == td_api::chatMemberStatusLeft::ID; group_info->kicked = group->status_->get_id() == td_api::chatMemberStatusBanned::ID; @@ -8502,24 +8514,31 @@ void Client::add_group(std::unordered_map &groups, object_ptr< } } +Client::GroupInfo *Client::add_group_info(int64 group_id) { + auto emplace_result = groups_.emplace(group_id, nullptr); + auto &group_info = emplace_result.first->second; + if (emplace_result.second) { + group_info = td::make_unique(); + } else { + CHECK(group_info != nullptr); + } + return group_info.get(); +} + const Client::GroupInfo *Client::get_group_info(int64 group_id) const { auto it = groups_.find(group_id); - return it == groups_.end() ? nullptr : &it->second; + return it == groups_.end() ? nullptr : it->second.get(); } void Client::set_group_description(int64 group_id, td::string &&descripton) { - auto group_info = &groups_[group_id]; - group_info->description = std::move(descripton); + add_group_info(group_id)->description = std::move(descripton); } void Client::set_group_invite_link(int64 group_id, td::string &&invite_link) { - auto group_info = &groups_[group_id]; - group_info->invite_link = std::move(invite_link); + add_group_info(group_id)->invite_link = std::move(invite_link); } -void Client::add_supergroup(std::unordered_map &supergroups, - object_ptr &&supergroup) { - auto supergroup_info = &supergroups[supergroup->id_]; +void Client::add_supergroup(SupergroupInfo *supergroup_info, object_ptr &&supergroup) { supergroup_info->username = std::move(supergroup->username_); supergroup_info->date = supergroup->date_; supergroup_info->status = std::move(supergroup->status_); @@ -8528,48 +8547,59 @@ void Client::add_supergroup(std::unordered_map &supergrou } void Client::set_supergroup_description(int64 supergroup_id, td::string &&descripton) { - auto supergroup_info = &supergroups_[supergroup_id]; - supergroup_info->description = std::move(descripton); + add_supergroup_info(supergroup_id)->description = std::move(descripton); } void Client::set_supergroup_invite_link(int64 supergroup_id, td::string &&invite_link) { - auto supergroup_info = &supergroups_[supergroup_id]; - supergroup_info->invite_link = std::move(invite_link); + add_supergroup_info(supergroup_id)->invite_link = std::move(invite_link); } void Client::set_supergroup_sticker_set_id(int64 supergroup_id, int64 sticker_set_id) { - auto supergroup_info = &supergroups_[supergroup_id]; - supergroup_info->sticker_set_id = sticker_set_id; + add_supergroup_info(supergroup_id)->sticker_set_id = sticker_set_id; } void Client::set_supergroup_can_set_sticker_set(int64 supergroup_id, bool can_set_sticker_set) { - auto supergroup_info = &supergroups_[supergroup_id]; - supergroup_info->can_set_sticker_set = can_set_sticker_set; + add_supergroup_info(supergroup_id)->can_set_sticker_set = can_set_sticker_set; } void Client::set_supergroup_slow_mode_delay(int64 supergroup_id, int32 slow_mode_delay) { - auto supergroup_info = &supergroups_[supergroup_id]; - supergroup_info->slow_mode_delay = slow_mode_delay; + add_supergroup_info(supergroup_id)->slow_mode_delay = slow_mode_delay; } void Client::set_supergroup_linked_chat_id(int64 supergroup_id, int64 linked_chat_id) { - auto supergroup_info = &supergroups_[supergroup_id]; - supergroup_info->linked_chat_id = linked_chat_id; + add_supergroup_info(supergroup_id)->linked_chat_id = linked_chat_id; } void Client::set_supergroup_location(int64 supergroup_id, object_ptr location) { - auto supergroup_info = &supergroups_[supergroup_id]; - supergroup_info->location = std::move(location); + add_supergroup_info(supergroup_id)->location = std::move(location); +} + +Client::SupergroupInfo *Client::add_supergroup_info(int64 supergroup_id) { + auto emplace_result = supergroups_.emplace(supergroup_id, nullptr); + auto &supergroup_info = emplace_result.first->second; + if (emplace_result.second) { + supergroup_info = td::make_unique(); + } else { + CHECK(supergroup_info != nullptr); + } + return supergroup_info.get(); } const Client::SupergroupInfo *Client::get_supergroup_info(int64 supergroup_id) const { auto it = supergroups_.find(supergroup_id); - return it == supergroups_.end() ? nullptr : &it->second; + return it == supergroups_.end() ? nullptr : it->second.get(); } Client::ChatInfo *Client::add_chat(int64 chat_id) { LOG(DEBUG) << "Update chat " << chat_id; - return &chats_[chat_id]; + auto emplace_result = chats_.emplace(chat_id, nullptr); + auto &chat_info = emplace_result.first->second; + if (emplace_result.second) { + chat_info = td::make_unique(); + } else { + CHECK(chat_info != nullptr); + } + return chat_info.get(); } const Client::ChatInfo *Client::get_chat(int64 chat_id) const { @@ -8577,7 +8607,7 @@ const Client::ChatInfo *Client::get_chat(int64 chat_id) const { if (it == chats_.end()) { return nullptr; } - return &it->second; + return it->second.get(); } Client::ChatType Client::get_chat_type(int64 chat_id) const { @@ -8879,10 +8909,7 @@ void Client::add_new_message(object_ptr &&message, bool is_edit } auto chat_id = message->chat_id_; - if (chat_id == 0) { - LOG(ERROR) << "Receive invalid chat in " << to_string(message); - return; - } + CHECK(chat_id != 0); new_message_queues_[chat_id].queue_.emplace(std::move(message), is_edited); process_new_message_queue(chat_id); } @@ -8916,10 +8943,7 @@ void Client::add_new_chosen_inline_result(int64 sender_user_id, object_ptr &&query) { CHECK(query != nullptr); auto user_id = query->sender_user_id_; - if (user_id == 0) { - LOG(ERROR) << "Receive invalid sender in " << to_string(query); - return; - } + CHECK(user_id != 0); new_callback_query_queues_[user_id].queue_.push(std::move(query)); process_new_callback_query_queue(user_id, 0); } @@ -9806,6 +9830,6 @@ constexpr Client::Slice Client::API_ID_INVALID_ERROR_DESCRIPTION; constexpr int Client::CLOSING_ERROR_CODE; constexpr Client::Slice Client::CLOSING_ERROR_DESCRIPTION; -std::unordered_map Client::methods_; +td::FlatHashMap Client::methods_; } // namespace telegram_bot_api diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index caefd33..0e8c116 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -19,6 +19,8 @@ #include "td/utils/common.h" #include "td/utils/Container.h" +#include "td/utils/FlatHashMap.h" +#include "td/utils/FlatHashSet.h" #include "td/utils/JsonBuilder.h" #include "td/utils/Slice.h" #include "td/utils/Status.h" @@ -27,8 +29,6 @@ #include #include #include -#include -#include namespace telegram_bot_api { @@ -588,9 +588,10 @@ class Client final : public WebhookActor::Callback { bool is_inline_bot = false; bool has_private_forwards = false; }; - static void add_user(std::unordered_map &users, object_ptr &&user); + static void add_user(UserInfo *user_info, object_ptr &&user); void set_user_bio(int64 user_id, td::string &&bio); void set_user_has_private_forwards(int64 user_id, bool has_private_forwards); + UserInfo *add_user_info(int64 user_id); const UserInfo *get_user_info(int64 user_id) const; struct GroupInfo { @@ -602,9 +603,10 @@ class Client final : public WebhookActor::Callback { bool is_active = false; int64 upgraded_to_supergroup_id = 0; }; - static void add_group(std::unordered_map &groups, object_ptr &&group); + static void add_group(GroupInfo *group_info, object_ptr &&group); void set_group_description(int64 group_id, td::string &&descripton); void set_group_invite_link(int64 group_id, td::string &&invite_link); + GroupInfo *add_group_info(int64 group_id); const GroupInfo *get_group_info(int64 group_id) const; struct SupergroupInfo { @@ -621,8 +623,7 @@ class Client final : public WebhookActor::Callback { bool can_set_sticker_set = false; bool has_location = false; }; - static void add_supergroup(std::unordered_map &supergroups, - object_ptr &&supergroup); + static void add_supergroup(SupergroupInfo *supergroup_info, object_ptr &&supergroup); void set_supergroup_description(int64 supergroup_id, td::string &&descripton); void set_supergroup_invite_link(int64 supergroup_id, td::string &&invite_link); void set_supergroup_sticker_set_id(int64 supergroup_id, int64 sticker_set_id); @@ -630,6 +631,7 @@ class Client final : public WebhookActor::Callback { void set_supergroup_slow_mode_delay(int64 supergroup_id, int32 slow_mode_delay); void set_supergroup_linked_chat_id(int64 supergroup_id, int64 linked_chat_id); void set_supergroup_location(int64 supergroup_id, object_ptr location); + SupergroupInfo *add_supergroup_info(int64 supergroup_id); const SupergroupInfo *get_supergroup_info(int64 supergroup_id) const; struct ChatInfo { @@ -861,30 +863,30 @@ class Client final : public WebhookActor::Callback { int64 channel_bot_user_id_ = 0; int64 service_notifications_user_id_ = 0; - static std::unordered_map methods_; + static td::FlatHashMap methods_; - std::unordered_map, FullMessageIdHash> messages_; // message cache - std::unordered_map users_; // user info cache - std::unordered_map groups_; // group info cache - std::unordered_map supergroups_; // supergroup info cache - std::unordered_map chats_; // chat info cache + td::FlatHashMap, FullMessageIdHash> messages_; // message cache + td::FlatHashMap> users_; // user info cache + td::FlatHashMap> groups_; // group info cache + td::FlatHashMap> supergroups_; // supergroup info cache + td::FlatHashMap> chats_; // chat info cache - std::unordered_map, FullMessageIdHash> + td::FlatHashMap, FullMessageIdHash> reply_message_ids_; // message -> replies to it - std::unordered_map, FullMessageIdHash> + td::FlatHashMap, FullMessageIdHash> yet_unsent_reply_message_ids_; // message -> replies to it - std::unordered_map> file_download_listeners_; - std::unordered_set download_started_file_ids_; + td::FlatHashMap> file_download_listeners_; + td::FlatHashSet download_started_file_ids_; struct YetUnsentMessage { int64 reply_to_message_id = 0; bool is_reply_to_message_deleted = false; int64 send_message_query_id = 0; }; - std::unordered_map yet_unsent_messages_; + td::FlatHashMap yet_unsent_messages_; - std::unordered_map yet_unsent_message_count_; + td::FlatHashMap yet_unsent_message_count_; // chat_id -> count struct PendingSendMessageQuery { PromisedQueryPtr query; @@ -893,7 +895,7 @@ class Client final : public WebhookActor::Callback { td::vector messages; object_ptr error; }; - std::unordered_map + td::FlatHashMap> pending_send_message_queries_; // query_id -> PendingSendMessageQuery int64 current_send_message_query_id_ = 1; @@ -909,28 +911,28 @@ class Client final : public WebhookActor::Callback { std::queue queue_; bool has_active_request_ = false; }; - std::unordered_map new_message_queues_; // chat_id -> queue + td::FlatHashMap new_message_queues_; // chat_id -> queue struct NewCallbackQueryQueue { std::queue> queue_; bool has_active_request_ = false; }; - std::unordered_map new_callback_query_queues_; // sender_user_id -> queue + td::FlatHashMap new_callback_query_queues_; // sender_user_id -> queue - std::unordered_map sticker_set_names_; + td::FlatHashMap sticker_set_names_; int64 cur_temp_bot_user_id_ = 1; - std::unordered_map bot_user_ids_; - std::unordered_set unresolved_bot_usernames_; - std::unordered_map temp_to_real_bot_user_id_; - std::unordered_map> awaiting_bot_resolve_queries_; + td::FlatHashMap bot_user_ids_; + td::FlatHashSet unresolved_bot_usernames_; + td::FlatHashMap temp_to_real_bot_user_id_; + td::FlatHashMap> awaiting_bot_resolve_queries_; struct PendingBotResolveQuery { std::size_t pending_resolve_count = 0; PromisedQueryPtr query; td::Promise on_success; }; - std::unordered_map pending_bot_resolve_queries_; + td::FlatHashMap pending_bot_resolve_queries_; int64 current_bot_resolve_query_id_ = 1; td::string dir_; diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index f0f023d..0630f21 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -71,9 +71,13 @@ void ClientManager::send(PromisedQueryPtr query) { return fail_query(401, "Unauthorized: invalid token specified", std::move(query)); } auto r_user_id = td::to_integer_safe(query->token().substr(0, token.find(':'))); - if (r_user_id.is_error() || r_user_id.ok() < 0 || !token_range_(r_user_id.ok())) { + if (r_user_id.is_error() || !token_range_(r_user_id.ok())) { return fail_query(421, "Misdirected Request: unallowed token specified", std::move(query)); } + auto user_id = r_user_id.ok(); + if (user_id <= 0 || user_id >= (static_cast(1) << 54)) { + return fail_query(401, "Unauthorized: invalid token specified", std::move(query)); + } if (query->is_test_dc()) { token += "/test"; @@ -113,7 +117,7 @@ void ClientManager::send(PromisedQueryPtr query) { } flood_control.add_event(static_cast(now)); } - auto tqueue_id = get_tqueue_id(r_user_id.ok(), query->is_test_dc()); + auto tqueue_id = get_tqueue_id(user_id, query->is_test_dc()); if (active_client_count_.find(tqueue_id) != active_client_count_.end()) { // return query->set_retry_after_error(1); } @@ -392,6 +396,7 @@ void ClientManager::raw_event(const td::Event::Raw &event) { auto id = get_link_token(); auto *info = clients_.get(id); CHECK(info != nullptr); + CHECK(info->tqueue_id_ != 0); auto &value = active_client_count_[info->tqueue_id_]; if (event.ptr != nullptr) { value++; diff --git a/telegram-bot-api/ClientManager.h b/telegram-bot-api/ClientManager.h index 5720d98..1dcc093 100644 --- a/telegram-bot-api/ClientManager.h +++ b/telegram-bot-api/ClientManager.h @@ -16,11 +16,11 @@ #include "td/utils/buffer.h" #include "td/utils/common.h" #include "td/utils/Container.h" +#include "td/utils/FlatHashMap.h" #include "td/utils/FloodControlFast.h" #include "td/utils/Slice.h" #include -#include #include namespace telegram_bot_api { @@ -61,9 +61,9 @@ class ClientManager final : public td::Actor { std::shared_ptr parameters_; TokenRange token_range_; - std::unordered_map token_to_id_; - std::unordered_map flood_controls_; - std::unordered_map active_client_count_; + td::FlatHashMap token_to_id_; + td::FlatHashMap flood_controls_; + td::FlatHashMap active_client_count_; bool close_flag_ = false; td::vector> close_promises_; diff --git a/telegram-bot-api/Query.cpp b/telegram-bot-api/Query.cpp index 41c66dd..d8fb3b9 100644 --- a/telegram-bot-api/Query.cpp +++ b/telegram-bot-api/Query.cpp @@ -21,7 +21,7 @@ namespace telegram_bot_api { -std::unordered_map> empty_parameters; +td::FlatHashMap> empty_parameters; Query::Query(td::vector &&container, td::Slice token, bool is_test_dc, td::MutableSlice method, td::vector> &&args, @@ -96,7 +96,7 @@ void Query::set_error(int http_status_code, td::BufferSlice result) { void Query::set_retry_after_error(int retry_after) { retry_after_ = retry_after; - std::unordered_map> parameters; + td::FlatHashMap> parameters; parameters.emplace("retry_after", std::make_unique(retry_after)); set_error(429, td::json_encode( JsonQueryError(429, PSLICE() << "Too Many Requests: retry after " << retry_after, parameters))); diff --git a/telegram-bot-api/Query.h b/telegram-bot-api/Query.h index f5d15f8..ed40911 100644 --- a/telegram-bot-api/Query.h +++ b/telegram-bot-api/Query.h @@ -15,6 +15,7 @@ #include "td/utils/buffer.h" #include "td/utils/common.h" +#include "td/utils/FlatHashMap.h" #include "td/utils/JsonBuilder.h" #include "td/utils/List.h" #include "td/utils/port/IPAddress.h" @@ -23,7 +24,6 @@ #include #include -#include #include namespace telegram_bot_api { @@ -164,11 +164,11 @@ td::StringBuilder &operator<<(td::StringBuilder &sb, const Query &query); // fix for outdated C++14 libraries // https://stackoverflow.com/questions/26947704/implicit-conversion-failure-from-initializer-list -extern std::unordered_map> empty_parameters; +extern td::FlatHashMap> empty_parameters; class JsonParameters final : public td::Jsonable { public: - explicit JsonParameters(const std::unordered_map> ¶meters) + explicit JsonParameters(const td::FlatHashMap> ¶meters) : parameters_(parameters) { } void store(td::JsonValueScope *scope) const { @@ -180,7 +180,7 @@ class JsonParameters final : public td::Jsonable { } private: - const std::unordered_map> ¶meters_; + const td::FlatHashMap> ¶meters_; }; template @@ -206,7 +206,7 @@ class JsonQueryError final : public td::Jsonable { public: JsonQueryError( int error_code, td::Slice description, - const std::unordered_map> ¶meters = empty_parameters) + const td::FlatHashMap> ¶meters = empty_parameters) : error_code_(error_code), description_(description), parameters_(parameters) { } void store(td::JsonValueScope *scope) const { @@ -222,7 +222,7 @@ class JsonQueryError final : public td::Jsonable { private: int error_code_; td::Slice description_; - const std::unordered_map> ¶meters_; + const td::FlatHashMap> ¶meters_; }; class PromiseDeleter { @@ -261,7 +261,7 @@ void answer_query(const Jsonable &result, PromisedQueryPtr query, td::Slice desc inline void fail_query( int http_status_code, td::Slice description, PromisedQueryPtr query, - const std::unordered_map> ¶meters = empty_parameters) { + const td::FlatHashMap> ¶meters = empty_parameters) { query->set_error(http_status_code, td::json_encode(JsonQueryError(http_status_code, description, parameters))); query.reset(); // send query into promise explicitly diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index bfab715..14df122 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -379,11 +379,14 @@ void WebhookActor::load_updates() { for (auto &update : updates) { VLOG(webhook) << "Load update " << update.id; - if (update_map_.find(update.id) != update_map_.end()) { - LOG(ERROR) << "Receive duplicated event " << update.id << " from tqueue"; + CHECK(update.id.is_valid()); + auto &dest_ptr = update_map_[update.id]; + if (dest_ptr != nullptr) { + LOG(ERROR) << "Receive duplicated event " << update.id << " from TQueue"; continue; } - auto &dest = update_map_[update.id]; + dest_ptr = td::make_unique(); + auto &dest = *dest_ptr; dest.id_ = update.id; dest.json_ = update.data.str(); dest.delay_ = 1; @@ -437,7 +440,7 @@ void WebhookActor::load_updates() { void WebhookActor::drop_event(td::TQueue::EventId event_id) { auto it = update_map_.find(event_id); CHECK(it != update_map_.end()); - auto queue_id = it->second.queue_id_; + auto queue_id = it->second->queue_id_; update_map_.erase(it); auto queue_updates_it = queue_updates_.find(queue_id); @@ -448,8 +451,10 @@ void WebhookActor::drop_event(td::TQueue::EventId event_id) { if (queue_updates_it->second.event_ids.empty()) { queue_updates_.erase(queue_updates_it); } else { - auto &update = update_map_[queue_updates_it->second.event_ids.front()]; - queues_.emplace(update.wakeup_at_, update.queue_id_); + auto update_id = queue_updates_it->second.event_ids.front(); + CHECK(update_id.is_valid()); + auto &update = update_map_[update_id]; + queues_.emplace(update->wakeup_at_, update->queue_id_); } parameters_->shared_data_->tqueue_->forget(tqueue_id_, event_id); @@ -462,7 +467,7 @@ void WebhookActor::on_update_ok(td::TQueue::EventId event_id) { auto it = update_map_.find(event_id); CHECK(it != update_map_.end()); - VLOG(webhook) << "Receive ok for update " << event_id << " in " << (last_success_time_ - it->second.last_send_time_) + VLOG(webhook) << "Receive ok for update " << event_id << " in " << (last_success_time_ - it->second->last_send_time_) << " seconds"; drop_event(event_id); @@ -474,21 +479,22 @@ void WebhookActor::on_update_error(td::TQueue::EventId event_id, td::Slice error auto it = update_map_.find(event_id); CHECK(it != update_map_.end()); + CHECK(it->second != nullptr); + auto &update = *it->second; const int MAX_RETRY_AFTER = 3600; retry_after = td::clamp(retry_after, 0, MAX_RETRY_AFTER); - int next_delay = it->second.delay_; + int next_delay = update.delay_; int next_effective_delay = retry_after; - if (retry_after == 0 && it->second.fail_count_ > 0) { + if (retry_after == 0 && update.fail_count_ > 0) { next_delay = td::min(WEBHOOK_MAX_RESEND_TIMEOUT, next_delay * 2); next_effective_delay = next_delay; } - if (parameters_->shared_data_->get_unix_time(now) + next_effective_delay > it->second.expires_at_) { + if (parameters_->shared_data_->get_unix_time(now) + next_effective_delay > update.expires_at_) { LOG(WARNING) << "Drop update " << event_id << ": " << error; drop_event(event_id); return; } - auto &update = it->second; update.delay_ = next_delay; update.wakeup_at_ = now + next_effective_delay; update.fail_count_++; @@ -514,10 +520,15 @@ td::Status WebhookActor::send_update() { } auto queue_id = it->id; + CHECK(queue_id != 0); queues_.erase(it); auto event_id = queue_updates_[queue_id].event_ids.front(); + CHECK(event_id.is_valid()); - auto &update = update_map_[event_id]; + auto update_map_it = update_map_.find(event_id); + CHECK(update_map_it != update_map_.end()); + CHECK(update_map_it->second != nullptr); + auto &update = *update_map_it->second; update.last_send_time_ = now; auto body = td::json_encode(JsonUpdate(update.id_.value(), update.json_)); diff --git a/telegram-bot-api/WebhookActor.h b/telegram-bot-api/WebhookActor.h index 6067d73..71d702e 100644 --- a/telegram-bot-api/WebhookActor.h +++ b/telegram-bot-api/WebhookActor.h @@ -20,6 +20,7 @@ #include "td/utils/BufferedFd.h" #include "td/utils/common.h" #include "td/utils/Container.h" +#include "td/utils/FlatHashMap.h" #include "td/utils/FloodControlFast.h" #include "td/utils/HttpUrl.h" #include "td/utils/JsonBuilder.h" @@ -35,7 +36,6 @@ #include #include #include -#include namespace telegram_bot_api { @@ -127,8 +127,8 @@ class WebhookActor final : public td::HttpOutboundConnection::Callback { return std::hash()(event_id.value()); } }; - std::unordered_map update_map_; - std::unordered_map queue_updates_; + td::FlatHashMap, EventIdHash> update_map_; + td::FlatHashMap queue_updates_; std::set queues_; td::int64 unique_queue_id_ = static_cast(1) << 60; From 4925532c2577b8172e5d69ea71678c5d213a1f89 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 16 Mar 2022 12:52:34 +0300 Subject: [PATCH 03/17] Use td::unique_ptr instead of std::unique_ptr. --- telegram-bot-api/Client.cpp | 244 +++++++++++++------------- telegram-bot-api/Client.h | 16 +- telegram-bot-api/ClientManager.cpp | 8 +- telegram-bot-api/HttpConnection.cpp | 6 +- telegram-bot-api/Query.cpp | 6 +- telegram-bot-api/Query.h | 12 +- telegram-bot-api/WebhookActor.cpp | 8 +- telegram-bot-api/telegram-bot-api.cpp | 4 +- 8 files changed, 152 insertions(+), 152 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 025fce3..91bd7df 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3180,7 +3180,7 @@ class Client::TdOnGetChatPinnedMessageCallback final : public TdQueryCallback { if (sticker_set_id != 0 && client_->get_sticker_set_name(sticker_set_id).empty()) { return client_->send_request( make_object(sticker_set_id), - std::make_unique(client_, chat_id_, pinned_message_id, std::move(query_))); + td::make_unique(client_, chat_id_, pinned_message_id, std::move(query_))); } } @@ -3217,7 +3217,7 @@ class Client::TdOnGetChatPinnedMessageToUnpinCallback final : public TdQueryCall CHECK(pinned_message_id > 0); client_->send_request(make_object(chat_id_, pinned_message_id), - std::make_unique(std::move(query_))); + td::make_unique(std::move(query_))); } private: @@ -3260,7 +3260,7 @@ class Client::TdOnGetChatFullInfoCallback final : public TdQueryCallback { // we don't need the result, everything is already received through updates client_->send_request(make_object(chat_id_), - std::make_unique(client_, chat_id_, std::move(query_))); + td::make_unique(client_, chat_id_, std::move(query_))); } private: @@ -3473,14 +3473,14 @@ void Client::close() { if (td_client_.empty()) { set_timeout_in(0); } else if (!closing_) { - do_send_request(make_object(), std::make_unique()); + do_send_request(make_object(), td::make_unique()); } } void Client::log_out(bool is_api_id_invalid) { is_api_id_invalid_ |= is_api_id_invalid; if (!td_client_.empty() && !logging_out_ && !closing_) { - do_send_request(make_object(), std::make_unique()); + do_send_request(make_object(), td::make_unique()); } } @@ -3718,7 +3718,7 @@ void Client::check_user(int64 user_id, PromisedQueryPtr query, OnSuccess on_succ return check_user_read_access(user_info, std::move(query), std::move(on_success)); } send_request(make_object(user_id), - std::make_unique>(this, std::move(query), std::move(on_success))); + td::make_unique>(this, std::move(query), std::move(on_success))); } template @@ -3729,7 +3729,7 @@ void Client::check_user_no_fail(int64 user_id, PromisedQueryPtr query, OnSuccess return; } send_request(make_object(user_id), - std::make_unique>(std::move(query), std::move(on_success))); + td::make_unique>(std::move(query), std::move(on_success))); } template @@ -3760,9 +3760,9 @@ void Client::check_chat_access(int64 chat_id, AccessRights access_rights, const CHECK(group_info != nullptr); if (!group_info->is_active && need_write_access) { if (group_info->upgraded_to_supergroup_id != 0) { - td::FlatHashMap> parameters; + td::FlatHashMap> parameters; auto updagraded_to_chat_id = get_supergroup_chat_id(group_info->upgraded_to_supergroup_id); - parameters.emplace("migrate_to_chat_id", std::make_unique(updagraded_to_chat_id)); + parameters.emplace("migrate_to_chat_id", td::make_unique(updagraded_to_chat_id)); return fail_query(400, "Bad Request: group chat was upgraded to a supergroup chat", std::move(query), std::move(parameters)); } else { @@ -3813,8 +3813,8 @@ void Client::check_chat(Slice chat_id_str, AccessRights access_rights, PromisedQ if (chat_id_str[0] == '@') { return send_request(make_object(chat_id_str.str()), - std::make_unique>(this, true, access_rights, std::move(query), - std::move(on_success))); + td::make_unique>(this, true, access_rights, std::move(query), + std::move(on_success))); } auto chat_id = td::to_integer(chat_id_str); @@ -3823,8 +3823,8 @@ void Client::check_chat(Slice chat_id_str, AccessRights access_rights, PromisedQ return check_chat_access(chat_id, access_rights, chat_info, std::move(query), std::move(on_success)); } send_request(make_object(chat_id), - std::make_unique>(this, false, access_rights, std::move(query), - std::move(on_success))); + td::make_unique>(this, false, access_rights, std::move(query), + std::move(on_success))); } template @@ -3843,7 +3843,7 @@ void Client::check_chat_no_fail(Slice chat_id_str, PromisedQueryPtr query, OnSuc if (chat_info != nullptr) { return on_success(chat_id, std::move(query)); } - send_request(make_object(chat_id), std::make_unique>( + send_request(make_object(chat_id), td::make_unique>( chat_id, std::move(query), std::move(on_success))); } @@ -3884,7 +3884,7 @@ void Client::check_remote_file_id(td::string file_id, PromisedQueryPtr query, On } send_request(make_object(std::move(file_id), nullptr), - std::make_unique>(std::move(query), std::move(on_success))); + td::make_unique>(std::move(query), std::move(on_success))); } bool Client::is_chat_member(const object_ptr &status) { @@ -3937,7 +3937,7 @@ void Client::check_message(Slice chat_id_str, int64 message_id, bool allow_empty send_request( make_object(chat_id, message_id), - std::make_unique>( + td::make_unique>( this, chat_id, message_id, allow_empty, message_type, std::move(query), std::move(on_success))); }); } @@ -3949,7 +3949,7 @@ void Client::resolve_sticker_set(const td::string &sticker_set_name, PromisedQue } send_request(make_object(sticker_set_name), - std::make_unique>(std::move(query), std::move(on_success))); + td::make_unique>(std::move(query), std::move(on_success))); } void Client::fix_reply_markup_bot_user_ids(object_ptr &reply_markup) const { @@ -4001,7 +4001,7 @@ void Client::resolve_bot_usernames(PromisedQueryPtr query, td::Promise(username), - std::make_unique(this, username)); + td::make_unique(this, username)); } } unresolved_bot_usernames_.clear(); @@ -4084,11 +4084,11 @@ void Client::get_chat_member(int64 chat_id, int64 user_id, PromisedQueryPtr quer [this, chat_id, user_id, on_success = std::move(on_success)](PromisedQueryPtr query) mutable { send_request( make_object(chat_id, td_api::make_object(user_id)), - std::make_unique>(std::move(query), std::move(on_success))); + td::make_unique>(std::move(query), std::move(on_success))); }); } -void Client::send_request(object_ptr &&f, std::unique_ptr handler) { +void Client::send_request(object_ptr &&f, td::unique_ptr handler) { if (logging_out_) { return handler->on_result( make_object(LOGGING_OUT_ERROR_CODE, get_logging_out_error_description().str())); @@ -4100,7 +4100,7 @@ void Client::send_request(object_ptr &&f, std::unique_ptr &&f, std::unique_ptr handler) { +void Client::do_send_request(object_ptr &&f, td::unique_ptr handler) { CHECK(!td_client_.empty()); auto id = handlers_.create(std::move(handler)); send_closure(td_client_, &td::ClientActor::request, id, std::move(f)); @@ -4118,7 +4118,7 @@ void Client::on_update_file(object_ptr file) { if (!parameters_->local_mode_ && file->local_->downloaded_size_ > MAX_DOWNLOAD_FILE_SIZE) { if (file->local_->is_downloading_active_) { send_request(make_object(file_id, false), - std::make_unique()); + td::make_unique()); } return on_file_download(file_id, Status::Error(400, "Bad Request: file is too big")); } @@ -4144,16 +4144,16 @@ void Client::on_update_authorization_state() { case td_api::authorizationStateWaitTdlibParameters::ID: { send_request( make_object("ignore_inline_thumbnails", make_object(true)), - std::make_unique()); + td::make_unique()); send_request(make_object("reuse_uploaded_photos_by_hash", make_object(true)), - std::make_unique()); + td::make_unique()); send_request(make_object("disable_persistent_network_statistics", make_object(true)), - std::make_unique()); + td::make_unique()); send_request(make_object("disable_time_adjustment_protection", make_object(true)), - std::make_unique()); + td::make_unique()); auto parameters = make_object(); @@ -4172,20 +4172,20 @@ void Client::on_update_authorization_state() { parameters->ignore_file_names_ = true; return send_request(make_object(std::move(parameters)), - std::make_unique(this)); + td::make_unique(this)); } case td_api::authorizationStateWaitEncryptionKey::ID: - return send_request(make_object(), std::make_unique(this)); + return send_request(make_object(), td::make_unique(this)); case td_api::authorizationStateWaitPhoneNumber::ID: send_request(make_object("online", make_object(true)), - std::make_unique()); + td::make_unique()); return send_request(make_object(bot_token_), - std::make_unique(this)); + td::make_unique(this)); case td_api::authorizationStateReady::ID: { auto user_info = get_user_info(my_id_); if (my_id_ <= 0 || user_info == nullptr) { LOG(INFO) << "Send getMe request for " << my_id_; - return send_request(make_object(), std::make_unique(this)); + return send_request(make_object(), td::make_unique(this)); } if (!was_authorized_) { @@ -4291,7 +4291,7 @@ void Client::on_update(object_ptr result) { auto message_id = update->message_id_; on_update_message_edited(chat_id, message_id, update->edit_date_, std::move(update->reply_markup_)); send_request(make_object(chat_id, message_id), - std::make_unique(this)); + td::make_unique(this)); break; } case td_api::updateDeleteMessages::ID: { @@ -4311,7 +4311,7 @@ void Client::on_update(object_ptr result) { auto generation_id = update->generation_id_; send_request( make_object(generation_id, make_object(400, "Wrong file_id")), - std::make_unique()); + td::make_unique()); break; } case td_api::updateNewChat::ID: { @@ -6442,7 +6442,7 @@ void Client::on_message_send_failed(int64 chat_id, int64 old_message_id, int64 n if (new_message_id != 0 && !logging_out_ && !closing_) { send_request(make_object(chat_id, td::vector{new_message_id}, false), - std::make_unique(this, chat_id, new_message_id)); + td::make_unique(this, chat_id, new_message_id)); } } @@ -6455,11 +6455,11 @@ void Client::on_cmd(PromisedQueryPtr query) { return query->set_retry_after_error(retry_after); } need_close_ = true; - return do_send_request(make_object(), std::make_unique(std::move(query))); + return do_send_request(make_object(), td::make_unique(std::move(query))); } if (query->method() == "logout") { clear_tqueue_ = true; - return do_send_request(make_object(), std::make_unique(std::move(query))); + return do_send_request(make_object(), td::make_unique(std::move(query))); } } @@ -6496,7 +6496,7 @@ td::Status Client::process_get_my_commands_query(PromisedQueryPtr &query) { [this](object_ptr &&scope, PromisedQueryPtr query) mutable { auto language_code = query->arg("language_code").str(); send_request(make_object(std::move(scope), language_code), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -6511,7 +6511,7 @@ td::Status Client::process_set_my_commands_query(PromisedQueryPtr &query) { PromisedQueryPtr query) mutable { auto language_code = query->arg("language_code").str(); send_request(make_object(std::move(scope), language_code, std::move(bot_commands)), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -6523,7 +6523,7 @@ td::Status Client::process_delete_my_commands_query(PromisedQueryPtr &query) { [this](object_ptr &&scope, PromisedQueryPtr query) mutable { auto language_code = query->arg("language_code").str(); send_request(make_object(std::move(scope), language_code), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -6535,7 +6535,7 @@ td::Status Client::process_get_user_profile_photos_query(PromisedQueryPtr &query check_user(user_id, std::move(query), [this, user_id, offset, limit](PromisedQueryPtr query) { send_request(make_object(user_id, offset, limit), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); return Status::OK(); } @@ -6838,7 +6838,7 @@ td::Status Client::process_stop_poll_query(PromisedQueryPtr &query) { PromisedQueryPtr query) mutable { send_request( make_object(chat_id, message_id, std::move(reply_markup)), - std::make_unique(this, chat_id, message_id, std::move(query))); + td::make_unique(this, chat_id, message_id, std::move(query))); }); }); return Status::OK(); @@ -6903,7 +6903,7 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { make_object(chat_id, 0, reply_to_message_id, get_message_send_options(disable_notification, protect_content), std::move(input_message_contents), false), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }; check_message(chat_id, reply_to_message_id, reply_to_message_id <= 0 || allow_sending_without_reply, AccessRights::Write, "replied message", std::move(query), std::move(on_success)); @@ -6921,7 +6921,7 @@ td::Status Client::process_send_chat_action_query(PromisedQueryPtr &query) { check_chat(chat_id, AccessRights::Write, std::move(query), [this, action = std::move(action)](int64 chat_id, PromisedQueryPtr query) mutable { send_request(make_object(chat_id, 0, std::move(action)), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -6940,7 +6940,7 @@ td::Status Client::process_edit_message_text_query(PromisedQueryPtr &query) { object_ptr reply_markup, PromisedQueryPtr query) mutable { send_request(make_object(inline_message_id, std::move(reply_markup), std::move(input_message_text)), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); } else { resolve_reply_markup_bot_usernames( @@ -6953,7 +6953,7 @@ td::Status Client::process_edit_message_text_query(PromisedQueryPtr &query) { int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object(chat_id, message_id, std::move(reply_markup), std::move(input_message_text)), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); }); } @@ -6980,7 +6980,7 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu send_request( make_object(inline_message_id, std::move(reply_markup), std::move(location), heading, proximity_alert_radius), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); } else { resolve_reply_markup_bot_usernames( @@ -6994,7 +6994,7 @@ td::Status Client::process_edit_message_live_location_query(PromisedQueryPtr &qu send_request(make_object( chat_id, message_id, std::move(reply_markup), std::move(location), heading, proximity_alert_radius), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); }); } @@ -7015,7 +7015,7 @@ td::Status Client::process_edit_message_media_query(PromisedQueryPtr &query) { object_ptr reply_markup, PromisedQueryPtr query) mutable { send_request(make_object(inline_message_id, std::move(reply_markup), std::move(input_message_content)), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); } else { resolve_reply_markup_bot_usernames( @@ -7028,7 +7028,7 @@ td::Status Client::process_edit_message_media_query(PromisedQueryPtr &query) { int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object(chat_id, message_id, std::move(reply_markup), std::move(input_message_content)), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); }); } @@ -7049,7 +7049,7 @@ td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) { object_ptr reply_markup, PromisedQueryPtr query) mutable { send_request(make_object(inline_message_id, std::move(reply_markup), std::move(caption)), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); } else { resolve_reply_markup_bot_usernames( @@ -7061,7 +7061,7 @@ td::Status Client::process_edit_message_caption_query(PromisedQueryPtr &query) { int64 chat_id, int64 message_id, PromisedQueryPtr query) mutable { send_request(make_object( chat_id, message_id, std::move(reply_markup), std::move(caption)), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); }); } @@ -7080,7 +7080,7 @@ td::Status Client::process_edit_message_reply_markup_query(PromisedQueryPtr &que [this, inline_message_id = inline_message_id.str()](object_ptr reply_markup, PromisedQueryPtr query) { send_request(make_object(inline_message_id, std::move(reply_markup)), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); } else { resolve_reply_markup_bot_usernames( @@ -7092,7 +7092,7 @@ td::Status Client::process_edit_message_reply_markup_query(PromisedQueryPtr &que PromisedQueryPtr query) mutable { send_request( make_object(chat_id, message_id, std::move(reply_markup)), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); }); } @@ -7115,7 +7115,7 @@ td::Status Client::process_delete_message_query(PromisedQueryPtr &query) { [this](int64 chat_id, int64 message_id, PromisedQueryPtr query) { delete_message(chat_id, message_id, false); send_request(make_object(chat_id, td::vector{message_id}, true), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7140,7 +7140,7 @@ td::Status Client::process_set_game_score_query(PromisedQueryPtr &query) { [this, inline_message_id = inline_message_id.str(), edit_message, user_id, score, force](PromisedQueryPtr query) { send_request(make_object(inline_message_id, edit_message, user_id, score, force), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); } else { check_message(chat_id, message_id, false, AccessRights::Edit, "message to set game score", std::move(query), @@ -7150,7 +7150,7 @@ td::Status Client::process_set_game_score_query(PromisedQueryPtr &query) { [this, chat_id, message_id, user_id, score, force, edit_message](PromisedQueryPtr query) { send_request(make_object(chat_id, message_id, edit_message, user_id, score, force), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); }); } @@ -7167,7 +7167,7 @@ td::Status Client::process_get_game_high_scores_query(PromisedQueryPtr &query) { check_user_no_fail(user_id, std::move(query), [this, inline_message_id = inline_message_id.str(), user_id](PromisedQueryPtr query) { send_request(make_object(inline_message_id, user_id), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); } else { check_message(chat_id, message_id, false, AccessRights::Read, "message to get game high scores", std::move(query), @@ -7175,7 +7175,7 @@ td::Status Client::process_get_game_high_scores_query(PromisedQueryPtr &query) { check_user_no_fail( user_id, std::move(query), [this, chat_id, message_id, user_id](PromisedQueryPtr query) { send_request(make_object(chat_id, message_id, user_id), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); }); } @@ -7200,7 +7200,7 @@ td::Status Client::process_answer_inline_query_query(PromisedQueryPtr &query) { send_request( make_object(inline_query_id, is_personal, std::move(results), cache_time, next_offset, switch_pm_text, switch_pm_parameter), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7213,7 +7213,7 @@ td::Status Client::process_answer_callback_query_query(PromisedQueryPtr &query) int32 cache_time = get_integer_arg(query.get(), "cache_time", 0, 0, 24 * 30 * 60 * 60); send_request(make_object(callback_query_id, text, show_alert, url, cache_time), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); return Status::OK(); } @@ -7229,7 +7229,7 @@ td::Status Client::process_answer_shipping_query_query(PromisedQueryPtr &query) } send_request( make_object(shipping_query_id, std::move(shipping_options), error_message.str()), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); return Status::OK(); } @@ -7242,7 +7242,7 @@ td::Status Client::process_answer_pre_checkout_query_query(PromisedQueryPtr &que } send_request(make_object(pre_checkout_query_id, error_message.str()), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); return Status::OK(); } @@ -7251,7 +7251,7 @@ td::Status Client::process_export_chat_invite_link_query(PromisedQueryPtr &query check_chat(chat_id, AccessRights::Write, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7268,7 +7268,7 @@ td::Status Client::process_create_chat_invite_link_query(PromisedQueryPtr &query PromisedQueryPtr query) { send_request(make_object(chat_id, name, expire_date, member_limit, creates_join_request), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); return Status::OK(); } @@ -7286,7 +7286,7 @@ td::Status Client::process_edit_chat_invite_link_query(PromisedQueryPtr &query) creates_join_request](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id, invite_link, name, expire_date, member_limit, creates_join_request), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); return Status::OK(); } @@ -7298,7 +7298,7 @@ td::Status Client::process_revoke_chat_invite_link_query(PromisedQueryPtr &query check_chat(chat_id, AccessRights::Write, std::move(query), [this, invite_link = invite_link.str()](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id, invite_link), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); return Status::OK(); } @@ -7312,13 +7312,13 @@ td::Status Client::process_get_chat_query(PromisedQueryPtr &query) { switch (chat_info->type) { case ChatInfo::Type::Private: return send_request(make_object(chat_info->user_id), - std::make_unique(this, chat_id, std::move(query))); + td::make_unique(this, chat_id, std::move(query))); case ChatInfo::Type::Group: return send_request(make_object(chat_info->group_id), - std::make_unique(this, chat_id, std::move(query))); + td::make_unique(this, chat_id, std::move(query))); case ChatInfo::Type::Supergroup: return send_request(make_object(chat_info->supergroup_id), - std::make_unique(this, chat_id, std::move(query))); + td::make_unique(this, chat_id, std::move(query))); case ChatInfo::Type::Unknown: default: UNREACHABLE(); @@ -7341,7 +7341,7 @@ td::Status Client::process_set_chat_photo_query(PromisedQueryPtr &query) { [this, photo = std::move(photo)](int64 chat_id, PromisedQueryPtr query) mutable { send_request(make_object( chat_id, make_object(std::move(photo))), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7351,7 +7351,7 @@ td::Status Client::process_delete_chat_photo_query(PromisedQueryPtr &query) { check_chat(chat_id, AccessRights::Write, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id, nullptr), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7363,7 +7363,7 @@ td::Status Client::process_set_chat_title_query(PromisedQueryPtr &query) { check_chat(chat_id, AccessRights::Write, std::move(query), [this, title = title.str()](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id, title), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7377,7 +7377,7 @@ td::Status Client::process_set_chat_permissions_query(PromisedQueryPtr &query) { check_chat(chat_id, AccessRights::Write, std::move(query), [this, permissions = std::move(permissions)](int64 chat_id, PromisedQueryPtr query) mutable { send_request(make_object(chat_id, std::move(permissions)), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7389,7 +7389,7 @@ td::Status Client::process_set_chat_description_query(PromisedQueryPtr &query) { check_chat(chat_id, AccessRights::Write, std::move(query), [this, description = description.str()](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id, description), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7402,7 +7402,7 @@ td::Status Client::process_pin_chat_message_query(PromisedQueryPtr &query) { check_message(chat_id, message_id, false, AccessRights::Write, "message to pin", std::move(query), [this, disable_notification](int64 chat_id, int64 message_id, PromisedQueryPtr query) { send_request(make_object(chat_id, message_id, disable_notification, false), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7414,13 +7414,13 @@ td::Status Client::process_unpin_chat_message_query(PromisedQueryPtr &query) { if (message_id == 0) { check_chat(chat_id, AccessRights::Write, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id), - std::make_unique(this, chat_id, std::move(query))); + td::make_unique(this, chat_id, std::move(query))); }); } else { check_message(chat_id, message_id, false, AccessRights::Write, "message to unpin", std::move(query), [this](int64 chat_id, int64 message_id, PromisedQueryPtr query) { send_request(make_object(chat_id, message_id), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); } return Status::OK(); @@ -7431,7 +7431,7 @@ td::Status Client::process_unpin_all_chat_messages_query(PromisedQueryPtr &query check_chat(chat_id, AccessRights::Write, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7453,7 +7453,7 @@ td::Status Client::process_set_chat_sticker_set_query(PromisedQueryPtr &query) { CHECK(chat_info->type == ChatInfo::Type::Supergroup); send_request( make_object(chat_info->supergroup_id, sticker_set_id), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7471,7 +7471,7 @@ td::Status Client::process_delete_chat_sticker_set_query(PromisedQueryPtr &query CHECK(chat_info != nullptr); CHECK(chat_info->type == ChatInfo::Type::Supergroup); send_request(make_object(chat_info->supergroup_id, 0), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7502,12 +7502,12 @@ td::Status Client::process_get_chat_administrators_query(PromisedQueryPtr &query return fail_query(400, "Bad Request: there are no administrators in the private chat", std::move(query)); case ChatInfo::Type::Group: return send_request(make_object(chat_info->group_id), - std::make_unique(this, true, std::move(query))); + td::make_unique(this, true, std::move(query))); case ChatInfo::Type::Supergroup: return send_request( make_object( chat_info->supergroup_id, make_object(), 0, 100), - std::make_unique(this, get_chat_type(chat_id), std::move(query))); + td::make_unique(this, get_chat_type(chat_id), std::move(query))); case ChatInfo::Type::Unknown: default: UNREACHABLE(); @@ -7532,7 +7532,7 @@ td::Status Client::process_get_chat_member_count_query(PromisedQueryPtr &query) } case ChatInfo::Type::Supergroup: return send_request(make_object(chat_info->supergroup_id), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); case ChatInfo::Type::Unknown: default: UNREACHABLE(); @@ -7545,7 +7545,7 @@ td::Status Client::process_leave_chat_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); check_chat(chat_id, AccessRights::Read, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { - send_request(make_object(chat_id), std::make_unique(std::move(query))); + send_request(make_object(chat_id), td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7590,7 +7590,7 @@ td::Status Client::process_promote_chat_member_query(PromisedQueryPtr &query) { send_request( make_object( chat_id, td_api::make_object(user_id), std::move(status)), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7623,7 +7623,7 @@ td::Status Client::process_set_chat_administrator_custom_title_query(PromisedQue send_request(make_object( chat_id, td_api::make_object(user_id), std::move(administrator)), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7642,7 +7642,7 @@ td::Status Client::process_ban_chat_member_query(PromisedQueryPtr &query) { send_request(make_object( chat_id, td_api::make_object(user_id), until_date, revoke_messages), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7680,7 +7680,7 @@ td::Status Client::process_restrict_chat_member_query(PromisedQueryPtr &query) { chat_id, td_api::make_object(user_id), make_object( is_chat_member(chat_member->status_), until_date, std::move(permissions))), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7711,14 +7711,14 @@ td::Status Client::process_unban_chat_member_query(PromisedQueryPtr &query) { send_request(make_object( chat_id, td_api::make_object(user_id), make_object()), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); } else { check_user_no_fail(user_id, std::move(query), [this, chat_id, user_id](PromisedQueryPtr query) { send_request(make_object( chat_id, td_api::make_object(user_id), make_object()), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); } }); @@ -7738,7 +7738,7 @@ td::Status Client::process_ban_chat_sender_chat_query(PromisedQueryPtr &query) { make_object( chat_id, td_api::make_object(sender_chat_id), until_date, false), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7755,7 +7755,7 @@ td::Status Client::process_unban_chat_sender_chat_query(PromisedQueryPtr &query) send_request(make_object( chat_id, td_api::make_object(sender_chat_id), make_object()), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7768,7 +7768,7 @@ td::Status Client::process_approve_chat_join_request_query(PromisedQueryPtr &que check_chat(chat_id, AccessRights::Write, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) { check_user_no_fail(user_id, std::move(query), [this, chat_id, user_id](PromisedQueryPtr query) { send_request(make_object(chat_id, user_id, true), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7781,7 +7781,7 @@ td::Status Client::process_decline_chat_join_request_query(PromisedQueryPtr &que check_chat(chat_id, AccessRights::Write, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) { check_user_no_fail(user_id, std::move(query), [this, chat_id, user_id](PromisedQueryPtr query) { send_request(make_object(chat_id, user_id, false), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7791,10 +7791,10 @@ td::Status Client::process_get_sticker_set_query(PromisedQueryPtr &query) { auto name = query->arg("name"); if (td::trim(to_lower(name)) == to_lower(GREAT_MINDS_SET_NAME)) { send_request(make_object(GREAT_MINDS_SET_ID), - std::make_unique(this, true, std::move(query))); + td::make_unique(this, true, std::move(query))); } else { send_request(make_object(name.str()), - std::make_unique(this, true, std::move(query))); + td::make_unique(this, true, std::move(query))); } return Status::OK(); } @@ -7808,7 +7808,7 @@ td::Status Client::process_upload_sticker_file_query(PromisedQueryPtr &query) { send_request(make_object( user_id, make_object(std::move(png_sticker), "", make_object())), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }); return Status::OK(); } @@ -7824,7 +7824,7 @@ td::Status Client::process_create_new_sticker_set_query(PromisedQueryPtr &query) [this, user_id, title, name, stickers = std::move(stickers)](PromisedQueryPtr query) mutable { send_request(make_object(user_id, title.str(), name.str(), std::move(stickers), PSTRING() << "bot" << my_id_), - std::make_unique(this, false, std::move(query))); + td::make_unique(this, false, std::move(query))); }); return Status::OK(); } @@ -7838,7 +7838,7 @@ td::Status Client::process_add_sticker_to_set_query(PromisedQueryPtr &query) { check_user(user_id, std::move(query), [this, user_id, name, sticker = std::move(stickers[0])](PromisedQueryPtr query) mutable { send_request(make_object(user_id, name.str(), std::move(sticker)), - std::make_unique(this, false, std::move(query))); + td::make_unique(this, false, std::move(query))); }); return Status::OK(); } @@ -7850,7 +7850,7 @@ td::Status Client::process_set_sticker_set_thumb_query(PromisedQueryPtr &query) check_user(user_id, std::move(query), [this, user_id, name, thumbnail = std::move(thumbnail)](PromisedQueryPtr query) mutable { send_request(make_object(user_id, name.str(), std::move(thumbnail)), - std::make_unique(this, false, std::move(query))); + td::make_unique(this, false, std::move(query))); }); return Status::OK(); } @@ -7864,7 +7864,7 @@ td::Status Client::process_set_sticker_position_in_set_query(PromisedQueryPtr &q send_request( make_object(make_object(file_id.str()), position), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); return Status::OK(); } @@ -7875,7 +7875,7 @@ td::Status Client::process_delete_sticker_from_set_query(PromisedQueryPtr &query } send_request(make_object(make_object(file_id.str())), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); return Status::OK(); } @@ -7886,7 +7886,7 @@ td::Status Client::process_set_passport_data_errors_query(PromisedQueryPtr &quer check_user(user_id, std::move(query), [this, user_id, errors = std::move(passport_element_errors)](PromisedQueryPtr query) mutable { send_request(make_object(user_id, std::move(errors)), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); }); return Status::OK(); } @@ -7895,7 +7895,7 @@ td::Status Client::process_send_custom_request_query(PromisedQueryPtr &query) { TRY_RESULT(method, get_required_string_arg(query.get(), "method")); auto parameters = query->arg("parameters"); send_request(make_object(method.str(), parameters.str()), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); return Status::OK(); } @@ -7903,7 +7903,7 @@ td::Status Client::process_answer_custom_query_query(PromisedQueryPtr &query) { auto custom_query_id = td::to_integer(query->arg("custom_query_id")); auto data = query->arg("data"); send_request(make_object(custom_query_id, data.str()), - std::make_unique(std::move(query))); + td::make_unique(std::move(query))); return Status::OK(); } @@ -8028,7 +8028,7 @@ void Client::do_get_file(object_ptr file, PromisedQueryPtr query) } send_request(make_object(file_id, 1, 0, 0, false), - std::make_unique(this, file_id)); + td::make_unique(this, file_id)); } bool Client::is_file_being_downloaded(int32 file_id) const { @@ -8091,7 +8091,7 @@ void Client::save_webhook() const { void Client::webhook_success() { next_bot_updates_warning_time_ = td::Time::now() + BOT_UPDATES_WARNING_DELAY; if (was_bot_updates_warning_) { - send_request(make_object(0, ""), std::make_unique()); + send_request(make_object(0, ""), td::make_unique()); was_bot_updates_warning_ = false; } } @@ -8105,7 +8105,7 @@ void Client::webhook_error(Status status) { if (pending_update_count >= MIN_PENDING_UPDATES_WARNING && td::Time::now() > next_bot_updates_warning_time_) { send_request(make_object(td::narrow_cast(pending_update_count), "Webhook error. " + last_webhook_error_.message().str()), - std::make_unique()); + td::make_unique()); next_bot_updates_warning_time_ = td::Time::now_cached() + BOT_UPDATES_WARNING_DELAY; was_bot_updates_warning_ = true; } @@ -8246,7 +8246,7 @@ void Client::do_send_message(object_ptr input_messa send_request(make_object(chat_id, 0, reply_to_message_id, get_message_send_options(disable_notification, protect_content), std::move(reply_markup), std::move(input_message_content)), - std::make_unique(this, std::move(query))); + td::make_unique(this, std::move(query))); }; check_message(chat_id, reply_to_message_id, reply_to_message_id <= 0 || allow_sending_without_reply, AccessRights::Write, "replied message", std::move(query), std::move(on_success)); @@ -8414,7 +8414,7 @@ void Client::do_get_updates(int32 offset, int32 limit, int32 timeout, PromisedQu previous_get_updates_finish_time_ = td::Time::now(); next_bot_updates_warning_time_ = td::Time::now() + BOT_UPDATES_WARNING_DELAY; if (total_size == updates.size() && was_bot_updates_warning_) { - send_request(make_object(0, ""), std::make_unique()); + send_request(make_object(0, ""), td::make_unique()); was_bot_updates_warning_ = false; } answer_query(JsonUpdates(updates), std::move(query)); @@ -8426,7 +8426,7 @@ void Client::long_poll_wakeup(bool force_flag) { if (pending_update_count >= MIN_PENDING_UPDATES_WARNING && td::Time::now() > next_bot_updates_warning_time_) { send_request(make_object(td::narrow_cast(pending_update_count), "The getUpdates method is not called for too long"), - std::make_unique()); + td::make_unique()); next_bot_updates_warning_time_ = td::Time::now_cached() + BOT_UPDATES_WARNING_DELAY; // do not send warnings too often was_bot_updates_warning_ = true; @@ -8841,7 +8841,7 @@ bool Client::update_allowed_update_types(const Query *query) { value = make_object(allowed_update_types); } send_request(make_object("xallowed_update_types", std::move(value)), - std::make_unique()); + td::make_unique()); return true; } return false; @@ -8969,7 +8969,7 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { // get the message from the server queue.has_active_request_ = true; return send_request(make_object(chat_id, message_id, query->id_), - std::make_unique(this, user_id, state)); + td::make_unique(this, user_id, state)); } state = 1; } @@ -8979,7 +8979,7 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { if (reply_to_message_id > 0 && get_message(chat_id, reply_to_message_id) == nullptr) { queue.has_active_request_ = true; return send_request(make_object(chat_id, message_id), - std::make_unique(this, user_id, state)); + td::make_unique(this, user_id, state)); } state = 2; } @@ -8988,7 +8988,7 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; return send_request(make_object(message_sticker_set_id), - std::make_unique(this, message_sticker_set_id, user_id, 0)); + td::make_unique(this, message_sticker_set_id, user_id, 0)); } auto reply_to_message_id = message_info == nullptr || message_info->is_reply_to_message_deleted ? 0 : message_info->reply_to_message_id; @@ -8999,7 +8999,7 @@ void Client::process_new_callback_query_queue(int64 user_id, int state) { if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; return send_request(make_object(reply_sticker_set_id), - std::make_unique(this, reply_sticker_set_id, user_id, 0)); + td::make_unique(this, reply_sticker_set_id, user_id, 0)); } } } @@ -9401,13 +9401,13 @@ void Client::process_new_message_queue(int64 chat_id) { if (reply_to_message_id > 0 && get_message(chat_id, reply_to_message_id) == nullptr) { queue.has_active_request_ = true; return send_request(make_object(chat_id, message_id), - std::make_unique(this, chat_id)); + td::make_unique(this, chat_id)); } auto message_sticker_set_id = get_sticker_set_id(message_ref->content_); if (!have_sticker_set_name(message_sticker_set_id)) { queue.has_active_request_ = true; return send_request(make_object(message_sticker_set_id), - std::make_unique(this, message_sticker_set_id, 0, chat_id)); + td::make_unique(this, message_sticker_set_id, 0, chat_id)); } if (reply_to_message_id > 0) { auto reply_to_message_info = get_message(chat_id, reply_to_message_id); @@ -9416,7 +9416,7 @@ void Client::process_new_message_queue(int64 chat_id) { if (!have_sticker_set_name(reply_sticker_set_id)) { queue.has_active_request_ = true; return send_request(make_object(reply_sticker_set_id), - std::make_unique(this, reply_sticker_set_id, 0, chat_id)); + td::make_unique(this, reply_sticker_set_id, 0, chat_id)); } } @@ -9534,10 +9534,10 @@ Client::FullMessageId Client::add_message(object_ptr &&message, int64 message_id = message->id_; LOG(DEBUG) << "Add message " << message_id << " to chat " << chat_id; - std::unique_ptr message_info; + td::unique_ptr message_info; auto it = messages_.find({chat_id, message_id}); if (it == messages_.end()) { - message_info = std::make_unique(); + message_info = td::make_unique(); } else { message_info = std::move(it->second); } @@ -9643,7 +9643,7 @@ Client::FullMessageId Client::add_message(object_ptr &&message, auto sticker_set_id = get_sticker_set_id(message_info->content); if (!have_sticker_set_name(sticker_set_id)) { send_request(make_object(sticker_set_id), - std::make_unique(this, sticker_set_id, 0, 0)); + td::make_unique(this, sticker_set_id, 0, 0)); } } set_message_reply_markup(message_info.get(), std::move(message->reply_markup_)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 0e8c116..639299e 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -279,8 +279,8 @@ class Client final : public WebhookActor::Callback { template void get_chat_member(int64 chat_id, int64 user_id, PromisedQueryPtr query, OnSuccess on_success); - void send_request(object_ptr &&f, std::unique_ptr handler); - void do_send_request(object_ptr &&f, std::unique_ptr handler); + void send_request(object_ptr &&f, td::unique_ptr handler); + void do_send_request(object_ptr &&f, td::unique_ptr handler); static object_ptr execute(object_ptr &&f); void on_update(object_ptr result); void on_result(td::uint64 id, object_ptr result); @@ -865,11 +865,11 @@ class Client final : public WebhookActor::Callback { static td::FlatHashMap methods_; - td::FlatHashMap, FullMessageIdHash> messages_; // message cache - td::FlatHashMap> users_; // user info cache - td::FlatHashMap> groups_; // group info cache - td::FlatHashMap> supergroups_; // supergroup info cache - td::FlatHashMap> chats_; // chat info cache + td::FlatHashMap, FullMessageIdHash> messages_; // message cache + td::FlatHashMap> users_; // user info cache + td::FlatHashMap> groups_; // group info cache + td::FlatHashMap> supergroups_; // supergroup info cache + td::FlatHashMap> chats_; // chat info cache td::FlatHashMap, FullMessageIdHash> reply_message_ids_; // message -> replies to it @@ -940,7 +940,7 @@ class Client final : public WebhookActor::Callback { td::ActorContext context_; std::queue cmd_queue_; td::vector> pending_updates_; - td::Container> handlers_; + td::Container> handlers_; static constexpr int32 LONG_POLL_MAX_TIMEOUT = 50; static constexpr double LONG_POLL_MAX_DELAY = 0.01; diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index 0630f21..740f92d 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -85,7 +85,7 @@ void ClientManager::send(PromisedQueryPtr query) { auto id_it = token_to_id_.find(token); if (id_it == token_to_id_.end()) { - std::string ip_address; + td::string ip_address; if (query->peer_address().is_valid() && !query->peer_address().is_reserved()) { // external connection ip_address = query->peer_address().get_ip_str().str(); } else { @@ -386,9 +386,9 @@ PromisedQueryPtr ClientManager::get_webhook_restore_query(td::Slice token, td::S args.emplace_back(add_string("url"), add_string(parser.read_all())); const auto method = add_string("setwebhook"); - auto query = std::make_unique(std::move(containers), token, is_test_dc, method, std::move(args), - td::vector>(), - td::vector(), std::move(shared_data), td::IPAddress(), true); + auto query = td::make_unique(std::move(containers), token, is_test_dc, method, std::move(args), + td::vector>(), + td::vector(), std::move(shared_data), td::IPAddress(), true); return PromisedQueryPtr(query.release(), PromiseDeleter(td::PromiseActor>())); } diff --git a/telegram-bot-api/HttpConnection.cpp b/telegram-bot-api/HttpConnection.cpp index 2875e75..68dcdec 100644 --- a/telegram-bot-api/HttpConnection.cpp +++ b/telegram-bot-api/HttpConnection.cpp @@ -44,9 +44,9 @@ void HttpConnection::handle(td::unique_ptr http_query, } auto method = url_path_parser.data(); - auto query = std::make_unique(std::move(http_query->container_), token, is_test_dc, method, - std::move(http_query->args_), std::move(http_query->headers_), - std::move(http_query->files_), shared_data_, http_query->peer_address_, false); + auto query = td::make_unique(std::move(http_query->container_), token, is_test_dc, method, + std::move(http_query->args_), std::move(http_query->headers_), + std::move(http_query->files_), shared_data_, http_query->peer_address_, false); td::PromiseActor> promise; td::FutureActor> future; diff --git a/telegram-bot-api/Query.cpp b/telegram-bot-api/Query.cpp index d8fb3b9..e2a7b08 100644 --- a/telegram-bot-api/Query.cpp +++ b/telegram-bot-api/Query.cpp @@ -21,7 +21,7 @@ namespace telegram_bot_api { -td::FlatHashMap> empty_parameters; +td::FlatHashMap> empty_parameters; Query::Query(td::vector &&container, td::Slice token, bool is_test_dc, td::MutableSlice method, td::vector> &&args, @@ -96,8 +96,8 @@ void Query::set_error(int http_status_code, td::BufferSlice result) { void Query::set_retry_after_error(int retry_after) { retry_after_ = retry_after; - td::FlatHashMap> parameters; - parameters.emplace("retry_after", std::make_unique(retry_after)); + td::FlatHashMap> parameters; + parameters.emplace("retry_after", td::make_unique(retry_after)); set_error(429, td::json_encode( JsonQueryError(429, PSLICE() << "Too Many Requests: retry after " << retry_after, parameters))); } diff --git a/telegram-bot-api/Query.h b/telegram-bot-api/Query.h index ed40911..96bd056 100644 --- a/telegram-bot-api/Query.h +++ b/telegram-bot-api/Query.h @@ -164,11 +164,11 @@ td::StringBuilder &operator<<(td::StringBuilder &sb, const Query &query); // fix for outdated C++14 libraries // https://stackoverflow.com/questions/26947704/implicit-conversion-failure-from-initializer-list -extern td::FlatHashMap> empty_parameters; +extern td::FlatHashMap> empty_parameters; class JsonParameters final : public td::Jsonable { public: - explicit JsonParameters(const td::FlatHashMap> ¶meters) + explicit JsonParameters(const td::FlatHashMap> ¶meters) : parameters_(parameters) { } void store(td::JsonValueScope *scope) const { @@ -180,7 +180,7 @@ class JsonParameters final : public td::Jsonable { } private: - const td::FlatHashMap> ¶meters_; + const td::FlatHashMap> ¶meters_; }; template @@ -206,7 +206,7 @@ class JsonQueryError final : public td::Jsonable { public: JsonQueryError( int error_code, td::Slice description, - const td::FlatHashMap> ¶meters = empty_parameters) + const td::FlatHashMap> ¶meters = empty_parameters) : error_code_(error_code), description_(description), parameters_(parameters) { } void store(td::JsonValueScope *scope) const { @@ -222,7 +222,7 @@ class JsonQueryError final : public td::Jsonable { private: int error_code_; td::Slice description_; - const td::FlatHashMap> ¶meters_; + const td::FlatHashMap> ¶meters_; }; class PromiseDeleter { @@ -261,7 +261,7 @@ void answer_query(const Jsonable &result, PromisedQueryPtr query, td::Slice desc inline void fail_query( int http_status_code, td::Slice description, PromisedQueryPtr query, - const td::FlatHashMap> ¶meters = empty_parameters) { + const td::FlatHashMap> ¶meters = empty_parameters) { query->set_error(http_status_code, td::json_encode(JsonQueryError(http_status_code, description, parameters))); query.reset(); // send query into promise explicitly diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index 14df122..1a42b81 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -597,10 +597,10 @@ void WebhookActor::handle(td::unique_ptr response) { if (!method.empty() && method != "deletewebhook" && method != "setwebhook" && method != "close" && method != "logout" && !td::begins_with(method, "get")) { VLOG(webhook) << "Receive request " << method << " in response to webhook"; - auto query = std::make_unique(std::move(response->container_), td::MutableSlice(), false, - td::MutableSlice(), std::move(response->args_), - std::move(response->headers_), std::move(response->files_), - parameters_->shared_data_, response->peer_address_, false); + auto query = td::make_unique(std::move(response->container_), td::MutableSlice(), false, + td::MutableSlice(), std::move(response->args_), + std::move(response->headers_), std::move(response->files_), + parameters_->shared_data_, response->peer_address_, false); auto promised_query = PromisedQueryPtr(query.release(), PromiseDeleter(td::PromiseActor>())); send_closure(callback_, &Callback::send, std::move(promised_query)); diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 5a82db5..a87f0bd 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -230,11 +230,11 @@ int main(int argc, char *argv[]) { } return 0; }(std::getenv("TELEGRAM_API_ID")); - parameters->api_hash_ = [](auto x) -> std::string { + parameters->api_hash_ = [](auto x) -> td::string { if (x) { return x; } - return std::string(); + return td::string(); }(std::getenv("TELEGRAM_API_HASH")); options.set_usage(td::Slice(argv[0]), "--api-id= --api-hash= [--local] [OPTION]..."); From b4f0ebbaab184418409f9b39a515855d8ebdee9d Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 16 Mar 2022 14:49:38 +0300 Subject: [PATCH 04/17] Store full chatPhoto and compare it with chatPhotoInfo. --- td | 2 +- telegram-bot-api/Client.cpp | 67 ++++++++++++++++++++++++++++++------- telegram-bot-api/Client.h | 8 ++++- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/td b/td index 3f54c30..054a823 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 3f54c301ead1bbe6529df4ecfb63c7f645dd181c +Subproject commit 054a823c1a812ee3e038f702c6d8ba3e6974be9c diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 91bd7df..743cd31 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -619,6 +619,7 @@ class Client::JsonChat final : public Jsonable { CHECK(chat_info != nullptr); auto object = scope->enter_object(); object("id", chat_id_); + const td_api::chatPhoto *photo = nullptr; switch (chat_info->type) { case ChatInfo::Type::Private: { auto user_info = client_->get_user_info(chat_info->user_id); @@ -639,6 +640,7 @@ class Client::JsonChat final : public Jsonable { object("has_private_forwards", td::JsonTrue()); } } + photo = user_info->photo.get(); break; } case ChatInfo::Type::Group: { @@ -663,6 +665,7 @@ class Client::JsonChat final : public Jsonable { permissions->can_add_web_page_previews_ && permissions->can_change_info_ && permissions->can_invite_users_ && permissions->can_pin_messages_; object("all_members_are_administrators", td::JsonBool(everyone_is_administrator)); + photo = group_info->photo.get(); break; } case ChatInfo::Type::Supergroup: { @@ -710,6 +713,7 @@ class Client::JsonChat final : public Jsonable { object("location", JsonChatLocation(supergroup_info->location.get())); } } + photo = supergroup_info->photo.get(); break; } case ChatInfo::Type::Unknown: @@ -717,8 +721,34 @@ class Client::JsonChat final : public Jsonable { UNREACHABLE(); } if (is_full_) { - if (chat_info->photo != nullptr) { - object("photo", JsonChatPhotoInfo(chat_info->photo.get())); + if (photo != nullptr) { + const td_api::file *small_file = nullptr; + const td_api::file *big_file = nullptr; + for (auto &size : photo->sizes_) { + if (size->type_ == "a") { + small_file = size->photo_.get(); + } else if (size->type_ == "c") { + big_file = size->photo_.get(); + } + } + if (small_file == nullptr || big_file == nullptr) { + LOG(ERROR) << "Failed to convert chatPhoto to chatPhotoInfo for " << chat_id_ << ": " << to_string(*photo); + } else { + if (chat_info->photo_info == nullptr) { + LOG(ERROR) << "Have chatPhoto without chatPhotoInfo for " << chat_id_; + } else { + if (small_file->remote_->unique_id_ != chat_info->photo_info->small_->remote_->unique_id_ || + big_file->remote_->unique_id_ != chat_info->photo_info->big_->remote_->unique_id_) { + LOG(ERROR) << "Have different chatPhoto and chatPhotoInfo for " << chat_id_ << ": " << to_string(*photo) + << ' ' << to_string(chat_info->photo_info); + } + } + } + } else if (chat_info->photo_info != nullptr) { + LOG(ERROR) << "Have chatPhotoInfo without chatPhoto for " << chat_id_; + } + if (chat_info->photo_info != nullptr) { + object("photo", JsonChatPhotoInfo(chat_info->photo_info.get())); } if (pinned_message_id_ != 0) { CHECK(pinned_message_id_ != -1); @@ -1687,10 +1717,7 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { } case td_api::messagePhoto::ID: { auto message_photo = static_cast(message_->content.get()); - if (message_photo->photo_ == nullptr) { - LOG(ERROR) << "Got empty messagePhoto"; - break; - } + CHECK(message_photo->photo_ != nullptr); object("photo", JsonPhoto(message_photo->photo_.get(), client_)); add_caption(object, message_photo->caption_); break; @@ -4355,7 +4382,7 @@ void Client::on_update(object_ptr result) { } chat_info->title = std::move(chat->title_); - chat_info->photo = std::move(chat->photo_); + chat_info->photo_info = std::move(chat->photo_); chat_info->permissions = std::move(chat->permissions_); chat_info->message_auto_delete_time = chat->message_ttl_; chat_info->has_protected_content = chat->has_protected_content_; @@ -4372,7 +4399,7 @@ void Client::on_update(object_ptr result) { auto update = move_object_as(result); auto chat_info = add_chat(update->chat_id_); CHECK(chat_info->type != ChatInfo::Type::Unknown); - chat_info->photo = std::move(update->photo_); + chat_info->photo_info = std::move(update->photo_); break; } case td_api::updateChatPermissions::ID: { @@ -4405,8 +4432,10 @@ void Client::on_update(object_ptr result) { case td_api::updateUserFullInfo::ID: { auto update = move_object_as(result); auto user_id = update->user_id_; - set_user_bio(user_id, std::move(update->user_full_info_->bio_)); - set_user_has_private_forwards(user_id, update->user_full_info_->has_private_forwards_); + auto full_info = update->user_full_info_.get(); + set_user_photo(user_id, std::move(full_info->photo_)); + set_user_bio(user_id, std::move(full_info->bio_)); + set_user_has_private_forwards(user_id, full_info->has_private_forwards_); break; } case td_api::updateBasicGroup::ID: { @@ -4418,7 +4447,8 @@ void Client::on_update(object_ptr result) { case td_api::updateBasicGroupFullInfo::ID: { auto update = move_object_as(result); auto group_id = update->basic_group_id_; - auto full_info = std::move(update->basic_group_full_info_); + auto full_info = update->basic_group_full_info_.get(); + set_group_photo(group_id, std::move(full_info->photo_)); set_group_description(group_id, std::move(full_info->description_)); set_group_invite_link(group_id, full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) @@ -4434,7 +4464,8 @@ void Client::on_update(object_ptr result) { case td_api::updateSupergroupFullInfo::ID: { auto update = move_object_as(result); auto supergroup_id = update->supergroup_id_; - auto full_info = std::move(update->supergroup_full_info_); + auto full_info = update->supergroup_full_info_.get(); + set_supergroup_photo(supergroup_id, std::move(full_info->photo_)); set_supergroup_description(supergroup_id, std::move(full_info->description_)); set_supergroup_invite_link(supergroup_id, full_info->invite_link_ != nullptr ? std::move(full_info->invite_link_->invite_link_) @@ -8495,6 +8526,10 @@ const Client::UserInfo *Client::get_user_info(int64 user_id) const { return it == users_.end() ? nullptr : it->second.get(); } +void Client::set_user_photo(int64 user_id, object_ptr &&photo) { + add_user_info(user_id)->photo = std::move(photo); +} + void Client::set_user_bio(int64 user_id, td::string &&bio) { add_user_info(user_id)->bio = std::move(bio); } @@ -8530,6 +8565,10 @@ const Client::GroupInfo *Client::get_group_info(int64 group_id) const { return it == groups_.end() ? nullptr : it->second.get(); } +void Client::set_group_photo(int64 group_id, object_ptr &&photo) { + add_group_info(group_id)->photo = std::move(photo); +} + void Client::set_group_description(int64 group_id, td::string &&descripton) { add_group_info(group_id)->description = std::move(descripton); } @@ -8546,6 +8585,10 @@ void Client::add_supergroup(SupergroupInfo *supergroup_info, object_ptrhas_location = supergroup->has_location_; } +void Client::set_supergroup_photo(int64 supergroup_id, object_ptr &&photo) { + add_supergroup_info(supergroup_id)->photo = std::move(photo); +} + void Client::set_supergroup_description(int64 supergroup_id, td::string &&descripton) { add_supergroup_info(supergroup_id)->description = std::move(descripton); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 639299e..034fe23 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -580,6 +580,7 @@ class Client final : public WebhookActor::Callback { td::string username; td::string language_code; + object_ptr photo; td::string bio; bool have_access = false; @@ -589,12 +590,14 @@ class Client final : public WebhookActor::Callback { bool has_private_forwards = false; }; static void add_user(UserInfo *user_info, object_ptr &&user); + void set_user_photo(int64 user_id, object_ptr &&photo); void set_user_bio(int64 user_id, td::string &&bio); void set_user_has_private_forwards(int64 user_id, bool has_private_forwards); UserInfo *add_user_info(int64 user_id); const UserInfo *get_user_info(int64 user_id) const; struct GroupInfo { + object_ptr photo; td::string description; td::string invite_link; int32 member_count = 0; @@ -604,6 +607,7 @@ class Client final : public WebhookActor::Callback { int64 upgraded_to_supergroup_id = 0; }; static void add_group(GroupInfo *group_info, object_ptr &&group); + void set_group_photo(int64 group_id, object_ptr &&photo); void set_group_description(int64 group_id, td::string &&descripton); void set_group_invite_link(int64 group_id, td::string &&invite_link); GroupInfo *add_group_info(int64 group_id); @@ -611,6 +615,7 @@ class Client final : public WebhookActor::Callback { struct SupergroupInfo { td::string username; + object_ptr photo; td::string description; td::string invite_link; int64 sticker_set_id = 0; @@ -624,6 +629,7 @@ class Client final : public WebhookActor::Callback { bool has_location = false; }; static void add_supergroup(SupergroupInfo *supergroup_info, object_ptr &&supergroup); + void set_supergroup_photo(int64 supergroup_id, object_ptr &&photo); void set_supergroup_description(int64 supergroup_id, td::string &&descripton); void set_supergroup_invite_link(int64 supergroup_id, td::string &&invite_link); void set_supergroup_sticker_set_id(int64 supergroup_id, int64 sticker_set_id); @@ -640,7 +646,7 @@ class Client final : public WebhookActor::Callback { td::string title; int32 message_auto_delete_time = 0; bool has_protected_content = false; - object_ptr photo; + object_ptr photo_info; object_ptr permissions; union { int64 user_id; From afaa577b1aba0e610cbc5fcbd9c71f5f5095c78e Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 18 Mar 2022 14:03:14 +0300 Subject: [PATCH 05/17] Add "last_synchronization_error_date" to getWebhookInfo. --- telegram-bot-api/Client.cpp | 32 ++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 6 ++++++ 2 files changed, 38 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 743cd31..417d578 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2499,6 +2499,9 @@ class Client::JsonWebhookInfo final : public Jsonable { if (client_->allowed_update_types_ != DEFAULT_ALLOWED_UPDATE_TYPES) { object("allowed_updates", JsonUpdateTypes(client_->allowed_update_types_)); } + if (client_->last_synchronization_error_date_ > 0) { + object("last_synchronization_error_date", client_->last_synchronization_error_date_); + } } private: @@ -3515,6 +3518,18 @@ std::size_t Client::get_pending_update_count() const { return parameters_->shared_data_->tqueue_->get_size(tqueue_id_); } +void Client::update_last_synchronization_error_date() { + if (disconnection_time_ == 0 || !was_authorized_ || logging_out_ || closing_) { + return; + } + auto now = td::Time::now(); + if (last_update_creation_time_ > now - 10 || disconnection_time_ > now - 180) { + return; + } + + last_synchronization_error_date_ = get_unix_time(); +} + ServerBotInfo Client::get_bot_info() const { ServerBotInfo res; res.id_ = bot_token_id_; @@ -4227,12 +4242,14 @@ void Client::on_update_authorization_state() { } td::reset_to_empty(pending_updates_); } + last_update_creation_time_ = td::Time::now(); } return loop(); } case td_api::authorizationStateLoggingOut::ID: if (!logging_out_) { LOG(WARNING) << "Logging out"; + update_last_synchronization_error_date(); logging_out_ = true; if (was_authorized_ && !closing_) { td::send_event(parent_, td::Event::raw(nullptr)); @@ -4242,6 +4259,7 @@ void Client::on_update_authorization_state() { case td_api::authorizationStateClosing::ID: if (!closing_) { LOG(WARNING) << "Closing"; + update_last_synchronization_error_date(); closing_ = true; if (was_authorized_ && !logging_out_) { td::send_event(parent_, td::Event::raw(nullptr)); @@ -4568,6 +4586,16 @@ void Client::on_update(object_ptr result) { case td_api::updateNewChatJoinRequest::ID: add_update_chat_join_request(move_object_as(result)); break; + case td_api::updateConnectionState::ID: { + auto update = move_object_as(result); + if (update->state_->get_id() == td_api::connectionStateReady::ID) { + update_last_synchronization_error_date(); + disconnection_time_ = 0; + } else if (disconnection_time_ == 0) { + disconnection_time_ = td::Time::now(); + } + break; + } default: // we are not interested in this update break; @@ -8028,6 +8056,7 @@ td::Status Client::process_set_webhook_query(PromisedQueryPtr &query) { } td::Status Client::process_get_webhook_info_query(PromisedQueryPtr &query) { + update_last_synchronization_error_date(); answer_query(JsonWebhookInfo(this), std::move(query)); return Status::OK(); } @@ -8910,6 +8939,9 @@ void Client::add_update(UpdateType update_type, const T &update, int32 timeout, void Client::add_update_impl(UpdateType update_type, const td::VirtuallyJsonable &update, int32 timeout, int64 webhook_queue_id) { + update_last_synchronization_error_date(); + last_update_creation_time_ = td::Time::now(); + if (((allowed_update_types_ >> static_cast(update_type)) & 1) == 0) { return; } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 034fe23..781fbcf 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -832,6 +832,8 @@ class Client final : public WebhookActor::Callback { std::size_t get_pending_update_count() const; + void update_last_synchronization_error_date(); + static bool is_chat_member(const object_ptr &status); static td::string get_chat_member_status(const object_ptr &status); @@ -983,6 +985,10 @@ class Client final : public WebhookActor::Callback { double local_unix_time_difference_ = 0; // Unix time - now() + double disconnection_time_ = 0; // the time when Connection state changed from "Ready", or 0 if it is "Ready" + double last_update_creation_time_ = 0; // the time when the last update was added + int32 last_synchronization_error_date_ = 0; // the date of the last connection error + int32 previous_get_updates_offset_ = -1; double previous_get_updates_start_time_ = 0; double previous_get_updates_finish_time_ = 0; From 3c99f26824c6a0a75cf4b6ae5810d05b1314adee Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 22 Mar 2022 17:25:59 +0300 Subject: [PATCH 06/17] Rename voice chats to video chats. --- telegram-bot-api/Client.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 417d578..c7c6392 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1937,19 +1937,23 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { } case td_api::messageVideoChatScheduled::ID: { auto content = static_cast(message_->content.get()); + object("video_chat_scheduled", JsonVideoChatScheduled(content)); object("voice_chat_scheduled", JsonVideoChatScheduled(content)); break; } case td_api::messageVideoChatStarted::ID: + object("video_chat_started", JsonVideoChatStarted()); object("voice_chat_started", JsonVideoChatStarted()); break; case td_api::messageVideoChatEnded::ID: { auto content = static_cast(message_->content.get()); + object("video_chat_ended", JsonVideoChatEnded(content)); object("voice_chat_ended", JsonVideoChatEnded(content)); break; } case td_api::messageInviteVideoChatParticipants::ID: { auto content = static_cast(message_->content.get()); + object("video_chat_participants_invited", JsonInviteVideoChatParticipants(content, client_)); object("voice_chat_participants_invited", JsonInviteVideoChatParticipants(content, client_)); break; } @@ -2313,6 +2317,7 @@ class Client::JsonChatMember final : public Jsonable { } object("can_promote_members", td::JsonBool(administrator->can_promote_members_)); object("can_manage_voice_chats", td::JsonBool(administrator->can_manage_video_chats_)); + object("can_manage_video_chats", td::JsonBool(administrator->can_manage_video_chats_)); if (!administrator->custom_title_.empty()) { object("custom_title", administrator->custom_title_); } @@ -7621,7 +7626,8 @@ td::Status Client::process_promote_chat_member_query(PromisedQueryPtr &query) { auto can_restrict_members = to_bool(query->arg("can_restrict_members")); auto can_pin_messages = to_bool(query->arg("can_pin_messages")); auto can_promote_members = to_bool(query->arg("can_promote_members")); - auto can_manage_video_chats = to_bool(query->arg("can_manage_voice_chats")); + auto can_manage_video_chats = + to_bool(query->arg("can_manage_voice_chats")) || to_bool(query->arg("can_manage_video_chats")); auto is_anonymous = to_bool(query->arg("is_anonymous")); auto status = make_object( td::string(), true, can_manage_chat, can_change_info, can_post_messages, can_edit_messages, can_delete_messages, From 58e62488745a6c9ddb4deacef18175a08a77af72 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 24 Mar 2022 11:49:55 +0300 Subject: [PATCH 07/17] Update TDLib to 1.8.3. --- telegram-bot-api/Client.cpp | 31 ++++++++++++++++--------------- telegram-bot-api/Client.h | 4 ++-- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index c7c6392..63cf206 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2303,25 +2303,25 @@ class Client::JsonChatMember final : public Jsonable { case td_api::chatMemberStatusAdministrator::ID: { auto administrator = static_cast(member_->status_.get()); object("can_be_edited", td::JsonBool(administrator->can_be_edited_)); - object("can_manage_chat", td::JsonBool(administrator->can_manage_chat_)); - object("can_change_info", td::JsonBool(administrator->can_change_info_)); + object("can_manage_chat", td::JsonBool(administrator->rights_->can_manage_chat_)); + object("can_change_info", td::JsonBool(administrator->rights_->can_change_info_)); if (chat_type_ == Client::ChatType::Channel) { - object("can_post_messages", td::JsonBool(administrator->can_post_messages_)); - object("can_edit_messages", td::JsonBool(administrator->can_edit_messages_)); + object("can_post_messages", td::JsonBool(administrator->rights_->can_post_messages_)); + object("can_edit_messages", td::JsonBool(administrator->rights_->can_edit_messages_)); } - object("can_delete_messages", td::JsonBool(administrator->can_delete_messages_)); - object("can_invite_users", td::JsonBool(administrator->can_invite_users_)); - object("can_restrict_members", td::JsonBool(administrator->can_restrict_members_)); + object("can_delete_messages", td::JsonBool(administrator->rights_->can_delete_messages_)); + object("can_invite_users", td::JsonBool(administrator->rights_->can_invite_users_)); + object("can_restrict_members", td::JsonBool(administrator->rights_->can_restrict_members_)); if (chat_type_ == Client::ChatType::Group || chat_type_ == Client::ChatType::Supergroup) { - object("can_pin_messages", td::JsonBool(administrator->can_pin_messages_)); + object("can_pin_messages", td::JsonBool(administrator->rights_->can_pin_messages_)); } - object("can_promote_members", td::JsonBool(administrator->can_promote_members_)); - object("can_manage_voice_chats", td::JsonBool(administrator->can_manage_video_chats_)); - object("can_manage_video_chats", td::JsonBool(administrator->can_manage_video_chats_)); + object("can_promote_members", td::JsonBool(administrator->rights_->can_promote_members_)); + object("can_manage_voice_chats", td::JsonBool(administrator->rights_->can_manage_video_chats_)); + object("can_manage_video_chats", td::JsonBool(administrator->rights_->can_manage_video_chats_)); if (!administrator->custom_title_.empty()) { object("custom_title", administrator->custom_title_); } - object("is_anonymous", td::JsonBool(administrator->is_anonymous_)); + object("is_anonymous", td::JsonBool(administrator->rights_->is_anonymous_)); break; } case td_api::chatMemberStatusMember::ID: @@ -7630,9 +7630,10 @@ td::Status Client::process_promote_chat_member_query(PromisedQueryPtr &query) { to_bool(query->arg("can_manage_voice_chats")) || to_bool(query->arg("can_manage_video_chats")); auto is_anonymous = to_bool(query->arg("is_anonymous")); auto status = make_object( - td::string(), true, can_manage_chat, can_change_info, can_post_messages, can_edit_messages, can_delete_messages, - can_invite_users, can_restrict_members, can_pin_messages, can_promote_members, can_manage_video_chats, - is_anonymous); + td::string(), true, + td_api::make_object( + can_manage_chat, can_change_info, can_post_messages, can_edit_messages, can_delete_messages, can_invite_users, + can_restrict_members, can_pin_messages, can_promote_members, can_manage_video_chats, is_anonymous)); check_chat(chat_id, AccessRights::Write, std::move(query), [this, user_id, status = std::move(status)](int64 chat_id, PromisedQueryPtr query) mutable { auto chat_info = get_chat(chat_id); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 781fbcf..97dce87 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -951,8 +951,8 @@ class Client final : public WebhookActor::Callback { td::Container> handlers_; static constexpr int32 LONG_POLL_MAX_TIMEOUT = 50; - static constexpr double LONG_POLL_MAX_DELAY = 0.01; - static constexpr double LONG_POLL_WAIT_AFTER = 0.002; + static constexpr double LONG_POLL_MAX_DELAY = 0.002; + static constexpr double LONG_POLL_WAIT_AFTER = 0.001; int32 long_poll_limit_ = 0; int32 long_poll_offset_ = 0; bool long_poll_was_wakeup_ = false; From 8bc5730532c2175a855737cd14016cf39e9e9b10 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 24 Mar 2022 12:02:15 +0300 Subject: [PATCH 08/17] Add answerWebAppQuery method. --- telegram-bot-api/Client.cpp | 68 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 5 +++ 2 files changed, 73 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 63cf206..efb7c7a 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -223,6 +223,7 @@ bool Client::init_methods() { methods_.emplace("deletemessage", &Client::process_delete_message_query); methods_.emplace("setgamescore", &Client::process_set_game_score_query); methods_.emplace("getgamehighscores", &Client::process_get_game_high_scores_query); + methods_.emplace("answerwebappquery", &Client::process_answer_web_app_query_query); methods_.emplace("answerinlinequery", &Client::process_answer_inline_query_query); methods_.emplace("answercallbackquery", &Client::process_answer_callback_query_query); methods_.emplace("answershippingquery", &Client::process_answer_shipping_query_query); @@ -2541,6 +2542,21 @@ class Client::JsonStickerSet final : public Jsonable { const Client *client_; }; +class Client::JsonSentWebAppMessage final : public Jsonable { + public: + explicit JsonSentWebAppMessage(const td_api::sentWebAppMessage *message) : message_(message) { + } + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (!message_->inline_message_id_.empty()) { + object("inline_message_id", message_->inline_message_id_); + } + } + + private: + const td_api::sentWebAppMessage *message_; +}; + class Client::TdOnOkCallback final : public TdQueryCallback { public: void on_result(object_ptr result) final { @@ -3437,6 +3453,25 @@ class Client::TdOnGetGameHighScoresCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnAnswerWebAppQueryCallback final : public TdQueryCallback { + public: + explicit TdOnAnswerWebAppQueryCallback(PromisedQueryPtr query) : query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + CHECK(result->get_id() == td_api::sentWebAppMessage::ID); + auto message = move_object_as(result); + answer_query(JsonSentWebAppMessage(message.get()), std::move(query_)); + } + + private: + PromisedQueryPtr query_; +}; + class Client::TdOnReturnFileCallback final : public TdQueryCallback { public: TdOnReturnFileCallback(const Client *client, PromisedQueryPtr query) : client_(client), query_(std::move(query)) { @@ -5374,6 +5409,22 @@ td::Result>> Clien return std::move(inline_query_results); } +td::Result> Client::get_inline_query_result(const Query *query) { + auto result_encoded = query->arg("result"); + if (result_encoded.empty()) { + return Status::Error(400, "Result isn't specified"); + } + + LOG(INFO) << "Parsing JSON object: " << result_encoded; + auto r_value = json_decode(result_encoded); + if (r_value.is_error()) { + return Status::Error(400, + PSLICE() << "Can't parse JSON encoded web view query results " << r_value.error().message()); + } + + return get_inline_query_result(r_value.move_as_ok()); +} + td::Result> Client::get_inline_query_result(td::JsonValue &&value) { if (value.type() != JsonValue::Type::Object) { return Status::Error(400, "Inline query result must be an object"); @@ -7246,6 +7297,23 @@ td::Status Client::process_get_game_high_scores_query(PromisedQueryPtr &query) { return Status::OK(); } +td::Status Client::process_answer_web_app_query_query(PromisedQueryPtr &query) { + auto web_app_query_id = query->arg("web_app_query_id"); + + TRY_RESULT(result, get_inline_query_result(query.get())); + td::vector> results; + results.push_back(std::move(result)); + + resolve_inline_query_results_bot_usernames( + std::move(results), std::move(query), + [this, web_app_query_id = web_app_query_id.str()](td::vector> results, PromisedQueryPtr query) { + CHECK(results.size() == 1); + send_request(make_object(web_app_query_id, std::move(results[0])), + td::make_unique(std::move(query))); + }); + return Status::OK(); +} + td::Status Client::process_answer_inline_query_query(PromisedQueryPtr &query) { auto inline_query_id = td::to_integer(query->arg("inline_query_id")); auto is_personal = to_bool(query->arg("is_personal")); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 97dce87..ad7c0d3 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -154,6 +154,7 @@ class Client final : public WebhookActor::Callback { class JsonUpdateTypes; class JsonWebhookInfo; class JsonStickerSet; + class JsonSentWebAppMessage; class JsonCustomJson; class TdOnOkCallback; @@ -182,6 +183,7 @@ class Client final : public WebhookActor::Callback { class TdOnReplacePrimaryChatInviteLinkCallback; class TdOnGetChatInviteLinkCallback; class TdOnGetGameHighScoresCallback; + class TdOnAnswerWebAppQueryCallback; class TdOnReturnFileCallback; class TdOnReturnStickerSetCallback; class TdOnDownloadFileCallback; @@ -334,6 +336,8 @@ class Client final : public WebhookActor::Callback { object_ptr get_input_thumbnail(const Query *query, Slice field_name) const; + td::Result> get_inline_query_result(const Query *query); + td::Result> get_inline_query_result(td::JsonValue &&value); td::Result>> get_inline_query_results(const Query *query); @@ -473,6 +477,7 @@ class Client final : public WebhookActor::Callback { Status process_delete_message_query(PromisedQueryPtr &query); Status process_set_game_score_query(PromisedQueryPtr &query); Status process_get_game_high_scores_query(PromisedQueryPtr &query); + Status process_answer_web_app_query_query(PromisedQueryPtr &query); Status process_answer_inline_query_query(PromisedQueryPtr &query); Status process_answer_callback_query_query(PromisedQueryPtr &query); Status process_answer_shipping_query_query(PromisedQueryPtr &query); From defcb525715af55b6264f1f7658db987a984299c Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 25 Mar 2022 01:00:48 +0300 Subject: [PATCH 09/17] Support WebApp buttons. --- telegram-bot-api/Client.cpp | 37 +++++++++++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 38 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index efb7c7a..91303b0 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1545,6 +1545,19 @@ class Client::JsonCallbackGame final : public Jsonable { } }; +class Client::JsonWebAppInfo final : public Jsonable { + public: + explicit JsonWebAppInfo(const td::string &url) : url_(url) { + } + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("url", url_); + } + + private: + const td::string &url_; +}; + class Client::JsonInlineKeyboardButton final : public Jsonable { public: explicit JsonInlineKeyboardButton(const td_api::inlineKeyboardButton *button) : button_(button) { @@ -1593,6 +1606,11 @@ class Client::JsonInlineKeyboardButton final : public Jsonable { object("url", PSLICE() << "tg://user?id=" << type->user_id_); break; } + case td_api::inlineKeyboardButtonTypeWebApp::ID: { + auto type = static_cast(button_->type_.get()); + object("web_app", JsonWebAppInfo(type->url_)); + break; + } default: UNREACHABLE(); break; @@ -4808,6 +4826,13 @@ td::Result> Client::get_keyboard_butt text, make_object(force_regular, force_quiz)); } + if (has_json_object_field(object, "web_app")) { + TRY_RESULT(web_app, get_json_object_field(object, "web_app", JsonValue::Type::Object, false)); + auto &web_app_object = web_app.get_object(); + TRY_RESULT(url, get_json_object_string_field(web_app_object, "url")); + return make_object(text, make_object(url)); + } + return make_object(text, nullptr); } if (button.type() == JsonValue::Type::String) { @@ -4904,6 +4929,13 @@ td::Result> Client::get_inline_ text, make_object(url, bot_user_id, forward_text)); } + if (has_json_object_field(object, "web_app")) { + TRY_RESULT(web_app, get_json_object_field(object, "web_app", JsonValue::Type::Object, false)); + auto &web_app_object = web_app.get_object(); + TRY_RESULT(url, get_json_object_string_field(web_app_object, "url")); + return make_object(text, make_object(url)); + } + return Status::Error(400, "Text buttons are unallowed in the inline keyboard"); } @@ -9467,6 +9499,11 @@ bool Client::are_equal_inline_keyboard_buttons(const td_api::inlineKeyboardButto auto rhs_type = static_cast(rhs->type_.get()); return lhs_type->user_id_ == rhs_type->user_id_; } + case td_api::inlineKeyboardButtonTypeWebApp::ID: { + auto lhs_type = static_cast(lhs->type_.get()); + auto rhs_type = static_cast(rhs->type_.get()); + return lhs_type->url_ == rhs_type->url_; + } default: UNREACHABLE(); return false; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index ad7c0d3..cabb2d3 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -119,6 +119,7 @@ class Client final : public WebhookActor::Callback { class JsonEntity; class JsonVectorEntities; class JsonCallbackGame; + class JsonWebAppInfo; class JsonInlineKeyboardButton; class JsonInlineKeyboard; class JsonReplyMarkup; From 325280944806e5fcffdb14ddb19c633d9a7ee412 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 28 Mar 2022 17:10:49 +0300 Subject: [PATCH 10/17] Unify message content variable names. --- telegram-bot-api/Client.cpp | 162 ++++++++++++++++++------------------ 1 file changed, 80 insertions(+), 82 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 91303b0..1c3a1fe 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1708,106 +1708,105 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { } switch (message_->content->get_id()) { case td_api::messageText::ID: { - auto message_text = static_cast(message_->content.get()); - object("text", message_text->text_->text_); - if (!message_text->text_->entities_.empty()) { - object("entities", JsonVectorEntities(message_text->text_->entities_, client_)); + auto content = static_cast(message_->content.get()); + object("text", content->text_->text_); + if (!content->text_->entities_.empty()) { + object("entities", JsonVectorEntities(content->text_->entities_, client_)); } break; } case td_api::messageAnimation::ID: { - auto message_animation = static_cast(message_->content.get()); - object("animation", JsonAnimation(message_animation->animation_.get(), false, client_)); - object("document", JsonAnimation(message_animation->animation_.get(), true, client_)); - add_caption(object, message_animation->caption_); + auto content = static_cast(message_->content.get()); + object("animation", JsonAnimation(content->animation_.get(), false, client_)); + object("document", JsonAnimation(content->animation_.get(), true, client_)); + add_caption(object, content->caption_); break; } case td_api::messageAudio::ID: { - auto message_audio = static_cast(message_->content.get()); - object("audio", JsonAudio(message_audio->audio_.get(), client_)); - add_caption(object, message_audio->caption_); + auto content = static_cast(message_->content.get()); + object("audio", JsonAudio(content->audio_.get(), client_)); + add_caption(object, content->caption_); break; } case td_api::messageDocument::ID: { - auto message_document = static_cast(message_->content.get()); - object("document", JsonDocument(message_document->document_.get(), client_)); - add_caption(object, message_document->caption_); + auto content = static_cast(message_->content.get()); + object("document", JsonDocument(content->document_.get(), client_)); + add_caption(object, content->caption_); break; } case td_api::messagePhoto::ID: { - auto message_photo = static_cast(message_->content.get()); - CHECK(message_photo->photo_ != nullptr); - object("photo", JsonPhoto(message_photo->photo_.get(), client_)); - add_caption(object, message_photo->caption_); + auto content = static_cast(message_->content.get()); + CHECK(content->photo_ != nullptr); + object("photo", JsonPhoto(content->photo_.get(), client_)); + add_caption(object, content->caption_); break; } case td_api::messageSticker::ID: { - auto message_sticker = static_cast(message_->content.get()); - object("sticker", JsonSticker(message_sticker->sticker_.get(), client_)); + auto content = static_cast(message_->content.get()); + object("sticker", JsonSticker(content->sticker_.get(), client_)); break; } case td_api::messageVideo::ID: { - auto message_video = static_cast(message_->content.get()); - object("video", JsonVideo(message_video->video_.get(), client_)); - add_caption(object, message_video->caption_); + auto content = static_cast(message_->content.get()); + object("video", JsonVideo(content->video_.get(), client_)); + add_caption(object, content->caption_); break; } case td_api::messageVideoNote::ID: { - auto message_video_note = static_cast(message_->content.get()); - object("video_note", JsonVideoNote(message_video_note->video_note_.get(), client_)); + auto content = static_cast(message_->content.get()); + object("video_note", JsonVideoNote(content->video_note_.get(), client_)); break; } case td_api::messageVoiceNote::ID: { - auto message_voice_note = static_cast(message_->content.get()); - object("voice", JsonVoiceNote(message_voice_note->voice_note_.get(), client_)); - add_caption(object, message_voice_note->caption_); + auto content = static_cast(message_->content.get()); + object("voice", JsonVoiceNote(content->voice_note_.get(), client_)); + add_caption(object, content->caption_); break; } case td_api::messageContact::ID: { - auto message_contact = static_cast(message_->content.get()); - object("contact", JsonContact(message_contact->contact_.get())); + auto content = static_cast(message_->content.get()); + object("contact", JsonContact(content->contact_.get())); break; } case td_api::messageDice::ID: { - auto message_dice = static_cast(message_->content.get()); - object("dice", JsonDice(message_dice->emoji_, message_dice->value_)); + auto content = static_cast(message_->content.get()); + object("dice", JsonDice(content->emoji_, content->value_)); break; } case td_api::messageGame::ID: { - auto message_game = static_cast(message_->content.get()); - object("game", JsonGame(message_game->game_.get(), client_)); + auto content = static_cast(message_->content.get()); + object("game", JsonGame(content->game_.get(), client_)); break; } case td_api::messageInvoice::ID: { - auto message_invoice = static_cast(message_->content.get()); - object("invoice", JsonInvoice(message_invoice)); + auto content = static_cast(message_->content.get()); + object("invoice", JsonInvoice(content)); break; } case td_api::messageLocation::ID: { - auto message_location = static_cast(message_->content.get()); - object("location", JsonLocation(message_location->location_.get(), message_location->expires_in_, - message_location->live_period_, message_location->heading_, - message_location->proximity_alert_radius_)); + auto content = static_cast(message_->content.get()); + object("location", JsonLocation(content->location_.get(), content->expires_in_, content->live_period_, + content->heading_, content->proximity_alert_radius_)); break; } case td_api::messageVenue::ID: { - auto message_venue = static_cast(message_->content.get()); - object("location", JsonLocation(message_venue->venue_->location_.get())); - object("venue", JsonVenue(message_venue->venue_.get())); + auto content = static_cast(message_->content.get()); + object("location", JsonLocation(content->venue_->location_.get())); + object("venue", JsonVenue(content->venue_.get())); break; } case td_api::messagePoll::ID: { - auto message_poll = static_cast(message_->content.get()); - object("poll", JsonPoll(message_poll->poll_.get(), client_)); + auto content = static_cast(message_->content.get()); + object("poll", JsonPoll(content->poll_.get(), client_)); break; } case td_api::messageChatAddMembers::ID: { - auto message_add_members = static_cast(message_->content.get()); - int64 user_id = client_->choose_added_member_id(message_add_members); + auto content = static_cast(message_->content.get()); + int64 user_id = client_->choose_added_member_id(content); if (user_id > 0) { object("new_chat_participant", JsonUser(user_id, client_)); object("new_chat_member", JsonUser(user_id, client_)); - object("new_chat_members", JsonUsers(message_add_members->member_user_ids_, client_)); + object("new_chat_members", JsonUsers(content->member_user_ids_, client_)); } else { LOG(ERROR) << "Can't choose added member for new_chat_member field"; } @@ -1830,24 +1829,24 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { break; } case td_api::messageChatDeleteMember::ID: { - auto message_delete_member = static_cast(message_->content.get()); - int64 user_id = message_delete_member->user_id_; + auto content = static_cast(message_->content.get()); + int64 user_id = content->user_id_; object("left_chat_participant", JsonUser(user_id, client_)); object("left_chat_member", JsonUser(user_id, client_)); break; } case td_api::messageChatChangeTitle::ID: { - auto message_change_title = static_cast(message_->content.get()); - object("new_chat_title", message_change_title->title_); + auto content = static_cast(message_->content.get()); + object("new_chat_title", content->title_); break; } case td_api::messageChatChangePhoto::ID: { - auto message_change_photo = static_cast(message_->content.get()); - if (message_change_photo->photo_ == nullptr) { + auto content = static_cast(message_->content.get()); + if (content->photo_ == nullptr) { LOG(ERROR) << "Got empty messageChatChangePhoto"; break; } - object("new_chat_photo", JsonChatPhoto(message_change_photo->photo_.get(), client_)); + object("new_chat_photo", JsonChatPhoto(content->photo_.get(), client_)); break; } case td_api::messageChatDeletePhoto::ID: @@ -1872,20 +1871,20 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { break; } case td_api::messageChatUpgradeTo::ID: { - auto message_chat_upgrade_to = static_cast(message_->content.get()); - auto chat_id = get_supergroup_chat_id(message_chat_upgrade_to->supergroup_id_); + auto content = static_cast(message_->content.get()); + auto chat_id = get_supergroup_chat_id(content->supergroup_id_); object("migrate_to_chat_id", td::JsonLong(chat_id)); break; } case td_api::messageChatUpgradeFrom::ID: { - auto message_chat_upgrade_from = static_cast(message_->content.get()); - auto chat_id = get_basic_group_chat_id(message_chat_upgrade_from->basic_group_id_); + auto content = static_cast(message_->content.get()); + auto chat_id = get_basic_group_chat_id(content->basic_group_id_); object("migrate_from_chat_id", td::JsonLong(chat_id)); break; } case td_api::messagePinMessage::ID: { - auto message_pin_message = static_cast(message_->content.get()); - auto message_id = message_pin_message->message_id_; + auto content = static_cast(message_->content.get()); + auto message_id = content->message_id_; if (message_id > 0) { const MessageInfo *pinned_message = client_->get_message(message_->chat_id, message_id); if (pinned_message != nullptr) { @@ -1901,8 +1900,8 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { case td_api::messagePaymentSuccessful::ID: break; case td_api::messagePaymentSuccessfulBot::ID: { - auto message_payment_sent_bot = static_cast(message_->content.get()); - object("successful_payment", JsonSuccessfulPaymentBot(message_payment_sent_bot)); + auto content = static_cast(message_->content.get()); + object("successful_payment", JsonSuccessfulPaymentBot(content)); break; } case td_api::messageCall::ID: @@ -1935,18 +1934,17 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { break; } - auto message_website_connected = static_cast(message_->content.get()); - if (!message_website_connected->domain_name_.empty()) { - object("connected_website", message_website_connected->domain_name_); + auto content = static_cast(message_->content.get()); + if (!content->domain_name_.empty()) { + object("connected_website", content->domain_name_); } break; } case td_api::messagePassportDataSent::ID: break; case td_api::messagePassportDataReceived::ID: { - auto message_passport_data_received = - static_cast(message_->content.get()); - object("passport_data", JsonPassportData(message_passport_data_received, client_)); + auto content = static_cast(message_->content.get()); + object("passport_data", JsonPassportData(content, client_)); break; } case td_api::messageProximityAlertTriggered::ID: { @@ -7338,7 +7336,8 @@ td::Status Client::process_answer_web_app_query_query(PromisedQueryPtr &query) { resolve_inline_query_results_bot_usernames( std::move(results), std::move(query), - [this, web_app_query_id = web_app_query_id.str()](td::vector> results, PromisedQueryPtr query) { + [this, web_app_query_id = web_app_query_id.str()](td::vector> results, + PromisedQueryPtr query) { CHECK(results.size() == 1); send_request(make_object(web_app_query_id, std::move(results[0])), td::make_unique(std::move(query))); @@ -9327,24 +9326,24 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrcontent_->get_id()) { case td_api::messagePhoto::ID: { - auto message_photo = static_cast(message->content_.get()); - if (message_photo->photo_ == nullptr) { + auto content = static_cast(message->content_.get()); + if (content->photo_ == nullptr) { LOG(ERROR) << "Got empty messagePhoto"; return true; } break; } case td_api::messageChatAddMembers::ID: { - auto message_add_members = static_cast(message->content_.get()); - if (message_add_members->member_user_ids_.empty()) { + auto content = static_cast(message->content_.get()); + if (content->member_user_ids_.empty()) { LOG(ERROR) << "Got empty messageChatAddMembers"; return true; } break; } case td_api::messageChatChangePhoto::ID: { - auto message_change_photo = static_cast(message->content_.get()); - if (message_change_photo->photo_ == nullptr) { + auto content = static_cast(message->content_.get()); + if (content->photo_ == nullptr) { LOG(ERROR) << "Got empty messageChatChangePhoto"; return true; } @@ -9358,8 +9357,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr(message->content_.get()); - auto pinned_message_id = message_pin_message->message_id_; + auto content = static_cast(message->content_.get()); + auto pinned_message_id = content->message_id_; if (pinned_message_id <= 0) { return true; } @@ -9371,10 +9370,9 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr(message->content_.get()); - return proximity_alert_triggered->traveler_id_->get_id() != td_api::messageSenderUser::ID || - proximity_alert_triggered->watcher_id_->get_id() != td_api::messageSenderUser::ID; + auto content = static_cast(message->content_.get()); + return content->traveler_id_->get_id() != td_api::messageSenderUser::ID || + content->watcher_id_->get_id() != td_api::messageSenderUser::ID; } case td_api::messageGameScore::ID: return true; From c278251d8f668aea24ee61618049c83c3217b50c Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 28 Mar 2022 17:15:39 +0300 Subject: [PATCH 11/17] Add web_app_data messages. --- telegram-bot-api/Client.cpp | 23 +++++++++++++++++++++++ telegram-bot-api/Client.h | 1 + 2 files changed, 24 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 1c3a1fe..8955a7c 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1456,6 +1456,20 @@ class Client::JsonPassportData final : public Jsonable { const Client *client_; }; +class Client::JsonWebAppData final : public Jsonable { + public: + explicit JsonWebAppData(const td_api::messageWebAppDataReceived *web_app_data) : web_app_data_(web_app_data) { + } + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("button_text", web_app_data_->button_text_); + object("data", web_app_data_->data_); + } + + private: + const td_api::messageWebAppDataReceived *web_app_data_; +}; + class Client::JsonProximityAlertTriggered final : public Jsonable { public: JsonProximityAlertTriggered(const td_api::messageProximityAlertTriggered *proximity_alert_triggered, @@ -1974,6 +1988,13 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { object("voice_chat_participants_invited", JsonInviteVideoChatParticipants(content, client_)); break; } + case td_api::messageWebAppDataSent::ID: + break; + case td_api::messageWebAppDataReceived::ID: { + auto content = static_cast(message_->content.get()); + object("web_app_data", JsonWebAppData(content)); + break; + } default: UNREACHABLE(); } @@ -9394,6 +9415,8 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Sun, 3 Apr 2022 09:33:40 +0300 Subject: [PATCH 12/17] Add setMyDefaultAdministratorRights. --- telegram-bot-api/Client.cpp | 124 ++++++++++++++++++++++++++---------- telegram-bot-api/Client.h | 5 ++ 2 files changed, 95 insertions(+), 34 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8955a7c..63e3963 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -192,6 +192,7 @@ bool Client::init_methods() { methods_.emplace("getmycommands", &Client::process_get_my_commands_query); methods_.emplace("setmycommands", &Client::process_set_my_commands_query); methods_.emplace("deletemycommands", &Client::process_delete_my_commands_query); + methods_.emplace("setmydefaultadministratorrights", &Client::process_set_my_default_administrator_rights_query); methods_.emplace("getuserprofilephotos", &Client::process_get_user_profile_photos_query); methods_.emplace("sendmessage", &Client::process_send_message_query); methods_.emplace("sendanimation", &Client::process_send_animation_query); @@ -4201,9 +4202,8 @@ void Client::get_chat_member(int64 chat_id, int64 user_id, PromisedQueryPtr quer check_user_no_fail( user_id, std::move(query), [this, chat_id, user_id, on_success = std::move(on_success)](PromisedQueryPtr query) mutable { - send_request( - make_object(chat_id, td_api::make_object(user_id)), - td::make_unique>(std::move(query), std::move(on_success))); + send_request(make_object(chat_id, make_object(user_id)), + td::make_unique>(std::move(query), std::move(on_success))); }); } @@ -5864,6 +5864,50 @@ td::Result>> Client::get_bot_c return std::move(bot_commands); } +td::Result> Client::get_chat_administrator_rights( + JsonValue &&value) { + if (value.type() != JsonValue::Type::Object) { + return Status::Error(400, "ChatAdministratorRights must be an Object"); + } + + auto &object = value.get_object(); + TRY_RESULT(can_manage_chat, get_json_object_bool_field(object, "can_manage_chat")); + TRY_RESULT(can_change_info, get_json_object_bool_field(object, "can_change_info")); + TRY_RESULT(can_post_messages, get_json_object_bool_field(object, "can_post_messages")); + TRY_RESULT(can_edit_messages, get_json_object_bool_field(object, "can_edit_messages")); + TRY_RESULT(can_delete_messages, get_json_object_bool_field(object, "can_delete_messages")); + TRY_RESULT(can_invite_users, get_json_object_bool_field(object, "can_invite_users")); + TRY_RESULT(can_restrict_members, get_json_object_bool_field(object, "can_restrict_members")); + TRY_RESULT(can_pin_messages, get_json_object_bool_field(object, "can_pin_messages")); + TRY_RESULT(can_promote_members, get_json_object_bool_field(object, "can_promote_members")); + TRY_RESULT(can_manage_video_chats, get_json_object_bool_field(object, "can_manage_video_chats")); + TRY_RESULT(is_anonymous, get_json_object_bool_field(object, "is_anonymous")); + return make_object( + can_manage_chat, can_change_info, can_post_messages, can_edit_messages, can_delete_messages, can_invite_users, + can_restrict_members, can_pin_messages, can_promote_members, can_manage_video_chats, is_anonymous); +} + +td::Result> Client::get_chat_administrator_rights( + const Query *query) { + auto rights = query->arg("rights"); + if (rights.empty()) { + return nullptr; + } + + LOG(INFO) << "Parsing JSON object: " << rights; + auto r_value = json_decode(rights); + if (r_value.is_error()) { + LOG(INFO) << "Can't parse JSON object: " << r_value.error(); + return Status::Error(400, "Can't parse ChatAdministratorRights JSON object"); + } + + auto r_rights = get_chat_administrator_rights(r_value.move_as_ok()); + if (r_rights.is_error()) { + return Status::Error(400, PSLICE() << "Can't parse ChatAdministratorRights: " << r_rights.error().message()); + } + return r_rights.move_as_ok(); +} + td::Result> Client::get_mask_position(JsonValue &&value) { if (value.type() != JsonValue::Type::Object) { return Status::Error(400, "MaskPosition must be an Object"); @@ -6694,6 +6738,20 @@ td::Status Client::process_delete_my_commands_query(PromisedQueryPtr &query) { return Status::OK(); } +td::Status Client::process_set_my_default_administrator_rights_query(PromisedQueryPtr &query) { + bool for_channels = to_bool(query->arg("for_channels")); + TRY_RESULT(rights, get_chat_administrator_rights(query.get())); + + if (for_channels) { + send_request(make_object(std::move(rights)), + td::make_unique(std::move(query))); + } else { + send_request(make_object(std::move(rights)), + td::make_unique(std::move(query))); + } + return Status::OK(); +} + td::Status Client::process_get_user_profile_photos_query(PromisedQueryPtr &query) { TRY_RESULT(user_id, get_user_id(query.get())); int32 offset = get_integer_arg(query.get(), "offset", 0, 0); @@ -7751,7 +7809,7 @@ td::Status Client::process_promote_chat_member_query(PromisedQueryPtr &query) { auto is_anonymous = to_bool(query->arg("is_anonymous")); auto status = make_object( td::string(), true, - td_api::make_object( + make_object( can_manage_chat, can_change_info, can_post_messages, can_edit_messages, can_delete_messages, can_invite_users, can_restrict_members, can_pin_messages, can_promote_members, can_manage_video_chats, is_anonymous)); check_chat(chat_id, AccessRights::Write, std::move(query), @@ -7773,10 +7831,9 @@ td::Status Client::process_promote_chat_member_query(PromisedQueryPtr &query) { status->custom_title_ = std::move(administrator->custom_title_); } - send_request( - make_object( - chat_id, td_api::make_object(user_id), std::move(status)), - td::make_unique(std::move(query))); + send_request(make_object( + chat_id, make_object(user_id), std::move(status)), + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7808,7 +7865,7 @@ td::Status Client::process_set_chat_administrator_custom_title_query(PromisedQue administrator->custom_title_ = query->arg("custom_title").str(); send_request(make_object( - chat_id, td_api::make_object(user_id), std::move(administrator)), + chat_id, make_object(user_id), std::move(administrator)), td::make_unique(std::move(query))); }); }); @@ -7821,16 +7878,16 @@ td::Status Client::process_ban_chat_member_query(PromisedQueryPtr &query) { int32 until_date = get_integer_arg(query.get(), "until_date", 0); auto revoke_messages = to_bool(query->arg("revoke_messages")); - check_chat(chat_id, AccessRights::Write, std::move(query), - [this, user_id, until_date, revoke_messages](int64 chat_id, PromisedQueryPtr query) { - check_user_no_fail(user_id, std::move(query), - [this, chat_id, user_id, until_date, revoke_messages](PromisedQueryPtr query) { - send_request(make_object( - chat_id, td_api::make_object(user_id), - until_date, revoke_messages), - td::make_unique(std::move(query))); - }); - }); + check_chat( + chat_id, AccessRights::Write, std::move(query), + [this, user_id, until_date, revoke_messages](int64 chat_id, PromisedQueryPtr query) { + check_user_no_fail( + user_id, std::move(query), [this, chat_id, user_id, until_date, revoke_messages](PromisedQueryPtr query) { + send_request(make_object(chat_id, make_object(user_id), + until_date, revoke_messages), + td::make_unique(std::move(query))); + }); + }); return Status::OK(); } @@ -7863,7 +7920,7 @@ td::Status Client::process_restrict_chat_member_query(PromisedQueryPtr &query) { } send_request(make_object( - chat_id, td_api::make_object(user_id), + chat_id, make_object(user_id), make_object( is_chat_member(chat_member->status_), until_date, std::move(permissions))), td::make_unique(std::move(query))); @@ -7895,14 +7952,14 @@ td::Status Client::process_unban_chat_member_query(PromisedQueryPtr &query) { } send_request(make_object( - chat_id, td_api::make_object(user_id), + chat_id, make_object(user_id), make_object()), td::make_unique(std::move(query))); }); } else { check_user_no_fail(user_id, std::move(query), [this, chat_id, user_id](PromisedQueryPtr query) { send_request(make_object( - chat_id, td_api::make_object(user_id), + chat_id, make_object(user_id), make_object()), td::make_unique(std::move(query))); }); @@ -7920,11 +7977,10 @@ td::Status Client::process_ban_chat_sender_chat_query(PromisedQueryPtr &query) { [this, sender_chat_id = sender_chat_id.str(), until_date](int64 chat_id, PromisedQueryPtr query) { check_chat_no_fail(sender_chat_id, std::move(query), [this, chat_id, until_date](int64 sender_chat_id, PromisedQueryPtr query) { - send_request( - make_object( - chat_id, td_api::make_object(sender_chat_id), - until_date, false), - td::make_unique(std::move(query))); + send_request(make_object( + chat_id, make_object(sender_chat_id), + until_date, false), + td::make_unique(std::move(query))); }); }); return Status::OK(); @@ -7936,13 +7992,13 @@ td::Status Client::process_unban_chat_sender_chat_query(PromisedQueryPtr &query) check_chat(chat_id, AccessRights::Write, std::move(query), [this, sender_chat_id = sender_chat_id.str()](int64 chat_id, PromisedQueryPtr query) { - check_chat_no_fail( - sender_chat_id, std::move(query), [this, chat_id](int64 sender_chat_id, PromisedQueryPtr query) { - send_request(make_object( - chat_id, td_api::make_object(sender_chat_id), - make_object()), - td::make_unique(std::move(query))); - }); + check_chat_no_fail(sender_chat_id, std::move(query), + [this, chat_id](int64 sender_chat_id, PromisedQueryPtr query) { + send_request(make_object( + chat_id, make_object(sender_chat_id), + make_object()), + td::make_unique(std::move(query))); + }); }); return Status::OK(); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 10ce589..dcace30 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -365,6 +365,10 @@ class Client final : public WebhookActor::Callback { static td::Result>> get_bot_commands(const Query *query); + static td::Result> get_chat_administrator_rights(td::JsonValue &&value); + + static td::Result> get_chat_administrator_rights(const Query *query); + static td::Result> get_mask_position(const Query *query, Slice field_name); static td::Result> get_mask_position(td::JsonValue &&value); @@ -448,6 +452,7 @@ class Client final : public WebhookActor::Callback { Status process_get_me_query(PromisedQueryPtr &query); Status process_get_my_commands_query(PromisedQueryPtr &query); Status process_set_my_commands_query(PromisedQueryPtr &query); + Status process_set_my_default_administrator_rights_query(PromisedQueryPtr &query); Status process_delete_my_commands_query(PromisedQueryPtr &query); Status process_get_user_profile_photos_query(PromisedQueryPtr &query); Status process_send_message_query(PromisedQueryPtr &query); From 2989274f1f9b8d9d9992871be37df79592dd2dea Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 3 Apr 2022 13:29:57 +0300 Subject: [PATCH 13/17] Add getMyDefaultAdministratorRights. --- telegram-bot-api/Client.cpp | 90 ++++++++++++++++++++++++++++++------- telegram-bot-api/Client.h | 6 +++ 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 63e3963..b81c6cc 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -192,6 +192,7 @@ bool Client::init_methods() { methods_.emplace("getmycommands", &Client::process_get_my_commands_query); methods_.emplace("setmycommands", &Client::process_set_my_commands_query); methods_.emplace("deletemycommands", &Client::process_delete_my_commands_query); + methods_.emplace("getmydefaultadministratorrights", &Client::process_get_my_default_administrator_rights_query); methods_.emplace("setmydefaultadministratorrights", &Client::process_set_my_default_administrator_rights_query); methods_.emplace("getuserprofilephotos", &Client::process_get_user_profile_photos_query); methods_.emplace("sendmessage", &Client::process_send_message_query); @@ -2292,6 +2293,23 @@ class Client::JsonBotCommand final : public Jsonable { const td_api::botCommand *command_; }; +class Client::JsonChatAdministratorRights final : public Jsonable { + public: + JsonChatAdministratorRights(const td_api::chatAdministratorRights *rights, Client::ChatType chat_type) + : rights_(rights), chat_type_(chat_type) { + } + + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + td_api::chatAdministratorRights empty_rights; + Client::json_store_administrator_rights(object, rights_ == nullptr ? &empty_rights : rights_, chat_type_); + } + + private: + const td_api::chatAdministratorRights *rights_; + Client::ChatType chat_type_; +}; + class Client::JsonChatPhotos final : public Jsonable { public: JsonChatPhotos(const td_api::chatPhotos *photos, const Client *client) : photos_(photos), client_(client) { @@ -2342,25 +2360,11 @@ class Client::JsonChatMember final : public Jsonable { case td_api::chatMemberStatusAdministrator::ID: { auto administrator = static_cast(member_->status_.get()); object("can_be_edited", td::JsonBool(administrator->can_be_edited_)); - object("can_manage_chat", td::JsonBool(administrator->rights_->can_manage_chat_)); - object("can_change_info", td::JsonBool(administrator->rights_->can_change_info_)); - if (chat_type_ == Client::ChatType::Channel) { - object("can_post_messages", td::JsonBool(administrator->rights_->can_post_messages_)); - object("can_edit_messages", td::JsonBool(administrator->rights_->can_edit_messages_)); - } - object("can_delete_messages", td::JsonBool(administrator->rights_->can_delete_messages_)); - object("can_invite_users", td::JsonBool(administrator->rights_->can_invite_users_)); - object("can_restrict_members", td::JsonBool(administrator->rights_->can_restrict_members_)); - if (chat_type_ == Client::ChatType::Group || chat_type_ == Client::ChatType::Supergroup) { - object("can_pin_messages", td::JsonBool(administrator->rights_->can_pin_messages_)); - } - object("can_promote_members", td::JsonBool(administrator->rights_->can_promote_members_)); + Client::json_store_administrator_rights(object, administrator->rights_.get(), chat_type_); object("can_manage_voice_chats", td::JsonBool(administrator->rights_->can_manage_video_chats_)); - object("can_manage_video_chats", td::JsonBool(administrator->rights_->can_manage_video_chats_)); if (!administrator->custom_title_.empty()) { object("custom_title", administrator->custom_title_); } - object("is_anonymous", td::JsonBool(administrator->rights_->is_anonymous_)); break; } case td_api::chatMemberStatusMember::ID: @@ -3335,6 +3339,36 @@ class Client::TdOnGetMyCommandsCallback final : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnGetMyDefaultAdministratorRightsCallback final : public TdQueryCallback { + public: + TdOnGetMyDefaultAdministratorRightsCallback(bool for_channels, PromisedQueryPtr query) + : for_channels_(for_channels), query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + CHECK(result->get_id() == td_api::userFullInfo::ID); + auto full_info = move_object_as(result); + if (full_info->bot_info_ == nullptr) { + LOG(ERROR) << "Have no bot info for self"; + return fail_query_with_error(std::move(query_), + make_object(500, "Requested data is inaccessible")); + } + auto bot_info = std::move(full_info->bot_info_); + const auto *rights = for_channels_ ? bot_info->default_channel_administrator_rights_.get() + : bot_info->default_group_administrator_rights_.get(); + answer_query(JsonChatAdministratorRights(rights, for_channels_ ? ChatType::Channel : ChatType::Supergroup), + std::move(query_)); + } + + private: + bool for_channels_; + PromisedQueryPtr query_; +}; + class Client::TdOnGetChatFullInfoCallback final : public TdQueryCallback { public: TdOnGetChatFullInfoCallback(Client *client, int64 chat_id, PromisedQueryPtr query) @@ -6738,6 +6772,13 @@ td::Status Client::process_delete_my_commands_query(PromisedQueryPtr &query) { return Status::OK(); } +td::Status Client::process_get_my_default_administrator_rights_query(PromisedQueryPtr &query) { + bool for_channels = to_bool(query->arg("for_channels")); + send_request(make_object(my_id_), + td::make_unique(for_channels, std::move(query))); + return Status::OK(); +} + td::Status Client::process_set_my_default_administrator_rights_query(PromisedQueryPtr &query) { bool for_channels = to_bool(query->arg("for_channels")); TRY_RESULT(rights, get_chat_administrator_rights(query.get())); @@ -8992,6 +9033,25 @@ void Client::json_store_callback_query_payload(td::JsonObjectScope &object, } } +void Client::json_store_administrator_rights(td::JsonObjectScope &object, const td_api::chatAdministratorRights *rights, + ChatType chat_type) { + object("can_manage_chat", td::JsonBool(rights->can_manage_chat_)); + object("can_change_info", td::JsonBool(rights->can_change_info_)); + if (chat_type == ChatType::Channel) { + object("can_post_messages", td::JsonBool(rights->can_post_messages_)); + object("can_edit_messages", td::JsonBool(rights->can_edit_messages_)); + } + object("can_delete_messages", td::JsonBool(rights->can_delete_messages_)); + object("can_invite_users", td::JsonBool(rights->can_invite_users_)); + object("can_restrict_members", td::JsonBool(rights->can_restrict_members_)); + if (chat_type == ChatType::Group || chat_type == ChatType::Supergroup) { + object("can_pin_messages", td::JsonBool(rights->can_pin_messages_)); + } + object("can_promote_members", td::JsonBool(rights->can_promote_members_)); + object("can_manage_video_chats", td::JsonBool(rights->can_manage_video_chats_)); + object("is_anonymous", td::JsonBool(rights->is_anonymous_)); +} + void Client::json_store_permissions(td::JsonObjectScope &object, const td_api::chatPermissions *permissions) { object("can_send_messages", td::JsonBool(permissions->can_send_messages_)); object("can_send_media_messages", td::JsonBool(permissions->can_send_media_messages_)); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index dcace30..fe340c6 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -134,6 +134,7 @@ class Client final : public WebhookActor::Callback { class JsonShippingQuery; class JsonPreCheckoutQuery; class JsonBotCommand; + class JsonChatAdministratorRights; class JsonChatPhotos; class JsonChatMember; class JsonChatMembers; @@ -175,6 +176,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetCallbackQueryMessageCallback; class TdOnGetStickerSetCallback; class TdOnGetMyCommandsCallback; + class TdOnGetMyDefaultAdministratorRightsCallback; class TdOnGetChatFullInfoCallback; class TdOnGetChatStickerSetCallback; class TdOnGetChatPinnedMessageCallback; @@ -452,6 +454,7 @@ class Client final : public WebhookActor::Callback { Status process_get_me_query(PromisedQueryPtr &query); Status process_get_my_commands_query(PromisedQueryPtr &query); Status process_set_my_commands_query(PromisedQueryPtr &query); + Status process_get_my_default_administrator_rights_query(PromisedQueryPtr &query); Status process_set_my_default_administrator_rights_query(PromisedQueryPtr &query); Status process_delete_my_commands_query(PromisedQueryPtr &query); Status process_get_user_profile_photos_query(PromisedQueryPtr &query); @@ -733,6 +736,9 @@ class Client final : public WebhookActor::Callback { static void json_store_callback_query_payload(td::JsonObjectScope &object, const td_api::CallbackQueryPayload *payload); + static void json_store_administrator_rights(td::JsonObjectScope &object, + const td_api::chatAdministratorRights *rights, ChatType chat_type); + static void json_store_permissions(td::JsonObjectScope &object, const td_api::chatPermissions *permissions); void remove_replies_to_message(int64 chat_id, int64 reply_to_message_id, bool only_from_cache); From 84199e5328fa709428b929e8e11fcc4974e438bd Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 8 Apr 2022 03:07:52 +0300 Subject: [PATCH 14/17] Add getChatMenuButton. --- telegram-bot-api/Client.cpp | 54 ++++++++++++++++++++++++++++++++++++- telegram-bot-api/Client.h | 5 +++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index b81c6cc..bed4440 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -194,6 +194,7 @@ bool Client::init_methods() { methods_.emplace("deletemycommands", &Client::process_delete_my_commands_query); methods_.emplace("getmydefaultadministratorrights", &Client::process_get_my_default_administrator_rights_query); methods_.emplace("setmydefaultadministratorrights", &Client::process_set_my_default_administrator_rights_query); + methods_.emplace("getchatmenubutton", &Client::process_get_chat_menu_button_query); methods_.emplace("getuserprofilephotos", &Client::process_get_user_profile_photos_query); methods_.emplace("sendmessage", &Client::process_send_message_query); methods_.emplace("sendanimation", &Client::process_send_animation_query); @@ -2293,6 +2294,25 @@ class Client::JsonBotCommand final : public Jsonable { const td_api::botCommand *command_; }; +class Client::JsonBotMenuButton final : public Jsonable { + public: + explicit JsonBotMenuButton(const td_api::botMenuButton *menu_button) : menu_button_(menu_button) { + } + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + if (menu_button_->text_.empty()) { + object("type", menu_button_->url_.empty() ? "commands" : "default"); + } else { + object("type", "web_app"); + object("text", menu_button_->text_); + object("web_app", JsonWebAppInfo(menu_button_->url_)); + } + } + + private: + const td_api::botMenuButton *menu_button_; +}; + class Client::JsonChatAdministratorRights final : public Jsonable { public: JsonChatAdministratorRights(const td_api::chatAdministratorRights *rights, Client::ChatType chat_type) @@ -3369,6 +3389,25 @@ class Client::TdOnGetMyDefaultAdministratorRightsCallback final : public TdQuery PromisedQueryPtr query_; }; +class Client::TdOnGetMenuButtonCallback final : public TdQueryCallback { + public: + explicit TdOnGetMenuButtonCallback(PromisedQueryPtr query) : query_(std::move(query)) { + } + + void on_result(object_ptr result) final { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + CHECK(result->get_id() == td_api::botMenuButton::ID); + auto menu_button = move_object_as(result); + answer_query(JsonBotMenuButton(menu_button.get()), std::move(query_)); + } + + private: + PromisedQueryPtr query_; +}; + class Client::TdOnGetChatFullInfoCallback final : public TdQueryCallback { public: TdOnGetChatFullInfoCallback(Client *client, int64 chat_id, PromisedQueryPtr query) @@ -3860,7 +3899,7 @@ template void Client::check_user_read_access(const UserInfo *user_info, PromisedQueryPtr query, OnSuccess on_success) { CHECK(user_info != nullptr); if (!user_info->have_access) { - return fail_query(400, "Bad Request: have no access to the user", std::move(query)); + // return fail_query(400, "Bad Request: have no access to the user", std::move(query)); } on_success(std::move(query)); } @@ -6793,6 +6832,19 @@ td::Status Client::process_set_my_default_administrator_rights_query(PromisedQue return Status::OK(); } +td::Status Client::process_get_chat_menu_button_query(PromisedQueryPtr &query) { + if (query->has_arg("chat_id")) { + TRY_RESULT(user_id, get_user_id(query.get(), "chat_id")); + check_user(user_id, std::move(query), [this, user_id](PromisedQueryPtr query) { + send_request(make_object(user_id), + td::make_unique(std::move(query))); + }); + } else { + send_request(make_object(0), td::make_unique(std::move(query))); + } + return Status::OK(); +} + td::Status Client::process_get_user_profile_photos_query(PromisedQueryPtr &query) { TRY_RESULT(user_id, get_user_id(query.get())); int32 offset = get_integer_arg(query.get(), "offset", 0, 0); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index fe340c6..d3e9211 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -134,6 +134,7 @@ class Client final : public WebhookActor::Callback { class JsonShippingQuery; class JsonPreCheckoutQuery; class JsonBotCommand; + class JsonBotMenuButton; class JsonChatAdministratorRights; class JsonChatPhotos; class JsonChatMember; @@ -175,6 +176,7 @@ class Client final : public WebhookActor::Callback { class TdOnGetEditedMessageCallback; class TdOnGetCallbackQueryMessageCallback; class TdOnGetStickerSetCallback; + class TdOnGetMenuButtonCallback; class TdOnGetMyCommandsCallback; class TdOnGetMyDefaultAdministratorRightsCallback; class TdOnGetChatFullInfoCallback; @@ -454,9 +456,10 @@ class Client final : public WebhookActor::Callback { Status process_get_me_query(PromisedQueryPtr &query); Status process_get_my_commands_query(PromisedQueryPtr &query); Status process_set_my_commands_query(PromisedQueryPtr &query); + Status process_delete_my_commands_query(PromisedQueryPtr &query); Status process_get_my_default_administrator_rights_query(PromisedQueryPtr &query); Status process_set_my_default_administrator_rights_query(PromisedQueryPtr &query); - Status process_delete_my_commands_query(PromisedQueryPtr &query); + Status process_get_chat_menu_button_query(PromisedQueryPtr &query); Status process_get_user_profile_photos_query(PromisedQueryPtr &query); Status process_send_message_query(PromisedQueryPtr &query); Status process_send_animation_query(PromisedQueryPtr &query); From 7a2f3715f9ba9c122f28b65a547855b0673cfc63 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 8 Apr 2022 04:12:22 +0300 Subject: [PATCH 15/17] Add setChatMenuButton. --- telegram-bot-api/Client.cpp | 66 +++++++++++++++++++++++++++++++++++-- telegram-bot-api/Client.h | 5 +++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index bed4440..5c0a153 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -195,6 +195,7 @@ bool Client::init_methods() { methods_.emplace("getmydefaultadministratorrights", &Client::process_get_my_default_administrator_rights_query); methods_.emplace("setmydefaultadministratorrights", &Client::process_set_my_default_administrator_rights_query); methods_.emplace("getchatmenubutton", &Client::process_get_chat_menu_button_query); + methods_.emplace("setchatmenubutton", &Client::process_set_chat_menu_button_query); methods_.emplace("getuserprofilephotos", &Client::process_get_user_profile_photos_query); methods_.emplace("sendmessage", &Client::process_send_message_query); methods_.emplace("sendanimation", &Client::process_send_animation_query); @@ -4921,7 +4922,7 @@ td::Result> Client::get_keyboard_butt if (has_json_object_field(object, "web_app")) { TRY_RESULT(web_app, get_json_object_field(object, "web_app", JsonValue::Type::Object, false)); auto &web_app_object = web_app.get_object(); - TRY_RESULT(url, get_json_object_string_field(web_app_object, "url")); + TRY_RESULT(url, get_json_object_string_field(web_app_object, "url", false)); return make_object(text, make_object(url)); } @@ -5024,7 +5025,7 @@ td::Result> Client::get_inline_ if (has_json_object_field(object, "web_app")) { TRY_RESULT(web_app, get_json_object_field(object, "web_app", JsonValue::Type::Object, false)); auto &web_app_object = web_app.get_object(); - TRY_RESULT(url, get_json_object_string_field(web_app_object, "url")); + TRY_RESULT(url, get_json_object_string_field(web_app_object, "url", false)); return make_object(text, make_object(url)); } @@ -5937,6 +5938,51 @@ td::Result>> Client::get_bot_c return std::move(bot_commands); } +td::Result> Client::get_bot_menu_button(JsonValue &&value) { + if (value.type() != JsonValue::Type::Object) { + return Status::Error(400, "MenuButton must be an Object"); + } + + auto &object = value.get_object(); + + TRY_RESULT(type, get_json_object_string_field(object, "type", false)); + if (type == "default") { + return td_api::make_object("", "default"); + } + if (type == "commands") { + return nullptr; + } + if (type == "web_app") { + TRY_RESULT(text, get_json_object_string_field(object, "text", false)); + TRY_RESULT(web_app, get_json_object_field(object, "web_app", JsonValue::Type::Object, false)); + auto &web_app_object = web_app.get_object(); + TRY_RESULT(url, get_json_object_string_field(web_app_object, "url", false)); + return td_api::make_object(text, url); + } + + return Status::Error(400, "MenuButton has unsupported type"); +} + +td::Result> Client::get_bot_menu_button(const Query *query) { + auto menu_button = query->arg("menu_button"); + if (menu_button.empty()) { + return td_api::make_object("", "default"); + } + + LOG(INFO) << "Parsing JSON object: " << menu_button; + auto r_value = json_decode(menu_button); + if (r_value.is_error()) { + LOG(INFO) << "Can't parse JSON object: " << r_value.error(); + return Status::Error(400, "Can't parse menu button JSON object"); + } + + auto r_menu_button = get_bot_menu_button(r_value.move_as_ok()); + if (r_menu_button.is_error()) { + return Status::Error(400, PSLICE() << "Can't parse menu button: " << r_menu_button.error().message()); + } + return r_menu_button.move_as_ok(); +} + td::Result> Client::get_chat_administrator_rights( JsonValue &&value) { if (value.type() != JsonValue::Type::Object) { @@ -6845,6 +6891,22 @@ td::Status Client::process_get_chat_menu_button_query(PromisedQueryPtr &query) { return Status::OK(); } +td::Status Client::process_set_chat_menu_button_query(PromisedQueryPtr &query) { + TRY_RESULT(menu_button, get_bot_menu_button(query.get())); + if (query->has_arg("chat_id")) { + TRY_RESULT(user_id, get_user_id(query.get(), "chat_id")); + check_user(user_id, std::move(query), + [this, user_id, menu_button = std::move(menu_button)](PromisedQueryPtr query) mutable { + send_request(make_object(user_id, std::move(menu_button)), + td::make_unique(std::move(query))); + }); + } else { + send_request(make_object(0, std::move(menu_button)), + td::make_unique(std::move(query))); + } + return Status::OK(); +} + td::Status Client::process_get_user_profile_photos_query(PromisedQueryPtr &query) { TRY_RESULT(user_id, get_user_id(query.get())); int32 offset = get_integer_arg(query.get(), "offset", 0, 0); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index d3e9211..5891eb6 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -369,6 +369,10 @@ class Client final : public WebhookActor::Callback { static td::Result>> get_bot_commands(const Query *query); + static td::Result> get_bot_menu_button(const Query *query); + + static td::Result> get_bot_menu_button(td::JsonValue &&value); + static td::Result> get_chat_administrator_rights(td::JsonValue &&value); static td::Result> get_chat_administrator_rights(const Query *query); @@ -460,6 +464,7 @@ class Client final : public WebhookActor::Callback { Status process_get_my_default_administrator_rights_query(PromisedQueryPtr &query); Status process_set_my_default_administrator_rights_query(PromisedQueryPtr &query); Status process_get_chat_menu_button_query(PromisedQueryPtr &query); + Status process_set_chat_menu_button_query(PromisedQueryPtr &query); Status process_get_user_profile_photos_query(PromisedQueryPtr &query); Status process_send_message_query(PromisedQueryPtr &query); Status process_send_animation_query(PromisedQueryPtr &query); From 31d947e9713043ddd7b9f180b6c94070f2810341 Mon Sep 17 00:00:00 2001 From: levlam Date: Sat, 16 Apr 2022 06:13:09 +0300 Subject: [PATCH 16/17] Update version to 6.0. --- CMakeLists.txt | 2 +- telegram-bot-api/telegram-bot-api.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be48be4..ffb73b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 5.7 LANGUAGES CXX) +project(TelegramBotApi VERSION 6.0 LANGUAGES CXX) if (POLICY CMP0069) option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.") diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index a87f0bd..b50abad 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) { auto start_time = td::Time::now(); auto shared_data = std::make_shared(); auto parameters = std::make_unique(); - parameters->version_ = "5.7"; + parameters->version_ = "6.0"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats(); From 0dfcb6153af500277fd9388dac3f10aa01008323 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 18 Apr 2022 01:23:20 +0300 Subject: [PATCH 17/17] Update TDLib and version to 6.0.1. --- CMakeLists.txt | 2 +- td | 2 +- telegram-bot-api/telegram-bot-api.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ffb73b1..b73a401 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 6.0 LANGUAGES CXX) +project(TelegramBotApi VERSION 6.0.1 LANGUAGES CXX) if (POLICY CMP0069) option(TELEGRAM_BOT_API_ENABLE_LTO "Use \"ON\" to enable Link Time Optimization.") diff --git a/td b/td index 054a823..782670c 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 054a823c1a812ee3e038f702c6d8ba3e6974be9c +Subproject commit 782670c7dbf278e0ba07fc7e168f39ac154c7238 diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index b50abad..b1283e9 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -200,7 +200,7 @@ int main(int argc, char *argv[]) { auto start_time = td::Time::now(); auto shared_data = std::make_shared(); auto parameters = std::make_unique(); - parameters->version_ = "6.0"; + parameters->version_ = "6.0.1"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats();