diff --git a/td/telegram/FileReferenceManager.cpp b/td/telegram/FileReferenceManager.cpp index 62e014419..61e8186d6 100644 --- a/td/telegram/FileReferenceManager.cpp +++ b/td/telegram/FileReferenceManager.cpp @@ -11,6 +11,7 @@ #include "td/telegram/files/FileManager.h" #include "td/telegram/Global.h" #include "td/telegram/MessagesManager.h" +#include "td/telegram/StickersManager.h" #include "td/telegram/WallpaperManager.h" #include "td/telegram/WebPagesManager.h" @@ -34,6 +35,7 @@ fileSourceSupergroupPhoto supergroup_id:int32 = FileSource; // repair fileSourceWebPage url:string = FileSource; // repaired with messages.getWebPage fileSourceWallpapers = FileSource; // repaired with account.getWallPapers fileSourceSavedAnimations = FileSource; // repaired with messages.getSavedGifs +fileSourceRecentStickers is_attached:Bool = FileSource; // repaired with messages.getRecentStickers, not reliable */ FileSourceId FileReferenceManager::get_current_file_source_id() const { @@ -83,6 +85,11 @@ FileSourceId FileReferenceManager::create_saved_animations_file_source() { return add_file_source_id(source, "saved animations"); } +FileSourceId FileReferenceManager::create_recent_stickers_file_source(bool is_attached) { + FileSourceRecentStickers source{is_attached}; + return add_file_source_id(source, PSLICE() << "recent " << (is_attached ? "attached " : "") << "stickers"); +} + bool FileReferenceManager::add_file_source(NodeId node_id, FileSourceId file_source_id) { VLOG(file_references) << "Add " << file_source_id << " for file " << node_id; return nodes_[node_id].file_source_ids.add(file_source_id); @@ -229,6 +236,10 @@ void FileReferenceManager::send_query(Destination dest, FileSourceId file_source [&](const FileSourceSavedAnimations &source) { send_closure_later(G()->animations_manager(), &AnimationsManager::reload_saved_animations_force, std::move(promise)); + }, + [&](const FileSourceRecentStickers &source) { + send_closure_later(G()->stickers_manager(), &StickersManager::reload_recent_stickers_force, source.is_attached, + std::move(promise)); })); } diff --git a/td/telegram/FileReferenceManager.h b/td/telegram/FileReferenceManager.h index c4a47d287..ec4c6b9a5 100644 --- a/td/telegram/FileReferenceManager.h +++ b/td/telegram/FileReferenceManager.h @@ -41,6 +41,7 @@ class FileReferenceManager : public Actor { FileSourceId create_wallpapers_file_source(); FileSourceId create_web_page_file_source(string url); FileSourceId create_saved_animations_file_source(); + FileSourceId create_recent_stickers_file_source(bool is_attached); using NodeId = FileId; void repair_file_reference(NodeId node_id, Promise<> promise); @@ -101,10 +102,14 @@ class FileReferenceManager : public Actor { struct FileSourceSavedAnimations { // empty }; + struct FileSourceRecentStickers { + bool is_attached; + }; // append only - using FileSource = Variant; + using FileSource = + Variant; vector file_sources_; int64 query_generation_{0}; diff --git a/td/telegram/FileReferenceManager.hpp b/td/telegram/FileReferenceManager.hpp index a8b0f2599..939fabcc7 100644 --- a/td/telegram/FileReferenceManager.hpp +++ b/td/telegram/FileReferenceManager.hpp @@ -14,6 +14,7 @@ #include "td/telegram/files/FileSourceId.h" #include "td/telegram/MessageId.h" #include "td/telegram/MessagesManager.h" +#include "td/telegram/StickersManager.h" #include "td/telegram/Td.h" #include "td/telegram/UserId.h" #include "td/telegram/WallpaperManager.h" @@ -39,7 +40,8 @@ void FileReferenceManager::store_file_source(FileSourceId file_source_id, Storer [&](const FileSourceChannelPhoto &source) { td::store(source.channel_id, storer); }, [&](const FileSourceWallpapers &source) {}, [&](const FileSourceWebPage &source) { td::store(source.url, storer); }, - [&](const FileSourceSavedAnimations &source) {})); + [&](const FileSourceSavedAnimations &source) {}, + [&](const FileSourceRecentStickers &source) { td::store(source.is_attached, storer); })); } template @@ -77,6 +79,11 @@ FileSourceId FileReferenceManager::parse_file_source(Td *td, ParserT &parser) { } case 6: return td->animations_manager_->get_saved_animations_file_source_id(); + case 7: { + bool is_attached; + td::parse(is_attached, parser); + return td->stickers_manager_->get_recent_stickers_file_source_id(is_attached); + } default: parser.set_error("Invalid type in FileSource"); return FileSourceId(); diff --git a/td/telegram/MessageContent.cpp b/td/telegram/MessageContent.cpp index dd903088b..7701c7a70 100644 --- a/td/telegram/MessageContent.cpp +++ b/td/telegram/MessageContent.cpp @@ -4466,7 +4466,6 @@ vector get_message_content_file_ids(const MessageContent *content, const case MessageContentType::Animation: case MessageContentType::Audio: case MessageContentType::Document: - case MessageContentType::Sticker: case MessageContentType::Video: case MessageContentType::VideoNote: case MessageContentType::VoiceNote: { @@ -4482,6 +4481,8 @@ vector get_message_content_file_ids(const MessageContent *content, const } return result; } + case MessageContentType::Sticker: + return td->stickers_manager_->get_sticker_file_ids(static_cast(content)->file_id); case MessageContentType::Game: return static_cast(content)->game.get_file_ids(); case MessageContentType::Invoice: diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index 99ac1211b..837d348f1 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -220,10 +220,12 @@ class GetAttachedStickerSetsQuery : public Td::ResultHandler { }; class GetRecentStickersQuery : public Td::ResultHandler { - bool is_attached_; + bool is_reload_ = false; + bool is_attached_ = false; public: - void send(bool is_attached, int32 hash) { + void send(bool is_reload, bool is_attached, int32 hash) { + is_reload_ = is_reload; is_attached_ = is_attached; int32 flags = 0; if (is_attached) { @@ -243,12 +245,12 @@ class GetRecentStickersQuery : public Td::ResultHandler { auto ptr = result_ptr.move_as_ok(); LOG(DEBUG) << "Receive result for get recent " << (is_attached_ ? "attached " : "") << "stickers: " << to_string(ptr); - td->stickers_manager_->on_get_recent_stickers(is_attached_, std::move(ptr)); + td->stickers_manager_->on_get_recent_stickers(is_reload_, is_attached_, std::move(ptr)); } void on_error(uint64 id, Status status) override { - LOG(ERROR) << "Receive error for get recent stickers: " << status; - td->stickers_manager_->on_get_recent_stickers_failed(is_attached_, std::move(status)); + LOG(ERROR) << "Receive error for get recent " << (is_attached_ ? "attached " : "") << "stickers: " << status; + td->stickers_manager_->on_get_recent_stickers_failed(is_reload_, is_attached_, std::move(status)); } }; @@ -279,7 +281,7 @@ class SaveRecentStickerQuery : public Td::ResultHandler { } bool result = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for save recent sticker: " << result; + LOG(INFO) << "Receive result for save recent " << (is_attached_ ? "attached " : "") << "sticker: " << result; if (!result) { td->stickers_manager_->reload_recent_stickers(is_attached_, true); } @@ -288,7 +290,7 @@ class SaveRecentStickerQuery : public Td::ResultHandler { } void on_error(uint64 id, Status status) override { - LOG(ERROR) << "Receive error for save recent sticker: " << status; + LOG(ERROR) << "Receive error for save recent " << (is_attached_ ? "attached " : "") << "sticker: " << status; td->stickers_manager_->reload_recent_stickers(is_attached_, true); promise_.set_error(std::move(status)); } @@ -321,7 +323,7 @@ class ClearRecentStickersQuery : public Td::ResultHandler { } bool result = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for clear recent stickers: " << result; + LOG(INFO) << "Receive result for clear recent " << (is_attached_ ? "attached " : "") << "stickers: " << result; if (!result) { td->stickers_manager_->reload_recent_stickers(is_attached_, true); } @@ -330,7 +332,7 @@ class ClearRecentStickersQuery : public Td::ResultHandler { } void on_error(uint64 id, Status status) override { - LOG(ERROR) << "Receive error for clear recent stickers: " << status; + LOG(ERROR) << "Receive error for clear recent " << (is_attached_ ? "attached " : "") << "stickers: " << status; td->stickers_manager_->reload_recent_stickers(is_attached_, true); promise_.set_error(std::move(status)); } @@ -1183,6 +1185,20 @@ void StickersManager::delete_sticker_thumbnail(FileId file_id) { sticker->message_thumbnail = PhotoSize(); } +vector StickersManager::get_sticker_file_ids(FileId file_id) const { + vector result; + auto sticker = get_sticker(file_id); + CHECK(sticker != nullptr); + result.push_back(file_id); + if (sticker->message_thumbnail.file_id.is_valid()) { + result.push_back(sticker->message_thumbnail.file_id); + } + if (sticker->sticker_thumbnail.file_id.is_valid()) { + result.push_back(sticker->sticker_thumbnail.file_id); + } + return result; +} + FileId StickersManager::dup_sticker(FileId new_id, FileId old_id) { const Sticker *old_sticker = get_sticker(old_id); CHECK(old_sticker != nullptr); @@ -3602,9 +3618,20 @@ void StickersManager::send_update_featured_sticker_sets() { void StickersManager::reload_recent_stickers(bool is_attached, bool force) { auto &next_load_time = next_recent_stickers_load_time_[is_attached]; if (!td_->auth_manager_->is_bot() && next_load_time >= 0 && (next_load_time < Time::now() || force)) { - LOG_IF(INFO, force) << "Reload recent stickers"; + LOG_IF(INFO, force) << "Reload recent " << (is_attached ? "attached " : "") << "stickers"; next_load_time = -1; - td_->create_handler()->send(is_attached, recent_stickers_hash_[is_attached]); + td_->create_handler()->send(false, is_attached, recent_stickers_hash_[is_attached]); + } +} + +void StickersManager::reload_recent_stickers_force(bool is_attached, Promise &&promise) { + if (td_->auth_manager_->is_bot()) { + return promise.set_error(Status::Error(400, "Bots has no recent stickers")); + } + + reload_recent_stickers_queries_[is_attached].push_back(std::move(promise)); + if (reload_recent_stickers_queries_[is_attached].size() == 1u) { + td_->create_handler()->send(true, is_attached, 0); } } @@ -3675,15 +3702,20 @@ void StickersManager::on_load_recent_stickers_finished(bool is_attached, vector< } } -void StickersManager::on_get_recent_stickers(bool is_attached, +void StickersManager::on_get_recent_stickers(bool is_reload, bool is_attached, tl_object_ptr &&stickers_ptr) { CHECK(!td_->auth_manager_->is_bot()); - next_recent_stickers_load_time_[is_attached] = Time::now_cached() + Random::fast(30 * 60, 50 * 60); + if (!is_reload) { + next_recent_stickers_load_time_[is_attached] = Time::now_cached() + Random::fast(30 * 60, 50 * 60); + } CHECK(stickers_ptr != nullptr); int32 constructor_id = stickers_ptr->get_id(); if (constructor_id == telegram_api::messages_recentStickersNotModified::ID) { - LOG(INFO) << (is_attached ? "Attached r" : "r") << "ecent stickers are not modified"; + if (is_reload) { + return on_get_recent_stickers_failed(true, is_attached, Status::Error(500, "Failed to reload recent stickers")); + } + LOG(INFO) << (is_attached ? "Attached r" : "R") << "ecent stickers are not modified"; return; } CHECK(constructor_id == telegram_api::messages_recentStickers::ID); @@ -3699,16 +3731,27 @@ void StickersManager::on_get_recent_stickers(bool is_attached, recent_sticker_ids.push_back(sticker_id); } - on_load_recent_stickers_finished(is_attached, std::move(recent_sticker_ids)); + if (is_reload) { + auto promises = std::move(reload_recent_stickers_queries_[is_attached]); + reload_recent_stickers_queries_[is_attached].clear(); + for (auto &promise : promises) { + promise.set_value(Unit()); + } + } else { + on_load_recent_stickers_finished(is_attached, std::move(recent_sticker_ids)); - LOG_IF(ERROR, recent_stickers_hash_[is_attached] != stickers->hash_) << "Stickers hash mismatch"; + LOG_IF(ERROR, recent_stickers_hash_[is_attached] != stickers->hash_) << "Stickers hash mismatch"; + } } -void StickersManager::on_get_recent_stickers_failed(bool is_attached, Status error) { +void StickersManager::on_get_recent_stickers_failed(bool is_reload, bool is_attached, Status error) { CHECK(error.is_error()); - next_recent_stickers_load_time_[is_attached] = Time::now_cached() + Random::fast(5, 10); - auto promises = std::move(load_recent_stickers_queries_[is_attached]); - load_recent_stickers_queries_[is_attached].clear(); + if (!is_reload) { + next_recent_stickers_load_time_[is_attached] = Time::now_cached() + Random::fast(5, 10); + } + auto &queries = is_reload ? reload_recent_stickers_queries_[is_attached] : load_recent_stickers_queries_[is_attached]; + auto promises = std::move(queries); + queries.clear(); for (auto &promise : promises) { promise.set_error(error.clone()); } @@ -3731,6 +3774,13 @@ int32 StickersManager::get_recent_stickers_hash(const vector &sticker_id return get_vector_hash(numbers); } +FileSourceId StickersManager::get_recent_stickers_file_source_id(bool is_attached) { + if (!recent_stickers_file_source_id_.is_valid()) { + recent_stickers_file_source_id_ = td_->file_reference_manager_->create_recent_stickers_file_source(is_attached); + } + return recent_stickers_file_source_id_; +} + void StickersManager::add_recent_sticker(bool is_attached, const tl_object_ptr &input_file, Promise &&promise) { if (td_->auth_manager_->is_bot()) { @@ -3911,6 +3961,17 @@ void StickersManager::send_update_recent_stickers(bool from_database) { if (need_update_recent_stickers_[is_attached]) { need_update_recent_stickers_[is_attached] = false; if (are_recent_stickers_loaded_[is_attached]) { + vector new_recent_sticker_file_ids = recent_sticker_ids_[is_attached]; + for (auto &sticker_id : recent_sticker_ids_[is_attached]) { + append(new_recent_sticker_file_ids, get_sticker_file_ids(sticker_id)); + } + std::sort(new_recent_sticker_file_ids.begin(), new_recent_sticker_file_ids.end()); + if (new_recent_sticker_file_ids != recent_sticker_file_ids_) { + td_->file_manager_->change_files_source(get_recent_stickers_file_source_id(is_attached), recent_sticker_file_ids_, + new_recent_sticker_file_ids); + recent_sticker_file_ids_ = std::move(new_recent_sticker_file_ids); + } + recent_stickers_hash_[is_attached] = get_recent_stickers_hash(recent_sticker_ids_[is_attached]); send_closure(G()->td(), &Td::send_update, get_update_recent_stickers_object(is_attached)); diff --git a/td/telegram/StickersManager.h b/td/telegram/StickersManager.h index f28ad756d..d72510aee 100644 --- a/td/telegram/StickersManager.h +++ b/td/telegram/StickersManager.h @@ -12,6 +12,7 @@ #include "td/actor/Timeout.h" #include "td/telegram/files/FileId.h" +#include "td/telegram/files/FileSourceId.h" #include "td/telegram/Photo.h" #include "td/telegram/SecretInputMedia.h" @@ -146,9 +147,12 @@ class StickersManager : public Actor { vector get_recent_stickers(bool is_attached, Promise &&promise); - void on_get_recent_stickers(bool is_attached, tl_object_ptr &&stickers_ptr); + void on_get_recent_stickers(bool is_reload, bool is_attached, + tl_object_ptr &&stickers_ptr); - void on_get_recent_stickers_failed(bool is_attached, Status error); + void on_get_recent_stickers_failed(bool is_reload, bool is_attached, Status error); + + FileSourceId get_recent_stickers_file_source_id(bool is_attached); void add_recent_sticker(bool is_attached, const tl_object_ptr &input_file, Promise &&promise); @@ -188,8 +192,12 @@ class StickersManager : public Actor { void reload_recent_stickers(bool is_attached, bool force); + void reload_recent_stickers_force(bool is_attached, Promise &&promise); + FileId get_sticker_thumbnail_file_id(FileId file_id) const; + vector get_sticker_file_ids(FileId file_id) const; + void delete_sticker_thumbnail(FileId file_id); FileId dup_sticker(FileId new_id, FileId old_id); @@ -483,8 +491,12 @@ class StickersManager : public Actor { vector> load_installed_sticker_sets_queries_[2]; vector> load_featured_sticker_sets_queries_; vector> load_recent_stickers_queries_[2]; + vector> reload_recent_stickers_queries_[2]; vector> load_favorite_stickers_queries_; + vector recent_sticker_file_ids_; + FileSourceId recent_stickers_file_source_id_; + vector archived_sticker_set_ids_[2]; int32 total_archived_sticker_set_count_[2] = {-1, -1};