diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index fc719b931..1e2b333e1 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -7216,8 +7216,11 @@ getUserProfilePhotos user_id:int53 offset:int32 limit:int32 = ChatPhotos; //@chat_id Chat identifier for which to return stickers. Available custom emoji stickers may be different for different chats getStickers sticker_type:StickerType query:string limit:int32 chat_id:int53 = Stickers; -//@description Searches for stickers from public sticker sets that correspond to a given emoji @emoji String representation of emoji; must be non-empty @limit The maximum number of stickers to be returned; 0-100 -searchStickers emoji:string limit:int32 = Stickers; +//@description Searches for stickers from public sticker sets that correspond to a given emoji +//@sticker_type Type of the stickers to return +//@emoji String representation of emoji; must be non-empty +//@limit The maximum number of stickers to be returned; 0-100 +searchStickers sticker_type:StickerType emoji:string limit:int32 = Stickers; //@description Returns premium stickers from regular sticker sets @limit The maximum number of stickers to be returned; 0-100 getPremiumStickers limit:int32 = Stickers; diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 9af21dec1..329f1da8e 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -238,6 +238,34 @@ class SearchStickersQuery final : public Td::ResultHandler { } }; +class SearchCustomEmojiQuery final : public Td::ResultHandler { + string emoji_; + + public: + void send(string &&emoji, int64 hash) { + emoji_ = std::move(emoji); + send_query(G()->net_query_creator().create(telegram_api::messages_searchCustomEmoji(emoji_, hash))); + } + + void on_result(BufferSlice packet) final { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for search custom emoji: " << to_string(ptr); + td_->stickers_manager_->on_find_custom_emojis_success(emoji_, std::move(ptr)); + } + + void on_error(Status status) final { + if (!G()->is_expected_error(status)) { + LOG(ERROR) << "Receive error for search stickers: " << status; + } + td_->stickers_manager_->on_find_custom_emojis_fail(emoji_, std::move(status)); + } +}; + class GetEmojiKeywordsLanguageQuery final : public Td::ResultHandler { Promise> promise_; @@ -4706,11 +4734,11 @@ vector StickersManager::get_stickers(StickerType sticker_type, string qu return result; } -string StickersManager::get_found_stickers_database_key(const string &emoji) { - return PSTRING() << "found_stickers" << emoji; +string StickersManager::get_found_stickers_database_key(StickerType sticker_type, const string &emoji) { + return PSTRING() << (sticker_type == StickerType::Regular ? "found_stickers" : "found_custom_emoji") << emoji; } -void StickersManager::search_stickers(string emoji, int32 limit, +void StickersManager::search_stickers(StickerType sticker_type, string emoji, int32 limit, Promise> &&promise) { if (limit == 0) { return promise.set_value(get_stickers_object({})); @@ -4726,12 +4754,13 @@ void StickersManager::search_stickers(string emoji, int32 limit, } remove_emoji_modifiers_in_place(emoji); - if (emoji.empty()) { + if (emoji.empty() || sticker_type == StickerType::Mask) { return promise.set_value(get_stickers_object({})); } - auto it = found_stickers_.find(emoji); - if (it != found_stickers_.end()) { + auto type = static_cast(sticker_type); + auto it = found_stickers_[type].find(emoji); + if (it != found_stickers_[type].end()) { const auto &sticker_ids = it->second.sticker_ids_; auto result_size = min(static_cast(limit), sticker_ids.size()); promise.set_value(get_stickers_object({sticker_ids.begin(), sticker_ids.begin() + result_size})); @@ -4743,60 +4772,73 @@ void StickersManager::search_stickers(string emoji, int32 limit, limit = 0; } - auto &promises = search_stickers_queries_[emoji]; + auto &promises = search_stickers_queries_[type][emoji]; promises.emplace_back(limit, std::move(promise)); if (promises.size() == 1u) { - if (it != found_stickers_.end()) { - return reload_found_stickers(std::move(emoji), get_recent_stickers_hash(it->second.sticker_ids_)); + if (it != found_stickers_[type].end()) { + return reload_found_stickers(sticker_type, std::move(emoji), get_recent_stickers_hash(it->second.sticker_ids_)); } if (G()->parameters().use_file_db) { LOG(INFO) << "Trying to load stickers for " << emoji << " from database"; - G()->td_db()->get_sqlite_pmc()->get( - get_found_stickers_database_key(emoji), PromiseCreator::lambda([emoji](string value) mutable { - send_closure(G()->stickers_manager(), &StickersManager::on_load_found_stickers_from_database, - std::move(emoji), std::move(value)); - })); + G()->td_db()->get_sqlite_pmc()->get(get_found_stickers_database_key(sticker_type, emoji), + PromiseCreator::lambda([sticker_type, emoji](string value) mutable { + send_closure(G()->stickers_manager(), + &StickersManager::on_load_found_stickers_from_database, + sticker_type, std::move(emoji), std::move(value)); + })); } else { - return reload_found_stickers(std::move(emoji), 0); + return reload_found_stickers(sticker_type, std::move(emoji), 0); } } } -void StickersManager::reload_found_stickers(string &&emoji, int64 hash) { - td_->create_handler()->send(std::move(emoji), hash); +void StickersManager::reload_found_stickers(StickerType sticker_type, string &&emoji, int64 hash) { + switch (sticker_type) { + case StickerType::Regular: + td_->create_handler()->send(std::move(emoji), hash); + break; + case StickerType::CustomEmoji: + td_->create_handler()->send(std::move(emoji), hash); + break; + default: + UNREACHABLE(); + } } -void StickersManager::on_load_found_stickers_from_database(string emoji, string value) { +void StickersManager::on_load_found_stickers_from_database(StickerType sticker_type, string emoji, string value) { if (G()->close_flag()) { - on_search_stickers_failed(emoji, G()->close_status()); + on_search_stickers_failed(sticker_type, emoji, G()->close_status()); return; } if (value.empty()) { LOG(INFO) << "Stickers for " << emoji << " aren't found in database"; - return reload_found_stickers(std::move(emoji), 0); + return reload_found_stickers(sticker_type, std::move(emoji), 0); } LOG(INFO) << "Successfully loaded stickers for " << emoji << " from database"; - auto &found_stickers = found_stickers_[emoji]; + auto type = static_cast(sticker_type); + auto &found_stickers = found_stickers_[type][emoji]; CHECK(found_stickers.next_reload_time_ == 0); auto status = log_event_parse(found_stickers, value); if (status.is_error()) { LOG(ERROR) << "Can't load stickers for emoji: " << status << ' ' << format::as_hex_dump<4>(Slice(value)); - found_stickers_.erase(emoji); - return reload_found_stickers(std::move(emoji), 0); + found_stickers_[type].erase(emoji); + return reload_found_stickers(sticker_type, std::move(emoji), 0); } - on_search_stickers_finished(emoji, found_stickers); + on_search_stickers_finished(sticker_type, emoji, found_stickers); } -void StickersManager::on_search_stickers_finished(const string &emoji, const FoundStickers &found_stickers) { - auto it = search_stickers_queries_.find(emoji); - CHECK(it != search_stickers_queries_.end()); +void StickersManager::on_search_stickers_finished(StickerType sticker_type, const string &emoji, + const FoundStickers &found_stickers) { + auto type = static_cast(sticker_type); + auto it = search_stickers_queries_[type].find(emoji); + CHECK(it != search_stickers_queries_[type].end()); CHECK(!it->second.empty()); auto queries = std::move(it->second); - search_stickers_queries_.erase(it); + search_stickers_queries_[type].erase(it); const auto &sticker_ids = found_stickers.sticker_ids_; for (auto &query : queries) { @@ -4805,12 +4847,30 @@ void StickersManager::on_search_stickers_finished(const string &emoji, const Fou } } -void StickersManager::on_search_stickers_failed(const string &emoji, Status &&error) { - auto it = search_stickers_queries_.find(emoji); - CHECK(it != search_stickers_queries_.end()); +void StickersManager::on_search_stickers_succeeded(StickerType sticker_type, const string &emoji, + vector &&sticker_ids) { + auto type = static_cast(sticker_type); + auto &found_stickers = found_stickers_[type][emoji]; + found_stickers.cache_time_ = 300; + found_stickers.next_reload_time_ = Time::now() + found_stickers.cache_time_; + found_stickers.sticker_ids_ = std::move(sticker_ids); + + if (G()->parameters().use_file_db && !G()->close_flag()) { + LOG(INFO) << "Save " << sticker_type << " stickers for " << emoji << " to database"; + G()->td_db()->get_sqlite_pmc()->set(get_found_stickers_database_key(sticker_type, emoji), + log_event_store(found_stickers).as_slice().str(), Auto()); + } + + return on_search_stickers_finished(sticker_type, emoji, found_stickers); +} + +void StickersManager::on_search_stickers_failed(StickerType sticker_type, const string &emoji, Status &&error) { + auto type = static_cast(sticker_type); + auto it = search_stickers_queries_[type].find(emoji); + CHECK(it != search_stickers_queries_[type].end()); CHECK(!it->second.empty()); auto queries = std::move(it->second); - search_stickers_queries_.erase(it); + search_stickers_queries_[type].erase(it); for (auto &query : queries) { query.second.set_error(error.clone()); @@ -4820,38 +4880,30 @@ void StickersManager::on_search_stickers_failed(const string &emoji, Status &&er void StickersManager::on_find_stickers_success(const string &emoji, tl_object_ptr &&stickers) { CHECK(stickers != nullptr); + auto sticker_type = StickerType::Regular; + auto type = static_cast(sticker_type); switch (stickers->get_id()) { case telegram_api::messages_stickersNotModified::ID: { - auto it = found_stickers_.find(emoji); - if (it == found_stickers_.end()) { + auto it = found_stickers_[type].find(emoji); + if (it == found_stickers_[type].end()) { return on_find_stickers_fail(emoji, Status::Error(500, "Receive messages.stickerNotModified")); } auto &found_stickers = it->second; found_stickers.next_reload_time_ = Time::now() + found_stickers.cache_time_; - return on_search_stickers_finished(emoji, found_stickers); + return on_search_stickers_finished(sticker_type, emoji, found_stickers); } case telegram_api::messages_stickers::ID: { auto received_stickers = move_tl_object_as(stickers); - auto &found_stickers = found_stickers_[emoji]; - found_stickers.cache_time_ = 300; - found_stickers.next_reload_time_ = Time::now() + found_stickers.cache_time_; - found_stickers.sticker_ids_.clear(); - + vector sticker_ids; for (auto &sticker : received_stickers->stickers_) { FileId sticker_id = on_get_sticker_document(std::move(sticker), StickerFormat::Unknown).second; if (sticker_id.is_valid()) { - found_stickers.sticker_ids_.push_back(sticker_id); + sticker_ids.push_back(sticker_id); } } - if (G()->parameters().use_file_db && !G()->close_flag()) { - LOG(INFO) << "Save stickers for " << emoji << " to database"; - G()->td_db()->get_sqlite_pmc()->set(get_found_stickers_database_key(emoji), - log_event_store(found_stickers).as_slice().str(), Auto()); - } - - return on_search_stickers_finished(emoji, found_stickers); + return on_search_stickers_succeeded(sticker_type, emoji, std::move(sticker_ids)); } default: UNREACHABLE(); @@ -4859,12 +4911,80 @@ void StickersManager::on_find_stickers_success(const string &emoji, } void StickersManager::on_find_stickers_fail(const string &emoji, Status &&error) { - if (found_stickers_.count(emoji) != 0) { - found_stickers_[emoji].cache_time_ = Random::fast(40, 80); + auto sticker_type = StickerType::Regular; + auto type = static_cast(sticker_type); + if (found_stickers_[type].count(emoji) != 0) { + found_stickers_[type][emoji].cache_time_ = Random::fast(40, 80); return on_find_stickers_success(emoji, make_tl_object()); } - on_search_stickers_failed(emoji, std::move(error)); + on_search_stickers_failed(sticker_type, emoji, std::move(error)); +} + +void StickersManager::on_find_custom_emojis_success(const string &emoji, + tl_object_ptr &&stickers) { + CHECK(stickers != nullptr); + auto sticker_type = StickerType::CustomEmoji; + auto type = static_cast(sticker_type); + switch (stickers->get_id()) { + case telegram_api::emojiListNotModified::ID: { + auto it = found_stickers_[type].find(emoji); + if (it == found_stickers_[type].end()) { + return on_find_custom_emojis_fail(emoji, Status::Error(500, "Receive emojiListNotModified")); + } + auto &found_stickers = it->second; + found_stickers.next_reload_time_ = Time::now() + found_stickers.cache_time_; + return on_search_stickers_finished(sticker_type, emoji, found_stickers); + } + case telegram_api::emojiList::ID: { + auto emoji_list = move_tl_object_as(stickers); + + auto custom_emoji_ids = + transform(std::move(emoji_list->document_id_), [](int64 document_id) { return CustomEmojiId(document_id); }); + auto hash = emoji_list->hash_; + + get_custom_emoji_stickers(custom_emoji_ids, true, + PromiseCreator::lambda([actor_id = actor_id(this), emoji, hash, custom_emoji_ids]( + Result> &&result) { + send_closure(actor_id, &StickersManager::on_load_custom_emojis, std::move(emoji), + hash, custom_emoji_ids, std::move(result)); + })); + break; + } + default: + UNREACHABLE(); + } +} + +void StickersManager::on_load_custom_emojis(string emoji, int64 hash, vector custom_emoji_ids, + Result> &&result) { + if (result.is_ok() && G()->close_flag()) { + result = G()->close_status(); + } + if (result.is_error()) { + return on_find_custom_emojis_fail(emoji, result.move_as_error()); + } + + vector sticker_ids; + for (auto custom_emoji_id : custom_emoji_ids) { + auto sticker_id = custom_emoji_to_sticker_id_.get(custom_emoji_id); + if (sticker_id.is_valid()) { + sticker_ids.push_back(sticker_id); + } + } + + on_search_stickers_succeeded(StickerType::CustomEmoji, emoji, std::move(sticker_ids)); +} + +void StickersManager::on_find_custom_emojis_fail(const string &emoji, Status &&error) { + auto sticker_type = StickerType::CustomEmoji; + auto type = static_cast(StickerType::CustomEmoji); + if (found_stickers_[type].count(emoji) != 0) { + found_stickers_[type][emoji].cache_time_ = Random::fast(40, 80); + return on_find_custom_emojis_success(emoji, make_tl_object()); + } + + on_search_stickers_failed(sticker_type, emoji, std::move(error)); } void StickersManager::get_premium_stickers(int32 limit, Promise> &&promise) { @@ -4888,7 +5008,7 @@ void StickersManager::get_premium_stickers(int32 limit, Promise> result) mutable { if (result.is_error()) { @@ -4921,8 +5041,8 @@ void StickersManager::do_get_premium_stickers(int32 limit, Promisesecond.sticker_ids_) { if (td::contains(sticker_ids, sticker_id)) { continue; diff --git a/td/telegram/StickersManager.h b/td/telegram/StickersManager.h index d6f3d5a8f..12b1c951b 100644 --- a/td/telegram/StickersManager.h +++ b/td/telegram/StickersManager.h @@ -162,7 +162,8 @@ class StickersManager final : public Actor { vector get_stickers(StickerType sticker_type, string query, int32 limit, DialogId dialog_id, bool force, Promise &&promise); - void search_stickers(string emoji, int32 limit, Promise> &&promise); + void search_stickers(StickerType sticker_type, string emoji, int32 limit, + Promise> &&promise); void get_premium_stickers(int32 limit, Promise> &&promise); @@ -398,6 +399,10 @@ class StickersManager final : public Actor { void on_find_stickers_fail(const string &emoji, Status &&error); + void on_find_custom_emojis_success(const string &emoji, tl_object_ptr &&stickers); + + void on_find_custom_emojis_fail(const string &emoji, Status &&error); + void on_find_sticker_sets_success(const string &query, tl_object_ptr &&sticker_sets); @@ -631,15 +636,20 @@ class StickersManager final : public Actor { Sticker *get_sticker(FileId file_id); const Sticker *get_sticker(FileId file_id) const; - static string get_found_stickers_database_key(const string &emoji); + static string get_found_stickers_database_key(StickerType sticker_type, const string &emoji); - void reload_found_stickers(string &&emoji, int64 hash); + void reload_found_stickers(StickerType sticker_type, string &&emoji, int64 hash); - void on_load_found_stickers_from_database(string emoji, string value); + void on_load_found_stickers_from_database(StickerType sticker_type, string emoji, string value); - void on_search_stickers_finished(const string &emoji, const FoundStickers &found_stickers); + void on_load_custom_emojis(string emoji, int64 hash, vector custom_emoji_ids, + Result> &&result); - void on_search_stickers_failed(const string &emoji, Status &&error); + void on_search_stickers_finished(StickerType sticker_type, const string &emoji, const FoundStickers &found_stickers); + + void on_search_stickers_succeeded(StickerType sticker_type, const string &emoji, vector &&sticker_ids); + + void on_search_stickers_failed(StickerType sticker_type, const string &emoji, Status &&error); static string get_custom_emoji_database_key(CustomEmojiId custom_emoji_id); @@ -1055,8 +1065,9 @@ class StickersManager final : public Actor { Hints installed_sticker_sets_hints_[MAX_STICKER_TYPE]; // search installed sticker sets by their title and name - FlatHashMap found_stickers_; - FlatHashMap>>>> search_stickers_queries_; + FlatHashMap found_stickers_[MAX_STICKER_TYPE]; + FlatHashMap>>>> + search_stickers_queries_[MAX_STICKER_TYPE]; std::unordered_map, Hash> found_sticker_sets_; std::unordered_map>, Hash> search_sticker_sets_queries_; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index f0dc3cb1b..439af368f 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -7149,7 +7149,8 @@ void Td::on_request(uint64 id, td_api::searchStickers &request) { CHECK_IS_USER(); CLEAN_INPUT_STRING(request.emoji_); CREATE_REQUEST_PROMISE(); - stickers_manager_->search_stickers(std::move(request.emoji_), request.limit_, std::move(promise)); + stickers_manager_->search_stickers(get_sticker_type(request.sticker_type_), std::move(request.emoji_), request.limit_, + std::move(promise)); } void Td::on_request(uint64 id, const td_api::getPremiumStickers &request) { @@ -8133,7 +8134,7 @@ void Td::on_request(uint64 id, const td_api::getPremiumFeatures &request) { void Td::on_request(uint64 id, const td_api::getPremiumStickerExamples &request) { CHECK_IS_USER(); CREATE_REQUEST_PROMISE(); - stickers_manager_->search_stickers("⭐️⭐️", 100, std::move(promise)); + stickers_manager_->search_stickers(StickerType::Regular, "⭐️⭐️", 100, std::move(promise)); } void Td::on_request(uint64 id, const td_api::viewPremiumFeature &request) { diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index 35c057832..5d0d19c13 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -2744,10 +2744,10 @@ class CliClient final : public Actor { get_args(args, query); send_request(td_api::make_object(as_sticker_type(op), query.query, query.limit, op == "gseeme" ? my_id_ : 0)); - } else if (op == "sst") { + } else if (op == "sst" || op == "sstm" || op == "sste") { SearchQuery query; get_args(args, query); - send_request(td_api::make_object(query.query, query.limit)); + send_request(td_api::make_object(as_sticker_type(op), query.query, query.limit)); } else if (op == "gprst") { string limit; get_args(args, limit);