Support Saved Messages tags in topics.

This commit is contained in:
levlam 2024-01-29 19:11:14 +03:00
parent 027b23ac5a
commit 930a3ccdca
8 changed files with 158 additions and 61 deletions

View File

@ -1644,7 +1644,10 @@ chatAvailableReactionsAll = ChatAvailableReactions;
chatAvailableReactionsSome reactions:vector<ReactionType> = ChatAvailableReactions;
//@description Represents a tag used in Saved Messages @tag The tag @label Label of the tag; 0-12 characters @count Number of times the tag was used; may be 0 if the tag has non-empty label
//@description Represents a tag used in Saved Messages or a Saved Messages topic
//@tag The tag
//@label Label of the tag; 0-12 characters. Always empty if the tag is returned for a Saved Messages topic
//@count Number of times the tag was used; may be 0 if the tag has non-empty label
savedMessagesTag tag:ReactionType label:string count:int32 = SavedMessagesTag;
//@description Contains a list of tags used in Saved Messages @tags List of tags
@ -6730,8 +6733,10 @@ updateActiveEmojiReactions emojis:vector<string> = Update;
//@description The type of default reaction has changed @reaction_type The new type of the default reaction
updateDefaultReactionType reaction_type:ReactionType = Update;
//@description Used Saved Messages tags have changed @tags The new used tags
updateSavedMessagesTags tags:savedMessagesTags = Update;
//@description Tags used in Saved Messages or a Saved Messages topic have changed
//@saved_messages_topic Saved Messages topic which tags were changed; may be null if tags for the whole chat has changed
//@tags The new tags
updateSavedMessagesTags saved_messages_topic:SavedMessagesTopic tags:savedMessagesTags = Update;
//@description The parameters of speech recognition without Telegram Premium subscription has changed
//@max_media_duration The maximum allowed duration of media for speech recognition without Telegram Premium subscription
@ -7738,8 +7743,9 @@ getMessageAddedReactions chat_id:int53 message_id:int53 reaction_type:ReactionTy
//@description Changes type of default reaction for the current user @reaction_type New type of the default reaction
setDefaultReactionType reaction_type:ReactionType = Ok;
//@description Returns tags used in Saved Messages; for Telegram Premium users only
getSavedMessagesTags = SavedMessagesTags;
//@description Returns tags used in Saved Messages or a Saved Messages topic; for Telegram Premium users only
//@saved_messages_topic Saved Messages topic which tags will be returned; pass null to get all Saved Messages tags
getSavedMessagesTags saved_messages_topic:SavedMessagesTopic = SavedMessagesTags;
//@description Changes label of a Saved Messages tag; for Telegram Premium users only @tag The tag which label will be changed @label New label for the tag; 0-12 characters
setSavedMessagesTagLabel tag:ReactionType label:string = Ok;

View File

@ -6650,7 +6650,7 @@ bool MessagesManager::update_message_interaction_info(Dialog *d, Message *m, int
unread_reaction_diff += (has_unread_message_reactions(dialog_id, m) ? 1 : 0);
auto new_chosen_tags = get_chosen_tags(m->reactions);
td_->reaction_manager_->update_saved_messages_tags(old_chosen_tags, new_chosen_tags);
td_->reaction_manager_->update_saved_messages_tags(m->saved_messages_topic_id, old_chosen_tags, new_chosen_tags);
if (is_visible_message_reactions(dialog_id, m)) {
need_update |= need_update_reactions;
@ -15394,7 +15394,7 @@ void MessagesManager::on_message_deleted_from_database(Dialog *d, const Message
update_message_count_by_index(d, -1, m);
update_reply_count_by_message(d, -1, m);
td_->reaction_manager_->update_saved_messages_tags(get_chosen_tags(m->reactions), {});
td_->reaction_manager_->update_saved_messages_tags(m->saved_messages_topic_id, get_chosen_tags(m->reactions), {});
}
void MessagesManager::on_message_deleted(Dialog *d, Message *m, bool is_permanently_deleted, const char *source) {
@ -22883,7 +22883,8 @@ void MessagesManager::add_message_reaction(MessageFullId message_full_id, Reacti
set_message_reactions(d, m, is_big, add_to_recent, std::move(promise));
if (is_tag) {
td_->reaction_manager_->update_saved_messages_tags(old_chosen_tags, get_chosen_tags(m->reactions));
td_->reaction_manager_->update_saved_messages_tags(m->saved_messages_topic_id, old_chosen_tags,
get_chosen_tags(m->reactions));
} else if (add_to_recent) {
td_->reaction_manager_->add_recent_reaction(reaction_type);
}
@ -22919,7 +22920,8 @@ void MessagesManager::remove_message_reaction(MessageFullId message_full_id, Rea
set_message_reactions(d, m, false, false, std::move(promise));
if (!old_chosen_tags.empty()) {
td_->reaction_manager_->update_saved_messages_tags(old_chosen_tags, get_chosen_tags(m->reactions));
td_->reaction_manager_->update_saved_messages_tags(m->saved_messages_topic_id, old_chosen_tags,
get_chosen_tags(m->reactions));
}
}

View File

@ -180,10 +180,17 @@ class GetSavedReactionTagsQuery final : public Td::ResultHandler {
: promise_(std::move(promise)) {
}
void send(int64 hash) {
void send(SavedMessagesTopicId saved_messages_topic_id, int64 hash) {
int32 flags = 0;
send_query(G()->net_query_creator().create(telegram_api::messages_getSavedReactionTags(flags, nullptr, hash),
{td_->dialog_manager_->get_my_dialog_id()}));
telegram_api::object_ptr<telegram_api::InputPeer> saved_input_peer;
if (saved_messages_topic_id.is_valid()) {
flags |= telegram_api::messages_getSavedReactionTags::PEER_MASK;
saved_input_peer = saved_messages_topic_id.get_input_peer(td_);
CHECK(saved_input_peer != nullptr);
}
send_query(G()->net_query_creator().create(
telegram_api::messages_getSavedReactionTags(flags, std::move(saved_input_peer), hash),
{td_->dialog_manager_->get_my_dialog_id()}));
}
void on_result(BufferSlice packet) final {
@ -873,31 +880,76 @@ void ReactionManager::send_set_default_reaction_query() {
ReactionType(td_->option_manager_->get_option_string("default_reaction")));
}
void ReactionManager::get_saved_messages_tags(Promise<td_api::object_ptr<td_api::savedMessagesTags>> &&promise) {
if (tags_.is_inited_) {
return promise.set_value(tags_.get_saved_messages_tags_object());
ReactionManager::SavedReactionTags *ReactionManager::get_saved_reaction_tags(
SavedMessagesTopicId saved_messages_topic_id) {
if (saved_messages_topic_id == SavedMessagesTopicId()) {
return &all_tags_;
}
reget_saved_messages_tags(std::move(promise));
auto it = topic_tags_.find(saved_messages_topic_id);
if (it != topic_tags_.end()) {
return it->second.get();
}
return nullptr;
}
void ReactionManager::reget_saved_messages_tags(Promise<td_api::object_ptr<td_api::savedMessagesTags>> &&promise) {
auto &promises = pending_get_saved_reaction_tags_queries_;
ReactionManager::SavedReactionTags *ReactionManager::add_saved_reaction_tags(
SavedMessagesTopicId saved_messages_topic_id) {
if (saved_messages_topic_id == SavedMessagesTopicId()) {
return &all_tags_;
}
auto &tags = topic_tags_[saved_messages_topic_id];
if (tags == nullptr) {
tags = make_unique<SavedReactionTags>();
}
return tags.get();
}
void ReactionManager::get_saved_messages_tags(SavedMessagesTopicId saved_messages_topic_id,
Promise<td_api::object_ptr<td_api::savedMessagesTags>> &&promise) {
if (!saved_messages_topic_id.is_valid() && saved_messages_topic_id != SavedMessagesTopicId()) {
return promise.set_error(Status::Error(400, "Invalid Saved Messages topic specified"));
}
const auto *tags = get_saved_reaction_tags(saved_messages_topic_id);
if (tags != nullptr && tags->is_inited_) {
return promise.set_value(tags->get_saved_messages_tags_object());
}
reget_saved_messages_tags(saved_messages_topic_id, std::move(promise));
}
void ReactionManager::reget_saved_messages_tags(SavedMessagesTopicId saved_messages_topic_id,
Promise<td_api::object_ptr<td_api::savedMessagesTags>> &&promise) {
auto &promises = saved_messages_topic_id == SavedMessagesTopicId()
? pending_get_all_saved_reaction_tags_queries_
: pending_get_topic_saved_reaction_tags_queries_[saved_messages_topic_id];
promises.push_back(std::move(promise));
if (promises.size() != 1) {
return;
}
auto query_promise = PromiseCreator::lambda(
[actor_id = actor_id(this)](Result<telegram_api::object_ptr<telegram_api::messages_SavedReactionTags>> r_tags) {
send_closure(actor_id, &ReactionManager::on_get_saved_messages_tags, std::move(r_tags));
auto query_promise =
PromiseCreator::lambda([actor_id = actor_id(this), saved_messages_topic_id](
Result<telegram_api::object_ptr<telegram_api::messages_SavedReactionTags>> r_tags) {
send_closure(actor_id, &ReactionManager::on_get_saved_messages_tags, saved_messages_topic_id,
std::move(r_tags));
});
td_->create_handler<GetSavedReactionTagsQuery>(std::move(query_promise))->send(tags_.hash_);
const auto *tags = get_saved_reaction_tags(saved_messages_topic_id);
td_->create_handler<GetSavedReactionTagsQuery>(std::move(query_promise))
->send(saved_messages_topic_id, tags != nullptr ? tags->hash_ : 0);
}
void ReactionManager::on_get_saved_messages_tags(
SavedMessagesTopicId saved_messages_topic_id,
Result<telegram_api::object_ptr<telegram_api::messages_SavedReactionTags>> &&r_tags) {
G()->ignore_result_if_closing(r_tags);
auto promises = std::move(pending_get_saved_reaction_tags_queries_);
reset_to_empty(pending_get_saved_reaction_tags_queries_);
vector<Promise<td_api::object_ptr<td_api::savedMessagesTags>>> promises;
if (saved_messages_topic_id == SavedMessagesTopicId()) {
promises = std::move(pending_get_all_saved_reaction_tags_queries_);
reset_to_empty(pending_get_all_saved_reaction_tags_queries_);
} else {
auto it = pending_get_topic_saved_reaction_tags_queries_.find(saved_messages_topic_id);
CHECK(it != pending_get_topic_saved_reaction_tags_queries_.end());
promises = std::move(it->second);
pending_get_topic_saved_reaction_tags_queries_.erase(it);
}
CHECK(!promises.empty());
if (r_tags.is_error()) {
@ -906,9 +958,12 @@ void ReactionManager::on_get_saved_messages_tags(
auto tags_ptr = r_tags.move_as_ok();
bool need_send_update = false;
auto *reaction_tags = add_saved_reaction_tags(saved_messages_topic_id);
switch (tags_ptr->get_id()) {
case telegram_api::messages_savedReactionTagsNotModified::ID:
// nothing to do
if (!reaction_tags->is_inited_) {
LOG(ERROR) << "Receive messages.savedReactionTagsNotModified for non-inited tags";
}
break;
case telegram_api::messages_savedReactionTags::ID: {
auto tags = telegram_api::move_object_as<telegram_api::messages_savedReactionTags>(tags_ptr);
@ -921,15 +976,15 @@ void ReactionManager::on_get_saved_messages_tags(
}
}
std::sort(saved_reaction_tags.begin(), saved_reaction_tags.end());
tags_.hash_ = tags->hash_;
if (saved_reaction_tags != tags_.tags_) {
tags_.tags_ = std::move(saved_reaction_tags);
reaction_tags->hash_ = tags->hash_;
if (saved_reaction_tags != reaction_tags->tags_) {
reaction_tags->tags_ = std::move(saved_reaction_tags);
need_send_update = true;
}
if (tags_.hash_ != tags_.calc_hash()) {
if (reaction_tags->hash_ != reaction_tags->calc_hash()) {
LOG(ERROR) << "Receive unexpected Saved Messages tag hash";
}
tags_.is_inited_ = true;
reaction_tags->is_inited_ = true;
break;
}
default:
@ -937,35 +992,50 @@ void ReactionManager::on_get_saved_messages_tags(
}
if (need_send_update) {
send_update_saved_messages_tags();
send_update_saved_messages_tags(saved_messages_topic_id, reaction_tags);
}
for (auto &promise : promises) {
promise.set_value(tags_.get_saved_messages_tags_object());
if (promise) {
promise.set_value(reaction_tags->get_saved_messages_tags_object());
}
}
}
td_api::object_ptr<td_api::updateSavedMessagesTags> ReactionManager::get_update_saved_messages_tags_object() const {
return td_api::make_object<td_api::updateSavedMessagesTags>(tags_.get_saved_messages_tags_object());
td_api::object_ptr<td_api::updateSavedMessagesTags> ReactionManager::get_update_saved_messages_tags_object(
SavedMessagesTopicId saved_messages_topic_id, const SavedReactionTags *tags) const {
CHECK(tags != nullptr);
return td_api::make_object<td_api::updateSavedMessagesTags>(
saved_messages_topic_id.get_saved_messages_topic_object(td_), tags->get_saved_messages_tags_object());
}
void ReactionManager::send_update_saved_messages_tags() {
send_closure(G()->td(), &Td::send_update, get_update_saved_messages_tags_object());
void ReactionManager::send_update_saved_messages_tags(SavedMessagesTopicId saved_messages_topic_id,
const SavedReactionTags *tags) {
send_closure(G()->td(), &Td::send_update, get_update_saved_messages_tags_object(saved_messages_topic_id, tags));
}
void ReactionManager::on_update_saved_reaction_tags(Promise<Unit> &&promise) {
reget_saved_messages_tags(PromiseCreator::lambda(
[promise = std::move(promise)](Result<td_api::object_ptr<td_api::savedMessagesTags>> result) mutable {
promise.set_value(Unit());
}));
reget_saved_messages_tags(
SavedMessagesTopicId(),
PromiseCreator::lambda(
[promise = std::move(promise)](Result<td_api::object_ptr<td_api::savedMessagesTags>> result) mutable {
promise.set_value(Unit());
}));
}
void ReactionManager::update_saved_messages_tags(const vector<ReactionType> &old_tags,
void ReactionManager::update_saved_messages_tags(SavedMessagesTopicId saved_messages_topic_id,
const vector<ReactionType> &old_tags,
const vector<ReactionType> &new_tags) {
if (old_tags == new_tags) {
return;
}
if (tags_.update_saved_messages_tags(old_tags, new_tags)) {
send_update_saved_messages_tags();
if (all_tags_.update_saved_messages_tags(old_tags, new_tags)) {
send_update_saved_messages_tags(SavedMessagesTopicId(), &all_tags_);
}
if (saved_messages_topic_id != SavedMessagesTopicId()) {
auto tags = get_saved_reaction_tags(saved_messages_topic_id);
if (tags != nullptr && tags->update_saved_messages_tags(old_tags, new_tags)) {
send_update_saved_messages_tags(saved_messages_topic_id, tags);
}
}
}
@ -975,8 +1045,8 @@ void ReactionManager::set_saved_messages_tag_title(ReactionType reaction_type, s
}
title = clean_name(title, MAX_TAG_TITLE_LENGTH);
if (tags_.set_tag_title(reaction_type, title)) {
send_update_saved_messages_tags();
if (all_tags_.set_tag_title(reaction_type, title)) {
send_update_saved_messages_tags(SavedMessagesTopicId(), &all_tags_);
}
auto query_promise =
@ -998,8 +1068,11 @@ void ReactionManager::get_current_state(vector<td_api::object_ptr<td_api::Update
if (!active_reaction_types_.empty()) {
updates.push_back(get_update_active_emoji_reactions_object());
}
if (tags_.is_inited_) {
updates.push_back(get_update_saved_messages_tags_object());
if (all_tags_.is_inited_) {
updates.push_back(get_update_saved_messages_tags_object(SavedMessagesTopicId(), &all_tags_));
}
for (auto &it : topic_tags_) {
updates.push_back(get_update_saved_messages_tags_object(it.first, it.second.get()));
}
}

View File

@ -11,6 +11,7 @@
#include "td/telegram/ReactionListType.h"
#include "td/telegram/ReactionType.h"
#include "td/telegram/ReactionUnavailabilityReason.h"
#include "td/telegram/SavedMessagesTopicId.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
@ -69,11 +70,13 @@ class ReactionManager final : public Actor {
void send_set_default_reaction_query();
void get_saved_messages_tags(Promise<td_api::object_ptr<td_api::savedMessagesTags>> &&promise);
void get_saved_messages_tags(SavedMessagesTopicId saved_messages_topic_id,
Promise<td_api::object_ptr<td_api::savedMessagesTags>> &&promise);
void on_update_saved_reaction_tags(Promise<Unit> &&promise);
void update_saved_messages_tags(const vector<ReactionType> &old_tags, const vector<ReactionType> &new_tags);
void update_saved_messages_tags(SavedMessagesTopicId saved_messages_topic_id, const vector<ReactionType> &old_tags,
const vector<ReactionType> &new_tags);
void set_saved_messages_tag_title(ReactionType reaction_type, string title, Promise<Unit> &&promise);
@ -197,18 +200,26 @@ class ReactionManager final : public Actor {
td_api::object_ptr<td_api::updateActiveEmojiReactions> get_update_active_emoji_reactions_object() const;
void reget_saved_messages_tags(Promise<td_api::object_ptr<td_api::savedMessagesTags>> &&promise);
SavedReactionTags *get_saved_reaction_tags(SavedMessagesTopicId saved_messages_topic_id);
void on_get_saved_messages_tags(Result<telegram_api::object_ptr<telegram_api::messages_SavedReactionTags>> &&r_tags);
SavedReactionTags *add_saved_reaction_tags(SavedMessagesTopicId saved_messages_topic_id);
td_api::object_ptr<td_api::updateSavedMessagesTags> get_update_saved_messages_tags_object() const;
void reget_saved_messages_tags(SavedMessagesTopicId saved_messages_topic_id,
Promise<td_api::object_ptr<td_api::savedMessagesTags>> &&promise);
void send_update_saved_messages_tags();
void on_get_saved_messages_tags(SavedMessagesTopicId saved_messages_topic_id,
Result<telegram_api::object_ptr<telegram_api::messages_SavedReactionTags>> &&r_tags);
td_api::object_ptr<td_api::updateSavedMessagesTags> get_update_saved_messages_tags_object(
SavedMessagesTopicId saved_messages_topic_id, const SavedReactionTags *tags) const;
void send_update_saved_messages_tags(SavedMessagesTopicId saved_messages_topic_id, const SavedReactionTags *tags);
Td *td_;
ActorShared<> parent_;
bool is_inited_ = false;
bool are_reactions_loaded_from_database_ = false;
vector<std::pair<string, Promise<td_api::object_ptr<td_api::emojiReaction>>>> pending_get_emoji_reaction_queries_;
@ -217,10 +228,13 @@ class ReactionManager final : public Actor {
ReactionList reaction_lists_[MAX_REACTION_LIST_TYPE];
SavedReactionTags tags_;
vector<Promise<td_api::object_ptr<td_api::savedMessagesTags>>> pending_get_saved_reaction_tags_queries_;
SavedReactionTags all_tags_;
FlatHashMap<SavedMessagesTopicId, unique_ptr<SavedReactionTags>, SavedMessagesTopicIdHash> topic_tags_;
bool are_reactions_loaded_from_database_ = false;
vector<Promise<td_api::object_ptr<td_api::savedMessagesTags>>> pending_get_all_saved_reaction_tags_queries_;
FlatHashMap<SavedMessagesTopicId, vector<Promise<td_api::object_ptr<td_api::savedMessagesTags>>>,
SavedMessagesTopicIdHash>
pending_get_topic_saved_reaction_tags_queries_;
};
} // namespace td

View File

@ -69,7 +69,8 @@ SavedMessagesTopicId::SavedMessagesTopicId(const Td *td,
}
}
td_api::object_ptr<td_api::SavedMessagesTopic> SavedMessagesTopicId::get_saved_messages_topic_object(Td *td) const {
td_api::object_ptr<td_api::SavedMessagesTopic> SavedMessagesTopicId::get_saved_messages_topic_object(
const Td *td) const {
if (dialog_id_ == DialogId()) {
return nullptr;
}

View File

@ -53,7 +53,7 @@ class SavedMessagesTopicId {
bool is_author_hidden() const;
td_api::object_ptr<td_api::SavedMessagesTopic> get_saved_messages_topic_object(Td *td) const;
td_api::object_ptr<td_api::SavedMessagesTopic> get_saved_messages_topic_object(const Td *td) const;
telegram_api::object_ptr<telegram_api::InputPeer> get_input_peer(const Td *td) const;
@ -74,7 +74,7 @@ class SavedMessagesTopicId {
struct SavedMessagesTopicIdHash {
uint32 operator()(SavedMessagesTopicId saved_messages_topic_id) const {
return Hash<DialogId>()(saved_messages_topic_id.dialog_id_);
return DialogIdHash()(saved_messages_topic_id.dialog_id_);
}
};

View File

@ -5489,7 +5489,8 @@ void Td::on_request(uint64 id, const td_api::setDefaultReactionType &request) {
void Td::on_request(uint64 id, const td_api::getSavedMessagesTags &request) {
CHECK_IS_USER();
CREATE_REQUEST_PROMISE();
reaction_manager_->get_saved_messages_tags(std::move(promise));
reaction_manager_->get_saved_messages_tags(SavedMessagesTopicId(this, request.saved_messages_topic_),
std::move(promise));
}
void Td::on_request(uint64 id, td_api::setSavedMessagesTagLabel &request) {

View File

@ -2865,7 +2865,7 @@ class CliClient final : public Actor {
send_request(td_api::make_object<td_api::getMessageAddedReactions>(
chat_id, message_id, as_reaction_type(reaction), offset, as_limit(limit)));
} else if (op == "gsmts") {
send_request(td_api::make_object<td_api::getSavedMessagesTags>());
send_request(td_api::make_object<td_api::getSavedMessagesTags>(get_saved_messages_topic()));
} else if (op == "ssmtl") {
string reaction;
string label;