From 997a7408c766ea5877c027e50c151c5c67b531f2 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 29 Sep 2021 20:34:21 +0300 Subject: [PATCH 01/11] Update TDLib. --- td | 2 +- telegram-bot-api/HttpServer.h | 5 +++-- telegram-bot-api/WebhookActor.cpp | 8 ++++---- telegram-bot-api/WebhookActor.h | 7 ++++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/td b/td index 0126cec..0208b70 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 0126cec2686e3b95cc1b6dfb5676d364da0e091b +Subproject commit 0208b7058b1c092dc1b5f9a7509359d36a48ba8c diff --git a/telegram-bot-api/HttpServer.h b/telegram-bot-api/HttpServer.h index 976836c..b500bab 100644 --- a/telegram-bot-api/HttpServer.h +++ b/telegram-bot-api/HttpServer.h @@ -11,6 +11,7 @@ #include "td/net/HttpInboundConnection.h" #include "td/net/TcpListener.h" +#include "td/utils/BufferedFd.h" #include "td/utils/FloodControlFast.h" #include "td/utils/format.h" #include "td/utils/logging.h" @@ -64,8 +65,8 @@ class HttpServer : public td::TcpListener::Callback { if (scheduler_id > 0) { scheduler_id--; } - td::create_actor("HttpInboundConnection", std::move(fd), 0, 20, 500, creator_(), - scheduler_id) + td::create_actor("HttpInboundConnection", td::BufferedFd(std::move(fd)), 0, + 20, 500, creator_(), scheduler_id) .release(); } diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index 31e3103..ce51f88 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -156,7 +156,7 @@ td::Status WebhookActor::create_connection() { public: Callback(td::ActorId actor, td::int64 id) : actor_(actor), id_(id) { } - void set_result(td::Result result) override { + void set_result(td::Result> result) override { send_closure(std::move(actor_), &WebhookActor::on_socket_ready_async, std::move(result), id_); CHECK(actor_.empty()); } @@ -195,7 +195,7 @@ td::Status WebhookActor::create_connection() { on_error(r_fd.move_as_error()); return error; } - return create_connection(r_fd.move_as_ok()); + return create_connection(td::BufferedFd(r_fd.move_as_ok())); } td::Result WebhookActor::create_ssl_stream() { @@ -215,7 +215,7 @@ td::Result WebhookActor::create_ssl_stream() { return r_ssl_stream.move_as_ok(); } -td::Status WebhookActor::create_connection(td::SocketFd fd) { +td::Status WebhookActor::create_connection(td::BufferedFd fd) { TRY_RESULT(ssl_stream, create_ssl_stream()); auto id = connections_.create(Connection()); @@ -237,7 +237,7 @@ td::Status WebhookActor::create_connection(td::SocketFd fd) { return td::Status::OK(); } -void WebhookActor::on_socket_ready_async(td::Result r_fd, td::int64 id) { +void WebhookActor::on_socket_ready_async(td::Result> r_fd, td::int64 id) { pending_sockets_.erase(id); if (r_fd.is_ok()) { VLOG(webhook) << "Socket " << id << " is ready"; diff --git a/telegram-bot-api/WebhookActor.h b/telegram-bot-api/WebhookActor.h index 49de882..fa98ddb 100644 --- a/telegram-bot-api/WebhookActor.h +++ b/telegram-bot-api/WebhookActor.h @@ -17,6 +17,7 @@ #include "td/actor/actor.h" #include "td/actor/PromiseFuture.h" +#include "td/utils/BufferedFd.h" #include "td/utils/common.h" #include "td/utils/Container.h" #include "td/utils/FloodControlFast.h" @@ -159,7 +160,7 @@ class WebhookActor : public td::HttpOutboundConnection::Callback { } }; td::Container> pending_sockets_; - td::vector ready_sockets_; + td::vector> ready_sockets_; td::int32 max_connections_ = 0; td::Container connections_; @@ -176,8 +177,8 @@ class WebhookActor : public td::HttpOutboundConnection::Callback { td::Result create_ssl_stream(); td::Status create_connection() TD_WARN_UNUSED_RESULT; - td::Status create_connection(td::SocketFd fd) TD_WARN_UNUSED_RESULT; - void on_socket_ready_async(td::Result r_fd, td::int64 id); + td::Status create_connection(td::BufferedFd fd) TD_WARN_UNUSED_RESULT; + void on_socket_ready_async(td::Result> r_fd, td::int64 id); void create_new_connections(); From 9380c2a3d18a1ca2f513acb809a54b5fac11e68f Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 29 Sep 2021 20:40:18 +0300 Subject: [PATCH 02/11] Log all responses with code < 200. --- telegram-bot-api/Client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ac4ab7d..d9e3b29 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -59,8 +59,8 @@ void Client::fail_query_with_error(PromisedQueryPtr query, int32 error_code, Sli } int32 real_error_code = error_code; Slice real_error_message = error_message; - if (error_code < 300 || error_code == 404) { - if (error_code <= 0) { + if (error_code < 400 || error_code == 404) { + if (error_code < 200) { LOG(ERROR) << "Receive error \"" << real_error_message << "\" with code " << error_code << " from " << *query; } From e715de9e1ce0b2b973dfcca8d7738de205f52500 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 30 Sep 2021 23:23:41 +0300 Subject: [PATCH 03/11] Count number of active clients with a given tqueue_id. --- telegram-bot-api/Client.cpp | 13 ++++++++++--- telegram-bot-api/ClientManager.cpp | 30 +++++++++++++++++++++++++----- telegram-bot-api/ClientManager.h | 3 +++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index d9e3b29..a845eb8 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3499,7 +3499,7 @@ void Client::raw_event(const td::Event::Raw &event) { } void Client::loop() { - if (logging_out_ || closing_ || was_authorized_) { + if (was_authorized_ || logging_out_ || closing_) { while (!cmd_queue_.empty()) { auto query = std::move(cmd_queue_.front()); cmd_queue_.pop(); @@ -4081,6 +4081,7 @@ void Client::on_update_authorization_state() { if (!was_authorized_) { LOG(WARNING) << "Logged in as @" << user_info->username; was_authorized_ = true; + td::send_event(parent_, td::Event::raw(static_cast(this))); update_shared_unix_time_difference(); if (!pending_updates_.empty()) { LOG(INFO) << "Process " << pending_updates_.size() << " pending updates"; @@ -4096,14 +4097,20 @@ void Client::on_update_authorization_state() { if (!logging_out_) { LOG(WARNING) << "Logging out"; logging_out_ = true; + if (was_authorized_ && !closing_) { + td::send_event(parent_, td::Event::raw(nullptr)); + } } - break; + return loop(); case td_api::authorizationStateClosing::ID: if (!closing_) { LOG(WARNING) << "Closing"; closing_ = true; + if (was_authorized_ && !logging_out_) { + td::send_event(parent_, td::Event::raw(nullptr)); + } } - break; + return loop(); case td_api::authorizationStateClosed::ID: return on_closed(); default: diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index d84eccf..c4730a9 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -112,13 +112,17 @@ 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()); + if (active_client_count_.find(tqueue_id) != active_client_count_.end()) { + // return query->set_retry_after_error(1); + } - auto id = clients_.create(ClientInfo{BotStatActor(stat_.actor_id(&stat_)), token, td::ActorOwn()}); + auto id = + clients_.create(ClientInfo{BotStatActor(stat_.actor_id(&stat_)), token, tqueue_id, td::ActorOwn()}); auto *client_info = clients_.get(id); - client_info->client_ = - td::create_actor(PSLICE() << "Client/" << token, actor_shared(this, id), query->token().str(), - query->is_test_dc(), get_tqueue_id(r_user_id.ok(), query->is_test_dc()), parameters_, - client_info->stat_.actor_id(&client_info->stat_)); + client_info->client_ = td::create_actor(PSLICE() << "Client/" << token, actor_shared(this, id), + query->token().str(), query->is_test_dc(), tqueue_id, parameters_, + client_info->stat_.actor_id(&client_info->stat_)); auto method = query->method(); if (method != "deletewebhook" && method != "setwebhook") { @@ -382,6 +386,21 @@ PromisedQueryPtr ClientManager::get_webhook_restore_query(td::Slice token, td::S return PromisedQueryPtr(query.release(), PromiseDeleter(td::PromiseActor>())); } +void ClientManager::raw_event(const td::Event::Raw &event) { + auto id = get_link_token(); + auto *info = clients_.get(id); + CHECK(info != nullptr); + auto &value = active_client_count_[info->tqueue_id_]; + if (event.ptr != nullptr) { + value++; + } else { + CHECK(value > 0); + if (--value == 0) { + active_client_count_.erase(info->tqueue_id_); + } + } +} + void ClientManager::hangup_shared() { auto id = get_link_token(); auto *info = clients_.get(id); @@ -391,6 +410,7 @@ void ClientManager::hangup_shared() { clients_.erase(id); if (close_flag_ && clients_.empty()) { + CHECK(active_client_count_.empty()); close_db(); } } diff --git a/telegram-bot-api/ClientManager.h b/telegram-bot-api/ClientManager.h index 8d0c375..e376490 100644 --- a/telegram-bot-api/ClientManager.h +++ b/telegram-bot-api/ClientManager.h @@ -52,6 +52,7 @@ class ClientManager final : public td::Actor { public: BotStatActor stat_; td::string token_; + td::int64 tqueue_id_; td::ActorOwn client_; }; td::Container clients_; @@ -62,6 +63,7 @@ class ClientManager final : public td::Actor { std::unordered_map token_to_id_; std::unordered_map flood_controls_; + std::unordered_map active_client_count_; bool close_flag_ = false; td::vector> close_promises_; @@ -72,6 +74,7 @@ class ClientManager final : public td::Actor { std::shared_ptr shared_data); void start_up() override; + void raw_event(const td::Event::Raw &event) override; void hangup_shared() override; void close_db(); void finish_close(); From 380e65d47e13857f334d46e3f2b56219ca42ce05 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 1 Oct 2021 14:52:47 +0300 Subject: [PATCH 04/11] Limit number of concurrently sent messages to a chat. --- telegram-bot-api/Client.cpp | 19 +++++++++++++++++++ telegram-bot-api/Client.h | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index a845eb8..8ce433b 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4466,6 +4466,7 @@ void Client::on_closed() { } on_message_send_failed(chat_id, message_id, 0, Status::Error(http_status_code, description)); } + CHECK(yet_unsent_message_count_.empty()); while (!pending_bot_resolve_queries_.empty()) { auto it = pending_bot_resolve_queries_.begin(); @@ -6213,6 +6214,13 @@ td::int64 Client::extract_yet_unsent_message_query_id(int64 chat_id, int64 messa yet_unsent_messages_.erase(yet_unsent_message_it); + auto count_it = yet_unsent_message_count_.find(chat_id); + CHECK(count_it != yet_unsent_message_count_.end()); + CHECK(count_it->second > 0); + if (--count_it->second == 0) { + yet_unsent_message_count_.erase(count_it); + } + if (reply_to_message_id > 0) { auto it = yet_unsent_reply_message_ids_.find({chat_id, reply_to_message_id}); CHECK(it != yet_unsent_reply_message_ids_.end()); @@ -6736,6 +6744,11 @@ td::Status Client::process_send_media_group_query(PromisedQueryPtr &query) { auto on_success = [this, disable_notification, input_message_contents = std::move(input_message_contents), reply_markup = std::move(reply_markup)](int64 chat_id, int64 reply_to_message_id, PromisedQueryPtr query) mutable { + auto it = yet_unsent_message_count_.find(chat_id); + if (it != yet_unsent_message_count_.end() && it->second > MAX_CONCURRENTLY_SENT_CHAT_MESSAGES) { + return query->set_retry_after_error(60); + } + send_request(make_object(chat_id, 0, reply_to_message_id, get_message_send_options(disable_notification), std::move(input_message_contents)), @@ -8001,6 +8014,11 @@ void Client::do_send_message(object_ptr input_messa auto on_success = [this, disable_notification, input_message_content = std::move(input_message_content), reply_markup = std::move(reply_markup)](int64 chat_id, int64 reply_to_message_id, PromisedQueryPtr query) mutable { + auto it = yet_unsent_message_count_.find(chat_id); + if (it != yet_unsent_message_count_.end() && it->second > MAX_CONCURRENTLY_SENT_CHAT_MESSAGES) { + return query->set_retry_after_error(60); + } + send_request(make_object(chat_id, 0, reply_to_message_id, get_message_send_options(disable_notification), std::move(reply_markup), std::move(input_message_content)), @@ -8036,6 +8054,7 @@ void Client::on_sent_message(object_ptr &&message, int64 query_ yet_unsent_message.send_message_query_id = query_id; 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++; } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 58b3624..495e4bd 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -63,6 +63,8 @@ class Client : public WebhookActor::Callback { static constexpr int32 MAX_CERTIFICATE_FILE_SIZE = 3 << 20; static constexpr int32 MAX_DOWNLOAD_FILE_SIZE = 20 << 20; + static constexpr int32 MAX_CONCURRENTLY_SENT_CHAT_MESSAGES = 1000; // some unreasonably big value + static constexpr int32 MESSAGES_CACHE_TIME = 3600; static constexpr std::size_t MIN_PENDING_UPDATES_WARNING = 200; @@ -874,6 +876,8 @@ class Client : public WebhookActor::Callback { }; std::unordered_map yet_unsent_messages_; + std::unordered_map yet_unsent_message_count_; + struct PendingSendMessageQuery { PromisedQueryPtr query; bool is_multisend = false; From 014890d720ec5bf89f1f5e26c1eb8eaa767bda18 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 26 Oct 2021 14:27:03 +0300 Subject: [PATCH 05/11] Explicitly mention that libc++ needs to be installed when clang is used. --- build.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.html b/build.html index 9eebdff..ab82511 100644 --- a/build.html +++ b/build.html @@ -250,7 +250,7 @@ function onOptionsChanged() { pre_text.push('Download and install Git.'); } if (os_linux && linux_distro === 'Other') { - var compiler = use_clang ? 'clang >= 3.4' : 'g++ >= 4.9.2'; + var compiler = use_clang ? 'clang >= 3.4, libc++' : 'g++ >= 4.9.2'; pre_text.push('Install Git, ' + compiler + ', make, CMake >= 3.0.2, OpenSSL-dev, zlib-dev, gperf using your package manager.'); } if (os_freebsd) { From 6aa090a43a5c4cb142dcf970ad2b86fa28408f7b Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 26 Oct 2021 14:28:09 +0300 Subject: [PATCH 06/11] Improve MultiPromiseActorSafe usage. --- telegram-bot-api/ClientManager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index c4730a9..f8b0b81 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -417,12 +417,15 @@ void ClientManager::hangup_shared() { void ClientManager::close_db() { LOG(WARNING) << "Closing databases"; - td::MultiPromiseActorSafe mpromise("close binlogs"); - mpromise.add_promise(td::PromiseCreator::lambda( + td::MultiPromiseActorSafe mpas("close binlogs"); + mpas.add_promise(td::PromiseCreator::lambda( [actor_id = actor_id(this)](td::Unit) { send_closure(actor_id, &ClientManager::finish_close); })); + mpas.set_ignore_errors(true); - parameters_->shared_data_->tqueue_->close(mpromise.get_promise()); - parameters_->shared_data_->webhook_db_->close(mpromise.get_promise()); + auto lock = mpas.get_promise(); + parameters_->shared_data_->tqueue_->close(mpas.get_promise()); + parameters_->shared_data_->webhook_db_->close(mpas.get_promise()); + lock.set_value(td::Unit()); } void ClientManager::finish_close() { From 5130c526767934fb69c2a44f9ed4efcfb0d9f5c8 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 27 Oct 2021 19:43:41 +0300 Subject: [PATCH 07/11] Add is_active to bot statistics. --- telegram-bot-api/ClientManager.cpp | 53 +++++++++++++++--------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index f8b0b81..09a905f 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -200,18 +200,18 @@ void ClientManager::get_stats(td::PromiseActor promise, top_bot_ids.emplace(static_cast(score * 1e9), id); } - sb << stat_.get_description() << "\n"; + sb << stat_.get_description() << '\n'; if (id_filter.empty()) { - sb << "uptime\t" << now - parameters_->start_time_ << "\n"; - sb << "bot_count\t" << clients_.size() << "\n"; - sb << "active_bot_count\t" << active_bot_count << "\n"; + sb << "uptime\t" << now - parameters_->start_time_ << '\n'; + sb << "bot_count\t" << clients_.size() << '\n'; + sb << "active_bot_count\t" << active_bot_count << '\n'; auto r_mem_stat = td::mem_stat(); if (r_mem_stat.is_ok()) { auto mem_stat = r_mem_stat.move_as_ok(); - sb << "rss\t" << td::format::as_size(mem_stat.resident_size_) << "\n"; - sb << "vm\t" << td::format::as_size(mem_stat.virtual_size_) << "\n"; - sb << "rss_peak\t" << td::format::as_size(mem_stat.resident_size_peak_) << "\n"; - sb << "vm_peak\t" << td::format::as_size(mem_stat.virtual_size_peak_) << "\n"; + sb << "rss\t" << td::format::as_size(mem_stat.resident_size_) << '\n'; + sb << "vm\t" << td::format::as_size(mem_stat.virtual_size_) << '\n'; + sb << "rss_peak\t" << td::format::as_size(mem_stat.resident_size_peak_) << '\n'; + sb << "vm_peak\t" << td::format::as_size(mem_stat.virtual_size_peak_) << '\n'; } else { LOG(INFO) << "Failed to get memory statistics: " << r_mem_stat.error(); } @@ -219,16 +219,16 @@ void ClientManager::get_stats(td::PromiseActor promise, ServerCpuStat::update(td::Time::now()); auto cpu_stats = ServerCpuStat::instance().as_vector(td::Time::now()); for (auto &stat : cpu_stats) { - sb << stat.key_ << "\t" << stat.value_ << "\n"; + sb << stat.key_ << "\t" << stat.value_ << '\n'; } - sb << "buffer_memory\t" << td::format::as_size(td::BufferAllocator::get_buffer_mem()) << "\n"; - sb << "active_webhook_connections\t" << WebhookActor::get_total_connections_count() << "\n"; - sb << "active_requests\t" << parameters_->shared_data_->query_count_.load() << "\n"; - sb << "active_network_queries\t" << td::get_pending_network_query_count(*parameters_->net_query_stats_) << "\n"; + sb << "buffer_memory\t" << td::format::as_size(td::BufferAllocator::get_buffer_mem()) << '\n'; + sb << "active_webhook_connections\t" << WebhookActor::get_total_connections_count() << '\n'; + sb << "active_requests\t" << parameters_->shared_data_->query_count_.load() << '\n'; + sb << "active_network_queries\t" << td::get_pending_network_query_count(*parameters_->net_query_stats_) << '\n'; auto stats = stat_.as_vector(now); for (auto &stat : stats) { - sb << stat.key_ << "\t" << stat.value_ << "\n"; + sb << stat.key_ << "\t" << stat.value_ << '\n'; } } @@ -237,22 +237,23 @@ void ClientManager::get_stats(td::PromiseActor promise, CHECK(client_info); auto bot_info = client_info->client_->get_actor_unsafe()->get_bot_info(); - sb << "\n"; - sb << "id\t" << bot_info.id_ << "\n"; - sb << "uptime\t" << now - bot_info.start_time_ << "\n"; - sb << "token\t" << bot_info.token_ << "\n"; - sb << "username\t" << bot_info.username_ << "\n"; - sb << "webhook\t" << bot_info.webhook_ << "\n"; - sb << "has_custom_certificate\t" << bot_info.has_webhook_certificate_ << "\n"; - sb << "head_update_id\t" << bot_info.head_update_id_ << "\n"; - sb << "tail_update_id\t" << bot_info.tail_update_id_ << "\n"; - sb << "pending_update_count\t" << bot_info.pending_update_count_ << "\n"; - sb << "webhook_max_connections\t" << bot_info.webhook_max_connections_ << "\n"; + sb << '\n'; + sb << "id\t" << bot_info.id_ << '\n'; + sb << "uptime\t" << now - bot_info.start_time_ << '\n'; + sb << "token\t" << bot_info.token_ << '\n'; + sb << "username\t" << bot_info.username_ << '\n'; + sb << "is_active\t" << client_info->stat_.is_active(now) << '\n'; + sb << "webhook\t" << bot_info.webhook_ << '\n'; + sb << "has_custom_certificate\t" << bot_info.has_webhook_certificate_ << '\n'; + sb << "head_update_id\t" << bot_info.head_update_id_ << '\n'; + sb << "tail_update_id\t" << bot_info.tail_update_id_ << '\n'; + sb << "pending_update_count\t" << bot_info.pending_update_count_ << '\n'; + sb << "webhook_max_connections\t" << bot_info.webhook_max_connections_ << '\n'; auto stats = client_info->stat_.as_vector(now); for (auto &stat : stats) { if (stat.key_ == "update_count" || stat.key_ == "request_count") { - sb << stat.key_ << "/sec\t" << stat.value_ << "\n"; + sb << stat.key_ << "/sec\t" << stat.value_ << '\n'; } } From 2fa32d7db7422a9b8866818790e145a94c565634 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 4 Nov 2021 13:02:05 +0300 Subject: [PATCH 08/11] Update TDLib to 1.7.9. --- td | 2 +- telegram-bot-api/Client.cpp | 102 ++++++++++++++++++++++-------------- telegram-bot-api/Client.h | 8 +-- 3 files changed, 69 insertions(+), 43 deletions(-) diff --git a/td b/td index 0208b70..7d41d9e 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 0208b7058b1c092dc1b5f9a7509359d36a48ba8c +Subproject commit 7d41d9eaa58a6e0927806283252dc9e74eda5512 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8ce433b..874eebe 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -558,6 +558,9 @@ class Client::JsonChatInviteLink : public Jsonable { void store(JsonValueScope *scope) const { auto object = scope->enter_object(); object("invite_link", chat_invite_link_->invite_link_); + if (!chat_invite_link_->name_.empty()) { + object("name", chat_invite_link_->name_); + } 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_); @@ -565,6 +568,10 @@ class Client::JsonChatInviteLink : public Jsonable { if (chat_invite_link_->member_limit_ != 0) { object("member_limit", chat_invite_link_->member_limit_); } + if (chat_invite_link_->pending_join_request_count_ != 0) { + object("pending_join_request_count", chat_invite_link_->pending_join_request_count_); + } + object("creates_join_request", td::JsonBool(chat_invite_link_->creates_join_request_)); object("is_primary", td::JsonBool(chat_invite_link_->is_primary_)); object("is_revoked", td::JsonBool(chat_invite_link_->is_revoked_)); } @@ -1421,54 +1428,54 @@ class Client::JsonProximityAlertTriggered : public Jsonable { const Client *client_; }; -class Client::JsonVoiceChatScheduled : public Jsonable { +class Client::JsonVideoChatScheduled : public Jsonable { public: - explicit JsonVoiceChatScheduled(const td_api::messageVoiceChatScheduled *voice_chat_scheduled) - : voice_chat_scheduled_(voice_chat_scheduled) { + explicit JsonVideoChatScheduled(const td_api::messageVideoChatScheduled *video_chat_scheduled) + : video_chat_scheduled_(video_chat_scheduled) { } void store(JsonValueScope *scope) const { auto object = scope->enter_object(); - object("start_date", voice_chat_scheduled_->start_date_); + object("start_date", video_chat_scheduled_->start_date_); } private: - const td_api::messageVoiceChatScheduled *voice_chat_scheduled_; + const td_api::messageVideoChatScheduled *video_chat_scheduled_; }; -class Client::JsonVoiceChatStarted : public Jsonable { +class Client::JsonVideoChatStarted : public Jsonable { public: void store(JsonValueScope *scope) const { auto object = scope->enter_object(); } }; -class Client::JsonVoiceChatEnded : public Jsonable { +class Client::JsonVideoChatEnded : public Jsonable { public: - explicit JsonVoiceChatEnded(const td_api::messageVoiceChatEnded *voice_chat_ended) - : voice_chat_ended_(voice_chat_ended) { + explicit JsonVideoChatEnded(const td_api::messageVideoChatEnded *video_chat_ended) + : video_chat_ended_(video_chat_ended) { } void store(JsonValueScope *scope) const { auto object = scope->enter_object(); - object("duration", voice_chat_ended_->duration_); + object("duration", video_chat_ended_->duration_); } private: - const td_api::messageVoiceChatEnded *voice_chat_ended_; + const td_api::messageVideoChatEnded *video_chat_ended_; }; -class Client::JsonInviteVoiceChatParticipants : public Jsonable { +class Client::JsonInviteVideoChatParticipants : public Jsonable { public: - JsonInviteVoiceChatParticipants(const td_api::messageInviteVoiceChatParticipants *invite_voice_chat_participants, + JsonInviteVideoChatParticipants(const td_api::messageInviteVideoChatParticipants *invite_video_chat_participants, const Client *client) - : invite_voice_chat_participants_(invite_voice_chat_participants), client_(client) { + : invite_video_chat_participants_(invite_video_chat_participants), client_(client) { } void store(JsonValueScope *scope) const { auto object = scope->enter_object(); - object("users", JsonUsers(invite_voice_chat_participants_->user_ids_, client_)); + object("users", JsonUsers(invite_video_chat_participants_->user_ids_, client_)); } private: - const td_api::messageInviteVoiceChatParticipants *invite_voice_chat_participants_; + const td_api::messageInviteVideoChatParticipants *invite_video_chat_participants_; const Client *client_; }; @@ -1745,6 +1752,14 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { } break; } + case td_api::messageChatJoinByRequest::ID: { + if (message_->sender_user_id > 0) { + object("new_chat_participant", JsonUser(message_->sender_user_id, client_)); + object("new_chat_member", JsonUser(message_->sender_user_id, client_)); + object("new_chat_members", JsonUsers({message_->sender_user_id}, client_)); + } + break; + } case td_api::messageChatDeleteMember::ID: { auto message_delete_member = static_cast(message_->content.get()); int64 user_id = message_delete_member->user_id_; @@ -1842,6 +1857,9 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { break; case td_api::messageChatSetTheme::ID: break; + case td_api::messageAnimatedEmoji::ID: + UNREACHABLE(); + break; case td_api::messageWebsiteConnected::ID: { auto chat = client_->get_chat(message_->chat_id); if (chat->type != ChatInfo::Type::Private) { @@ -1867,22 +1885,22 @@ void Client::JsonMessage::store(JsonValueScope *scope) const { object("proximity_alert_triggered", JsonProximityAlertTriggered(content, client_)); break; } - case td_api::messageVoiceChatScheduled::ID: { - auto content = static_cast(message_->content.get()); - object("voice_chat_scheduled", JsonVoiceChatScheduled(content)); + case td_api::messageVideoChatScheduled::ID: { + auto content = static_cast(message_->content.get()); + object("voice_chat_scheduled", JsonVideoChatScheduled(content)); break; } - case td_api::messageVoiceChatStarted::ID: - object("voice_chat_started", JsonVoiceChatStarted()); + case td_api::messageVideoChatStarted::ID: + object("voice_chat_started", JsonVideoChatStarted()); break; - case td_api::messageVoiceChatEnded::ID: { - auto content = static_cast(message_->content.get()); - object("voice_chat_ended", JsonVoiceChatEnded(content)); + case td_api::messageVideoChatEnded::ID: { + auto content = static_cast(message_->content.get()); + object("voice_chat_ended", JsonVideoChatEnded(content)); break; } - case td_api::messageInviteVoiceChatParticipants::ID: { - auto content = static_cast(message_->content.get()); - object("voice_chat_participants_invited", JsonInviteVoiceChatParticipants(content, client_)); + case td_api::messageInviteVideoChatParticipants::ID: { + auto content = static_cast(message_->content.get()); + object("voice_chat_participants_invited", JsonInviteVideoChatParticipants(content, client_)); break; } default: @@ -2241,7 +2259,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_)); + object("can_manage_voice_chats", td::JsonBool(administrator->can_manage_video_chats_)); if (!administrator->custom_title_.empty()) { object("custom_title", administrator->custom_title_); } @@ -4960,6 +4978,9 @@ td_api::object_ptr Client::get_chat_action(const Query *quer if (action == "upload_document") { return make_object(); } + if (action == "choose_sticker") { + return make_object(); + } if (action == "pick_up_location" || action == "find_location") { return make_object(); } @@ -7107,12 +7128,14 @@ td::Status Client::process_export_chat_invite_link_query(PromisedQueryPtr &query td::Status Client::process_create_chat_invite_link_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); + auto name = query->arg("name"); 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); + auto creates_join_request = to_bool(query->arg("creates_join_request")); 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), + [this, name = name.str(), expire_date, member_limit, creates_join_request](int64 chat_id, PromisedQueryPtr query) { + send_request(make_object(chat_id, name, expire_date, member_limit, creates_join_request), std::make_unique(this, std::move(query))); }); return Status::OK(); @@ -7121,12 +7144,14 @@ td::Status Client::process_create_chat_invite_link_query(PromisedQueryPtr &query 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 name = query->arg("name"); 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); + auto creates_join_request = to_bool(query->arg("creates_join_request")); 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), + [this, invite_link = invite_link.str(), name = name.str(), expire_date, member_limit, 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))); }); return Status::OK(); @@ -7403,11 +7428,11 @@ 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 can_manage_video_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_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, + 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 { @@ -8833,12 +8858,13 @@ bool Client::need_skip_update_message(int64 chat_id, const object_ptr Date: Thu, 4 Nov 2021 13:35:43 +0300 Subject: [PATCH 09/11] Add "chat_join_request" updates. --- telegram-bot-api/Client.cpp | 50 ++++++++++++++++++++++++++++++++++--- telegram-bot-api/Client.h | 4 +++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 874eebe..46e3c01 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2354,6 +2354,29 @@ class Client::JsonChatMemberUpdated : public Jsonable { const Client *client_; }; +class Client::JsonChatJoinRequest : public Jsonable { + public: + JsonChatJoinRequest(const td_api::updateNewChatJoinRequest *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_->request_->user_id_, client_)); + object("date", update_->request_->date_); + if (!update_->request_->bio_.empty()) { + object("bio", update_->request_->bio_); + } + if (update_->invite_link_ != nullptr) { + object("invite_link", JsonChatInviteLink(update_->invite_link_.get(), client_)); + } + } + + private: + const td_api::updateNewChatJoinRequest *update_; + const Client *client_; +}; + class Client::JsonGameHighScore : public Jsonable { public: JsonGameHighScore(const td_api::gameHighScore *score, const Client *client) : score_(score), client_(client) { @@ -4427,6 +4450,9 @@ void Client::on_update(object_ptr result) { case td_api::updateChatMember::ID: add_update_chat_member(move_object_as(result)); break; + case td_api::updateNewChatJoinRequest::ID: + add_update_chat_join_request(move_object_as(result)); + break; default: // we are not interested in this update break; @@ -7134,8 +7160,10 @@ td::Status Client::process_create_chat_invite_link_query(PromisedQueryPtr &query auto creates_join_request = to_bool(query->arg("creates_join_request")); check_chat(chat_id, AccessRights::Write, std::move(query), - [this, name = name.str(), expire_date, member_limit, creates_join_request](int64 chat_id, PromisedQueryPtr query) { - send_request(make_object(chat_id, name, expire_date, member_limit, creates_join_request), + [this, name = name.str(), expire_date, member_limit, creates_join_request](int64 chat_id, + PromisedQueryPtr query) { + send_request(make_object(chat_id, name, expire_date, member_limit, + creates_join_request), std::make_unique(this, std::move(query))); }); return Status::OK(); @@ -7150,8 +7178,10 @@ td::Status Client::process_edit_chat_invite_link_query(PromisedQueryPtr &query) auto creates_join_request = to_bool(query->arg("creates_join_request")); check_chat(chat_id, AccessRights::Write, std::move(query), - [this, invite_link = invite_link.str(), name = name.str(), expire_date, member_limit, creates_join_request](int64 chat_id, PromisedQueryPtr query) { - send_request(make_object(chat_id, invite_link, name, expire_date, member_limit, creates_join_request), + [this, invite_link = invite_link.str(), name = name.str(), expire_date, member_limit, + 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))); }); return Status::OK(); @@ -8548,6 +8578,8 @@ Client::Slice Client::get_update_type_name(UpdateType update_type) { return Slice("my_chat_member"); case UpdateType::ChatMember: return Slice("chat_member"); + case UpdateType::ChatJoinRequest: + return Slice("chat_join_request"); default: UNREACHABLE(); return Slice(); @@ -8836,6 +8868,16 @@ void Client::add_update_chat_member(object_ptr &&updat } } +void Client::add_update_chat_join_request(object_ptr &&update) { + CHECK(update != nullptr); + CHECK(update->request_ != nullptr); + auto left_time = update->request_->date_ + 86400 - get_unix_time(); + if (left_time > 0) { + auto webhook_queue_id = update->chat_id_ + (static_cast(6) << 33); + add_update(UpdateType::ChatJoinRequest, JsonChatJoinRequest(update.get(), this), left_time, webhook_queue_id); + } +} + td::int64 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_) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index f00e23f..6883e5c 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -139,6 +139,7 @@ class Client : public WebhookActor::Callback { class JsonChatMember; class JsonChatMembers; class JsonChatMemberUpdated; + class JsonChatJoinRequest; class JsonGameHighScore; class JsonAddress; class JsonOrderInfo; @@ -780,6 +781,8 @@ class Client : public WebhookActor::Callback { void add_update_chat_member(object_ptr &&update); + void add_update_chat_join_request(object_ptr &&update); + // append only before Size enum class UpdateType : int32 { Message, @@ -797,6 +800,7 @@ class Client : public WebhookActor::Callback { PollAnswer, MyChatMember, ChatMember, + ChatJoinRequest, Size }; From e2728cba7c47103b0dcdd0fe718e9e726e0577c9 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 4 Nov 2021 14:08:17 +0300 Subject: [PATCH 10/11] Add approve/declineChatJoinRequest. --- telegram-bot-api/Client.cpp | 28 ++++++++++++++++++++++++++++ telegram-bot-api/Client.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 46e3c01..2679149 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -257,6 +257,8 @@ bool Client::init_methods() { methods_.emplace("kickchatmember", &Client::process_ban_chat_member_query); methods_.emplace("restrictchatmember", &Client::process_restrict_chat_member_query); methods_.emplace("unbanchatmember", &Client::process_unban_chat_member_query); + methods_.emplace("approvechatjoinrequest", &Client::process_approve_chat_join_request_query); + methods_.emplace("declinechatjoinrequest", &Client::process_decline_chat_join_request_query); methods_.emplace("getstickerset", &Client::process_get_sticker_set_query); methods_.emplace("uploadstickerfile", &Client::process_upload_sticker_file_query); methods_.emplace("createnewstickerset", &Client::process_create_new_sticker_set_query); @@ -7621,6 +7623,32 @@ td::Status Client::process_unban_chat_member_query(PromisedQueryPtr &query) { return Status::OK(); } +td::Status Client::process_approve_chat_join_request_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + TRY_RESULT(user_id, get_user_id(query.get())); + + 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), + std::make_unique(std::move(query))); + }); + }); + return Status::OK(); +} + +td::Status Client::process_decline_chat_join_request_query(PromisedQueryPtr &query) { + auto chat_id = query->arg("chat_id"); + TRY_RESULT(user_id, get_user_id(query.get())); + + 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), + std::make_unique(std::move(query))); + }); + }); + return Status::OK(); +} + 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)) { diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 6883e5c..4b7f3d0 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -497,6 +497,8 @@ class Client : public WebhookActor::Callback { Status process_ban_chat_member_query(PromisedQueryPtr &query); Status process_restrict_chat_member_query(PromisedQueryPtr &query); Status process_unban_chat_member_query(PromisedQueryPtr &query); + Status process_approve_chat_join_request_query(PromisedQueryPtr &query); + Status process_decline_chat_join_request_query(PromisedQueryPtr &query); Status process_get_sticker_set_query(PromisedQueryPtr &query); Status process_upload_sticker_file_query(PromisedQueryPtr &query); Status process_create_new_sticker_set_query(PromisedQueryPtr &query); From a838756c9a206bb80390c0a99aa4c66d1df6a29f Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 4 Nov 2021 15:51:16 +0300 Subject: [PATCH 11/11] Update version to 5.4. --- 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 e875fcf..95f1aa8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 5.3.3 LANGUAGES CXX) +project(TelegramBotApi VERSION 5.4 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 f6da025..6680c44 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -198,7 +198,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.3.3"; + parameters->version_ = "5.4"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats();