diff --git a/CMakeLists.txt b/CMakeLists.txt index 6baa2f3d8..799787125 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -220,6 +220,7 @@ if (NOT MSVC) add_cxx_compiler_flag("-Wno-sign-conversion") add_cxx_compiler_flag("-Wc++14-compat-pedantic") add_cxx_compiler_flag("-Wdeprecated") + add_cxx_compiler_flag("-Wno-unused-command-line-argument") add_cxx_compiler_flag("-Qunused-arguments") add_cxx_compiler_flag("-Wodr") add_cxx_compiler_flag("-flto-odr-type-merging") diff --git a/example/java/CMakeLists.txt b/example/java/CMakeLists.txt index edc8246a0..46373743f 100644 --- a/example/java/CMakeLists.txt +++ b/example/java/CMakeLists.txt @@ -15,7 +15,7 @@ endif() message(STATUS "Found JNI: ${JNI_INCLUDE_DIRS} ${JNI_LIBRARIES}") if (NOT Java_FOUND) - find_package(Java 1.6 REQUIRED) + find_package(Java REQUIRED) endif() message(STATUS "Found Java: ${Java_JAVAC_EXECUTABLE} ${Java_JAVADOC_EXECUTABLE}") diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index f7475fc81..94dcb3fbe 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -301,7 +301,7 @@ venue location:location title:string address:string provider:string id:string ty //@param_description Game description @photo Game photo @animation Game animation; may be null game id:int64 short_name:string title:string text:formattedText description:string photo:photo animation:animation = Game; -//@description Describes a poll @id Unique poll identifier @question Poll question, 1-255 characters @options List of poll answer options +//@description Describes a poll @id Unique poll identifier @question Poll question, 1-300 characters @options List of poll answer options //@total_voter_count Total number of voters, participating in the poll @recent_voter_user_ids User identifiers of recent voters, if the poll is non-anonymous //@is_anonymous True, if the poll is anonymous @type Type of the poll //@open_period Amount of time the poll will be active after creation, in seconds @close_date Point in time (Unix timestamp) when the poll will be automatically closed @is_closed True, if the poll is closed @@ -428,7 +428,7 @@ chatAdministrators administrators:vector = ChatAdministrators //@can_send_messages True, if the user can send text messages, contacts, locations, and venues //@can_send_media_messages True, if the user can send audio files, documents, photos, videos, video notes, and voice notes. Implies can_send_messages permissions //@can_send_polls True, if the user can send polls. Implies can_send_messages permissions -//@can_send_other_messages True, if the user can send animations, games, and stickers and use inline bots. Implies can_send_messages permissions +//@can_send_other_messages True, if the user can send animations, games, stickers and dice and use inline bots. Implies can_send_messages permissions //@can_add_web_page_previews True, if the user may add a web page preview to their messages. Implies can_send_messages permissions //@can_change_info True, if the user can change the chat title, photo, and other settings //@can_invite_users True, if the user can invite new users to the chat @@ -1750,7 +1750,7 @@ inputMessageGame bot_user_id:int32 game_short_name:string = InputMessageContent; //@payload The invoice payload @provider_token Payment provider token @provider_data JSON-encoded data about the invoice, which will be shared with the payment provider @start_parameter Unique invoice bot start_parameter for the generation of this invoice inputMessageInvoice invoice:invoice title:string description:string photo_url:string photo_size:int32 photo_width:int32 photo_height:int32 payload:bytes provider_token:string provider_data:string start_parameter:string = InputMessageContent; -//@description A message with a poll. Polls can't be sent to secret chats. Polls can be sent only to a private chat with a bot @question Poll question, 1-255 characters @options List of poll answer options, 2-10 strings 1-100 characters each +//@description A message with a poll. Polls can't be sent to secret chats. Polls can be sent only to a private chat with a bot @question Poll question, 1-255 characters (up to 300 characters for bots) @options List of poll answer options, 2-10 strings 1-100 characters each //@is_anonymous True, if the poll voters are anonymous. Non-anonymous polls can't be sent or forwarded to channels @type Type of the poll //@open_period Amount of time the poll will be active after creation, in seconds; for bots only //@close_date Point in time (Unix timestamp) when the poll will be automatically closed; for bots only @@ -3244,7 +3244,7 @@ updateSelectedBackground for_dark_theme:Bool background:background = Update; //@description Some language pack strings have been updated @localization_target Localization target to which the language pack belongs @language_pack_id Identifier of the updated language pack @strings List of changed language pack strings updateLanguagePackStrings localization_target:string language_pack_id:string strings:vector = Update; -//@description The connection state has changed @state The new connection state +//@description The connection state has changed. This update must be used only to show the user a human-readable description of the connection state @state The new connection state updateConnectionState state:ConnectionState = Update; //@description New terms of service must be accepted by the user. If the terms of service are declined, then the deleteAccount method should be called with the reason "Decline ToS update" @terms_of_service_id Identifier of the terms of service @terms_of_service The new terms of service @@ -3339,7 +3339,7 @@ testVectorStringObject value:vector = TestVectorStringObject; ---functions--- -//@description Returns the current authorization state; this is an offline request. For informational purposes only. Use updateAuthorizationState instead to maintain the current authorization state +//@description Returns the current authorization state; this is an offline request. For informational purposes only. Use updateAuthorizationState instead to maintain the current authorization state. Can be called before initialization getAuthorizationState = AuthorizationState; @@ -3384,10 +3384,10 @@ checkAuthenticationBotToken token:string = Ok; //@description Closes the TDLib instance after a proper logout. Requires an available network connection. All local data will be destroyed. After the logout completes, updateAuthorizationState with authorizationStateClosed will be sent logOut = Ok; -//@description Closes the TDLib instance. All databases will be flushed to disk and properly closed. After the close completes, updateAuthorizationState with authorizationStateClosed will be sent +//@description Closes the TDLib instance. All databases will be flushed to disk and properly closed. After the close completes, updateAuthorizationState with authorizationStateClosed will be sent. Can be called before initialization close = Ok; -//@description Closes the TDLib instance, destroying all local data without a proper logout. The current user session will remain in the list of all active sessions. All local data will be destroyed. After the destruction completes updateAuthorizationState with authorizationStateClosed will be sent +//@description Closes the TDLib instance, destroying all local data without a proper logout. The current user session will remain in the list of all active sessions. All local data will be destroyed. After the destruction completes updateAuthorizationState with authorizationStateClosed will be sent. Can be called before authorization destroy = Ok; @@ -3395,7 +3395,7 @@ destroy = Ok; confirmQrCodeAuthentication link:string = Session; -//@description Returns all updates needed to restore current TDLib state, i.e. all actual UpdateAuthorizationState/UpdateUser/UpdateNewChat and others. This is especially useful if TDLib is run in a separate process. This is an offline method. Can be called before authorization +//@description Returns all updates needed to restore current TDLib state, i.e. all actual UpdateAuthorizationState/UpdateUser/UpdateNewChat and others. This is especially useful if TDLib is run in a separate process. Can be called before initialization getCurrentState = Updates; @@ -3720,36 +3720,36 @@ editInlineMessageReplyMarkup inline_message_id:string reply_markup:ReplyMarkup = editMessageSchedulingState chat_id:int53 message_id:int53 scheduling_state:MessageSchedulingState = Ok; -//@description Returns all entities (mentions, hashtags, cashtags, bot commands, bank card numbers, URLs, and email addresses) contained in the text. This is an offline method. Can be called before authorization. Can be called synchronously @text The text in which to look for entites +//@description Returns all entities (mentions, hashtags, cashtags, bot commands, bank card numbers, URLs, and email addresses) contained in the text. Can be called synchronously @text The text in which to look for entites getTextEntities text:string = TextEntities; -//@description Parses Bold, Italic, Underline, Strikethrough, Code, Pre, PreCode, TextUrl and MentionName entities contained in the text. This is an offline method. Can be called before authorization. Can be called synchronously @text The text to parse @parse_mode Text parse mode +//@description Parses Bold, Italic, Underline, Strikethrough, Code, Pre, PreCode, TextUrl and MentionName entities contained in the text. Can be called synchronously @text The text to parse @parse_mode Text parse mode parseTextEntities text:string parse_mode:TextParseMode = FormattedText; -//@description Parses Markdown entities in a human-friendly format, ignoring mark up errors. This is an offline method. Can be called before authorization. Can be called synchronously +//@description Parses Markdown entities in a human-friendly format, ignoring markup errors. Can be called synchronously //@text The text to parse. For example, "__italic__ ~~strikethrough~~ **bold** `code` ```pre``` __[italic__ text_url](telegram.org) __italic**bold italic__bold**" parseMarkdown text:formattedText = FormattedText; -//@description Replaces text entities with Markdown formatting in a human-friendly format. Entities that can't be represented in Markdown unambiguously are kept as is. This is an offline method. Can be called before authorization. Can be called synchronously @text The text +//@description Replaces text entities with Markdown formatting in a human-friendly format. Entities that can't be represented in Markdown unambiguously are kept as is. Can be called synchronously @text The text getMarkdownText text:formattedText = FormattedText; -//@description Returns the MIME type of a file, guessed by its extension. Returns an empty string on failure. This is an offline method. Can be called before authorization. Can be called synchronously @file_name The name of the file or path to the file +//@description Returns the MIME type of a file, guessed by its extension. Returns an empty string on failure. Can be called synchronously @file_name The name of the file or path to the file getFileMimeType file_name:string = Text; -//@description Returns the extension of a file, guessed by its MIME type. Returns an empty string on failure. This is an offline method. Can be called before authorization. Can be called synchronously @mime_type The MIME type of the file +//@description Returns the extension of a file, guessed by its MIME type. Returns an empty string on failure. Can be called synchronously @mime_type The MIME type of the file getFileExtension mime_type:string = Text; -//@description Removes potentially dangerous characters from the name of a file. The encoding of the file name is supposed to be UTF-8. Returns an empty string on failure. This is an offline method. Can be called before authorization. Can be called synchronously @file_name File name or path to the file +//@description Removes potentially dangerous characters from the name of a file. The encoding of the file name is supposed to be UTF-8. Returns an empty string on failure. Can be called synchronously @file_name File name or path to the file cleanFileName file_name:string = Text; -//@description Returns a string stored in the local database from the specified localization target and language pack by its key. Returns a 404 error if the string is not found. This is an offline method. Can be called before authorization. Can be called synchronously +//@description Returns a string stored in the local database from the specified localization target and language pack by its key. Returns a 404 error if the string is not found. Can be called synchronously //@language_pack_database_path Path to the language pack database in which strings are stored @localization_target Localization target to which the language pack belongs @language_pack_id Language pack identifier @key Language pack key of the string to be returned getLanguagePackString language_pack_database_path:string localization_target:string language_pack_id:string key:string = LanguagePackStringValue; -//@description Converts a JSON-serialized string to corresponding JsonValue object. This is an offline method. Can be called before authorization. Can be called synchronously @json The JSON-serialized string +//@description Converts a JSON-serialized string to corresponding JsonValue object. Can be called synchronously @json The JSON-serialized string getJsonValue json:string = JsonValue; -//@description Converts a JsonValue object to corresponding JSON-serialized string. This is an offline method. Can be called before authorization. Can be called synchronously @json_value The JsonValue object +//@description Converts a JsonValue object to corresponding JSON-serialized string. Can be called synchronously @json_value The JsonValue object getJsonString json_value:JsonValue = Text; @@ -3901,7 +3901,7 @@ reorderChatFilters chat_filter_ids:vector = Ok; //@description Returns recommended chat filters for the current user getRecommendedChatFilters = RecommendedChatFilters; -//@description Returns default icon name for a filter. This is an offline method. Can be called before authorization. Can be called synchronously @filter Chat filter +//@description Returns default icon name for a filter. Can be called synchronously @filter Chat filter getChatFilterDefaultIconName filter:chatFilter = Text; @@ -4408,7 +4408,7 @@ registerDevice device_token:DeviceToken other_user_ids:vector = PushRecei //@payload JSON-encoded push notification payload with all fields sent by the server, and "google.sent_time" and "google.notification.sound" fields added processPushNotification payload:string = Ok; -//@description Returns a globally unique push notification subscription identifier for identification of an account, which has received a push notification. This is an offline method. Can be called before authorization. Can be called synchronously @payload JSON-encoded push notification payload +//@description Returns a globally unique push notification subscription identifier for identification of an account, which has received a push notification. Can be called synchronously @payload JSON-encoded push notification payload getPushReceiverId payload:string = PushReceiverId; @@ -4616,7 +4616,7 @@ sendCustomRequest method:string parameters:string = CustomRequestResult; answerCustomQuery custom_query_id:int64 data:string = Ok; -//@description Succeeds after a specified amount of time has passed. Can be called before authorization. Can be called before initialization @seconds Number of seconds before the function returns +//@description Succeeds after a specified amount of time has passed. Can be called before initialization @seconds Number of seconds before the function returns setAlarm seconds:double = Ok; @@ -4662,30 +4662,30 @@ getProxyLink proxy_id:int32 = Text; pingProxy proxy_id:int32 = Seconds; -//@description Sets new log stream for internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously @log_stream New log stream +//@description Sets new log stream for internal logging of TDLib. Can be called synchronously @log_stream New log stream setLogStream log_stream:LogStream = Ok; -//@description Returns information about currently used log stream for internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously +//@description Returns information about currently used log stream for internal logging of TDLib. Can be called synchronously getLogStream = LogStream; -//@description Sets the verbosity level of the internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously +//@description Sets the verbosity level of the internal logging of TDLib. Can be called synchronously //@new_verbosity_level New value of the verbosity level for logging. Value 0 corresponds to fatal errors, value 1 corresponds to errors, value 2 corresponds to warnings and debug warnings, value 3 corresponds to informational, value 4 corresponds to debug, value 5 corresponds to verbose debug, value greater than 5 and up to 1023 can be used to enable even more logging setLogVerbosityLevel new_verbosity_level:int32 = Ok; -//@description Returns current verbosity level of the internal logging of TDLib. This is an offline method. Can be called before authorization. Can be called synchronously +//@description Returns current verbosity level of the internal logging of TDLib. Can be called synchronously getLogVerbosityLevel = LogVerbosityLevel; -//@description Returns list of available TDLib internal log tags, for example, ["actor", "binlog", "connections", "notifications", "proxy"]. This is an offline method. Can be called before authorization. Can be called synchronously +//@description Returns list of available TDLib internal log tags, for example, ["actor", "binlog", "connections", "notifications", "proxy"]. Can be called synchronously getLogTags = LogTags; -//@description Sets the verbosity level for a specified TDLib internal log tag. This is an offline method. Can be called before authorization. Can be called synchronously +//@description Sets the verbosity level for a specified TDLib internal log tag. Can be called synchronously //@tag Logging tag to change verbosity level @new_verbosity_level New verbosity level; 1-1024 setLogTagVerbosityLevel tag:string new_verbosity_level:int32 = Ok; -//@description Returns current verbosity level for a specified TDLib internal log tag. This is an offline method. Can be called before authorization. Can be called synchronously @tag Logging tag to change verbosity level +//@description Returns current verbosity level for a specified TDLib internal log tag. Can be called synchronously @tag Logging tag to change verbosity level getLogTagVerbosityLevel tag:string = LogVerbosityLevel; -//@description Adds a message to TDLib internal log. This is an offline method. Can be called before authorization. Can be called synchronously +//@description Adds a message to TDLib internal log. Can be called synchronously //@verbosity_level The minimum verbosity level needed for the message to be logged, 0-1023 @text Text of a message to log addLogMessage verbosity_level:int32 text:string = Ok; @@ -4715,5 +4715,5 @@ testProxy server:string port:int32 type:ProxyType dc_id:int32 timeout:double = O testGetDifference = Ok; //@description Does nothing and ensures that the Update object is used; for testing only. This is an offline method. Can be called before authorization testUseUpdate = Update; -//@description Returns the specified error and ensures that the Error object is used; for testing only. This is an offline method. Can be called before authorization. Can be called synchronously @error The error to be returned +//@description Returns the specified error and ensures that the Error object is used; for testing only. Can be called synchronously @error The error to be returned testReturnError error:error = Error; diff --git a/td/telegram/Client.cpp b/td/telegram/Client.cpp index d3e368e97..e8e6cbe49 100644 --- a/td/telegram/Client.cpp +++ b/td/telegram/Client.cpp @@ -67,7 +67,7 @@ class TdReceiver { MultiClient::Response receive(double timeout) { if (!responses_.empty()) { auto result = std::move(responses_.front()); - responses_.pop_front(); + responses_.pop(); return result; } return {0, 0, nullptr}; @@ -79,17 +79,17 @@ class TdReceiver { Callback(MultiClient::ClientId client_id, TdReceiver *impl) : client_id_(client_id), impl_(impl) { } void on_result(uint64 id, td_api::object_ptr result) override { - impl_->responses_.push_back({client_id_, id, std::move(result)}); + impl_->responses_.push({client_id_, id, std::move(result)}); } void on_error(uint64 id, td_api::object_ptr error) override { - impl_->responses_.push_back({client_id_, id, std::move(error)}); + impl_->responses_.push({client_id_, id, std::move(error)}); } Callback(const Callback &) = delete; Callback &operator=(const Callback &) = delete; Callback(Callback &&) = delete; Callback &operator=(Callback &&) = delete; ~Callback() override { - impl_->responses_.push_back({client_id_, 0, nullptr}); + impl_->responses_.push({client_id_, 0, nullptr}); } private: @@ -153,7 +153,6 @@ class MultiClient::Impl final { return response; } - Impl() = default; Impl(const Impl &) = delete; Impl &operator=(const Impl &) = delete; Impl(Impl &&) = delete; diff --git a/td/telegram/Client.h b/td/telegram/Client.h index 40f50613a..d88c2ccb1 100644 --- a/td/telegram/Client.h +++ b/td/telegram/Client.h @@ -161,6 +161,7 @@ class MultiClient final { MultiClient &operator=(MultiClient &&other); private: + friend class Client; class Impl; std::unique_ptr impl_; }; diff --git a/td/telegram/ConfigManager.cpp b/td/telegram/ConfigManager.cpp index c8dae2040..23bd09036 100644 --- a/td/telegram/ConfigManager.cpp +++ b/td/telegram/ConfigManager.cpp @@ -1055,7 +1055,7 @@ void ConfigManager::request_config_from_dc_impl(DcId dc_id) { config_sent_cnt_++; auto query = G()->net_query_creator().create_unauth(telegram_api::help_getConfig(), dc_id); query->total_timeout_limit_ = 60 * 60 * 24; - G()->net_query_dispatcher().dispatch_with_callback(std::move(query), actor_shared(this, 0)); + G()->net_query_dispatcher().dispatch_with_callback(std::move(query), actor_shared(this, 8)); } void ConfigManager::do_set_ignore_sensitive_content_restrictions(bool ignore_sensitive_content_restrictions) { @@ -1276,7 +1276,7 @@ void ConfigManager::on_result(NetQueryPtr res) { return; } - CHECK(token == 0); + CHECK(token == 8); CHECK(config_sent_cnt_ > 0); config_sent_cnt_--; auto r_config = fetch_result(std::move(res)); diff --git a/td/telegram/DelayDispatcher.cpp b/td/telegram/DelayDispatcher.cpp index 69ce597fd..487ae0f2c 100644 --- a/td/telegram/DelayDispatcher.cpp +++ b/td/telegram/DelayDispatcher.cpp @@ -62,6 +62,7 @@ void DelayDispatcher::tear_down() { query.net_query->set_error(Status::Error(500, "Request aborted")); send_closure(std::move(query.callback), &NetQueryCallback::on_result, std::move(query.net_query)); } + parent_.reset(); } } // namespace td diff --git a/td/telegram/DelayDispatcher.h b/td/telegram/DelayDispatcher.h index dba3ec083..0e9ef76ec 100644 --- a/td/telegram/DelayDispatcher.h +++ b/td/telegram/DelayDispatcher.h @@ -18,7 +18,8 @@ namespace td { class DelayDispatcher : public Actor { public: - explicit DelayDispatcher(double default_delay) : default_delay_(default_delay) { + DelayDispatcher(double default_delay, ActorShared<> parent) + : default_delay_(default_delay), parent_(std::move(parent)) { } void send_with_callback(NetQueryPtr query, ActorShared callback); @@ -35,6 +36,7 @@ class DelayDispatcher : public Actor { std::queue queue_; Timestamp wakeup_at_; double default_delay_; + ActorShared<> parent_; void loop() override; void tear_down() override; diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index f776376f5..f803cec7b 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -8116,7 +8116,8 @@ void MessagesManager::after_get_difference() { auto *list = get_dialog_list(dialog_list_id); CHECK(list != nullptr); if (!list->is_dialog_unread_count_inited_) { - get_dialogs(dialog_list_id, MIN_DIALOG_DATE, 1, false, PromiseCreator::lambda([dialog_list_id](Unit) { + get_dialogs(dialog_list_id, MIN_DIALOG_DATE, static_cast(list->pinned_dialogs_.size() + 2), false, + PromiseCreator::lambda([dialog_list_id](Unit) { if (!G()->close_flag()) { LOG(INFO) << "Inited total chat count in " << dialog_list_id; } @@ -10862,6 +10863,7 @@ void MessagesManager::start_up() { } void MessagesManager::create_folders() { + LOG(INFO) << "Create folders"; dialog_folders_[FolderId::main()].folder_id = FolderId::main(); dialog_folders_[FolderId::archive()].folder_id = FolderId::archive(); @@ -10879,15 +10881,16 @@ void MessagesManager::init() { start_time_ = Time::now(); - bool is_authorized_user = td_->auth_manager_->is_authorized() && !td_->auth_manager_->is_bot(); - if (is_authorized_user) { + bool is_authorized = td_->auth_manager_->is_authorized(); + bool was_authorized_user = td_->auth_manager_->was_authorized() && !td_->auth_manager_->is_bot(); + if (was_authorized_user) { create_folders(); // ensure that Main and Archive dialog lists are created } - if (td_->auth_manager_->is_authorized() && td_->auth_manager_->is_bot()) { + if (is_authorized && td_->auth_manager_->is_bot()) { disable_get_dialog_filter_ = true; } - if (is_authorized_user) { + if (was_authorized_user) { vector scopes{NotificationSettingsScope::Private, NotificationSettingsScope::Group, NotificationSettingsScope::Channel}; for (auto scope : scopes) { @@ -10905,7 +10908,7 @@ void MessagesManager::init() { send_closure(G()->td(), &Td::send_update, get_update_scope_notification_settings_object(scope)); } } - if (!channels_notification_settings_.is_synchronized) { + if (!channels_notification_settings_.is_synchronized && is_authorized) { channels_notification_settings_ = chats_notification_settings_; channels_notification_settings_.disable_pinned_message_notifications = false; channels_notification_settings_.disable_mention_notifications = false; @@ -10915,7 +10918,7 @@ void MessagesManager::init() { } G()->td_db()->get_binlog_pmc()->erase("nsfac"); - if (is_authorized_user) { + if (was_authorized_user) { auto dialog_filters = G()->td_db()->get_binlog_pmc()->get("dialog_filters"); if (!dialog_filters.empty()) { DialogFiltersLogEvent log_event; @@ -10939,7 +10942,7 @@ void MessagesManager::init() { send_update_chat_filters(); // always send updateChatFilters } - if (G()->parameters().use_message_db && is_authorized_user) { + if (G()->parameters().use_message_db && was_authorized_user) { // erase old keys G()->td_db()->get_binlog_pmc()->erase("last_server_dialog_date"); G()->td_db()->get_binlog_pmc()->erase("unread_message_count"); @@ -11114,7 +11117,7 @@ void MessagesManager::init() { load_calls_db_state(); - if (is_authorized_user) { + if (was_authorized_user && is_authorized) { if (need_synchronize_dialog_filters()) { reload_dialog_filters(); } else { @@ -24948,6 +24951,11 @@ void MessagesManager::send_update_new_chat(Dialog *d, int64 real_order) { } void MessagesManager::send_update_chat_draft_message(const Dialog *d) { + if (td_->auth_manager_->is_bot()) { + // just in case + return; + } + CHECK(d != nullptr); LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_draft_message"; on_dialog_updated(d->dialog_id, "send_update_chat_draft_message"); @@ -24964,9 +24972,16 @@ void MessagesManager::send_update_chat_last_message(Dialog *d, const char *sourc } void MessagesManager::send_update_chat_last_message_impl(const Dialog *d, const char *source) const { + if (td_->auth_manager_->is_bot()) { + return; + } + //TDLIGHT-PATCH-START if (!G()->shared_config().get_option_boolean("ignore_update_chat_last_message")) { + return; + } //TDLIGHT-PATCH-END + CHECK(d != nullptr); LOG_CHECK(d->is_update_new_chat_sent) << "Wrong " << d->dialog_id << " in send_update_chat_last_message from " << source; @@ -24975,9 +24990,6 @@ void MessagesManager::send_update_chat_last_message_impl(const Dialog *d, const d->dialog_id.get(), get_message_object(d->dialog_id, get_message(d, d->last_message_id)), get_chat_positions_object(d)); send_closure(G()->td(), &Td::send_update, std::move(update)); - //TDLIGHT-PATCH-START - } - //TDLIGHT-PATCH-END } void MessagesManager::send_update_chat_filters() { @@ -30899,9 +30911,18 @@ bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_sen DialogDate old_date(d->order, dialog_id); DialogDate new_date(new_order, dialog_id); - auto &folder = *get_dialog_folder(d->folder_id); if (old_date == new_date) { - LOG(INFO) << "Order of " << d->dialog_id << " is still " << new_order << " from " << source; + LOG(INFO) << "Order of " << d->dialog_id << " from " << d->folder_id << " is still " << new_order << " from " + << source; + } else { + LOG(INFO) << "Update order of " << dialog_id << " from " << d->folder_id << " from " << d->order << " to " + << new_order << " from " << source; + } + + auto folder_ptr = get_dialog_folder(d->folder_id); + CHECK(folder_ptr != nullptr); + auto &folder = *folder_ptr; + if (old_date == new_date) { if (new_order == DEFAULT_ORDER) { // first addition of a new left dialog if (folder.ordered_dialogs_.insert(new_date).second) { @@ -30916,8 +30937,6 @@ bool MessagesManager::set_dialog_order(Dialog *d, int64 new_order, bool need_sen return false; } - LOG(INFO) << "Update order of " << dialog_id << " from " << d->order << " to " << new_order << " from " << source; - auto dialog_positions = get_dialog_positions(d); if (folder.ordered_dialogs_.erase(old_date) == 0) { @@ -31572,6 +31591,9 @@ MessagesManager::DialogList &MessagesManager::add_dialog_list(DialogListId dialo if (dialog_list_id.is_folder() && dialog_list_id.get_folder_id() != FolderId::archive()) { dialog_list_id = DialogListId(FolderId::main()); } + if (dialog_lists_.find(dialog_list_id) == dialog_lists_.end()) { + LOG(INFO) << "Create " << dialog_list_id; + } auto &list = dialog_lists_[dialog_list_id]; list.dialog_list_id = dialog_list_id; return list; diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 49b4b64ef..c267253cb 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2818,7 +2818,7 @@ class MessagesManager : public Actor { KHeap ttl_heap_; Slot ttl_slot_; - enum YieldType : int32 { None, Ttl, TtlDb }; // None must be first + enum YieldType : int32 { None, TtlDb }; // None must be first int32 ttl_db_expires_from_; int32 ttl_db_expires_till_; bool ttl_db_has_query_; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index aeb3caf05..c69bae077 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -3378,6 +3378,8 @@ void Td::request(uint64 id, tl_object_ptr function) { return send_result(id, get_fake_authorization_state_object()); case td_api::getCurrentState::ID: { vector> updates; + updates.push_back(td_api::make_object( + "version", td_api::make_object(TDLIB_VERSION))); updates.push_back(td_api::make_object(get_fake_authorization_state_object())); // send response synchronously to prevent "Request aborted" return send_result(id, td_api::make_object(std::move(updates))); diff --git a/td/telegram/files/FileLoadManager.cpp b/td/telegram/files/FileLoadManager.cpp index 59ed04db2..6cf56069e 100644 --- a/td/telegram/files/FileLoadManager.cpp +++ b/td/telegram/files/FileLoadManager.cpp @@ -158,7 +158,8 @@ void FileLoadManager::update_local_file_location(QueryId id, const LocalFileLoca } send_closure(node->loader_, &FileLoaderActor::update_local_file_location, local); } -void FileLoadManager::update_download_offset(QueryId id, int64 offset) { + +void FileLoadManager::update_downloaded_part(QueryId id, int64 offset, int64 limit) { if (stop_flag_) { return; } @@ -170,22 +171,9 @@ void FileLoadManager::update_download_offset(QueryId id, int64 offset) { if (node == nullptr) { return; } - send_closure(node->loader_, &FileLoaderActor::update_download_offset, offset); -} -void FileLoadManager::update_download_limit(QueryId id, int64 limit) { - if (stop_flag_) { - return; - } - auto it = query_id_to_node_id_.find(id); - if (it == query_id_to_node_id_.end()) { - return; - } - auto node = nodes_container_.get(it->second); - if (node == nullptr) { - return; - } - send_closure(node->loader_, &FileLoaderActor::update_download_limit, limit); + send_closure(node->loader_, &FileLoaderActor::update_downloaded_part, offset, limit); } + void FileLoadManager::hangup() { nodes_container_.for_each([](auto id, auto &node) { node.loader_.reset(); }); stop_flag_ = true; diff --git a/td/telegram/files/FileLoadManager.h b/td/telegram/files/FileLoadManager.h index 0aa2b58fa..8519b14ab 100644 --- a/td/telegram/files/FileLoadManager.h +++ b/td/telegram/files/FileLoadManager.h @@ -58,8 +58,7 @@ class FileLoadManager final : public Actor { void from_bytes(QueryId id, FileType type, BufferSlice bytes, string name); void cancel(QueryId id); void update_local_file_location(QueryId id, const LocalFileLocation &local); - void update_download_offset(QueryId id, int64 offset); - void update_download_limit(QueryId id, int64 limit); + void update_downloaded_part(QueryId id, int64 offset, int64 limit); void get_content(const FullLocalFileLocation &local_location, Promise promise); private: diff --git a/td/telegram/files/FileLoader.cpp b/td/telegram/files/FileLoader.cpp index 40a6ec41b..462c8e966 100644 --- a/td/telegram/files/FileLoader.cpp +++ b/td/telegram/files/FileLoader.cpp @@ -40,12 +40,15 @@ void FileLoader::set_ordered_flag(bool flag) { size_t FileLoader::get_part_size() const { return parts_manager_.get_part_size(); } + void FileLoader::hangup() { - // if (!stop_flag_) { - // stop_flag_ = true; - // on_error(Status::Error("Cancelled")); - //} - stop(); + delay_dispatcher_.reset(); +} + +void FileLoader::hangup_shared() { + if (get_link_token() == 1) { + stop(); + } } void FileLoader::update_local_file_location(const LocalFileLocation &local) { @@ -65,24 +68,27 @@ void FileLoader::update_local_file_location(const LocalFileLocation &local) { loop(); } -void FileLoader::update_download_offset(int64 offset) { +void FileLoader::update_downloaded_part(int64 offset, int64 limit) { if (parts_manager_.get_streaming_offset() != offset) { - parts_manager_.set_streaming_offset(offset); - //TODO: cancel only some queries + auto begin_part_id = parts_manager_.set_streaming_offset(offset, limit); + auto new_end_part_id = limit <= 0 ? parts_manager_.get_part_count() + : static_cast((offset + limit - 1) / parts_manager_.get_part_size()) + 1; + auto max_parts = static_cast(ResourceManager::MAX_RESOURCE_LIMIT / parts_manager_.get_part_size()); + auto end_part_id = begin_part_id + td::min(max_parts, new_end_part_id - begin_part_id); + VLOG(files) << "Protect parts " << begin_part_id << " ... " << end_part_id - 1; for (auto &it : part_map_) { - it.second.second.reset(); // cancel_query(it.second.second); + if (!it.second.second.empty() && !(begin_part_id <= it.second.first.id && it.second.first.id < end_part_id)) { + VLOG(files) << "Cancel part " << it.second.first.id; + it.second.second.reset(); // cancel_query(it.second.second); + } } + } else { + parts_manager_.set_streaming_limit(limit); } update_estimated_limit(); loop(); } -void FileLoader::update_download_limit(int64 limit) { - parts_manager_.set_streaming_limit(limit); - update_estimated_limit(); - loop(); -} - void FileLoader::start_up() { auto r_file_info = init(); if (r_file_info.is_error()) { @@ -120,13 +126,12 @@ void FileLoader::start_up() { if (file_info.only_check) { parts_manager_.set_checked_prefix_size(0); } - parts_manager_.set_streaming_offset(file_info.offset); - parts_manager_.set_streaming_limit(file_info.limit); + parts_manager_.set_streaming_offset(file_info.offset, file_info.limit); if (ordered_flag_) { ordered_parts_ = OrderedEventsProcessor>(parts_manager_.get_ready_prefix_count()); } if (file_info.need_delay) { - delay_dispatcher_ = create_actor("DelayDispatcher", 0.003); + delay_dispatcher_ = create_actor("DelayDispatcher", 0.003, actor_shared(this, 1)); next_delay_ = 0.05; } resource_state_.set_unit_size(parts_manager_.get_part_size()); @@ -149,6 +154,7 @@ void FileLoader::loop() { return; } } + Status FileLoader::do_loop() { TRY_RESULT(check_info, check_loop(parts_manager_.get_checked_prefix_size(), parts_manager_.get_unchecked_ready_prefix_size(), @@ -210,6 +216,7 @@ Status FileLoader::do_loop() { if (delay_dispatcher_.empty()) { G()->net_query_dispatcher().dispatch_with_callback(std::move(query), std::move(callback)); } else { + query->debug("sent to DelayDispatcher"); send_closure(delay_dispatcher_, &DelayDispatcher::send_with_callback_and_delay, std::move(query), std::move(callback), next_delay_); next_delay_ = max(next_delay_ * 0.8, 0.003); @@ -223,8 +230,11 @@ void FileLoader::tear_down() { it.second.second.reset(); // cancel_query(it.second.second); } ordered_parts_.clear([](auto &&part) { part.second->clear(); }); - send_closure(std::move(delay_dispatcher_), &DelayDispatcher::close_silent); + if (!delay_dispatcher_.empty()) { + send_closure(std::move(delay_dispatcher_), &DelayDispatcher::close_silent); + } } + void FileLoader::update_estimated_limit() { if (stop_flag_) { return; @@ -259,6 +269,7 @@ void FileLoader::on_result(NetQueryPtr query) { Part part = it->second.first; it->second.second.release(); CHECK(query->is_ready()); + part_map_.erase(it); bool next = false; auto status = [&] { diff --git a/td/telegram/files/FileLoader.h b/td/telegram/files/FileLoader.h index 82a1697b3..f213961cc 100644 --- a/td/telegram/files/FileLoader.h +++ b/td/telegram/files/FileLoader.h @@ -8,6 +8,7 @@ #include "td/actor/actor.h" +#include "td/telegram/DelayDispatcher.h" #include "td/telegram/files/FileLoaderActor.h" #include "td/telegram/files/FileLocation.h" #include "td/telegram/files/PartsManager.h" @@ -15,8 +16,6 @@ #include "td/telegram/files/ResourceState.h" #include "td/telegram/net/NetQuery.h" -#include "td/telegram/DelayDispatcher.h" - #include "td/utils/OrderedEventsProcessor.h" #include "td/utils/Status.h" @@ -39,8 +38,7 @@ class FileLoader : public FileLoaderActor { void update_resources(const ResourceState &other) override; void update_local_file_location(const LocalFileLocation &local) override; - void update_download_offset(int64 offset) override; - void update_download_limit(int64 limit) override; + void update_downloaded_part(int64 offset, int64 limit) override; protected: void set_ordered_flag(bool flag); @@ -130,6 +128,7 @@ class FileLoader : public FileLoaderActor { void loop() override; Status do_loop(); void hangup() override; + void hangup_shared() override; void tear_down() override; void update_estimated_limit(); diff --git a/td/telegram/files/FileLoaderActor.h b/td/telegram/files/FileLoaderActor.h index a38f5f192..3164e133b 100644 --- a/td/telegram/files/FileLoaderActor.h +++ b/td/telegram/files/FileLoaderActor.h @@ -26,9 +26,7 @@ class FileLoaderActor : public NetQueryCallback { // TODO: existence of these three functions is a dirty hack. Refactoring is highly appreciated virtual void update_local_file_location(const LocalFileLocation &local) { } - virtual void update_download_offset(int64 offset) { - } - virtual void update_download_limit(int64 limit) { + virtual void update_downloaded_part(int64 offset, int64 limit) { } }; diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index ba782c09a..978d00577 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -2287,13 +2287,17 @@ void FileManager::run_download(FileNodePtr node) { LOG(INFO) << "Update download offset and limits of file " << node->main_file_id_; CHECK(node->download_id_ != 0); send_closure(file_load_manager_, &FileLoadManager::update_priority, node->download_id_, priority); - if (need_update_limit) { + if (need_update_limit || need_update_offset) { + auto download_offset = node->download_offset_; auto download_limit = node->download_limit_; - send_closure(file_load_manager_, &FileLoadManager::update_download_limit, node->download_id_, download_limit); - } - if (need_update_offset) { - auto download_offset = file_view.is_encrypted_any() ? 0 : node->download_offset_; - send_closure(file_load_manager_, &FileLoadManager::update_download_offset, node->download_id_, download_offset); + if (file_view.is_encrypted_any()) { + CHECK(download_offset <= MAX_FILE_SIZE); + CHECK(download_limit <= std::numeric_limits::max()); + download_limit += download_offset; + download_offset = 0; + } + send_closure(file_load_manager_, &FileLoadManager::update_downloaded_part, node->download_id_, download_offset, + download_limit); } return; } @@ -2353,8 +2357,14 @@ void FileManager::run_download(FileNodePtr node) { LOG(INFO) << "Run download of file " << file_id << " of size " << node->size_ << " from " << node->remote_.full.value() << " with suggested name " << node->suggested_name() << " and encyption key " << node->encryption_key_; - auto download_offset = file_view.is_encrypted_any() ? 0 : node->download_offset_; + auto download_offset = node->download_offset_; auto download_limit = node->download_limit_; + if (file_view.is_encrypted_any()) { + CHECK(download_offset <= MAX_FILE_SIZE); + CHECK(download_limit <= std::numeric_limits::max()); + download_limit += download_offset; + download_offset = 0; + } send_closure(file_load_manager_, &FileLoadManager::download, id, node->remote_.full.value(), node->local_, node->size_, node->suggested_name(), node->encryption_key_, node->can_search_locally_, download_offset, download_limit, priority); diff --git a/td/telegram/files/PartsManager.cpp b/td/telegram/files/PartsManager.cpp index 7c8f26441..fab3b5557 100644 --- a/td/telegram/files/PartsManager.cpp +++ b/td/telegram/files/PartsManager.cpp @@ -29,22 +29,27 @@ Status PartsManager::init_known_prefix(int64 known_prefix, size_t part_size, con return init_no_size(part_size, ready_parts); } -void PartsManager::set_streaming_offset(int64 offset) { - SCOPE_EXIT { - set_streaming_limit(streaming_limit_); +int32 PartsManager::set_streaming_offset(int64 offset, int64 limit) { + auto finish = [&] { + set_streaming_limit(limit); + update_first_not_ready_part(); + return first_streaming_not_ready_part_; }; + if (offset < 0 || need_check_ || (!unknown_size_flag_ && get_size() < offset)) { streaming_offset_ = 0; LOG_IF(ERROR, offset != 0) << "Ignore streaming_offset " << offset << ", need_check_ = " << need_check_ << ", unknown_size_flag_ = " << unknown_size_flag_ << ", size = " << get_size(); - return; + + return finish(); } auto part_i = offset / part_size_; if (use_part_count_limit_ && part_i >= MAX_PART_COUNT) { streaming_offset_ = 0; LOG(ERROR) << "Ignore streaming_offset " << offset << " in part " << part_i; - return; + + return finish(); } streaming_offset_ = offset; @@ -54,6 +59,12 @@ void PartsManager::set_streaming_offset(int64 offset) { part_count_ = first_streaming_empty_part_; part_status_.resize(part_count_, PartStatus::Empty); } + + return finish(); +} + +int32 PartsManager::get_pending_count() const { + return pending_count_; } void PartsManager::set_streaming_limit(int64 limit) { @@ -215,6 +226,7 @@ string PartsManager::get_bitmask() { } bool PartsManager::is_part_in_streaming_limit(int part_i) const { + CHECK(part_i < part_count_); auto offset_begin = static_cast(part_i) * static_cast(get_part_size()); auto offset_end = offset_begin + static_cast(get_part(part_i).size); @@ -253,6 +265,9 @@ bool PartsManager::is_streaming_limit_reached() { if (!unknown_size_flag_ && part_i == part_count_) { part_i = first_not_ready_part_; } + if (part_i == part_count_) { + return false; + } return !is_part_in_streaming_limit(part_i); } @@ -487,7 +502,7 @@ Status PartsManager::init_common(const std::vector &ready_parts) { void PartsManager::set_need_check() { need_check_ = true; - set_streaming_offset(0); + set_streaming_offset(0, 0); } void PartsManager::set_checked_prefix_size(int64 size) { diff --git a/td/telegram/files/PartsManager.h b/td/telegram/files/PartsManager.h index ebd80a67c..2cc99912c 100644 --- a/td/telegram/files/PartsManager.h +++ b/td/telegram/files/PartsManager.h @@ -35,7 +35,7 @@ class PartsManager { Status set_known_prefix(size_t size, bool is_ready); void set_need_check(); void set_checked_prefix_size(int64 size); - void set_streaming_offset(int64 offset); + int32 set_streaming_offset(int64 offset, int64 limit); void set_streaming_limit(int64 limit); int64 get_checked_prefix_size() const; @@ -51,6 +51,7 @@ class PartsManager { int32 get_ready_prefix_count(); int64 get_streaming_offset() const; string get_bitmask(); + int32 get_pending_count() const; private: static constexpr int MAX_PART_COUNT = 4000; diff --git a/td/telegram/files/ResourceManager.cpp b/td/telegram/files/ResourceManager.cpp index 39c9fcf28..a66b0fc81 100644 --- a/td/telegram/files/ResourceManager.cpp +++ b/td/telegram/files/ResourceManager.cpp @@ -132,7 +132,7 @@ void ResourceManager::loop() { return; } auto active_limit = resource_state_.active_limit(); - resource_state_.update_limit(2 * 1024 * (1 << 10) - active_limit); + resource_state_.update_limit(MAX_RESOURCE_LIMIT - active_limit); LOG(INFO) << tag("unused", resource_state_.unused()); if (mode_ == Mode::Greedy) { diff --git a/td/telegram/files/ResourceManager.h b/td/telegram/files/ResourceManager.h index 3eb9fe535..eaeba97c2 100644 --- a/td/telegram/files/ResourceManager.h +++ b/td/telegram/files/ResourceManager.h @@ -28,6 +28,8 @@ class ResourceManager : public Actor { void register_worker(ActorShared callback, int8 priority); + static constexpr int64 MAX_RESOURCE_LIMIT = 1 << 21; + private: Mode mode_; using NodeId = uint64; diff --git a/tdactor/td/actor/SignalSlot.h b/tdactor/td/actor/SignalSlot.h index e7cc7e162..6159c9f88 100644 --- a/tdactor/td/actor/SignalSlot.h +++ b/tdactor/td/actor/SignalSlot.h @@ -72,7 +72,7 @@ class Slot final : public Actor { } ActorShared<> get_signal_new() { register_if_empty(); - return actor_shared(); + return actor_shared(this); } private: diff --git a/tdactor/td/actor/impl/Actor-decl.h b/tdactor/td/actor/impl/Actor-decl.h index c750ac1fb..129fcda52 100644 --- a/tdactor/td/actor/impl/Actor-decl.h +++ b/tdactor/td/actor/impl/Actor-decl.h @@ -101,7 +101,6 @@ class Actor : public ObserverBase { template ActorId actor_id(SelfT *self); - ActorShared<> actor_shared(); template ActorShared actor_shared(SelfT *self, uint64 id = static_cast(-1)); diff --git a/tdactor/td/actor/impl/Actor.h b/tdactor/td/actor/impl/Actor.h index fd78012af..cd709ce60 100644 --- a/tdactor/td/actor/impl/Actor.h +++ b/tdactor/td/actor/impl/Actor.h @@ -125,12 +125,11 @@ ActorId Actor::actor_id(SelfT *self) { return ActorId(info_.get_weak()); } -inline ActorShared<> Actor::actor_shared() { - return actor_shared(this); -} template ActorShared Actor::actor_shared(SelfT *self, uint64 id) { CHECK(static_cast(self) == this); + // TODO replace with CHECK + LOG_IF(ERROR, id == 0) << "ActorShared with token 0 must not be created"; return ActorShared(actor_id(self), id); } diff --git a/tdactor/test/actors_main.cpp b/tdactor/test/actors_main.cpp index a26236967..f9f085361 100644 --- a/tdactor/test/actors_main.cpp +++ b/tdactor/test/actors_main.cpp @@ -353,7 +353,7 @@ class SendToDead : public Actor { set_timeout_in(Random::fast_uint32() % 3 * 0.001); if (ttl_ != 0) { child_ = create_actor_on_scheduler( - "Child", Random::fast_uint32() % Scheduler::instance()->sched_count(), actor_shared(), ttl_ - 1); + "Child", Random::fast_uint32() % Scheduler::instance()->sched_count(), actor_shared(this), ttl_ - 1); } } void timeout_expired() override { @@ -376,7 +376,7 @@ class SendToDead : public Actor { ActorShared<> create_reference() { ref_cnt_++; - return actor_shared(); + return actor_shared(this); } void hangup_shared() override { ref_cnt_--; diff --git a/tdactor/test/actors_simple.cpp b/tdactor/test/actors_simple.cpp index 4204d60ee..709a8bc65 100644 --- a/tdactor/test/actors_simple.cpp +++ b/tdactor/test/actors_simple.cpp @@ -482,7 +482,7 @@ class LaterMasterActor : public Actor { std::vector> children_; void start_up() override { for (int i = 0; i < cnt_; i++) { - children_.push_back(create_actor("B", actor_shared())); + children_.push_back(create_actor("B", actor_shared(this))); } yield(); } diff --git a/tddb/td/db/TQueue.cpp b/tddb/td/db/TQueue.cpp index a126c7bd7..9d5d70775 100644 --- a/tddb/td/db/TQueue.cpp +++ b/tddb/td/db/TQueue.cpp @@ -186,11 +186,7 @@ class TQueueImpl : public TQueue { if (it == queues_.end()) { return EventId(); } - auto &q = it->second; - if (q.events.empty()) { - return q.tail_id; - } - return q.events.begin()->first; + return get_queue_head(it->second); } EventId get_tail(QueueId queue_id) const override { @@ -227,7 +223,7 @@ class TQueueImpl : public TQueue { if (from_id.value() > q.tail_id.value() + 10) { return Status::Error("Specified from_id is in the future"); } - if (from_id.value() < q.tail_id.value() - static_cast(MAX_QUEUE_EVENTS) * 2) { + if (from_id.value() < get_queue_head(q).value() - static_cast(MAX_QUEUE_EVENTS)) { return Status::Error("Specified from_id is in the past"); } @@ -267,7 +263,7 @@ class TQueueImpl : public TQueue { return deleted_events; } - size_t get_size(QueueId queue_id) override { + size_t get_size(QueueId queue_id) const override { auto it = queues_.find(queue_id); if (it == queues_.end()) { return 0; @@ -294,7 +290,14 @@ class TQueueImpl : public TQueue { std::set> queue_gc_at_; unique_ptr callback_; - static size_t get_size(Queue &q) { + static EventId get_queue_head(const Queue &q) { + if (q.events.empty()) { + return q.tail_id; + } + return q.events.begin()->first; + } + + static size_t get_size(const Queue &q) { if (q.events.empty()) { return 0; } diff --git a/tddb/td/db/TQueue.h b/tddb/td/db/TQueue.h index 14b46b0ef..58efc283a 100644 --- a/tddb/td/db/TQueue.h +++ b/tddb/td/db/TQueue.h @@ -111,7 +111,7 @@ class TQueue { virtual Result get(QueueId queue_id, EventId from_id, bool forget_previous, int32 unix_time_now, MutableSpan &result_events) = 0; - virtual size_t get_size(QueueId queue_id) = 0; + virtual size_t get_size(QueueId queue_id) const = 0; virtual int64 run_gc(int32 unix_time_now) = 0; virtual void close(Promise<> promise) = 0; diff --git a/tdutils/td/utils/StringBuilder.h b/tdutils/td/utils/StringBuilder.h index 5491f8053..57fe5b9e0 100644 --- a/tdutils/td/utils/StringBuilder.h +++ b/tdutils/td/utils/StringBuilder.h @@ -39,9 +39,22 @@ class StringBuilder { return error_flag_; } - StringBuilder &operator<<(const char *str) { + template + std::enable_if_t>::value, StringBuilder> &operator<<(T str) { return *this << Slice(str); } + template + std::enable_if_t>::value, StringBuilder> &operator<<(T str) { + return *this << Slice(str); + } + + template + StringBuilder &operator<<(char (&str)[N]) = delete; + + template + StringBuilder &operator<<(const char (&str)[N]) { + return *this << Slice(str, N - 1); + } StringBuilder &operator<<(const wchar_t *str) = delete; @@ -94,11 +107,6 @@ class StringBuilder { StringBuilder &operator<<(const void *ptr); - template - StringBuilder &operator<<(const T *ptr) { - return *this << static_cast(ptr); - } - private: char *begin_ptr_; char *current_ptr_; diff --git a/test/mtproto.cpp b/test/mtproto.cpp index 9651b2c67..b7c528e6e 100644 --- a/test/mtproto.cpp +++ b/test/mtproto.cpp @@ -459,7 +459,7 @@ class Socks5TestActor : public Actor { return promise.set_error(Status::Error(PSTRING() << "Failed to open socket: " << r_socket.error())); } create_actor("socks5", r_socket.move_as_ok(), mtproto_ip_address, "", "", - make_unique(std::move(promise)), actor_shared()) + make_unique(std::move(promise)), actor_shared(this)) .release(); }