From 0ac8c2d389b558182cfacf10d55d516d3ddeed71 Mon Sep 17 00:00:00 2001 From: levlam Date: Wed, 23 Jan 2019 22:20:48 +0300 Subject: [PATCH] Repair file_reference in SaveGifQuery. GitOrigin-RevId: ae9fcc543795a659c51699af8ea0048a0b5f8fb5 --- td/telegram/AnimationsManager.cpp | 73 ++++++++++++++++++++-------- td/telegram/AnimationsManager.h | 3 ++ td/telegram/FileReferenceManager.cpp | 11 +++-- td/telegram/FileReferenceManager.h | 3 ++ td/telegram/SetWithPosition.h | 11 +++++ td/telegram/StickersManager.cpp | 8 +-- td/telegram/files/FileLocation.h | 8 +-- td/telegram/files/FileManager.cpp | 4 +- 8 files changed, 87 insertions(+), 34 deletions(-) diff --git a/td/telegram/AnimationsManager.cpp b/td/telegram/AnimationsManager.cpp index 467ebe0d5..a8196536e 100644 --- a/td/telegram/AnimationsManager.cpp +++ b/td/telegram/AnimationsManager.cpp @@ -64,13 +64,22 @@ class GetSavedGifsQuery : public Td::ResultHandler { }; class SaveGifQuery : public Td::ResultHandler { + FileId file_id_; + string file_reference_; + bool unsave_ = false; + Promise promise_; public: explicit SaveGifQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(tl_object_ptr &&input_document, bool unsave) { + void send(FileId file_id, tl_object_ptr &&input_document, bool unsave) { + CHECK(input_document != nullptr); + CHECK(file_id.is_valid()); + file_id_ = file_id; + file_reference_ = input_document->file_reference_.as_slice().str(); + unsave_ = unsave; send_query(G()->net_query_creator().create( create_storer(telegram_api::messages_saveGif(std::move(input_document), unsave)))); } @@ -82,7 +91,7 @@ class SaveGifQuery : public Td::ResultHandler { } bool result = result_ptr.move_as_ok(); - LOG(INFO) << "Receive result for save gif: " << result; + LOG(INFO) << "Receive result for save GIF: " << result; if (!result) { td->animations_manager_->reload_saved_animations(true); } @@ -91,7 +100,22 @@ class SaveGifQuery : public Td::ResultHandler { } void on_error(uint64 id, Status status) override { - LOG(ERROR) << "Receive error for save gif: " << status; + if (FileReferenceManager::is_file_reference_error(status)) { + td->file_manager_->delete_file_reference(file_id_, file_reference_); + td->file_reference_manager_->repair_file_reference( + file_id_, PromiseCreator::lambda([animation_id = file_id_, unsave = unsave_, + promise = std::move(promise_)](Result result) mutable { + if (result.is_error()) { + return promise.set_error(Status::Error(400, "Failed to find the animation")); + } + + send_closure(G()->animations_manager(), &AnimationsManager::send_save_gif_query, animation_id, unsave, + std::move(promise)); + })); + return; + } + + LOG(ERROR) << "Receive error for save GIF: " << status; td->animations_manager_->reload_saved_animations(true); promise_.set_error(std::move(status)); } @@ -310,6 +334,7 @@ tl_object_ptr AnimationsManager::get_input_media( return nullptr; } + SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file_id, tl_object_ptr input_file, const string &caption, BufferSlice thumbnail, @@ -511,7 +536,7 @@ void AnimationsManager::on_get_saved_animations( for (auto &document_ptr : saved_animations->gifs_) { int32 document_constructor_id = document_ptr->get_id(); if (document_constructor_id == telegram_api::documentEmpty::ID) { - LOG(ERROR) << "Empty gif document received"; + LOG(ERROR) << "Empty saved animation document received"; continue; } CHECK(document_constructor_id == telegram_api::document::ID); @@ -588,11 +613,19 @@ void AnimationsManager::add_saved_animation(const tl_object_ptr &&promise) { + // TODO invokeAfter and log event + auto file_view = td_->file_manager_->get_file_view(animation_id); + CHECK(file_view.has_remote_location()); + CHECK(file_view.remote_location().is_document()) << file_view.remote_location(); + CHECK(!file_view.remote_location().is_web()); + td_->create_handler(std::move(promise)) + ->send(animation_id, file_view.remote_location().as_input_document(), unsave); +} + void AnimationsManager::add_saved_animation_inner(FileId animation_id, Promise &&promise) { if (add_saved_animation_impl(animation_id, promise)) { - // TODO invokeAfter and log event - auto file_view = td_->file_manager_->get_file_view(animation_id); - td_->create_handler(std::move(promise))->send(file_view.remote_location().as_input_document(), false); + send_save_gif_query(animation_id, false, std::move(promise)); } } @@ -697,12 +730,7 @@ void AnimationsManager::remove_saved_animation(const tl_object_ptrfile_manager_->get_file_view(file_id); - CHECK(file_view.has_remote_location()); - CHECK(file_view.remote_location().is_document()) << file_view.remote_location(); - CHECK(!file_view.remote_location().is_web()); - td_->create_handler(std::move(promise))->send(file_view.remote_location().as_input_document(), true); + send_save_gif_query(file_id, true, std::move(promise)); saved_animation_ids_.erase(it); @@ -716,19 +744,22 @@ td_api::object_ptr AnimationsManager::get_update_ void AnimationsManager::send_update_saved_animations(bool from_database) { if (are_saved_animations_loaded_) { - if (!saved_animations_file_source_id_.is_valid() && !saved_animation_ids_.empty()) { - saved_animations_file_source_id_ = td_->file_reference_manager_->create_saved_animations_file_source(); - } + vector new_saved_animation_file_ids = saved_animation_ids_; for (auto &animation_id : saved_animation_ids_) { - td_->file_manager_->add_file_source(animation_id, saved_animations_file_source_id_); auto thumbnail_file_id = get_animation_thumbnail_file_id(animation_id); if (thumbnail_file_id.is_valid()) { - td_->file_manager_->add_file_source(thumbnail_file_id, saved_animations_file_source_id_); + new_saved_animation_file_ids.push_back(thumbnail_file_id); } } - // there is no much reason to delete source from deleted saved animations, - // it will be automatically deleted after unsuccessfull try of file reference repairing - // moreover one thumbnail can belong to different animations, so removal should be careful + std::sort(new_saved_animation_file_ids.begin(), new_saved_animation_file_ids.end()); + if (new_saved_animation_file_ids != saved_animation_file_ids_) { + if (!saved_animations_file_source_id_.is_valid()) { + saved_animations_file_source_id_ = td_->file_reference_manager_->create_saved_animations_file_source(); + } + td_->file_manager_->change_files_source(saved_animations_file_source_id_, saved_animation_file_ids_, + new_saved_animation_file_ids); + saved_animation_file_ids_ = std::move(new_saved_animation_file_ids); + } send_closure(G()->td(), &Td::send_update, get_update_saved_animations_object()); diff --git a/td/telegram/AnimationsManager.h b/td/telegram/AnimationsManager.h index 1791a4fcf..4d68d1d6c 100644 --- a/td/telegram/AnimationsManager.h +++ b/td/telegram/AnimationsManager.h @@ -68,6 +68,8 @@ class AnimationsManager : public Actor { vector get_saved_animations(Promise &&promise); + void send_save_gif_query(FileId animation_id, bool unsave, Promise &&promise); + void add_saved_animation(const tl_object_ptr &input_file, Promise &&promise); void add_saved_animation_by_id(FileId animation_id); @@ -133,6 +135,7 @@ class AnimationsManager : public Actor { int32 saved_animations_limit_ = 200; vector saved_animation_ids_; + vector saved_animation_file_ids_; double next_saved_animations_load_time_ = 0; bool are_saved_animations_loaded_ = false; vector> load_saved_animations_queries_; diff --git a/td/telegram/FileReferenceManager.cpp b/td/telegram/FileReferenceManager.cpp index c9e427848..e094b0b02 100644 --- a/td/telegram/FileReferenceManager.cpp +++ b/td/telegram/FileReferenceManager.cpp @@ -128,14 +128,19 @@ void FileReferenceManager::run_node(NodeId node_id) { if (node.query->active_queries != 0) { return; } - VLOG(file_references) << "Run file references repair for file " << node_id; + VLOG(file_references) << "Trying to repair file reference for file " << node_id; if (node.query->promises.empty()) { node.query = {}; return; } if (!node.file_source_ids.has_next()) { + VLOG(file_references) << "Have no more file sources to repair file reference for file " << node_id; for (auto &p : node.query->promises) { - p.set_value(Unit()); + if (node.file_source_ids.empty()) { + p.set_error(Status::Error(400, "File not found")); + } else { + p.set_error(Status::Error(429, "Too Many Requests: retry after 1")); + } } node.query = {}; return; @@ -253,7 +258,7 @@ void FileReferenceManager::repair_file_reference(NodeId node_id, Promise<> promi node.query = make_unique(); node.query->generation = ++query_generation_; node.file_source_ids.reset_position(); - VLOG(file_references) << "new query " << query_generation_; + VLOG(file_references) << "Create new file reference repair query with " << query_generation_; } node.query->promises.push_back(std::move(promise)); run_node(node_id); diff --git a/td/telegram/FileReferenceManager.h b/td/telegram/FileReferenceManager.h index 0e0730861..a1b7dfdcc 100644 --- a/td/telegram/FileReferenceManager.h +++ b/td/telegram/FileReferenceManager.h @@ -42,8 +42,11 @@ class FileReferenceManager : public Actor { using NodeId = FileId; void repair_file_reference(NodeId node_id, Promise<> promise); + void add_file_source(NodeId node_id, FileSourceId file_source_id); + void remove_file_source(NodeId node_id, FileSourceId file_source_id); + void merge(NodeId to_node_id, NodeId from_node_id); private: diff --git a/td/telegram/SetWithPosition.h b/td/telegram/SetWithPosition.h index 915d3ed22..48d8d4ba3 100644 --- a/td/telegram/SetWithPosition.h +++ b/td/telegram/SetWithPosition.h @@ -77,6 +77,10 @@ class FastSetWithPosition { return checked_.size() + not_checked_.size(); } + bool empty() const { + return size() == 0; + } + private: std::set checked_; std::set not_checked_; @@ -168,6 +172,13 @@ class SetWithPosition { return static_cast(has_value_); } + bool empty() const { + if (fast_) { + return false; + } + return !has_value_; + } + private: T value_{}; bool has_value_{false}; diff --git a/td/telegram/StickersManager.cpp b/td/telegram/StickersManager.cpp index f06ac6b57..a63cdf410 100644 --- a/td/telegram/StickersManager.cpp +++ b/td/telegram/StickersManager.cpp @@ -241,7 +241,7 @@ class SaveRecentStickerQuery : public Td::ResultHandler { explicit SaveRecentStickerQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(bool is_attached, tl_object_ptr &&input_document, bool unsave) { + void send(bool is_attached, tl_object_ptr &&input_document, bool unsave) { is_attached_ = is_attached; int32 flags = 0; @@ -347,7 +347,7 @@ class FaveStickerQuery : public Td::ResultHandler { explicit FaveStickerQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(tl_object_ptr &&input_document, bool unsave) { + void send(tl_object_ptr &&input_document, bool unsave) { send_query(G()->net_query_creator().create( create_storer(telegram_api::messages_faveSticker(std::move(input_document), unsave)))); } @@ -666,7 +666,7 @@ class SetStickerPositionQuery : public Td::ResultHandler { explicit SetStickerPositionQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(tl_object_ptr &&input_document, int32 position) { + void send(tl_object_ptr &&input_document, int32 position) { send_query(G()->net_query_creator().create( create_storer(telegram_api::stickers_changeStickerPosition(std::move(input_document), position)))); } @@ -695,7 +695,7 @@ class DeleteStickerFromSetQuery : public Td::ResultHandler { explicit DeleteStickerFromSetQuery(Promise &&promise) : promise_(std::move(promise)) { } - void send(tl_object_ptr &&input_document) { + void send(tl_object_ptr &&input_document) { send_query(G()->net_query_creator().create( create_storer(telegram_api::stickers_removeStickerFromSet(std::move(input_document))))); } diff --git a/td/telegram/files/FileLocation.h b/td/telegram/files/FileLocation.h index 379b720c9..033f0619f 100644 --- a/td/telegram/files/FileLocation.h +++ b/td/telegram/files/FileLocation.h @@ -480,7 +480,7 @@ class FullRemoteFileLocation { } #define as_input_document() as_input_document_impl(__FILE__, __LINE__) - tl_object_ptr as_input_document_impl(const char *file, int line) const { + tl_object_ptr as_input_document_impl(const char *file, int line) const { CHECK(is_common()) << file << ' ' << line; CHECK(is_document()) << file << ' ' << line; return make_tl_object(common().id_, common().access_hash_, @@ -488,18 +488,18 @@ class FullRemoteFileLocation { } #define as_input_photo() as_input_photo_impl(__FILE__, __LINE__) - tl_object_ptr as_input_photo_impl(const char *file, int line) const { + tl_object_ptr as_input_photo_impl(const char *file, int line) const { CHECK(is_photo()) << file << ' ' << line; return make_tl_object(photo().id_, photo().access_hash_, BufferSlice(file_reference_)); } - tl_object_ptr as_input_encrypted_file() const { + tl_object_ptr as_input_encrypted_file() const { CHECK(is_encrypted_secret()); return make_tl_object(common().id_, common().access_hash_); } #define as_input_secure_file() as_input_secure_file_impl(__FILE__, __LINE__) - tl_object_ptr as_input_secure_file_impl(const char *file, int line) const { + tl_object_ptr as_input_secure_file_impl(const char *file, int line) const { CHECK(is_secure()) << file << ' ' << line; return make_tl_object(common().id_, common().access_hash_); } diff --git a/td/telegram/files/FileManager.cpp b/td/telegram/files/FileManager.cpp index b163f5ba2..34d999576 100644 --- a/td/telegram/files/FileManager.cpp +++ b/td/telegram/files/FileManager.cpp @@ -164,7 +164,7 @@ void FileNode::set_remote_location(const RemoteFileLocation &remote, FileLocatio void FileNode::delete_file_reference(Slice file_reference) { if (remote_.type() == RemoteFileLocation::Type::Full && remote_.full().delete_file_reference(file_reference)) { - VLOG(file_references) << "Delete file reference of file " << main_file_id_; + VLOG(file_references) << "Do delete file reference of main file " << main_file_id_; upload_was_update_file_reference_ = false; download_was_update_file_reference_ = false; on_pmc_changed(); @@ -1915,7 +1915,7 @@ bool FileManager::delete_partial_remote_location(FileId file_id) { void FileManager::delete_file_reference(FileId file_id, string file_reference) { VLOG(file_references) << "Delete file reference of file " << file_id << " " - << tag("reference", base64_encode(file_reference)); + << tag("reference_base64", base64_encode(file_reference)); auto node = get_sync_file_node(file_id); if (!node) { LOG(ERROR) << "Wrong file id " << file_id;