Move resolved usernames to DialogManager.

This commit is contained in:
levlam 2024-01-07 23:45:33 +03:00
parent dc3929fede
commit a2c6f4aa7c
10 changed files with 324 additions and 298 deletions

View File

@ -13,7 +13,6 @@
#include "td/telegram/Global.h"
#include "td/telegram/LinkManager.h"
#include "td/telegram/MessageId.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/OptionManager.h"
#include "td/telegram/ServerMessageId.h"
#include "td/telegram/Td.h"
@ -437,7 +436,7 @@ void BoostManager::get_dialog_boost_link_info(Slice url, Promise<DialogBoostLink
auto info = r_dialog_boost_link_info.move_as_ok();
auto query_promise = PromiseCreator::lambda(
[info, promise = std::move(promise)](Result<DialogId> &&result) mutable { promise.set_value(std::move(info)); });
td_->messages_manager_->resolve_dialog(info.username, info.channel_id, std::move(query_promise));
td_->dialog_manager_->resolve_dialog(info.username, info.channel_id, std::move(query_promise));
}
td_api::object_ptr<td_api::chatBoostLinkInfo> BoostManager::get_chat_boost_link_info_object(
@ -446,7 +445,7 @@ td_api::object_ptr<td_api::chatBoostLinkInfo> BoostManager::get_chat_boost_link_
bool is_public = !info.username.empty();
DialogId dialog_id =
is_public ? td_->messages_manager_->resolve_dialog_username(info.username) : DialogId(info.channel_id);
is_public ? td_->dialog_manager_->get_resolved_dialog_by_username(info.username) : DialogId(info.channel_id);
return td_api::make_object<td_api::chatBoostLinkInfo>(
is_public, td_->dialog_manager_->get_chat_id_object(dialog_id, "chatBoostLinkInfo"));
}

View File

@ -12726,7 +12726,7 @@ void ContactsManager::update_user(User *u, UserId user_id, bool from_binlog, boo
td_->inline_queries_manager_->remove_recent_inline_bot(user_id, Promise<>());
}
if (from_binlog || from_database) {
td_->messages_manager_->on_dialog_usernames_received(DialogId(user_id), u->usernames, true);
td_->dialog_manager_->on_dialog_usernames_received(DialogId(user_id), u->usernames, true);
}
LOG(DEBUG) << "Update " << user_id << ": need_save_to_database = " << u->need_save_to_database
@ -13019,7 +13019,7 @@ void ContactsManager::update_channel(Channel *c, ChannelId channel_id, bool from
}
if (from_binlog || from_database) {
td_->messages_manager_->on_dialog_usernames_received(DialogId(channel_id), c->usernames, true);
td_->dialog_manager_->on_dialog_usernames_received(DialogId(channel_id), c->usernames, true);
}
if (!is_channel_public(c) && !c->has_linked_channel) {
@ -14132,6 +14132,7 @@ void ContactsManager::on_update_user_name(User *u, UserId user_id, string &&firs
void ContactsManager::on_update_user_usernames(User *u, UserId user_id, Usernames &&usernames) {
if (u->usernames != usernames) {
td_->dialog_manager_->on_dialog_usernames_updated(DialogId(user_id), u->usernames, usernames);
td_->messages_manager_->on_dialog_usernames_updated(DialogId(user_id), u->usernames, usernames);
if (u->can_be_edited_bot && u->usernames.get_editable_username() != usernames.get_editable_username()) {
u->is_full_info_changed = true;
@ -14141,7 +14142,7 @@ void ContactsManager::on_update_user_usernames(User *u, UserId user_id, Username
LOG(DEBUG) << "Usernames have changed for " << user_id;
u->is_changed = true;
} else if (u->is_bot || !td_->auth_manager_->is_bot()) {
td_->messages_manager_->on_dialog_usernames_received(DialogId(user_id), usernames, false);
td_->dialog_manager_->on_dialog_usernames_received(DialogId(user_id), usernames, false);
}
}
@ -17381,6 +17382,7 @@ void ContactsManager::on_update_channel_usernames(ChannelId channel_id, Username
void ContactsManager::on_update_channel_usernames(Channel *c, ChannelId channel_id, Usernames &&usernames) {
if (c->usernames != usernames) {
td_->dialog_manager_->on_dialog_usernames_updated(DialogId(channel_id), c->usernames, usernames);
td_->messages_manager_->on_dialog_usernames_updated(DialogId(channel_id), c->usernames, usernames);
if (c->is_update_supergroup_sent) {
on_channel_usernames_changed(c, channel_id, c->usernames, usernames);
@ -17390,7 +17392,7 @@ void ContactsManager::on_update_channel_usernames(Channel *c, ChannelId channel_
c->is_username_changed = true;
c->is_changed = true;
} else {
td_->messages_manager_->on_dialog_usernames_received(DialogId(channel_id), usernames, false);
td_->dialog_manager_->on_dialog_usernames_received(DialogId(channel_id), usernames, false);
}
}

View File

@ -23,6 +23,7 @@
#include "td/telegram/Td.h"
#include "td/telegram/UpdatesManager.h"
#include "td/telegram/UserId.h"
#include "td/telegram/Usernames.h"
#include "td/utils/algorithm.h"
#include "td/utils/buffer.h"
@ -32,6 +33,43 @@
namespace td {
class ResolveUsernameQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
string username_;
public:
explicit ResolveUsernameQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(const string &username) {
username_ = username;
send_query(G()->net_query_creator().create(telegram_api::contacts_resolveUsername(username)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::contacts_resolveUsername>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(DEBUG) << "Receive result for ResolveUsernameQuery: " << to_string(ptr);
td_->contacts_manager_->on_get_users(std::move(ptr->users_), "ResolveUsernameQuery");
td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "ResolveUsernameQuery");
td_->dialog_manager_->on_resolved_username(username_, DialogId(ptr->peer_));
promise_.set_value(Unit());
}
void on_error(Status status) final {
if (status.message() == Slice("USERNAME_NOT_OCCUPIED")) {
td_->dialog_manager_->drop_username(username_);
}
promise_.set_error(std::move(status));
}
};
class EditDialogTitleQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
DialogId dialog_id_;
@ -381,6 +419,11 @@ DialogManager::DialogManager(Td *td, ActorShared<> parent) : td_(td), parent_(st
upload_dialog_photo_callback_ = std::make_shared<UploadDialogPhotoCallback>();
}
DialogManager::~DialogManager() {
Scheduler::instance()->destroy_on_scheduler(G()->get_gc_scheduler_id(), resolved_usernames_,
inaccessible_resolved_usernames_);
}
void DialogManager::tear_down() {
parent_.reset();
}
@ -1584,4 +1627,205 @@ bool DialogManager::is_dialog_removed_from_dialog_list(DialogId dialog_id) const
return false;
}
void DialogManager::on_dialog_usernames_updated(DialogId dialog_id, const Usernames &old_usernames,
const Usernames &new_usernames) {
LOG(INFO) << "Update usernames in " << dialog_id << " from " << old_usernames << " to " << new_usernames;
for (auto &username : old_usernames.get_active_usernames()) {
auto cleaned_username = clean_username(username);
resolved_usernames_.erase(cleaned_username);
inaccessible_resolved_usernames_.erase(cleaned_username);
}
on_dialog_usernames_received(dialog_id, new_usernames, false);
}
void DialogManager::on_dialog_usernames_received(DialogId dialog_id, const Usernames &usernames, bool from_database) {
for (auto &username : usernames.get_active_usernames()) {
auto cleaned_username = clean_username(username);
if (!cleaned_username.empty()) {
resolved_usernames_[cleaned_username] =
ResolvedUsername{dialog_id, Time::now() + (from_database ? 0 : USERNAME_CACHE_EXPIRE_TIME)};
}
}
}
void DialogManager::send_resolve_dialog_username_query(const string &username, Promise<Unit> &&promise) {
td_->create_handler<ResolveUsernameQuery>(std::move(promise))->send(username);
}
void DialogManager::resolve_dialog(const string &username, ChannelId channel_id, Promise<DialogId> promise) {
CHECK(username.empty() == channel_id.is_valid());
bool have_dialog = username.empty() ? td_->contacts_manager_->have_channel_force(channel_id, "resolve_dialog")
: get_resolved_dialog_by_username(username).is_valid();
if (!have_dialog) {
auto query_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), username, channel_id, promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &DialogManager::on_resolve_dialog, username, channel_id, std::move(promise));
});
if (username.empty()) {
td_->contacts_manager_->reload_channel(channel_id, std::move(query_promise), "resolve_dialog");
} else {
send_resolve_dialog_username_query(username, std::move(query_promise));
}
return;
}
return on_resolve_dialog(username, channel_id, std::move(promise));
}
void DialogManager::on_resolve_dialog(const string &username, ChannelId channel_id, Promise<DialogId> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
DialogId dialog_id;
if (username.empty()) {
if (!td_->contacts_manager_->have_channel(channel_id)) {
return promise.set_error(Status::Error(500, "Chat info not found"));
}
dialog_id = DialogId(channel_id);
force_create_dialog(dialog_id, "on_resolve_dialog");
} else {
dialog_id = get_resolved_dialog_by_username(username);
if (dialog_id.is_valid()) {
force_create_dialog(dialog_id, "on_resolve_dialog", true);
}
}
if (!have_dialog_force(dialog_id, "on_resolve_dialog")) {
return promise.set_error(Status::Error(500, "Chat not found"));
}
promise.set_value(std::move(dialog_id));
}
DialogId DialogManager::get_resolved_dialog_by_username(const string &username) const {
auto cleaned_username = clean_username(username);
auto resolved_username = resolved_usernames_.get(cleaned_username);
if (resolved_username.dialog_id.is_valid()) {
return resolved_username.dialog_id;
}
return inaccessible_resolved_usernames_.get(cleaned_username);
}
DialogId DialogManager::resolve_dialog_username(const string &username, Promise<Unit> &promise) {
auto resolved_username = resolved_usernames_.get(username);
if (resolved_username.dialog_id.is_valid()) {
if (resolved_username.expires_at < Time::now()) {
send_resolve_dialog_username_query(username, Promise<Unit>());
}
return resolved_username.dialog_id;
} else {
auto dialog_id = inaccessible_resolved_usernames_.get(username);
if (!dialog_id.is_valid()) {
send_resolve_dialog_username_query(username, std::move(promise));
}
return dialog_id;
}
}
DialogId DialogManager::search_public_dialog(const string &username_to_search, bool force, Promise<Unit> &&promise) {
string username = clean_username(username_to_search);
if (username[0] == '@') {
username = username.substr(1);
}
if (username.empty()) {
promise.set_error(Status::Error(200, "Username is invalid"));
return DialogId();
}
DialogId dialog_id;
auto resolved_username = resolved_usernames_.get(username);
if (resolved_username.dialog_id.is_valid()) {
if (resolved_username.expires_at < Time::now()) {
send_resolve_dialog_username_query(username, Promise<Unit>());
}
dialog_id = resolved_username.dialog_id;
} else {
dialog_id = inaccessible_resolved_usernames_.get(username);
}
if (dialog_id.is_valid()) {
if (have_input_peer(dialog_id, AccessRights::Read)) {
if (!force && reload_voice_chat_on_search_usernames_.count(username)) {
reload_voice_chat_on_search_usernames_.erase(username);
if (dialog_id.get_type() == DialogType::Channel) {
td_->contacts_manager_->reload_channel_full(dialog_id.get_channel_id(), std::move(promise),
"search_public_dialog");
return DialogId();
}
}
td_->messages_manager_->create_dialog(dialog_id, false, std::move(promise));
return dialog_id;
} else {
// bot username may be known despite there is no access_hash
if (force || dialog_id.get_type() != DialogType::User) {
force_create_dialog(dialog_id, "search_public_dialog", true);
promise.set_value(Unit());
return dialog_id;
}
}
}
send_resolve_dialog_username_query(username, std::move(promise));
return DialogId();
}
void DialogManager::reload_voice_chat_on_search(const string &username) {
if (!td_->auth_manager_->is_authorized()) {
return;
}
auto cleaned_username = clean_username(username);
if (!cleaned_username.empty()) {
reload_voice_chat_on_search_usernames_.insert(cleaned_username);
}
}
void DialogManager::on_resolved_username(const string &username, DialogId dialog_id) {
if (!dialog_id.is_valid()) {
LOG(ERROR) << "Resolve username \"" << username << "\" to invalid " << dialog_id;
return;
}
auto cleaned_username = clean_username(username);
if (cleaned_username.empty()) {
return;
}
auto resolved_username = resolved_usernames_.get(cleaned_username);
if (resolved_username.dialog_id.is_valid()) {
LOG_IF(ERROR, resolved_username.dialog_id != dialog_id)
<< "Resolve username \"" << username << "\" to " << dialog_id << ", but have it in "
<< resolved_username.dialog_id;
return;
}
inaccessible_resolved_usernames_[cleaned_username] = dialog_id;
}
void DialogManager::drop_username(const string &username) {
auto cleaned_username = clean_username(username);
if (cleaned_username.empty()) {
return;
}
inaccessible_resolved_usernames_.erase(cleaned_username);
auto resolved_username = resolved_usernames_.get(cleaned_username);
if (resolved_username.dialog_id.is_valid()) {
auto dialog_id = resolved_username.dialog_id;
if (have_input_peer(dialog_id, AccessRights::Read)) {
CHECK(dialog_id.get_type() != DialogType::SecretChat);
reload_dialog_info_full(dialog_id, "drop_username");
}
resolved_usernames_.erase(cleaned_username);
}
}
} // namespace td

View File

@ -8,6 +8,7 @@
#include "td/telegram/AccentColorId.h"
#include "td/telegram/AccessRights.h"
#include "td/telegram/ChannelId.h"
#include "td/telegram/CustomEmojiId.h"
#include "td/telegram/DialogId.h"
#include "td/telegram/DialogParticipant.h"
@ -26,6 +27,7 @@
#include "td/utils/FlatHashMap.h"
#include "td/utils/Promise.h"
#include "td/utils/Status.h"
#include "td/utils/WaitFreeHashMap.h"
#include <memory>
#include <utility>
@ -34,10 +36,16 @@ namespace td {
class ReportReason;
class Td;
class Usernames;
class DialogManager final : public Actor {
public:
DialogManager(Td *td, ActorShared<> parent);
DialogManager(const DialogManager &) = delete;
DialogManager &operator=(const DialogManager &) = delete;
DialogManager(DialogManager &&) = delete;
DialogManager &operator=(DialogManager &&) = delete;
~DialogManager() final;
DialogId get_my_dialog_id() const;
@ -157,9 +165,29 @@ class DialogManager final : public Actor {
void upload_dialog_photo(DialogId dialog_id, FileId file_id, bool is_animation, double main_frame_timestamp,
bool is_reupload, Promise<Unit> &&promise, vector<int> bad_parts = {});
void on_dialog_usernames_updated(DialogId dialog_id, const Usernames &old_usernames, const Usernames &new_usernames);
void on_dialog_usernames_received(DialogId dialog_id, const Usernames &usernames, bool from_database);
void resolve_dialog(const string &username, ChannelId channel_id, Promise<DialogId> promise);
DialogId get_resolved_dialog_by_username(const string &username) const;
DialogId resolve_dialog_username(const string &username, Promise<Unit> &promise);
DialogId search_public_dialog(const string &username_to_search, bool force, Promise<Unit> &&promise);
void reload_voice_chat_on_search(const string &username);
void on_resolved_username(const string &username, DialogId dialog_id);
void drop_username(const string &username);
private:
static constexpr size_t MAX_TITLE_LENGTH = 128; // server side limit for chat title
static constexpr int32 USERNAME_CACHE_EXPIRE_TIME = 86400;
void tear_down() final;
void on_upload_dialog_photo(FileId file_id, telegram_api::object_ptr<telegram_api::InputFile> input_file);
@ -170,6 +198,10 @@ class DialogManager final : public Actor {
telegram_api::object_ptr<telegram_api::InputChatPhoto> &&input_chat_photo,
Promise<Unit> &&promise);
void send_resolve_dialog_username_query(const string &username, Promise<Unit> &&promise);
void on_resolve_dialog(const string &username, ChannelId channel_id, Promise<DialogId> &&promise);
class UploadDialogPhotoCallback;
std::shared_ptr<UploadDialogPhotoCallback> upload_dialog_photo_callback_;
@ -191,6 +223,18 @@ class DialogManager final : public Actor {
};
FlatHashMap<FileId, UploadedDialogPhotoInfo, FileIdHash> being_uploaded_dialog_photos_;
struct ResolvedUsername {
DialogId dialog_id;
double expires_at = 0.0;
ResolvedUsername() = default;
ResolvedUsername(DialogId dialog_id, double expires_at) : dialog_id(dialog_id), expires_at(expires_at) {
}
};
WaitFreeHashMap<string, ResolvedUsername> resolved_usernames_;
WaitFreeHashMap<string, DialogId> inaccessible_resolved_usernames_;
FlatHashSet<string> reload_voice_chat_on_search_usernames_;
Td *td_;
ActorShared<> parent_;
};

View File

@ -26,7 +26,6 @@
#include "td/telegram/MessageContent.h"
#include "td/telegram/MessageContentType.h"
#include "td/telegram/MessageEntity.h"
#include "td/telegram/MessagesManager.h"
#include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h"
#include "td/telegram/Photo.h"
@ -2116,8 +2115,8 @@ bool InlineQueriesManager::load_recently_used_bots(Promise<Unit> &promise) {
auto lock = resolve_recent_inline_bots_multipromise_.get_promise();
if (!G()->use_chat_info_database()) {
for (auto &bot_username : bot_usernames) {
td_->messages_manager_->search_public_dialog(bot_username, false,
resolve_recent_inline_bots_multipromise_.get_promise());
td_->dialog_manager_->search_public_dialog(bot_username, false,
resolve_recent_inline_bots_multipromise_.get_promise());
}
} else {
for (auto &bot_id : bot_ids) {

View File

@ -331,7 +331,7 @@ class LinkManager::InternalLinkBotStart final : public InternalLink {
autostart = true;
} else {
const Td *td = G()->td().get_actor_unsafe();
auto dialog_id = td->messages_manager_->resolve_dialog_username(bot_username_);
auto dialog_id = td->dialog_manager_->get_resolved_dialog_by_username(bot_username_);
if (dialog_id.is_valid() && dialog_id.get_type() == DialogType::User &&
td->messages_manager_->get_dialog_has_last_message(dialog_id) &&
!td->messages_manager_->is_dialog_blocked(dialog_id)) {
@ -1259,7 +1259,7 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_tg_link_query(Slice que
// resolve?domain=<username>&videochat
// resolve?domain=<username>&videochat=<invite_hash>
if (Scheduler::context() != nullptr) {
send_closure(G()->messages_manager(), &MessagesManager::reload_voice_chat_on_search, username);
send_closure(G()->dialog_manager(), &DialogManager::reload_voice_chat_on_search, username);
}
return td::make_unique<InternalLinkVoiceChat>(std::move(username), arg.second, arg.first == "livestream");
}
@ -1708,7 +1708,7 @@ unique_ptr<LinkManager::InternalLink> LinkManager::parse_t_me_link_query(Slice q
// /<username>?videochat
// /<username>?videochat=<invite_hash>
if (Scheduler::context() != nullptr) {
send_closure(G()->messages_manager(), &MessagesManager::reload_voice_chat_on_search, username);
send_closure(G()->dialog_manager(), &DialogManager::reload_voice_chat_on_search, username);
}
return td::make_unique<InternalLinkVoiceChat>(std::move(username), arg.second, arg.first == "livestream");
}

View File

@ -81,6 +81,7 @@
#include "td/telegram/TopDialogManager.h"
#include "td/telegram/TranslationManager.h"
#include "td/telegram/UpdatesManager.h"
#include "td/telegram/Usernames.h"
#include "td/telegram/Version.h"
#include "td/telegram/WebPageId.h"
@ -3904,43 +3905,6 @@ class GetChannelDifferenceQuery final : public Td::ResultHandler {
}
};
class ResolveUsernameQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
string username_;
public:
explicit ResolveUsernameQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) {
}
void send(const string &username) {
username_ = username;
send_query(G()->net_query_creator().create(telegram_api::contacts_resolveUsername(username)));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::contacts_resolveUsername>(packet);
if (result_ptr.is_error()) {
return on_error(result_ptr.move_as_error());
}
auto ptr = result_ptr.move_as_ok();
LOG(DEBUG) << "Receive result for ResolveUsernameQuery: " << to_string(ptr);
td_->contacts_manager_->on_get_users(std::move(ptr->users_), "ResolveUsernameQuery");
td_->contacts_manager_->on_get_chats(std::move(ptr->chats_), "ResolveUsernameQuery");
td_->messages_manager_->on_resolved_username(username_, DialogId(ptr->peer_));
promise_.set_value(Unit());
}
void on_error(Status status) final {
if (status.message() == Slice("USERNAME_NOT_OCCUPIED")) {
td_->messages_manager_->drop_username(username_);
}
promise_.set_error(std::move(status));
}
};
class MessagesManager::UploadMediaCallback final : public FileManager::UploadCallback {
public:
void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
@ -5248,10 +5212,9 @@ MessagesManager::~MessagesManager() {
message_embedding_codes_[1], message_to_replied_media_timestamp_messages_,
story_to_replied_media_timestamp_messages_, notification_group_id_to_dialog_id_, pending_get_channel_differences_,
active_get_channel_differences_, get_channel_difference_to_log_event_id_, channel_get_difference_retry_timeouts_,
is_channel_difference_finished_, expected_channel_pts_, expected_channel_max_message_id_, resolved_usernames_,
inaccessible_resolved_usernames_, dialog_bot_command_message_ids_, message_full_id_to_file_source_id_,
last_outgoing_forwarded_message_date_, dialog_viewed_messages_, previous_repaired_read_inbox_max_message_id_,
failed_to_load_dialogs_);
is_channel_difference_finished_, expected_channel_pts_, expected_channel_max_message_id_,
dialog_bot_command_message_ids_, message_full_id_to_file_source_id_, last_outgoing_forwarded_message_date_,
dialog_viewed_messages_, previous_repaired_read_inbox_max_message_id_, failed_to_load_dialogs_);
}
MessagesManager::AddDialogData::AddDialogData(int32 dependent_dialog_count, unique_ptr<Message> &&last_message,
@ -12669,7 +12632,7 @@ void MessagesManager::on_get_secret_message(SecretChatId secret_chat_id, UserId
send_closure(actor_id, &MessagesManager::on_resolve_secret_chat_message_via_bot_username, via_bot_username,
message_info_ptr, std::move(promise));
});
search_public_dialog(message->via_bot_name_, false, std::move(request_promise));
td_->dialog_manager_->search_public_dialog(message->via_bot_name_, false, std::move(request_promise));
}
message_info.content = get_secret_message_content(
@ -12684,7 +12647,7 @@ void MessagesManager::on_resolve_secret_chat_message_via_bot_username(const stri
MessageInfo *message_info_ptr,
Promise<Unit> &&promise) {
if (!G()->close_flag()) {
auto dialog_id = resolve_dialog_username(via_bot_username);
auto dialog_id = td_->dialog_manager_->get_resolved_dialog_by_username(via_bot_username);
if (dialog_id.is_valid() && dialog_id.get_type() == DialogType::User) {
auto user_id = dialog_id.get_user_id();
auto r_bot_data = td_->contacts_manager_->get_bot_data(user_id);
@ -15839,18 +15802,12 @@ vector<DialogId> MessagesManager::search_public_dialogs(const string &query, Pro
for (auto &short_username : get_valid_short_usernames()) {
if (2 * username.size() > short_username.size() && begins_with(short_username, username)) {
username = short_username.str();
auto resolved_username = resolved_usernames_.get(username);
if (!resolved_username.dialog_id.is_valid()) {
send_resolve_dialog_username_query(username, std::move(promise));
auto dialog_id = td_->dialog_manager_->resolve_dialog_username(username, promise);
if (!dialog_id.is_valid()) {
return {};
}
if (resolved_username.expires_at < Time::now()) {
send_resolve_dialog_username_query(username, Promise<Unit>());
}
auto dialog_id = resolved_username.dialog_id;
force_create_dialog(dialog_id, "public dialogs search");
force_create_dialog(dialog_id, "search_public_dialogs");
auto d = get_dialog(dialog_id);
if (d == nullptr || d->order != DEFAULT_ORDER ||
@ -17155,7 +17112,7 @@ void MessagesManager::get_message_link_info(Slice url, Promise<MessageLinkInfo>
send_closure(actor_id, &MessagesManager::on_get_message_link_dialog, std::move(info), result.ok(),
std::move(promise));
});
resolve_dialog(info.username, info.channel_id, std::move(query_promise));
td_->dialog_manager_->resolve_dialog(info.username, info.channel_id, std::move(query_promise));
}
void MessagesManager::on_get_message_link_dialog(MessageLinkInfo &&info, DialogId dialog_id,
@ -17233,7 +17190,8 @@ td_api::object_ptr<td_api::messageLinkInfo> MessagesManager::get_message_link_in
bool is_public = !info.username.empty();
DialogId dialog_id = info.comment_dialog_id.is_valid()
? info.comment_dialog_id
: (is_public ? resolve_dialog_username(info.username) : DialogId(info.channel_id));
: (is_public ? td_->dialog_manager_->get_resolved_dialog_by_username(info.username)
: DialogId(info.channel_id));
MessageId top_thread_message_id;
MessageId message_id = info.comment_dialog_id.is_valid() ? info.comment_message_id : info.message_id;
td_api::object_ptr<td_api::message> message;
@ -30820,137 +30778,6 @@ void MessagesManager::on_dialog_linked_channel_updated(DialogId dialog_id, Chann
}
}
void MessagesManager::send_resolve_dialog_username_query(const string &username, Promise<Unit> &&promise) {
td_->create_handler<ResolveUsernameQuery>(std::move(promise))->send(username);
}
void MessagesManager::resolve_dialog(const string &username, ChannelId channel_id, Promise<DialogId> promise) {
CHECK(username.empty() == channel_id.is_valid());
bool have_dialog = username.empty() ? td_->contacts_manager_->have_channel_force(channel_id, "resolve_dialog")
: resolve_dialog_username(username).is_valid();
if (!have_dialog) {
auto query_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), username, channel_id, promise = std::move(promise)](Result<Unit> &&result) mutable {
if (result.is_error()) {
return promise.set_error(result.move_as_error());
}
send_closure(actor_id, &MessagesManager::on_resolve_dialog, username, channel_id, std::move(promise));
});
if (username.empty()) {
td_->contacts_manager_->reload_channel(channel_id, std::move(query_promise), "resolve_dialog");
} else {
send_resolve_dialog_username_query(username, std::move(query_promise));
}
return;
}
return on_resolve_dialog(username, channel_id, std::move(promise));
}
void MessagesManager::on_resolve_dialog(const string &username, ChannelId channel_id, Promise<DialogId> &&promise) {
TRY_STATUS_PROMISE(promise, G()->close_status());
DialogId dialog_id;
if (username.empty()) {
if (!td_->contacts_manager_->have_channel(channel_id)) {
return promise.set_error(Status::Error(500, "Chat info not found"));
}
dialog_id = DialogId(channel_id);
force_create_dialog(dialog_id, "on_resolve_dialog");
} else {
dialog_id = resolve_dialog_username(username);
if (dialog_id.is_valid()) {
force_create_dialog(dialog_id, "on_resolve_dialog", true);
}
}
Dialog *d = get_dialog_force(dialog_id, "on_get_message_link_dialog");
if (d == nullptr) {
return promise.set_error(Status::Error(500, "Chat not found"));
}
promise.set_value(std::move(dialog_id));
}
DialogId MessagesManager::resolve_dialog_username(const string &username) const {
auto cleaned_username = clean_username(username);
auto resolved_username = resolved_usernames_.get(cleaned_username);
if (resolved_username.dialog_id.is_valid()) {
return resolved_username.dialog_id;
}
return inaccessible_resolved_usernames_.get(cleaned_username);
}
DialogId MessagesManager::search_public_dialog(const string &username_to_search, bool force, Promise<Unit> &&promise) {
string username = clean_username(username_to_search);
if (username[0] == '@') {
username = username.substr(1);
}
if (username.empty()) {
promise.set_error(Status::Error(200, "Username is invalid"));
return DialogId();
}
DialogId dialog_id;
auto resolved_username = resolved_usernames_.get(username);
if (resolved_username.dialog_id.is_valid()) {
if (resolved_username.expires_at < Time::now()) {
send_resolve_dialog_username_query(username, Promise<Unit>());
}
dialog_id = resolved_username.dialog_id;
} else {
dialog_id = inaccessible_resolved_usernames_.get(username);
}
if (dialog_id.is_valid()) {
if (td_->dialog_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
if (!force && reload_voice_chat_on_search_usernames_.count(username)) {
reload_voice_chat_on_search_usernames_.erase(username);
if (dialog_id.get_type() == DialogType::Channel) {
td_->contacts_manager_->reload_channel_full(dialog_id.get_channel_id(), std::move(promise),
"search_public_dialog");
return DialogId();
}
}
if (td_->auth_manager_->is_bot()) {
force_create_dialog(dialog_id, "search_public_dialog", true);
} else {
const Dialog *d = get_dialog_force(dialog_id, "search_public_dialog");
if (!is_dialog_inited(d)) {
send_get_dialog_query(dialog_id, std::move(promise), 0, "search_public_dialog");
return DialogId();
}
}
promise.set_value(Unit());
return dialog_id;
} else {
// bot username maybe known despite there is no access_hash
if (force || dialog_id.get_type() != DialogType::User) {
force_create_dialog(dialog_id, "search_public_dialog", true);
promise.set_value(Unit());
return dialog_id;
}
}
}
send_resolve_dialog_username_query(username, std::move(promise));
return DialogId();
}
void MessagesManager::reload_voice_chat_on_search(const string &username) {
if (!td_->auth_manager_->is_authorized()) {
return;
}
auto cleaned_username = clean_username(username);
if (!cleaned_username.empty()) {
reload_voice_chat_on_search_usernames_.insert(cleaned_username);
}
}
class MessagesManager::RegetDialogLogEvent {
public:
DialogId dialog_id_;
@ -31044,77 +30871,18 @@ void MessagesManager::on_get_dialog_query_finished(DialogId dialog_id, Status &&
void MessagesManager::on_dialog_usernames_updated(DialogId dialog_id, const Usernames &old_usernames,
const Usernames &new_usernames) {
CHECK(dialog_id.is_valid());
if (td_->auth_manager_->is_bot()) {
return;
}
LOG(INFO) << "Update usernames in " << dialog_id << " from " << old_usernames << " to " << new_usernames;
message_embedding_codes_[0].erase(dialog_id);
message_embedding_codes_[1].erase(dialog_id);
for (auto &username : old_usernames.get_active_usernames()) {
auto cleaned_username = clean_username(username);
resolved_usernames_.erase(cleaned_username);
inaccessible_resolved_usernames_.erase(cleaned_username);
}
on_dialog_usernames_received(dialog_id, new_usernames, false);
}
void MessagesManager::on_dialog_usernames_received(DialogId dialog_id, const Usernames &usernames, bool from_database) {
if (!td_->auth_manager_->is_bot()) {
const auto *d = get_dialog(dialog_id);
if (d != nullptr) {
update_dialogs_hints(d);
}
}
for (auto &username : usernames.get_active_usernames()) {
auto cleaned_username = clean_username(username);
if (!cleaned_username.empty()) {
resolved_usernames_[cleaned_username] =
ResolvedUsername{dialog_id, Time::now() + (from_database ? 0 : USERNAME_CACHE_EXPIRE_TIME)};
}
}
}
void MessagesManager::on_resolved_username(const string &username, DialogId dialog_id) {
if (!dialog_id.is_valid()) {
LOG(ERROR) << "Resolve username \"" << username << "\" to invalid " << dialog_id;
return;
}
auto cleaned_username = clean_username(username);
if (cleaned_username.empty()) {
return;
}
auto resolved_username = resolved_usernames_.get(cleaned_username);
if (resolved_username.dialog_id.is_valid()) {
LOG_IF(ERROR, resolved_username.dialog_id != dialog_id)
<< "Resolve username \"" << username << "\" to " << dialog_id << ", but have it in "
<< resolved_username.dialog_id;
return;
}
inaccessible_resolved_usernames_[cleaned_username] = dialog_id;
}
void MessagesManager::drop_username(const string &username) {
auto cleaned_username = clean_username(username);
if (cleaned_username.empty()) {
return;
}
inaccessible_resolved_usernames_.erase(cleaned_username);
auto resolved_username = resolved_usernames_.get(cleaned_username);
if (resolved_username.dialog_id.is_valid()) {
auto dialog_id = resolved_username.dialog_id;
if (td_->dialog_manager_->have_input_peer(dialog_id, AccessRights::Read)) {
CHECK(dialog_id.get_type() != DialogType::SecretChat);
send_get_dialog_query(dialog_id, Auto(), 0, "drop_username");
}
resolved_usernames_.erase(cleaned_username);
const auto *d = get_dialog(dialog_id);
if (d != nullptr) {
update_dialogs_hints(d);
}
}

View File

@ -67,7 +67,6 @@
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/telegram/UserId.h"
#include "td/telegram/Usernames.h"
#include "td/actor/actor.h"
#include "td/actor/MultiPromise.h"
@ -111,6 +110,7 @@ struct InputMessageContent;
class MessageContent;
struct MessageReactions;
class Td;
class Usernames;
class MessagesManager final : public Actor {
public:
@ -383,14 +383,6 @@ class MessagesManager final : public Actor {
std::pair<int32, vector<DialogId>> get_recently_opened_dialogs(int32 limit, Promise<Unit> &&promise);
void resolve_dialog(const string &username, ChannelId channel_id, Promise<DialogId> promise);
DialogId resolve_dialog_username(const string &username) const;
DialogId search_public_dialog(const string &username_to_search, bool force, Promise<Unit> &&promise);
void reload_voice_chat_on_search(const string &username);
void get_dialog_send_message_as_dialog_ids(DialogId dialog_id,
Promise<td_api::object_ptr<td_api::chatMessageSenders>> &&promise,
bool is_recursive = false);
@ -809,7 +801,6 @@ class MessagesManager final : public Actor {
void on_dialog_title_updated(DialogId dialog_id);
void on_dialog_emoji_status_updated(DialogId dialog_id);
void on_dialog_usernames_updated(DialogId dialog_id, const Usernames &old_usernames, const Usernames &new_usernames);
void on_dialog_usernames_received(DialogId dialog_id, const Usernames &usernames, bool from_database);
void on_dialog_default_permissions_updated(DialogId dialog_id);
void on_dialog_has_protected_content_updated(DialogId dialog_id);
@ -821,9 +812,6 @@ class MessagesManager final : public Actor {
void drop_dialog_pending_join_requests(DialogId dialog_id);
void on_resolved_username(const string &username, DialogId dialog_id);
void drop_username(const string &username);
void on_update_notification_scope_is_muted(NotificationSettingsScope scope, bool is_muted);
void on_update_dialog_notify_settings(DialogId dialog_id,
@ -1628,7 +1616,6 @@ class MessagesManager final : public Actor {
static constexpr int32 LIVE_LOCATION_VIEW_PERIOD = 60; // seconds, server-side limit
static constexpr int32 UPDATE_VIEWED_MESSAGES_PERIOD = 15; // seconds
static constexpr int32 USERNAME_CACHE_EXPIRE_TIME = 86400;
static constexpr int32 AUTH_NOTIFICATION_ID_CACHE_TIME = 7 * 86400;
static constexpr size_t MAX_SAVED_AUTH_NOTIFICATION_IDS = 100;
@ -1895,10 +1882,6 @@ class MessagesManager final : public Actor {
bool is_message_unload_enabled() const;
void send_resolve_dialog_username_query(const string &username, Promise<Unit> &&promise);
void on_resolve_dialog(const string &username, ChannelId channel_id, Promise<DialogId> &&promise);
int64 generate_new_media_album_id();
static bool can_forward_message(DialogId from_dialog_id, const Message *m);
@ -3321,19 +3304,6 @@ class MessagesManager final : public Actor {
FlatHashMap<DialogId, vector<Promise<Unit>>, DialogIdHash> load_scheduled_messages_from_database_queries_;
struct ResolvedUsername {
DialogId dialog_id;
double expires_at = 0.0;
ResolvedUsername() = default;
ResolvedUsername(DialogId dialog_id, double expires_at) : dialog_id(dialog_id), expires_at(expires_at) {
}
};
WaitFreeHashMap<string, ResolvedUsername> resolved_usernames_;
WaitFreeHashMap<string, DialogId> inaccessible_resolved_usernames_;
FlatHashSet<string> reload_voice_chat_on_search_usernames_;
struct GetDialogsTask {
DialogListId dialog_list_id;
int32 limit;

View File

@ -99,7 +99,7 @@ void RecentDialogList::load_dialogs(Promise<Unit> &&promise) {
vector<DialogId> dialog_ids;
for (auto &found_dialog : found_dialogs) {
if (found_dialog[0] == '@') {
td_->messages_manager_->search_public_dialog(found_dialog, false, mpas.get_promise());
td_->dialog_manager_->search_public_dialog(found_dialog, false, mpas.get_promise());
} else {
dialog_ids.push_back(DialogId(to_integer<int64>(found_dialog)));
}
@ -137,7 +137,7 @@ void RecentDialogList::on_load_dialogs(vector<string> &&found_dialogs) {
for (auto it = found_dialogs.rbegin(); it != found_dialogs.rend(); ++it) {
DialogId dialog_id;
if ((*it)[0] == '@') {
dialog_id = td_->messages_manager_->resolve_dialog_username(it->substr(1));
dialog_id = td_->dialog_manager_->get_resolved_dialog_by_username(it->substr(1));
} else {
dialog_id = DialogId(to_integer<int64>(*it));
}

View File

@ -791,7 +791,7 @@ class SearchPublicChatRequest final : public RequestActor<> {
DialogId dialog_id_;
void do_run(Promise<Unit> &&promise) final {
dialog_id_ = td_->messages_manager_->search_public_dialog(username_, get_tries() < 3, std::move(promise));
dialog_id_ = td_->dialog_manager_->search_public_dialog(username_, get_tries() < 3, std::move(promise));
}
void do_send_result() final {