diff options
| author | levlam <levlam@telegram.org> | 2024-01-04 19:30:58 +0300 |
|---|---|---|
| committer | levlam <levlam@telegram.org> | 2024-01-04 19:30:58 +0300 |
| commit | 249598a711feb7c1c9ad87cee306f754afb8f3e7 (patch) | |
| tree | a60b6b44559f7cffd71018982d8aa47feed504f8 /td/telegram/CommonDialogManager.cpp | |
| parent | 8d7058109cef2ab62eb9c5979dd2ebd159306488 (diff) | |
Move get_common_dialogs to CommonDialogManager.
Diffstat (limited to 'td/telegram/CommonDialogManager.cpp')
| -rw-r--r-- | td/telegram/CommonDialogManager.cpp | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/td/telegram/CommonDialogManager.cpp b/td/telegram/CommonDialogManager.cpp index 8c782de54..2892f5d13 100644 --- a/td/telegram/CommonDialogManager.cpp +++ b/td/telegram/CommonDialogManager.cpp @@ -6,13 +6,215 @@ // #include "td/telegram/CommonDialogManager.h" +#include "td/telegram/ContactsManager.h" +#include "td/telegram/DialogManager.h" +#include "td/telegram/Global.h" +#include "td/telegram/Td.h" + +#include "td/utils/algorithm.h" +#include "td/utils/buffer.h" +#include "td/utils/logging.h" + +#include <algorithm> + namespace td { +class GetCommonDialogsQuery final : public Td::ResultHandler { + Promise<Unit> promise_; + UserId user_id_; + int64 offset_chat_id_ = 0; + + public: + explicit GetCommonDialogsQuery(Promise<Unit> &&promise) : promise_(std::move(promise)) { + } + + void send(UserId user_id, tl_object_ptr<telegram_api::InputUser> &&input_user, int64 offset_chat_id, int32 limit) { + user_id_ = user_id; + offset_chat_id_ = offset_chat_id; + + send_query(G()->net_query_creator().create( + telegram_api::messages_getCommonChats(std::move(input_user), offset_chat_id, limit))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result<telegram_api::messages_getCommonChats>(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto chats_ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for GetCommonDialogsQuery: " << to_string(chats_ptr); + switch (chats_ptr->get_id()) { + case telegram_api::messages_chats::ID: { + auto chats = move_tl_object_as<telegram_api::messages_chats>(chats_ptr); + td_->common_dialog_manager_->on_get_common_dialogs(user_id_, offset_chat_id_, std::move(chats->chats_), + narrow_cast<int32>(chats->chats_.size())); + break; + } + case telegram_api::messages_chatsSlice::ID: { + auto chats = move_tl_object_as<telegram_api::messages_chatsSlice>(chats_ptr); + td_->common_dialog_manager_->on_get_common_dialogs(user_id_, offset_chat_id_, std::move(chats->chats_), + chats->count_); + break; + } + default: + UNREACHABLE(); + } + + promise_.set_value(Unit()); + } + + void on_error(Status status) final { + promise_.set_error(std::move(status)); + } +}; + CommonDialogManager::CommonDialogManager(Td *td, ActorShared<> parent) : td_(td), parent_(std::move(parent)) { } +CommonDialogManager::~CommonDialogManager() { + Scheduler::instance()->destroy_on_scheduler(G()->get_gc_scheduler_id(), found_common_dialogs_); +} + void CommonDialogManager::tear_down() { parent_.reset(); } +void CommonDialogManager::drop_common_dialogs_cache(UserId user_id) { + auto it = found_common_dialogs_.find(user_id); + if (it != found_common_dialogs_.end()) { + it->second.is_outdated = true; + } +} + +std::pair<int32, vector<DialogId>> CommonDialogManager::get_common_dialogs(UserId user_id, DialogId offset_dialog_id, + int32 limit, bool force, + Promise<Unit> &&promise) { + auto r_input_user = td_->contacts_manager_->get_input_user(user_id); + if (r_input_user.is_error()) { + promise.set_error(r_input_user.move_as_error()); + return {}; + } + + if (user_id == td_->contacts_manager_->get_my_id()) { + promise.set_error(Status::Error(400, "Can't get common chats with self")); + return {}; + } + if (limit <= 0) { + promise.set_error(Status::Error(400, "Parameter limit must be positive")); + return {}; + } + if (limit > MAX_GET_DIALOGS) { + limit = MAX_GET_DIALOGS; + } + + int64 offset_chat_id = 0; + switch (offset_dialog_id.get_type()) { + case DialogType::Chat: + offset_chat_id = offset_dialog_id.get_chat_id().get(); + break; + case DialogType::Channel: + offset_chat_id = offset_dialog_id.get_channel_id().get(); + break; + case DialogType::None: + if (offset_dialog_id == DialogId()) { + break; + } + // fallthrough + case DialogType::User: + case DialogType::SecretChat: + promise.set_error(Status::Error(400, "Wrong offset_chat_id")); + return {}; + default: + UNREACHABLE(); + break; + } + + auto it = found_common_dialogs_.find(user_id); + if (it != found_common_dialogs_.end() && !it->second.dialog_ids.empty()) { + int32 total_count = it->second.total_count; + vector<DialogId> &common_dialog_ids = it->second.dialog_ids; + bool use_cache = (!it->second.is_outdated && it->second.receive_time >= Time::now() - 3600) || force || + offset_chat_id != 0 || common_dialog_ids.size() >= static_cast<size_t>(MAX_GET_DIALOGS); + // use cache if it is up-to-date, or we required to use it or we can't update it + if (use_cache) { + auto offset_it = common_dialog_ids.begin(); + if (offset_dialog_id != DialogId()) { + offset_it = std::find(common_dialog_ids.begin(), common_dialog_ids.end(), offset_dialog_id); + if (offset_it == common_dialog_ids.end()) { + promise.set_error(Status::Error(400, "Wrong offset_chat_id")); + return {}; + } + ++offset_it; + } + vector<DialogId> result; + while (result.size() < static_cast<size_t>(limit)) { + if (offset_it == common_dialog_ids.end()) { + break; + } + auto dialog_id = *offset_it++; + if (dialog_id == DialogId()) { // end of the list + promise.set_value(Unit()); + return {total_count, std::move(result)}; + } + result.push_back(dialog_id); + } + if (result.size() == static_cast<size_t>(limit) || force) { + promise.set_value(Unit()); + return {total_count, std::move(result)}; + } + } + } + + td_->create_handler<GetCommonDialogsQuery>(std::move(promise)) + ->send(user_id, r_input_user.move_as_ok(), offset_chat_id, MAX_GET_DIALOGS); + return {}; +} + +void CommonDialogManager::on_get_common_dialogs(UserId user_id, int64 offset_chat_id, + vector<tl_object_ptr<telegram_api::Chat>> &&chats, int32 total_count) { + CHECK(user_id.is_valid()); + td_->contacts_manager_->on_update_user_common_chat_count(user_id, total_count); + + auto &common_dialogs = found_common_dialogs_[user_id]; + if (common_dialogs.is_outdated && offset_chat_id == 0 && + common_dialogs.dialog_ids.size() < static_cast<size_t>(MAX_GET_DIALOGS)) { + // drop outdated cache if possible + common_dialogs = CommonDialogs(); + } + if (common_dialogs.receive_time == 0) { + common_dialogs.receive_time = Time::now(); + } + common_dialogs.is_outdated = false; + auto &result = common_dialogs.dialog_ids; + if (!result.empty() && result.back() == DialogId()) { + return; + } + bool is_last = chats.empty() && offset_chat_id == 0; + for (auto &chat : chats) { + auto dialog_id = ContactsManager::get_dialog_id(chat); + if (!dialog_id.is_valid()) { + LOG(ERROR) << "Receive invalid " << to_string(chat); + continue; + } + td_->contacts_manager_->on_get_chat(std::move(chat), "on_get_common_dialogs"); + + if (!td::contains(result, dialog_id)) { + td_->dialog_manager_->force_create_dialog(dialog_id, "get common dialogs"); + result.push_back(dialog_id); + } + } + if (result.size() >= static_cast<size_t>(total_count) || is_last) { + if (result.size() != static_cast<size_t>(total_count)) { + LOG(ERROR) << "Fix total count of common groups with " << user_id << " from " << total_count << " to " + << result.size(); + total_count = narrow_cast<int32>(result.size()); + td_->contacts_manager_->on_update_user_common_chat_count(user_id, total_count); + } + + result.emplace_back(); + } + common_dialogs.total_count = total_count; +} + } // namespace td |
