diff --git a/CMakeLists.txt b/CMakeLists.txt index 07b1960b9..482c7fd5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -444,6 +444,7 @@ set(TDLIB_SOURCE td/telegram/PremiumGiftOption.cpp td/telegram/QueryCombiner.cpp td/telegram/QueryMerger.cpp + td/telegram/ReactionType.cpp td/telegram/RecentDialogList.cpp td/telegram/ReplyMarkup.cpp td/telegram/ReportReason.cpp @@ -734,6 +735,7 @@ set(TDLIB_SOURCE td/telegram/PublicDialogType.h td/telegram/QueryCombiner.h td/telegram/QueryMerger.h + td/telegram/ReactionType.h td/telegram/RecentDialogList.h td/telegram/ReplyMarkup.h td/telegram/ReportReason.h @@ -838,6 +840,7 @@ set(TDLIB_SOURCE td/telegram/PollId.hpp td/telegram/PollManager.hpp td/telegram/PremiumGiftOption.hpp + td/telegram/ReactionType.hpp td/telegram/ReplyMarkup.hpp td/telegram/RequestedDialogType.hpp td/telegram/ScopeNotificationSettings.hpp diff --git a/td/telegram/ChatReactions.cpp b/td/telegram/ChatReactions.cpp index 3107f7430..3d302d690 100644 --- a/td/telegram/ChatReactions.cpp +++ b/td/telegram/ChatReactions.cpp @@ -28,10 +28,9 @@ ChatReactions::ChatReactions(telegram_api::object_ptr(chat_reactions_ptr); - reactions_ = - transform(chat_reactions->reactions_, [](const telegram_api::object_ptr &reaction) { - return get_message_reaction_string(reaction); - }); + reaction_types_ = transform( + chat_reactions->reactions_, + [](const telegram_api::object_ptr &reaction) { return ReactionType(reaction); }); break; } default: @@ -51,9 +50,9 @@ ChatReactions::ChatReactions(td_api::object_ptr break; case td_api::chatAvailableReactionsSome::ID: { auto chat_reactions = move_tl_object_as(chat_reactions_ptr); - reactions_ = transform(chat_reactions->reactions_, [](const td_api::object_ptr &reaction) { - return get_message_reaction_string(reaction); - }); + reaction_types_ = + transform(chat_reactions->reactions_, + [](const td_api::object_ptr &reaction) { return ReactionType(reaction); }); break; } default: @@ -61,30 +60,33 @@ ChatReactions::ChatReactions(td_api::object_ptr } } -ChatReactions ChatReactions::get_active_reactions(const FlatHashMap &active_reaction_pos) const { +ChatReactions ChatReactions::get_active_reactions( + const FlatHashMap &active_reaction_pos) const { ChatReactions result = *this; - if (!reactions_.empty()) { + if (!reaction_types_.empty()) { CHECK(!allow_all_); CHECK(!allow_custom_); - td::remove_if(result.reactions_, - [&](const string &reaction) { return !is_active_reaction(reaction, active_reaction_pos); }); + td::remove_if(result.reaction_types_, [&](const ReactionType &reaction_type) { + return !reaction_type.is_active_reaction(active_reaction_pos); + }); } return result; } -bool ChatReactions::is_allowed_reaction(const string &reaction) const { +bool ChatReactions::is_allowed_reaction_type(const ReactionType &reaction_type) const { CHECK(!allow_all_); - if (allow_custom_ && is_custom_reaction(reaction)) { + if (allow_custom_ && reaction_type.is_custom_reaction()) { return true; } - return td::contains(reactions_, reaction); + return td::contains(reaction_types_, reaction_type); } td_api::object_ptr ChatReactions::get_chat_available_reactions_object() const { if (allow_all_) { return td_api::make_object(); } - return td_api::make_object(transform(reactions_, get_reaction_type_object)); + return td_api::make_object(transform( + reaction_types_, [](const ReactionType &reaction_type) { return reaction_type.get_reaction_type_object(); })); } telegram_api::object_ptr ChatReactions::get_input_chat_reactions() const { @@ -95,15 +97,16 @@ telegram_api::object_ptr ChatReactions::get_input_c } return telegram_api::make_object(flags, allow_custom_); } - if (!reactions_.empty()) { - return telegram_api::make_object(transform(reactions_, get_input_reaction)); + if (!reaction_types_.empty()) { + return telegram_api::make_object(transform( + reaction_types_, [](const ReactionType &reaction_type) { return reaction_type.get_input_reaction(); })); } return telegram_api::make_object(); } bool operator==(const ChatReactions &lhs, const ChatReactions &rhs) { // don't compare allow_custom_ - return lhs.reactions_ == rhs.reactions_ && lhs.allow_all_ == rhs.allow_all_; + return lhs.reaction_types_ == rhs.reaction_types_ && lhs.allow_all_ == rhs.allow_all_; } StringBuilder &operator<<(StringBuilder &string_builder, const ChatReactions &reactions) { @@ -113,7 +116,7 @@ StringBuilder &operator<<(StringBuilder &string_builder, const ChatReactions &re } return string_builder << "AllRegularReactions"; } - return string_builder << '[' << reactions.reactions_ << ']'; + return string_builder << '[' << reactions.reaction_types_ << ']'; } } // namespace td diff --git a/td/telegram/ChatReactions.h b/td/telegram/ChatReactions.h index bf92d37c0..cdab23bdf 100644 --- a/td/telegram/ChatReactions.h +++ b/td/telegram/ChatReactions.h @@ -6,6 +6,7 @@ // #pragma once +#include "td/telegram/ReactionType.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" @@ -17,13 +18,13 @@ namespace td { struct ChatReactions { - vector reactions_; + vector reaction_types_; bool allow_all_ = false; // implies empty reactions bool allow_custom_ = false; // implies allow_all ChatReactions() = default; - explicit ChatReactions(vector &&reactions) : reactions_(std::move(reactions)) { + explicit ChatReactions(vector &&reactions) : reaction_types_(std::move(reactions)) { } explicit ChatReactions(telegram_api::object_ptr &&chat_reactions_ptr); @@ -33,28 +34,29 @@ struct ChatReactions { ChatReactions(bool allow_all, bool allow_custom) : allow_all_(allow_all), allow_custom_(allow_custom) { } - ChatReactions get_active_reactions(const FlatHashMap &active_reaction_pos) const; + ChatReactions get_active_reactions( + const FlatHashMap &active_reaction_pos) const; - bool is_allowed_reaction(const string &reaction) const; + bool is_allowed_reaction_type(const ReactionType &reaction) const; telegram_api::object_ptr get_input_chat_reactions() const; td_api::object_ptr get_chat_available_reactions_object() const; bool empty() const { - return reactions_.empty() && !allow_all_; + return reaction_types_.empty() && !allow_all_; } template void store(StorerT &storer) const { - bool has_reactions = !reactions_.empty(); + bool has_reactions = !reaction_types_.empty(); BEGIN_STORE_FLAGS(); STORE_FLAG(allow_all_); STORE_FLAG(allow_custom_); STORE_FLAG(has_reactions); END_STORE_FLAGS(); if (has_reactions) { - td::store(reactions_, storer); + td::store(reaction_types_, storer); } } @@ -67,7 +69,7 @@ struct ChatReactions { PARSE_FLAG(has_reactions); END_PARSE_FLAGS(); if (has_reactions) { - td::parse(reactions_, parser); + td::parse(reaction_types_, parser); } } }; diff --git a/td/telegram/ConfigManager.cpp b/td/telegram/ConfigManager.cpp index f0de281b2..74ac996ab 100644 --- a/td/telegram/ConfigManager.cpp +++ b/td/telegram/ConfigManager.cpp @@ -25,6 +25,7 @@ #include "td/telegram/net/PublicRsaKeyShared.h" #include "td/telegram/net/Session.h" #include "td/telegram/Premium.h" +#include "td/telegram/ReactionType.h" #include "td/telegram/StateManager.h" #include "td/telegram/Td.h" #include "td/telegram/TdDb.h" @@ -1402,9 +1403,9 @@ void ConfigManager::process_config(tl_object_ptr config) { options.set_option_integer("notification_default_delay_ms", fix_timeout_ms(config->notify_default_delay_ms_)); if (is_from_main_dc && !options.have_option("default_reaction_need_sync")) { - auto reaction_str = get_message_reaction_string(config->reactions_default_); - if (!reaction_str.empty()) { - options.set_option_string("default_reaction", reaction_str); + ReactionType reaction_type(config->reactions_default_); + if (!reaction_type.is_empty()) { + options.set_option_string("default_reaction", reaction_type.get_string()); } } diff --git a/td/telegram/MessageReaction.cpp b/td/telegram/MessageReaction.cpp index 2bb8772c5..8f71f5ca5 100644 --- a/td/telegram/MessageReaction.cpp +++ b/td/telegram/MessageReaction.cpp @@ -13,7 +13,6 @@ #include "td/telegram/Global.h" #include "td/telegram/MessageSender.h" #include "td/telegram/MessagesManager.h" -#include "td/telegram/misc.h" #include "td/telegram/OptionManager.h" #include "td/telegram/ServerMessageId.h" #include "td/telegram/StickersManager.h" @@ -25,17 +24,11 @@ #include "td/actor/SleepActor.h" #include "td/utils/algorithm.h" -#include "td/utils/as.h" -#include "td/utils/base64.h" #include "td/utils/buffer.h" -#include "td/utils/crypto.h" -#include "td/utils/emoji.h" #include "td/utils/FlatHashSet.h" #include "td/utils/logging.h" #include "td/utils/Slice.h" -#include "td/utils/SliceBuilder.h" #include "td/utils/Status.h" -#include "td/utils/utf8.h" #include #include @@ -49,81 +42,6 @@ static size_t get_max_reaction_count() { max(static_cast(1), static_cast(G()->get_option_integer(option_key, is_premium ? 3 : 1)))); } -static int64 get_custom_emoji_id(const string &reaction) { - auto r_decoded = base64_decode(Slice(&reaction[1], reaction.size() - 1)); - CHECK(r_decoded.is_ok()); - CHECK(r_decoded.ok().size() == 8); - return as(r_decoded.ok().c_str()); -} - -static string get_custom_emoji_string(int64 custom_emoji_id) { - char s[8]; - as(&s) = custom_emoji_id; - return PSTRING() << '#' << base64_encode(Slice(s, 8)); -} - -telegram_api::object_ptr get_input_reaction(const string &reaction) { - if (reaction.empty()) { - return telegram_api::make_object(); - } - if (is_custom_reaction(reaction)) { - return telegram_api::make_object(get_custom_emoji_id(reaction)); - } - return telegram_api::make_object(reaction); -} - -string get_message_reaction_string(const telegram_api::object_ptr &reaction) { - if (reaction == nullptr) { - return string(); - } - switch (reaction->get_id()) { - case telegram_api::reactionEmpty::ID: - return string(); - case telegram_api::reactionEmoji::ID: { - const string &emoji = static_cast(reaction.get())->emoticon_; - if (is_custom_reaction(emoji)) { - return string(); - } - return emoji; - } - case telegram_api::reactionCustomEmoji::ID: - return get_custom_emoji_string( - static_cast(reaction.get())->document_id_); - default: - UNREACHABLE(); - return string(); - } -} - -td_api::object_ptr get_reaction_type_object(const string &reaction) { - CHECK(!reaction.empty()); - if (is_custom_reaction(reaction)) { - return td_api::make_object(get_custom_emoji_id(reaction)); - } - return td_api::make_object(reaction); -} - -string get_message_reaction_string(const td_api::object_ptr &type) { - if (type == nullptr) { - return string(); - } - switch (type->get_id()) { - case td_api::reactionTypeEmoji::ID: { - const string &emoji = static_cast(type.get())->emoji_; - if (!check_utf8(emoji) || is_custom_reaction(emoji)) { - return string(); - } - return emoji; - } - case td_api::reactionTypeCustomEmoji::ID: - return get_custom_emoji_string( - static_cast(type.get())->custom_emoji_id_); - default: - UNREACHABLE(); - return string(); - } -} - class GetMessagesReactionsQuery final : public Td::ResultHandler { DialogId dialog_id_; vector message_ids_; @@ -186,7 +104,7 @@ class SendReactionQuery final : public Td::ResultHandler { explicit SendReactionQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(FullMessageId full_message_id, vector reactions, bool is_big, bool add_to_recent) { + void send(FullMessageId full_message_id, vector reaction_types, bool is_big, bool add_to_recent) { dialog_id_ = full_message_id.get_dialog_id(); auto input_peer = td_->messages_manager_->get_input_peer(dialog_id_, AccessRights::Read); @@ -195,7 +113,7 @@ class SendReactionQuery final : public Td::ResultHandler { } int32 flags = 0; - if (!reactions.empty()) { + if (!reaction_types.empty()) { flags |= telegram_api::messages_sendReaction::REACTION_MASK; if (is_big) { @@ -208,9 +126,11 @@ class SendReactionQuery final : public Td::ResultHandler { } send_query(G()->net_query_creator().create( - telegram_api::messages_sendReaction(flags, false /*ignored*/, false /*ignored*/, std::move(input_peer), - full_message_id.get_message_id().get_server_message_id().get(), - transform(reactions, get_input_reaction)), + telegram_api::messages_sendReaction( + flags, false /*ignored*/, false /*ignored*/, std::move(input_peer), + full_message_id.get_message_id().get_server_message_id().get(), + transform(reaction_types, + [](const ReactionType &reaction_type) { return reaction_type.get_input_reaction(); })), {{dialog_id_}, {full_message_id}})); } @@ -238,7 +158,7 @@ class GetMessageReactionsListQuery final : public Td::ResultHandler { Promise> promise_; DialogId dialog_id_; MessageId message_id_; - string reaction_; + ReactionType reaction_type_; string offset_; public: @@ -246,10 +166,10 @@ class GetMessageReactionsListQuery final : public Td::ResultHandler { : promise_(std::move(promise)) { } - void send(FullMessageId full_message_id, string reaction, string offset, int32 limit) { + void send(FullMessageId full_message_id, ReactionType reaction_type, string offset, int32 limit) { dialog_id_ = full_message_id.get_dialog_id(); message_id_ = full_message_id.get_message_id(); - reaction_ = std::move(reaction); + reaction_type_ = std::move(reaction_type); offset_ = std::move(offset); auto input_peer = td_->messages_manager_->get_input_peer(dialog_id_, AccessRights::Read); @@ -258,7 +178,7 @@ class GetMessageReactionsListQuery final : public Td::ResultHandler { } int32 flags = 0; - if (!reaction_.empty()) { + if (!reaction_type_.is_empty()) { flags |= telegram_api::messages_getMessageReactionsList::REACTION_MASK; } if (!offset_.empty()) { @@ -268,7 +188,7 @@ class GetMessageReactionsListQuery final : public Td::ResultHandler { send_query(G()->net_query_creator().create( telegram_api::messages_getMessageReactionsList(flags, std::move(input_peer), message_id_.get_server_message_id().get(), - get_input_reaction(reaction_), offset_, limit), + reaction_type_.get_input_reaction(), offset_, limit), {{full_message_id}})); } @@ -292,29 +212,30 @@ class GetMessageReactionsListQuery final : public Td::ResultHandler { } vector> reactions; - FlatHashMap> recent_reactions; + FlatHashMap, ReactionTypeHash> recent_reaction_types; for (const auto &reaction : ptr->reactions_) { DialogId dialog_id(reaction->peer_id_); - auto reaction_str = get_message_reaction_string(reaction->reaction_); - if (!dialog_id.is_valid() || (reaction_.empty() ? reaction_str.empty() : reaction_ != reaction_str)) { + auto reaction_type = ReactionType(reaction->reaction_); + if (!dialog_id.is_valid() || + (reaction_type_.is_empty() ? reaction_type.is_empty() : reaction_type_ != reaction_type)) { LOG(ERROR) << "Receive unexpected " << to_string(reaction); continue; } if (offset_.empty()) { - recent_reactions[reaction_str].push_back(dialog_id); + recent_reaction_types[reaction_type].push_back(dialog_id); } auto message_sender = get_min_message_sender_object(td_, dialog_id, "GetMessageReactionsListQuery"); if (message_sender != nullptr) { - reactions.push_back(td_api::make_object(get_reaction_type_object(reaction_str), + reactions.push_back(td_api::make_object(reaction_type.get_reaction_type_object(), std::move(message_sender), reaction->date_)); } } if (offset_.empty()) { - td_->messages_manager_->on_get_message_reaction_list({dialog_id_, message_id_}, reaction_, - std::move(recent_reactions), total_count); + td_->messages_manager_->on_get_message_reaction_list({dialog_id_, message_id_}, reaction_type_, + std::move(recent_reaction_types), total_count); } promise_.set_value( @@ -328,13 +249,13 @@ class GetMessageReactionsListQuery final : public Td::ResultHandler { }; class SetDefaultReactionQuery final : public Td::ResultHandler { - string reaction_; + ReactionType reaction_type_; public: - void send(const string &reaction) { - reaction_ = reaction; + void send(const ReactionType &reaction_type) { + reaction_type_ = reaction_type; send_query( - G()->net_query_creator().create(telegram_api::messages_setDefaultReaction(get_input_reaction(reaction)))); + G()->net_query_creator().create(telegram_api::messages_setDefaultReaction(reaction_type.get_input_reaction()))); } void on_result(BufferSlice packet) final { @@ -348,7 +269,7 @@ class SetDefaultReactionQuery final : public Td::ResultHandler { } auto default_reaction = td_->option_manager_->get_option_string("default_reaction", "-"); - if (default_reaction != reaction_) { + if (default_reaction != reaction_type_.get_string()) { send_set_default_reaction_query(td_); } else { td_->option_manager_->set_option_empty("default_reaction_needs_sync"); @@ -404,10 +325,10 @@ class ReportReactionQuery final : public Td::ResultHandler { } }; -MessageReaction::MessageReaction(string reaction, int32 choose_count, bool is_chosen, +MessageReaction::MessageReaction(ReactionType reaction_type, int32 choose_count, bool is_chosen, DialogId my_recent_chooser_dialog_id, vector &&recent_chooser_dialog_ids, vector> &&recent_chooser_min_channels) - : reaction_(std::move(reaction)) + : reaction_type_(std::move(reaction_type)) , choose_count_(choose_count) , is_chosen_(is_chosen) , my_recent_chooser_dialog_id_(my_recent_chooser_dialog_id) @@ -453,7 +374,7 @@ void MessageReaction::update_recent_chooser_dialog_ids(const MessageReaction &ol return; } CHECK(is_chosen_ && old_reaction.is_chosen_); - CHECK(reaction_ == old_reaction.reaction_); + CHECK(reaction_type_ == old_reaction.reaction_type_); CHECK(old_reaction.recent_chooser_dialog_ids_.size() == MAX_RECENT_CHOOSERS + 1); for (size_t i = 0; i < MAX_RECENT_CHOOSERS; i++) { if (recent_chooser_dialog_ids_[i] != old_reaction.recent_chooser_dialog_ids_[i]) { @@ -528,18 +449,18 @@ td_api::object_ptr MessageReaction::get_message_reactio } } } - return td_api::make_object(get_reaction_type_object(reaction_), choose_count_, is_chosen_, - std::move(recent_choosers)); + return td_api::make_object(reaction_type_.get_reaction_type_object(), choose_count_, + is_chosen_, std::move(recent_choosers)); } bool operator==(const MessageReaction &lhs, const MessageReaction &rhs) { - return lhs.reaction_ == rhs.reaction_ && lhs.choose_count_ == rhs.choose_count_ && lhs.is_chosen_ == rhs.is_chosen_ && - lhs.my_recent_chooser_dialog_id_ == rhs.my_recent_chooser_dialog_id_ && + return lhs.reaction_type_ == rhs.reaction_type_ && lhs.choose_count_ == rhs.choose_count_ && + lhs.is_chosen_ == rhs.is_chosen_ && lhs.my_recent_chooser_dialog_id_ == rhs.my_recent_chooser_dialog_id_ && lhs.recent_chooser_dialog_ids_ == rhs.recent_chooser_dialog_ids_; } StringBuilder &operator<<(StringBuilder &string_builder, const MessageReaction &reaction) { - string_builder << '[' << reaction.reaction_ << (reaction.is_chosen_ ? " X " : " x ") << reaction.choose_count_; + string_builder << '[' << reaction.reaction_type_ << (reaction.is_chosen_ ? " X " : " x ") << reaction.choose_count_; if (!reaction.recent_chooser_dialog_ids_.empty()) { string_builder << " by " << reaction.recent_chooser_dialog_ids_; if (reaction.my_recent_chooser_dialog_id_.is_valid()) { @@ -554,16 +475,17 @@ td_api::object_ptr UnreadMessageReaction::get_unread_rea if (sender_id == nullptr) { return nullptr; } - return td_api::make_object(get_reaction_type_object(reaction_), std::move(sender_id), + return td_api::make_object(reaction_type_.get_reaction_type_object(), std::move(sender_id), is_big_); } bool operator==(const UnreadMessageReaction &lhs, const UnreadMessageReaction &rhs) { - return lhs.reaction_ == rhs.reaction_ && lhs.sender_dialog_id_ == rhs.sender_dialog_id_ && lhs.is_big_ == rhs.is_big_; + return lhs.reaction_type_ == rhs.reaction_type_ && lhs.sender_dialog_id_ == rhs.sender_dialog_id_ && + lhs.is_big_ == rhs.is_big_; } StringBuilder &operator<<(StringBuilder &string_builder, const UnreadMessageReaction &unread_reaction) { - return string_builder << '[' << unread_reaction.reaction_ << (unread_reaction.is_big_ ? " BY " : " by ") + return string_builder << '[' << unread_reaction.reaction_type_ << (unread_reaction.is_big_ ? " BY " : " by ") << unread_reaction.sender_dialog_id_ << ']'; } @@ -591,18 +513,18 @@ unique_ptr MessageReactions::get_message_reactions( } } - FlatHashSet reaction_strings; - vector> chosen_reaction_order; + FlatHashSet reaction_types; + vector> chosen_reaction_order; for (auto &reaction_count : reactions->results_) { - auto reaction_str = get_message_reaction_string(reaction_count->reaction_); + auto reaction_type = ReactionType(reaction_count->reaction_); if (reaction_count->count_ <= 0 || reaction_count->count_ >= MessageReaction::MAX_CHOOSE_COUNT || - reaction_str.empty()) { - LOG(ERROR) << "Receive reaction " << reaction_str << " with invalid count " << reaction_count->count_; + reaction_type.is_empty()) { + LOG(ERROR) << "Receive reaction " << reaction_type << " with invalid count " << reaction_count->count_; continue; } - if (!reaction_strings.insert(reaction_str).second) { - LOG(ERROR) << "Receive duplicate reaction " << reaction_str; + if (!reaction_types.insert(reaction_type).second) { + LOG(ERROR) << "Receive duplicate reaction " << reaction_type; continue; } @@ -611,15 +533,15 @@ unique_ptr MessageReactions::get_message_reactions( vector recent_chooser_dialog_ids; vector> recent_chooser_min_channels; for (auto &peer_reaction : reactions->recent_reactions_) { - auto peer_reaction_str = get_message_reaction_string(peer_reaction->reaction_); - if (peer_reaction_str == reaction_str) { + auto peer_reaction_type = ReactionType(peer_reaction->reaction_); + if (peer_reaction_type == reaction_type) { DialogId dialog_id(peer_reaction->peer_id_); if (!dialog_id.is_valid()) { - LOG(ERROR) << "Receive invalid " << dialog_id << " as a recent chooser for reaction " << reaction_str; + LOG(ERROR) << "Receive invalid " << dialog_id << " as a recent chooser for reaction " << reaction_type; continue; } if (!recent_choosers.insert(dialog_id).second) { - LOG(ERROR) << "Receive duplicate " << dialog_id << " as a recent chooser for reaction " << reaction_str; + LOG(ERROR) << "Receive duplicate " << dialog_id << " as a recent chooser for reaction " << reaction_type; continue; } if (!td->messages_manager_->have_dialog_info(dialog_id)) { @@ -649,7 +571,7 @@ unique_ptr MessageReactions::get_message_reactions( my_recent_chooser_dialog_id = dialog_id; } if (peer_reaction->unread_) { - result->unread_reactions_.emplace_back(std::move(peer_reaction_str), dialog_id, peer_reaction->big_); + result->unread_reactions_.emplace_back(std::move(peer_reaction_type), dialog_id, peer_reaction->big_); } if (recent_chooser_dialog_ids.size() == MessageReaction::MAX_RECENT_CHOOSERS) { break; @@ -659,32 +581,32 @@ unique_ptr MessageReactions::get_message_reactions( bool is_chosen = (reaction_count->flags_ & telegram_api::reactionCount::CHOSEN_ORDER_MASK) != 0; if (is_chosen) { - chosen_reaction_order.emplace_back(reaction_count->chosen_order_, reaction_str); + chosen_reaction_order.emplace_back(reaction_count->chosen_order_, reaction_type); } - result->reactions_.push_back({std::move(reaction_str), reaction_count->count_, is_chosen, + result->reactions_.push_back({std::move(reaction_type), reaction_count->count_, is_chosen, my_recent_chooser_dialog_id, std::move(recent_chooser_dialog_ids), std::move(recent_chooser_min_channels)}); } if (chosen_reaction_order.size() > 1) { std::sort(chosen_reaction_order.begin(), chosen_reaction_order.end()); result->chosen_reaction_order_ = - transform(chosen_reaction_order, [](const std::pair &order) { return order.second; }); + transform(chosen_reaction_order, [](const std::pair &order) { return order.second; }); } return result; } -MessageReaction *MessageReactions::get_reaction(const string &reaction) { +MessageReaction *MessageReactions::get_reaction(const ReactionType &reaction_type) { for (auto &added_reaction : reactions_) { - if (added_reaction.get_reaction() == reaction) { + if (added_reaction.get_reaction_type() == reaction_type) { return &added_reaction; } } return nullptr; } -const MessageReaction *MessageReactions::get_reaction(const string &reaction) const { +const MessageReaction *MessageReactions::get_reaction(const ReactionType &reaction_type) const { for (auto &added_reaction : reactions_) { - if (added_reaction.get_reaction() == reaction) { + if (added_reaction.get_reaction_type() == reaction_type) { return &added_reaction; } } @@ -698,12 +620,12 @@ void MessageReactions::update_from(const MessageReactions &old_reactions) { chosen_reaction_order_ = old_reactions.chosen_reaction_order_; for (const auto &old_reaction : old_reactions.reactions_) { if (old_reaction.is_chosen()) { - auto *reaction = get_reaction(old_reaction.get_reaction()); + auto *reaction = get_reaction(old_reaction.get_reaction_type()); if (reaction != nullptr) { reaction->update_from(old_reaction); } } else { - td::remove(chosen_reaction_order_, old_reaction.get_reaction()); + td::remove(chosen_reaction_order_, old_reaction.get_reaction_type()); } } unread_reactions_ = old_reactions.unread_reactions_; @@ -714,7 +636,7 @@ void MessageReactions::update_from(const MessageReactions &old_reactions) { for (const auto &old_reaction : old_reactions.reactions_) { if (old_reaction.is_chosen() && old_reaction.get_recent_chooser_dialog_ids().size() == MessageReaction::MAX_RECENT_CHOOSERS + 1) { - auto *reaction = get_reaction(old_reaction.get_reaction()); + auto *reaction = get_reaction(old_reaction.get_reaction_type()); if (reaction != nullptr && reaction->is_chosen()) { reaction->update_recent_chooser_dialog_ids(old_reaction); } @@ -722,11 +644,11 @@ void MessageReactions::update_from(const MessageReactions &old_reactions) { } } -bool MessageReactions::add_reaction(const string &reaction, bool is_big, DialogId my_dialog_id, +bool MessageReactions::add_reaction(const ReactionType &reaction_type, bool is_big, DialogId my_dialog_id, bool have_recent_choosers) { - vector new_chosen_reaction_order = get_chosen_reactions(); + vector new_chosen_reaction_order = get_chosen_reaction_types(); - auto added_reaction = get_reaction(reaction); + auto added_reaction = get_reaction(reaction_type); if (added_reaction == nullptr) { vector recent_chooser_dialog_ids; DialogId my_recent_chooser_dialog_id; @@ -735,18 +657,18 @@ bool MessageReactions::add_reaction(const string &reaction, bool is_big, DialogI my_recent_chooser_dialog_id = my_dialog_id; } reactions_.push_back( - {reaction, 1, true, my_recent_chooser_dialog_id, std::move(recent_chooser_dialog_ids), Auto()}); - new_chosen_reaction_order.emplace_back(reaction); + {reaction_type, 1, true, my_recent_chooser_dialog_id, std::move(recent_chooser_dialog_ids), Auto()}); + new_chosen_reaction_order.emplace_back(reaction_type); } else if (!added_reaction->is_chosen()) { added_reaction->set_as_chosen(my_dialog_id, have_recent_choosers); - new_chosen_reaction_order.emplace_back(reaction); + new_chosen_reaction_order.emplace_back(reaction_type); } else if (!is_big) { return false; } auto max_reaction_count = get_max_reaction_count(); while (new_chosen_reaction_order.size() > max_reaction_count) { - auto index = new_chosen_reaction_order[0] == reaction ? 1 : 0; + auto index = new_chosen_reaction_order[0] == reaction_type ? 1 : 0; CHECK(static_cast(index) < new_chosen_reaction_order.size()); bool is_removed = do_remove_reaction(new_chosen_reaction_order[index]); CHECK(is_removed); @@ -765,10 +687,10 @@ bool MessageReactions::add_reaction(const string &reaction, bool is_big, DialogI return true; } -bool MessageReactions::remove_reaction(const string &reaction, DialogId my_dialog_id) { - if (do_remove_reaction(reaction)) { +bool MessageReactions::remove_reaction(const ReactionType &reaction_type, DialogId my_dialog_id) { + if (do_remove_reaction(reaction_type)) { if (!chosen_reaction_order_.empty()) { - bool is_removed = td::remove(chosen_reaction_order_, reaction); + bool is_removed = td::remove(chosen_reaction_order_, reaction_type); CHECK(is_removed); // if the user isn't a Premium user, then max_reaction_count could be reduced from 3 to 1 @@ -793,10 +715,10 @@ bool MessageReactions::remove_reaction(const string &reaction, DialogId my_dialo return false; } -bool MessageReactions::do_remove_reaction(const string &reaction) { +bool MessageReactions::do_remove_reaction(const ReactionType &reaction_type) { for (auto it = reactions_.begin(); it != reactions_.end(); ++it) { auto &message_reaction = *it; - if (message_reaction.get_reaction() == reaction) { + if (message_reaction.get_reaction_type() == reaction_type) { if (message_reaction.is_chosen()) { message_reaction.unset_as_chosen(); if (message_reaction.is_empty()) { @@ -810,21 +732,21 @@ bool MessageReactions::do_remove_reaction(const string &reaction) { return false; } -void MessageReactions::sort_reactions(const FlatHashMap &active_reaction_pos) { +void MessageReactions::sort_reactions(const FlatHashMap &active_reaction_pos) { std::sort(reactions_.begin(), reactions_.end(), [&active_reaction_pos](const MessageReaction &lhs, const MessageReaction &rhs) { if (lhs.get_choose_count() != rhs.get_choose_count()) { return lhs.get_choose_count() > rhs.get_choose_count(); } - auto lhs_it = active_reaction_pos.find(lhs.get_reaction()); + auto lhs_it = active_reaction_pos.find(lhs.get_reaction_type()); auto lhs_pos = lhs_it != active_reaction_pos.end() ? lhs_it->second : active_reaction_pos.size(); - auto rhs_it = active_reaction_pos.find(rhs.get_reaction()); + auto rhs_it = active_reaction_pos.find(rhs.get_reaction_type()); auto rhs_pos = rhs_it != active_reaction_pos.end() ? rhs_it->second : active_reaction_pos.size(); if (lhs_pos != rhs_pos) { return lhs_pos < rhs_pos; } - return lhs.get_reaction() < rhs.get_reaction(); + return lhs.get_reaction_type() < rhs.get_reaction_type(); }); } @@ -856,22 +778,23 @@ void MessageReactions::fix_my_recent_chooser_dialog_id(DialogId my_dialog_id) { } } -vector MessageReactions::get_chosen_reactions() const { +vector MessageReactions::get_chosen_reaction_types() const { if (!chosen_reaction_order_.empty()) { return chosen_reaction_order_; } - vector reaction_order; + vector reaction_order; for (auto &reaction : reactions_) { if (reaction.is_chosen()) { - reaction_order.push_back(reaction.get_reaction()); + reaction_order.push_back(reaction.get_reaction_type()); } } return reaction_order; } -bool MessageReactions::are_consistent_with_list(const string &reaction, FlatHashMap> reactions, - int32 total_count) const { +bool MessageReactions::are_consistent_with_list( + const ReactionType &reaction_type, FlatHashMap, ReactionTypeHash> reaction_types, + int32 total_count) const { auto are_consistent = [](const vector &lhs, const vector &rhs) { size_t i = 0; size_t max_i = td::min(lhs.size(), rhs.size()); @@ -881,27 +804,27 @@ bool MessageReactions::are_consistent_with_list(const string &reaction, FlatHash return i == max_i; }; - if (reaction.empty()) { + if (reaction_type.is_empty()) { // received list and total_count for all reactions int32 old_total_count = 0; for (const auto &message_reaction : reactions_) { - CHECK(!message_reaction.get_reaction().empty()); - if (!are_consistent(reactions[message_reaction.get_reaction()], + CHECK(!message_reaction.get_reaction_type().is_empty()); + if (!are_consistent(reaction_types[message_reaction.get_reaction_type()], message_reaction.get_recent_chooser_dialog_ids())) { return false; } old_total_count += message_reaction.get_choose_count(); - reactions.erase(message_reaction.get_reaction()); + reaction_types.erase(message_reaction.get_reaction_type()); } - return old_total_count == total_count && reactions.empty(); + return old_total_count == total_count && reaction_types.empty(); } // received list and total_count for a single reaction - const auto *message_reaction = get_reaction(reaction); + const auto *message_reaction = get_reaction(reaction_type); if (message_reaction == nullptr) { - return reactions.count(reaction) == 0 && total_count == 0; + return reaction_types.count(reaction_type) == 0 && total_count == 0; } else { - return are_consistent(reactions[reaction], message_reaction->get_recent_chooser_dialog_ids()) && + return are_consistent(reaction_types[reaction_type], message_reaction->get_recent_chooser_dialog_ids()) && message_reaction->get_choose_count() == total_count; } } @@ -970,14 +893,6 @@ StringBuilder &operator<<(StringBuilder &string_builder, const unique_ptr &active_reaction_pos) { - return !reaction.empty() && (is_custom_reaction(reaction) || active_reaction_pos.count(reaction) > 0); -} - void reload_message_reactions(Td *td, DialogId dialog_id, vector &&message_ids) { if (!td->messages_manager_->have_input_peer(dialog_id, AccessRights::Read) || dialog_id.get_type() == DialogType::SecretChat || message_ids.empty()) { @@ -998,14 +913,14 @@ void reload_message_reactions(Td *td, DialogId dialog_id, vector &&me td->create_handler()->send(dialog_id, std::move(message_ids)); } -void send_message_reaction(Td *td, FullMessageId full_message_id, vector reactions, bool is_big, +void send_message_reaction(Td *td, FullMessageId full_message_id, vector reaction_types, bool is_big, bool add_to_recent, Promise &&promise) { td->create_handler(std::move(promise)) - ->send(full_message_id, std::move(reactions), is_big, add_to_recent); + ->send(full_message_id, std::move(reaction_types), is_big, add_to_recent); } -void get_message_added_reactions(Td *td, FullMessageId full_message_id, string reaction, string offset, int32 limit, - Promise> &&promise) { +void get_message_added_reactions(Td *td, FullMessageId full_message_id, ReactionType reaction_type, string offset, + int32 limit, Promise> &&promise) { if (!td->messages_manager_->have_message_force(full_message_id, "get_message_added_reactions")) { return promise.set_error(Status::Error(400, "Message not found")); } @@ -1025,19 +940,19 @@ void get_message_added_reactions(Td *td, FullMessageId full_message_id, string r } td->create_handler(std::move(promise)) - ->send(full_message_id, std::move(reaction), std::move(offset), limit); + ->send(full_message_id, std::move(reaction_type), std::move(offset), limit); } -void set_default_reaction(Td *td, string reaction, Promise &&promise) { - if (reaction.empty()) { +void set_default_reaction(Td *td, ReactionType reaction_type, Promise &&promise) { + if (reaction_type.is_empty()) { return promise.set_error(Status::Error(400, "Default reaction must be non-empty")); } - if (!is_custom_reaction(reaction) && !td->stickers_manager_->is_active_reaction(reaction)) { + if (!reaction_type.is_custom_reaction() && !td->stickers_manager_->is_active_reaction(reaction_type)) { return promise.set_error(Status::Error(400, "Can't set incative reaction as default")); } - if (td->option_manager_->get_option_string("default_reaction", "-") != reaction) { - td->option_manager_->set_option_string("default_reaction", reaction); + if (td->option_manager_->get_option_string("default_reaction", "-") != reaction_type.get_string()) { + td->option_manager_->set_option_string("default_reaction", reaction_type.get_string()); if (!td->option_manager_->get_option_boolean("default_reaction_needs_sync")) { td->option_manager_->set_option_boolean("default_reaction_needs_sync", true); send_set_default_reaction_query(td); @@ -1047,14 +962,8 @@ void set_default_reaction(Td *td, string reaction, Promise &&promise) { } void send_set_default_reaction_query(Td *td) { - td->create_handler()->send(td->option_manager_->get_option_string("default_reaction")); -} - -td_api::object_ptr get_update_default_reaction_type(const string &default_reaction) { - if (default_reaction.empty()) { - return nullptr; - } - return td_api::make_object(get_reaction_type_object(default_reaction)); + td->create_handler()->send( + ReactionType(td->option_manager_->get_option_string("default_reaction"))); } void report_message_reactions(Td *td, FullMessageId full_message_id, DialogId chooser_dialog_id, @@ -1088,38 +997,16 @@ void report_message_reactions(Td *td, FullMessageId full_message_id, DialogId ch td->create_handler(std::move(promise))->send(dialog_id, message_id, chooser_dialog_id); } -vector get_recent_reactions(Td *td) { +vector get_recent_reactions(Td *td) { return td->stickers_manager_->get_recent_reactions(); } -vector get_top_reactions(Td *td) { +vector get_top_reactions(Td *td) { return td->stickers_manager_->get_top_reactions(); } -void add_recent_reaction(Td *td, const string &reaction) { - td->stickers_manager_->add_recent_reaction(reaction); -} - -int64 get_reactions_hash(const vector &reactions) { - vector numbers; - for (auto &reaction : reactions) { - if (is_custom_reaction(reaction)) { - auto custom_emoji_id = static_cast(get_custom_emoji_id(reaction)); - numbers.push_back(custom_emoji_id >> 32); - numbers.push_back(custom_emoji_id & 0xFFFFFFFF); - } else { - auto emoji = remove_emoji_selectors(reaction); - unsigned char hash[16]; - md5(emoji, {hash, sizeof(hash)}); - auto get = [hash](int num) { - return static_cast(hash[num]); - }; - - numbers.push_back(0); - numbers.push_back(static_cast((get(0) << 24) + (get(1) << 16) + (get(2) << 8) + get(3))); - } - } - return get_vector_hash(numbers); +void add_recent_reaction(Td *td, const ReactionType &reaction_type) { + td->stickers_manager_->add_recent_reaction(reaction_type); } } // namespace td diff --git a/td/telegram/MessageReaction.h b/td/telegram/MessageReaction.h index 5f8729909..f9c761694 100644 --- a/td/telegram/MessageReaction.h +++ b/td/telegram/MessageReaction.h @@ -11,6 +11,7 @@ #include "td/telegram/FullMessageId.h" #include "td/telegram/MessageId.h" #include "td/telegram/MinChannel.h" +#include "td/telegram/ReactionType.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" #include "td/telegram/UserId.h" @@ -33,7 +34,7 @@ class MessageReaction { static constexpr size_t MAX_RECENT_CHOOSERS = 3; - string reaction_; + ReactionType reaction_type_; int32 choose_count_ = 0; bool is_chosen_ = false; DialogId my_recent_chooser_dialog_id_; @@ -46,7 +47,7 @@ class MessageReaction { friend struct MessageReactions; - MessageReaction(string reaction, int32 choose_count, bool is_chosen, DialogId my_recent_chooser_dialog_id, + MessageReaction(ReactionType reaction_type, int32 choose_count, bool is_chosen, DialogId my_recent_chooser_dialog_id, vector &&recent_chooser_dialog_ids, vector> &&recent_chooser_min_channels); @@ -94,8 +95,8 @@ class MessageReaction { public: MessageReaction() = default; - const string &get_reaction() const { - return reaction_; + const ReactionType &get_reaction_type() const { + return reaction_type_; } template @@ -114,7 +115,7 @@ inline bool operator!=(const MessageReaction &lhs, const MessageReaction &rhs) { StringBuilder &operator<<(StringBuilder &string_builder, const MessageReaction &reaction); class UnreadMessageReaction { - string reaction_; + ReactionType reaction_type_; DialogId sender_dialog_id_; bool is_big_ = false; @@ -125,8 +126,8 @@ class UnreadMessageReaction { public: UnreadMessageReaction() = default; - UnreadMessageReaction(string reaction, DialogId sender_dialog_id, bool is_big) - : reaction_(std::move(reaction)), sender_dialog_id_(sender_dialog_id), is_big_(is_big) { + UnreadMessageReaction(ReactionType reaction_type, DialogId sender_dialog_id, bool is_big) + : reaction_type_(std::move(reaction_type)), sender_dialog_id_(sender_dialog_id), is_big_(is_big) { } td_api::object_ptr get_unread_reaction_object(Td *td) const; @@ -149,7 +150,7 @@ StringBuilder &operator<<(StringBuilder &string_builder, const UnreadMessageReac struct MessageReactions { vector reactions_; vector unread_reactions_; - vector chosen_reaction_order_; + vector chosen_reaction_order_; bool is_min_ = false; bool need_polling_ = true; bool can_get_added_reactions_ = false; @@ -160,25 +161,26 @@ struct MessageReactions { tl_object_ptr &&reactions, bool is_bot); - MessageReaction *get_reaction(const string &reaction); + MessageReaction *get_reaction(const ReactionType &reaction_type); - const MessageReaction *get_reaction(const string &reaction) const; + const MessageReaction *get_reaction(const ReactionType &reaction_type) const; void update_from(const MessageReactions &old_reactions); - bool add_reaction(const string &reaction, bool is_big, DialogId my_dialog_id, bool have_recent_choosers); + bool add_reaction(const ReactionType &reaction_type, bool is_big, DialogId my_dialog_id, bool have_recent_choosers); - bool remove_reaction(const string &reaction, DialogId my_dialog_id); + bool remove_reaction(const ReactionType &reaction_type, DialogId my_dialog_id); - void sort_reactions(const FlatHashMap &active_reaction_pos); + void sort_reactions(const FlatHashMap &active_reaction_pos); void fix_chosen_reaction(); void fix_my_recent_chooser_dialog_id(DialogId my_dialog_id); - vector get_chosen_reactions() const; + vector get_chosen_reaction_types() const; - bool are_consistent_with_list(const string &reaction, FlatHashMap> reactions, + bool are_consistent_with_list(const ReactionType &reaction_type, + FlatHashMap, ReactionTypeHash> reaction_types, int32 total_count) const; vector> get_message_reactions_object(Td *td, UserId my_user_id, @@ -201,48 +203,32 @@ struct MessageReactions { void parse(ParserT &parser); private: - bool do_remove_reaction(const string &reaction); + bool do_remove_reaction(const ReactionType &reaction_type); }; StringBuilder &operator<<(StringBuilder &string_builder, const MessageReactions &reactions); StringBuilder &operator<<(StringBuilder &string_builder, const unique_ptr &reactions); -telegram_api::object_ptr get_input_reaction(const string &reaction); - -td_api::object_ptr get_reaction_type_object(const string &reaction); - -string get_message_reaction_string(const telegram_api::object_ptr &reaction); - -string get_message_reaction_string(const td_api::object_ptr &type); - -bool is_custom_reaction(const string &reaction); - -bool is_active_reaction(const string &reaction, const FlatHashMap &active_reaction_pos); - void reload_message_reactions(Td *td, DialogId dialog_id, vector &&message_ids); -void send_message_reaction(Td *td, FullMessageId full_message_id, vector reactions, bool is_big, +void send_message_reaction(Td *td, FullMessageId full_message_id, vector reaction_types, bool is_big, bool add_to_recent, Promise &&promise); -void get_message_added_reactions(Td *td, FullMessageId full_message_id, string reaction, string offset, int32 limit, - Promise> &&promise); +void get_message_added_reactions(Td *td, FullMessageId full_message_id, ReactionType reaction_type, string offset, + int32 limit, Promise> &&promise); -void set_default_reaction(Td *td, string reaction, Promise &&promise); +void set_default_reaction(Td *td, ReactionType reaction_type, Promise &&promise); void send_set_default_reaction_query(Td *td); -td_api::object_ptr get_update_default_reaction_type(const string &default_reaction); - void report_message_reactions(Td *td, FullMessageId full_message_id, DialogId chooser_dialog_id, Promise &&promise); -vector get_recent_reactions(Td *td); +vector get_recent_reactions(Td *td); -vector get_top_reactions(Td *td); +vector get_top_reactions(Td *td); -void add_recent_reaction(Td *td, const string &reaction); - -int64 get_reactions_hash(const vector &reactions); +void add_recent_reaction(Td *td, const ReactionType &reaction_type); } // namespace td diff --git a/td/telegram/MessageReaction.hpp b/td/telegram/MessageReaction.hpp index 529b82fcf..295343fc1 100644 --- a/td/telegram/MessageReaction.hpp +++ b/td/telegram/MessageReaction.hpp @@ -8,6 +8,7 @@ #include "td/telegram/MessageReaction.h" #include "td/telegram/MinChannel.hpp" +#include "td/telegram/ReactionType.hpp" #include "td/utils/algorithm.h" #include "td/utils/common.h" @@ -27,7 +28,7 @@ void MessageReaction::store(StorerT &storer) const { STORE_FLAG(has_recent_chooser_min_channels); STORE_FLAG(has_my_recent_chooser_dialog_id); END_STORE_FLAGS(); - td::store(reaction_, storer); + td::store(reaction_type_, storer); td::store(choose_count_, storer); if (has_recent_chooser_dialog_ids) { td::store(recent_chooser_dialog_ids_, storer); @@ -51,7 +52,7 @@ void MessageReaction::parse(ParserT &parser) { PARSE_FLAG(has_recent_chooser_min_channels); PARSE_FLAG(has_my_recent_chooser_dialog_id); END_PARSE_FLAGS(); - td::parse(reaction_, parser); + td::parse(reaction_type_, parser); td::parse(choose_count_, parser); if (has_recent_chooser_dialog_ids) { td::parse(recent_chooser_dialog_ids_, parser); @@ -65,7 +66,7 @@ void MessageReaction::parse(ParserT &parser) { CHECK(td::contains(recent_chooser_dialog_ids_, my_recent_chooser_dialog_id_)); } CHECK(!is_empty()); - CHECK(!reaction_.empty()); + CHECK(!reaction_type_.is_empty()); } template @@ -73,7 +74,7 @@ void UnreadMessageReaction::store(StorerT &storer) const { BEGIN_STORE_FLAGS(); STORE_FLAG(is_big_); END_STORE_FLAGS(); - td::store(reaction_, storer); + td::store(reaction_type_, storer); td::store(sender_dialog_id_, storer); } @@ -82,9 +83,9 @@ void UnreadMessageReaction::parse(ParserT &parser) { BEGIN_PARSE_FLAGS(); PARSE_FLAG(is_big_); END_PARSE_FLAGS(); - td::parse(reaction_, parser); + td::parse(reaction_type_, parser); td::parse(sender_dialog_id_, parser); - CHECK(!reaction_.empty()); + CHECK(!reaction_type_.is_empty()); } template diff --git a/td/telegram/MessagesManager.cpp b/td/telegram/MessagesManager.cpp index 3ca17758f..9b6cc59b6 100644 --- a/td/telegram/MessagesManager.cpp +++ b/td/telegram/MessagesManager.cpp @@ -5766,9 +5766,9 @@ void MessagesManager::Dialog::parse(ParserT &parser) { if (has_available_reactions) { parse(available_reactions, parser); } else if (has_legacy_available_reactions) { - vector legacy_available_reactions; - parse(legacy_available_reactions, parser); - available_reactions = ChatReactions(std::move(legacy_available_reactions)); + vector legacy_available_reaction_types; + parse(legacy_available_reaction_types, parser); + available_reactions = ChatReactions(std::move(legacy_available_reaction_types)); } if (has_available_reactions_generation) { parse(available_reactions_generation, parser); @@ -6846,8 +6846,9 @@ void MessagesManager::update_message_reactions(FullMessageId full_message_id, update_message_interaction_info(full_message_id, -1, -1, false, nullptr, true, std::move(reactions)); } -void MessagesManager::on_get_message_reaction_list(FullMessageId full_message_id, const string &reaction, - FlatHashMap> reactions, int32 total_count) { +void MessagesManager::on_get_message_reaction_list( + FullMessageId full_message_id, const ReactionType &reaction_type, + FlatHashMap, ReactionTypeHash> reaction_types, int32 total_count) { const Message *m = get_message_force(full_message_id, "on_get_message_reaction_list"); if (m == nullptr || m->reactions == nullptr) { return; @@ -6855,7 +6856,7 @@ void MessagesManager::on_get_message_reaction_list(FullMessageId full_message_id // it's impossible to use received reactions to update message reactions, because there is no way to find, // which reactions are chosen by the current user, so just reload message reactions for consistency - if (m->reactions->are_consistent_with_list(reaction, std::move(reactions), total_count)) { + if (m->reactions->are_consistent_with_list(reaction_type, std::move(reaction_types), total_count)) { return; } @@ -8454,19 +8455,19 @@ void MessagesManager::hide_dialog_message_reactions(Dialog *d) { } } -void MessagesManager::set_active_reactions(vector active_reactions) { - if (active_reactions == active_reactions_) { +void MessagesManager::set_active_reactions(vector active_reaction_types) { + if (active_reaction_types == active_reaction_types_) { return; } - LOG(INFO) << "Set active reactions to " << active_reactions; - bool is_changed = active_reactions != active_reactions_; - active_reactions_ = std::move(active_reactions); + LOG(INFO) << "Set active reactions to " << active_reaction_types; + bool is_changed = active_reaction_types != active_reaction_types_; + active_reaction_types_ = std::move(active_reaction_types); auto old_active_reaction_pos_ = std::move(active_reaction_pos_); active_reaction_pos_.clear(); - for (size_t i = 0; i < active_reactions_.size(); i++) { - active_reaction_pos_[active_reactions_[i]] = i; + for (size_t i = 0; i < active_reaction_types_.size(); i++) { + active_reaction_pos_[active_reaction_types_[i]] = i; } if (td_->auth_manager_->is_bot()) { @@ -23787,22 +23788,22 @@ Result> MessagesManager::get_mess LOG(INFO) << "Have available reactions " << available_reactions << " to be sorted by top reactions " << top_reactions << " and recent reactions " << recent_reactions; if (active_reactions.allow_custom_ && active_reactions.allow_all_) { - for (auto &reaction : recent_reactions) { - if (is_custom_reaction(reaction)) { + for (auto &reaction_type : recent_reactions) { + if (reaction_type.is_custom_reaction()) { show_premium = true; } } - for (auto &reaction : top_reactions) { - if (is_custom_reaction(reaction)) { + for (auto &reaction_type : top_reactions) { + if (reaction_type.is_custom_reaction()) { show_premium = true; } } } - FlatHashSet all_available_reactions; - for (const auto &reaction : available_reactions.reactions_) { - CHECK(!reaction.empty()); - all_available_reactions.insert(reaction); + FlatHashSet all_available_reaction_types; + for (const auto &reaction_type : available_reactions.reaction_types_) { + CHECK(!reaction_type.is_empty()); + all_available_reaction_types.insert(reaction_type); } vector> top_reaction_objects; @@ -23810,22 +23811,22 @@ Result> MessagesManager::get_mess vector> popular_reaction_objects; vector> last_reaction_objects; - FlatHashSet added_custom_reactions; + FlatHashSet added_custom_reaction_types; auto add_reactions = [&](vector> &reaction_objects, - const vector &reactions) { - for (auto &reaction : reactions) { - if (all_available_reactions.erase(reaction) != 0) { + const vector &reaction_types) { + for (auto &reaction_type : reaction_types) { + if (all_available_reaction_types.erase(reaction_type) != 0) { // add available reaction - if (is_custom_reaction(reaction)) { - added_custom_reactions.insert(reaction); + if (reaction_type.is_custom_reaction()) { + added_custom_reaction_types.insert(reaction_type); } reaction_objects.push_back( - td_api::make_object(get_reaction_type_object(reaction), false)); - } else if (is_custom_reaction(reaction) && available_reactions.allow_custom_ && - added_custom_reactions.insert(reaction).second) { + td_api::make_object(reaction_type.get_reaction_type_object(), false)); + } else if (reaction_type.is_custom_reaction() && available_reactions.allow_custom_ && + added_custom_reaction_types.insert(reaction_type).second) { // add implicitly available custom reaction reaction_objects.push_back( - td_api::make_object(get_reaction_type_object(reaction), !is_premium)); + td_api::make_object(reaction_type.get_reaction_type_object(), !is_premium)); } else { // skip the reaction } @@ -23843,8 +23844,8 @@ Result> MessagesManager::get_mess } else { add_reactions(top_reaction_objects, top_reactions); } - add_reactions(last_reaction_objects, active_reactions_); - add_reactions(last_reaction_objects, available_reactions.reactions_); + add_reactions(last_reaction_objects, active_reaction_types_); + add_reactions(last_reaction_objects, available_reactions.reaction_types_); if (show_premium) { if (recent_reactions.empty()) { @@ -23864,7 +23865,7 @@ Result> MessagesManager::get_mess append(top_reaction_objects, std::move(last_reaction_objects)); } - CHECK(all_available_reactions.empty()); + CHECK(all_available_reaction_types.empty()); return td_api::make_object( std::move(top_reaction_objects), std::move(recent_reaction_objects), std::move(popular_reaction_objects), @@ -23899,16 +23900,16 @@ ChatReactions MessagesManager::get_message_available_reactions(const Dialog *d, } if (active_reactions.allow_all_) { - active_reactions.reactions_ = active_reactions_; + active_reactions.reaction_types_ = active_reaction_types_; active_reactions.allow_all_ = false; } if (m->reactions != nullptr) { for (const auto &reaction : m->reactions->reactions_) { // an already used reaction can be added if it is an active reaction - const string &reaction_str = reaction.get_reaction(); - if (can_use_reactions && is_active_reaction(reaction_str, active_reaction_pos_) && - !td::contains(active_reactions.reactions_, reaction_str)) { - active_reactions.reactions_.push_back(reaction_str); + const auto &reaction_type = reaction.get_reaction_type(); + if (can_use_reactions && reaction_type.is_active_reaction(active_reaction_pos_) && + !td::contains(active_reactions.reaction_types_, reaction_type)) { + active_reactions.reaction_types_.push_back(reaction_type); } } } @@ -23918,7 +23919,7 @@ ChatReactions MessagesManager::get_message_available_reactions(const Dialog *d, return active_reactions; } -void MessagesManager::add_message_reaction(FullMessageId full_message_id, string reaction, bool is_big, +void MessagesManager::add_message_reaction(FullMessageId full_message_id, ReactionType reaction_type, bool is_big, bool add_to_recent, Promise &&promise) { auto dialog_id = full_message_id.get_dialog_id(); Dialog *d = get_dialog_force(dialog_id, "add_message_reaction"); @@ -23931,7 +23932,7 @@ void MessagesManager::add_message_reaction(FullMessageId full_message_id, string return promise.set_error(Status::Error(400, "Message not found")); } - if (!get_message_available_reactions(d, m, true).is_allowed_reaction(reaction)) { + if (!get_message_available_reactions(d, m, true).is_allowed_reaction_type(reaction_type)) { return promise.set_error(Status::Error(400, "The reaction isn't available for the message")); } @@ -23944,18 +23945,19 @@ void MessagesManager::add_message_reaction(FullMessageId full_message_id, string auto my_dialog_id = d->default_send_message_as_dialog_id.is_valid() ? d->default_send_message_as_dialog_id : get_my_dialog_id(); - if (!m->reactions->add_reaction(reaction, is_big, my_dialog_id, have_recent_choosers)) { + if (!m->reactions->add_reaction(reaction_type, is_big, my_dialog_id, have_recent_choosers)) { return promise.set_value(Unit()); } if (add_to_recent) { - add_recent_reaction(td_, reaction); + add_recent_reaction(td_, reaction_type); } set_message_reactions(d, m, is_big, add_to_recent, std::move(promise)); } -void MessagesManager::remove_message_reaction(FullMessageId full_message_id, string reaction, Promise &&promise) { +void MessagesManager::remove_message_reaction(FullMessageId full_message_id, ReactionType reaction_type, + Promise &&promise) { auto dialog_id = full_message_id.get_dialog_id(); Dialog *d = get_dialog_force(dialog_id, "remove_message_reaction"); if (d == nullptr) { @@ -23967,13 +23969,13 @@ void MessagesManager::remove_message_reaction(FullMessageId full_message_id, str return promise.set_error(Status::Error(400, "Message not found")); } - if (reaction.empty()) { + if (reaction_type.is_empty()) { return promise.set_error(Status::Error(400, "Invalid reaction specified")); } auto my_dialog_id = d->default_send_message_as_dialog_id.is_valid() ? d->default_send_message_as_dialog_id : get_my_dialog_id(); - if (m->reactions == nullptr || !m->reactions->remove_reaction(reaction, my_dialog_id)) { + if (m->reactions == nullptr || !m->reactions->remove_reaction(reaction_type, my_dialog_id)) { return promise.set_value(Unit()); } @@ -23999,7 +24001,7 @@ void MessagesManager::set_message_reactions(Dialog *d, Message *m, bool is_big, send_closure(actor_id, &MessagesManager::on_set_message_reactions, full_message_id, std::move(result), std::move(promise)); }); - send_message_reaction(td_, full_message_id, m->reactions->get_chosen_reactions(), is_big, add_to_recent, + send_message_reaction(td_, full_message_id, m->reactions->get_chosen_reaction_types(), is_big, add_to_recent, std::move(query_promise)); } @@ -33833,7 +33835,7 @@ void MessagesManager::set_dialog_available_reactions( ChatReactions available_reactions(std::move(available_reactions_ptr), !is_broadcast_channel(dialog_id)); auto active_reactions = get_active_reactions(available_reactions); - if (active_reactions.reactions_.size() != available_reactions.reactions_.size()) { + if (active_reactions.reaction_types_.size() != available_reactions.reaction_types_.size()) { return promise.set_error(Status::Error(400, "Invalid reactions specified")); } available_reactions = std::move(active_reactions); diff --git a/td/telegram/MessagesManager.h b/td/telegram/MessagesManager.h index 45eb09eab..678d8bb2c 100644 --- a/td/telegram/MessagesManager.h +++ b/td/telegram/MessagesManager.h @@ -54,6 +54,7 @@ #include "td/telegram/NotificationSettingsScope.h" #include "td/telegram/OrderedMessage.h" #include "td/telegram/Photo.h" +#include "td/telegram/ReactionType.h" #include "td/telegram/RecentDialogList.h" #include "td/telegram/ReplyMarkup.h" #include "td/telegram/RestrictionReason.h" @@ -355,8 +356,9 @@ class MessagesManager final : public Actor { void try_reload_message_reactions(DialogId dialog_id, bool is_finished); - void on_get_message_reaction_list(FullMessageId full_message_id, const string &reaction, - FlatHashMap> reactions, int32 total_count); + void on_get_message_reaction_list(FullMessageId full_message_id, const ReactionType &reaction_type, + FlatHashMap, ReactionTypeHash> reaction_types, + int32 total_count); void on_update_message_interaction_info(FullMessageId full_message_id, int32 view_count, int32 forward_count, bool has_reply_info, @@ -566,7 +568,7 @@ class MessagesManager final : public Actor { void set_dialog_description(DialogId dialog_id, const string &description, Promise &&promise); - void set_active_reactions(vector active_reactions); + void set_active_reactions(vector active_reaction_types); void set_dialog_available_reactions(DialogId dialog_id, td_api::object_ptr &&available_reactions_ptr, @@ -856,10 +858,10 @@ class MessagesManager final : public Actor { Result> get_message_available_reactions(FullMessageId full_message_id, int32 row_size); - void add_message_reaction(FullMessageId full_message_id, string reaction, bool is_big, bool add_to_recent, + void add_message_reaction(FullMessageId full_message_id, ReactionType reaction_type, bool is_big, bool add_to_recent, Promise &&promise); - void remove_message_reaction(FullMessageId full_message_id, string reaction, Promise &&promise); + void remove_message_reaction(FullMessageId full_message_id, ReactionType reaction_type, Promise &&promise); void get_message_public_forwards(FullMessageId full_message_id, string offset, int32 limit, Promise> &&promise); @@ -3697,8 +3699,8 @@ class MessagesManager final : public Actor { FlatHashMap pending_read_reactions_; - vector active_reactions_; - FlatHashMap active_reaction_pos_; + vector active_reaction_types_; + FlatHashMap active_reaction_pos_; FlatHashMap>, PendingGetHistoryQueryHash> get_history_queries_; diff --git a/td/telegram/OptionManager.cpp b/td/telegram/OptionManager.cpp index 0047bd7ff..d8b59a4ef 100644 --- a/td/telegram/OptionManager.cpp +++ b/td/telegram/OptionManager.cpp @@ -17,10 +17,10 @@ #include "td/telegram/Global.h" #include "td/telegram/JsonValue.h" #include "td/telegram/LanguagePackManager.h" -#include "td/telegram/MessageReaction.h" #include "td/telegram/net/MtprotoHeader.h" #include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/NotificationManager.h" +#include "td/telegram/ReactionType.h" #include "td/telegram/StateManager.h" #include "td/telegram/StickersManager.h" #include "td/telegram/StorageManager.h" @@ -315,7 +315,7 @@ bool OptionManager::is_internal_option(Slice name) { td_api::object_ptr OptionManager::get_internal_option_update(Slice name) const { if (name == "default_reaction") { - return get_update_default_reaction_type(get_option_string(name)); + return ReactionType(get_option_string(name)).get_update_default_reaction_type(); } if (name == "otherwise_relogin_days") { auto days = narrow_cast(get_option_integer(name)); diff --git a/td/telegram/ReactionType.cpp b/td/telegram/ReactionType.cpp new file mode 100644 index 000000000..b6e582497 --- /dev/null +++ b/td/telegram/ReactionType.cpp @@ -0,0 +1,154 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/ReactionType.h" + +#include "td/telegram/misc.h" + +#include "td/utils/as.h" +#include "td/utils/base64.h" +#include "td/utils/crypto.h" +#include "td/utils/emoji.h" +#include "td/utils/SliceBuilder.h" +#include "td/utils/utf8.h" + +namespace td { + +static int64 get_custom_emoji_id(const string &reaction) { + auto r_decoded = base64_decode(Slice(&reaction[1], reaction.size() - 1)); + CHECK(r_decoded.is_ok()); + CHECK(r_decoded.ok().size() == 8); + return as(r_decoded.ok().c_str()); +} + +static string get_custom_emoji_string(int64 custom_emoji_id) { + char s[8]; + as(&s) = custom_emoji_id; + return PSTRING() << '#' << base64_encode(Slice(s, 8)); +} + +ReactionType::ReactionType(string &&emoji) : reaction_(std::move(emoji)) { +} + +ReactionType::ReactionType(const telegram_api::object_ptr &reaction) { + if (reaction == nullptr) { + return; + } + switch (reaction->get_id()) { + case telegram_api::reactionEmpty::ID: + break; + case telegram_api::reactionEmoji::ID: + reaction_ = static_cast(reaction.get())->emoticon_; + if (is_custom_reaction()) { + reaction_ = string(); + } + break; + case telegram_api::reactionCustomEmoji::ID: + reaction_ = + get_custom_emoji_string(static_cast(reaction.get())->document_id_); + break; + default: + UNREACHABLE(); + break; + } +} + +ReactionType::ReactionType(const td_api::object_ptr &type) { + if (type == nullptr) { + return; + } + switch (type->get_id()) { + case td_api::reactionTypeEmoji::ID: { + const string &emoji = static_cast(type.get())->emoji_; + if (!check_utf8(emoji)) { + break; + } + reaction_ = emoji; + if (is_custom_reaction()) { + reaction_ = string(); + break; + } + break; + } + case td_api::reactionTypeCustomEmoji::ID: + reaction_ = + get_custom_emoji_string(static_cast(type.get())->custom_emoji_id_); + break; + default: + UNREACHABLE(); + break; + } +} + +telegram_api::object_ptr ReactionType::get_input_reaction() const { + if (is_empty()) { + return telegram_api::make_object(); + } + if (is_custom_reaction()) { + return telegram_api::make_object(get_custom_emoji_id(reaction_)); + } + return telegram_api::make_object(reaction_); +} + +td_api::object_ptr ReactionType::get_reaction_type_object() const { + CHECK(!is_empty()); + if (is_custom_reaction()) { + return td_api::make_object(get_custom_emoji_id(reaction_)); + } + return td_api::make_object(reaction_); +} + +td_api::object_ptr ReactionType::get_update_default_reaction_type() const { + if (is_empty()) { + return nullptr; + } + return td_api::make_object(get_reaction_type_object()); +} + +bool ReactionType::is_custom_reaction() const { + return reaction_[0] == '#'; +} + +bool ReactionType::is_active_reaction( + const FlatHashMap &active_reaction_pos) const { + return !reaction_.empty() && (is_custom_reaction() || active_reaction_pos.count(*this) > 0); +} + +bool operator<(const ReactionType &lhs, const ReactionType &rhs) { + return lhs.reaction_ < rhs.reaction_; +} + +bool operator==(const ReactionType &lhs, const ReactionType &rhs) { + return lhs.reaction_ == rhs.reaction_; +} + +StringBuilder &operator<<(StringBuilder &string_builder, const ReactionType &reaction_type) { + return string_builder << reaction_type.reaction_; +} + +int64 get_reaction_types_hash(const vector &reaction_types) { + vector numbers; + for (auto &reaction_type : reaction_types) { + if (reaction_type.is_custom_reaction()) { + auto custom_emoji_id = static_cast(get_custom_emoji_id(reaction_type.get_string())); + numbers.push_back(custom_emoji_id >> 32); + numbers.push_back(custom_emoji_id & 0xFFFFFFFF); + } else { + auto emoji = remove_emoji_selectors(reaction_type.get_string()); + unsigned char hash[16]; + md5(emoji, {hash, sizeof(hash)}); + auto get = [hash](int num) { + return static_cast(hash[num]); + }; + + numbers.push_back(0); + numbers.push_back(static_cast((get(0) << 24) + (get(1) << 16) + (get(2) << 8) + get(3))); + } + } + return get_vector_hash(numbers); +} + +} // namespace td diff --git a/td/telegram/ReactionType.h b/td/telegram/ReactionType.h new file mode 100644 index 000000000..30873ddea --- /dev/null +++ b/td/telegram/ReactionType.h @@ -0,0 +1,85 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/td_api.h" +#include "td/telegram/telegram_api.h" + +#include "td/utils/common.h" +#include "td/utils/FlatHashMap.h" +#include "td/utils/StringBuilder.h" + +namespace td { + +class Dependencies; + +class Td; + +class ReactionType { + string reaction_; + + friend bool operator<(const ReactionType &lhs, const ReactionType &rhs); + + friend bool operator==(const ReactionType &lhs, const ReactionType &rhs); + + friend StringBuilder &operator<<(StringBuilder &string_builder, const ReactionType &reaction_type); + + friend struct ReactionTypeHash; + + public: + ReactionType() = default; + + explicit ReactionType(string &&emoji); + + explicit ReactionType(const telegram_api::object_ptr &reaction); + + explicit ReactionType(const td_api::object_ptr &type); + + telegram_api::object_ptr get_input_reaction() const; + + td_api::object_ptr get_reaction_type_object() const; + + td_api::object_ptr get_update_default_reaction_type() const; + + bool is_custom_reaction() const; + + bool is_active_reaction(const FlatHashMap &active_reaction_pos) const; + + bool is_empty() const { + return reaction_.empty(); + } + + const string &get_string() const { + return reaction_; + } + + template + void store(StorerT &storer) const; + + template + void parse(ParserT &parser); +}; + +struct ReactionTypeHash { + uint32 operator()(const ReactionType &reaction_type) const { + return Hash()(reaction_type.reaction_); + } +}; + +bool operator<(const ReactionType &lhs, const ReactionType &rhs); + +bool operator==(const ReactionType &lhs, const ReactionType &rhs); + +inline bool operator!=(const ReactionType &lhs, const ReactionType &rhs) { + return !(lhs == rhs); +} + +StringBuilder &operator<<(StringBuilder &string_builder, const ReactionType &reaction_type); + +int64 get_reaction_types_hash(const vector &reaction_types); + +} // namespace td diff --git a/td/telegram/ReactionType.hpp b/td/telegram/ReactionType.hpp new file mode 100644 index 000000000..fe3734071 --- /dev/null +++ b/td/telegram/ReactionType.hpp @@ -0,0 +1,27 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/ReactionType.h" + +#include "td/utils/common.h" +#include "td/utils/tl_helpers.h" + +namespace td { + +template +void ReactionType::store(StorerT &storer) const { + CHECK(!is_empty()); + td::store(reaction_, storer); +} + +template +void ReactionType::parse(ParserT &parser) { + td::parse(reaction_, parser); +} + +} // namespace td diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 823794836..767c8dfda 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -1812,12 +1812,13 @@ void StickersManager::init() { td_api::object_ptr StickersManager::get_emoji_reaction_object(const string &emoji) const { for (auto &reaction : reactions_.reactions_) { - if (reaction.reaction_ == emoji) { + if (reaction.reaction_type_.get_string() == emoji) { return td_api::make_object( - reaction.reaction_, reaction.title_, reaction.is_active_, get_sticker_object(reaction.static_icon_), - get_sticker_object(reaction.appear_animation_), get_sticker_object(reaction.select_animation_), - get_sticker_object(reaction.activate_animation_), get_sticker_object(reaction.effect_animation_), - get_sticker_object(reaction.around_animation_), get_sticker_object(reaction.center_animation_)); + reaction.reaction_type_.get_string(), reaction.title_, reaction.is_active_, + get_sticker_object(reaction.static_icon_), get_sticker_object(reaction.appear_animation_), + get_sticker_object(reaction.select_animation_), get_sticker_object(reaction.activate_animation_), + get_sticker_object(reaction.effect_animation_), get_sticker_object(reaction.around_animation_), + get_sticker_object(reaction.center_animation_)); } } return nullptr; @@ -1833,47 +1834,47 @@ void StickersManager::get_emoji_reaction(const string &emoji, promise.set_value(get_emoji_reaction_object(emoji)); } -vector StickersManager::get_recent_reactions() { +vector StickersManager::get_recent_reactions() { load_recent_reactions(); - return recent_reactions_.reactions_; + return recent_reactions_.reaction_types_; } -vector StickersManager::get_top_reactions() { +vector StickersManager::get_top_reactions() { load_top_reactions(); - return top_reactions_.reactions_; + return top_reactions_.reaction_types_; } -void StickersManager::add_recent_reaction(const string &reaction) { +void StickersManager::add_recent_reaction(const ReactionType &reaction_type) { load_recent_reactions(); - auto &reactions = recent_reactions_.reactions_; - if (!reactions.empty() && reactions[0] == reaction) { + auto &reactions = recent_reactions_.reaction_types_; + if (!reactions.empty() && reactions[0] == reaction_type) { return; } - auto it = std::find(reactions.begin(), reactions.end(), reaction); + auto it = std::find(reactions.begin(), reactions.end(), reaction_type); if (it == reactions.end()) { if (static_cast(reactions.size()) == MAX_RECENT_REACTIONS) { - reactions.back() = reaction; + reactions.back() = reaction_type; } else { - reactions.push_back(reaction); + reactions.push_back(reaction_type); } it = reactions.end() - 1; } std::rotate(reactions.begin(), it, it + 1); - recent_reactions_.hash_ = get_reactions_hash(reactions); + recent_reactions_.hash_ = get_reaction_types_hash(reactions); } void StickersManager::clear_recent_reactions(Promise &&promise) { load_recent_reactions(); - if (recent_reactions_.reactions_.empty()) { + if (recent_reactions_.reaction_types_.empty()) { return promise.set_value(Unit()); } recent_reactions_.hash_ = 0; - recent_reactions_.reactions_.clear(); + recent_reactions_.reaction_types_.clear(); td_->create_handler(std::move(promise))->send(); } @@ -4139,12 +4140,13 @@ void StickersManager::on_get_special_sticker_set(const SpecialStickerSetType &ty td_api::object_ptr StickersManager::get_update_active_emoji_reactions_object() const { - return td_api::make_object(vector(active_reactions_)); + return td_api::make_object( + transform(active_reaction_types_, [](const ReactionType &reaction_type) { return reaction_type.get_string(); })); } void StickersManager::save_active_reactions() { - LOG(INFO) << "Save " << active_reactions_.size() << " active reactions"; - G()->td_db()->get_binlog_pmc()->set("active_reactions", log_event_store(active_reactions_).as_slice().str()); + LOG(INFO) << "Save " << active_reaction_types_.size() << " active reactions"; + G()->td_db()->get_binlog_pmc()->set("active_reactions", log_event_store(active_reaction_types_).as_slice().str()); } void StickersManager::save_reactions() { @@ -4154,34 +4156,34 @@ void StickersManager::save_reactions() { } void StickersManager::save_recent_reactions() { - LOG(INFO) << "Save " << recent_reactions_.reactions_.size() << " recent reactions"; + LOG(INFO) << "Save " << recent_reactions_.reaction_types_.size() << " recent reactions"; are_recent_reactions_loaded_from_database_ = true; G()->td_db()->get_binlog_pmc()->set("recent_reactions", log_event_store(recent_reactions_).as_slice().str()); } void StickersManager::save_top_reactions() { - LOG(INFO) << "Save " << top_reactions_.reactions_.size() << " top reactions"; + LOG(INFO) << "Save " << top_reactions_.reaction_types_.size() << " top reactions"; are_top_reactions_loaded_from_database_ = true; G()->td_db()->get_binlog_pmc()->set("top_reactions", log_event_store(top_reactions_).as_slice().str()); } void StickersManager::load_active_reactions() { LOG(INFO) << "Loading active reactions"; - string active_reactions = G()->td_db()->get_binlog_pmc()->get("active_reactions"); - if (active_reactions.empty()) { + string active_reaction_types = G()->td_db()->get_binlog_pmc()->get("active_reactions"); + if (active_reaction_types.empty()) { return reload_reactions(); } - auto status = log_event_parse(active_reactions_, active_reactions); + auto status = log_event_parse(active_reaction_types_, active_reaction_types); if (status.is_error()) { LOG(ERROR) << "Can't load active reactions: " << status; - active_reactions_ = {}; + active_reaction_types_ = {}; return reload_reactions(); } - LOG(INFO) << "Successfully loaded " << active_reactions_.size() << " active reactions"; + LOG(INFO) << "Successfully loaded " << active_reaction_types_.size() << " active reactions"; - td_->messages_manager_->set_active_reactions(vector(active_reactions_)); + td_->messages_manager_->set_active_reactions(active_reaction_types_); send_closure(G()->td(), &Td::send_update, get_update_active_emoji_reactions_object()); } @@ -4204,8 +4206,8 @@ void StickersManager::load_reactions() { LOG(ERROR) << "Can't load available reactions: " << status; return reload_reactions(); } - for (auto &reaction : new_reactions.reactions_) { - if (!reaction.is_valid()) { + for (auto &reaction_type : new_reactions.reactions_) { + if (!reaction_type.is_valid()) { LOG(ERROR) << "Loaded invalid reaction"; return reload_reactions(); } @@ -4236,7 +4238,7 @@ void StickersManager::load_recent_reactions() { return reload_recent_reactions(); } - LOG(INFO) << "Successfully loaded " << recent_reactions_.reactions_.size() << " recent reactions"; + LOG(INFO) << "Successfully loaded " << recent_reactions_.reaction_types_.size() << " recent reactions"; } void StickersManager::load_top_reactions() { @@ -4258,26 +4260,26 @@ void StickersManager::load_top_reactions() { return reload_top_reactions(); } - LOG(INFO) << "Successfully loaded " << top_reactions_.reactions_.size() << " top reactions"; + LOG(INFO) << "Successfully loaded " << top_reactions_.reaction_types_.size() << " top reactions"; } void StickersManager::update_active_reactions() { - vector active_reactions; + vector active_reaction_types; for (auto &reaction : reactions_.reactions_) { if (reaction.is_active_) { - active_reactions.emplace_back(reaction.reaction_); + active_reaction_types.emplace_back(reaction.reaction_type_); } } - if (active_reactions == active_reactions_) { + if (active_reaction_types == active_reaction_types_) { return; } - active_reactions_ = active_reactions; + active_reaction_types_ = active_reaction_types; save_active_reactions(); send_closure(G()->td(), &Td::send_update, get_update_active_emoji_reactions_object()); - td_->messages_manager_->set_active_reactions(std::move(active_reactions)); + td_->messages_manager_->set_active_reactions(std::move(active_reaction_types)); } void StickersManager::on_get_available_reactions( @@ -4311,7 +4313,7 @@ void StickersManager::on_get_available_reactions( Reaction reaction; reaction.is_active_ = !available_reaction->inactive_; reaction.is_premium_ = available_reaction->premium_; - reaction.reaction_ = std::move(available_reaction->reaction_); + reaction.reaction_type_ = ReactionType(std::move(available_reaction->reaction_)); reaction.title_ = std::move(available_reaction->title_); reaction.static_icon_ = on_get_sticker_document(std::move(available_reaction->static_icon_), StickerFormat::Webp).second; @@ -4329,11 +4331,11 @@ void StickersManager::on_get_available_reactions( on_get_sticker_document(std::move(available_reaction->center_icon_), StickerFormat::Tgs).second; if (!reaction.is_valid()) { - LOG(ERROR) << "Receive invalid reaction " << reaction.reaction_; + LOG(ERROR) << "Receive invalid reaction " << reaction.reaction_type_; continue; } if (reaction.is_premium_) { - LOG(ERROR) << "Receive premium reaction " << reaction.reaction_; + LOG(ERROR) << "Receive premium reaction " << reaction.reaction_type_; continue; } @@ -4364,21 +4366,20 @@ void StickersManager::on_get_recent_reactions(tl_object_ptr(reactions_ptr); - auto new_reactions = - transform(reactions->reactions_, [](const telegram_api::object_ptr &reaction) { - return get_message_reaction_string(reaction); - }); - if (new_reactions == recent_reactions_.reactions_ && recent_reactions_.hash_ == reactions->hash_) { + auto new_reaction_types = transform( + reactions->reactions_, + [](const telegram_api::object_ptr &reaction) { return ReactionType(reaction); }); + if (new_reaction_types == recent_reactions_.reaction_types_ && recent_reactions_.hash_ == reactions->hash_) { LOG(INFO) << "Top reactions are not modified"; return; } - recent_reactions_.reactions_ = std::move(new_reactions); + recent_reactions_.reaction_types_ = std::move(new_reaction_types); recent_reactions_.hash_ = reactions->hash_; - auto expected_hash = get_reactions_hash(recent_reactions_.reactions_); + auto expected_hash = get_reaction_types_hash(recent_reactions_.reaction_types_); if (recent_reactions_.hash_ != expected_hash) { LOG(ERROR) << "Receive hash " << recent_reactions_.hash_ << " instead of " << expected_hash << " for reactions " - << recent_reactions_.reactions_; + << recent_reactions_.reaction_types_; } save_recent_reactions(); @@ -4401,15 +4402,14 @@ void StickersManager::on_get_top_reactions(tl_object_ptr(reactions_ptr); - auto new_reactions = - transform(reactions->reactions_, [](const telegram_api::object_ptr &reaction) { - return get_message_reaction_string(reaction); - }); - if (new_reactions == top_reactions_.reactions_ && top_reactions_.hash_ == reactions->hash_) { + auto new_reaction_types = transform( + reactions->reactions_, + [](const telegram_api::object_ptr &reaction) { return ReactionType(reaction); }); + if (new_reaction_types == top_reactions_.reaction_types_ && top_reactions_.hash_ == reactions->hash_) { LOG(INFO) << "Top reactions are not modified"; return; } - top_reactions_.reactions_ = std::move(new_reactions); + top_reactions_.reaction_types_ = std::move(new_reaction_types); top_reactions_.hash_ = reactions->hash_; save_top_reactions(); @@ -7229,9 +7229,9 @@ void StickersManager::send_update_animated_emoji_clicked(FullMessageId full_mess full_message_id.get_message_id().get(), get_sticker_object(sticker_id, false, true))); } -bool StickersManager::is_active_reaction(const string &reaction) const { +bool StickersManager::is_active_reaction(const ReactionType &reaction_type) const { for (auto &supported_reaction : reactions_.reactions_) { - if (supported_reaction.reaction_ == reaction) { + if (supported_reaction.reaction_type_ == reaction_type) { return supported_reaction.is_active_; } } @@ -10412,7 +10412,7 @@ void StickersManager::get_current_state(vector sticker, @@ -195,11 +196,11 @@ class StickersManager final : public Actor { void get_emoji_reaction(const string &emoji, Promise> &&promise); - vector get_recent_reactions(); + vector get_recent_reactions(); - vector get_top_reactions(); + vector get_top_reactions(); - void add_recent_reaction(const string &reaction); + void add_recent_reaction(const ReactionType &reaction_type); void clear_recent_reactions(Promise &&promise); @@ -584,7 +585,7 @@ class StickersManager final : public Actor { }; struct Reaction { - string reaction_; + ReactionType reaction_type_; string title_; bool is_active_ = false; bool is_premium_ = false; @@ -598,7 +599,7 @@ class StickersManager final : public Actor { bool is_valid() const { return static_icon_.is_valid() && appear_animation_.is_valid() && select_animation_.is_valid() && - activate_animation_.is_valid() && effect_animation_.is_valid() && !reaction_.empty(); + activate_animation_.is_valid() && effect_animation_.is_valid() && !reaction_type_.is_empty(); } template @@ -623,7 +624,7 @@ class StickersManager final : public Actor { struct ReactionList { int64 hash_ = 0; bool is_being_reloaded_ = false; - vector reactions_; + vector reaction_types_; template void store(StorerT &storer) const; @@ -1178,7 +1179,7 @@ class StickersManager final : public Actor { FlatHashMap>, FileIdHash> being_uploaded_files_; Reactions reactions_; - vector active_reactions_; + vector active_reaction_types_; ReactionList recent_reactions_; ReactionList top_reactions_; diff --git a/td/telegram/StickersManager.hpp b/td/telegram/StickersManager.hpp index 674f2e4e5..73f498119 100644 --- a/td/telegram/StickersManager.hpp +++ b/td/telegram/StickersManager.hpp @@ -476,7 +476,7 @@ void StickersManager::Reaction::store(StorerT &storer) const { STORE_FLAG(has_center_animation); STORE_FLAG(is_premium_); END_STORE_FLAGS(); - td::store(reaction_, storer); + td::store(reaction_type_, storer); td::store(title_, storer); stickers_manager->store_sticker(static_icon_, false, storer, "Reaction"); stickers_manager->store_sticker(appear_animation_, false, storer, "Reaction"); @@ -502,7 +502,7 @@ void StickersManager::Reaction::parse(ParserT &parser) { PARSE_FLAG(has_center_animation); PARSE_FLAG(is_premium_); END_PARSE_FLAGS(); - td::parse(reaction_, parser); + td::parse(reaction_type_, parser); td::parse(title_, parser); static_icon_ = stickers_manager->parse_sticker(false, parser); appear_animation_ = stickers_manager->parse_sticker(false, parser); @@ -545,24 +545,24 @@ void StickersManager::Reactions::parse(ParserT &parser) { template void StickersManager::ReactionList::store(StorerT &storer) const { - bool has_reactions = !reactions_.empty(); + bool has_reaction_types = !reaction_types_.empty(); BEGIN_STORE_FLAGS(); - STORE_FLAG(has_reactions); + STORE_FLAG(has_reaction_types); END_STORE_FLAGS(); - if (has_reactions) { - td::store(reactions_, storer); + if (has_reaction_types) { + td::store(reaction_types_, storer); td::store(hash_, storer); } } template void StickersManager::ReactionList::parse(ParserT &parser) { - bool has_reactions; + bool has_reaction_types; BEGIN_PARSE_FLAGS(); - PARSE_FLAG(has_reactions); + PARSE_FLAG(has_reaction_types); END_PARSE_FLAGS(); - if (has_reactions) { - td::parse(reactions_, parser); + if (has_reaction_types) { + td::parse(reaction_types_, parser); td::parse(hash_, parser); } } diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 3e2662daf..39c2f863a 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -107,6 +107,7 @@ #include "td/telegram/Premium.h" #include "td/telegram/PrivacyManager.h" #include "td/telegram/PublicDialogType.h" +#include "td/telegram/ReactionType.h" #include "td/telegram/ReportReason.h" #include "td/telegram/RequestActor.h" #include "td/telegram/ScopeNotificationSettings.h" @@ -5350,7 +5351,7 @@ void Td::on_request(uint64 id, td_api::addMessageReaction &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); messages_manager_->add_message_reaction({DialogId(request.chat_id_), MessageId(request.message_id_)}, - get_message_reaction_string(request.reaction_type_), request.is_big_, + ReactionType(request.reaction_type_), request.is_big_, request.update_recent_reactions_, std::move(promise)); } @@ -5358,7 +5359,7 @@ void Td::on_request(uint64 id, td_api::removeMessageReaction &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); messages_manager_->remove_message_reaction({DialogId(request.chat_id_), MessageId(request.message_id_)}, - get_message_reaction_string(request.reaction_type_), std::move(promise)); + ReactionType(request.reaction_type_), std::move(promise)); } void Td::on_request(uint64 id, td_api::getMessageAddedReactions &request) { @@ -5366,14 +5367,14 @@ void Td::on_request(uint64 id, td_api::getMessageAddedReactions &request) { CLEAN_INPUT_STRING(request.offset_); CREATE_REQUEST_PROMISE(); get_message_added_reactions(this, {DialogId(request.chat_id_), MessageId(request.message_id_)}, - get_message_reaction_string(request.reaction_type_), std::move(request.offset_), - request.limit_, std::move(promise)); + ReactionType(request.reaction_type_), std::move(request.offset_), request.limit_, + std::move(promise)); } void Td::on_request(uint64 id, td_api::setDefaultReactionType &request) { CHECK_IS_USER(); CREATE_OK_REQUEST_PROMISE(); - set_default_reaction(this, get_message_reaction_string(request.reaction_type_), std::move(promise)); + set_default_reaction(this, ReactionType(request.reaction_type_), std::move(promise)); } void Td::on_request(uint64 id, td_api::getMessagePublicForwards &request) {