From 190117c839650a917182e0cb814b1f9f360fb669 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 16 May 2022 18:11:49 +0300 Subject: [PATCH 01/14] Add local reply_to_message_id to forwarded by the server messages. --- td/telegram/MessagesManager.cpp | 83 ++++++++++++++++++++++++++------- td/telegram/MessagesManager.h | 2 + 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index e43e119bb..bc1d9127f 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -3197,6 +3197,7 @@ class SendMessageQuery final : public Td::ResultHandler { flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS; } + CHECK(reply_to_message_id == MessageId() || reply_to_message_id.is_server()); auto query = G()->net_query_creator().create( telegram_api::messages_sendMessage( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, @@ -3329,6 +3330,7 @@ class SendInlineBotResultQuery final : public Td::ResultHandler { flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS; } + CHECK(reply_to_message_id == MessageId() || reply_to_message_id.is_server()); auto query = G()->net_query_creator().create( telegram_api::messages_sendInlineBotResult(flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer), @@ -3392,6 +3394,7 @@ class SendMultiMediaQuery final : public Td::ResultHandler { } // no quick ack, because file reference errors are very likely to happen + CHECK(reply_to_message_id == MessageId() || reply_to_message_id.is_server()); send_query(G()->net_query_creator().create( telegram_api::messages_sendMultiMedia(flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer), @@ -3508,6 +3511,7 @@ class SendMediaQuery final : public Td::ResultHandler { flags |= MessagesManager::SEND_MESSAGE_FLAG_HAS_SEND_AS; } + CHECK(reply_to_message_id == MessageId() || reply_to_message_id.is_server()); auto query = G()->net_query_creator().create( telegram_api::messages_sendMedia( flags, false /*ignored*/, false /*ignored*/, false /*ignored*/, false /*ignored*/, std::move(input_peer), @@ -13013,6 +13017,7 @@ void MessagesManager::on_message_ttl_expired_impl(Dialog *d, Message *m) { m->noforwards = false; m->contains_mention = false; m->reply_to_message_id = MessageId(); + m->reply_to_random_id = 0; m->max_reply_media_timestamp = -1; m->reply_in_dialog_id = DialogId(); m->top_thread_message_id = MessageId(); @@ -14362,6 +14367,7 @@ std::pair> MessagesManager::creat message->reply_markup = nullptr; } message->reply_to_message_id = MessageId(); + message->reply_to_random_id = 0; message->reply_in_dialog_id = DialogId(); message->top_thread_message_id = MessageId(); message->linked_top_thread_message_id = MessageId(); @@ -24483,7 +24489,6 @@ unique_ptr MessagesManager::create_message_to_send( unique_ptr &&content, bool suppress_reply_info, unique_ptr forward_info, bool is_copy, DialogId send_as_dialog_id) const { CHECK(d != nullptr); - CHECK(!reply_to_message_id.is_scheduled()); CHECK(content != nullptr); bool is_scheduled = options.schedule_date != 0; @@ -24527,7 +24532,7 @@ unique_ptr MessagesManager::create_message_to_send( m->reply_to_message_id = reply_to_message_id; if (!is_scheduled) { m->top_thread_message_id = top_thread_message_id; - if (reply_to_message_id.is_valid()) { + if (reply_to_message_id.is_valid() && !reply_to_message_id.is_yet_unsent()) { const Message *reply_m = get_message(d, reply_to_message_id); if (reply_m != nullptr && reply_m->top_thread_message_id.is_valid()) { m->top_thread_message_id = reply_m->top_thread_message_id; @@ -24716,8 +24721,14 @@ MessageId MessagesManager::get_reply_to_message_id(Dialog *d, MessageId top_thre void MessagesManager::fix_server_reply_to_message_id(DialogId dialog_id, MessageId message_id, DialogId reply_in_dialog_id, MessageId &reply_to_message_id) { - CHECK(!reply_to_message_id.is_scheduled()); if (!reply_to_message_id.is_valid()) { + if (reply_to_message_id.is_scheduled()) { + if (!message_id.is_scheduled() || message_id == reply_to_message_id) { + LOG(ERROR) << "Receive reply to " << reply_to_message_id << " for " << message_id << " in " << dialog_id; + reply_to_message_id = MessageId(); + } + return; + } if (reply_to_message_id != MessageId()) { LOG(ERROR) << "Receive reply to " << reply_to_message_id << " for " << message_id << " in " << dialog_id; reply_to_message_id = MessageId(); @@ -27232,7 +27243,7 @@ void MessagesManager::update_message_max_reply_media_timestamp(const Dialog *d, } auto new_max_reply_media_timestamp = -1; - if (m->reply_to_message_id.is_valid()) { + if (m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_yet_unsent()) { auto replied_m = get_message(d, m->reply_to_message_id); if (replied_m != nullptr) { new_max_reply_media_timestamp = get_message_own_max_media_timestamp(replied_m); @@ -27288,6 +27299,9 @@ void MessagesManager::update_message_max_reply_media_timestamp_in_replied_messag return; } CHECK(reply_to_message_id.is_valid()); + if (reply_to_message_id.is_yet_unsent()) { + return; + } FullMessageId full_message_id{dialog_id, reply_to_message_id}; auto it = replied_by_media_timestamp_messages_.find(full_message_id); @@ -27308,7 +27322,7 @@ void MessagesManager::update_message_max_reply_media_timestamp_in_replied_messag } void MessagesManager::register_message_reply(DialogId dialog_id, const Message *m) { - if (!m->reply_to_message_id.is_valid() || td_->auth_manager_->is_bot()) { + if (!m->reply_to_message_id.is_valid() || m->reply_to_message_id.is_yet_unsent() || td_->auth_manager_->is_bot()) { return; } @@ -27321,7 +27335,7 @@ void MessagesManager::register_message_reply(DialogId dialog_id, const Message * } void MessagesManager::reregister_message_reply(DialogId dialog_id, const Message *m) { - if (!m->reply_to_message_id.is_valid() || td_->auth_manager_->is_bot()) { + if (!m->reply_to_message_id.is_valid() || m->reply_to_message_id.is_yet_unsent() || td_->auth_manager_->is_bot()) { return; } @@ -27367,6 +27381,7 @@ bool MessagesManager::get_message_disable_web_page_preview(const Message *m) { int32 MessagesManager::get_message_flags(const Message *m) { int32 flags = 0; if (m->reply_to_message_id.is_valid()) { + CHECK(m->reply_to_message_id.is_server()); flags |= SEND_MESSAGE_FLAG_IS_REPLY; } if (m->disable_web_page_preview) { @@ -28069,6 +28084,7 @@ Result> MessagesManager::forward_messages( auto drop_author = forwarded_messages_info.drop_author; auto drop_media_captions = forwarded_messages_info.drop_media_captions; + FlatHashMap forwarded_message_id_to_new_message_id; vector> result(message_ids.size()); vector forwarded_messages; vector forwarded_message_ids; @@ -28090,13 +28106,20 @@ Result> MessagesManager::forward_messages( forward_info->sender_name = std::move(private_forward_name); } } + MessageId reply_to_message_id; + if (forwarded_message->reply_to_message_id.is_valid() && message_send_options.schedule_date == 0) { + auto it = forwarded_message_id_to_new_message_id.find(forwarded_message->reply_to_message_id); + if (it != forwarded_message_id_to_new_message_id.end()) { + reply_to_message_id = it->second; + } + } unique_ptr message; Message *m; if (only_preview) { - message = create_message_to_send(to_dialog, MessageId(), MessageId(), message_send_options, std::move(content), - j + 1 != forwarded_message_contents.size(), std::move(forward_info), false, - DialogId()); + message = create_message_to_send(to_dialog, MessageId(), reply_to_message_id, message_send_options, + std::move(content), j + 1 != forwarded_message_contents.size(), + std::move(forward_info), false, DialogId()); MessageId new_message_id = message_send_options.schedule_date != 0 ? get_next_yet_unsent_scheduled_message_id(to_dialog, message_send_options.schedule_date) @@ -28104,7 +28127,7 @@ Result> MessagesManager::forward_messages( set_message_id(message, new_message_id); m = message.get(); } else { - m = get_message_to_send(to_dialog, MessageId(), MessageId(), message_send_options, std::move(content), + m = get_message_to_send(to_dialog, MessageId(), reply_to_message_id, message_send_options, std::move(content), &need_update_dialog_pos, j + 1 != forwarded_message_contents.size(), std::move(forward_info)); } @@ -28113,6 +28136,7 @@ Result> MessagesManager::forward_messages( m->in_game_share = in_game_share; m->real_forward_from_dialog_id = from_dialog_id; m->real_forward_from_message_id = message_id; + forwarded_message_id_to_new_message_id.emplace(message_id, m->message_id); if (!only_preview) { send_update_new_message(to_dialog, m); @@ -34357,7 +34381,8 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } const Message *m = message.get(); - if (m->message_id.is_yet_unsent() && m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_yet_unsent()) { + if (m->message_id.is_yet_unsent() && m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_yet_unsent() && + !m->reply_to_message_id.is_scheduled()) { replied_by_yet_unsent_messages_[FullMessageId{dialog_id, m->reply_to_message_id}]++; } @@ -34656,7 +34681,8 @@ MessagesManager::Message *MessagesManager::add_scheduled_message_to_dialog(Dialo LOG(INFO) << "Adding not found " << message_id << " to " << dialog_id << " from " << source; const Message *m = message.get(); - if (m->message_id.is_yet_unsent() && m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_yet_unsent()) { + if (m->message_id.is_yet_unsent() && m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_yet_unsent() && + !m->reply_to_message_id.is_scheduled()) { replied_by_yet_unsent_messages_[FullMessageId{dialog_id, m->reply_to_message_id}]++; } @@ -35293,13 +35319,15 @@ bool MessagesManager::update_message(Dialog *d, Message *old_message, unique_ptr update_message_max_reply_media_timestamp(d, old_message, is_message_in_dialog); need_send_update = true; } else if (is_new_available) { - if (message_id.is_yet_unsent() && old_message->reply_to_message_id == MessageId()) { + if (message_id.is_yet_unsent() && + (old_message->reply_to_message_id == MessageId() || old_message->reply_to_message_id.is_yet_unsent())) { CHECK(!is_message_in_dialog); - CHECK(new_message->reply_to_message_id.is_valid()); - CHECK(new_message->reply_to_message_id.is_server()); + CHECK(new_message->reply_to_message_id.is_any_server()); old_message->reply_to_message_id = new_message->reply_to_message_id; + update_message_max_reply_media_timestamp(d, old_message, is_message_in_dialog); + need_send_update = true; } else { - LOG(ERROR) << message_id << " in " << dialog_id << " has changed message it is reply to from " + LOG(ERROR) << message_id << " in " << dialog_id << " has changed message it is replied message from " << old_message->reply_to_message_id << " to " << new_message->reply_to_message_id << ", message content type is " << old_content_type << '/' << new_content_type; } @@ -35681,13 +35709,12 @@ MessagesManager::Dialog *MessagesManager::get_dialog_by_message_id(MessageId mes MessageId MessagesManager::get_message_id_by_random_id(Dialog *d, int64 random_id, const char *source) { CHECK(d != nullptr); - CHECK(d->dialog_id.get_type() == DialogType::SecretChat); if (random_id == 0) { return MessageId(); } auto it = d->random_id_to_message_id.find(random_id); if (it == d->random_id_to_message_id.end()) { - if (G()->parameters().use_message_db) { + if (G()->parameters().use_message_db && d->dialog_id.get_type() == DialogType::SecretChat) { auto r_value = G()->td_db()->get_messages_db_sync()->get_message_by_random_id(d->dialog_id, random_id); if (r_value.is_ok()) { debug_add_message_to_dialog_fail_reason_ = "not called"; @@ -38431,6 +38458,22 @@ void MessagesManager::update_has_outgoing_messages(DialogId dialog_id, const Mes } } +void MessagesManager::restore_message_reply_to_message_id(Dialog *d, Message *m) { + if (!m->reply_to_message_id.is_valid() || !m->reply_to_message_id.is_yet_unsent()) { + return; + } + + auto message_id = get_message_id_by_random_id(d, m->reply_to_random_id, "restore_message_reply_to_message_id"); + if (!message_id.is_valid()) { + LOG(INFO) << "Failed to find replied " << m->reply_to_message_id << " with random_id = " << m->reply_to_random_id; + m->reply_to_message_id = m->top_thread_message_id; + m->reply_to_random_id = 0; + } else { + LOG(INFO) << "Restore message reply to " << message_id << " with random_id = " << m->reply_to_random_id; + m->reply_to_message_id = message_id; + } +} + MessagesManager::Message *MessagesManager::continue_send_message(DialogId dialog_id, unique_ptr &&m, uint64 log_event_id) { CHECK(log_event_id != 0); @@ -38463,6 +38506,8 @@ MessagesManager::Message *MessagesManager::continue_send_message(DialogId dialog m->have_previous = true; m->have_next = true; + restore_message_reply_to_message_id(d, m.get()); + bool need_update = false; bool need_update_dialog_pos = false; auto result_message = @@ -38689,6 +38734,8 @@ void MessagesManager::on_binlog_events(vector &&events) { m->have_previous = true; m->have_next = true; + restore_message_reply_to_message_id(to_dialog, m.get()); + forwarded_messages.push_back(add_message_to_dialog(to_dialog, std::move(m), true, &need_update, &need_update_dialog_pos, "forward message again")); send_update_new_message(to_dialog, forwarded_messages.back()); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 889114798..960f97325 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2022,6 +2022,8 @@ class MessagesManager final : public Actor { void do_send_screenshot_taken_notification_message(DialogId dialog_id, const Message *m, uint64 log_event_id); + void restore_message_reply_to_message_id(Dialog *d, Message *m); + Message *continue_send_message(DialogId dialog_id, unique_ptr &&m, uint64 log_event_id); bool is_message_unload_enabled() const; From 26ceefb2d4fee9a35e5b0e85f877c526a1d05f98 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 16 May 2022 19:47:06 +0300 Subject: [PATCH 02/14] Keep reply_to_message_id for yet unsent messages between restarts. --- td/telegram/MessagesManager.cpp | 59 ++++++++++++++++++--------------- td/telegram/MessagesManager.h | 4 +-- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index bc1d9127f..ec00d50e7 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -15696,8 +15696,7 @@ unique_ptr MessagesManager::delete_message(Dialog *d, void MessagesManager::add_random_id_to_message_id_correspondence(Dialog *d, int64 random_id, MessageId message_id) { CHECK(d != nullptr); - CHECK(d->dialog_id.get_type() == DialogType::SecretChat); - CHECK(message_id.is_valid()); + CHECK(d->dialog_id.get_type() == DialogType::SecretChat || message_id.is_yet_unsent()); auto it = d->random_id_to_message_id.find(random_id); if (it == d->random_id_to_message_id.end() || it->second < message_id) { LOG(INFO) << "Add correspondence from random_id " << random_id << " to " << message_id << " in " << d->dialog_id; @@ -15707,8 +15706,7 @@ void MessagesManager::add_random_id_to_message_id_correspondence(Dialog *d, int6 void MessagesManager::delete_random_id_to_message_id_correspondence(Dialog *d, int64 random_id, MessageId message_id) { CHECK(d != nullptr); - CHECK(d->dialog_id.get_type() == DialogType::SecretChat); - CHECK(message_id.is_valid()); + CHECK(d->dialog_id.get_type() == DialogType::SecretChat || message_id.is_yet_unsent()); auto it = d->random_id_to_message_id.find(random_id); if (it != d->random_id_to_message_id.end() && it->second == message_id) { LOG(INFO) << "Delete correspondence from random_id " << random_id << " to " << message_id << " in " << d->dialog_id; @@ -16168,7 +16166,8 @@ void MessagesManager::on_message_deleted(Dialog *d, Message *m, bool is_permanen cancel_send_deleted_message(d->dialog_id, m, is_permanently_deleted); - switch (d->dialog_id.get_type()) { + auto dialog_type = d->dialog_id.get_type(); + switch (dialog_type) { case DialogType::User: case DialogType::Chat: if (m->message_id.is_server()) { @@ -16176,10 +16175,8 @@ void MessagesManager::on_message_deleted(Dialog *d, Message *m, bool is_permanen } break; case DialogType::Channel: - // nothing to do - break; case DialogType::SecretChat: - delete_random_id_to_message_id_correspondence(d, m->random_id, m->message_id); + // nothing to do break; case DialogType::None: default: @@ -16193,6 +16190,9 @@ void MessagesManager::on_message_deleted(Dialog *d, Message *m, bool is_permanen if (m->notification_id.is_valid()) { delete_notification_id_to_message_id_correspondence(d, m->notification_id, m->message_id); } + if (m->message_id.is_yet_unsent() || dialog_type == DialogType::SecretChat) { + delete_random_id_to_message_id_correspondence(d, m->random_id, m->message_id); + } added_message_count_--; } @@ -24476,11 +24476,12 @@ bool MessagesManager::get_dialog_silent_send_message(DialogId dialog_id) const { return d->notification_settings.silent_send_message; } -int64 MessagesManager::generate_new_random_id() { +int64 MessagesManager::generate_new_random_id(const Dialog *d) { int64 random_id; do { random_id = Random::secure_int64(); - } while (random_id == 0 || being_sent_messages_.count(random_id) > 0); + } while (random_id == 0 || being_sent_messages_.count(random_id) > 0 || + d->random_id_to_message_id.count(random_id) > 0); return random_id; } @@ -24590,16 +24591,18 @@ unique_ptr MessagesManager::create_message_to_send( m->ttl = 0; } m->is_content_secret = is_secret_message_content(m->ttl, m->content->get_type()); - if (reply_to_message_id.is_valid()) { - // the message was forcely preloaded in get_reply_to_message_id - auto *reply_to_message = get_message(d, reply_to_message_id); - if (reply_to_message != nullptr) { - m->reply_to_random_id = reply_to_message->random_id; - } else { - m->reply_to_message_id = MessageId(); - } + } + if ((reply_to_message_id.is_valid() || reply_to_message_id.is_valid_scheduled()) && + (dialog_type == DialogType::SecretChat || reply_to_message_id.is_yet_unsent())) { + // the message was forcely preloaded in get_reply_to_message_id + auto *reply_to_message = get_message(d, reply_to_message_id); + if (reply_to_message == nullptr || (reply_to_message->message_id.is_yet_unsent() && is_scheduled)) { + m->reply_to_message_id = MessageId(); + } else { + m->reply_to_random_id = reply_to_message->random_id; } } + return m; } @@ -24619,7 +24622,7 @@ MessagesManager::Message *MessagesManager::get_message_to_send( message->have_previous = true; message->have_next = true; - message->random_id = generate_new_random_id(); + message->random_id = generate_new_random_id(d); bool need_update = false; CHECK(have_input_peer(d->dialog_id, AccessRights::Read)); @@ -30797,10 +30800,11 @@ void MessagesManager::on_send_message_file_part_missing(int64 random_id, int bad Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); - // need to change message random_id before resending - m->random_id = generate_new_random_id(); + delete_random_id_to_message_id_correspondence(d, m->random_id, m->message_id); + + // need to change message random_id before resending + m->random_id = generate_new_random_id(d); - delete_random_id_to_message_id_correspondence(d, random_id, m->message_id); add_random_id_to_message_id_correspondence(d, m->random_id, m->message_id); auto log_event = SendMessageLogEvent(dialog_id, m); @@ -30846,10 +30850,11 @@ void MessagesManager::on_send_message_file_reference_error(int64 random_id) { Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); - // need to change message random_id before resending - m->random_id = generate_new_random_id(); + delete_random_id_to_message_id_correspondence(d, m->random_id, m->message_id); + + // need to change message random_id before resending + m->random_id = generate_new_random_id(d); - delete_random_id_to_message_id_correspondence(d, random_id, m->message_id); add_random_id_to_message_id_correspondence(d, m->random_id, m->message_id); auto log_event = SendMessageLogEvent(dialog_id, m); @@ -34551,7 +34556,6 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq // nothing to do break; case DialogType::SecretChat: - add_random_id_to_message_id_correspondence(d, m->random_id, m->message_id); break; case DialogType::None: default: @@ -34561,6 +34565,9 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq if (m->notification_id.is_valid()) { add_notification_id_to_message_id_correspondence(d, m->notification_id, m->message_id); } + if (m->message_id.is_yet_unsent() || dialog_type == DialogType::SecretChat) { + add_random_id_to_message_id_correspondence(d, m->random_id, m->message_id); + } try_add_bot_command_message_id(dialog_id, m); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 960f97325..609794bcd 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1349,7 +1349,7 @@ class MessagesManager final : public Actor { int32 pending_read_channel_inbox_pts = 0; // for channels only int32 pending_read_channel_inbox_server_unread_count = 0; // for channels only MessageId pending_read_channel_inbox_max_message_id; // for channels only - std::unordered_map random_id_to_message_id; // for secret chats only + std::unordered_map random_id_to_message_id; // for secret chats and yet unsent messages only MessageId last_assigned_message_id; // identifier of the last local or yet unsent message, assigned after // application start, used to guarantee that all assigned message identifiers @@ -1864,7 +1864,7 @@ class MessagesManager final : public Actor { bool is_anonymous_administrator(DialogId dialog_id, string *author_signature) const; - int64 generate_new_random_id(); + int64 generate_new_random_id(const Dialog *d); unique_ptr create_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id, const MessageSendOptions &options, unique_ptr &&content, From 8f42c972523f0880e7bf47a8a722bae0c29be61e Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 16 May 2022 20:00:59 +0300 Subject: [PATCH 03/14] Fix CHECK. --- td/telegram/MessagesManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index ec00d50e7..9a6fa0709 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -27934,7 +27934,7 @@ Result MessagesManager::get_forwarded_messag bool to_secret = to_dialog_id.get_type() == DialogType::SecretChat; - bool can_use_server_forward = !to_secret; + bool can_use_server_forward = true; for (auto ©_option : copy_options) { if (!copy_option.is_supported_server_side()) { can_use_server_forward = false; @@ -27942,6 +27942,9 @@ Result MessagesManager::get_forwarded_messag } } CHECK(can_use_server_forward || copy_options.size() == 1); + if (to_secret) { + can_use_server_forward = false; + } ForwardedMessages result; result.to_dialog = to_dialog; From bf37753056787ce4de6c11f5ab9725cc8f081af4 Mon Sep 17 00:00:00 2001 From: levlam Date: Mon, 16 May 2022 21:10:18 +0300 Subject: [PATCH 04/14] Keep reply_to_message_id for forwards to secret chats. --- td/telegram/MessagesManager.cpp | 32 +++++++++++++++++++++++++------- td/telegram/MessagesManager.h | 2 ++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 9a6fa0709..34da647af 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -13613,7 +13613,7 @@ void MessagesManager::on_send_secret_message_success(int64 random_id, MessageId } } - on_send_message_success(random_id, message_id, date, 0, new_file_id, "process send_secret_message_success"); + on_send_message_success(random_id, message_id, date, 0, new_file_id, "on_send_secret_message_success"); } void MessagesManager::delete_secret_messages(SecretChatId secret_chat_id, std::vector random_ids, @@ -13646,7 +13646,7 @@ void MessagesManager::finish_delete_secret_messages(DialogId dialog_id, std::vec CHECK(d != nullptr); vector to_delete_message_ids; for (auto &random_id : random_ids) { - auto message_id = get_message_id_by_random_id(d, random_id, "delete_secret_messages"); + auto message_id = get_message_id_by_random_id(d, random_id, "finish_delete_secret_messages"); if (!message_id.is_valid()) { LOG(INFO) << "Can't find message with random_id " << random_id; continue; @@ -28029,6 +28029,7 @@ Result MessagesManager::get_forwarded_messag if (is_local_copy) { copied_messages.push_back({std::move(content), top_thread_message_id, reply_to_message_id, + forwarded_message->message_id, forwarded_message->reply_to_message_id, std::move(reply_markup), forwarded_message->media_album_id, get_message_disable_web_page_preview(forwarded_message), i}); } else { @@ -28159,14 +28160,30 @@ Result> MessagesManager::forward_messages( drop_media_captions, 0); } + bool is_secret = to_dialog_id.get_type() == DialogType::SecretChat; + bool is_copy = !is_secret; + for (const auto &copied_message : copied_messages) { + if (forwarded_message_id_to_new_message_id.count(copied_message.original_reply_to_message_id) > 0) { + is_copy = true; + break; + } + forwarded_message_id_to_new_message_id.emplace(copied_message.original_message_id, MessageId()); + } for (auto &copied_message : copied_messages) { + MessageId reply_to_message_id = copied_message.reply_to_message_id; + if (!reply_to_message_id.is_valid() && copied_message.original_reply_to_message_id.is_valid() && is_secret) { + auto it = forwarded_message_id_to_new_message_id.find(copied_message.original_reply_to_message_id); + if (it != forwarded_message_id_to_new_message_id.end()) { + reply_to_message_id = it->second; + } + } + unique_ptr message; Message *m; - bool is_copy = to_dialog_id.get_type() != DialogType::SecretChat; if (only_preview) { - message = create_message_to_send(to_dialog, copied_message.top_thread_message_id, - copied_message.reply_to_message_id, message_send_options, - std::move(copied_message.content), false, nullptr, is_copy, DialogId()); + message = create_message_to_send(to_dialog, copied_message.top_thread_message_id, reply_to_message_id, + message_send_options, std::move(copied_message.content), false, nullptr, is_copy, + DialogId()); MessageId new_message_id = message_send_options.schedule_date != 0 ? get_next_yet_unsent_scheduled_message_id(to_dialog, message_send_options.schedule_date) @@ -28174,13 +28191,14 @@ Result> MessagesManager::forward_messages( set_message_id(message, new_message_id); m = message.get(); } else { - m = get_message_to_send(to_dialog, copied_message.top_thread_message_id, copied_message.reply_to_message_id, + m = get_message_to_send(to_dialog, copied_message.top_thread_message_id, reply_to_message_id, message_send_options, std::move(copied_message.content), &need_update_dialog_pos, false, nullptr, is_copy); } m->disable_web_page_preview = copied_message.disable_web_page_preview; m->media_album_id = copied_message.media_album_id; m->reply_markup = std::move(copied_message.reply_markup); + forwarded_message_id_to_new_message_id[copied_message.original_message_id] = m->message_id; if (!only_preview) { save_send_message_log_event(to_dialog_id, m); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 609794bcd..942812b9c 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -1952,6 +1952,8 @@ class MessagesManager final : public Actor { unique_ptr content; MessageId top_thread_message_id; MessageId reply_to_message_id; + MessageId original_message_id; + MessageId original_reply_to_message_id; unique_ptr reply_markup; int64 media_album_id; bool disable_web_page_preview; From f53f750b3941fcc00e649bcb927250dbffd19204 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 17 May 2022 15:06:40 +0300 Subject: [PATCH 05/14] Change replied message ID from yet unsent to persistent after the message is sent. --- td/telegram/MessagesManager.cpp | 102 +++++++++++++++++++++++++------- td/telegram/MessagesManager.h | 3 + 2 files changed, 82 insertions(+), 23 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 34da647af..1775d116b 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -12993,6 +12993,7 @@ void MessagesManager::on_message_ttl_expired_impl(Dialog *d, Message *m) { CHECK(d != nullptr); CHECK(m != nullptr); CHECK(m->message_id.is_valid()); + CHECK(!m->message_id.is_yet_unsent()); CHECK(m->ttl > 0); CHECK(d->dialog_id.get_type() != DialogType::SecretChat); delete_message_files(d->dialog_id, m); @@ -14493,11 +14494,14 @@ FullMessageId MessagesManager::on_get_message(MessageInfo &&message_info, bool f return FullMessageId(); } + // must be called before delete_message + update_reply_to_message_id(dialog_id, old_message_id, message_id); + being_readded_message_id_ = {dialog_id, old_message_id}; unique_ptr old_message = delete_message(d, old_message_id, false, &need_update_dialog_pos, "add sent message"); if (old_message == nullptr) { - delete_sent_message_on_server(dialog_id, new_message->message_id); + delete_sent_message_on_server(dialog_id, message_id); being_readded_message_id_ = FullMessageId(); return FullMessageId(); } @@ -24794,13 +24798,38 @@ void MessagesManager::cancel_send_message_query(DialogId dialog_id, Message *m) m->send_message_log_event_id = 0; } - if (m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_yet_unsent()) { - auto it = replied_by_yet_unsent_messages_.find({dialog_id, m->reply_to_message_id}); - CHECK(it != replied_by_yet_unsent_messages_.end()); - it->second--; - CHECK(it->second >= 0); - if (it->second == 0) { - replied_by_yet_unsent_messages_.erase(it); + if (m->reply_to_message_id.is_valid()) { + if (!m->reply_to_message_id.is_yet_unsent()) { + auto it = replied_by_yet_unsent_messages_.find({dialog_id, m->reply_to_message_id}); + CHECK(it != replied_by_yet_unsent_messages_.end()); + it->second--; + CHECK(it->second >= 0); + if (it->second == 0) { + replied_by_yet_unsent_messages_.erase(it); + } + } else { + auto it = replied_yet_unsent_messages_.find({dialog_id, m->reply_to_message_id}); + CHECK(it != replied_yet_unsent_messages_.end()); + size_t erased_count = it->second.erase(m->message_id); + CHECK(erased_count > 0); + if (it->second.empty()) { + replied_yet_unsent_messages_.erase(it); + } + } + } + { + auto it = replied_yet_unsent_messages_.find({dialog_id, m->message_id}); + if (it != replied_yet_unsent_messages_.end()) { + for (auto message_id : it->second) { + auto replied_m = get_message({dialog_id, message_id}); + CHECK(replied_m != nullptr); + CHECK(replied_m->reply_to_message_id == m->message_id); + unregister_message_reply(dialog_id, replied_m); + replied_m->reply_to_message_id = replied_m->top_thread_message_id; + replied_m->reply_to_random_id = 0; + register_message_reply(dialog_id, replied_m); + } + replied_yet_unsent_messages_.erase(it); } } @@ -30670,6 +30699,34 @@ void MessagesManager::check_send_message_result(int64 random_id, DialogId dialog } } +void MessagesManager::update_reply_to_message_id(DialogId dialog_id, MessageId old_message_id, + MessageId new_message_id) { + auto it = replied_yet_unsent_messages_.find({dialog_id, old_message_id}); + if (it == replied_yet_unsent_messages_.end()) { + return; + } + CHECK(old_message_id.is_yet_unsent()); + + for (auto message_id : it->second) { + CHECK(message_id.is_yet_unsent()); + FullMessageId full_message_id{dialog_id, message_id}; + auto replied_m = get_message(full_message_id); + CHECK(replied_m != nullptr); + CHECK(replied_m->reply_to_message_id == old_message_id); + LOG(INFO) << "Update replied message in " << full_message_id << " from " << old_message_id << " to " + << new_message_id; + unregister_message_reply(dialog_id, replied_m); + replied_m->reply_to_message_id = new_message_id; + // TODO rewrite send message log event + register_message_reply(dialog_id, replied_m); + } + if (new_message_id.is_valid()) { + CHECK(!new_message_id.is_yet_unsent()); + replied_by_yet_unsent_messages_[FullMessageId{dialog_id, new_message_id}] = static_cast(it->second.size()); + } + replied_yet_unsent_messages_.erase(it); +} + FullMessageId MessagesManager::on_send_message_success(int64 random_id, MessageId new_message_id, int32 date, int32 ttl_period, FileId new_file_id, const char *source) { CHECK(source != nullptr); @@ -30709,6 +30766,9 @@ FullMessageId MessagesManager::on_send_message_success(int64 random_id, MessageI being_sent_messages_.erase(it); + // must be called before delete_message + update_reply_to_message_id(dialog_id, old_message_id, new_message_id); + Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); @@ -31162,6 +31222,8 @@ void MessagesManager::fail_send_message(FullMessageId full_message_id, int error CHECK(old_message_id.is_valid() || old_message_id.is_valid_scheduled()); CHECK(old_message_id.is_yet_unsent()); + update_reply_to_message_id(dialog_id, old_message_id, MessageId()); + bool need_update_dialog_pos = false; being_readded_message_id_ = full_message_id; unique_ptr message = delete_message(d, old_message_id, false, &need_update_dialog_pos, "fail send message"); @@ -34407,9 +34469,12 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq } const Message *m = message.get(); - if (m->message_id.is_yet_unsent() && m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_yet_unsent() && - !m->reply_to_message_id.is_scheduled()) { - replied_by_yet_unsent_messages_[FullMessageId{dialog_id, m->reply_to_message_id}]++; + if (m->message_id.is_yet_unsent() && m->reply_to_message_id.is_valid() && !m->reply_to_message_id.is_scheduled()) { + if (!m->reply_to_message_id.is_yet_unsent()) { + replied_by_yet_unsent_messages_[FullMessageId{dialog_id, m->reply_to_message_id}]++; + } else { + replied_yet_unsent_messages_[FullMessageId{dialog_id, m->reply_to_message_id}].insert(m->message_id); + } } if (!m->from_database && !m->message_id.is_yet_unsent()) { @@ -35347,18 +35412,9 @@ bool MessagesManager::update_message(Dialog *d, Message *old_message, unique_ptr update_message_max_reply_media_timestamp(d, old_message, is_message_in_dialog); need_send_update = true; } else if (is_new_available) { - if (message_id.is_yet_unsent() && - (old_message->reply_to_message_id == MessageId() || old_message->reply_to_message_id.is_yet_unsent())) { - CHECK(!is_message_in_dialog); - CHECK(new_message->reply_to_message_id.is_any_server()); - old_message->reply_to_message_id = new_message->reply_to_message_id; - update_message_max_reply_media_timestamp(d, old_message, is_message_in_dialog); - need_send_update = true; - } else { - LOG(ERROR) << message_id << " in " << dialog_id << " has changed message it is replied message from " - << old_message->reply_to_message_id << " to " << new_message->reply_to_message_id - << ", message content type is " << old_content_type << '/' << new_content_type; - } + LOG(ERROR) << message_id << " in " << dialog_id << " has changed message it is replied message from " + << old_message->reply_to_message_id << " to " << new_message->reply_to_message_id + << ", message content type is " << old_content_type << '/' << new_content_type; } } if (old_message->reply_in_dialog_id != new_message->reply_in_dialog_id) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 942812b9c..117ec398a 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2322,6 +2322,8 @@ class MessagesManager final : public Actor { void delete_message_from_database(Dialog *d, MessageId message_id, const Message *m, bool is_permanently_deleted); + void update_reply_to_message_id(DialogId dialog_id, MessageId old_message_id, MessageId new_message_id); + void delete_message_files(DialogId dialog_id, const Message *m) const; static void add_random_id_to_message_id_correspondence(Dialog *d, int64 random_id, MessageId message_id); @@ -3486,6 +3488,7 @@ class MessagesManager final : public Actor { FlatHashMap get_dialog_query_log_event_id_; FlatHashMap replied_by_yet_unsent_messages_; + FlatHashMap, FullMessageIdHash> replied_yet_unsent_messages_; // full_message_id -> replies with media timestamps FlatHashMap, FullMessageIdHash> From 19407656b55a19d0d95471c2572a3d144ae8319c Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 17 May 2022 15:30:58 +0300 Subject: [PATCH 06/14] Add more logging and don't set unused message flags. --- td/telegram/MessagesManager.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 1775d116b..9224b65ef 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -13819,17 +13819,8 @@ void MessagesManager::on_get_secret_message(SecretChatId secret_chat_id, UserId int32 flags = MESSAGE_FLAG_HAS_UNREAD_CONTENT | MESSAGE_FLAG_HAS_FROM_ID; if ((message->flags_ & secret_api::decryptedMessage::REPLY_TO_RANDOM_ID_MASK) != 0) { - message_info.reply_to_message_id = get_message_id_by_random_id( - get_dialog(message_info.dialog_id), message->reply_to_random_id_, "on_get_secret_message"); - if (message_info.reply_to_message_id.is_valid()) { - flags |= MESSAGE_FLAG_IS_REPLY; - } - } - if ((message->flags_ & secret_api::decryptedMessage::ENTITIES_MASK) != 0) { - flags |= MESSAGE_FLAG_HAS_ENTITIES; - } - if ((message->flags_ & secret_api::decryptedMessage::MEDIA_MASK) != 0) { - flags |= MESSAGE_FLAG_HAS_MEDIA; + message_info.reply_to_message_id = + get_message_id_by_random_id(d, message->reply_to_random_id_, "on_get_secret_message"); } if ((message->flags_ & secret_api::decryptedMessage::SILENT_MASK) != 0) { flags |= MESSAGE_FLAG_IS_SILENT; @@ -13850,7 +13841,6 @@ void MessagesManager::on_get_secret_message(SecretChatId secret_chat_id, UserId } if ((message->flags_ & secret_api::decryptedMessage::GROUPED_ID_MASK) != 0 && message->grouped_id_ != 0) { message_info.media_album_id = message->grouped_id_; - flags |= MESSAGE_FLAG_HAS_MEDIA_ALBUM_ID; } message_info.flags = flags; @@ -35817,14 +35807,19 @@ MessageId MessagesManager::get_message_id_by_random_id(Dialog *d, int64 random_i << source << " " << random_id << " " << d->random_id_to_message_id[random_id] << " " << m->message_id << " " << m->is_failed_to_send << " " << m->is_outgoing << " " << m->from_database << " " << get_message(d, m->message_id) << " " << m << " " << debug_add_message_to_dialog_fail_reason_; + LOG(INFO) << "Found " << FullMessageId{d->dialog_id, m->message_id} << " by random_id " << random_id + << " from " << source; return m->message_id; } } } + LOG(INFO) << "Found no message by random_id " << random_id << " from " << source; return MessageId(); } + LOG(INFO) << "Found " << FullMessageId{d->dialog_id, it->second} << " by random_id " << random_id << " from " + << source; return it->second; } From 0bf2aaf4f2b66a159bfd5670083e01debfa43dc1 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 17 May 2022 16:19:39 +0300 Subject: [PATCH 07/14] Resolve identifiers of being added secret messages by their random_id. --- td/telegram/MessagesManager.cpp | 22 ++++++++++++++++++++++ td/telegram/MessagesManager.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 9224b65ef..b7a55f6a8 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -13814,6 +13814,8 @@ void MessagesManager::on_get_secret_message(SecretChatId secret_chat_id, UserId return; } + pending_secret_message_ids_[message_info.dialog_id][message_info.random_id] = message_id; + pending_secret_message->load_data_multipromise.add_promise(Auto()); auto lock_promise = pending_secret_message->load_data_multipromise.get_promise(); @@ -13821,6 +13823,15 @@ void MessagesManager::on_get_secret_message(SecretChatId secret_chat_id, UserId if ((message->flags_ & secret_api::decryptedMessage::REPLY_TO_RANDOM_ID_MASK) != 0) { message_info.reply_to_message_id = get_message_id_by_random_id(d, message->reply_to_random_id_, "on_get_secret_message"); + if (!message_info.reply_to_message_id.is_valid()) { + auto dialog_it = pending_secret_message_ids_.find(message_info.dialog_id); + if (dialog_it != pending_secret_message_ids_.end()) { + auto message_it = dialog_it->second.find(message->reply_to_random_id_); + if (message_it != dialog_it->second.end()) { + message_info.reply_to_message_id = message_it->second; + } + } + } } if ((message->flags_ & secret_api::decryptedMessage::SILENT_MASK) != 0) { flags |= MESSAGE_FLAG_IS_SILENT; @@ -13997,6 +14008,17 @@ void MessagesManager::finish_add_secret_message(unique_ptr on_get_message(std::move(pending_secret_message->message_info), true, false, true, true, "finish add secret message"); } + auto dialog_it = pending_secret_message_ids_.find(d->dialog_id); + if (dialog_it != pending_secret_message_ids_.end()) { + auto message_it = dialog_it->second.find(random_id); + if (message_it != dialog_it->second.end() && message_it->second == message_id) { + dialog_it->second.erase(message_it); + if (dialog_it->second.empty()) { + pending_secret_message_ids_.erase(dialog_it); + } + } + } + pending_secret_message->success_promise.set_value(Unit()); // TODO: set after message is saved } diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 117ec398a..31e6db08b 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -3600,6 +3600,9 @@ class MessagesManager final : public Actor { ChangesProcessor> pending_secret_messages_; + FlatHashMap, DialogIdHash> + pending_secret_message_ids_; // random_id -> message_id + FlatHashMap, DialogIdHash> pending_add_dialog_last_database_message_dependent_dialogs_; FlatHashMap>, DialogIdHash> pending_add_dialog_last_database_message_; // dialog -> dependency counter + message From e65c0827a4e038be37d170282586bd8d69492125 Mon Sep 17 00:00:00 2001 From: levlam Date: Tue, 17 May 2022 16:27:46 +0300 Subject: [PATCH 08/14] Drop dangling replies to yet unsent messages. --- td/telegram/MessagesManager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index b7a55f6a8..30c78129c 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -14533,6 +14533,11 @@ FullMessageId MessagesManager::on_get_message(MessageInfo &&message_info, bool f update_message(d, old_message.get(), std::move(new_message), &need_update_dialog_pos, false); new_message = std::move(old_message); + if (new_message->reply_to_message_id != MessageId() && new_message->reply_to_message_id.is_yet_unsent()) { + LOG(INFO) << "Drop reply to " << new_message->reply_to_message_id; + new_message->reply_to_message_id = MessageId(); + } + set_message_id(new_message, message_id); send_update_message_send_succeeded(d, old_message_id, new_message.get()); @@ -30831,6 +30836,11 @@ FullMessageId MessagesManager::on_send_message_success(int64 random_id, MessageI sent_message->have_previous = true; sent_message->have_next = true; + if (sent_message->reply_to_message_id != MessageId() && sent_message->reply_to_message_id.is_yet_unsent()) { + LOG(INFO) << "Drop reply to " << sent_message->reply_to_message_id; + sent_message->reply_to_message_id = MessageId(); + } + send_update_message_send_succeeded(d, old_message_id, sent_message.get()); bool need_update = true; From 1616513c4cae920c05724de3840d58d9661e2ce8 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 18 May 2022 12:16:32 +0300 Subject: [PATCH 09/14] Add and use MessagesManager::is_deleted_message. --- td/telegram/MessagesManager.cpp | 78 +++++++++++---------------------- td/telegram/MessagesManager.h | 2 + 2 files changed, 28 insertions(+), 52 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 30c78129c..8b0ee3d88 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -10455,7 +10455,7 @@ void MessagesManager::delete_dialog_messages(DialogId dialog_id, const vectordeleted_message_ids.count(message_id) != 0; + bool was_already_deleted = is_deleted_message(d, message_id); auto message = delete_message(d, message_id, true, &need_update_dialog_pos, source); if (message == nullptr) { if (!skip_update_for_not_found_messages && !was_already_deleted) { @@ -16218,6 +16218,14 @@ void MessagesManager::on_message_deleted(Dialog *d, Message *m, bool is_permanen added_message_count_--; } +bool MessagesManager::is_deleted_message(const Dialog *d, MessageId message_id) { + if (message_id.is_scheduled() && message_id.is_valid_scheduled() && message_id.is_scheduled_server()) { + return d->deleted_scheduled_server_message_ids.count(message_id.get_scheduled_server_message_id()) > 0; + } else { + return d->deleted_message_ids.count(message_id) > 0; + } +} + unique_ptr MessagesManager::do_delete_scheduled_message(Dialog *d, MessageId message_id, bool is_permanently_deleted, const char *source) { @@ -17746,7 +17754,7 @@ void MessagesManager::get_message_force_from_server(Dialog *d, MessageId message LOG(INFO) << "Get " << message_id << " in " << d->dialog_id << " using " << to_string(input_message); auto dialog_type = d->dialog_id.get_type(); auto m = get_message_force(d, message_id, "get_message_force_from_server"); - if (m == nullptr) { + if (m == nullptr && !is_deleted_message(d, message_id) && dialog_type != DialogType::SecretChat) { if (message_id.is_valid() && message_id.is_server()) { if (d->last_new_message_id != MessageId() && message_id > d->last_new_message_id && dialog_type != DialogType::Channel) { @@ -17754,15 +17762,11 @@ void MessagesManager::get_message_force_from_server(Dialog *d, MessageId message return promise.set_value(Unit()); } - if (d->deleted_message_ids.count(message_id) == 0 && dialog_type != DialogType::SecretChat) { - return get_message_from_server({d->dialog_id, message_id}, std::move(promise), "get_message_force_from_server", - std::move(input_message)); - } - } else if (message_id.is_valid_scheduled() && message_id.is_scheduled_server()) { - if (d->deleted_scheduled_server_message_ids.count(message_id.get_scheduled_server_message_id()) == 0 && - dialog_type != DialogType::SecretChat && input_message == nullptr) { - return get_message_from_server({d->dialog_id, message_id}, std::move(promise), "get_message_force_from_server"); - } + return get_message_from_server({d->dialog_id, message_id}, std::move(promise), "get_message_force_from_server", + std::move(input_message)); + } + if (message_id.is_valid_scheduled() && message_id.is_scheduled_server() && input_message == nullptr) { + return get_message_from_server({d->dialog_id, message_id}, std::move(promise), "get_message_force_from_server"); } } @@ -18524,7 +18528,7 @@ Result> MessagesManager::get_message_link(FullMessageId if (!m->top_thread_message_id.is_valid() || !m->top_thread_message_id.is_server()) { for_comment = false; } - if (d->deleted_message_ids.count(m->top_thread_message_id) != 0) { + if (is_deleted_message(d, m->top_thread_message_id)) { for_comment = false; } if (for_comment && is_broadcast_channel(dialog_id)) { @@ -27296,7 +27300,7 @@ void MessagesManager::update_message_max_reply_media_timestamp(const Dialog *d, auto replied_m = get_message(d, m->reply_to_message_id); if (replied_m != nullptr) { new_max_reply_media_timestamp = get_message_own_max_media_timestamp(replied_m); - } else if (!d->deleted_message_ids.count(m->reply_to_message_id) && + } else if (!is_deleted_message(d, m->reply_to_message_id) && m->reply_to_message_id > d->last_clear_history_message_id && m->reply_to_message_id > d->max_unavailable_message_id) { // replied message isn't deleted and isn't loaded yet @@ -28959,7 +28963,7 @@ Result MessagesManager::get_messag if (message_id <= d->last_clear_history_message_id) { return Status::Error("Ignore notification about message from cleared chat history"); } - if (d->deleted_message_ids.count(message_id)) { + if (is_deleted_message(d, message_id)) { return Status::Error("Ignore notification about deleted message"); } if (message_id <= d->max_unavailable_message_id) { @@ -30816,12 +30820,6 @@ FullMessageId MessagesManager::on_send_message_success(int64 random_id, MessageI sent_message->ttl_period = ttl_period; - // reply_to message may be already deleted - // but can't use get_message_force for check, because the message can be already unloaded from the memory - // if (get_message_force(d, sent_message->reply_to_message_id, "on_send_message_success 2") == nullptr) { - // sent_message->reply_to_message_id = MessageId(); - // } - if (merge_message_content_file_id(td_, sent_message->content.get(), new_file_id)) { send_update_message_content(d, sent_message.get(), false, source); } @@ -31262,19 +31260,17 @@ void MessagesManager::fail_send_message(FullMessageId full_message_id, int error // dump_debug_message_op(d, 5); } - MessageId new_message_id = - old_message_id.get_next_message_id(MessageType::Local); // trying to not change message place + MessageId new_message_id = old_message_id.get_next_message_id(MessageType::Local); // trying to keep message position if (!old_message_id.is_scheduled()) { - if (get_message_force(d, new_message_id, "fail_send_message") != nullptr || - d->deleted_message_ids.count(new_message_id) || new_message_id <= d->last_clear_history_message_id) { + if (get_message_force(d, new_message_id, "fail_send_message") != nullptr || is_deleted_message(d, new_message_id) || + new_message_id <= d->last_clear_history_message_id) { new_message_id = get_next_local_message_id(d); } else if (new_message_id > d->last_assigned_message_id) { d->last_assigned_message_id = new_message_id; } } else { - // check deleted_message_ids, because the new_message_id is not a server scheduled while (get_message_force(d, new_message_id, "fail_send_message") != nullptr || - d->deleted_message_ids.count(new_message_id)) { + is_deleted_message(d, new_message_id)) { new_message_id = new_message_id.get_next_message_id(MessageType::Local); } } @@ -33717,24 +33713,14 @@ MessagesManager::Message *MessagesManager::get_message_force(Dialog *d, MessageI return result; } - if (!G()->parameters().use_message_db || message_id.is_yet_unsent()) { + if (!G()->parameters().use_message_db || message_id.is_yet_unsent() || is_deleted_message(d, message_id)) { return nullptr; } - if (d->deleted_message_ids.count(message_id)) { + if (message_id.is_scheduled() && d->has_loaded_scheduled_messages_from_database) { return nullptr; } - if (message_id.is_scheduled()) { - if (d->has_loaded_scheduled_messages_from_database) { - return nullptr; - } - if (message_id.is_scheduled_server() && - d->deleted_scheduled_server_message_ids.count(message_id.get_scheduled_server_message_id())) { - return nullptr; - } - } - LOG(INFO) << "Trying to load " << FullMessageId{d->dialog_id, message_id} << " from database from " << source; auto r_value = G()->td_db()->get_messages_db_sync()->get_message({d->dialog_id, message_id}); @@ -33939,11 +33925,6 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq debug_add_message_to_dialog_fail_reason_ = "cleared full history"; return nullptr; } - if (d->deleted_message_ids.count(message->reply_to_message_id)) { - // LOG(INFO) << "Remove reply to deleted " << message->reply_to_message_id << " in " << message_id << " from " << dialog_id << " from " << source; - // we don't want to lose information that the message was a reply - // message->reply_to_message_id = MessageId(); - } LOG(INFO) << "Adding " << message_id << " of type " << message->content->get_type() << " to " << dialog_id << " from " << source << ". Last new is " << d->last_new_message_id << ", last is " << d->last_message_id @@ -33964,7 +33945,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq CHECK(from_update); } - if (d->deleted_message_ids.count(message_id)) { + if (is_deleted_message(d, message_id)) { LOG(INFO) << "Skip adding deleted " << message_id << " to " << dialog_id << " from " << source; debug_add_message_to_dialog_fail_reason_ = "adding deleted message"; return nullptr; @@ -34719,19 +34700,12 @@ MessagesManager::Message *MessagesManager::add_scheduled_message_to_dialog(Dialo message->top_thread_message_id = MessageId(); - if (d->deleted_message_ids.count(message_id)) { + if (is_deleted_message(d, message_id)) { LOG(INFO) << "Skip adding deleted " << message_id << " to " << dialog_id << " from " << source; debug_add_message_to_dialog_fail_reason_ = "adding deleted scheduled message"; return nullptr; } - if (message_id.is_scheduled_server() && - d->deleted_scheduled_server_message_ids.count(message_id.get_scheduled_server_message_id())) { - LOG(INFO) << "Skip adding deleted " << message_id << " to " << dialog_id << " from " << source; - debug_add_message_to_dialog_fail_reason_ = "adding deleted scheduled server message"; - return nullptr; - } - if (dialog_id.get_type() == DialogType::SecretChat) { LOG(ERROR) << "Tried to add " << message_id << " to " << dialog_id << " from " << source; debug_add_message_to_dialog_fail_reason_ = "skip adding scheduled message to secret chat"; diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 31e6db08b..9a02b3be5 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -2068,6 +2068,8 @@ class MessagesManager final : public Actor { void on_message_deleted(Dialog *d, Message *m, bool is_permanently_deleted, const char *source); + static bool is_deleted_message(const Dialog *d, MessageId message_id); + int32 get_unload_dialog_delay() const; int32 get_next_unload_dialog_delay() const; From 18cd0dd95eceb4ea6de52ca55fba8ffcaf7da960 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 18 May 2022 16:59:15 +0300 Subject: [PATCH 10/14] Workaround GCC 12 false positive warnings. --- CMake/TdSetUpCompiler.cmake | 3 +++ td/telegram/SecretChatActor.cpp | 7 +++---- td/telegram/logevent/SecretChatEvent.h | 18 +++++++++--------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/CMake/TdSetUpCompiler.cmake b/CMake/TdSetUpCompiler.cmake index 67320174e..728615e27 100644 --- a/CMake/TdSetUpCompiler.cmake +++ b/CMake/TdSetUpCompiler.cmake @@ -145,6 +145,9 @@ function(td_set_up_compiler) # see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1579 add_cxx_compiler_flag("-Wno-redundant-move") endif() + if (GCC AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0)) + add_cxx_compiler_flag("-Wno-stringop-overflow") # some false positives + endif() if (CLANG AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)) # https://stackoverflow.com/questions/26744556/warning-returning-a-captured-reference-from-a-lambda add_cxx_compiler_flag("-Wno-return-stack-address") diff --git a/td/telegram/SecretChatActor.cpp b/td/telegram/SecretChatActor.cpp index 181c3eb3c..2d70b3195 100644 --- a/td/telegram/SecretChatActor.cpp +++ b/td/telegram/SecretChatActor.cpp @@ -1516,7 +1516,7 @@ Status SecretChatActor::outbound_rewrite_with_empty(uint64 state_id) { state->message->is_external = false; state->message->need_notify_user = false; state->message->is_silent = true; - state->message->file = log_event::EncryptedInputFile::from_input_encrypted_file(nullptr); + state->message->file = log_event::EncryptedInputFile(); binlog_rewrite(context_->binlog(), state->message->log_event_id(), LogEvent::HandlerType::SecretChats, create_storer(*state->message)); return Status::OK(); @@ -1606,15 +1606,14 @@ void SecretChatActor::on_outbound_send_message_result(NetQueryPtr query, Promise auto sent = move_tl_object_as(result); auto file = EncryptedFile::get_encrypted_file(std::move(sent->file_)); if (file == nullptr) { - state->message->file = log_event::EncryptedInputFile::from_input_encrypted_file(nullptr); + state->message->file = log_event::EncryptedInputFile(); state->send_result_ = [this, random_id = state->message->random_id, message_id = MessageId(ServerMessageId(state->message->message_id)), date = sent->date_](Promise<> promise) { context_->on_send_message_ok(random_id, message_id, date, nullptr, std::move(promise)); }; } else { - state->message->file = log_event::EncryptedInputFile::from_input_encrypted_file( - make_tl_object(file->id_, file->access_hash_)); + state->message->file = {log_event::EncryptedInputFile::Location, file->id_, file->access_hash_, 0, 0}; state->send_result_ = [this, random_id = state->message->random_id, message_id = MessageId(ServerMessageId(state->message->message_id)), date = sent->date_, file = *file](Promise<> promise) { diff --git a/td/telegram/logevent/SecretChatEvent.h b/td/telegram/logevent/SecretChatEvent.h index 6186c7d68..f5951d039 100644 --- a/td/telegram/logevent/SecretChatEvent.h +++ b/td/telegram/logevent/SecretChatEvent.h @@ -175,31 +175,30 @@ struct EncryptedInputFile { } } static EncryptedInputFile from_input_encrypted_file(const tl_object_ptr &from) { - if (!from) { - return EncryptedInputFile{Empty, 0, 0, 0, 0}; + if (from == nullptr) { + return EncryptedInputFile(); } - return from_input_encrypted_file(*from); - } - static EncryptedInputFile from_input_encrypted_file(const telegram_api::InputEncryptedFile &from) { - switch (from.get_id()) { + switch (from->get_id()) { case telegram_api::inputEncryptedFileEmpty::ID: return EncryptedInputFile{Empty, 0, 0, 0, 0}; case telegram_api::inputEncryptedFileUploaded::ID: { - auto &uploaded = static_cast(from); + auto &uploaded = static_cast(*from); return EncryptedInputFile{Uploaded, uploaded.id_, 0, uploaded.parts_, uploaded.key_fingerprint_}; } case telegram_api::inputEncryptedFileBigUploaded::ID: { - auto &uploaded = static_cast(from); + auto &uploaded = static_cast(*from); return EncryptedInputFile{BigUploaded, uploaded.id_, 0, uploaded.parts_, uploaded.key_fingerprint_}; } case telegram_api::inputEncryptedFile::ID: { - auto &uploaded = static_cast(from); + auto &uploaded = static_cast(*from); return EncryptedInputFile{Location, uploaded.id_, uploaded.access_hash_, 0, 0}; } default: UNREACHABLE(); + return EncryptedInputFile(); } } + tl_object_ptr as_input_encrypted_file() const { switch (type) { case Empty: @@ -212,6 +211,7 @@ struct EncryptedInputFile { return make_tl_object(id, access_hash); } UNREACHABLE(); + return nullptr; } }; From 5fda16c89e9623f1cea406853ddadb49c992102b Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 19 May 2022 19:20:07 +0300 Subject: [PATCH 11/14] Add WaitFreeHashMap. --- tdutils/CMakeLists.txt | 2 + tdutils/td/utils/WaitFreeHashMap.h | 66 ++++++++++++++++++++++++++++++ tdutils/test/WaitFreeHashMap.cpp | 53 ++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 tdutils/td/utils/WaitFreeHashMap.h create mode 100644 tdutils/test/WaitFreeHashMap.cpp diff --git a/tdutils/CMakeLists.txt b/tdutils/CMakeLists.txt index de7e26eba..7d7125e63 100644 --- a/tdutils/CMakeLists.txt +++ b/tdutils/CMakeLists.txt @@ -289,6 +289,7 @@ set(TDUTILS_SOURCE td/utils/utf8.h td/utils/Variant.h td/utils/VectorQueue.h + td/utils/WaitFreeHashMap.h ) if (TDUTILS_MIME_TYPE) @@ -329,6 +330,7 @@ set(TDUTILS_TEST_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/test/SharedSlice.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/StealingQueue.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/variant.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test/WaitFreeHashMap.cpp PARENT_SCOPE ) diff --git a/tdutils/td/utils/WaitFreeHashMap.h b/tdutils/td/utils/WaitFreeHashMap.h new file mode 100644 index 000000000..0d32e0bd5 --- /dev/null +++ b/tdutils/td/utils/WaitFreeHashMap.h @@ -0,0 +1,66 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/utils/common.h" +#include "td/utils/FlatHashMap.h" +#include "td/utils/HashTableUtils.h" + +#include + +namespace td { + +template , class EqT = std::equal_to> +class WaitFreeHashMap { + using Storage = FlatHashMap; + static constexpr size_t MAX_STORAGE_COUNT = 256; + static_assert((MAX_STORAGE_COUNT & (MAX_STORAGE_COUNT - 1)) == 0, ""); + static constexpr size_t MAX_STORAGE_SIZE = MAX_STORAGE_COUNT * MAX_STORAGE_COUNT / 2; + + Storage default_map_; + struct WaitFreeStorage { + Storage maps_[MAX_STORAGE_COUNT]; + }; + unique_ptr wait_free_storage_; + + Storage &get_storage(const KeyT &key) { + if (wait_free_storage_ == nullptr) { + return default_map_; + } + + return wait_free_storage_->maps_[randomize_hash(HashT()(key)) & (MAX_STORAGE_COUNT - 1)]; + } + + public: + void set(const KeyT &key, ValueT value) { + auto &storage = get_storage(key); + storage[key] = std::move(value); + if (default_map_.size() == MAX_STORAGE_SIZE) { + CHECK(wait_free_storage_ == nullptr); + wait_free_storage_ = make_unique(); + for (auto &it : default_map_) { + get_storage(it.first).emplace(it.first, std::move(it.second)); + } + default_map_.clear(); + } + } + + ValueT get(const KeyT &key) { + auto &storage = get_storage(key); + auto it = storage.find(key); + if (it == storage.end()) { + return {}; + } + return it->second; + } + + size_t erase(const KeyT &key) { + return get_storage(key).erase(key); + } +}; + +} // namespace td diff --git a/tdutils/test/WaitFreeHashMap.cpp b/tdutils/test/WaitFreeHashMap.cpp new file mode 100644 index 000000000..8865d5ffd --- /dev/null +++ b/tdutils/test/WaitFreeHashMap.cpp @@ -0,0 +1,53 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/utils/common.h" +#include "td/utils/FlatHashMap.h" +#include "td/utils/Random.h" +#include "td/utils/tests.h" +#include "td/utils/WaitFreeHashMap.h" + +TEST(WaitFreeHashMap, stress_test) { + td::Random::Xorshift128plus rnd(123); + td::FlatHashMap reference; + td::WaitFreeHashMap map; + + td::vector steps; + auto add_step = [&](td::uint32 weight, auto f) { + steps.emplace_back(td::RandomSteps::Step{std::move(f), weight}); + }; + + auto gen_key = [&] { + return rnd() % 100000 + 1; + }; + + add_step(2000, [&] { + auto key = gen_key(); + auto value = rnd(); + reference[key] = value; + map.set(key, value); + ASSERT_EQ(reference[key], map.get(key)); + }); + + add_step(2000, [&] { + auto key = gen_key(); + auto ref_it = reference.find(key); + auto ref_value = ref_it == reference.end() ? 0 : ref_it->second; + ASSERT_EQ(ref_value, map.get(key)); + }); + + add_step(500, [&] { + auto key = gen_key(); + size_t reference_erased_count = reference.erase(key); + size_t map_erased_count = map.erase(key); + ASSERT_EQ(reference_erased_count, map_erased_count); + }); + + td::RandomSteps runner(std::move(steps)); + for (size_t i = 0; i < 1000000; i++) { + runner.step(rnd); + } +} From 16959e33e47e4954e00d4faf2ee0263178968bb6 Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 19 May 2022 19:34:48 +0300 Subject: [PATCH 12/14] Use WaitFreeHashMap for message_id_to_dialog_id_. --- td/telegram/MessagesManager.cpp | 14 +++++++------- td/telegram/MessagesManager.h | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 8b0ee3d88..1e77b9c45 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -34638,7 +34638,7 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq case DialogType::User: case DialogType::Chat: if (m->message_id.is_server()) { - message_id_to_dialog_id_[m->message_id] = dialog_id; + message_id_to_dialog_id_.set(m->message_id, dialog_id); } break; case DialogType::Channel: @@ -35760,18 +35760,18 @@ bool MessagesManager::update_message_content(DialogId dialog_id, Message *old_me MessagesManager::Dialog *MessagesManager::get_dialog_by_message_id(MessageId message_id) { CHECK(message_id.is_valid() && message_id.is_server()); - auto it = message_id_to_dialog_id_.find(message_id); - if (it == message_id_to_dialog_id_.end()) { + auto dialog_id = message_id_to_dialog_id_.get(message_id); + if (dialog_id == DialogId()) { if (G()->parameters().use_message_db) { auto r_value = G()->td_db()->get_messages_db_sync()->get_message_by_unique_message_id(message_id.get_server_message_id()); if (r_value.is_ok()) { Message *m = on_get_message_from_database(r_value.ok(), false, "get_dialog_by_message_id"); if (m != nullptr) { - auto dialog_id = r_value.ok().dialog_id; + dialog_id = r_value.ok().dialog_id; CHECK(m->message_id == message_id); - LOG_CHECK(message_id_to_dialog_id_[message_id] == dialog_id) - << message_id << ' ' << dialog_id << ' ' << message_id_to_dialog_id_[message_id] << ' ' + LOG_CHECK(message_id_to_dialog_id_.get(message_id) == dialog_id) + << message_id << ' ' << dialog_id << ' ' << message_id_to_dialog_id_.get(message_id) << ' ' << m->debug_source; Dialog *d = get_dialog(dialog_id); CHECK(d != nullptr); @@ -35784,7 +35784,7 @@ MessagesManager::Dialog *MessagesManager::get_dialog_by_message_id(MessageId mes return nullptr; } - return get_dialog(it->second); + return get_dialog(dialog_id); } MessageId MessagesManager::get_message_id_by_random_id(Dialog *d, int64 random_id, const char *source) { diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 9a02b3be5..f9ad3c744 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -75,6 +75,7 @@ #include "td/utils/Slice.h" #include "td/utils/Status.h" #include "td/utils/StringBuilder.h" +#include "td/utils/WaitFreeHashMap.h" #include #include @@ -3427,7 +3428,7 @@ class MessagesManager final : public Actor { }; FlatHashMap pending_message_group_sends_; // media_album_id -> ... - FlatHashMap message_id_to_dialog_id_; + WaitFreeHashMap message_id_to_dialog_id_; FlatHashMap last_clear_history_message_id_to_dialog_id_; bool created_public_broadcasts_inited_ = false; From 9c9a74c52df2a3d00705d6c97a594e0a8fb1e61e Mon Sep 17 00:00:00 2001 From: levlam Date: Thu, 19 May 2022 19:50:02 +0300 Subject: [PATCH 13/14] Workaround GCC 7.4.0 false warning. --- td/telegram/MessagesManager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 1e77b9c45..a031cd32b 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -11029,11 +11029,9 @@ MessagesManager::CanDeleteDialog MessagesManager::can_delete_dialog(const Dialog if (td_->contacts_manager_->get_secret_chat_state(d->dialog_id.get_secret_chat_id()) == SecretChatState::Closed) { // in a closed secret chats there is no way to delete messages for both users return {true, false}; - } else { - // active secret chats can be deleted only for both users - return {false, true}; } - break; + // active secret chats can be deleted only for both users + return {false, true}; case DialogType::None: default: UNREACHABLE(); From c2a580bbfb879bdce718d68d66677c52e68de47b Mon Sep 17 00:00:00 2001 From: levlam Date: Fri, 20 May 2022 16:59:14 +0300 Subject: [PATCH 14/14] Don't try to reload data without authorization. --- td/telegram/UpdatesManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/td/telegram/UpdatesManager.cpp b/td/telegram/UpdatesManager.cpp index 8448d7b0b..4c54158ba 100644 --- a/td/telegram/UpdatesManager.cpp +++ b/td/telegram/UpdatesManager.cpp @@ -1611,7 +1611,8 @@ void UpdatesManager::try_reload_data_static(void *td) { } void UpdatesManager::try_reload_data() { - if (td_->auth_manager_->is_bot() || running_get_difference_ || !td_->is_online()) { + if (!td_->auth_manager_->is_authorized() || td_->auth_manager_->is_bot() || running_get_difference_ || + !td_->is_online()) { return; }