From bcd0c8eaa56920a951e3710671702a049157b706 Mon Sep 17 00:00:00 2001 From: KnorpelSenf Date: Mon, 10 May 2021 17:49:50 +0200 Subject: [PATCH 01/25] Add --version flag (#132) --- telegram-bot-api/telegram-bot-api.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 3e1b02b..693dbb4 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -142,6 +142,7 @@ int main(int argc, char *argv[]) { td::OptionParser options; bool need_print_usage = false; + bool need_print_version = false; int http_port = 8081; int http_stat_port = 0; td::string http_ip_address = "0.0.0.0"; @@ -173,6 +174,7 @@ int main(int argc, char *argv[]) { options.set_usage(td::Slice(argv[0]), "--api-id= --api-hash= [--local] [OPTION]..."); options.set_description("Telegram Bot API server"); options.add_option('h', "help", "display this help text and exit", [&] { need_print_usage = true; }); + options.add_option('\0', "version", "display version number and exit", [&] { need_print_version = true; }); options.add_option('\0', "local", "allow the Bot API server to serve local requests", [&] { parameters->local_mode_ = true; }); options.add_checked_option( @@ -275,6 +277,10 @@ int main(int argc, char *argv[]) { LOG(PLAIN) << options; return 0; } + if (need_print_version) { + LOG(PLAIN) << "Bot API " << parameters->version_; + return 0; + } if (r_non_options.is_error()) { LOG(PLAIN) << argv[0] << ": " << r_non_options.error(); LOG(PLAIN) << options; From f423f426a212d77d1f357baf7c275f49436b31e1 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 10 May 2021 19:02:49 +0300 Subject: [PATCH 02/25] Improve handling of deleted group chats. --- telegram-bot-api/Client.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ae8f08e..f227cb3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3682,9 +3682,7 @@ void Client::check_chat_access(int64 chat_id, AccessRights access_rights, const return fail_query(400, "Bad Request: group chat was upgraded to a supergroup chat", std::move(query), std::move(parameters)); } else { - LOG(WARNING) << "Group chat " << chat_info->group_id << " with " << group_info->member_count - << " members and title \"" << chat_info->title << "\" is deactivated"; - return fail_query(400, "Bad Request: group chat was deactivated", std::move(query)); + return fail_query(403, "Forbidden: the group chat was deleted", std::move(query)); } } if (group_info->is_active && group_info->kicked && need_edit_access) { From 72d8f73dbed3a38289ecef7ab9962af25aff1475 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 10 May 2021 19:44:12 +0300 Subject: [PATCH 03/25] Don't allow to access member list in deactivated groups. --- telegram-bot-api/Client.cpp | 33 ++++++++++++++++----------------- telegram-bot-api/Client.h | 2 +- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index f227cb3..bcc409a 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3672,6 +3672,10 @@ void Client::check_chat_access(int64 chat_id, AccessRights access_rights, const break; } case ChatInfo::Type::Group: { + if (access_rights == AccessRights::ReadMembers) { // member list is inaccessible in deactivated groups + need_write_access = true; + need_edit_access = true; + } auto group_info = get_group_info(chat_info->group_id); CHECK(group_info != nullptr); if (!group_info->is_active && need_write_access) { @@ -7182,31 +7186,29 @@ td::Status Client::process_get_chat_member_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); TRY_RESULT(user_id, get_user_id(query.get())); - check_chat(chat_id, AccessRights::Read, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) { - get_chat_member(chat_id, user_id, std::move(query), - [this, chat_type = get_chat_type(chat_id)](td_api::object_ptr &&chat_member, - PromisedQueryPtr query) { - answer_query(JsonChatMember(chat_member.get(), chat_type, this), std::move(query)); - }); - }); + check_chat(chat_id, AccessRights::ReadMembers, std::move(query), + [this, user_id](int64 chat_id, PromisedQueryPtr query) { + get_chat_member(chat_id, user_id, std::move(query), + [this, chat_type = get_chat_type(chat_id)]( + td_api::object_ptr &&chat_member, PromisedQueryPtr query) { + answer_query(JsonChatMember(chat_member.get(), chat_type, this), std::move(query)); + }); + }); return Status::OK(); } td::Status Client::process_get_chat_administrators_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); - check_chat(chat_id, AccessRights::Read, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { + check_chat(chat_id, AccessRights::ReadMembers, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { auto chat_info = get_chat(chat_id); CHECK(chat_info != nullptr); switch (chat_info->type) { case ChatInfo::Type::Private: return fail_query(400, "Bad Request: there are no administrators in the private chat", std::move(query)); - case ChatInfo::Type::Group: { - auto group_info = get_group_info(chat_info->group_id); - CHECK(group_info != nullptr); + case ChatInfo::Type::Group: return send_request(make_object(chat_info->group_id), std::make_unique(this, true, std::move(query))); - } case ChatInfo::Type::Supergroup: return send_request( make_object( @@ -7223,7 +7225,7 @@ td::Status Client::process_get_chat_administrators_query(PromisedQueryPtr &query td::Status Client::process_get_chat_member_count_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); - check_chat(chat_id, AccessRights::Read, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { + check_chat(chat_id, AccessRights::ReadMembers, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { auto chat_info = get_chat(chat_id); CHECK(chat_info != nullptr); switch (chat_info->type) { @@ -7232,9 +7234,6 @@ td::Status Client::process_get_chat_member_count_query(PromisedQueryPtr &query) case ChatInfo::Type::Group: { auto group_info = get_group_info(chat_info->group_id); CHECK(group_info != nullptr); - if (group_info->member_count == 0) { - return fail_query(403, "Forbidden: bot is not a member of the group chat", std::move(query)); - } return answer_query(td::VirtuallyJsonableInt(group_info->member_count), std::move(query)); } case ChatInfo::Type::Supergroup: @@ -7251,7 +7250,7 @@ td::Status Client::process_get_chat_member_count_query(PromisedQueryPtr &query) td::Status Client::process_leave_chat_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); - check_chat(chat_id, AccessRights::Read, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { + check_chat(chat_id, AccessRights::ReadMembers, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id), std::make_unique(std::move(query))); }); return Status::OK(); diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index fb6fa2a..7b93838 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -212,7 +212,7 @@ class Client : public WebhookActor::Callback { struct UserInfo; struct ChatInfo; - enum class AccessRights { Read, Edit, Write }; + enum class AccessRights { Read, ReadMembers, Edit, Write }; template class TdOnCheckUserCallback; From 7f9e9fd80967ac7ba223e7198857b11c14c29975 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 20 May 2021 23:51:37 +0300 Subject: [PATCH 04/25] Update TDLib. --- td | 2 +- telegram-bot-api/Client.cpp | 1 + telegram-bot-api/ClientManager.cpp | 1 + telegram-bot-api/HttpConnection.cpp | 1 + telegram-bot-api/HttpServer.h | 1 + telegram-bot-api/Query.cpp | 1 + telegram-bot-api/Stats.cpp | 2 +- telegram-bot-api/WebhookActor.cpp | 1 + telegram-bot-api/telegram-bot-api.cpp | 84 ++++----------------------- 9 files changed, 19 insertions(+), 75 deletions(-) diff --git a/td b/td index 5bd0c2c..5e7adcd 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 5bd0c2c46ded5c75a641829cfe84c0b5fead5bfc +Subproject commit 5e7adcd1cbf58e86ea2ac91dce796aef44d43978 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index bcc409a..16fdc81 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -25,6 +25,7 @@ #include "td/utils/port/Stat.h" #include "td/utils/Random.h" #include "td/utils/Slice.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Span.h" #include "td/utils/StackAllocator.h" #include "td/utils/Status.h" diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index 60c2e9b..59bf6b5 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -30,6 +30,7 @@ #include "td/utils/port/IPAddress.h" #include "td/utils/port/Stat.h" #include "td/utils/Slice.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/StackAllocator.h" #include "td/utils/StringBuilder.h" #include "td/utils/Time.h" diff --git a/telegram-bot-api/HttpConnection.cpp b/telegram-bot-api/HttpConnection.cpp index ae4bda4..dff9a0d 100644 --- a/telegram-bot-api/HttpConnection.cpp +++ b/telegram-bot-api/HttpConnection.cpp @@ -14,6 +14,7 @@ #include "td/utils/JsonBuilder.h" #include "td/utils/logging.h" #include "td/utils/Parser.h" +#include "td/utils/SliceBuilder.h" namespace telegram_bot_api { diff --git a/telegram-bot-api/HttpServer.h b/telegram-bot-api/HttpServer.h index 35bf747..976836c 100644 --- a/telegram-bot-api/HttpServer.h +++ b/telegram-bot-api/HttpServer.h @@ -15,6 +15,7 @@ #include "td/utils/format.h" #include "td/utils/logging.h" #include "td/utils/port/SocketFd.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Time.h" #include diff --git a/telegram-bot-api/Query.cpp b/telegram-bot-api/Query.cpp index 5deed1d..12c0273 100644 --- a/telegram-bot-api/Query.cpp +++ b/telegram-bot-api/Query.cpp @@ -14,6 +14,7 @@ #include "td/utils/logging.h" #include "td/utils/misc.h" #include "td/utils/port/IPAddress.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Time.h" #include diff --git a/telegram-bot-api/Stats.cpp b/telegram-bot-api/Stats.cpp index ba81026..59ca63e 100644 --- a/telegram-bot-api/Stats.cpp +++ b/telegram-bot-api/Stats.cpp @@ -7,8 +7,8 @@ #include "telegram-bot-api/Stats.h" #include "td/utils/common.h" -#include "td/utils/logging.h" #include "td/utils/port/thread.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/StringBuilder.h" namespace telegram_bot_api { diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index 4df3ab0..0be8d7c 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -28,6 +28,7 @@ #include "td/utils/port/SocketFd.h" #include "td/utils/Random.h" #include "td/utils/ScopeGuard.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Span.h" #include "td/utils/Time.h" diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 693dbb4..00f43b1 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -24,8 +24,8 @@ #include "td/actor/ConcurrentScheduler.h" #include "td/actor/PromiseFuture.h" -#include "td/utils/algorithm.h" #include "td/utils/buffer.h" +#include "td/utils/CombinedLog.h" #include "td/utils/common.h" #include "td/utils/crypto.h" #include "td/utils/ExitGuard.h" @@ -43,8 +43,10 @@ #include "td/utils/port/stacktrace.h" #include "td/utils/port/user.h" #include "td/utils/Slice.h" +#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" #include "td/utils/Time.h" +#include "td/utils/TsLog.h" #include "memprof/memprof.h" @@ -56,10 +58,10 @@ namespace telegram_bot_api { -static std::atomic_flag need_rotate_log; +static std::atomic_flag need_reopen_log; -static void rotate_log_signal_handler(int sig) { - need_rotate_log.clear(); +static void after_log_rotation_signal_handler(int sig) { + need_reopen_log.clear(); } static std::atomic_flag need_quit; @@ -110,7 +112,7 @@ int main(int argc, char *argv[]) { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL)); td::ExitGuard exit_guard; - need_rotate_log.test_and_set(); + need_reopen_log.test_and_set(); need_quit.test_and_set(); need_change_verbosity_level.test_and_set(); need_dump_log.test_and_set(); @@ -118,7 +120,7 @@ int main(int argc, char *argv[]) { td::Stacktrace::init(); td::setup_signals_alt_stack().ensure(); - td::set_signal_handler(td::SignalType::User, rotate_log_signal_handler).ensure(); + td::set_signal_handler(td::SignalType::User, after_log_rotation_signal_handler).ensure(); td::ignore_signal(td::SignalType::HangUp).ensure(); td::ignore_signal(td::SignalType::Pipe).ensure(); td::set_signal_handler(td::SignalType::Quit, quit_signal_handler).ensure(); @@ -287,71 +289,7 @@ int main(int argc, char *argv[]) { return 1; } - class CombineLog : public td::LogInterface { - 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_) { - second_->append(slice, log_level); - } - } - - void set_first(LogInterface *first) { - first_ = first; - } - - void set_second(LogInterface *second) { - second_ = second; - } - - void set_first_verbosity_level(int verbosity_level) { - first_verbosity_level_ = verbosity_level; - } - - void set_second_verbosity_level(int verbosity_level) { - 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(); - } - if (second_) { - second_->rotate(); - } - } - - td::vector get_file_paths() override { - td::vector result; - if (first_) { - td::append(result, first_->get_file_paths()); - } - if (second_) { - td::append(result, second_->get_file_paths()); - } - return result; - } - - private: - LogInterface *first_ = nullptr; - int first_verbosity_level_ = VERBOSITY_NAME(FATAL); - LogInterface *second_ = nullptr; - int second_verbosity_level_ = VERBOSITY_NAME(FATAL); - }; - CombineLog log; + td::CombinedLog log; log.set_first(td::default_log_interface); log.set_second(&memory_log); td::log_interface = &log; @@ -451,8 +389,8 @@ int main(int argc, char *argv[]) { while (true) { sched.run_main(next_cron_time - td::Time::now()); - if (!need_rotate_log.test_and_set()) { - td::log_interface->rotate(); + if (!need_reopen_log.test_and_set()) { + td::log_interface->after_rotation(); } if (!need_quit.test_and_set()) { From 6a7b2fd8a4d494519b866a2f8b8494f049ddf6b5 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 3 Jun 2021 19:26:19 +0300 Subject: [PATCH 05/25] Don't store invalid callback_data in messages. --- telegram-bot-api/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 16fdc81..ffd47a5 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -1500,7 +1500,7 @@ class Client::JsonInlineKeyboardButton : public Jsonable { case td_api::inlineKeyboardButtonTypeCallbackWithPassword::ID: { auto data = get_callback_data(button_->type_); if (!td::check_utf8(data)) { - object("callback_data", td::JsonRawString(data)); + object("callback_data", "INVALID"); } else { object("callback_data", data); } From 19f9e1eff0a8b5f2109c51aa90e3d79c5ee67fc6 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 4 Jun 2021 17:43:04 +0300 Subject: [PATCH 06/25] Output uptime and current state on closing. --- telegram-bot-api/telegram-bot-api.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 00f43b1..83cd0cd 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -399,7 +399,8 @@ int main(int argc, char *argv[]) { std::_Exit(0); } - LOG(WARNING) << "Stopping engine by a signal"; + LOG(WARNING) << "Stopping engine with uptime " << (td::Time::now() - start_time) << " seconds by a signal"; + last_dump_time = td::Time::now() - 1e6; close_flag = true; auto guard = sched.get_main_guard(); send_closure(client_manager, &ClientManager::close, td::PromiseCreator::lambda([&can_quit](td::Unit) { @@ -473,7 +474,7 @@ int main(int argc, char *argv[]) { total_size += info.size; } LOG(WARNING) << td::tag("other", td::format::as_size(other_size)); - LOG(WARNING) << td::tag("total", td::format::as_size(total_size)); + LOG(WARNING) << td::tag("total size", td::format::as_size(total_size)); LOG(WARNING) << td::tag("total traces", get_ht_size()); LOG(WARNING) << td::tag("fast_backtrace_success_rate", get_fast_backtrace_success_rate()); } From 4eb391decd6a942c50bebb38f74bd5eb2e8d432c Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 4 Jun 2021 18:20:08 +0300 Subject: [PATCH 07/25] Dump memory statistics with other state. --- telegram-bot-api/telegram-bot-api.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 83cd0cd..d818b6d 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -41,6 +41,7 @@ #include "td/utils/port/rlimit.h" #include "td/utils/port/signals.h" #include "td/utils/port/stacktrace.h" +#include "td/utils/port/Stat.h" #include "td/utils/port/user.h" #include "td/utils/Slice.h" #include "td/utils/SliceBuilder.h" @@ -478,6 +479,14 @@ int main(int argc, char *argv[]) { LOG(WARNING) << td::tag("total traces", get_ht_size()); LOG(WARNING) << td::tag("fast_backtrace_success_rate", get_fast_backtrace_success_rate()); } + auto r_mem_stat = td::mem_stat(); + if (r_mem_stat.is_ok()) { + auto mem_stat = r_mem_stat.move_as_ok(); + LOG(WARNING) << td::tag("rss", td::format::as_size(mem_stat.resident_size_)); + LOG(WARNING) << td::tag("vm", td::format::as_size(mem_stat.virtual_size_)); + LOG(WARNING) << td::tag("rss_peak", td::format::as_size(mem_stat.resident_size_peak_)); + LOG(WARNING) << td::tag("vm_peak", td::format::as_size(mem_stat.virtual_size_peak_)); + } LOG(WARNING) << td::tag("buffer_mem", td::format::as_size(td::BufferAllocator::get_buffer_mem())); LOG(WARNING) << td::tag("buffer_slice_size", td::format::as_size(td::BufferAllocator::get_buffer_slice_size())); From 29f11170be4a49da8fbe2e0c191a56f4fa11bdb3 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 8 Jun 2021 19:22:52 +0300 Subject: [PATCH 08/25] Fix Back button in build.html on the main page. --- build.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.html b/build.html index 7c31d38..338e025 100644 --- a/build.html +++ b/build.html @@ -121,7 +121,7 @@ function onLoad(initial) { function onOsChanged(initial) { var os = document.getElementById('osSelect').value; if (os.includes('Choose ')) { - if (history.state != '') { + if (history.state !== '' && history.state !== null) { history.pushState('', '', 'build.html'); } From 21cc85064cd2f3ff13db6019487475a0a7200de0 Mon Sep 17 00:00:00 2001 From: levlam Date: Sun, 13 Jun 2021 05:51:38 +0300 Subject: [PATCH 09/25] Do not export symbols from executable on Linux with CMake 3.4+. --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 45de0b3..65eee35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,11 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) +if (POLICY CMP0065) + # do not export symbols from executables + # affects compiler checks in project(), so must be set before it + cmake_policy(SET CMP0065 NEW) +endif() + project(TelegramBotApi VERSION 5.2 LANGUAGES CXX) add_subdirectory(td EXCLUDE_FROM_ALL) From aa70087df406efa3c6eede63e62929e13581a889 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 14 Jun 2021 03:45:44 +0300 Subject: [PATCH 10/25] Make bots online while logging in. --- telegram-bot-api/Client.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index ffd47a5..7d847e3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4047,6 +4047,8 @@ void Client::on_update_authorization_state() { case td_api::authorizationStateWaitEncryptionKey::ID: return send_request(make_object(), std::make_unique(this)); case td_api::authorizationStateWaitPhoneNumber::ID: + send_request(make_object("online", make_object(true)), + std::make_unique()); return send_request(make_object(bot_token_), std::make_unique(this)); case td_api::authorizationStateReady::ID: { From 05bbc55569e05059af452a9d8d8516546f3e3dd9 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 14 Jun 2021 04:07:37 +0300 Subject: [PATCH 11/25] Clamp default arg value just in case. --- telegram-bot-api/Client.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 7d847e3..b52dadf 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -6062,11 +6062,8 @@ td::Result> Client::get_poll_options(const Query *query) td::int32 Client::get_integer_arg(const Query *query, Slice field_name, int32 default_value, int32 min_value, int32 max_value) { auto s_arg = query->arg(field_name); - if (s_arg.empty()) { - return default_value; - } - - return td::clamp(td::to_integer(s_arg), min_value, max_value); + auto value = s_arg.empty() ? default_value : td::to_integer(s_arg); + return td::clamp(value, min_value, max_value); } td::Result Client::get_required_string_arg(const Query *query, Slice field_name) { From 084aa2a6f3e29635e118f678d451f3ca44519687 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 14 Jun 2021 04:11:15 +0300 Subject: [PATCH 12/25] Ignore internal setWebhook queries in flood-control. --- telegram-bot-api/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index b52dadf..0e008d5 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -7579,7 +7579,7 @@ td::Status Client::process_set_webhook_query(PromisedQueryPtr &query) { } auto now = td::Time::now_cached(); - if (!new_url.empty()) { + if (!new_url.empty() && !query->is_internal()) { if (now < next_allowed_set_webhook_time_) { query->set_retry_after_error(1); return Status::OK(); From 061c34749a031e4f1d84e39143ab83aad8faf127 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 14 Jun 2021 20:53:55 +0300 Subject: [PATCH 13/25] Dump statistics additionally to log by signal. --- telegram-bot-api/telegram-bot-api.cpp | 108 ++++++++++++++------------ 1 file changed, 57 insertions(+), 51 deletions(-) diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index d818b6d..28faaa7 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -109,6 +109,60 @@ static void sigsegv_signal_handler(int signum, void *addr) { fail_signal_handler(signum); } +static void dump_statistics(const std::shared_ptr &shared_data, + const std::shared_ptr &net_query_stats) { + if (is_memprof_on()) { + LOG(WARNING) << "Memory dump:"; + td::vector v; + dump_alloc([&](const AllocInfo &info) { v.push_back(info); }); + std::sort(v.begin(), v.end(), [](const AllocInfo &a, const AllocInfo &b) { return a.size > b.size; }); + size_t total_size = 0; + size_t other_size = 0; + int count = 0; + for (auto &info : v) { + if (count++ < 50) { + LOG(WARNING) << td::format::as_size(info.size) << td::format::as_array(info.backtrace); + } else { + other_size += info.size; + } + total_size += info.size; + } + LOG(WARNING) << td::tag("other", td::format::as_size(other_size)); + LOG(WARNING) << td::tag("total size", td::format::as_size(total_size)); + LOG(WARNING) << td::tag("total traces", get_ht_size()); + LOG(WARNING) << td::tag("fast_backtrace_success_rate", get_fast_backtrace_success_rate()); + } + auto r_mem_stat = td::mem_stat(); + if (r_mem_stat.is_ok()) { + auto mem_stat = r_mem_stat.move_as_ok(); + LOG(WARNING) << td::tag("rss", td::format::as_size(mem_stat.resident_size_)); + LOG(WARNING) << td::tag("vm", td::format::as_size(mem_stat.virtual_size_)); + LOG(WARNING) << td::tag("rss_peak", td::format::as_size(mem_stat.resident_size_peak_)); + LOG(WARNING) << td::tag("vm_peak", td::format::as_size(mem_stat.virtual_size_peak_)); + } + LOG(WARNING) << td::tag("buffer_mem", td::format::as_size(td::BufferAllocator::get_buffer_mem())); + LOG(WARNING) << td::tag("buffer_slice_size", td::format::as_size(td::BufferAllocator::get_buffer_slice_size())); + + auto query_count = shared_data->query_count_.load(); + LOG(WARNING) << td::tag("pending queries", query_count); + + td::uint64 i = 0; + bool was_gap = false; + for (auto end = &shared_data->query_list_, cur = end->prev; cur != end; cur = cur->prev, i++) { + if (i < 20 || i > query_count - 20 || i % (query_count / 50 + 1) == 0) { + if (was_gap) { + LOG(WARNING) << "..."; + was_gap = false; + } + LOG(WARNING) << static_cast(*cur); + } else { + was_gap = true; + } + } + + td::dump_pending_network_queries(*net_query_stats); +} + int main(int argc, char *argv[]) { SET_VERBOSITY_LEVEL(VERBOSITY_NAME(FATAL)); td::ExitGuard exit_guard; @@ -401,7 +455,7 @@ int main(int argc, char *argv[]) { } LOG(WARNING) << "Stopping engine with uptime " << (td::Time::now() - start_time) << " seconds by a signal"; - last_dump_time = td::Time::now() - 1e6; + dump_statistics(shared_data, net_query_stats); close_flag = true; auto guard = sched.get_main_guard(); send_closure(client_manager, &ClientManager::close, td::PromiseCreator::lambda([&can_quit](td::Unit) { @@ -430,6 +484,7 @@ int main(int argc, char *argv[]) { if (!need_dump_log.test_and_set()) { print_log(); + dump_statistics(shared_data, net_query_stats); } double now = td::Time::now(); @@ -458,56 +513,7 @@ int main(int argc, char *argv[]) { if (now > last_dump_time + 300.0) { last_dump_time = now; - if (is_memprof_on()) { - LOG(WARNING) << "Memory dump:"; - td::vector v; - dump_alloc([&](const AllocInfo &info) { v.push_back(info); }); - std::sort(v.begin(), v.end(), [](const AllocInfo &a, const AllocInfo &b) { return a.size > b.size; }); - size_t total_size = 0; - size_t other_size = 0; - int count = 0; - for (auto &info : v) { - if (count++ < 50) { - LOG(WARNING) << td::format::as_size(info.size) << td::format::as_array(info.backtrace); - } else { - other_size += info.size; - } - total_size += info.size; - } - LOG(WARNING) << td::tag("other", td::format::as_size(other_size)); - LOG(WARNING) << td::tag("total size", td::format::as_size(total_size)); - LOG(WARNING) << td::tag("total traces", get_ht_size()); - LOG(WARNING) << td::tag("fast_backtrace_success_rate", get_fast_backtrace_success_rate()); - } - auto r_mem_stat = td::mem_stat(); - if (r_mem_stat.is_ok()) { - auto mem_stat = r_mem_stat.move_as_ok(); - LOG(WARNING) << td::tag("rss", td::format::as_size(mem_stat.resident_size_)); - LOG(WARNING) << td::tag("vm", td::format::as_size(mem_stat.virtual_size_)); - LOG(WARNING) << td::tag("rss_peak", td::format::as_size(mem_stat.resident_size_peak_)); - LOG(WARNING) << td::tag("vm_peak", td::format::as_size(mem_stat.virtual_size_peak_)); - } - LOG(WARNING) << td::tag("buffer_mem", td::format::as_size(td::BufferAllocator::get_buffer_mem())); - LOG(WARNING) << td::tag("buffer_slice_size", td::format::as_size(td::BufferAllocator::get_buffer_slice_size())); - - auto query_count = shared_data->query_count_.load(); - LOG(WARNING) << td::tag("pending queries", query_count); - - td::uint64 i = 0; - bool was_gap = false; - for (auto end = &shared_data->query_list_, cur = end->prev; cur != end; cur = cur->prev, i++) { - if (i < 20 || i > query_count - 20 || i % (query_count / 50 + 1) == 0) { - if (was_gap) { - LOG(WARNING) << "..."; - was_gap = false; - } - LOG(WARNING) << static_cast(*cur); - } else { - was_gap = true; - } - } - - td::dump_pending_network_queries(*net_query_stats); + dump_statistics(shared_data, net_query_stats); } } From 54112379ff6a21b993c03b7bcb36049f5f43c993 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 14 Jun 2021 21:24:20 +0300 Subject: [PATCH 14/25] Check write access to temporary directory. --- telegram-bot-api/telegram-bot-api.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 28faaa7..3de714a 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -339,7 +339,7 @@ int main(int argc, char *argv[]) { return 0; } if (r_non_options.is_error()) { - LOG(PLAIN) << argv[0] << ": " << r_non_options.error(); + LOG(PLAIN) << argv[0] << ": " << r_non_options.error().message(); LOG(PLAIN) << options; return 1; } @@ -370,6 +370,20 @@ int main(int argc, char *argv[]) { TRY_STATUS_PREFIX(td::set_temporary_dir(temporary_directory), "Can't set temporary directory: "); } + auto temp_dir = td::get_temporary_dir(); + if (temp_dir.empty()) { + return td::Status::Error("Can't find directory for temporary files. Use --temp-dir option to specify it"); + } + + auto r_temp_file = td::mkstemp(temp_dir); + if (r_temp_file.is_error()) { + return td::Status::Error( + PSLICE() << "Can't create files in the directory \"" << temp_dir + << "\". Use --temp-dir option to specify another directory for temporary files"); + } + r_temp_file.ok_ref().first.close(); + td::unlink(r_temp_file.ok().second).ensure(); + if (!log_file_path.empty()) { TRY_STATUS_PREFIX(file_log.init(log_file_path, log_max_file_size), "Can't open log file: "); log.set_first(&ts_log); @@ -378,7 +392,7 @@ int main(int argc, char *argv[]) { return td::Status::OK(); }(); if (init_status.is_error()) { - LOG(PLAIN) << init_status.error(); + LOG(PLAIN) << init_status.error().message(); LOG(PLAIN) << options; return 1; } From 7de971ec2016e6091428dd92e0e7c341b9a419f5 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 14 Jun 2021 22:47:01 +0300 Subject: [PATCH 15/25] Simplify Query creation and statistics. --- telegram-bot-api/Client.cpp | 5 +--- telegram-bot-api/ClientManager.cpp | 22 +++++--------- telegram-bot-api/HttpConnection.cpp | 2 +- telegram-bot-api/Query.cpp | 22 +++++++++++--- telegram-bot-api/Query.h | 45 +++++++++++------------------ telegram-bot-api/WebhookActor.cpp | 8 ++--- 6 files changed, 49 insertions(+), 55 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 0e008d5..b384ed3 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3494,10 +3494,7 @@ void Client::start_up() { void Client::send(PromisedQueryPtr query) { if (!query->is_internal()) { - send_closure( - stat_actor_, &BotStatActor::add_event, - ServerBotStat::Request{query->query_size(), query->file_count(), query->files_size(), query->files_max_size()}, - td::Time::now()); + query->set_stat_actor(stat_actor_); } cmd_queue_.emplace(std::move(query)); loop(); diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index 59bf6b5..a1347ea 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -115,30 +115,25 @@ void ClientManager::send(PromisedQueryPtr query) { auto id = clients_.create(ClientInfo{BotStatActor(stat_.actor_id(&stat_)), token, td::ActorOwn()}); auto *client_info = clients_.get(id); - auto stat_actor = client_info->stat_.actor_id(&client_info->stat_); - auto client_id = 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_, std::move(stat_actor)); + 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_)); auto method = query->method(); if (method != "deletewebhook" && method != "setwebhook") { auto bot_token_with_dc = PSTRING() << query->token() << (query->is_test_dc() ? ":T" : ""); auto webhook_info = parameters_->shared_data_->webhook_db_->get(bot_token_with_dc); if (!webhook_info.empty()) { - send_closure(client_id, &Client::send, + send_closure(client_info->client_, &Client::send, get_webhook_restore_query(bot_token_with_dc, webhook_info, parameters_->shared_data_)); } } - clients_.get(id)->client_ = std::move(client_id); std::tie(id_it, std::ignore) = token_to_id_.emplace(token, id); } - auto *client_info = clients_.get(id_it->second); - - if (!query->is_internal()) { - query->set_stat_actor(client_info->stat_.actor_id(&client_info->stat_)); - } - send_closure(client_info->client_, &Client::send, std::move(query)); // will send 429 if the client is already closed + send_closure(clients_.get(id_it->second)->client_, &Client::send, + std::move(query)); // will send 429 if the client is already closed } void ClientManager::get_stats(td::PromiseActor promise, @@ -367,8 +362,7 @@ PromisedQueryPtr ClientManager::get_webhook_restore_query(td::Slice token, td::S const auto method = add_string("setwebhook"); auto query = std::make_unique(std::move(containers), token, is_test_dc, method, std::move(args), td::vector>(), - td::vector(), std::move(shared_data), td::IPAddress()); - query->set_internal(true); + td::vector(), std::move(shared_data), td::IPAddress(), true); return PromisedQueryPtr(query.release(), PromiseDeleter(td::PromiseActor>())); } diff --git a/telegram-bot-api/HttpConnection.cpp b/telegram-bot-api/HttpConnection.cpp index dff9a0d..2875e75 100644 --- a/telegram-bot-api/HttpConnection.cpp +++ b/telegram-bot-api/HttpConnection.cpp @@ -46,7 +46,7 @@ void HttpConnection::handle(td::unique_ptr http_query, auto method = url_path_parser.data(); auto query = std::make_unique(std::move(http_query->container_), token, is_test_dc, method, std::move(http_query->args_), std::move(http_query->headers_), - std::move(http_query->files_), shared_data_, http_query->peer_address_); + std::move(http_query->files_), shared_data_, http_query->peer_address_, false); td::PromiseActor> promise; td::FutureActor> future; diff --git a/telegram-bot-api/Query.cpp b/telegram-bot-api/Query.cpp index 12c0273..5f71ba9 100644 --- a/telegram-bot-api/Query.cpp +++ b/telegram-bot-api/Query.cpp @@ -26,7 +26,7 @@ std::unordered_map> empty_par Query::Query(td::vector &&container, td::Slice token, bool is_test_dc, td::MutableSlice method, td::vector> &&args, td::vector> &&headers, td::vector &&files, - std::shared_ptr shared_data, const td::IPAddress &peer_address) + std::shared_ptr shared_data, const td::IPAddress &peer_address, bool is_internal) : state_(State::Query) , shared_data_(shared_data) , peer_address_(peer_address) @@ -36,7 +36,8 @@ Query::Query(td::vector &&container, td::Slice token, bool is_t , method_(method) , args_(std::move(args)) , headers_(std::move(headers)) - , files_(std::move(files)) { + , files_(std::move(files)) + , is_internal_(is_internal) { if (method_.empty()) { method_ = arg("method"); } @@ -67,6 +68,11 @@ td::int64 Query::files_max_size() const { [](td::int64 acc, const td::HttpFile &file) { return td::max(acc, file.size); }); } +void Query::set_stat_actor(td::ActorId stat_actor) { + stat_actor_ = stat_actor; + send_request_stat(); +} + void Query::set_ok(td::BufferSlice result) { CHECK(state_ == State::Query); LOG(INFO) << "QUERY: got ok " << td::tag("ptr", this) << td::tag("text", result.as_slice()); @@ -109,12 +115,20 @@ td::StringBuilder &operator<<(td::StringBuilder &sb, const Query &query) { return sb; } -void Query::send_response_stat() { +void Query::send_request_stat() const { + if (stat_actor_.empty()) { + return; + } + send_closure(stat_actor_, &BotStatActor::add_event, + ServerBotStat::Request{query_size(), file_count(), files_size(), files_max_size()}, td::Time::now()); +} + +void Query::send_response_stat() const { if (stat_actor_.empty()) { return; } send_closure(stat_actor_, &BotStatActor::add_event, - ServerBotStat::Response{is_ok(), answer().size()}, td::Time::now()); + ServerBotStat::Response{state_ == State::OK, answer_.size()}, td::Time::now()); } } // namespace telegram_bot_api diff --git a/telegram-bot-api/Query.h b/telegram-bot-api/Query.h index 33bedc4..5ccb65d 100644 --- a/telegram-bot-api/Query.h +++ b/telegram-bot-api/Query.h @@ -73,17 +73,6 @@ class Query : public td::ListNode { return peer_address_; } - // for stats - td::int32 file_count() const { - return static_cast(files_.size()); - } - - td::int64 query_size() const; - - td::int64 files_size() const; - - td::int64 files_max_size() const; - td::BufferSlice &answer() { return answer_; } @@ -106,26 +95,14 @@ class Query : public td::ListNode { return state_ != State::Query; } - bool is_error() const { - return state_ == State::Error; - } - - bool is_ok() const { - return state_ == State::OK; - } - bool is_internal() const { return is_internal_; } - void set_internal(bool is_internal) { - is_internal_ = is_internal; - } - Query(td::vector &&container, td::Slice token, bool is_test_dc, td::MutableSlice method, td::vector> &&args, td::vector> &&headers, td::vector &&files, - std::shared_ptr shared_data, const td::IPAddress &peer_address); + std::shared_ptr shared_data, const td::IPAddress &peer_address, bool is_internal); Query(const Query &) = delete; Query &operator=(const Query &) = delete; Query(Query &&) = delete; @@ -140,10 +117,7 @@ class Query : public td::ListNode { return start_timestamp_; } - void set_stat_actor(td::ActorId stat_actor) { - stat_actor_ = stat_actor; - } - void send_response_stat(); + void set_stat_actor(td::ActorId stat_actor); private: State state_; @@ -166,6 +140,21 @@ class Query : public td::ListNode { td::BufferSlice answer_; int http_status_code_ = 0; int retry_after_ = 0; + + // for stats + td::int32 file_count() const { + return static_cast(files_.size()); + } + + td::int64 query_size() const; + + td::int64 files_size() const; + + td::int64 files_max_size() const; + + void send_request_stat() const; + + void send_response_stat() const; }; td::StringBuilder &operator<<(td::StringBuilder &sb, const Query &query); diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index 0be8d7c..cf70695 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -586,10 +586,10 @@ void WebhookActor::handle(td::unique_ptr response) { if (!method.empty() && method != "deletewebhook" && method != "setwebhook" && method != "close" && method != "logout" && !td::begins_with(method, "get")) { VLOG(webhook) << "Receive request " << method << " in response to webhook"; - auto query = - std::make_unique(std::move(response->container_), td::MutableSlice(), false, td::MutableSlice(), - std::move(response->args_), std::move(response->headers_), - std::move(response->files_), parameters_->shared_data_, response->peer_address_); + auto query = std::make_unique(std::move(response->container_), td::MutableSlice(), false, + td::MutableSlice(), std::move(response->args_), + std::move(response->headers_), std::move(response->files_), + parameters_->shared_data_, response->peer_address_, false); auto promised_query = PromisedQueryPtr(query.release(), PromiseDeleter(td::PromiseActor>())); send_closure(callback_, &Callback::send, std::move(promised_query)); From ab8edb4de76035fc519f51fa20d4c6ba29d2c2b3 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 14 Jun 2021 22:58:23 +0300 Subject: [PATCH 16/25] Log too old queries. --- telegram-bot-api/Query.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Query.cpp b/telegram-bot-api/Query.cpp index 5f71ba9..e1dd27a 100644 --- a/telegram-bot-api/Query.cpp +++ b/telegram-bot-api/Query.cpp @@ -124,11 +124,17 @@ void Query::send_request_stat() const { } void Query::send_response_stat() const { + auto now = td::Time::now(); + if (now - start_timestamp_ >= 100.0) { + LOG(WARNING) << "Answer too old query with code " << http_status_code_ << " and answer size " << answer_.size() + << ": " << *this; + } + if (stat_actor_.empty()) { return; } send_closure(stat_actor_, &BotStatActor::add_event, - ServerBotStat::Response{state_ == State::OK, answer_.size()}, td::Time::now()); + ServerBotStat::Response{state_ == State::OK, answer_.size()}, now); } } // namespace telegram_bot_api From ad55377cba661db7f04ebab03ed10bf33b6df91d Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 14 Jun 2021 23:15:40 +0300 Subject: [PATCH 17/25] Allow to leave deactivated basic groups independently from supergroups. --- telegram-bot-api/Client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index b384ed3..9d20fbd 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -7247,7 +7247,7 @@ td::Status Client::process_get_chat_member_count_query(PromisedQueryPtr &query) td::Status Client::process_leave_chat_query(PromisedQueryPtr &query) { auto chat_id = query->arg("chat_id"); - check_chat(chat_id, AccessRights::ReadMembers, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { + check_chat(chat_id, AccessRights::Read, std::move(query), [this](int64 chat_id, PromisedQueryPtr query) { send_request(make_object(chat_id), std::make_unique(std::move(query))); }); return Status::OK(); From 08a92a2347274237704c7d9000467772c3b0d790 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 22 Jun 2021 21:26:41 +0300 Subject: [PATCH 18/25] Use absolute file paths. --- telegram-bot-api/Client.cpp | 17 +++----- telegram-bot-api/Client.h | 1 - telegram-bot-api/ClientManager.cpp | 5 ++- telegram-bot-api/ClientParameters.h | 2 + telegram-bot-api/telegram-bot-api.cpp | 56 ++++++++++++++++++++------- 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 9d20fbd..a653445 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3455,9 +3455,6 @@ void Client::start_up() { set_context(context); set_tag(bot_token_id_); - auto r_absolute_dir = td::realpath(td::string(".") + TD_DIR_SLASH, true); - CHECK(r_absolute_dir.is_ok()); - absolute_dir_ = r_absolute_dir.move_as_ok(); auto suff = bot_token_with_dc_ + TD_DIR_SLASH; #if TD_PORT_WINDOWS for (auto &c : suff) { @@ -3466,11 +3463,7 @@ void Client::start_up() { } } #endif - dir_ = td::string(".") + TD_DIR_SLASH + suff; - if (absolute_dir_.back() != TD_DIR_SLASH) { - absolute_dir_ += TD_DIR_SLASH; - } - absolute_dir_ += suff; + dir_ = parameters_->working_directory_ + suff; class TdCallback : public td::TdCallback { public: @@ -4464,8 +4457,8 @@ void Client::on_closed() { td::ActorId parent_; void start_up() override { - CHECK(!dir_.empty()); - CHECK(dir_[0] == '.'); + CHECK(dir_.size() >= 24); + CHECK(dir_.back() == TD_DIR_SLASH); td::rmrf(dir_).ignore(); stop(); } @@ -7657,7 +7650,7 @@ void Client::do_get_file(object_ptr file, PromisedQueryPtr query) auto file_id = file->id_; file_download_listeners_[file_id].push_back(std::move(query)); if (file->local_->is_downloading_completed_) { - Slice relative_path = td::PathView::relative(file->local_->path_, absolute_dir_, true); + Slice relative_path = td::PathView::relative(file->local_->path_, dir_, true); if (!relative_path.empty()) { auto r_stat = td::stat(file->local_->path_); if (r_stat.is_ok() && r_stat.ok().is_reg_ && r_stat.ok().size_ == file->size_) { @@ -8293,7 +8286,7 @@ void Client::json_store_file(td::JsonObjectScope &object, const td_api::file *fi object("file_path", td::JsonRawString(file->local_->path_)); } } else { - Slice relative_path = td::PathView::relative(file->local_->path_, absolute_dir_, true); + Slice relative_path = td::PathView::relative(file->local_->path_, dir_, true); if (!relative_path.empty() && file->local_->downloaded_size_ <= MAX_DOWNLOAD_FILE_SIZE) { object("file_path", relative_path); } diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 7b93838..40224b5 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -902,7 +902,6 @@ class Client : public WebhookActor::Callback { int64 current_bot_resolve_query_id_ = 1; td::string dir_; - td::string absolute_dir_; td::ActorOwn td_client_; td::ActorContext context_; std::queue cmd_queue_; diff --git a/telegram-bot-api/ClientManager.cpp b/telegram-bot-api/ClientManager.cpp index a1347ea..6f8cabb 100644 --- a/telegram-bot-api/ClientManager.cpp +++ b/telegram-bot-api/ClientManager.cpp @@ -266,7 +266,7 @@ void ClientManager::start_up() { td::vector failed_to_replay_log_event_ids; td::int64 loaded_event_count = 0; binlog - ->init("tqueue.binlog", + ->init(parameters_->working_directory_ + "tqueue.binlog", [&](const td::BinlogEvent &event) { if (tqueue_binlog->replay(event, *tqueue).is_error()) { failed_to_replay_log_event_ids.push_back(event.id_); @@ -295,7 +295,8 @@ void ClientManager::start_up() { // init webhook_db auto concurrent_webhook_db = td::make_unique>(); - auto status = concurrent_webhook_db->init("webhooks_db.binlog", td::DbKey::empty(), scheduler_id); + auto status = concurrent_webhook_db->init(parameters_->working_directory_ + "webhooks_db.binlog", td::DbKey::empty(), + scheduler_id); LOG_IF(FATAL, status.is_error()) << "Can't open webhooks_db.binlog " << status.error(); parameters_->shared_data_->webhook_db_ = std::move(concurrent_webhook_db); diff --git a/telegram-bot-api/ClientParameters.h b/telegram-bot-api/ClientParameters.h index 6ca1432..e686887 100644 --- a/telegram-bot-api/ClientParameters.h +++ b/telegram-bot-api/ClientParameters.h @@ -54,6 +54,8 @@ struct SharedData { }; struct ClientParameters { + td::string working_directory_; + bool local_mode_ = false; td::int32 api_id_ = 0; diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 3de714a..6454651 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -36,6 +36,7 @@ #include "td/utils/MemoryLog.h" #include "td/utils/misc.h" #include "td/utils/OptionParser.h" +#include "td/utils/PathView.h" #include "td/utils/port/IPAddress.h" #include "td/utils/port/path.h" #include "td/utils/port/rlimit.h" @@ -208,7 +209,7 @@ int main(int argc, char *argv[]) { 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 working_directory = PSTRING() << "." << TD_DIR_SLASH; td::string temporary_directory; td::string username; td::string groupname; @@ -362,29 +363,54 @@ int main(int argc, char *argv[]) { TRY_STATUS_PREFIX(td::change_user(username, groupname), "Can't change effective user: "); } - if (!working_directory.empty()) { - TRY_STATUS_PREFIX(td::chdir(working_directory), "Can't set working directory: "); + { + TRY_RESULT_PREFIX_ASSIGN(working_directory, td::realpath(working_directory, true), + "Invalid working directory specified: "); + if (working_directory.empty()) { + return td::Status::Error("Working directory can't be empty"); + } + if (working_directory.back() != TD_DIR_SLASH) { + working_directory += TD_DIR_SLASH; + } + + TRY_STATUS_PREFIX(td::mkpath(working_directory, 0750), "Failed to create working directory: "); + + auto r_temp_file = td::mkstemp(working_directory); + if (r_temp_file.is_error()) { + return td::Status::Error(PSLICE() << "Can't create files in the directory \"" << working_directory + << "\". Use --dir option to specify a writable working directory"); + } + r_temp_file.ok_ref().first.close(); + td::unlink(r_temp_file.ok().second).ensure(); } if (!temporary_directory.empty()) { + if (td::PathView(temporary_directory).is_relative()) { + temporary_directory = working_directory + temporary_directory; + } TRY_STATUS_PREFIX(td::set_temporary_dir(temporary_directory), "Can't set temporary directory: "); } - auto temp_dir = td::get_temporary_dir(); - if (temp_dir.empty()) { - return td::Status::Error("Can't find directory for temporary files. Use --temp-dir option to specify it"); - } + { // check temporary directory + auto temp_dir = td::get_temporary_dir(); + if (temp_dir.empty()) { + return td::Status::Error("Can't find directory for temporary files. Use --temp-dir option to specify it"); + } - auto r_temp_file = td::mkstemp(temp_dir); - if (r_temp_file.is_error()) { - return td::Status::Error( - PSLICE() << "Can't create files in the directory \"" << temp_dir - << "\". Use --temp-dir option to specify another directory for temporary files"); + auto r_temp_file = td::mkstemp(temp_dir); + if (r_temp_file.is_error()) { + return td::Status::Error(PSLICE() + << "Can't create files in the directory \"" << temp_dir + << "\". Use --temp-dir option to specify another directory for temporary files"); + } + r_temp_file.ok_ref().first.close(); + td::unlink(r_temp_file.ok().second).ensure(); } - r_temp_file.ok_ref().first.close(); - td::unlink(r_temp_file.ok().second).ensure(); if (!log_file_path.empty()) { + if (td::PathView(log_file_path).is_relative()) { + log_file_path = working_directory + log_file_path; + } TRY_STATUS_PREFIX(file_log.init(log_file_path, log_max_file_size), "Can't open log file: "); log.set_first(&ts_log); } @@ -397,6 +423,8 @@ int main(int argc, char *argv[]) { return 1; } + parameters->working_directory_ = std::move(working_directory); + if (parameters->default_max_webhook_connections_ <= 0) { parameters->default_max_webhook_connections_ = parameters->local_mode_ ? 100 : 40; } From badeb9a7f0e9cff11a9d49676d2d8c61fb6e0947 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 23 Jun 2021 02:03:22 +0300 Subject: [PATCH 19/25] Automatically detect whether colon can be used in a directory name. --- telegram-bot-api/Client.cpp | 10 +++++----- telegram-bot-api/ClientParameters.h | 1 + telegram-bot-api/telegram-bot-api.cpp | 11 +++++++++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index a653445..7c7f8a4 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -3456,13 +3456,13 @@ void Client::start_up() { set_tag(bot_token_id_); auto suff = bot_token_with_dc_ + TD_DIR_SLASH; -#if TD_PORT_WINDOWS - for (auto &c : suff) { - if (c == ':') { - c = '~'; + if (!parameters_->allow_colon_in_filenames_) { + for (auto &c : suff) { + if (c == ':') { + c = '~'; + } } } -#endif dir_ = parameters_->working_directory_ + suff; class TdCallback : public td::TdCallback { diff --git a/telegram-bot-api/ClientParameters.h b/telegram-bot-api/ClientParameters.h index e686887..a0f2333 100644 --- a/telegram-bot-api/ClientParameters.h +++ b/telegram-bot-api/ClientParameters.h @@ -55,6 +55,7 @@ struct SharedData { struct ClientParameters { td::string working_directory_; + bool allow_colon_in_filenames_ = true; bool local_mode_ = false; diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index 6454651..c43ad34 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -382,6 +382,17 @@ int main(int argc, char *argv[]) { } r_temp_file.ok_ref().first.close(); td::unlink(r_temp_file.ok().second).ensure(); + + auto r_temp_dir = td::mkdtemp(working_directory, "1:a"); + if (r_temp_dir.is_error()) { + parameters->allow_colon_in_filenames_ = false; + r_temp_dir = td::mkdtemp(working_directory, "1~a"); + if (r_temp_dir.is_error()) { + return td::Status::Error(PSLICE() << "Can't create directories in the directory \"" << working_directory + << "\". Use --dir option to specify a writable working directory"); + } + } + td::rmdir(r_temp_dir.ok()).ensure(); } if (!temporary_directory.empty()) { From 878a1e16a89c75d791bd24050e5721d63e637eaf Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 23 Jun 2021 03:34:31 +0300 Subject: [PATCH 20/25] Update TDLib. --- td | 2 +- telegram-bot-api/Client.cpp | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/td b/td index 5e7adcd..9628668 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 5e7adcd1cbf58e86ea2ac91dce796aef44d43978 +Subproject commit 9628668def2dfe5765cb049813ce504c8f7a5b49 diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 7c7f8a4..557348d 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -2277,14 +2277,8 @@ class Client::JsonChatMembers : public Jsonable { continue; } auto user_id = static_cast(member->member_id_.get())->user_id_; - bool is_member_bot = member->bot_info_ != nullptr; - if (!is_member_bot) { - // bot info may be unknown - auto user_info = client_->get_user_info(user_id); - if (user_info != nullptr && user_info->type == UserInfo::Type::Bot) { - is_member_bot = true; - } - } + auto user_info = client_->get_user_info(user_id); + bool is_member_bot = user_info != nullptr && user_info->type == UserInfo::Type::Bot; if (is_member_bot && user_id != client_->my_id_) { continue; } @@ -3141,11 +3135,7 @@ class Client::TdOnGetMyCommandsCallback : public TdQueryCallback { CHECK(result->get_id() == td_api::userFullInfo::ID); auto user_full_info = move_object_as(result); - td::vector> commands; - if (user_full_info->bot_info_ != nullptr) { - commands = std::move(user_full_info->bot_info_->commands_); - } - answer_query(td::json_array(commands, [](auto &command) { return JsonBotCommand(command.get()); }), + answer_query(td::json_array(user_full_info->commands_, [](auto &command) { return JsonBotCommand(command.get()); }), std::move(query_)); } @@ -4742,13 +4732,13 @@ td::Result> Client::get_reply_markup(Jso object_ptr result; if (!rows.empty()) { - result = make_object(std::move(rows), resize, one_time, is_personal); + result = make_object(std::move(rows), resize, one_time, is_personal, td::string()); } else if (!inline_rows.empty()) { result = make_object(std::move(inline_rows)); } else if (remove) { result = make_object(is_personal); } else if (force_reply) { - result = make_object(is_personal); + result = make_object(is_personal, td::string()); } if (result == nullptr || result->get_id() != td_api::replyMarkupInlineKeyboard::ID) { unresolved_bot_usernames_.clear(); @@ -6235,7 +6225,7 @@ td::Status Client::process_get_my_commands_query(PromisedQueryPtr &query) { td::Status Client::process_set_my_commands_query(PromisedQueryPtr &query) { TRY_RESULT(bot_commands, get_bot_commands(query.get())); - send_request(make_object(std::move(bot_commands)), + send_request(make_object(nullptr, "", std::move(bot_commands)), std::make_unique(std::move(query))); return Status::OK(); } @@ -7439,7 +7429,8 @@ td::Status Client::process_upload_sticker_file_query(PromisedQueryPtr &query) { check_user(user_id, std::move(query), [this, user_id, png_sticker = std::move(png_sticker)](PromisedQueryPtr query) mutable { - send_request(make_object(user_id, std::move(png_sticker)), + send_request(make_object( + user_id, make_object(std::move(png_sticker), "", nullptr)), std::make_unique(this, std::move(query))); }); return Status::OK(); @@ -7455,7 +7446,7 @@ td::Status Client::process_create_new_sticker_set_query(PromisedQueryPtr &query) check_user(user_id, std::move(query), [this, user_id, title, name, is_masks, stickers = std::move(stickers)](PromisedQueryPtr query) mutable { send_request(make_object(user_id, title.str(), name.str(), is_masks, - std::move(stickers)), + std::move(stickers), PSTRING() << "bot" << my_id_), std::make_unique(this, false, std::move(query))); }); return Status::OK(); From 73b65fc99eab7e03281a59d64ee819b18067d566 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 23 Jun 2021 03:38:17 +0300 Subject: [PATCH 21/25] Support input field placehoder in ReplyMarkup. --- telegram-bot-api/Client.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 557348d..8b9b191 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -4652,6 +4652,7 @@ td::Result> Client::get_reply_markup(con td::Result> Client::get_reply_markup(JsonValue &&value) { td::vector>> rows; td::vector>> inline_rows; + Slice input_field_placeholder; bool resize = false; bool one_time = false; bool remove = false; @@ -4727,18 +4728,24 @@ td::Result> Client::get_reply_markup(Jso return Status::Error(400, "Field \"force_reply\" of the reply markup must be of the type Boolean"); } force_reply = field_value.second.get_boolean(); + } else if (field_value.first == "input_field_placeholder") { + if (field_value.second.type() != JsonValue::Type::String) { + return Status::Error(400, "Field \"input_field_placeholder\" of the reply markup must be of the type String"); + } + input_field_placeholder = field_value.second.get_string(); } } object_ptr result; if (!rows.empty()) { - result = make_object(std::move(rows), resize, one_time, is_personal, td::string()); + result = make_object(std::move(rows), resize, one_time, is_personal, + input_field_placeholder.str()); } else if (!inline_rows.empty()) { result = make_object(std::move(inline_rows)); } else if (remove) { result = make_object(is_personal); } else if (force_reply) { - result = make_object(is_personal, td::string()); + result = make_object(is_personal, input_field_placeholder.str()); } if (result == nullptr || result->get_id() != td_api::replyMarkupInlineKeyboard::ID) { unresolved_bot_usernames_.clear(); From b8693ae500a9e596d36edaf402f8bfd52da00f72 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 23 Jun 2021 06:48:24 +0300 Subject: [PATCH 22/25] Support new bot command methods. --- telegram-bot-api/Client.cpp | 174 ++++++++++++++++++++++++++++++------ telegram-bot-api/Client.h | 20 +++++ 2 files changed, 167 insertions(+), 27 deletions(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 8b9b191..6edf756 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -178,6 +178,7 @@ bool Client::init_methods() { methods_.emplace("getme", &Client::process_get_me_query); methods_.emplace("getmycommands", &Client::process_get_my_commands_query); methods_.emplace("setmycommands", &Client::process_set_my_commands_query); + methods_.emplace("deletemycommands", &Client::process_delete_my_commands_query); methods_.emplace("getuserprofilephotos", &Client::process_get_user_profile_photos_query); methods_.emplace("sendmessage", &Client::process_send_message_query); methods_.emplace("sendanimation", &Client::process_send_animation_query); @@ -288,7 +289,7 @@ class Client::JsonDatedFile : public Jsonable { class Client::JsonDatedFiles : public Jsonable { public: - JsonDatedFiles(const td::vector> &files, const Client *client) + JsonDatedFiles(const td::vector> &files, const Client *client) : files_(files), client_(client) { } void store(JsonValueScope *scope) const { @@ -299,7 +300,7 @@ class Client::JsonDatedFiles : public Jsonable { } private: - const td::vector> &files_; + const td::vector> &files_; const Client *client_; }; @@ -3133,9 +3134,9 @@ class Client::TdOnGetMyCommandsCallback : public TdQueryCallback { return fail_query_with_error(std::move(query_), move_object_as(result)); } - CHECK(result->get_id() == td_api::userFullInfo::ID); - auto user_full_info = move_object_as(result); - answer_query(td::json_array(user_full_info->commands_, [](auto &command) { return JsonBotCommand(command.get()); }), + CHECK(result->get_id() == td_api::botCommands::ID); + auto bot_commands = move_object_as(result); + answer_query(td::json_array(bot_commands->commands_, [](auto &command) { return JsonBotCommand(command.get()); }), std::move(query_)); } @@ -3728,6 +3729,36 @@ void Client::check_chat(Slice chat_id_str, AccessRights access_rights, PromisedQ std::move(on_success))); } +template +void Client::check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success) { + CHECK(scope.scope_ != nullptr); + if (scope.chat_id_.empty()) { + on_success(std::move(scope.scope_), std::move(query)); + return; + } + check_chat(scope.chat_id_, AccessRights::ReadMembers, std::move(query), + [this, user_id = scope.user_id_, scope_id = scope.scope_->get_id(), on_success = std::move(on_success)]( + int64 chat_id, PromisedQueryPtr query) mutable { + switch (scope_id) { + case td_api::botCommandScopeChat::ID: + on_success(make_object(chat_id), std::move(query)); + break; + case td_api::botCommandScopeChatAdministrators::ID: + on_success(make_object(chat_id), std::move(query)); + break; + case td_api::botCommandScopeChatMember::ID: + check_user_no_fail( + user_id, std::move(query), + [chat_id, user_id, on_success = std::move(on_success)](PromisedQueryPtr query) mutable { + on_success(make_object(chat_id, user_id), std::move(query)); + }); + break; + default: + UNREACHABLE(); + } + }); +} + template void Client::check_remote_file_id(td::string file_id, PromisedQueryPtr query, OnSuccess on_success) { if (file_id.empty()) { @@ -5415,6 +5446,69 @@ td::Result> Client::get_inlin return Status::Error(400, PSLICE() << "type \"" << type << "\" is unsupported for the inline query result"); } +td::Result Client::get_bot_command_scope(JsonValue &&value) { + if (value.type() != JsonValue::Type::Object) { + return Status::Error(400, "BotCommandScope must be an Object"); + } + + auto &object = value.get_object(); + + TRY_RESULT(type, get_json_object_string_field(object, "type", false)); + if (type == "default") { + return BotCommandScope(make_object()); + } + if (type == "all_private_chats") { + return BotCommandScope(make_object()); + } + if (type == "all_group_chats") { + return BotCommandScope(make_object()); + } + if (type == "all_chat_administrators") { + return BotCommandScope(make_object()); + } + if (type != "chat" && type != "chat_administrators" && type != "chat_member") { + return Status::Error(400, "Unsupported type specified"); + } + + TRY_RESULT(chat_id, get_json_object_string_field(object, "chat_id", false)); + if (chat_id.empty()) { + return Status::Error(400, "Empty chat_id specified"); + } + if (type == "chat") { + return BotCommandScope(make_object(0), std::move(chat_id)); + } + if (type == "chat_administrators") { + return BotCommandScope(make_object(0), std::move(chat_id)); + } + + TRY_RESULT(user_id, get_json_object_int_field(object, "user_id", false)); + if (user_id <= 0) { + return Status::Error(400, "Invalid user_id specified"); + } + CHECK(type == "chat_member"); + return BotCommandScope(make_object(0, user_id), std::move(chat_id), user_id); +} + +td::Result Client::get_bot_command_scope(const Query *query) { + auto scope = query->arg("scope"); + if (scope.empty()) { + return BotCommandScope(make_object()); + } + + LOG(INFO) << "Parsing JSON object: " << scope; + auto r_value = json_decode(scope); + if (r_value.is_error()) { + LOG(INFO) << "Can't parse JSON object: " << r_value.error(); + return Status::Error(400, "Can't parse BotCommandScope JSON object"); + } + + auto r_scope = get_bot_command_scope(r_value.move_as_ok()); + if (r_scope.is_error()) { + return Status::Error(400, PSLICE() << "Can't parse BotCommandScope: " << r_scope.error().message()); + } + return r_scope.move_as_ok(); +} + td::Result> Client::get_bot_command(JsonValue &&value) { if (value.type() != JsonValue::Type::Object) { return Status::Error(400, "expected an Object"); @@ -6225,15 +6319,41 @@ td::Status Client::process_get_me_query(PromisedQueryPtr &query) { } td::Status Client::process_get_my_commands_query(PromisedQueryPtr &query) { - send_request(make_object(my_id_), - std::make_unique(std::move(query))); + TRY_RESULT(scope, get_bot_command_scope(query.get())); + + check_bot_command_scope(std::move(scope), std::move(query), + [this](object_ptr &&scope, PromisedQueryPtr query) mutable { + auto language_code = query->arg("language_code").str(); + send_request(make_object(std::move(scope), language_code), + std::make_unique(std::move(query))); + }); return Status::OK(); } td::Status Client::process_set_my_commands_query(PromisedQueryPtr &query) { TRY_RESULT(bot_commands, get_bot_commands(query.get())); - send_request(make_object(nullptr, "", std::move(bot_commands)), - std::make_unique(std::move(query))); + TRY_RESULT(scope, get_bot_command_scope(query.get())); + + check_bot_command_scope( + std::move(scope), std::move(query), + [this, bot_commands = std::move(bot_commands)](object_ptr &&scope, + PromisedQueryPtr query) mutable { + auto language_code = query->arg("language_code").str(); + send_request(make_object(std::move(scope), language_code, std::move(bot_commands)), + std::make_unique(std::move(query))); + }); + return Status::OK(); +} + +td::Status Client::process_delete_my_commands_query(PromisedQueryPtr &query) { + TRY_RESULT(scope, get_bot_command_scope(query.get())); + + check_bot_command_scope(std::move(scope), std::move(query), + [this](object_ptr &&scope, PromisedQueryPtr query) mutable { + auto language_code = query->arg("language_code").str(); + send_request(make_object(std::move(scope), language_code), + std::make_unique(std::move(query))); + }); return Status::OK(); } @@ -6557,7 +6677,7 @@ td::Status Client::process_copy_message_query(PromisedQueryPtr &query) { TRY_RESULT(from_chat_id, get_required_string_arg(query.get(), "from_chat_id")); auto message_id = get_message_id(query.get()); bool replace_caption = query->has_arg("caption"); - td_api::object_ptr caption; + object_ptr caption; if (replace_caption) { TRY_RESULT_ASSIGN(caption, get_caption(query.get())); } @@ -7176,8 +7296,8 @@ td::Status Client::process_get_chat_member_query(PromisedQueryPtr &query) { check_chat(chat_id, AccessRights::ReadMembers, std::move(query), [this, user_id](int64 chat_id, PromisedQueryPtr query) { get_chat_member(chat_id, user_id, std::move(query), - [this, chat_type = get_chat_type(chat_id)]( - td_api::object_ptr &&chat_member, PromisedQueryPtr query) { + [this, chat_type = get_chat_type(chat_id)](object_ptr &&chat_member, + PromisedQueryPtr query) { answer_query(JsonChatMember(chat_member.get(), chat_type, this), std::move(query)); }); }); @@ -7272,8 +7392,8 @@ td::Status Client::process_promote_chat_member_query(PromisedQueryPtr &query) { get_chat_member( chat_id, user_id, std::move(query), - [this, chat_id, user_id, status = std::move(status)]( - td_api::object_ptr &&chat_member, PromisedQueryPtr query) mutable { + [this, chat_id, user_id, status = std::move(status)](object_ptr &&chat_member, + PromisedQueryPtr query) mutable { if (chat_member->status_->get_id() == td_api::chatMemberStatusAdministrator::ID) { auto administrator = static_cast(chat_member->status_.get()); @@ -7300,7 +7420,7 @@ td::Status Client::process_set_chat_administrator_custom_title_query(PromisedQue get_chat_member( chat_id, user_id, std::move(query), - [this, chat_id, user_id](td_api::object_ptr &&chat_member, PromisedQueryPtr query) { + [this, chat_id, user_id](object_ptr &&chat_member, PromisedQueryPtr query) { if (chat_member->status_->get_id() == td_api::chatMemberStatusCreator::ID) { return fail_query(400, "Bad Request: only creator can edit their custom title", std::move(query)); } @@ -7358,7 +7478,7 @@ td::Status Client::process_restrict_chat_member_query(PromisedQueryPtr &query) { get_chat_member( chat_id, user_id, std::move(query), [this, chat_id, user_id, until_date, is_legacy, permissions = std::move(permissions)]( - td_api::object_ptr &&chat_member, PromisedQueryPtr query) mutable { + object_ptr &&chat_member, PromisedQueryPtr query) mutable { if (is_legacy && chat_member->status_->get_id() == td_api::chatMemberStatusRestricted::ID) { auto restricted = static_cast(chat_member->status_.get()); @@ -7394,18 +7514,18 @@ td::Status Client::process_unban_chat_member_query(PromisedQueryPtr &query) { } if (only_if_banned) { - get_chat_member(chat_id, user_id, std::move(query), - [this, chat_id, user_id](td_api::object_ptr &&chat_member, - PromisedQueryPtr query) { - if (chat_member->status_->get_id() != td_api::chatMemberStatusBanned::ID) { - return answer_query(td::JsonTrue(), std::move(query)); - } + get_chat_member( + chat_id, user_id, std::move(query), + [this, chat_id, user_id](object_ptr &&chat_member, PromisedQueryPtr query) { + if (chat_member->status_->get_id() != td_api::chatMemberStatusBanned::ID) { + return answer_query(td::JsonTrue(), std::move(query)); + } - send_request(make_object( - chat_id, td_api::make_object(user_id), - make_object()), - std::make_unique(std::move(query))); - }); + send_request(make_object( + chat_id, td_api::make_object(user_id), + make_object()), + std::make_unique(std::move(query))); + }); } else { check_user_no_fail(user_id, std::move(query), [this, chat_id, user_id](PromisedQueryPtr query) { send_request(make_object( diff --git a/telegram-bot-api/Client.h b/telegram-bot-api/Client.h index 40224b5..02b1f4b 100644 --- a/telegram-bot-api/Client.h +++ b/telegram-bot-api/Client.h @@ -211,6 +211,7 @@ class Client : public WebhookActor::Callback { struct UserInfo; struct ChatInfo; + struct BotCommandScope; enum class AccessRights { Read, ReadMembers, Edit, Write }; @@ -248,6 +249,9 @@ class Client : public WebhookActor::Callback { template void check_chat(Slice chat_id_str, AccessRights access_rights, PromisedQueryPtr query, OnSuccess on_success); + template + void check_bot_command_scope(BotCommandScope &&scope, PromisedQueryPtr query, OnSuccess on_success); + template void check_remote_file_id(td::string file_id, PromisedQueryPtr query, OnSuccess on_success); @@ -330,6 +334,21 @@ class Client : public WebhookActor::Callback { td::Result>> get_inline_query_results(td::JsonValue &&value); + struct BotCommandScope { + object_ptr scope_; + td::string chat_id_; + td::int32 user_id_ = 0; + + explicit BotCommandScope(object_ptr scope, td::string chat_id = td::string(), + td::int32 user_id = 0) + : scope_(std::move(scope)), chat_id_(std::move(chat_id)), user_id_(user_id) { + } + }; + + static td::Result get_bot_command_scope(const Query *query); + + static td::Result get_bot_command_scope(td::JsonValue &&value); + static td::Result> get_bot_command(td::JsonValue &&value); static td::Result>> get_bot_commands(const Query *query); @@ -416,6 +435,7 @@ class Client : public WebhookActor::Callback { Status process_get_me_query(PromisedQueryPtr &query); Status process_get_my_commands_query(PromisedQueryPtr &query); Status process_set_my_commands_query(PromisedQueryPtr &query); + Status process_delete_my_commands_query(PromisedQueryPtr &query); Status process_get_user_profile_photos_query(PromisedQueryPtr &query); Status process_send_message_query(PromisedQueryPtr &query); Status process_send_animation_query(PromisedQueryPtr &query); From b7af1798097a276f732b199dbebfa71b49d4c3c4 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 24 Jun 2021 17:27:15 +0300 Subject: [PATCH 23/25] Add logging on errors with non-positive error code. --- telegram-bot-api/Client.cpp | 4 ++++ telegram-bot-api/WebhookActor.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/telegram-bot-api/Client.cpp b/telegram-bot-api/Client.cpp index 6edf756..de13560 100644 --- a/telegram-bot-api/Client.cpp +++ b/telegram-bot-api/Client.cpp @@ -60,6 +60,10 @@ 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) { + LOG(ERROR) << "Receive error \"" << real_error_message << "\" with code " << error_code << " from " << *query; + } + error_code = 400; } if (error_code == 400) { diff --git a/telegram-bot-api/WebhookActor.cpp b/telegram-bot-api/WebhookActor.cpp index cf70695..31e3103 100644 --- a/telegram-bot-api/WebhookActor.cpp +++ b/telegram-bot-api/WebhookActor.cpp @@ -166,7 +166,7 @@ td::Status WebhookActor::create_connection() { Callback &operator=(Callback &&) = delete; ~Callback() { if (!actor_.empty()) { - send_closure(std::move(actor_), &WebhookActor::on_socket_ready_async, td::Status::Error("Cancelled"), id_); + send_closure(std::move(actor_), &WebhookActor::on_socket_ready_async, td::Status::Error("Canceled"), id_); } } void on_connected() override { From a4c562e4a51f01168e4b79e451a337870d66252c Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 24 Jun 2021 17:37:49 +0300 Subject: [PATCH 24/25] Update TDLib. --- td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/td b/td index 9628668..50d2d0f 160000 --- a/td +++ b/td @@ -1 +1 @@ -Subproject commit 9628668def2dfe5765cb049813ce504c8f7a5b49 +Subproject commit 50d2d0ff000c0a6ab78bfb8a6f56ba496b548677 From 81f298361cf80d1d6c70a074ff88534bd3d450b3 Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 25 Jun 2021 04:20:57 +0300 Subject: [PATCH 25/25] Update version to 5.3. --- 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 65eee35..9af6665 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if (POLICY CMP0065) cmake_policy(SET CMP0065 NEW) endif() -project(TelegramBotApi VERSION 5.2 LANGUAGES CXX) +project(TelegramBotApi VERSION 5.3 LANGUAGES CXX) add_subdirectory(td EXCLUDE_FROM_ALL) diff --git a/telegram-bot-api/telegram-bot-api.cpp b/telegram-bot-api/telegram-bot-api.cpp index c43ad34..3f4769b 100644 --- a/telegram-bot-api/telegram-bot-api.cpp +++ b/telegram-bot-api/telegram-bot-api.cpp @@ -192,7 +192,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.2"; + parameters->version_ = "5.3"; parameters->shared_data_ = shared_data; parameters->start_time_ = start_time; auto net_query_stats = td::create_net_query_stats();