Merge remote-tracking branch 'td/master'

This commit is contained in:
Andrea Cavalli 2022-05-24 00:22:37 +02:00
commit aa3b705842
9 changed files with 425 additions and 160 deletions

View File

@ -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")

View File

@ -3198,6 +3198,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*/,
@ -3330,6 +3331,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),
@ -3393,6 +3395,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),
@ -3509,6 +3512,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),
@ -10538,7 +10542,7 @@ void MessagesManager::delete_dialog_messages(DialogId dialog_id, const vector<Me
CHECK(message_id.is_valid());
}
bool was_already_deleted = d->deleted_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) {
@ -11112,11 +11116,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();
@ -13079,6 +13081,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);
@ -13103,6 +13106,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();
@ -13698,7 +13702,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<int64> random_ids,
@ -13731,7 +13735,7 @@ void MessagesManager::finish_delete_secret_messages(DialogId dialog_id, std::vec
CHECK(d != nullptr);
vector<MessageId> 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;
@ -13898,23 +13902,25 @@ 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();
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;
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::ENTITIES_MASK) != 0) {
flags |= MESSAGE_FLAG_HAS_ENTITIES;
}
if ((message->flags_ & secret_api::decryptedMessage::MEDIA_MASK) != 0) {
flags |= MESSAGE_FLAG_HAS_MEDIA;
}
if ((message->flags_ & secret_api::decryptedMessage::SILENT_MASK) != 0) {
flags |= MESSAGE_FLAG_IS_SILENT;
}
@ -13934,7 +13940,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;
@ -14091,6 +14096,17 @@ void MessagesManager::finish_add_secret_message(unique_ptr<PendingSecretMessage>
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
}
@ -14452,6 +14468,7 @@ std::pair<DialogId, unique_ptr<MessagesManager::Message>> 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();
@ -14577,11 +14594,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<Message> 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();
}
@ -14601,6 +14621,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());
@ -15781,8 +15806,7 @@ unique_ptr<MessagesManager::Message> 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;
@ -15792,8 +15816,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;
@ -16253,7 +16276,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()) {
@ -16263,10 +16287,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:
@ -16280,10 +16302,21 @@ 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_--;
}
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::Message> MessagesManager::do_delete_scheduled_message(Dialog *d, MessageId message_id,
bool is_permanently_deleted,
const char *source) {
@ -17812,7 +17845,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) {
@ -17820,15 +17853,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");
}
}
@ -18590,7 +18619,7 @@ Result<std::pair<string, bool>> 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)) {
@ -24563,11 +24592,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;
}
@ -24576,7 +24606,6 @@ unique_ptr<MessagesManager::Message> MessagesManager::create_message_to_send(
unique_ptr<MessageContent> &&content, bool suppress_reply_info, unique_ptr<MessageForwardInfo> 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;
@ -24620,7 +24649,7 @@ unique_ptr<MessagesManager::Message> 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;
@ -24678,16 +24707,18 @@ unique_ptr<MessagesManager::Message> 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;
}
@ -24707,7 +24738,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));
@ -24809,8 +24840,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();
@ -24873,13 +24910,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);
}
}
@ -27325,11 +27387,11 @@ 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);
} 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
@ -27381,6 +27443,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);
@ -27401,7 +27466,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;
}
@ -27414,7 +27479,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;
}
@ -27460,6 +27525,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) {
@ -28009,7 +28075,7 @@ Result<MessagesManager::ForwardedMessages> 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 &copy_option : copy_options) {
if (!copy_option.is_supported_server_side()) {
can_use_server_forward = false;
@ -28017,6 +28083,9 @@ Result<MessagesManager::ForwardedMessages> 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;
@ -28101,6 +28170,7 @@ Result<MessagesManager::ForwardedMessages> 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 {
@ -28162,6 +28232,7 @@ Result<td_api::object_ptr<td_api::messages>> MessagesManager::forward_messages(
auto drop_author = forwarded_messages_info.drop_author;
auto drop_media_captions = forwarded_messages_info.drop_media_captions;
FlatHashMap<MessageId, MessageId, MessageIdHash> forwarded_message_id_to_new_message_id;
vector<td_api::object_ptr<td_api::message>> result(message_ids.size());
vector<Message *> forwarded_messages;
vector<MessageId> forwarded_message_ids;
@ -28183,13 +28254,20 @@ Result<td_api::object_ptr<td_api::messages>> 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;
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)
@ -28197,7 +28275,7 @@ Result<td_api::object_ptr<td_api::messages>> 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));
}
@ -28206,6 +28284,7 @@ Result<td_api::object_ptr<td_api::messages>> 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);
@ -28222,14 +28301,30 @@ Result<td_api::object_ptr<td_api::messages>> 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;
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)
@ -28237,13 +28332,14 @@ Result<td_api::object_ptr<td_api::messages>> 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);
@ -28958,7 +29054,7 @@ Result<MessagesManager::MessagePushNotificationInfo> 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) {
@ -30722,6 +30818,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<int32>(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);
@ -30761,6 +30885,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);
@ -30791,12 +30918,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);
}
@ -30811,6 +30932,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;
@ -30873,10 +30999,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);
@ -30922,10 +31049,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);
@ -31212,6 +31340,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> message = delete_message(d, old_message_id, false, &need_update_dialog_pos, "fail send message");
@ -31228,19 +31358,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);
}
}
@ -33683,24 +33811,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});
@ -33905,11 +34023,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
@ -33930,7 +34043,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;
@ -34457,8 +34570,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()) {
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()) {
@ -34619,16 +34736,13 @@ MessagesManager::Message *MessagesManager::add_message_to_dialog(Dialog *d, uniq
case DialogType::User:
case DialogType::Chat:
if (m->message_id.is_server()) {
if (!G()->shared_config().get_option_boolean("ignore_server_deletes_and_reads", false)) {
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:
// 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:
@ -34638,6 +34752,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);
@ -34681,19 +34798,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";
@ -34758,7 +34868,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}]++;
}
@ -35395,16 +35506,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()) {
CHECK(!is_message_in_dialog);
CHECK(new_message->reply_to_message_id.is_valid());
CHECK(new_message->reply_to_message_id.is_server());
old_message->reply_to_message_id = new_message->reply_to_message_id;
} else {
LOG(ERROR) << message_id << " in " << dialog_id << " has changed message it is reply to 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) {
@ -35754,18 +35858,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);
@ -35778,18 +35882,17 @@ 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) {
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";
@ -35808,14 +35911,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;
}
@ -38533,6 +38641,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<Message> &&m,
uint64 log_event_id) {
CHECK(log_event_id != 0);
@ -38565,6 +38689,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 =
@ -38791,6 +38917,8 @@ void MessagesManager::on_binlog_events(vector<BinlogEvent> &&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());

View File

@ -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 <array>
#include <functional>
@ -1351,7 +1352,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<int64, MessageId> random_id_to_message_id; // for secret chats only
std::unordered_map<int64, MessageId> 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
@ -1866,7 +1867,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<Message> create_message_to_send(Dialog *d, MessageId top_thread_message_id, MessageId reply_to_message_id,
const MessageSendOptions &options, unique_ptr<MessageContent> &&content,
@ -1954,6 +1955,8 @@ class MessagesManager final : public Actor {
unique_ptr<MessageContent> content;
MessageId top_thread_message_id;
MessageId reply_to_message_id;
MessageId original_message_id;
MessageId original_reply_to_message_id;
unique_ptr<ReplyMarkup> reply_markup;
int64 media_album_id;
bool disable_web_page_preview;
@ -2024,6 +2027,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<Message> &&m, uint64 log_event_id);
bool is_message_unload_enabled() const;
@ -2066,6 +2071,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;
@ -2320,6 +2327,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);
@ -3421,7 +3430,7 @@ class MessagesManager final : public Actor {
};
FlatHashMap<int64, PendingMessageGroupSend> pending_message_group_sends_; // media_album_id -> ...
FlatHashMap<MessageId, DialogId, MessageIdHash> message_id_to_dialog_id_;
WaitFreeHashMap<MessageId, DialogId, MessageIdHash> message_id_to_dialog_id_;
FlatHashMap<MessageId, DialogId, MessageIdHash> last_clear_history_message_id_to_dialog_id_;
bool created_public_broadcasts_inited_ = false;
@ -3484,6 +3493,7 @@ class MessagesManager final : public Actor {
FlatHashMap<DialogId, uint64, DialogIdHash> get_dialog_query_log_event_id_;
FlatHashMap<FullMessageId, int32, FullMessageIdHash> replied_by_yet_unsent_messages_;
FlatHashMap<FullMessageId, FlatHashSet<MessageId, MessageIdHash>, FullMessageIdHash> replied_yet_unsent_messages_;
// full_message_id -> replies with media timestamps
FlatHashMap<FullMessageId, FlatHashSet<MessageId, MessageIdHash>, FullMessageIdHash>
@ -3595,6 +3605,9 @@ class MessagesManager final : public Actor {
ChangesProcessor<unique_ptr<PendingSecretMessage>> pending_secret_messages_;
FlatHashMap<DialogId, FlatHashMap<int64, MessageId>, DialogIdHash>
pending_secret_message_ids_; // random_id -> message_id
FlatHashMap<DialogId, vector<DialogId>, DialogIdHash> pending_add_dialog_last_database_message_dependent_dialogs_;
FlatHashMap<DialogId, std::pair<int32, unique_ptr<Message>>, DialogIdHash>
pending_add_dialog_last_database_message_; // dialog -> dependency counter + message

View File

@ -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<telegram_api::messages_sentEncryptedFile>(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<telegram_api::inputEncryptedFile>(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) {

View File

@ -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;
}

View File

@ -175,31 +175,30 @@ struct EncryptedInputFile {
}
}
static EncryptedInputFile from_input_encrypted_file(const tl_object_ptr<telegram_api::InputEncryptedFile> &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<const telegram_api::inputEncryptedFileUploaded &>(from);
auto &uploaded = static_cast<const telegram_api::inputEncryptedFileUploaded &>(*from);
return EncryptedInputFile{Uploaded, uploaded.id_, 0, uploaded.parts_, uploaded.key_fingerprint_};
}
case telegram_api::inputEncryptedFileBigUploaded::ID: {
auto &uploaded = static_cast<const telegram_api::inputEncryptedFileBigUploaded &>(from);
auto &uploaded = static_cast<const telegram_api::inputEncryptedFileBigUploaded &>(*from);
return EncryptedInputFile{BigUploaded, uploaded.id_, 0, uploaded.parts_, uploaded.key_fingerprint_};
}
case telegram_api::inputEncryptedFile::ID: {
auto &uploaded = static_cast<const telegram_api::inputEncryptedFile &>(from);
auto &uploaded = static_cast<const telegram_api::inputEncryptedFile &>(*from);
return EncryptedInputFile{Location, uploaded.id_, uploaded.access_hash_, 0, 0};
}
default:
UNREACHABLE();
return EncryptedInputFile();
}
}
tl_object_ptr<telegram_api::InputEncryptedFile> as_input_encrypted_file() const {
switch (type) {
case Empty:
@ -212,6 +211,7 @@ struct EncryptedInputFile {
return make_tl_object<telegram_api::inputEncryptedFile>(id, access_hash);
}
UNREACHABLE();
return nullptr;
}
};

View File

@ -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
)

View File

@ -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 <functional>
namespace td {
template <class KeyT, class ValueT, class HashT = std::hash<KeyT>, class EqT = std::equal_to<KeyT>>
class WaitFreeHashMap {
using Storage = FlatHashMap<KeyT, ValueT, HashT, EqT>;
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<WaitFreeStorage> 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<WaitFreeStorage>();
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

View File

@ -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<td::uint64, td::uint64> reference;
td::WaitFreeHashMap<td::uint64, td::uint64> map;
td::vector<td::RandomSteps::Step> 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);
}
}