Add td_api::getSimilarChats.

This commit is contained in:
levlam 2023-11-20 22:03:21 +03:00
parent c1352603d5
commit b6bb02baad
6 changed files with 168 additions and 0 deletions

View File

@ -6832,6 +6832,9 @@ searchChatsOnServer query:string limit:int32 = Chats;
//@location Current user location
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 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;

View File

@ -3277,6 +3277,54 @@ class MigrateChatQuery final : public Td::ResultHandler {
}
};
class GetChannelRecommendationsQuery final : public Td::ResultHandler {
Promise<vector<tl_object_ptr<telegram_api::Chat>>> promise_;
ChannelId channel_id_;
public:
explicit GetChannelRecommendationsQuery(Promise<vector<tl_object_ptr<telegram_api::Chat>>> &&promise)
: promise_(std::move(promise)) {
}
void send(ChannelId channel_id) {
channel_id_ = channel_id;
auto input_channel = td_->contacts_manager_->get_input_channel(channel_id);
CHECK(input_channel != nullptr);
send_query(
G()->net_query_creator().create(telegram_api::channels_getChannelRecommendations(std::move(input_channel))));
}
void on_result(BufferSlice packet) final {
auto result_ptr = fetch_result<telegram_api::channels_getChannelRecommendations>(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 GetChannelRecommendationsQuery: " << 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);
return promise_.set_value(std::move(chats->chats_));
}
case telegram_api::messages_chatsSlice::ID: {
auto chats = move_tl_object_as<telegram_api::messages_chatsSlice>(chats_ptr);
LOG(ERROR) << "Receive chatsSlice in result of GetChannelRecommendationsQuery";
return promise_.set_value(std::move(chats->chats_));
}
default:
UNREACHABLE();
return promise_.set_error(Status::Error("Unreachable"));
}
}
void on_error(Status status) final {
td_->contacts_manager_->on_get_channel_error(channel_id_, status, "GetChannelRecommendationsQuery");
promise_.set_error(std::move(status));
}
};
class GetCreatedPublicChannelsQuery final : public Td::ResultHandler {
Promise<Unit> promise_;
PublicDialogType type_;
@ -9539,6 +9587,96 @@ vector<DialogId> ContactsManager::get_dialog_ids(vector<tl_object_ptr<telegram_a
return dialog_ids;
}
bool ContactsManager::is_suitable_recommended_channel(DialogId dialog_id) const {
if (dialog_id.get_type() != DialogType::Channel) {
return false;
}
return is_suitable_recommended_channel(dialog_id.get_channel_id());
}
bool ContactsManager::is_suitable_recommended_channel(ChannelId channel_id) const {
const Channel *c = get_channel(channel_id);
if (c == nullptr) {
return false;
}
return have_input_peer_channel(c, channel_id, AccessRights::Read) && !get_channel_status(c).is_member();
}
void ContactsManager::get_channel_recommendations(DialogId dialog_id,
Promise<td_api::object_ptr<td_api::chats>> &&promise) {
if (!td_->messages_manager_->have_dialog_force(dialog_id, "get_channel_recommendations")) {
return promise.set_error(Status::Error(400, "Chat not found"));
}
if (dialog_id.get_type() != DialogType::Channel) {
return promise.set_value(td_api::make_object<td_api::chats>());
}
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<td_api::chats>());
}
auto it = channel_recommended_dialog_ids_.find(channel_id);
if (it != channel_recommended_dialog_ids_.end()) {
bool is_valid = true;
for (auto recommended_dialog_id : it->second) {
if (!is_suitable_recommended_channel(recommended_dialog_id)) {
is_valid = false;
break;
}
}
if (is_valid) {
return promise.set_value(td_->messages_manager_->get_chats_object(-1, it->second, "get_channel_recommendations"));
}
LOG(INFO) << "Drop cache for similar chats of " << dialog_id;
channel_recommended_dialog_ids_.erase(it);
}
reload_channel_recommendations(channel_id, std::move(promise));
}
void ContactsManager::reload_channel_recommendations(ChannelId channel_id,
Promise<td_api::object_ptr<td_api::chats>> &&promise) {
auto &queries = get_channel_recommendations_queries_[channel_id];
queries.push_back(std::move(promise));
if (queries.size() == 1) {
auto query_promise = PromiseCreator::lambda(
[actor_id = actor_id(this), channel_id](Result<vector<tl_object_ptr<telegram_api::Chat>>> &&result) {
send_closure(actor_id, &ContactsManager::on_get_channel_recommendations, channel_id, std::move(result));
});
td_->create_handler<GetChannelRecommendationsQuery>(std::move(query_promise))->send(channel_id);
}
}
void ContactsManager::on_get_channel_recommendations(ChannelId channel_id,
Result<vector<tl_object_ptr<telegram_api::Chat>>> &&r_chats) {
G()->ignore_result_if_closing(r_chats);
auto it = get_channel_recommendations_queries_.find(channel_id);
CHECK(it != get_channel_recommendations_queries_.end());
CHECK(!it->second.empty());
auto promises = std::move(it->second);
get_channel_recommendations_queries_.erase(it);
if (r_chats.is_error()) {
return fail_promises(promises, r_chats.move_as_error());
}
auto channel_ids = get_channel_ids(r_chats.move_as_ok(), "on_get_channel_recommendations");
vector<DialogId> dialog_ids;
for (auto recommended_channel_id : channel_ids) {
td_->messages_manager_->force_create_dialog(DialogId(recommended_channel_id), "on_get_channel_recommendations");
if (is_suitable_recommended_channel(recommended_channel_id)) {
dialog_ids.push_back(DialogId(recommended_channel_id));
}
}
channel_recommended_dialog_ids_[channel_id] = dialog_ids;
// save_channel_recommendations(channel_id);
for (auto &promise : promises) {
promise.set_value(td_->messages_manager_->get_chats_object(-1, dialog_ids, "on_get_channel_recommendations"));
}
}
void ContactsManager::return_created_public_dialogs(Promise<td_api::object_ptr<td_api::chats>> &&promise,
const vector<ChannelId> &channel_ids) {
if (!promise) {

View File

@ -561,6 +561,8 @@ class ContactsManager final : public Actor {
ChannelId migrate_chat_to_megagroup(ChatId chat_id, Promise<Unit> &promise);
void get_channel_recommendations(DialogId dialog_id, Promise<td_api::object_ptr<td_api::chats>> &&promise);
void get_created_public_dialogs(PublicDialogType type, Promise<td_api::object_ptr<td_api::chats>> &&promise,
bool from_binlog);
@ -1708,6 +1710,15 @@ class ContactsManager final : public Actor {
void update_is_location_visible();
bool is_suitable_recommended_channel(DialogId dialog_id) const;
bool is_suitable_recommended_channel(ChannelId channel_id) const;
void reload_channel_recommendations(ChannelId channel_id, Promise<td_api::object_ptr<td_api::chats>> &&promise);
void on_get_channel_recommendations(ChannelId channel_id,
Result<vector<tl_object_ptr<telegram_api::Chat>>> &&r_chats);
static bool is_channel_public(const Channel *c);
static bool is_suitable_created_public_channel(PublicDialogType type, const Channel *c);
@ -1988,6 +1999,10 @@ class ContactsManager final : public Actor {
FlatHashMap<string, unique_ptr<InviteLinkInfo>> invite_link_infos_;
FlatHashMap<DialogId, DialogAccessByInviteLink, DialogIdHash> dialog_access_by_invite_link_;
FlatHashMap<ChannelId, vector<DialogId>, ChannelIdHash> channel_recommended_dialog_ids_;
FlatHashMap<ChannelId, vector<Promise<td_api::object_ptr<td_api::chats>>>, ChannelIdHash>
get_channel_recommendations_queries_;
bool created_public_channels_inited_[2] = {false, false};
vector<ChannelId> created_public_channels_[2];
vector<Promise<td_api::object_ptr<td_api::chats>>> get_created_public_channels_queries_[2];

View File

@ -5085,6 +5085,12 @@ void Td::on_request(uint64 id, const td_api::clearAutosaveSettingsExceptions &re
autosave_manager_->clear_autosave_settings_exceptions(std::move(promise));
}
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));
}
void Td::on_request(uint64 id, const td_api::getTopChats &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();

View File

@ -634,6 +634,8 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::clearAutosaveSettingsExceptions &request);
void on_request(uint64 id, const td_api::getSimilarChats &request);
void on_request(uint64 id, const td_api::getTopChats &request);
void on_request(uint64 id, const td_api::removeTopChat &request);

View File

@ -5150,6 +5150,10 @@ class CliClient final : public Actor {
ChatId chat_id;
get_args(args, chat_id);
send_request(td_api::make_object<td_api::deleteChat>(chat_id));
} else if (op == "gscs") {
ChatId chat_id;
get_args(args, chat_id);
send_request(td_api::make_object<td_api::getSimilarChats>(chat_id));
} else if (op == "gcpc") {
send_request(td_api::make_object<td_api::getCreatedPublicChats>());
} else if (op == "gcpcl") {