diff --git a/td/generate/scheme/td_api.tl b/td/generate/scheme/td_api.tl index a9fa6b55..c767bf25 100644 --- a/td/generate/scheme/td_api.tl +++ b/td/generate/scheme/td_api.tl @@ -2515,9 +2515,15 @@ getAttachedStickerSets file_id:int32 = StickerSets; //@description Returns information about a sticker set by its identifier @set_id Identifier of the sticker set getStickerSet set_id:int64 = StickerSet; -//@description Searches for a sticker set by its short name @name Name of the sticker set +//@description Searches for a sticker set by its name @name Name of the sticker set searchStickerSet name:string = StickerSet; +//@description Searches for installed sticker sets by looking for specified query in their title and name @is_masks Pass true to return mask sticker sets; pass false to return ordinary sticker sets @query Query to search for @limit Maximum number of sticker sets to return +searchInstalledStickerSets is_masks:Bool query:string limit:int32 = StickerSets; + +//@description Searches for ordinary sticker sets by looking for specified query in their title and name. Excludes installed sticker sets from the results @query Query to search for +searchStickerSets query:string = StickerSets; + //@description Installs/uninstalls or activates/archives a sticker set @set_id Identifier of the sticker set @is_installed The new value of is_installed @is_archived The new value of is_archived. A sticker set can't be installed and archived simultaneously changeStickerSet set_id:int64 is_installed:Bool is_archived:Bool = Ok; diff --git a/td/generate/scheme/td_api.tlo b/td/generate/scheme/td_api.tlo index dcf11bdf..764bb342 100644 Binary files a/td/generate/scheme/td_api.tlo and b/td/generate/scheme/td_api.tlo differ diff --git a/td/telegram/ContactsManager.cpp b/td/telegram/ContactsManager.cpp index e734b88b..06d81cbe 100644 --- a/td/telegram/ContactsManager.cpp +++ b/td/telegram/ContactsManager.cpp @@ -3735,7 +3735,7 @@ std::pair> ContactsManager::search_contacts(const string & } promise.set_value(Unit()); - return {narrow_cast(result.first), user_ids}; + return {narrow_cast(result.first), std::move(user_ids)}; } void ContactsManager::set_profile_photo(const tl_object_ptr &input_photo, Promise &&promise) { diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 90b23932..1da1fa29 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -408,6 +408,33 @@ class GetStickerSetQuery : public Td::ResultHandler { } }; +class SearchStickerSetsQuery : public Td::ResultHandler { + string query_; + + public: + void send(string query) { + query_ = std::move(query); + send_query(G()->net_query_creator().create( + create_storer(telegram_api::messages_searchStickerSets(0, false /*ignored*/, query_, 0)))); + } + + void on_result(uint64 id, BufferSlice packet) override { + auto result_ptr = fetch_result(packet); + if (result_ptr.is_error()) { + return on_error(id, result_ptr.move_as_error()); + } + + auto ptr = result_ptr.move_as_ok(); + LOG(INFO) << "Receive result for search sticker sets: " << to_string(ptr); + td->stickers_manager_->on_find_sticker_sets_success(query_, std::move(ptr)); + } + + void on_error(uint64 id, Status status) override { + LOG(ERROR) << "Receive error for search sticker sets: " << status; + td->stickers_manager_->on_find_sticker_sets_fail(query_, std::move(status)); + } +}; + class InstallStickerSetQuery : public Td::ResultHandler { Promise promise_; int64 set_id_; @@ -1379,6 +1406,10 @@ int64 StickersManager::on_get_sticker_set(tl_object_ptrtitle = std::move(set->title_); s->is_changed = true; + + if (installed_sticker_sets_hints_[s->is_masks].has_key(set_id)) { + installed_sticker_sets_hints_[s->is_masks].add(set_id, s->title + " " + s->short_name); + } } if (s->short_name != set->short_name_) { LOG(ERROR) << "Sticker set " << set_id << " short name has changed from \"" << s->short_name << "\" to \"" @@ -1386,6 +1417,10 @@ int64 StickersManager::on_get_sticker_set(tl_object_ptrshort_name)); s->short_name = std::move(set->short_name_); s->is_changed = true; + + if (installed_sticker_sets_hints_[s->is_masks].has_key(set_id)) { + installed_sticker_sets_hints_[s->is_masks].add(set_id, s->title + " " + s->short_name); + } } if (s->sticker_count != set->count_ || s->hash != set->hash_) { @@ -1608,6 +1643,7 @@ void StickersManager::on_get_installed_sticker_sets(bool is_masks, vector installed_sticker_set_ids; vector hashes; vector sticker_set_ids; + std::reverse(stickers->sets_.begin(), stickers->sets_.end()); // apply installed sticker sets in reverse order for (auto &set : stickers->sets_) { hashes.push_back(set->hash_); sticker_set_ids.push_back(set->id_); @@ -1633,6 +1669,9 @@ void StickersManager::on_get_installed_sticker_sets(bool is_masks, sets_to_load.push_back(set_id); } } + std::reverse(hashes.begin(), hashes.end()); + std::reverse(installed_sticker_set_ids.begin(), installed_sticker_set_ids.end()); + std::reverse(sticker_set_ids.begin(), sticker_set_ids.end()); if (!sets_to_load.empty()) { load_sticker_sets(std::move(sets_to_load), Auto()); @@ -1906,6 +1945,97 @@ int64 StickersManager::search_sticker_set(const string &short_name_to_search, Pr return sticker_set->id; } +std::pair> StickersManager::search_installed_sticker_sets(bool is_masks, const string &query, + int32 limit, Promise &&promise) { + LOG(INFO) << "Search installed " << (is_masks ? "masks " : "") << "sticker sets with query = \"" << query + << "\" and limit = " << limit; + + if (limit < 0) { + promise.set_error(Status::Error(400, "Limit must be non-negative")); + return {}; + } + + if (!are_installed_sticker_sets_loaded_[is_masks]) { + load_installed_sticker_sets(is_masks, std::move(promise)); + return {}; + } + reload_installed_sticker_sets(is_masks, false); + + std::pair> result = installed_sticker_sets_hints_[is_masks].search(query, limit); + promise.set_value(Unit()); + return {narrow_cast(result.first), std::move(result.second)}; +} + +vector StickersManager::search_sticker_sets(const string &query, Promise &&promise) { + auto q = clean_name(query, 1000); + auto it = found_sticker_sets_.find(q); + if (it != found_sticker_sets_.end()) { + promise.set_value(Unit()); + return it->second; + } + + auto &promises = search_sticker_sets_queries_[q]; + promises.push_back(std::move(promise)); + if (promises.size() == 1u) { + td_->create_handler()->send(std::move(q)); + } + + return {}; +} + +void StickersManager::on_find_sticker_sets_success( + const string &query, tl_object_ptr &&sticker_sets) { + CHECK(sticker_sets != nullptr); + switch (sticker_sets->get_id()) { + case telegram_api::messages_foundStickerSetsNotModified::ID: + return on_find_sticker_sets_fail(query, Status::Error(500, "Receive messages.foundStickerSetsNotModified")); + case telegram_api::messages_foundStickerSets::ID: { + auto found_stickers_sets = move_tl_object_as(sticker_sets); + vector &sticker_set_ids = found_sticker_sets_[query]; + CHECK(sticker_set_ids.empty()); + + for (auto &sticker_set : found_stickers_sets->sets_) { + int64 set_id = on_get_sticker_set_covered(std::move(sticker_set), true); + if (set_id == 0) { + continue; + } + + update_sticker_set(get_sticker_set(set_id)); + sticker_set_ids.push_back(set_id); + } + + send_update_installed_sticker_sets(); + break; + } + default: + UNREACHABLE(); + } + + auto it = search_sticker_sets_queries_.find(query); + CHECK(it != search_sticker_sets_queries_.end()); + CHECK(!it->second.empty()); + auto promises = std::move(it->second); + search_sticker_sets_queries_.erase(it); + + for (auto &promise : promises) { + promise.set_value(Unit()); + } +} + +void StickersManager::on_find_sticker_sets_fail(const string &query, Status &&error) { + CHECK(found_sticker_sets_.count(query) == 0); + + auto it = search_sticker_sets_queries_.find(query); + CHECK(it != search_sticker_sets_queries_.end()); + CHECK(!it->second.empty()); + auto promises = std::move(it->second); + search_sticker_sets_queries_.erase(it); + + for (auto &promise : promises) { + promise.set_error(error.clone()); + } +} + void StickersManager::change_sticker_set(int64 set_id, bool is_installed, bool is_archived, Promise &&promise) { if (is_installed && is_archived) { return promise.set_error(Status::Error(400, "Sticker set can't be installed and archived simultaneously")); @@ -1965,8 +2095,11 @@ void StickersManager::on_update_sticker_set(StickerSet *sticker_set, bool is_ins need_update_installed_sticker_sets_[sticker_set->is_masks] = true; if (is_added) { + installed_sticker_sets_hints_[sticker_set->is_masks].add(sticker_set->id, + sticker_set->title + " " + sticker_set->short_name); sticker_set_ids.insert(sticker_set_ids.begin(), sticker_set->id); } else { + installed_sticker_sets_hints_[sticker_set->is_masks].remove(sticker_set->id); sticker_set_ids.erase(std::remove(sticker_set_ids.begin(), sticker_set_ids.end(), sticker_set->id), sticker_set_ids.end()); } @@ -2069,13 +2202,14 @@ void StickersManager::on_load_installed_sticker_sets_finished(bool is_masks, vec } } if (need_reload) { - LOG(ERROR) << "Reload installed sticker sets, because only " << installed_sticker_set_ids_[is_masks].size() - << " of " << installed_sticker_set_ids.size() << " are really installed"; + LOG(ERROR) << "Reload installed " << (is_masks ? "masks " : "") << "sticker sets, because only " + << installed_sticker_set_ids_[is_masks].size() << " of " << installed_sticker_set_ids.size() + << " are really installed"; reload_installed_sticker_sets(is_masks, true); } else if (!old_installed_sticker_set_ids.empty() && old_installed_sticker_set_ids != installed_sticker_set_ids_[is_masks]) { - LOG(ERROR) << "Reload installed sticker sets, because they has changed from " << old_installed_sticker_set_ids - << " to " << installed_sticker_set_ids_[is_masks]; + LOG(ERROR) << "Reload installed " << (is_masks ? "masks " : "") << "sticker sets, because they has changed from " + << old_installed_sticker_set_ids << " to " << installed_sticker_set_ids_[is_masks]; reload_installed_sticker_sets(is_masks, true); } diff --git a/td/telegram/StickersManager.h b/td/telegram/StickersManager.h index 9a05b87e..96fc6305 100644 --- a/td/telegram/StickersManager.h +++ b/td/telegram/StickersManager.h @@ -17,6 +17,7 @@ #include "td/utils/buffer.h" #include "td/utils/common.h" +#include "td/utils/Hints.h" #include "td/utils/Status.h" #include "td/telegram/td_api.h" @@ -74,6 +75,11 @@ class StickersManager : public Actor { int64 search_sticker_set(const string &short_name_to_search, Promise &&promise); + std::pair> search_installed_sticker_sets(bool is_masks, const string &query, int32 limit, + Promise &&promise); + + vector search_sticker_sets(const string &query, Promise &&promise); + void change_sticker_set(int64 set_id, bool is_installed, bool is_archived, Promise &&promise); void view_featured_sticker_sets(const vector &sticker_set_ids); @@ -192,6 +198,11 @@ class StickersManager : public Actor { void on_uploaded_sticker_file(FileId file_id, tl_object_ptr media, Promise &&promise); + void on_find_sticker_sets_success(const string &query, + tl_object_ptr &&sticker_sets); + + void on_find_sticker_sets_fail(const string &query, Status &&error); + private: static constexpr int32 MAX_FEATURED_STICKER_SET_VIEW_DELAY = 5; static constexpr size_t RECENT_STICKERS_LIMIT = 30; @@ -450,6 +461,11 @@ class StickersManager : public Actor { std::unordered_map, FileIdHash> attached_sticker_sets_; + Hints installed_sticker_sets_hints_[2]; // search installed sticker sets by their title and name + + std::unordered_map> found_sticker_sets_; + std::unordered_map>> search_sticker_sets_queries_; + std::unordered_set pending_viewed_featured_sticker_set_ids_; Timeout pending_featured_sticker_set_views_timeout_; diff --git a/td/telegram/Td.cpp b/td/telegram/Td.cpp index 454b6467..2cd3f278 100644 --- a/td/telegram/Td.cpp +++ b/td/telegram/Td.cpp @@ -2873,6 +2873,47 @@ class SearchStickerSetRequest : public RequestActor<> { } }; +class SearchInstalledStickerSetsRequest : public RequestActor<> { + bool is_masks_; + string query_; + int32 limit_; + + std::pair> sticker_set_ids_; + + void do_run(Promise &&promise) override { + sticker_set_ids_ = + td->stickers_manager_->search_installed_sticker_sets(is_masks_, query_, limit_, std::move(promise)); + } + + void do_send_result() override { + send_result(td->stickers_manager_->get_sticker_sets_object(sticker_set_ids_.first, sticker_set_ids_.second, 5)); + } + + public: + SearchInstalledStickerSetsRequest(ActorShared td, uint64 request_id, bool is_masks, string &&query, int32 limit) + : RequestActor(std::move(td), request_id), is_masks_(is_masks), query_(std::move(query)), limit_(limit) { + } +}; + +class SearchStickerSetsRequest : public RequestActor<> { + string query_; + + vector sticker_set_ids_; + + void do_run(Promise &&promise) override { + sticker_set_ids_ = td->stickers_manager_->search_sticker_sets(query_, std::move(promise)); + } + + void do_send_result() override { + send_result(td->stickers_manager_->get_sticker_sets_object(-1, sticker_set_ids_, 5)); + } + + public: + SearchStickerSetsRequest(ActorShared td, uint64 request_id, string &&query) + : RequestActor(std::move(td), request_id), query_(std::move(query)) { + } +}; + class ChangeStickerSetRequest : public RequestOnceActor { int64 set_id_; bool is_installed_; @@ -6253,6 +6294,18 @@ void Td::on_request(uint64 id, td_api::searchStickerSet &request) { CREATE_REQUEST(SearchStickerSetRequest, std::move(request.name_)); } +void Td::on_request(uint64 id, td_api::searchInstalledStickerSets &request) { + CHECK_AUTH(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchInstalledStickerSetsRequest, request.is_masks_, std::move(request.query_), request.limit_); +} + +void Td::on_request(uint64 id, td_api::searchStickerSets &request) { + CHECK_AUTH(); + CLEAN_INPUT_STRING(request.query_); + CREATE_REQUEST(SearchStickerSetsRequest, std::move(request.query_)); +} + void Td::on_request(uint64 id, const td_api::changeStickerSet &request) { CHECK_AUTH(); CHECK_IS_USER(); diff --git a/td/telegram/Td.h b/td/telegram/Td.h index d6f61ec2..a59ec18d 100644 --- a/td/telegram/Td.h +++ b/td/telegram/Td.h @@ -657,6 +657,10 @@ class Td final : public NetQueryCallback { void on_request(uint64 id, td_api::searchStickerSet &request); + void on_request(uint64 id, td_api::searchInstalledStickerSets &request); + + void on_request(uint64 id, td_api::searchStickerSets &request); + void on_request(uint64 id, const td_api::changeStickerSet &request); void on_request(uint64 id, const td_api::viewTrendingStickerSets &request); diff --git a/td/telegram/cli.cpp b/td/telegram/cli.cpp index a52c96fd..5cf6e9a8 100644 --- a/td/telegram/cli.cpp +++ b/td/telegram/cli.cpp @@ -1618,6 +1618,10 @@ class CliClient final : public Actor { send_request(make_tl_object(get_top_chat_category(category), as_chat_id(chat_id))); } else if (op == "sss") { send_request(make_tl_object(args)); + } else if (op == "siss") { + send_request(make_tl_object(false, args, 2)); + } else if (op == "ssss") { + send_request(make_tl_object(args)); } else if (op == "css") { string set_id; string is_installed;