diff --git a/.clang-format b/.clang-format index 78d519b..6ce3c0d 100644 --- a/.clang-format +++ b/.clang-format @@ -92,7 +92,7 @@ PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 -PointerAlignment: Left +PointerAlignment: Right ReflowComments: false # true SortIncludes: false # disabled, because we need case insensitive sort SortUsingDeclarations: false # true diff --git a/CMakeLists.txt b/CMakeLists.txt index f3eed02..56b275e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) -project(TelegramBotApi VERSION 5.0.1 LANGUAGES CXX) +project(TelegramBotApi VERSION 5.1 LANGUAGES CXX) add_subdirectory(td EXCLUDE_FROM_ALL) diff --git a/td b/td index ec5614f..ebeaf7f 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit ec5614fd43c56ba4d6dd7e6a517bc55116ab45cd +Subproject commit ebeaf7f90e733441f417a52dee7920f6b76c8f71 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 86ca45d..d8b943e 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,6 +13,7 @@ #include "td/db/TQueue.h" +#include "td/utils/algorithm.h" #include "td/utils/base64.h" #include "td/utils/filesystem.h" #include "td/utils/HttpUrl.h" @@ -20,7 +21,6 @@ #include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/PathView.h" -#include "td/utils/port/Clocks.h" #include "td/utils/port/path.h" #include "td/utils/port/Stat.h" #include "td/utils/Random.h" @@ -145,6 +145,9 @@ void Client::fail_query_with_error(PromisedQueryPtr query, int32 error_code, Sli break; case 500: prefix = Slice("Internal Server Error"); + if (real_error_message != Slice("Request aborted")) { + LOG(ERROR) << "Receive Internal Server Error: " << real_error_message; + } break; default: LOG(ERROR) << "Unsupported error " << real_error_code << ": " << real_error_message; @@ -232,6 +235,9 @@ bool Client::init_methods() { methods_.emplace("answershippingquery", &Client::process_answer_shipping_query_query); methods_.emplace("answerprecheckoutquery", &Client::process_answer_pre_checkout_query_query); methods_.emplace("exportchatinvitelink", &Client::process_export_chat_invite_link_query); + methods_.emplace("createchatinvitelink", &Client::process_create_chat_invite_link_query); + methods_.emplace("editchatinvitelink", &Client::process_edit_chat_invite_link_query); + methods_.emplace("revokechatinvitelink", &Client::process_revoke_chat_invite_link_query); methods_.emplace("getchat", &Client::process_get_chat_query); methods_.emplace("setchatphoto", &Client::process_set_chat_photo_query); methods_.emplace("deletechatphoto", &Client::process_delete_chat_photo_query); @@ -586,6 +592,30 @@ class Client::JsonChatLocation : public Jsonable { const td_api::chatLocation *chat_location_; }; +class Client::JsonChatInviteLink : public Jsonable { + public: + JsonChatInviteLink(const td_api::chatInviteLink *chat_invite_link, const Client *client) + : chat_invite_link_(chat_invite_link), client_(client) { + } + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("invite_link", chat_invite_link_->invite_link_); + object("creator", JsonUser(chat_invite_link_->creator_user_id_, client_)); + if (chat_invite_link_->expire_date_ != 0) { + object("expire_date", chat_invite_link_->expire_date_); + } + if (chat_invite_link_->member_limit_ != 0) { + object("member_limit", chat_invite_link_->member_limit_); + } + object("is_primary", td::JsonBool(chat_invite_link_->is_primary_)); + object("is_revoked", td::JsonBool(chat_invite_link_->is_revoked_)); + } + + private: + const td_api::chatInviteLink *chat_invite_link_; + const Client *client_; +}; + class Client::JsonMessage : public Jsonable { public: JsonMessage(const MessageInfo *message, bool need_reply, const td::string &source, const Client *client) @@ -752,6 +782,9 @@ class Client::JsonChat : public Jsonable { LOG(ERROR) << "Pinned unknown, inaccessible or deleted message " << pinned_message_id_; } } + if (chat_info->message_auto_delete_time != 0) { + object("message_auto_delete_time", chat_info->message_auto_delete_time); + } } // start custom properties impl @@ -1462,6 +1495,62 @@ class Client::JsonProximityAlertTriggered : public Jsonable { const Client *client_; }; +class Client::JsonVoiceChatStarted : public Jsonable { + public: + explicit JsonVoiceChatStarted(const td_api::messageVoiceChatStarted *voice_chat_started) + : voice_chat_started_(voice_chat_started) { + } + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + } + + private: + const td_api::messageVoiceChatStarted *voice_chat_started_; +}; + +class Client::JsonVoiceChatEnded : public Jsonable { + public: + explicit JsonVoiceChatEnded(const td_api::messageVoiceChatEnded *voice_chat_ended) + : voice_chat_ended_(voice_chat_ended) { + } + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("duration", voice_chat_ended_->duration_); + } + + private: + const td_api::messageVoiceChatEnded *voice_chat_ended_; +}; + +class Client::JsonInviteVoiceChatParticipants : public Jsonable { + public: + JsonInviteVoiceChatParticipants(const td_api::messageInviteVoiceChatParticipants *invite_voice_chat_participants, + const Client *client) + : invite_voice_chat_participants_(invite_voice_chat_participants), client_(client) { + } + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("users", JsonUsers(invite_voice_chat_participants_->user_ids_, client_)); + } + + private: + const td_api::messageInviteVoiceChatParticipants *invite_voice_chat_participants_; + const Client *client_; +}; + +class Client::JsonChatSetTtl : public Jsonable { + public: + explicit JsonChatSetTtl(const td_api::messageChatSetTtl *chat_set_ttl) : chat_set_ttl_(chat_set_ttl) { + } + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("message_auto_delete_time", chat_set_ttl_->ttl_); + } + + private: + const td_api::messageChatSetTtl *chat_set_ttl_; +}; + class Client::JsonCallbackGame : public Jsonable { public: void store(JsonValueScope *scope) const { @@ -1821,8 +1910,11 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { break; case td_api::messageScreenshotTaken::ID: break; - case td_api::messageChatSetTtl::ID: + case td_api::messageChatSetTtl::ID: { + auto content = static_cast(message_->content.get()); + object("message_auto_delete_timer_changed", JsonChatSetTtl(content)); break; + } case td_api::messageUnsupported::ID: break; case td_api::messageContactRegistered::ID: @@ -1858,6 +1950,21 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { object("proximity_alert_triggered", JsonProximityAlertTriggered(content, client_)); break; } + case td_api::messageVoiceChatStarted::ID: { + auto content = static_cast(message_->content.get()); + object("voice_chat_started", JsonVoiceChatStarted(content)); + break; + } + case td_api::messageVoiceChatEnded::ID: { + auto content = static_cast(message_->content.get()); + object("voice_chat_ended", JsonVoiceChatEnded(content)); + break; + } + case td_api::messageInviteVoiceChatParticipants::ID: { + auto content = static_cast(message_->content.get()); + object("voice_chat_participants_invited", JsonInviteVoiceChatParticipants(content, client_)); + break; + } default: UNREACHABLE(); } @@ -1903,10 +2010,12 @@ class Client::JsonMessageId : public Jsonable { class Client::JsonInlineQuery : public Jsonable { public: JsonInlineQuery(int64 inline_query_id, int32 sender_user_id, const td_api::location *user_location, - const td::string &query, const td::string &offset, const Client *client) + const td_api::ChatType *chat_type, const td::string &query, const td::string &offset, + const Client *client) : inline_query_id_(inline_query_id) , sender_user_id_(sender_user_id) , user_location_(user_location) + , chat_type_(chat_type) , query_(query) , offset_(offset) , client_(client) { @@ -1919,6 +2028,35 @@ class Client::JsonInlineQuery : public Jsonable { if (user_location_ != nullptr) { object("location", JsonLocation(user_location_)); } + if (chat_type_ != nullptr) { + auto chat_type = [&] { + switch (chat_type_->get_id()) { + case td_api::chatTypePrivate::ID: { + auto type = static_cast(chat_type_); + if (type->user_id_ == sender_user_id_) { + return "sender"; + } + return "private"; + } + case td_api::chatTypeBasicGroup::ID: + return "group"; + case td_api::chatTypeSupergroup::ID: { + auto type = static_cast(chat_type_); + if (type->is_channel_) { + return "channel"; + } else { + return "supergroup"; + } + } + case td_api::chatTypeSecret::ID: + return ""; + default: + UNREACHABLE(); + return ""; + } + }(); + object("chat_type", chat_type); + } object("query", query_); object("offset", offset_); } @@ -1927,6 +2065,7 @@ class Client::JsonInlineQuery : public Jsonable { int64 inline_query_id_; int32 sender_user_id_; const td_api::location *user_location_; + const td_api::ChatType *chat_type_; const td::string &query_; const td::string &offset_; const Client *client_; @@ -2166,6 +2305,7 @@ class Client::JsonChatMember : 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_)); if (chat_type_ == Client::ChatType::Channel) { object("can_post_messages", td::JsonBool(administrator->can_post_messages_)); @@ -2178,6 +2318,7 @@ class Client::JsonChatMember : public Jsonable { object("can_pin_messages", td::JsonBool(administrator->can_pin_messages_)); } object("can_promote_members", td::JsonBool(administrator->can_promote_members_)); + object("can_manage_voice_chats", td::JsonBool(administrator->can_manage_voice_chats_)); if (!administrator->custom_title_.empty()) { object("custom_title", administrator->custom_title_); } @@ -2252,6 +2393,29 @@ class Client::JsonChatMembers : public Jsonable { const Client *client_; }; +class Client::JsonChatMemberUpdated : public Jsonable { + public: + JsonChatMemberUpdated(const td_api::updateChatMember *update, const Client *client) + : update_(update), client_(client) { + } + void store(JsonValueScope *scope) const { + auto object = scope->enter_object(); + object("chat", JsonChat(update_->chat_id_, false, client_)); + object("from", JsonUser(update_->actor_user_id_, client_)); + object("date", update_->date_); + auto chat_type = client_->get_chat_type(update_->chat_id_); + object("old_chat_member", JsonChatMember(update_->old_chat_member_.get(), chat_type, client_)); + object("new_chat_member", JsonChatMember(update_->new_chat_member_.get(), chat_type, client_)); + if (update_->invite_link_ != nullptr) { + object("invite_link", JsonChatInviteLink(update_->invite_link_.get(), client_)); + } + } + + private: + const td_api::updateChatMember *update_; + const Client *client_; +}; + class Client::JsonGameHighScore : public Jsonable { public: JsonGameHighScore(const td_api::gameHighScore *score, const Client *client) : score_(score), client_(client) { @@ -2507,7 +2671,7 @@ class Client::TdOnAuthorizationCallback : public TdQueryCallback { } LOG(WARNING) << "Logging out due to " << td::oneline(to_string(error)); - client_->log_out(); + client_->log_out(error->message_ == "API_ID_INVALID"); } else if (was_ready) { client_->on_update_authorization_state(); } @@ -2539,7 +2703,7 @@ class Client::TdOnAuthorizationQueryCallback : public TdQueryCallback { fail_query(401, "Unauthorized: Log in failed, logging out due to " + td::oneline(to_string(error)), std::move(query_)); LOG(WARNING) << "Logging out due to " << td::oneline(to_string(error)); - client_->log_out(); + client_->log_out(false); } else { if (client_->authorization_state_->get_id() == td_api::authorizationStateWaitRegistration::ID && !client_->parameters_->allow_users_registration_) { @@ -2547,7 +2711,7 @@ class Client::TdOnAuthorizationQueryCallback : public TdQueryCallback { "Unauthorized: It is not allowed to register users with this api. You can enable it with the " "command line option --allow-users-registration. Logging out", std::move(query_)); - return client_->log_out(); + return client_->log_out(false); } if (send_token_) { answer_query(JsonAuthorizationState(client_->authorization_state_.get(), client_->bot_token_), std::move(query_)); @@ -3375,9 +3539,9 @@ class Client::TdOnGetSupergroupMembersCountCallback : public TdQueryCallback { PromisedQueryPtr query_; }; -class Client::TdOnGenerateChatInviteLinkCallback : public TdQueryCallback { +class Client::TdOnReplacePrimaryChatInviteLinkCallback : public TdQueryCallback { public: - explicit TdOnGenerateChatInviteLinkCallback(PromisedQueryPtr query) : query_(std::move(query)) { + explicit TdOnReplacePrimaryChatInviteLinkCallback(PromisedQueryPtr query) : query_(std::move(query)) { } void on_result(object_ptr result) override { @@ -3394,6 +3558,33 @@ class Client::TdOnGenerateChatInviteLinkCallback : public TdQueryCallback { PromisedQueryPtr query_; }; +class Client::TdOnGetChatInviteLinkCallback : public TdQueryCallback { + public: + TdOnGetChatInviteLinkCallback(const Client *client, PromisedQueryPtr query) + : client_(client), query_(std::move(query)) { + } + + void on_result(object_ptr result) override { + if (result->get_id() == td_api::error::ID) { + return fail_query_with_error(std::move(query_), move_object_as(result)); + } + + if (result->get_id() == td_api::chatInviteLink::ID) { + auto invite_link = move_object_as(result); + return answer_query(JsonChatInviteLink(invite_link.get(), client_), std::move(query_)); + } else { + CHECK(result->get_id() == td_api::chatInviteLinks::ID); + auto invite_links = move_object_as(result); + CHECK(!invite_links->invite_links_.empty()); + return answer_query(JsonChatInviteLink(invite_links->invite_links_[0].get(), client_), std::move(query_)); + } + } + + private: + const Client *client_; + PromisedQueryPtr query_; +}; + class Client::TdOnGetGameHighScoresCallback : public TdQueryCallback { public: TdOnGetGameHighScoresCallback(const Client *client, PromisedQueryPtr query) @@ -3658,7 +3849,8 @@ void Client::close() { } } -void Client::log_out() { +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()); } @@ -3704,7 +3896,7 @@ void Client::start_up() { next_set_webhook_logging_time_ = start_time_; next_webhook_is_not_modified_warning_time_ = start_time_; previous_get_updates_start_time_ = start_time_ - 100; - previous_get_updates_finish_time_ = start_time_ - 100; + next_get_updates_conflict_time_ = start_time_ - 100; sticker_set_names_[GREAT_MINDS_SET_ID] = GREAT_MINDS_SET_NAME.str(); @@ -4069,11 +4261,16 @@ void Client::check_message(Slice chat_id_str, int64 message_id, bool allow_empty check_chat(chat_id_str, access_rights, std::move(query), [this, message_id, allow_empty, message_type, on_success = std::move(on_success)]( int64 chat_id, PromisedQueryPtr query) mutable { - if (!have_message_access(chat_id)) { + if ((message_id <= 0 && !allow_empty) || !have_message_access(chat_id)) { return fail_query_with_error(std::move(query), 400, "MESSAGE_NOT_FOUND", PSLICE() << message_type << " not found"); } + if (message_id <= 0) { + CHECK(allow_empty); + return on_success(chat_id, 0, std::move(query)); + } + send_request(make_object(chat_id, message_id), std::make_unique>( this, chat_id, allow_empty, message_type, std::move(query), std::move(on_success))); @@ -4227,7 +4424,8 @@ void Client::get_chat_member(int64 chat_id, int32 user_id, PromisedQueryPtr quer void Client::send_request(object_ptr &&f, std::unique_ptr handler) { if (logging_out_) { - return handler->on_result(make_object(LOGGING_OUT_ERROR_CODE, LOGGING_OUT_ERROR_DESCRIPTION.str())); + return handler->on_result( + make_object(LOGGING_OUT_ERROR_CODE, get_logging_out_error_description().str())); } if (closing_) { return handler->on_result(make_object(CLOSING_ERROR_CODE, CLOSING_ERROR_DESCRIPTION.str())); @@ -4265,7 +4463,7 @@ void Client::on_update_file(object_ptr file) { // also includes all 5xx and 429 errors auto error = Status::Error(400, "Bad Request: wrong file_id or the file is temporarily unavailable"); if (logging_out_) { - error = Status::Error(LOGGING_OUT_ERROR_CODE, LOGGING_OUT_ERROR_DESCRIPTION); + error = Status::Error(LOGGING_OUT_ERROR_CODE, get_logging_out_error_description()); } if (closing_) { error = Status::Error(CLOSING_ERROR_CODE, CLOSING_ERROR_DESCRIPTION); @@ -4333,7 +4531,7 @@ void Client::on_update_authorization_state() { parameters->api_hash_ = parameters_->api_hash_; parameters->system_language_code_ = "en"; parameters->device_model_ = "server"; - parameters->application_version_ = "5.0.1"; + parameters->application_version_ = "5.1"; parameters->enable_storage_optimizer_ = true; parameters->ignore_file_names_ = true; @@ -4393,7 +4591,7 @@ void Client::on_update_authorization_state() { case td_api::authorizationStateClosed::ID: return on_closed(); default: - return log_out(); // just in case + return log_out(false); // just in case } } @@ -4490,33 +4688,32 @@ void Client::on_update(object_ptr result) { bool need_warning = false; switch (chat->type_->get_id()) { case td_api::chatTypePrivate::ID: { - auto info = move_object_as(chat->type_); + auto type = move_object_as(chat->type_); chat_info->type = ChatInfo::Type::Private; - auto user_id = info->user_id_; + auto user_id = type->user_id_; chat_info->user_id = user_id; need_warning = get_user_info(user_id) == nullptr; break; } case td_api::chatTypeBasicGroup::ID: { - auto info = move_object_as(chat->type_); + auto type = move_object_as(chat->type_); chat_info->type = ChatInfo::Type::Group; - auto group_id = info->basic_group_id_; + auto group_id = type->basic_group_id_; chat_info->group_id = group_id; need_warning = get_group_info(group_id) == nullptr; break; } case td_api::chatTypeSupergroup::ID: { - auto info = move_object_as(chat->type_); + auto type = move_object_as(chat->type_); chat_info->type = ChatInfo::Type::Supergroup; - auto supergroup_id = info->supergroup_id_; + auto supergroup_id = type->supergroup_id_; chat_info->supergroup_id = supergroup_id; need_warning = get_supergroup_info(supergroup_id) == nullptr; break; } - case td_api::chatTypeSecret::ID: { + case td_api::chatTypeSecret::ID: // unsupported break; - } default: UNREACHABLE(); } @@ -4527,6 +4724,7 @@ void Client::on_update(object_ptr result) { chat_info->title = std::move(chat->title_); chat_info->photo = std::move(chat->photo_); chat_info->permissions = std::move(chat->permissions_); + chat_info->message_auto_delete_time = chat->message_ttl_setting_; break; } case td_api::updateChatTitle::ID: { @@ -4550,6 +4748,13 @@ void Client::on_update(object_ptr result) { chat_info->permissions = std::move(update->permissions_); break; } + case td_api::updateChatMessageTtlSetting::ID: { + auto update = move_object_as(result); + auto chat_info = add_chat(update->chat_id_); + CHECK(chat_info->type != ChatInfo::Type::Unknown); + chat_info->message_auto_delete_time = update->message_ttl_setting_; + break; + } case td_api::updateUser::ID: { auto update = move_object_as(result); add_user(users_, std::move(update->user_)); @@ -4569,8 +4774,11 @@ 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_; - set_group_description(group_id, std::move(update->basic_group_full_info_->description_)); - set_group_invite_link(group_id, std::move(update->basic_group_full_info_->invite_link_)); + auto full_info = std::move(update->basic_group_full_info_); + 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_) + : td::string()); break; } case td_api::updateSupergroup::ID: { @@ -4581,18 +4789,21 @@ void Client::on_update(object_ptr result) { case td_api::updateSupergroupFullInfo::ID: { auto update = move_object_as(result); auto supergroup_id = update->supergroup_id_; - set_supergroup_description(supergroup_id, std::move(update->supergroup_full_info_->description_)); - set_supergroup_invite_link(supergroup_id, std::move(update->supergroup_full_info_->invite_link_)); - set_supergroup_sticker_set_id(supergroup_id, update->supergroup_full_info_->sticker_set_id_); - set_supergroup_can_set_sticker_set(supergroup_id, update->supergroup_full_info_->can_set_sticker_set_); - set_supergroup_slow_mode_delay(supergroup_id, update->supergroup_full_info_->slow_mode_delay_); - set_supergroup_linked_chat_id(supergroup_id, update->supergroup_full_info_->linked_chat_id_); - set_supergroup_location(supergroup_id, std::move(update->supergroup_full_info_->location_)); + auto full_info = std::move(update->supergroup_full_info_); + 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_) + : td::string()); + set_supergroup_sticker_set_id(supergroup_id, full_info->sticker_set_id_); + set_supergroup_can_set_sticker_set(supergroup_id, full_info->can_set_sticker_set_); + set_supergroup_slow_mode_delay(supergroup_id, full_info->slow_mode_delay_); + set_supergroup_linked_chat_id(supergroup_id, full_info->linked_chat_id_); + set_supergroup_location(supergroup_id, std::move(full_info->location_)); break; } case td_api::updateOption::ID: { auto update = move_object_as(result); - auto name = update->name_; + const td::string &name = update->name_; if (name == "my_id") { if (update->value_->get_id() == td_api::optionValueEmpty::ID) { CHECK(logging_out_); @@ -4646,8 +4857,8 @@ void Client::on_update(object_ptr result) { break; case td_api::updateNewInlineQuery::ID: { auto update = move_object_as(result); - add_new_inline_query(update->id_, update->sender_user_id_, std::move(update->user_location_), update->query_, - update->offset_); + add_new_inline_query(update->id_, update->sender_user_id_, std::move(update->user_location_), + std::move(update->chat_type_), update->query_, update->offset_); break; } case td_api::updateNewChosenInlineResult::ID: { @@ -4674,6 +4885,9 @@ void Client::on_update(object_ptr result) { case td_api::updateNewCustomQuery::ID: add_new_custom_query(move_object_as(result)); break; + case td_api::updateChatMember::ID: + add_update_chat_member(move_object_as(result)); + break; default: // we are not interested in this updates break; @@ -4693,6 +4907,10 @@ void Client::on_result(td::uint64 id, object_ptr result) { handlers_.erase(id); } +td::Slice Client::get_logging_out_error_description() const { + return is_api_id_invalid_ ? API_ID_INVALID_ERROR_DESCRIPTION : LOGGING_OUT_ERROR_DESCRIPTION; +} + void Client::on_closed() { LOG(WARNING) << "Closed"; CHECK(logging_out_ || closing_); @@ -4700,7 +4918,7 @@ void Client::on_closed() { td_client_.reset(); int http_status_code = logging_out_ ? LOGGING_OUT_ERROR_CODE : CLOSING_ERROR_CODE; - Slice description = logging_out_ ? LOGGING_OUT_ERROR_DESCRIPTION : CLOSING_ERROR_DESCRIPTION; + Slice description = logging_out_ ? get_logging_out_error_description() : CLOSING_ERROR_DESCRIPTION; if (webhook_set_query_) { fail_query(http_status_code, description, std::move(webhook_set_query_)); } @@ -5568,7 +5786,7 @@ td::Result> Client::get_inlin TRY_RESULT(sticker_file_id, get_json_object_string_field(object, "sticker_file_id", false)); if (input_message_content == nullptr) { - input_message_content = make_object(nullptr, nullptr, 0, 0); + input_message_content = make_object(nullptr, nullptr, 0, 0, td::string()); } return make_object(id, "", sticker_file_id, 0, 0, std::move(reply_markup), std::move(input_message_content)); @@ -5910,16 +6128,23 @@ td::Result>> Cl return std::move(errors); } -td::Result> Client::get_caption(const Query *query) { - JsonValue entities; - auto r_value = json_decode(query->arg("caption_entities")); - if (r_value.is_ok()) { - entities = r_value.move_as_ok(); - } else { - LOG(INFO) << "Can't parse JSON object: " << r_value.error(); +JsonValue Client::get_input_entities(const Query *query, Slice field_name) { + auto entities = query->arg(field_name); + if (!entities.empty()) { + auto r_value = json_decode(entities); + if (r_value.is_ok()) { + return r_value.move_as_ok(); + } + + LOG(INFO) << "Can't parse entities JSON object: " << r_value.error(); } - return get_formatted_text(query->arg("caption").str(), query->arg("parse_mode").str(), std::move(entities)); + return JsonValue(); +} + +td::Result> Client::get_caption(const Query *query) { + return get_formatted_text(query->arg("caption").str(), query->arg("parse_mode").str(), + get_input_entities(query, "caption_entities")); } td::Result> Client::get_text_entity_type(td::JsonObject &object) { @@ -6028,16 +6253,8 @@ td::Result> Client::get_formatted_text } td::Result> Client::get_input_message_text(const Query *query) { - JsonValue entities; - auto r_value = json_decode(query->arg("entities")); - if (r_value.is_ok()) { - entities = r_value.move_as_ok(); - } else { - LOG(INFO) << "Can't parse JSON object: " << r_value.error(); - } - return get_input_message_text(query->arg("text").str(), to_bool(query->arg("disable_web_page_preview")), - query->arg("parse_mode").str(), std::move(entities)); + query->arg("parse_mode").str(), get_input_entities(query, "entities")); } td::Result> Client::get_input_message_text(td::string text, @@ -6432,7 +6649,7 @@ td::Result> Client::get_report_reas } else if (reason == "violence") { result = make_object(); } else { - result = make_object(reason.str()); + result = make_object(); } return std::move(result); } @@ -6580,10 +6797,10 @@ void Client::on_cmd(PromisedQueryPtr query) { } if (logging_out_) { - return fail_query(LOGGING_OUT_ERROR_CODE, LOGGING_OUT_ERROR_DESCRIPTION, std::move(query)); + return fail_query(LOGGING_OUT_ERROR_CODE, get_logging_out_error_description(), std::move(query)); } if (closing_) { - return fail_query(CLOSING_ERROR_CODE, LOGGING_OUT_ERROR_DESCRIPTION, std::move(query)); + return fail_query(CLOSING_ERROR_CODE, CLOSING_ERROR_DESCRIPTION, std::move(query)); } CHECK(was_authorized_); @@ -6708,7 +6925,8 @@ td::Status Client::process_send_sticker_query(PromisedQueryPtr &query) { if (sticker == nullptr) { return Status::Error(400, "There is no sticker in the request"); } - do_send_message(make_object(std::move(sticker), nullptr, 0, 0), std::move(query)); + do_send_message(make_object(std::move(sticker), nullptr, 0, 0, td::string()), + std::move(query)); return Status::OK(); } @@ -6873,15 +7091,9 @@ td::Status Client::process_send_poll_query(PromisedQueryPtr &query) { object_ptr poll_type; auto type = query->arg("type"); if (type == "quiz") { - JsonValue entities; - auto r_value = json_decode(query->arg("explanation_entities")); - if (r_value.is_ok()) { - entities = r_value.move_as_ok(); - } else { - LOG(INFO) << "Can't parse JSON object: " << r_value.error(); - } - TRY_RESULT(explanation, get_formatted_text(query->arg("explanation").str(), - query->arg("explanation_parse_mode").str(), std::move(entities))); + TRY_RESULT(explanation, + get_formatted_text(query->arg("explanation").str(), query->arg("explanation_parse_mode").str(), + get_input_entities(query.get(), "explanation_entities"))); poll_type = make_object(get_integer_arg(query.get(), "correct_option_id", -1), std::move(explanation)); @@ -6975,7 +7187,7 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { std::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, "reply message", std::move(query), std::move(on_success)); + AccessRights::Write, "replied message", std::move(query), std::move(on_success)); }); return Status::OK(); } @@ -7331,12 +7543,51 @@ td::Status Client::process_export_chat_invite_link_query(PromisedQueryPtr &query auto chat_id = query->arg("chat_id"); 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))); + send_request(make_object(chat_id), + std::make_unique(std::move(query))); }); return Status::OK(); } +td::Status Client::process_create_chat_invite_link_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + auto expire_date = get_integer_arg(query.get(), "expire_date", 0, 0); + auto member_limit = get_integer_arg(query.get(), "member_limit", 0, 0, 100000); + + check_chat(chat_id, AccessRights::Write, std::move(query), + [this, expire_date, member_limit](int64 chat_id, PromisedQueryPtr query) { + send_request(make_object(chat_id, expire_date, member_limit), + std::make_unique(this, std::move(query))); + }); + return Status::OK(); +} + +td::Status Client::process_edit_chat_invite_link_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + auto invite_link = query->arg("invite_link"); + auto expire_date = get_integer_arg(query.get(), "expire_date", 0, 0); + auto member_limit = get_integer_arg(query.get(), "member_limit", 0, 0, 100000); + + check_chat(chat_id, AccessRights::Write, std::move(query), + [this, invite_link = invite_link.str(), expire_date, member_limit](int64 chat_id, PromisedQueryPtr query) { + send_request(make_object(chat_id, invite_link, expire_date, member_limit), + std::make_unique(this, std::move(query))); + }); + return Status::OK(); +} + +td::Status Client::process_revoke_chat_invite_link_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + auto invite_link = query->arg("invite_link"); + + 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))); + }); + return Status::OK(); +} + td::Status Client::process_get_chat_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); @@ -7617,6 +7868,7 @@ td::Status Client::process_leave_chat_query(PromisedQueryPtr &query) { td::Status Client::process_promote_chat_member_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); TRY_RESULT(user_id, get_user_id(query.get())); + auto can_manage_chat = to_bool(query->arg("can_manage_chat")); auto can_change_info = to_bool(query->arg("can_change_info")); auto can_post_messages = to_bool(query->arg("can_post_messages")); auto can_edit_messages = to_bool(query->arg("can_edit_messages")); @@ -7625,10 +7877,12 @@ 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_voice_chats = to_bool(query->arg("can_manage_voice_chats")); auto is_anonymous = to_bool(query->arg("is_anonymous")); auto status = make_object( - td::string(), true, can_change_info, can_post_messages, can_edit_messages, can_delete_messages, can_invite_users, - can_restrict_members, can_pin_messages, can_promote_members, is_anonymous); + 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_voice_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); @@ -7691,13 +7945,14 @@ td::Status Client::process_ban_chat_member_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); TRY_RESULT(user_id, get_user_id(query.get())); 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](int64 chat_id, PromisedQueryPtr 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](PromisedQueryPtr query) { - send_request(make_object( - chat_id, user_id, make_object(until_date)), + user_id, std::move(query), + [this, chat_id, user_id, until_date, revoke_messages](PromisedQueryPtr query) { + send_request(make_object(chat_id, user_id, until_date, revoke_messages), std::make_unique(std::move(query))); }); }); @@ -8239,7 +8494,8 @@ td::Status Client::process_report_chat_query(PromisedQueryPtr &query) { check_chat(chat_id, AccessRights::Read, std::move(query), [this, reason = std::move(reason), message_ids = std::move(message_ids)](int64 chat_id, PromisedQueryPtr query) mutable { - send_request(make_object(chat_id, std::move(reason), std::move(message_ids)), + + send_request(make_object(chat_id, std::move(message_ids), std::move(reason), reason->get_id() == td_api::chatReportReasonCustom::ID ? query->arg("reason").str() : td::string()), std::make_unique(std::move(query))); }); return Status::OK(); @@ -8252,10 +8508,10 @@ td::Status Client::process_create_chat_query(PromisedQueryPtr &query) { auto description = query->arg("description"); if (chat_type == "supergroup") { - send_request(make_object(title.str(), false, description.str(), nullptr), + send_request(make_object(title.str(), false, description.str(), nullptr, false), std::make_unique(this, std::move(query))); } else if (chat_type == "channel") { - send_request(make_object(title.str(), true, description.str(), nullptr), + send_request(make_object(title.str(), true, description.str(), nullptr, false), std::make_unique(this, std::move(query))); } else if (chat_type == "group") { TRY_RESULT(initial_members, get_int_array_arg(query.get(), "user_ids")) @@ -8657,7 +8913,7 @@ void Client::do_send_message(object_ptr input_messa std::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, "reply message", std::move(query), std::move(on_success)); + AccessRights::Write, "replied message", std::move(query), std::move(on_success)); }); } @@ -8704,9 +8960,9 @@ void Client::abort_long_poll(bool from_set_webhook) { void Client::fail_query_conflict(Slice message, PromisedQueryPtr &&query) { auto now = td::Time::now_cached(); - if (now >= previous_get_updates_finish_time_) { + if (now >= next_get_updates_conflict_time_) { fail_query(409, message, std::move(query)); - previous_get_updates_finish_time_ = now + 3.0; + next_get_updates_conflict_time_ = now + 3.0; } else { td::create_actor( "FailQueryConflictSleepActor", 3.0, @@ -8798,7 +9054,8 @@ void Client::do_get_updates(int32 offset, int32 limit, int32 timeout, PromisedQu } if (need_warning) { LOG(WARNING) << "Found " << updates.size() << " updates out of " << total_size << " + " << updates.size() - << " after last getUpdates call at " << previous_get_updates_finish_date_; + << " after last getUpdates call " << (td::Time::now() - previous_get_updates_finish_time_) + << " seconds ago"; } else { LOG(DEBUG) << "Found " << updates.size() << " updates out of " << total_size << " from " << from; } @@ -8814,7 +9071,7 @@ void Client::do_get_updates(int32 offset, int32 limit, int32 timeout, PromisedQu long_poll_slot_.set_timeout_at(long_poll_hard_timeout_); return; } - previous_get_updates_finish_date_ = td::Clocks::system(); // local time to output it to the log + 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()); @@ -8852,10 +9109,10 @@ 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_]; - user_info->first_name = user->first_name_; - user_info->last_name = user->last_name_; - user_info->username = user->username_; - user_info->language_code = user->language_code_; + 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_); + user_info->language_code = std::move(user->language_code_); // start custom properties user_info->is_verified = user->is_verified_; @@ -9156,6 +9413,10 @@ Client::Slice Client::get_update_type_name(UpdateType update_type) { return Slice("poll"); case UpdateType::PollAnswer: return Slice("poll_answer"); + case UpdateType::MyChatMember: + return Slice("my_chat_member"); + case UpdateType::ChatMember: + return Slice("chat_member"); default: UNREACHABLE(); return Slice(); @@ -9302,9 +9563,10 @@ void Client::add_update_poll_answer(object_ptr &&updat } void Client::add_new_inline_query(int64 inline_query_id, int32 sender_user_id, object_ptr location, - const td::string &query, const td::string &offset) { + object_ptr chat_type, const td::string &query, + const td::string &offset) { add_update(UpdateType::InlineQuery, - JsonInlineQuery(inline_query_id, sender_user_id, location.get(), query, offset, this), 30, + JsonInlineQuery(inline_query_id, sender_user_id, location.get(), chat_type.get(), query, offset, this), 30, sender_user_id + (static_cast(1) << 33)); } @@ -9426,6 +9688,17 @@ void Client::add_new_custom_query(object_ptr &&que add_update(UpdateType::CustomQuery, JsonCustomJson(query->data_), timeout, 0); } +void Client::add_update_chat_member(object_ptr &&update) { + CHECK(update != nullptr); + auto left_time = update->date_ + 86400 - get_unix_time(); + if (left_time > 0) { + bool is_my = (update->old_chat_member_->user_id_ == my_id_); + auto webhook_queue_id = update->chat_id_ + (static_cast(is_my ? 5 : 6) << 33); + auto update_type = is_my ? UpdateType::MyChatMember : UpdateType::ChatMember; + add_update(update_type, JsonChatMemberUpdated(update.get(), this), left_time, webhook_queue_id); + } +} + td::int32 Client::choose_added_member_id(const td_api::messageChatAddMembers *message_add_members) const { CHECK(message_add_members != nullptr); for (auto &member_user_id : message_add_members->member_user_ids_) { @@ -9450,6 +9723,9 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptrttl_ > 0) { - // return true; - //} +/* + if (message->ttl_ > 0 && message->ttl_expires_in_ == 0) { + return true; + } +*/ + if (message->forward_info_ != nullptr && + message->forward_info_->origin_->get_id() == td_api::messageForwardOriginMessageImport::ID) { + return true; + } switch (message->content_->get_id()) { case td_api::messagePhoto::ID: { @@ -9829,21 +10111,23 @@ void Client::delete_message(int64 chat_id, int64 message_id, bool only_from_cach auto it = messages_.find({chat_id, message_id}); if (it == messages_.end()) { if (yet_unsent_messages_.count({chat_id, message_id}) > 0) { - // yet unsent message is deleted, possible only if we are trying to write to inaccessible supergroup + // yet unsent message is deleted, possible only if we are trying to write to inaccessible supergroup or + // sent message was deleted before added to the chat auto chat_info = get_chat(chat_id); CHECK(chat_info != nullptr); - Status error; - if (chat_info->type != ChatInfo::Type::Supergroup) { - LOG(ERROR) << "Yet unsent message " << message_id << " is deleted in the chat " << chat_id; - error = Status::Error(403, "Forbidden: bot is not a member of the chat"); - } else { + Status error = + Status::Error(500, "Internal Server Error: sent message was immediately deleted and can't be returned"); + if (chat_info->type == ChatInfo::Type::Supergroup) { auto supergroup_info = get_supergroup_info(chat_info->supergroup_id); CHECK(supergroup_info != nullptr); - if (supergroup_info->is_supergroup) { - error = Status::Error(403, "Forbidden: bot is not a member of the supergroup chat"); - } else { - error = Status::Error(403, "Forbidden: bot is not a member of the channel chat"); + if (supergroup_info->status->get_id() == td_api::chatMemberStatusBanned::ID || + supergroup_info->status->get_id() == td_api::chatMemberStatusLeft::ID) { + if (supergroup_info->is_supergroup) { + error = Status::Error(403, "Forbidden: bot is not a member of the supergroup chat"); + } else { + error = Status::Error(403, "Forbidden: bot is not a member of the channel chat"); + } } } @@ -9977,19 +10261,24 @@ Client::FullMessageId Client::add_message(object_ptr &&message, case td_api::messageForwardOriginChat::ID: { auto forward_info = move_object_as(origin); message_info->initial_sender_chat_id = forward_info->sender_chat_id_; - message_info->initial_author_signature = forward_info->author_signature_; + message_info->initial_author_signature = std::move(forward_info->author_signature_); break; } case td_api::messageForwardOriginHiddenUser::ID: { auto forward_info = move_object_as(origin); - message_info->initial_sender_name = forward_info->sender_name_; + message_info->initial_sender_name = std::move(forward_info->sender_name_); break; } case td_api::messageForwardOriginChannel::ID: { auto forward_info = move_object_as(origin); message_info->initial_chat_id = forward_info->chat_id_; message_info->initial_message_id = forward_info->message_id_; - message_info->initial_author_signature = forward_info->author_signature_; + message_info->initial_author_signature = std::move(forward_info->author_signature_); + break; + } + case td_api::messageForwardOriginMessageImport::ID: { + auto forward_info = move_object_as(origin); + message_info->initial_sender_name = std::move(forward_info->sender_name_); break; } default: @@ -10220,6 +10509,7 @@ constexpr Client::Slice Client::MASK_POINTS[MASK_POINTS_SIZE]; constexpr int Client::LOGGING_OUT_ERROR_CODE; constexpr Client::Slice Client::LOGGING_OUT_ERROR_DESCRIPTION; +constexpr Client::Slice Client::API_ID_INVALID_ERROR_DESCRIPTION; constexpr int Client::CLOSING_ERROR_CODE; constexpr Client::Slice Client::CLOSING_ERROR_DESCRIPTION; diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index f9c6a51..eac965d 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -78,6 +78,7 @@ class Client : public WebhookActor::Callback { static constexpr int LOGGING_OUT_ERROR_CODE = 401; static constexpr Slice LOGGING_OUT_ERROR_DESCRIPTION = "Unauthorized"; + static constexpr Slice API_ID_INVALID_ERROR_DESCRIPTION = "Unauthorized: invalid api-id/api-hash"; static constexpr int CLOSING_ERROR_CODE = 500; static constexpr Slice CLOSING_ERROR_DESCRIPTION = "Internal Server Error: restart"; @@ -96,6 +97,7 @@ class Client : public WebhookActor::Callback { class JsonChatPermissions; class JsonChatPhotoInfo; class JsonChatLocation; + class JsonChatInviteLink; class JsonChat; class JsonMessageSender; class JsonAnimation; @@ -140,6 +142,7 @@ class Client : public WebhookActor::Callback { class JsonChatPhotos; class JsonChatMember; class JsonChatMembers; + class JsonChatMemberUpdated; class JsonGameHighScore; class JsonAddress; class JsonOrderInfo; @@ -148,6 +151,10 @@ class Client : public WebhookActor::Callback { class JsonEncryptedCredentials; class JsonPassportData; class JsonProximityAlertTriggered; + class JsonVoiceChatStarted; + class JsonVoiceChatEnded; + class JsonInviteVoiceChatParticipants; + class JsonChatSetTtl; class JsonUpdateTypes; class JsonWebhookInfo; class JsonStickerSet; @@ -185,7 +192,8 @@ class Client : public WebhookActor::Callback { class TdOnGetGroupMembersCallback; class TdOnGetSupergroupMembersCallback; class TdOnGetSupergroupMembersCountCallback; - class TdOnGenerateChatInviteLinkCallback; + class TdOnReplacePrimaryChatInviteLinkCallback; + class TdOnGetChatInviteLinkCallback; class TdOnGetGameHighScoresCallback; class TdOnReturnFileCallback; class TdOnReturnStickerSetCallback; @@ -307,7 +315,8 @@ class Client : public WebhookActor::Callback { void on_result(td::uint64 id, object_ptr result); void on_update_authorization_state(); - void log_out(); + void log_out(bool is_api_id_invalid); + Slice get_logging_out_error_description() const; void on_closed(); void finish_closing(); @@ -382,6 +391,8 @@ class Client : public WebhookActor::Callback { static td::Result>> get_passport_element_errors( const Query *query); + static td::JsonValue get_input_entities(const Query *query, Slice field_name); + static td::Result> get_caption(const Query *query); static td::Result> get_text_entity_type(td::JsonObject &object); @@ -495,6 +506,9 @@ class Client : public WebhookActor::Callback { Status process_answer_shipping_query_query(PromisedQueryPtr &query); Status process_answer_pre_checkout_query_query(PromisedQueryPtr &query); Status process_export_chat_invite_link_query(PromisedQueryPtr &query); + Status process_create_chat_invite_link_query(PromisedQueryPtr &query); + Status process_edit_chat_invite_link_query(PromisedQueryPtr &query); + Status process_revoke_chat_invite_link_query(PromisedQueryPtr &query); Status process_get_chat_query(PromisedQueryPtr &query); Status process_set_chat_photo_query(PromisedQueryPtr &query); Status process_delete_chat_photo_query(PromisedQueryPtr &query); @@ -688,6 +702,7 @@ class Client : public WebhookActor::Callback { enum class Type { Private, Group, Supergroup, Unknown }; Type type = Type::Unknown; td::string title; + int32 message_auto_delete_time = 0; object_ptr photo; object_ptr permissions; union { @@ -832,7 +847,7 @@ class Client : public WebhookActor::Callback { void add_update_poll_answer(object_ptr &&update); void add_new_inline_query(int64 inline_query_id, int32 sender_user_id, object_ptr location, - const td::string &query, const td::string &offset); + object_ptr chat_type, const td::string &query, const td::string &offset); void add_new_chosen_inline_result(int32 sender_user_id, object_ptr location, const td::string &query, const td::string &result_id, @@ -851,6 +866,8 @@ class Client : public WebhookActor::Callback { void add_new_custom_query(object_ptr &&query); + void add_update_chat_member(object_ptr &&update); + // append only before Size enum class UpdateType : int32 { Message, @@ -866,6 +883,8 @@ class Client : public WebhookActor::Callback { PreCheckoutQuery, Poll, PollAnswer, + MyChatMember, + ChatMember, Size }; @@ -893,13 +912,15 @@ class Client : public WebhookActor::Callback { bool have_message_access(int64 chat_id) const; - // by default all 13 update types up to PollAnswer are allowed - static constexpr td::uint32 DEFAULT_ALLOWED_UPDATE_TYPES = ((1 << 13) - 1); + // by default ChatMember updates are disabled + static constexpr td::uint32 DEFAULT_ALLOWED_UPDATE_TYPES = + (1 << static_cast(UpdateType::Size)) - 1 - (1 << static_cast(UpdateType::ChatMember)); object_ptr authorization_state_; bool was_authorized_ = false; bool closing_ = false; bool logging_out_ = false; + bool is_api_id_invalid_ = false; bool need_close_ = false; bool clear_tqueue_ = false; bool waiting_for_auth_input_ = false; @@ -1037,8 +1058,8 @@ class Client : public WebhookActor::Callback { int32 previous_get_updates_offset_ = -1; double previous_get_updates_start_time_ = 0; - double previous_get_updates_finish_date_ = 0; double previous_get_updates_finish_time_ = 0; + double next_get_updates_conflict_time_ = 0; td::uint64 webhook_generation_ = 1; diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index da00240..4fe7edd 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020, Luckydonald (tdlight-telegram-bot-api+code@luckydonald.de) 2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021, Luckydonald (tdlight-telegram-bot-api+code@luckydonald.de) 2020 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -75,7 +75,7 @@ void ClientManager::send(PromisedQueryPtr 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())) { - return fail_query(401, "Unauthorized: unallowed token specified", std::move(query)); + return fail_query(421, "Misdirected Request: unallowed token specified", std::move(query)); } if (query->is_test_dc()) { diff --git a/telegram-bot-api/ClientManager.h b/telegram-bot-api/ClientManager.h index 3885a3a..efe665b 100644 --- a/telegram-bot-api/ClientManager.h +++ b/telegram-bot-api/ClientManager.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/ClientParameters.h b/telegram-bot-api/ClientParameters.h index ec17e54..7a2560b 100644 --- a/telegram-bot-api/ClientParameters.h +++ b/telegram-bot-api/ClientParameters.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/HttpConnection.cpp b/telegram-bot-api/HttpConnection.cpp index ab47f5b..7de8252 100644 --- a/telegram-bot-api/HttpConnection.cpp +++ b/telegram-bot-api/HttpConnection.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/HttpConnection.h b/telegram-bot-api/HttpConnection.h index 8d583db..a4b1160 100644 --- a/telegram-bot-api/HttpConnection.h +++ b/telegram-bot-api/HttpConnection.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/HttpServer.h b/telegram-bot-api/HttpServer.h index 18a5b06..35bf747 100644 --- a/telegram-bot-api/HttpServer.h +++ b/telegram-bot-api/HttpServer.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/HttpStatConnection.cpp b/telegram-bot-api/HttpStatConnection.cpp index e377ca7..922f80e 100644 --- a/telegram-bot-api/HttpStatConnection.cpp +++ b/telegram-bot-api/HttpStatConnection.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/HttpStatConnection.h b/telegram-bot-api/HttpStatConnection.h index fbed6fe..ea4f499 100644 --- a/telegram-bot-api/HttpStatConnection.h +++ b/telegram-bot-api/HttpStatConnection.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Query.cpp b/telegram-bot-api/Query.cpp index adc6a32..bdae447 100644 --- a/telegram-bot-api/Query.cpp +++ b/telegram-bot-api/Query.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Query.h b/telegram-bot-api/Query.h index f1aca57..5491619 100644 --- a/telegram-bot-api/Query.h +++ b/telegram-bot-api/Query.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Stats.cpp b/telegram-bot-api/Stats.cpp index 56dcf4d..86ddae6 100644 --- a/telegram-bot-api/Stats.cpp +++ b/telegram-bot-api/Stats.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/Stats.h b/telegram-bot-api/Stats.h index 2ba728c..2ff2482 100644 --- a/telegram-bot-api/Stats.h +++ b/telegram-bot-api/Stats.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index a4282d6..9a2cf34 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -8,8 +8,6 @@ #include "telegram-bot-api/ClientParameters.h" -#include "td/db/TQueue.h" - #include "td/net/GetHostByNameActor.h" #include "td/net/HttpHeaderCreator.h" #include "td/net/HttpProxy.h" @@ -26,7 +24,6 @@ #include "td/utils/JsonBuilder.h" #include "td/utils/logging.h" #include "td/utils/misc.h" -#include "td/utils/port/Clocks.h" #include "td/utils/port/IPAddress.h" #include "td/utils/port/SocketFd.h" #include "td/utils/Random.h" @@ -253,7 +250,7 @@ void WebhookActor::on_socket_ready_async(td::Result r_fd, td::int6 } void WebhookActor::create_new_connections() { - size_t need_connections = queues_.size(); + size_t need_connections = queue_updates_.size(); if (need_connections > static_cast(max_connections_)) { need_connections = max_connections_; } @@ -382,20 +379,18 @@ 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 from tqueue " << update.id; + LOG(ERROR) << "Receive duplicated event " << update.id << " from tqueue"; continue; } auto &dest = update_map_[update.id]; dest.id_ = update.id; dest.json_ = update.data.str(); - dest.state_ = Update::State::Begin; dest.delay_ = 1; dest.wakeup_at_ = now; CHECK(update.expires_at >= unix_time_now); dest.expires_at_ = update.expires_at; dest.queue_id_ = update.extra; tqueue_offset_ = update.id.next().move_as_ok(); - begin_updates_n_++; if (dest.queue_id_ == 0) { dest.queue_id_ = unique_queue_id_++; @@ -421,9 +416,10 @@ void WebhookActor::load_updates() { } } if (need_warning) { - LOG(WARNING) << "Loaded " << updates.size() << " updates out of " << total_size << ". Have total of " - << update_map_.size() << " loaded in " << queues_.size() << " queues after last error \"" - << last_error_message_ << "\" at " << last_error_date_; + LOG(WARNING) << "Loaded " << updates.size() << " updates out of " << total_size << ". Have " << update_map_.size() + << " updates loaded in " << queue_updates_.size() << " queues after last error \"" + << last_error_message_ << "\" " << (last_error_time_ == 0 ? -1 : td::Time::now() - last_error_time_) + << " seconds ago"; } if (updates.size() == total_size && last_update_was_successful_) { @@ -439,6 +435,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_; update_map_.erase(it); @@ -460,7 +457,12 @@ void WebhookActor::drop_event(td::TQueue::EventId event_id) { void WebhookActor::on_update_ok(td::TQueue::EventId event_id) { last_update_was_successful_ = true; last_success_time_ = td::Time::now(); - VLOG(webhook) << "Receive ok for update " << 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_) + << " seconds"; drop_event(event_id); } @@ -470,6 +472,7 @@ void WebhookActor::on_update_error(td::TQueue::EventId event_id, td::Slice error double now = td::Time::now(); auto it = update_map_.find(event_id); + CHECK(it != update_map_.end()); const int MAX_RETRY_AFTER = 3600; retry_after = td::clamp(retry_after, 0, MAX_RETRY_AFTER); @@ -485,14 +488,13 @@ void WebhookActor::on_update_error(td::TQueue::EventId event_id, td::Slice error return; } auto &update = it->second; - update.state_ = Update::State::Begin; update.delay_ = next_delay; update.wakeup_at_ = now + next_effective_delay; update.fail_count_++; queues_.emplace(update.wakeup_at_, update.queue_id_); VLOG(webhook) << "Delay update " << event_id << " for " << (update.wakeup_at_ - now) << " seconds because of " - << error << " after " << update.fail_count_ << " fails"; - begin_updates_n_++; + << error << " after " << update.fail_count_ << " fails received in " << (now - update.last_send_time_) + << " seconds"; } td::Status WebhookActor::send_update() { @@ -501,10 +503,11 @@ td::Status WebhookActor::send_update() { } if (queues_.empty()) { - return td::Status::Error("No updates"); + return td::Status::Error("No pending updates"); } auto it = queues_.begin(); - if (it->wakeup_at > td::Time::now()) { + auto now = td::Time::now(); + if (it->wakeup_at > now) { relax_wakeup_at(it->wakeup_at, "send_update"); return td::Status::Error("No ready updates"); } @@ -514,6 +517,7 @@ td::Status WebhookActor::send_update() { auto event_id = queue_updates_[queue_id].event_ids.front(); auto &update = update_map_[event_id]; + update.last_send_time_ = now; auto body = td::json_encode(JsonUpdate(update.id_.value(), update.json_)); @@ -533,8 +537,6 @@ td::Status WebhookActor::send_update() { } auto &connection = *Connection::from_list_node(ready_connections_.get()); - begin_updates_n_--; - update.state_ = Update::State::Send; connection.event_id_ = update.id_; VLOG(webhook) << "Send update " << update.id_ << " from queue " << queue_id << " into connection " << connection.id_ @@ -548,11 +550,9 @@ td::Status WebhookActor::send_update() { } void WebhookActor::send_updates() { - VLOG(webhook) << "Have " << begin_updates_n_ << " pending updates to send"; - while (begin_updates_n_ > 0) { - if (send_update().is_error()) { - return; - } + VLOG(webhook) << "Have " << (queues_.size() + update_map_.size() - queue_updates_.size()) << " pending updates in " + << queues_.size() << " queues to send"; + while (send_update().is_ok()) { } } @@ -653,7 +653,7 @@ void WebhookActor::handle(td::unique_ptr response) { void WebhookActor::start_up() { max_loaded_updates_ = max_connections_ * 2; - next_ip_address_resolve_time_ = last_success_time_ = td::Time::now(); + next_ip_address_resolve_time_ = last_success_time_ = td::Time::now() - 3600; active_new_connection_flood_.add_limit(1, 10 * max_connections_); active_new_connection_flood_.add_limit(5, 20 * max_connections_); @@ -749,7 +749,7 @@ void WebhookActor::on_connection_error(td::Status error) { void WebhookActor::on_webhook_error(td::Slice error) { if (was_checked_) { send_closure(callback_, &Callback::webhook_error, td::Status::Error(error)); - last_error_date_ = td::Clocks::system(); // local time to output it to the log + last_error_time_ = td::Time::now(); last_error_message_ = error.str(); } } diff --git a/telegram-bot-api/WebhookActor.h b/telegram-bot-api/WebhookActor.h index f588b3f..49de882 100644 --- a/telegram-bot-api/WebhookActor.h +++ b/telegram-bot-api/WebhookActor.h @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -79,7 +79,7 @@ class WebhookActor : public td::HttpOutboundConnection::Callback { td::string cert_path_; std::shared_ptr parameters_; - double last_error_date_ = 0; + double last_error_time_ = 0; td::string last_error_message_ = ""; bool fix_ip_address_ = false; @@ -94,11 +94,11 @@ class WebhookActor : public td::HttpOutboundConnection::Callback { td::TQueue::EventId id_; td::string json_; td::int32 expires_at_ = 0; + double last_send_time_ = 0; double wakeup_at_ = 0; int delay_ = 0; int fail_count_ = 0; - enum State { Begin, Send } state_ = State::Begin; - td::int64 queue_id_{0}; + td::int64 queue_id_ = 0; }; struct QueueUpdates { @@ -119,8 +119,6 @@ class WebhookActor : public td::HttpOutboundConnection::Callback { } }; - td::int32 begin_updates_n_ = 0; - td::TQueue::EventId tqueue_offset_; std::size_t max_loaded_updates_ = 0; struct EventIdHash { diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index a3d3971..f2f6706 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -1,5 +1,5 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -24,6 +24,7 @@ #include "td/actor/ConcurrentScheduler.h" #include "td/actor/PromiseFuture.h" +#include "td/utils/algorithm.h" #include "td/utils/buffer.h" #include "td/utils/common.h" #include "td/utils/crypto.h" @@ -145,7 +146,8 @@ int main(int argc, char *argv[]) { td::string http_ip_address = "0.0.0.0"; td::string http_stat_ip_address = "0.0.0.0"; td::string log_file_path; - int verbosity_level = 0; + int default_verbosity_level = 0; + int memory_verbosity_level = VERBOSITY_NAME(INFO); td::int64 log_max_file_size = 2000000000; td::string working_directory; td::string temporary_directory; @@ -234,7 +236,10 @@ int main(int argc, char *argv[]) { options.add_option('l', "log", "path to the file where the log will be written", td::OptionParser::parse_string(log_file_path)); - options.add_checked_option('v', "verbosity", "log verbosity level", td::OptionParser::parse_integer(verbosity_level)); + options.add_checked_option('v', "verbosity", "log verbosity level", + td::OptionParser::parse_integer(default_verbosity_level)); + options.add_checked_option('\0', "memory-verbosity", "memory log verbosity level; defaults to 3", + td::OptionParser::parse_integer(memory_verbosity_level)); options.add_checked_option( '\0', "log-max-file-size", PSLICE() << "maximum size of the log file in bytes before it will be auto-rotated (default is " @@ -266,11 +271,17 @@ int main(int argc, char *argv[]) { return td::Status::OK(); }); options.add_check([&] { - if (verbosity_level < 0) { + if (default_verbosity_level < 0) { return td::Status::Error("Wrong verbosity level specified"); } return td::Status::OK(); }); + options.add_check([&] { + if (memory_verbosity_level < 0) { + return td::Status::Error("Wrong memory verbosity level specified"); + } + return td::Status::OK(); + }); auto r_non_options = options.run(argc, argv, 0); if (need_print_usage) { LOG(PLAIN) << options; @@ -286,6 +297,9 @@ int main(int argc, char *argv[]) { public: void append(td::CSlice slice, int log_level) override { if (first_ && log_level <= first_verbosity_level_) { + if (log_level == VERBOSITY_NAME(FATAL) && second_ && VERBOSITY_NAME(FATAL) <= second_verbosity_level_) { + second_->append(slice, VERBOSITY_NAME(ERROR)); + } first_->append(slice, log_level); } if (second_ && log_level <= second_verbosity_level_) { @@ -309,6 +323,14 @@ int main(int argc, char *argv[]) { second_verbosity_level_ = verbosity_level; } + int get_first_verbosity_level() const { + return first_verbosity_level_; + } + + int get_second_verbosity_level() const { + return second_verbosity_level_; + } + void rotate() override { if (first_) { first_->rotate(); @@ -380,11 +402,14 @@ int main(int argc, char *argv[]) { ::td::VERBOSITY_NAME(dns_resolver) = VERBOSITY_NAME(WARNING); - int memory_verbosity_level = td::max(VERBOSITY_NAME(INFO), verbosity_level); - SET_VERBOSITY_LEVEL(memory_verbosity_level); - log.set_first_verbosity_level(verbosity_level); log.set_second_verbosity_level(memory_verbosity_level); + auto set_verbosity_level = [&log, memory_verbosity_level](int new_verbosity_level) { + SET_VERBOSITY_LEVEL(td::max(memory_verbosity_level, new_verbosity_level)); + log.set_first_verbosity_level(new_verbosity_level); + }; + set_verbosity_level(default_verbosity_level); + // LOG(WARNING) << "Bot API server with commit " << td::GitInfo::commit() << ' ' // << (td::GitInfo::is_dirty() ? "(dirty)" : "") << " started"; LOG(WARNING) << "Bot API server started"; @@ -455,20 +480,18 @@ int main(int argc, char *argv[]) { } if (!need_change_verbosity_level.test_and_set()) { - auto current_global_verbosity_level = GET_VERBOSITY_LEVEL(); - SET_VERBOSITY_LEVEL(256 - current_global_verbosity_level); - verbosity_level = 256 - verbosity_level; - log.set_first_verbosity_level(verbosity_level); + if (log.get_first_verbosity_level() == default_verbosity_level) { + // increase default log verbosity level + set_verbosity_level(100); + } else { + // return back verbosity level + set_verbosity_level(default_verbosity_level); + } } auto next_verbosity_level = shared_data->next_verbosity_level_.exchange(-1); if (next_verbosity_level != -1) { - verbosity_level = next_verbosity_level; - memory_verbosity_level = td::max(VERBOSITY_NAME(INFO), verbosity_level); - SET_VERBOSITY_LEVEL(memory_verbosity_level); - - log.set_first_verbosity_level(verbosity_level); - log.set_second_verbosity_level(memory_verbosity_level); + set_verbosity_level(next_verbosity_level); } if (!need_dump_log.test_and_set()) {