diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index 166002c17..f65c9eff8 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -6876,6 +6876,11 @@ searchChatsNearby location:location = ChatsNearby; //@description Returns a list of chats similar to the given chat @chat_id Identifier of the target chat; must be an identifier of a channel chat getSimilarChats chat_id:int53 = Chats; +//@description Returns approximate number of chats similar to the given chat +//@chat_id Identifier of the target chat; must be an identifier of a channel chat +//@return_local Pass true to get the number of chats without sending network requests, or -1 if the number of chats is unknown locally +getSimilarChatCount chat_id:int53 return_local:Bool = Count; + //@description Returns a list of frequently used chats @category Category of chats to be returned @limit The maximum number of chats to be returned; up to 30 getTopChats category:TopChatCategory limit:int32 = Chats; diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index 9508cdb90..4ec6cf8e5 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -9739,29 +9739,54 @@ bool ContactsManager::are_suitable_recommended_dialogs(const RecommendedDialogs return true; } -void ContactsManager::get_channel_recommendations(DialogId dialog_id, - Promise> &&promise) { +void ContactsManager::get_channel_recommendations(DialogId dialog_id, bool return_local, + Promise> &&chats_promise, + Promise> &&count_promise) { if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_channel_recommendations")) { - return promise.set_error(Status::Error(400, "Chat not found")); + if (chats_promise) { + chats_promise.set_error(Status::Error(400, "Chat not found")); + } + if (count_promise) { + count_promise.set_error(Status::Error(400, "Chat not found")); + } + return; } if (dialog_id.get_type() != DialogType::Channel) { - return promise.set_value(td_api::make_object()); + if (chats_promise) { + chats_promise.set_value(td_api::make_object()); + } + if (count_promise) { + count_promise.set_value(td_api::make_object(0)); + } + return; } auto channel_id = dialog_id.get_channel_id(); if (!is_broadcast_channel(channel_id) || get_input_channel(channel_id) == nullptr) { - return promise.set_value(td_api::make_object()); + if (chats_promise) { + chats_promise.set_value(td_api::make_object()); + } + if (count_promise) { + count_promise.set_value(td_api::make_object(0)); + } + return; } bool use_database = true; auto it = channel_recommended_dialogs_.find(channel_id); if (it != channel_recommended_dialogs_.end()) { if (are_suitable_recommended_dialogs(it->second)) { auto next_reload_time = it->second.next_reload_time_; - promise.set_value(td_->messages_manager_->get_chats_object(it->second.total_count_, it->second.dialog_ids_, - "get_channel_recommendations")); + if (chats_promise) { + chats_promise.set_value(td_->messages_manager_->get_chats_object( + it->second.total_count_, it->second.dialog_ids_, "get_channel_recommendations")); + } + if (count_promise) { + count_promise.set_value(td_api::make_object(it->second.total_count_)); + } if (next_reload_time > Time::now()) { return; } - promise = {}; + chats_promise = {}; + count_promise = {}; } else { LOG(INFO) << "Drop cache for similar chats of " << dialog_id; channel_recommended_dialogs_.erase(it); @@ -9769,17 +9794,22 @@ void ContactsManager::get_channel_recommendations(DialogId dialog_id, } use_database = false; } - load_channel_recommendations(channel_id, use_database, std::move(promise)); + load_channel_recommendations(channel_id, use_database, return_local, std::move(chats_promise), + std::move(count_promise)); } string ContactsManager::get_channel_recommendations_database_key(ChannelId channel_id) { return PSTRING() << "channel_recommendations" << channel_id.get(); } -void ContactsManager::load_channel_recommendations(ChannelId channel_id, bool use_database, - Promise> &&promise) { +void ContactsManager::load_channel_recommendations(ChannelId channel_id, bool use_database, bool return_local, + Promise> &&chats_promise, + Promise> &&count_promise) { + if (count_promise) { + get_channel_recommendation_count_queries_[return_local][channel_id].push_back(std::move(count_promise)); + } auto &queries = get_channel_recommendations_queries_[channel_id]; - queries.push_back(std::move(promise)); + queries.push_back(std::move(chats_promise)); if (queries.size() == 1) { if (G()->use_message_database() && use_database) { G()->td_db()->get_sqlite_pmc()->get( @@ -9795,6 +9825,15 @@ void ContactsManager::load_channel_recommendations(ChannelId channel_id, bool us } void ContactsManager::fail_load_channel_recommendations_queries(ChannelId channel_id, Status &&error) { + for (int return_local = 0; return_local < 2; return_local++) { + auto it = get_channel_recommendation_count_queries_[return_local].find(channel_id); + if (it != get_channel_recommendation_count_queries_[return_local].end()) { + auto promises = std::move(it->second); + CHECK(!promises.empty()); + get_channel_recommendation_count_queries_[return_local].erase(it); + fail_promises(promises, error.clone()); + } + } auto it = get_channel_recommendations_queries_.find(channel_id); CHECK(it != get_channel_recommendations_queries_.end()); auto promises = std::move(it->second); @@ -9805,6 +9844,17 @@ void ContactsManager::fail_load_channel_recommendations_queries(ChannelId channe void ContactsManager::finish_load_channel_recommendations_queries(ChannelId channel_id, int32 total_count, vector dialog_ids) { + for (int return_local = 0; return_local < 2; return_local++) { + auto it = get_channel_recommendation_count_queries_[return_local].find(channel_id); + if (it != get_channel_recommendation_count_queries_[return_local].end()) { + auto promises = std::move(it->second); + CHECK(!promises.empty()); + get_channel_recommendation_count_queries_[return_local].erase(it); + for (auto &promise : promises) { + promise.set_value(td_api::make_object(total_count)); + } + } + } auto it = get_channel_recommendations_queries_.find(channel_id); CHECK(it != get_channel_recommendations_queries_.end()); auto promises = std::move(it->second); @@ -9839,11 +9889,20 @@ void ContactsManager::on_load_channel_recommendations_from_database(ChannelId ch recommended_dialogs.dialog_ids_); if (next_reload_time <= Time::now()) { - load_channel_recommendations(channel_id, false, Auto()); + load_channel_recommendations(channel_id, false, false, Auto(), Auto()); } } void ContactsManager::reload_channel_recommendations(ChannelId channel_id) { + auto it = get_channel_recommendation_count_queries_[1].find(channel_id); + if (it != get_channel_recommendation_count_queries_[1].end()) { + auto promises = std::move(it->second); + CHECK(!promises.empty()); + get_channel_recommendation_count_queries_[1].erase(it); + for (auto &promise : promises) { + promise.set_value(td_api::make_object(-1)); + } + } auto query_promise = PromiseCreator::lambda([actor_id = actor_id(this), channel_id]( Result>>> &&result) { diff --git a/td/telegram/ContactsManager.h b/td/telegram/ContactsManager.h index d26acac4e..f9c4d22e2 100644 --- a/td/telegram/ContactsManager.h +++ b/td/telegram/ContactsManager.h @@ -566,7 +566,9 @@ class ContactsManager final : public Actor { ChannelId migrate_chat_to_megagroup(ChatId chat_id, Promise &promise); - void get_channel_recommendations(DialogId dialog_id, Promise> &&promise); + void get_channel_recommendations(DialogId dialog_id, bool return_local, + Promise> &&chats_promise, + Promise> &&count_promise); void get_created_public_dialogs(PublicDialogType type, Promise> &&promise, bool from_binlog); @@ -1745,8 +1747,9 @@ class ContactsManager final : public Actor { static string get_channel_recommendations_database_key(ChannelId channel_id); - void load_channel_recommendations(ChannelId channel_id, bool use_database, - Promise> &&promise); + void load_channel_recommendations(ChannelId channel_id, bool use_database, bool return_local, + Promise> &&chats_promise, + Promise> &&count_promise); void fail_load_channel_recommendations_queries(ChannelId channel_id, Status &&error); @@ -2043,6 +2046,8 @@ class ContactsManager final : public Actor { FlatHashMap channel_recommended_dialogs_; FlatHashMap>>, ChannelIdHash> get_channel_recommendations_queries_; + FlatHashMap>>, ChannelIdHash> + get_channel_recommendation_count_queries_[2]; bool created_public_channels_inited_[2] = {false, false}; vector created_public_channels_[2]; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index c6b4ec4c4..a06154e7b 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -5101,7 +5101,14 @@ void Td::on_request(uint64 id, const td_api::clearAutosaveSettingsExceptions &re void Td::on_request(uint64 id, const td_api::getSimilarChats &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - contacts_manager_->get_channel_recommendations(DialogId(request.chat_id_), std::move(promise)); + contacts_manager_->get_channel_recommendations(DialogId(request.chat_id_), false, std::move(promise), Auto()); +} + +void Td::on_request(uint64 id, const td_api::getSimilarChatCount &request) { + CHECK_IS_USER(); + CREATE_REQUEST_PROMISE(); + contacts_manager_->get_channel_recommendations(DialogId(request.chat_id_), request.return_local_, Auto(), + std::move(promise)); } void Td::on_request(uint64 id, const td_api::getTopChats &request) { diff --git a/td/telegram/Td.h b/td/telegram/Td.h index e39200476..0193c8658 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -639,6 +639,8 @@ class Td final : public Actor { void on_request(uint64 id, const td_api::getSimilarChats &request); + void on_request(uint64 id, const td_api::getSimilarChatCount &request); + void on_request(uint64 id, const td_api::getTopChats &request); void on_request(uint64 id, const td_api::removeTopChat &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 9adf710fb..0528a1a4d 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -5159,6 +5159,11 @@ class CliClient final : public Actor { ChatId chat_id; get_args(args, chat_id); send_request(td_api::make_object(chat_id)); + } else if (op == "gscc") { + ChatId chat_id; + bool return_local; + get_args(args, chat_id, return_local); + send_request(td_api::make_object(chat_id, return_local)); } else if (op == "gcpc") { send_request(td_api::make_object()); } else if (op == "gcpcl") {