summaryrefslogtreecommitdiff
path: root/protocols/Telegram/tdlib/td/td/telegram/files/FileManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Telegram/tdlib/td/td/telegram/files/FileManager.cpp')
-rw-r--r--protocols/Telegram/tdlib/td/td/telegram/files/FileManager.cpp1927
1 files changed, 1386 insertions, 541 deletions
diff --git a/protocols/Telegram/tdlib/td/td/telegram/files/FileManager.cpp b/protocols/Telegram/tdlib/td/td/telegram/files/FileManager.cpp
index 31220c6127..a53aacb8b2 100644
--- a/protocols/Telegram/tdlib/td/td/telegram/files/FileManager.cpp
+++ b/protocols/Telegram/tdlib/td/td/telegram/files/FileManager.cpp
@@ -1,5 +1,5 @@
//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2024
//
// 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)
@@ -72,24 +72,42 @@ StringBuilder &operator<<(StringBuilder &string_builder, FileLocationSource sour
}
}
-StringBuilder &operator<<(StringBuilder &string_builder, FileManager::Query::Type type) {
+StringBuilder &operator<<(StringBuilder &string_builder, const NewRemoteFileLocation &location) {
+ if (location.is_full_alive) {
+ string_builder << "alive ";
+ }
+ if (location.full) {
+ string_builder << location.full.value();
+ } else {
+ string_builder << "[no location]";
+ }
+ return string_builder << " from " << location.full_source;
+}
+
+StringBuilder &operator<<(StringBuilder &string_builder, FileManager::DownloadQuery::Type type) {
switch (type) {
- case FileManager::Query::Type::UploadByHash:
- return string_builder << "UploadByHash";
- case FileManager::Query::Type::UploadWaitFileReference:
- return string_builder << "UploadWaitFileReference";
- case FileManager::Query::Type::Upload:
- return string_builder << "Upload";
- case FileManager::Query::Type::DownloadWaitFileReference:
+ case FileManager::DownloadQuery::Type::DownloadWaitFileReference:
return string_builder << "DownloadWaitFileReference";
- case FileManager::Query::Type::DownloadReloadDialog:
+ case FileManager::DownloadQuery::Type::DownloadReloadDialog:
return string_builder << "DownloadReloadDialog";
- case FileManager::Query::Type::Download:
+ case FileManager::DownloadQuery::Type::Download:
return string_builder << "Download";
- case FileManager::Query::Type::SetContent:
+ case FileManager::DownloadQuery::Type::SetContent:
return string_builder << "SetContent";
- case FileManager::Query::Type::Generate:
- return string_builder << "Generate";
+ default:
+ UNREACHABLE();
+ return string_builder << "Unknown";
+ }
+}
+
+StringBuilder &operator<<(StringBuilder &string_builder, FileManager::UploadQuery::Type type) {
+ switch (type) {
+ case FileManager::UploadQuery::Type::UploadByHash:
+ return string_builder << "UploadByHash";
+ case FileManager::UploadQuery::Type::UploadWaitFileReference:
+ return string_builder << "UploadWaitFileReference";
+ case FileManager::UploadQuery::Type::Upload:
+ return string_builder << "Upload";
default:
UNREACHABLE();
return string_builder << "Unknown";
@@ -120,6 +138,382 @@ RemoteFileLocation NewRemoteFileLocation::partial_or_empty() const {
return {};
}
+class FileManager::FileInfoLocal final : public FileManager::FileInfo {
+ FullLocalFileLocation location_;
+ int64 size_ = 0;
+ unique_ptr<PartialRemoteFileLocation> partial_remote_location_;
+ const FileIdInfo *remote_file_info_ = nullptr;
+
+ public:
+ FileInfoLocal(FullLocalFileLocation location, int64 size) : location_(std::move(location)), size_(size) {
+ }
+
+ FileInfoType get_file_info_type() const final {
+ return FileInfoType::Local;
+ }
+
+ FileType get_file_type() const final {
+ return location_.file_type_;
+ }
+
+ int64 get_local_size() const final {
+ return size_;
+ }
+
+ int64 get_remote_size() const final {
+ if (remote_file_info_ != nullptr) {
+ if (remote_file_info_->file_info_ != nullptr) {
+ return remote_file_info_->file_info_->get_remote_size();
+ }
+ return 0;
+ }
+ if (partial_remote_location_ != nullptr) {
+ return partial_remote_location_->ready_size_;
+ }
+ return 0;
+ }
+
+ int64 get_size() const final {
+ return size_;
+ }
+
+ int64 get_expected_size(bool) const final {
+ return size_;
+ }
+
+ const FullLocalFileLocation *get_local_location() const final {
+ return &location_;
+ }
+
+ const FullGenerateFileLocation *get_generate_location() const final {
+ return nullptr;
+ }
+
+ const FullRemoteFileLocation *get_remote_location() const final {
+ if (remote_file_info_ != nullptr && remote_file_info_->file_info_ != nullptr) {
+ return remote_file_info_->file_info_->get_remote_location();
+ }
+ return nullptr;
+ }
+
+ const string *get_url() const final {
+ return nullptr;
+ }
+
+ string get_path() const final {
+ return location_.path_;
+ }
+
+ string get_suggested_path() const final {
+ return location_.path_;
+ }
+
+ string get_remote_name() const final {
+ return string();
+ }
+
+ string get_persistent_file_id() const final {
+ return string();
+ }
+
+ string get_unique_file_id() const final {
+ return string();
+ }
+
+ bool can_be_deleted() const final {
+ return begins_with(location_.path_, get_files_dir(get_file_type()));
+ }
+
+ unique_ptr<FileInfo> clone() const final {
+ auto result = make_unique<FileInfoLocal>(location_, size_);
+ result->remote_file_info_ = remote_file_info_;
+ return result;
+ }
+};
+
+class FileManager::FileInfoGenerate final : public FileManager::FileInfo {
+ FullGenerateFileLocation location_;
+ int64 expected_size_ = 0;
+ string url_;
+ unique_ptr<PartialLocalFileLocation> partial_local_location_;
+ unique_ptr<PartialRemoteFileLocation> partial_remote_location_;
+ const FileIdInfo *local_file_info_ = nullptr;
+
+ public:
+ FileInfoGenerate(FullGenerateFileLocation location, int64 expected_size, string url)
+ : location_(std::move(location)), expected_size_(expected_size), url_(std::move(url)) {
+ }
+
+ FileInfoType get_file_info_type() const final {
+ return FileInfoType::Generate;
+ }
+
+ FileType get_file_type() const final {
+ return location_.file_type_;
+ }
+
+ int64 get_local_size() const final {
+ if (local_file_info_ != nullptr) {
+ if (local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->get_local_size();
+ }
+ return 0;
+ }
+ if (partial_local_location_ != nullptr) {
+ return partial_local_location_->ready_size_;
+ }
+ return 0;
+ }
+
+ int64 get_remote_size() const final {
+ if (local_file_info_ != nullptr) {
+ if (local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->get_remote_size();
+ }
+ return 0;
+ }
+ if (partial_remote_location_ != nullptr) {
+ return partial_remote_location_->ready_size_;
+ }
+ return 0;
+ }
+
+ int64 get_size() const final {
+ if (local_file_info_ == nullptr) {
+ return 0;
+ }
+ if (local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->get_size();
+ }
+ return 0;
+ }
+
+ int64 get_expected_size(bool may_guess) const final {
+ if (local_file_info_ != nullptr) {
+ if (local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->get_size();
+ }
+ return 0;
+ }
+ int64 current_size = 0;
+ if (partial_local_location_ != nullptr) {
+ current_size = partial_local_location_->ready_size_;
+ }
+ if (expected_size_ != 0) {
+ return max(current_size, expected_size_);
+ }
+ return may_guess ? current_size * 3 : current_size;
+ }
+
+ const FullLocalFileLocation *get_local_location() const final {
+ if (local_file_info_ != nullptr && local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->get_local_location();
+ }
+ return nullptr;
+ }
+
+ const FullGenerateFileLocation *get_generate_location() const final {
+ return &location_;
+ }
+
+ const FullRemoteFileLocation *get_remote_location() const final {
+ if (local_file_info_ != nullptr && local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->get_remote_location();
+ }
+ return nullptr;
+ }
+
+ const string *get_url() const final {
+ return url_.empty() ? nullptr : &url_;
+ }
+
+ string get_path() const final {
+ if (local_file_info_ != nullptr) {
+ if (local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->get_path();
+ }
+ return string();
+ }
+ if (partial_local_location_ != nullptr) {
+ return partial_local_location_->path_;
+ }
+ return string();
+ }
+
+ string get_suggested_path() const final {
+ if (!url_.empty()) {
+ return get_url_file_name(url_);
+ }
+ return location_.original_path_;
+ }
+
+ string get_remote_name() const final {
+ return string();
+ }
+
+ string get_persistent_file_id() const final {
+ if (!url_.empty()) {
+ return url_;
+ }
+ if (FileManager::is_remotely_generated_file(location_.conversion_)) {
+ return FileNode::get_persistent_id(location_);
+ }
+ return string();
+ }
+
+ string get_unique_file_id() const final {
+ if (FileManager::is_remotely_generated_file(location_.conversion_)) {
+ return FileNode::get_unique_id(location_);
+ }
+ return string();
+ }
+
+ bool can_be_deleted() const final {
+ if (local_file_info_ != nullptr) {
+ if (local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->can_be_deleted();
+ }
+ return false;
+ }
+ return partial_local_location_ != nullptr;
+ }
+
+ unique_ptr<FileInfo> clone() const final {
+ return td::make_unique<FileInfoGenerate>(location_, expected_size_, url_);
+ }
+};
+
+class FileManager::FileInfoRemote final : public FileManager::FileInfo {
+ FullRemoteFileLocation location_;
+ int64 size_ = 0;
+ int64 expected_size_ = 0;
+ string remote_name_;
+ string url_;
+ unique_ptr<PartialLocalFileLocation> partial_local_location_;
+ const FileIdInfo *local_file_info_ = nullptr;
+
+ public:
+ FileInfoRemote(FullRemoteFileLocation location, int64 size, int64 expected_size, string remote_name, string url)
+ : location_(std::move(location))
+ , size_(size)
+ , expected_size_(expected_size)
+ , remote_name_(std::move(remote_name))
+ , url_(std::move(url)) {
+ }
+
+ FileInfoType get_file_info_type() const final {
+ return FileInfoType::Remote;
+ }
+
+ FileType get_file_type() const final {
+ return location_.file_type_;
+ }
+
+ int64 get_local_size() const final {
+ if (local_file_info_ != nullptr) {
+ if (local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->get_local_size();
+ }
+ return 0;
+ }
+ if (partial_local_location_ != nullptr) {
+ return partial_local_location_->ready_size_;
+ }
+ return 0;
+ }
+
+ int64 get_remote_size() const final {
+ return size_;
+ }
+
+ int64 get_size() const final {
+ return size_;
+ }
+
+ int64 get_expected_size(bool) const final {
+ if (size_ != 0) {
+ return size_;
+ }
+ if (partial_local_location_ != nullptr) {
+ return max(partial_local_location_->ready_size_, expected_size_);
+ }
+ return expected_size_;
+ }
+
+ const FullLocalFileLocation *get_local_location() const final {
+ if (local_file_info_ != nullptr && local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->get_local_location();
+ }
+ return nullptr;
+ }
+
+ const FullGenerateFileLocation *get_generate_location() const final {
+ return nullptr;
+ }
+
+ const FullRemoteFileLocation *get_remote_location() const final {
+ return &location_;
+ }
+
+ const string *get_url() const final {
+ return url_.empty() ? nullptr : &url_;
+ }
+
+ string get_path() const final {
+ if (local_file_info_ != nullptr) {
+ if (local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->get_path();
+ }
+ return string();
+ }
+ if (partial_local_location_ != nullptr) {
+ return partial_local_location_->path_;
+ }
+ return string();
+ }
+
+ string get_suggested_path() const final {
+ if (!remote_name_.empty()) {
+ return remote_name_;
+ }
+ if (!url_.empty()) {
+ return get_url_file_name(url_);
+ }
+ return string();
+ }
+
+ string get_remote_name() const final {
+ return remote_name_;
+ }
+
+ string get_persistent_file_id() const final {
+ return FileNode::get_persistent_id(location_);
+ }
+
+ string get_unique_file_id() const final {
+ if (location_.is_web()) {
+ return string();
+ }
+ return FileNode::get_unique_id(location_);
+ }
+
+ bool can_be_deleted() const final {
+ if (local_file_info_ != nullptr) {
+ if (local_file_info_->file_info_ != nullptr) {
+ return local_file_info_->file_info_->can_be_deleted();
+ }
+ return false;
+ }
+ return partial_local_location_ != nullptr;
+ }
+
+ unique_ptr<FileInfo> clone() const final {
+ auto result = td::make_unique<FileInfoRemote>(location_, size_, expected_size_, remote_name_, url_);
+ result->local_file_info_ = local_file_info_;
+ return result;
+ }
+};
+
FileNode *FileNodePtr::operator->() const {
return get();
}
@@ -170,9 +564,10 @@ void FileNode::init_ready_size() {
if (local_.type() != LocalFileLocation::Type::Partial) {
return;
}
- auto bitmask = Bitmask(Bitmask::Decode{}, local_.partial().ready_bitmask_);
- local_ready_prefix_size_ = bitmask.get_ready_prefix_size(0, local_.partial().part_size_, size_);
- local_ready_size_ = bitmask.get_total_size(local_.partial().part_size_, size_);
+ auto &partial = local_.partial();
+ auto bitmask = Bitmask(Bitmask::Decode{}, partial.ready_bitmask_);
+ local_ready_prefix_size_ = bitmask.get_ready_prefix_size(0, partial.part_size_, size_);
+ partial.ready_size_ = bitmask.get_total_size(partial.part_size_, size_);
}
void FileNode::set_download_offset(int64 download_offset) {
@@ -233,17 +628,10 @@ void FileNode::set_ignore_download_limit(bool ignore_download_limit) {
}
void FileNode::drop_local_location() {
- set_local_location(LocalFileLocation(), 0, -1, -1);
+ set_local_location(LocalFileLocation(), -1, -1);
}
-void FileNode::set_local_location(const LocalFileLocation &local, int64 ready_size, int64 prefix_offset,
- int64 ready_prefix_size) {
- if (local_ready_size_ != ready_size) {
- VLOG(update_file) << "File " << main_file_id_ << " has changed local ready size from " << local_ready_size_
- << " to " << ready_size;
- local_ready_size_ = ready_size;
- on_info_changed();
- }
+void FileNode::set_local_location(const LocalFileLocation &local, int64 prefix_offset, int64 ready_prefix_size) {
if (local_ != local) {
VLOG(update_file) << "File " << main_file_id_ << " has changed local location";
local_ = local;
@@ -280,7 +668,7 @@ void FileNode::set_new_remote_location(NewRemoteFileLocation new_remote) {
}
if (new_remote.partial) {
- set_partial_remote_location(*new_remote.partial, new_remote.ready_size);
+ set_partial_remote_location(*new_remote.partial);
} else {
delete_partial_remote_location();
}
@@ -291,25 +679,13 @@ void FileNode::delete_partial_remote_location() {
remote_.partial.reset();
on_changed();
}
- if (remote_.ready_size != 0) {
- VLOG(update_file) << "File " << main_file_id_ << " has changed remote ready size from " << remote_.ready_size
- << " to " << 0;
- remote_.ready_size = 0;
- on_info_changed();
- }
}
-void FileNode::set_partial_remote_location(PartialRemoteFileLocation remote, int64 ready_size) {
+void FileNode::set_partial_remote_location(PartialRemoteFileLocation remote) {
if (remote_.is_full_alive) {
VLOG(update_file) << "File " << main_file_id_ << " remote is still alive, so there is NO reason to update partial";
return;
}
- if (remote_.ready_size != ready_size) {
- VLOG(update_file) << "File " << main_file_id_ << " has changed remote ready size from " << remote_.ready_size
- << " to " << ready_size;
- remote_.ready_size = ready_size;
- on_info_changed();
- }
if (remote_.partial && *remote_.partial == remote) {
VLOG(update_file) << "Partial location of " << main_file_id_ << " is NOT changed";
return;
@@ -515,16 +891,18 @@ string FileNode::suggested_path() const {
}
/*** FileView ***/
-bool FileView::has_local_location() const {
+bool FileView::has_full_local_location() const {
return node_->local_.type() == LocalFileLocation::Type::Full;
}
-const FullLocalFileLocation &FileView::local_location() const {
- CHECK(has_local_location());
- return node_->local_.full();
+const FullLocalFileLocation *FileView::get_full_local_location() const {
+ if (!has_full_local_location()) {
+ return nullptr;
+ }
+ return &node_->local_.full();
}
-bool FileView::has_remote_location() const {
+bool FileView::has_full_remote_location() const {
return static_cast<bool>(node_->remote_.full);
}
@@ -533,49 +911,54 @@ bool FileView::has_alive_remote_location() const {
}
bool FileView::has_active_upload_remote_location() const {
- if (!has_remote_location()) {
+ const auto *main_remote_location = get_main_remote_location();
+ if (main_remote_location == nullptr) {
return false;
}
if (!has_alive_remote_location()) {
return false;
}
- if (main_remote_location().is_encrypted_any()) {
+ if (main_remote_location->is_encrypted_any()) {
return true;
}
- return main_remote_location().has_file_reference();
+ return main_remote_location->has_file_reference();
}
bool FileView::has_active_download_remote_location() const {
- if (!has_remote_location()) {
+ const auto *full_remote_location = get_full_remote_location();
+ if (full_remote_location == nullptr) {
return false;
}
- if (remote_location().is_encrypted_any()) {
+ if (full_remote_location->is_encrypted_any()) {
return true;
}
- return remote_location().has_file_reference();
+ return full_remote_location->has_file_reference();
}
-const FullRemoteFileLocation &FileView::remote_location() const {
- CHECK(has_remote_location());
- auto *remote = node_.get_remote();
- if (remote) {
- return *remote;
+const FullRemoteFileLocation *FileView::get_full_remote_location() const {
+ const auto *remote = node_.get_remote();
+ if (remote != nullptr) {
+ return remote;
+ }
+ if (!has_full_remote_location()) {
+ return nullptr;
}
- return node_->remote_.full.value();
+ return &node_->remote_.full.value();
}
-const FullRemoteFileLocation &FileView::main_remote_location() const {
- CHECK(has_remote_location());
- return node_->remote_.full.value();
+const FullRemoteFileLocation *FileView::get_main_remote_location() const {
+ if (!has_full_remote_location()) {
+ return nullptr;
+ }
+ return &node_->remote_.full.value();
}
bool FileView::has_generate_location() const {
return node_->generate_ != nullptr;
}
-const FullGenerateFileLocation &FileView::generate_location() const {
- CHECK(has_generate_location());
- return *node_->generate_;
+const FullGenerateFileLocation *FileView::get_generate_location() const {
+ return node_->generate_.get();
}
int64 FileView::size() const {
@@ -594,124 +977,149 @@ int64 FileView::get_allocated_local_size() const {
return r_stat.ok().real_size_;
}
-int64 FileView::expected_size(bool may_guess) const {
- if (node_->size_ != 0) {
- return node_->size_;
+int64 FileNode::expected_size(bool may_guess) const {
+ if (size_ != 0) {
+ return size_;
}
int64 current_size = local_total_size(); // TODO: this is not the best approximation
- if (node_->expected_size_ != 0) {
- return max(current_size, node_->expected_size_);
+ if (expected_size_ != 0) {
+ return max(current_size, expected_size_);
}
- if (may_guess && node_->local_.type() == LocalFileLocation::Type::Partial) {
+ if (may_guess && local_.type() == LocalFileLocation::Type::Partial) {
current_size *= 3;
}
return current_size;
}
+int64 FileView::expected_size(bool may_guess) const {
+ return node_->expected_size(may_guess);
+}
+
+bool FileNode::is_downloading() const {
+ return download_priority_ != 0 || generate_download_priority_ != 0;
+}
+
bool FileView::is_downloading() const {
- return node_->download_priority_ != 0 || node_->generate_download_priority_ != 0;
+ return node_->is_downloading();
}
int64 FileView::download_offset() const {
return node_->download_offset_;
}
-int64 FileView::downloaded_prefix(int64 offset) const {
- switch (node_->local_.type()) {
+int64 FileNode::downloaded_prefix(int64 offset) const {
+ switch (local_.type()) {
case LocalFileLocation::Type::Empty:
return 0;
case LocalFileLocation::Type::Full:
- if (offset < node_->size_) {
- return node_->size_ - offset;
+ if (offset < size_) {
+ return size_ - offset;
}
return 0;
case LocalFileLocation::Type::Partial:
- if (is_encrypted_secure()) {
+ if (get_type() == FileType::SecureEncrypted) {
// File is not decrypted and verified yet
return 0;
}
- return Bitmask(Bitmask::Decode{}, node_->local_.partial().ready_bitmask_)
- .get_ready_prefix_size(offset, node_->local_.partial().part_size_, node_->size_);
+ return Bitmask(Bitmask::Decode{}, local_.partial().ready_bitmask_)
+ .get_ready_prefix_size(offset, local_.partial().part_size_, size_);
default:
UNREACHABLE();
return 0;
}
}
-int64 FileView::local_prefix_size() const {
- switch (node_->local_.type()) {
+int64 FileView::downloaded_prefix(int64 offset) const {
+ return node_->downloaded_prefix(offset);
+}
+
+int64 FileNode::local_prefix_size() const {
+ switch (local_.type()) {
case LocalFileLocation::Type::Full:
- return node_->download_offset_ <= node_->size_ ? node_->size_ - node_->download_offset_ : 0;
+ return download_offset_ <= size_ ? size_ - download_offset_ : 0;
case LocalFileLocation::Type::Partial: {
- if (is_encrypted_secure()) {
+ if (get_type() == FileType::SecureEncrypted) {
// File is not decrypted and verified yet
return 0;
}
- return node_->local_ready_prefix_size_;
+ return local_ready_prefix_size_;
}
default:
return 0;
}
}
-int64 FileView::local_total_size() const {
- switch (node_->local_.type()) {
+
+int64 FileView::local_prefix_size() const {
+ return node_->local_prefix_size();
+}
+
+int64 FileNode::local_total_size() const {
+ switch (local_.type()) {
case LocalFileLocation::Type::Empty:
return 0;
case LocalFileLocation::Type::Full:
- return node_->size_;
+ return size_;
case LocalFileLocation::Type::Partial:
- VLOG(update_file) << "Have local_ready_prefix_size = " << node_->local_ready_prefix_size_
- << " and local_ready_size = " << node_->local_ready_size_;
- return max(node_->local_ready_prefix_size_, node_->local_ready_size_);
+ return local_.partial().ready_size_;
default:
UNREACHABLE();
return 0;
}
}
+int64 FileView::local_total_size() const {
+ return node_->local_total_size();
+}
+
+bool FileNode::is_uploading() const {
+ return upload_priority_ != 0 || generate_upload_priority_ != 0 || upload_pause_.is_valid();
+}
+
bool FileView::is_uploading() const {
- return node_->upload_priority_ != 0 || node_->generate_upload_priority_ != 0 || node_->upload_pause_.is_valid();
+ return node_->is_uploading();
}
-int64 FileView::remote_size() const {
- if (node_->remote_.is_full_alive) {
- return node_->size_;
+int64 FileNode::remote_size() const {
+ if (remote_.is_full_alive) {
+ return size_;
}
- if (node_->remote_.partial) {
- auto part_size = static_cast<int64>(node_->remote_.partial->part_size_);
- auto ready_part_count = node_->remote_.partial->ready_part_count_;
- auto remote_ready_size = node_->remote_.ready_size;
- VLOG(update_file) << "Have part_size = " << part_size << ", remote_ready_part_count = " << ready_part_count
- << ", remote_ready_size = " << remote_ready_size << ", size = " << size();
- auto res = max(part_size * ready_part_count, remote_ready_size);
- if (size() != 0 && size() < res) {
- res = size();
- }
- return res;
+ if (remote_.partial) {
+ return remote_.partial->ready_size_;
}
- return node_->remote_.ready_size; //???
+ return 0;
}
-string FileView::path() const {
- switch (node_->local_.type()) {
+int64 FileView::remote_size() const {
+ return node_->remote_size();
+}
+
+string FileNode::path() const {
+ switch (local_.type()) {
case LocalFileLocation::Type::Full:
- return node_->local_.full().path_;
+ return local_.full().path_;
case LocalFileLocation::Type::Partial:
- return node_->local_.partial().path_;
+ return local_.partial().path_;
default:
return string();
}
}
+string FileView::path() const {
+ return node_->path();
+}
+
bool FileView::has_url() const {
- return !node_->url_.empty();
+ return get_url() != nullptr;
}
-const string &FileView::url() const {
- return node_->url_;
+const string *FileView::get_url() const {
+ if (node_->url_.empty()) {
+ return nullptr;
+ }
+ return &node_->url_;
}
-const string &FileView::remote_name() const {
+string FileView::remote_name() const {
return node_->remote_name_;
}
@@ -735,19 +1143,20 @@ bool FileView::empty() const {
}
bool FileView::can_download_from_server() const {
- if (!has_remote_location()) {
+ const auto *full_remote_location = get_full_remote_location();
+ if (full_remote_location == nullptr) {
return false;
}
- if (remote_location().file_type_ == FileType::Encrypted && encryption_key().empty()) {
+ if (full_remote_location->file_type_ == FileType::Encrypted && encryption_key().empty()) {
return false;
}
- if (remote_location().is_web()) {
+ if (full_remote_location->is_web()) {
return true;
}
- if (remote_location().get_dc_id().is_empty()) {
+ if (full_remote_location->get_dc_id().is_empty()) {
return false;
}
- if (!remote_location().is_encrypted_any() && !remote_location().has_file_reference() &&
+ if (!full_remote_location->is_encrypted_any() && !full_remote_location->has_file_reference() &&
((node_->download_id_ == 0 && node_->download_was_update_file_reference_) || !node_->remote_.is_full_alive)) {
return false;
}
@@ -758,60 +1167,60 @@ bool FileView::can_generate() const {
return has_generate_location();
}
-bool FileView::can_delete() const {
- if (has_local_location()) {
- return begins_with(local_location().path_, get_files_dir(get_type()));
+bool FileNode::can_delete() const {
+ if (local_.type() == LocalFileLocation::Type::Full) {
+ return begins_with(local_.full().path_, get_files_dir(get_type()));
}
- return node_->local_.type() == LocalFileLocation::Type::Partial;
+ return local_.type() == LocalFileLocation::Type::Partial;
}
-string FileView::get_unique_id(const FullGenerateFileLocation &location) {
+bool FileView::can_delete() const {
+ return node_->can_delete();
+}
+
+string FileNode::get_unique_id(const FullGenerateFileLocation &location) {
return base64url_encode(zero_encode('\xff' + serialize(location)));
}
-string FileView::get_unique_id(const FullRemoteFileLocation &location) {
+string FileNode::get_unique_id(const FullRemoteFileLocation &location) {
return base64url_encode(zero_encode(serialize(location.as_unique())));
}
-string FileView::get_persistent_id(const FullGenerateFileLocation &location) {
+string FileNode::get_persistent_id(const FullGenerateFileLocation &location) {
auto binary = serialize(location);
binary = zero_encode(binary);
- binary.push_back(FileNode::PERSISTENT_ID_VERSION_GENERATED);
+ binary.push_back(PERSISTENT_ID_VERSION_GENERATED);
return base64url_encode(binary);
}
-string FileView::get_persistent_id(const FullRemoteFileLocation &location) {
+string FileNode::get_persistent_id(const FullRemoteFileLocation &location) {
auto binary = serialize(location);
binary = zero_encode(binary);
binary.push_back(static_cast<char>(narrow_cast<uint8>(Version::Next) - 1));
- binary.push_back(FileNode::PERSISTENT_ID_VERSION);
+ binary.push_back(PERSISTENT_ID_VERSION);
return base64url_encode(binary);
}
-string FileView::get_persistent_file_id() const {
- if (!empty()) {
- if (has_alive_remote_location()) {
- return get_persistent_id(remote_location());
- } else if (has_url()) {
- return url();
- } else if (has_generate_location() && FileManager::is_remotely_generated_file(generate_location().conversion_)) {
- return get_persistent_id(generate_location());
- }
+string FileNode::get_persistent_file_id() const {
+ if (remote_.is_full_alive) {
+ return get_persistent_id(remote_.full.value());
+ } else if (!url_.empty()) {
+ return url_;
+ } else if (generate_ != nullptr && FileManager::is_remotely_generated_file(generate_->conversion_)) {
+ return get_persistent_id(*generate_);
}
return string();
}
-string FileView::get_unique_file_id() const {
- if (!empty()) {
- if (has_alive_remote_location()) {
- if (!remote_location().is_web()) {
- return get_unique_id(remote_location());
- }
- } else if (has_generate_location() && FileManager::is_remotely_generated_file(generate_location().conversion_)) {
- return get_unique_id(generate_location());
+string FileNode::get_unique_file_id() const {
+ if (remote_.is_full_alive) {
+ if (!remote_.full.value().is_web()) {
+ return get_unique_id(remote_.full.value());
}
+ } else if (generate_ != nullptr && FileManager::is_remotely_generated_file(generate_->conversion_)) {
+ return get_unique_id(*generate_);
}
return string();
}
@@ -839,8 +1248,13 @@ FileManager::FileManager(unique_ptr<Context> context) : context_(std::move(conte
}
void FileManager::init_actor() {
- file_load_manager_ = create_actor_on_scheduler<FileLoadManager>("FileLoadManager", G()->get_slow_net_scheduler_id(),
- actor_shared(this), context_->create_reference());
+ file_download_manager_ = create_actor_on_scheduler<FileDownloadManager>(
+ "FileDownloadManager", G()->get_slow_net_scheduler_id(), make_unique<FileDownloadManagerCallback>(actor_id(this)),
+ context_->create_reference());
+ file_load_manager_ = create_actor_on_scheduler<FileLoadManager>("FileLoadManager", G()->get_slow_net_scheduler_id());
+ file_upload_manager_ = create_actor_on_scheduler<FileUploadManager>(
+ "FileUploadManager", G()->get_slow_net_scheduler_id(), make_unique<FileUploadManagerCallback>(actor_id(this)),
+ context_->create_reference());
file_generate_manager_ = create_actor_on_scheduler<FileGenerateManager>(
"FileGenerateManager", G()->get_slow_net_scheduler_id(), context_->create_reference());
}
@@ -867,6 +1281,7 @@ string FileManager::get_file_name(FileType file_type, Slice path) {
break;
case FileType::ProfilePhoto:
case FileType::Photo:
+ case FileType::PhotoStory:
if (extension != "jpg" && extension != "jpeg" && extension != "gif" && extension != "png" && extension != "tif" &&
extension != "bmp") {
return fix_file_extension(file_name, "photo", "jpg");
@@ -885,6 +1300,11 @@ string FileManager::get_file_name(FileType file_type, Slice path) {
return fix_file_extension(file_name, "video", "mp4");
}
break;
+ case FileType::VideoStory:
+ if (extension != "mp4") {
+ return fix_file_extension(file_name, "video", "mp4");
+ }
+ break;
case FileType::Audio:
if (extension != "ogg" && extension != "oga" && extension != "mp3" && extension != "mpeg3" &&
extension != "m4a") {
@@ -927,6 +1347,23 @@ bool FileManager::is_remotely_generated_file(Slice conversion) {
return begins_with(conversion, "#map#") || begins_with(conversion, "#audio_t#");
}
+vector<int> FileManager::get_missing_file_parts(const Status &error) {
+ vector<int> result;
+ auto error_message = error.message();
+ if (begins_with(error_message, "FILE_PART_") && ends_with(error_message, "_MISSING")) {
+ auto r_file_part = to_integer_safe<int>(error_message.substr(10, error_message.size() - 18));
+ if (r_file_part.is_error()) {
+ LOG(ERROR) << "Receive error " << error;
+ } else {
+ result.push_back(r_file_part.ok());
+ }
+ }
+ if (error_message == "FILE_PART_INVALID") {
+ result.push_back(0);
+ }
+ return result;
+}
+
void FileManager::check_local_location(FileId file_id, bool skip_file_size_checks) {
auto node = get_sync_file_node(file_id);
if (node) {
@@ -1090,16 +1527,15 @@ bool FileManager::try_fix_partial_local_location(FileNodePtr node) {
partial.part_size_ = new_part_size;
partial.ready_bitmask_ = new_mask.encode();
-
- auto ready_size = new_mask.get_total_size(partial.part_size_, node->size_);
- node->set_local_location(LocalFileLocation(std::move(partial)), ready_size, -1, -1);
+ partial.ready_size_ = new_mask.get_total_size(partial.part_size_, node->size_);
+ node->set_local_location(LocalFileLocation(std::move(partial)), -1, -1);
LOG(INFO) << " ok: increase part_size " << old_part_size << "->" << new_part_size;
return true;
}
FileManager::FileIdInfo *FileManager::get_file_id_info(FileId file_id) {
CHECK(static_cast<size_t>(file_id.get()) < file_id_info_.size());
- return &file_id_info_[file_id.get()];
+ return file_id_info_[file_id.get()].get();
}
FileId FileManager::dup_file_id(FileId file_id, const char *source) {
@@ -1108,7 +1544,15 @@ FileId FileManager::dup_file_id(FileId file_id, const char *source) {
if (!file_node) {
return FileId();
}
- auto result_file_id = FileId(create_file_id(file_node_id, file_node).get(), file_id.get_remote());
+ auto new_file_id = next_file_id();
+ auto file_id_info = get_file_id_info(new_file_id);
+ file_id_info->node_id_ = file_node_id;
+ auto old_file_info = get_file_id_info(file_id)->file_info_.get();
+ if (old_file_info != nullptr) {
+ file_id_info->file_info_ = old_file_info->clone();
+ }
+ file_node->file_ids_.push_back(new_file_id);
+ auto result_file_id = FileId(new_file_id.get(), file_id.get_remote());
LOG(INFO) << "Dup file " << file_id << " to " << result_file_id << " from " << source;
return result_file_id;
}
@@ -1117,32 +1561,24 @@ FileId FileManager::copy_file_id(FileId file_id, FileType file_type, DialogId ow
auto file_view = get_file_view(file_id);
auto download_file_id = dup_file_id(file_id, source);
auto result_file_id =
- register_generate(file_type, FileLocationSource::FromServer, file_view.suggested_path(),
- PSTRING() << "#file_id#" << download_file_id.get(), owner_dialog_id, file_view.size())
- .ok();
+ register_generate(file_type, file_view.suggested_path(), PSTRING() << "#file_id#" << download_file_id.get(),
+ owner_dialog_id, file_view.size());
LOG(INFO) << "Copy file " << file_id << " to " << result_file_id << " from " << source;
return result_file_id;
}
-FileId FileManager::create_file_id(int32 file_node_id, FileNode *file_node) {
- auto file_id = next_file_id();
- get_file_id_info(file_id)->node_id_ = file_node_id;
- file_node->file_ids_.push_back(file_id);
- return file_id;
-}
-
-void FileManager::try_forget_file_id(FileId file_id) {
+bool FileManager::try_forget_file_id(FileId file_id) {
auto *info = get_file_id_info(file_id);
if (info->send_updates_flag_ || info->pin_flag_ || info->sent_file_id_flag_) {
LOG(DEBUG) << "Can't forget file " << file_id << ", because of"
<< (info->send_updates_flag_ ? " (sent updates)" : "") << (info->pin_flag_ ? " (pin)" : "")
<< (info->sent_file_id_flag_ ? " (sent file identifier)" : "");
- return;
+ return false;
}
auto file_node = get_file_node(file_id);
if (file_node->main_file_id_ == file_id) {
LOG(DEBUG) << "Can't forget main file " << file_id;
- return;
+ return false;
}
LOG(DEBUG) << "Forget file " << file_id;
@@ -1150,10 +1586,30 @@ void FileManager::try_forget_file_id(FileId file_id) {
CHECK(is_removed);
*info = FileIdInfo();
empty_file_ids_.push_back(file_id.get());
+ return true;
}
FileId FileManager::register_empty(FileType type) {
- return register_local(FullLocalFileLocation(type, "", 0), DialogId(), 0, false, true).ok();
+ auto location = FullLocalFileLocation(type, "", 0);
+ auto &file_id = local_location_to_file_id_[location];
+ if (file_id.is_valid()) {
+ return file_id;
+ }
+ file_id = next_file_id();
+
+ LOG(INFO) << "Register empty file as " << file_id;
+ auto file_info = STORE_FILE_INFO ? td::make_unique<FileInfoLocal>(location, 0) : nullptr;
+ auto file_node_id = next_file_node_id();
+ file_nodes_[file_node_id] =
+ td::make_unique<FileNode>(LocalFileLocation(std::move(location)), NewRemoteFileLocation(), nullptr, 0, 0,
+ string(), string(), DialogId(), FileEncryptionKey(), file_id, static_cast<int8>(0));
+
+ auto file_id_info = get_file_id_info(file_id);
+ file_id_info->node_id_ = file_node_id;
+ file_id_info->file_info_ = std::move(file_info);
+ file_id_info->pin_flag_ = true;
+
+ return file_id;
}
void FileManager::on_file_unlink(const FullLocalFileLocation &location) {
@@ -1171,48 +1627,142 @@ void FileManager::on_file_unlink(const FullLocalFileLocation &location) {
}
Result<FileId> FileManager::register_local(FullLocalFileLocation location, DialogId owner_dialog_id, int64 size,
- bool get_by_hash, bool force, bool skip_file_size_checks,
- FileId merge_file_id) {
- // TODO: use get_by_hash
- FileData data;
- data.local_ = LocalFileLocation(std::move(location));
- data.owner_dialog_id_ = owner_dialog_id;
- data.size_ = size;
- return register_file(std::move(data), FileLocationSource::None /*won't be used*/, merge_file_id, "register_local",
- force, skip_file_size_checks);
+ bool get_by_hash, bool skip_file_size_checks, FileId merge_file_id) {
+ TRY_RESULT(info, check_full_local_location({std::move(location), size}, skip_file_size_checks));
+ location = std::move(info.location_);
+ size = info.size_;
+
+ if (bad_paths_.count(location.path_) != 0) {
+ return Status::Error(400, "Sending of internal database files is forbidden");
+ }
+
+ auto &file_id = local_location_to_file_id_[location];
+ bool is_new = false;
+ if (!file_id.is_valid()) {
+ file_id = next_file_id();
+ LOG(INFO) << "Register " << location << " as " << file_id;
+
+ auto file_info = STORE_FILE_INFO ? td::make_unique<FileInfoLocal>(location, size) : nullptr;
+ auto file_node_id = next_file_node_id();
+ auto &node = file_nodes_[file_node_id];
+ node = td::make_unique<FileNode>(LocalFileLocation(std::move(location)), NewRemoteFileLocation(), nullptr, size, 0,
+ string(), string(), owner_dialog_id, FileEncryptionKey(), file_id,
+ static_cast<int8>(0));
+ node->need_load_from_pmc_ = true;
+ auto file_id_info = get_file_id_info(file_id);
+ file_id_info->node_id_ = file_node_id;
+ file_id_info->file_info_ = std::move(file_info);
+ is_new = true;
+ }
+
+ if (merge_file_id.is_valid()) {
+ auto status = merge(file_id, merge_file_id);
+ if (status.is_ok()) {
+ auto node = get_file_node(file_id);
+ auto main_file_id = node->main_file_id_;
+ if (main_file_id != file_id) {
+ if (is_new) {
+ bool is_removed = try_forget_file_id(file_id);
+ CHECK(is_removed);
+ node = get_file_node(main_file_id);
+ }
+ file_id = main_file_id;
+ }
+ try_flush_node(node, "register_local");
+ }
+ if (is_new) {
+ get_file_id_info(file_id)->pin_flag_ = true;
+ }
+ if (status.is_error()) {
+ return std::move(status);
+ }
+ } else if (is_new) {
+ get_file_id_info(file_id)->pin_flag_ = true;
+ }
+ return file_id;
}
FileId FileManager::register_remote(FullRemoteFileLocation location, FileLocationSource file_location_source,
DialogId owner_dialog_id, int64 size, int64 expected_size, string remote_name) {
- FileData data;
+ if (size < 0) {
+ LOG(ERROR) << "Receive file " << location << " of size " << size;
+ size = 0;
+ }
+ if (expected_size < 0) {
+ LOG(ERROR) << "Receive file " << location << " of expected size " << expected_size;
+ expected_size = 0;
+ }
auto url = location.get_url();
- data.remote_ = RemoteFileLocation(std::move(location));
- data.owner_dialog_id_ = owner_dialog_id;
- data.size_ = size;
- data.expected_size_ = expected_size;
- data.remote_name_ = std::move(remote_name);
-
- auto file_id = register_file(std::move(data), file_location_source, FileId(), "register_remote", false).move_as_ok();
- if (!url.empty()) {
- auto file_node = get_file_node(file_id);
- CHECK(file_node);
- file_node->set_url(url);
+
+ FileId file_id;
+ FileId merge_file_id;
+ int32 remote_key = 0;
+ if (context_->keep_exact_remote_location()) {
+ file_id = next_file_id();
+ RemoteInfo info{location, file_location_source, file_id};
+ remote_key = remote_location_info_.add(info);
+ auto &stored_info = remote_location_info_.get(remote_key);
+ if (stored_info.file_id_ != file_id) {
+ merge_file_id = stored_info.file_id_;
+ if (merge_choose_remote_location(location, file_location_source, stored_info.remote_,
+ stored_info.file_location_source_) == 0) {
+ stored_info.remote_ = location;
+ stored_info.file_location_source_ = file_location_source;
+ }
+ }
+ } else {
+ auto &other_id = remote_location_to_file_id_[location];
+ if (other_id.is_valid() && get_file_node(other_id)->remote_.full_source == FileLocationSource::FromServer) {
+ // if the file has already been received from the server, then we don't need merge or create new file
+ // skip merging of dc_id, file_reference, and access_hash
+ return other_id;
+ }
+
+ file_id = next_file_id();
+ if (other_id.empty()) {
+ other_id = file_id;
+ } else {
+ merge_file_id = other_id;
+ }
}
- return file_id;
+
+ LOG(INFO) << "Register " << location << " as " << file_id;
+ auto file_info =
+ STORE_FILE_INFO ? td::make_unique<FileInfoRemote>(location, size, expected_size, remote_name, url) : nullptr;
+ auto file_node_id = next_file_node_id();
+ auto &node = file_nodes_[file_node_id];
+ node = td::make_unique<FileNode>(LocalFileLocation(),
+ NewRemoteFileLocation(RemoteFileLocation(std::move(location)), file_location_source),
+ nullptr, size, expected_size, std::move(remote_name), std::move(url),
+ owner_dialog_id, FileEncryptionKey(), file_id, static_cast<int8>(1));
+ auto file_id_info = get_file_id_info(file_id);
+ file_id_info->node_id_ = file_node_id;
+ file_id_info->file_info_ = std::move(file_info);
+
+ auto main_file_id = file_id;
+ if (!merge_file_id.is_valid()) {
+ node->need_load_from_pmc_ = true;
+ get_file_id_info(main_file_id)->pin_flag_ = true;
+ } else {
+ // may invalidate node
+ merge(file_id, merge_file_id, true).ignore();
+ try_flush_node(get_file_node(file_id), "register_remote");
+
+ main_file_id = get_file_node(file_id)->main_file_id_;
+ if (main_file_id != file_id) {
+ try_forget_file_id(file_id);
+ }
+ }
+ return FileId(main_file_id.get(), remote_key);
}
-FileId FileManager::register_url(string url, FileType file_type, FileLocationSource file_location_source,
- DialogId owner_dialog_id) {
- auto file_id = register_generate(file_type, file_location_source, url, "#url#", owner_dialog_id, 0).ok();
- auto file_node = get_file_node(file_id);
- CHECK(file_node);
- file_node->set_url(url);
- return file_id;
+FileId FileManager::register_url(string url, FileType file_type, DialogId owner_dialog_id) {
+ return do_register_generate(td::make_unique<FullGenerateFileLocation>(file_type, url, "#url#"), owner_dialog_id, 0,
+ url);
}
-Result<FileId> FileManager::register_generate(FileType file_type, FileLocationSource file_location_source,
- string original_path, string conversion, DialogId owner_dialog_id,
- int64 expected_size) {
+FileId FileManager::register_generate(FileType file_type, string original_path, string conversion,
+ DialogId owner_dialog_id, int64 expected_size) {
// add #mtime# into conversion
if (!original_path.empty() && conversion[0] != '#' && PathView(original_path).is_absolute()) {
auto file_paths = log_interface->get_file_paths();
@@ -1222,21 +1772,39 @@ Result<FileId> FileManager::register_generate(FileType file_type, FileLocationSo
conversion = PSTRING() << "#mtime#" << lpad0(to_string(mtime), 20) << '#' << conversion;
}
}
+ return do_register_generate(
+ td::make_unique<FullGenerateFileLocation>(file_type, std::move(original_path), std::move(conversion)),
+ owner_dialog_id, max(expected_size, static_cast<int64>(0)), string());
+}
- FileData data;
- data.generate_ =
- td::make_unique<FullGenerateFileLocation>(file_type, std::move(original_path), std::move(conversion));
- data.owner_dialog_id_ = owner_dialog_id;
- data.expected_size_ = expected_size;
- return register_file(std::move(data), file_location_source, FileId(), "register_generate", false);
+FileId FileManager::do_register_generate(unique_ptr<FullGenerateFileLocation> generate, DialogId owner_dialog_id,
+ int64 expected_size, string url) {
+ auto &file_id = generate_location_to_file_id_[*generate];
+ if (!file_id.is_valid()) {
+ file_id = next_file_id();
+ LOG(INFO) << "Register " << *generate << " as " << file_id;
+
+ auto file_node_id = next_file_node_id();
+ auto &node = file_nodes_[file_node_id];
+ auto file_info = STORE_FILE_INFO ? td::make_unique<FileInfoGenerate>(*generate, expected_size, url) : nullptr;
+ node = td::make_unique<FileNode>(LocalFileLocation(), NewRemoteFileLocation(), std::move(generate), 0,
+ expected_size, string(), std::move(url), owner_dialog_id, FileEncryptionKey(),
+ file_id, static_cast<int8>(0));
+ node->need_load_from_pmc_ = true;
+
+ auto file_id_info = get_file_id_info(file_id);
+ file_id_info->node_id_ = file_node_id;
+ file_id_info->file_info_ = std::move(file_info);
+ file_id_info->pin_flag_ = true;
+ }
+ return file_id;
}
Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource file_location_source,
- FileId merge_file_id, const char *source, bool force,
- bool skip_file_size_checks) {
+ const char *source) {
bool has_remote = data.remote_.type() == RemoteFileLocation::Type::Full;
bool has_generate = data.generate_ != nullptr;
- if (data.local_.type() == LocalFileLocation::Type::Full && !force) {
+ if (data.local_.type() == LocalFileLocation::Type::Full) {
bool is_from_database = file_location_source == FileLocationSource::FromBinlog ||
file_location_source == FileLocationSource::FromDatabase;
if (is_from_database) {
@@ -1249,7 +1817,7 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
if (file_location_source != FileLocationSource::FromDatabase) {
Status status;
- auto r_info = check_full_local_location({data.local_.full(), data.size_}, skip_file_size_checks);
+ auto r_info = check_full_local_location({data.local_.full(), data.size_}, false);
if (r_info.is_error()) {
status = r_info.move_as_error();
} else if (bad_paths_.count(r_info.ok().location_.path_) != 0) {
@@ -1271,7 +1839,7 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
}
} else {
// the location has been checked previously, but recheck it just in case
- recheck_full_local_location({data.local_.full(), data.size_}, skip_file_size_checks);
+ recheck_full_local_location({data.local_.full(), data.size_}, false);
}
}
bool has_local = data.local_.type() == LocalFileLocation::Type::Full;
@@ -1281,14 +1849,25 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
}
if (data.size_ < 0) {
- LOG(ERROR) << "Receive file of size " << data.size_;
+ LOG(ERROR) << "Receive file of size " << data.size_ << " from " << source;
data.size_ = 0;
}
if (data.expected_size_ < 0) {
- LOG(ERROR) << "Receive file of expected size " << data.expected_size_;
+ LOG(ERROR) << "Receive file of expected size " << data.expected_size_ << " from " << source;
data.expected_size_ = 0;
}
+ if (data.remote_.type() == RemoteFileLocation::Type::Partial) {
+ auto &partial = data.remote_.partial();
+ auto part_size = static_cast<int64>(partial.part_size_);
+ auto ready_part_count = partial.ready_part_count_;
+ auto remote_ready_size = partial.ready_size_;
+ partial.ready_size_ = max(part_size * ready_part_count, remote_ready_size);
+ if (data.size_ != 0 && data.size_ < partial.ready_size_) {
+ partial.ready_size_ = data.size_;
+ }
+ }
+
FileId file_id = next_file_id();
LOG(INFO) << "Register file data " << data << " as " << file_id << " from " << source;
@@ -1300,8 +1879,8 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
std::move(data.remote_name_), std::move(data.url_), data.owner_dialog_id_,
std::move(data.encryption_key_), file_id, static_cast<int8>(has_remote));
node->pmc_id_ = FileDbId(data.pmc_id_);
- get_file_id_info(file_id)->node_id_ = file_node_id;
- node->file_ids_.push_back(file_id);
+ auto file_id_info = get_file_id_info(file_id);
+ file_id_info->node_id_ = file_node_id;
FileView file_view(get_file_node(file_id));
@@ -1319,9 +1898,10 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
bool new_remote = false;
FileId *new_remote_file_id = nullptr;
int32 remote_key = 0;
- if (file_view.has_remote_location()) {
+ const auto *full_remote_location = file_view.get_full_remote_location();
+ if (full_remote_location != nullptr) {
if (context_->keep_exact_remote_location()) {
- RemoteInfo info{file_view.remote_location(), file_location_source, file_id};
+ RemoteInfo info{*full_remote_location, file_location_source, file_id};
remote_key = remote_location_info_.add(info);
auto &stored_info = remote_location_info_.get(remote_key);
if (stored_info.file_id_ == file_id) {
@@ -1329,29 +1909,31 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
new_remote = true;
} else {
to_merge.push_back(stored_info.file_id_);
- if (merge_choose_remote_location(file_view.remote_location(), file_location_source, stored_info.remote_,
+ if (merge_choose_remote_location(*full_remote_location, file_location_source, stored_info.remote_,
stored_info.file_location_source_) == 0) {
- stored_info.remote_ = file_view.remote_location();
+ stored_info.remote_ = *full_remote_location;
stored_info.file_location_source_ = file_location_source;
}
}
} else {
- new_remote_file_id = register_location(file_view.remote_location(), remote_location_to_file_id_);
+ new_remote_file_id = register_location(*full_remote_location, remote_location_to_file_id_);
new_remote = new_remote_file_id != nullptr;
}
}
FileId *new_local_file_id = nullptr;
- if (file_view.has_local_location()) {
- new_local_file_id = register_location(file_view.local_location(), local_location_to_file_id_);
+ const auto *full_local_location = file_view.get_full_local_location();
+ if (full_local_location != nullptr) {
+ new_local_file_id = register_location(*full_local_location, local_location_to_file_id_);
}
FileId *new_generate_file_id = nullptr;
- if (file_view.has_generate_location()) {
- new_generate_file_id = register_location(file_view.generate_location(), generate_location_to_file_id_);
+ const auto *generate_location = file_view.get_generate_location();
+ if (generate_location != nullptr) {
+ new_generate_file_id = register_location(*generate_location, generate_location_to_file_id_);
}
td::unique(to_merge);
int new_cnt = new_remote + (new_local_file_id != nullptr) + (new_generate_file_id != nullptr);
- if (data.pmc_id_ == 0 && file_db_ && new_cnt > 0) {
+ if (data.pmc_id_ == 0 && new_cnt > 0) {
node->need_load_from_pmc_ = true;
}
bool no_sync_merge = to_merge.size() == 1 && new_cnt == 0;
@@ -1359,10 +1941,6 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
// may invalidate node
merge(file_id, id, no_sync_merge).ignore();
}
- Status status;
- if (merge_file_id.is_valid()) {
- status = merge(file_id, merge_file_id);
- }
try_flush_node(get_file_node(file_id), "register_file");
auto main_file_id = get_file_node(file_id)->main_file_id_;
@@ -1389,9 +1967,6 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
context_->add_file_source(main_file_id, file_source_id);
}
}
- if (status.is_error()) {
- return std::move(status);
- }
return FileId(main_file_id.get(), remote_key);
}
@@ -1526,7 +2101,7 @@ void FileManager::do_cancel_download(FileNodePtr node) {
if (node->download_id_ == 0) {
return;
}
- send_closure(file_load_manager_, &FileLoadManager::cancel, node->download_id_);
+ send_closure(file_download_manager_, &FileDownloadManager::cancel, node->download_id_);
node->download_id_ = 0;
node->is_download_started_ = false;
node->download_was_update_file_reference_ = false;
@@ -1537,7 +2112,7 @@ void FileManager::do_cancel_upload(FileNodePtr node) {
if (node->upload_id_ == 0) {
return;
}
- send_closure(file_load_manager_, &FileLoadManager::cancel, node->upload_id_);
+ send_closure(file_upload_manager_, &FileUploadManager::cancel, node->upload_id_);
node->upload_id_ = 0;
node->upload_was_update_file_reference_ = false;
node->set_upload_priority(0);
@@ -1634,8 +2209,9 @@ Status FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sync) {
if (size_i == -1) {
try_flush_node_info(x_node, "merge 2");
try_flush_node_info(y_node, "merge 3");
- return Status::Error(
- 400, PSLICE() << "Can't merge files. Different size: " << x_node->size_ << " and " << y_node->size_);
+ return Status::Error(400, PSLICE() << "Can't merge files " << x_node->local_ << '/' << x_node->remote_ << " and "
+ << y_node->local_ << '/' << y_node->remote_
+ << ". Different size: " << x_node->size_ << " and " << y_node->size_);
}
if (encryption_key_i == -1) {
if (nodes[remote_i]->remote_.full && nodes[local_i]->local_.type() != LocalFileLocation::Type::Partial) {
@@ -1678,8 +2254,7 @@ Status FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sync) {
if (local_i == other_node_i) {
do_cancel_download(node);
node->set_download_offset(other_node->download_offset_);
- node->set_local_location(other_node->local_, other_node->local_ready_size_, other_node->download_offset_,
- other_node->local_ready_prefix_size_);
+ node->set_local_location(other_node->local_, other_node->download_offset_, other_node->local_ready_prefix_size_);
node->download_id_ = other_node->download_id_;
node->download_was_update_file_reference_ = other_node->download_was_update_file_reference_;
node->is_download_started_ |= other_node->is_download_started_;
@@ -1777,7 +2352,7 @@ Status FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sync) {
bool send_updates_flag = false;
auto other_pmc_id = other_node->pmc_id_;
- node->file_ids_.insert(node->file_ids_.end(), other_node->file_ids_.begin(), other_node->file_ids_.end());
+ append(node->file_ids_, other_node->file_ids_);
for (auto file_id : other_node->file_ids_) {
auto file_id_info = get_file_id_info(file_id);
@@ -1801,7 +2376,7 @@ Status FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sync) {
// Check if some download/upload queries are ready
for (auto file_id : vector<FileId>(node->file_ids_)) {
auto *info = get_file_id_info(file_id);
- if (info->download_priority_ != 0 && file_view.has_local_location()) {
+ if (info->download_priority_ != 0 && file_view.has_full_local_location()) {
info->download_priority_ = 0;
if (info->download_callback_) {
info->download_callback_->on_download_ok(file_id);
@@ -1832,6 +2407,31 @@ Status FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sync) {
return Status::OK();
}
+void FileManager::try_merge_documents(FileId old_file_id, FileId new_file_id) {
+ if (!old_file_id.is_valid() || !new_file_id.is_valid()) {
+ return;
+ }
+ FileView old_file_view = get_file_view(old_file_id);
+ FileView new_file_view = get_file_view(new_file_id);
+ // if file type has changed, but file size remains the same, we are trying to update local location of the new
+ // file with the old local location
+ if (old_file_view.has_full_local_location() && !new_file_view.has_full_local_location() &&
+ old_file_view.size() != 0 && old_file_view.size() == new_file_view.size()) {
+ auto old_file_type = old_file_view.get_type();
+ auto new_file_type = new_file_view.get_type();
+
+ if (is_document_file_type(old_file_type) && is_document_file_type(new_file_type)) {
+ const auto *old_location = old_file_view.get_full_local_location();
+ auto r_file_id =
+ register_local(FullLocalFileLocation(new_file_type, old_location->path_, old_location->mtime_nsec_),
+ DialogId(), old_file_view.size());
+ if (r_file_id.is_ok()) {
+ LOG_STATUS(merge(new_file_id, r_file_id.ok()));
+ }
+ }
+ }
+}
+
void FileManager::add_file_source(FileId file_id, FileSourceId file_source_id) {
auto node = get_sync_file_node(file_id); // synchronously load the file to preload known file sources
if (!node) {
@@ -1967,11 +2567,11 @@ void FileManager::clear_from_pmc(FileNodePtr node) {
LOG(INFO) << "Delete files " << format::as_array(node->file_ids_) << " from pmc";
FileData data;
auto file_view = FileView(node);
- if (file_view.has_local_location()) {
+ if (file_view.has_full_local_location()) {
data.local_ = node->local_;
prepare_path_for_pmc(data.local_.full().file_type_, data.local_.full().path_);
}
- if (file_view.has_remote_location()) {
+ if (file_view.has_full_remote_location()) {
data.remote_ = RemoteFileLocation(*node->remote_.full);
}
if (file_view.has_generate_location()) {
@@ -1986,7 +2586,7 @@ void FileManager::flush_to_pmc(FileNodePtr node, bool new_remote, bool new_local
if (!file_db_) {
return;
}
- FileView view(node);
+ FileView file_view(node);
bool create_flag = false;
if (node->pmc_id_.empty()) {
create_flag = true;
@@ -2023,8 +2623,8 @@ void FileManager::flush_to_pmc(FileNodePtr node, bool new_remote, bool new_local
data.encryption_key_ = node->encryption_key_;
data.url_ = node->url_;
data.owner_dialog_id_ = node->owner_dialog_id_;
- data.file_source_ids_ = context_->get_some_file_sources(view.get_main_file_id());
- VLOG(file_references) << "Save file " << view.get_main_file_id() << " to database with " << data.file_source_ids_
+ data.file_source_ids_ = context_->get_some_file_sources(file_view.get_main_file_id());
+ VLOG(file_references) << "Save file " << file_view.get_main_file_id() << " to database with " << data.file_source_ids_
<< " from " << source;
file_db_->set_file_data(node->pmc_id_, data, (create_flag || new_remote), (create_flag || new_local),
@@ -2035,7 +2635,7 @@ FileNode *FileManager::get_file_node_raw(FileId file_id, FileNodeId *file_node_i
if (file_id.get() <= 0 || file_id.get() >= static_cast<int32>(file_id_info_.size())) {
return nullptr;
}
- FileNodeId node_id = file_id_info_[file_id.get()].node_id_;
+ FileNodeId node_id = file_id_info_[file_id.get()]->node_id_;
if (node_id == 0) {
return nullptr;
}
@@ -2058,37 +2658,48 @@ void FileManager::load_from_pmc(FileNodePtr node, bool new_remote, bool new_loca
if (!node->need_load_from_pmc_) {
return;
}
- auto file_id = node->main_file_id_;
node->need_load_from_pmc_ = false;
if (!file_db_) {
return;
}
+ auto file_id = node->main_file_id_;
auto file_view = get_file_view(file_id);
CHECK(!file_view.empty());
FullRemoteFileLocation remote;
FullLocalFileLocation local;
FullGenerateFileLocation generate;
- new_remote &= file_view.has_remote_location();
if (new_remote) {
- remote = file_view.remote_location();
+ const auto *full_remote_location = file_view.get_full_remote_location();
+ if (full_remote_location != nullptr) {
+ remote = *full_remote_location;
+ } else {
+ new_remote = false;
+ }
}
- new_local &= file_view.has_local_location();
if (new_local) {
- local = file_view.local_location();
- prepare_path_for_pmc(local.file_type_, local.path_);
+ const auto *full_local_location = file_view.get_full_local_location();
+ if (full_local_location != nullptr) {
+ local = *full_local_location;
+ prepare_path_for_pmc(local.file_type_, local.path_);
+ } else {
+ new_local = false;
+ }
}
- new_generate &= file_view.has_generate_location();
if (new_generate) {
- generate = file_view.generate_location();
+ const auto *generate_location = file_view.get_generate_location();
+ if (generate_location != nullptr) {
+ generate = *generate_location;
+ } else {
+ new_generate = false;
+ }
}
LOG(DEBUG) << "Load from pmc file " << file_id << '/' << file_view.get_main_file_id()
<< ", new_remote = " << new_remote << ", new_local = " << new_local << ", new_generate = " << new_generate;
auto load = [&](auto location, const char *source) {
TRY_RESULT(file_data, file_db_->get_file_data_sync(location));
- TRY_RESULT(new_file_id,
- register_file(std::move(file_data), FileLocationSource::FromDatabase, FileId(), source, false));
+ TRY_RESULT(new_file_id, register_file(std::move(file_data), FileLocationSource::FromDatabase, source));
TRY_STATUS(merge(file_id, new_file_id)); // merge manually to keep merge parameters order
return Status::OK();
};
@@ -2108,8 +2719,8 @@ bool FileManager::set_encryption_key(FileId file_id, FileEncryptionKey key) {
if (!node) {
return false;
}
- auto view = FileView(node);
- if (view.has_local_location() && view.has_remote_location()) {
+ auto file_view = FileView(node);
+ if (file_view.has_full_local_location() && file_view.has_full_remote_location()) {
return false;
}
if (!node->encryption_key_.empty()) {
@@ -2146,11 +2757,12 @@ bool FileManager::set_content(FileId file_id, BufferSlice bytes) {
node->set_download_priority(FROM_BYTES_PRIORITY);
- QueryId query_id = queries_container_.create(Query{file_id, Query::Type::SetContent});
+ FileDownloadManager::QueryId query_id =
+ download_queries_.create(DownloadQuery{file_id, DownloadQuery::Type::SetContent});
node->download_id_ = query_id;
node->is_download_started_ = true;
- send_closure(file_load_manager_, &FileLoadManager::from_bytes, query_id, node->remote_.full.value().file_type_,
- std::move(bytes), node->suggested_path());
+ send_closure(file_download_manager_, &FileDownloadManager::from_bytes, query_id,
+ node->remote_.full.value().file_type_, std::move(bytes), node->suggested_path());
return true;
}
@@ -2162,11 +2774,12 @@ void FileManager::get_content(FileId file_id, Promise<BufferSlice> promise) {
check_local_location(node, true).ignore();
auto file_view = FileView(node);
- if (!file_view.has_local_location()) {
+ const auto *full_local_location = file_view.get_full_local_location();
+ if (full_local_location == nullptr) {
return promise.set_error(Status::Error("No local location"));
}
- send_closure(file_load_manager_, &FileLoadManager::get_content, node->local_.full().path_, std::move(promise));
+ send_closure(file_load_manager_, &FileLoadManager::get_content, full_local_location->path_, std::move(promise));
}
void FileManager::read_file_part(FileId file_id, int64 offset, int64 count, int left_tries,
@@ -2204,8 +2817,9 @@ void FileManager::read_file_part(FileId file_id, int64 offset, int64 count, int
const string *path = nullptr;
bool is_partial = false;
- if (file_view.has_local_location()) {
- path = &file_view.local_location().path_;
+ const auto *full_local_location = file_view.get_full_local_location();
+ if (full_local_location != nullptr) {
+ path = &full_local_location->path_;
if (!begins_with(*path, get_files_dir(file_view.get_type()))) {
return promise.set_error(Status::Error(400, "File is not inside the cache"));
}
@@ -2254,8 +2868,8 @@ void FileManager::delete_file(FileId file_id, Promise<Unit> promise, const char
send_closure(G()->download_manager(), &DownloadManager::remove_file_if_finished, file_view.get_main_file_id());
string path;
- if (file_view.has_local_location()) {
- if (begins_with(file_view.local_location().path_, get_files_dir(file_view.get_type()))) {
+ if (file_view.has_full_local_location()) {
+ if (begins_with(file_view.get_full_local_location()->path_, get_files_dir(file_view.get_type()))) {
clear_from_pmc(node);
if (context_->need_notify_on_new_files()) {
context_->on_new_file(-file_view.size(), -file_view.get_allocated_local_size(), -1);
@@ -2432,7 +3046,7 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) {
LOG(INFO) << "Update download offset and limits of file " << node->main_file_id_;
CHECK(node->download_id_ != 0);
if (force_update_priority || priority != old_priority) {
- send_closure(file_load_manager_, &FileLoadManager::update_priority, node->download_id_, priority);
+ send_closure(file_download_manager_, &FileDownloadManager::update_priority, node->download_id_, priority);
}
if (need_update_limit || need_update_offset) {
auto download_offset = node->download_offset_;
@@ -2443,8 +3057,8 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) {
download_limit += download_offset;
download_offset = 0;
}
- send_closure(file_load_manager_, &FileLoadManager::update_downloaded_part, node->download_id_, download_offset,
- download_limit);
+ send_closure(file_download_manager_, &FileDownloadManager::update_downloaded_part, node->download_id_,
+ download_offset, download_limit);
}
return;
}
@@ -2455,10 +3069,11 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) {
if (node->need_reload_photo_ && file_view.may_reload_photo()) {
LOG(INFO) << "Reload photo from file " << node->main_file_id_;
- QueryId query_id = queries_container_.create(Query{file_id, Query::Type::DownloadReloadDialog});
+ FileDownloadManager::QueryId query_id =
+ download_queries_.create(DownloadQuery{file_id, DownloadQuery::Type::DownloadReloadDialog});
node->download_id_ = query_id;
- context_->reload_photo(file_view.remote_location().get_source(),
- PromiseCreator::lambda([query_id, actor_id = actor_id(this), file_id](Result<Unit> res) {
+ context_->reload_photo(file_view.get_full_remote_location()->get_source(),
+ PromiseCreator::lambda([actor_id = actor_id(this), query_id, file_id](Result<Unit> res) {
Status error;
if (res.is_ok()) {
error = Status::Error("FILE_DOWNLOAD_ID_INVALID");
@@ -2467,7 +3082,7 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) {
}
VLOG(file_references)
<< "Receive result from reload photo for file " << file_id << ": " << error;
- send_closure(actor_id, &FileManager::on_error, query_id, std::move(error));
+ send_closure(actor_id, &FileManager::on_download_error, query_id, std::move(error));
}));
node->need_reload_photo_ = false;
return;
@@ -2476,15 +3091,16 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) {
// If file reference is needed
if (!file_view.has_active_download_remote_location()) {
VLOG(file_references) << "Do not have valid file_reference for file " << file_id;
- QueryId query_id = queries_container_.create(Query{file_id, Query::Type::DownloadWaitFileReference});
+ FileDownloadManager::QueryId query_id =
+ download_queries_.create(DownloadQuery{file_id, DownloadQuery::Type::DownloadWaitFileReference});
node->download_id_ = query_id;
if (node->download_was_update_file_reference_) {
- return on_error(query_id, Status::Error("Can't download file: have no valid file reference"));
+ return on_download_error(query_id, Status::Error("Can't download file: have no valid file reference"));
}
node->download_was_update_file_reference_ = true;
context_->repair_file_reference(
- file_id, PromiseCreator::lambda([query_id, actor_id = actor_id(this), file_id](Result<Unit> res) {
+ file_id, PromiseCreator::lambda([actor_id = actor_id(this), query_id, file_id](Result<Unit> res) {
Status error;
if (res.is_ok()) {
error = Status::Error("FILE_DOWNLOAD_RESTART_WITH_FILE_REFERENCE");
@@ -2492,12 +3108,13 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) {
error = res.move_as_error();
}
VLOG(file_references) << "Receive result from FileSourceManager for file " << file_id << ": " << error;
- send_closure(actor_id, &FileManager::on_error, query_id, std::move(error));
+ send_closure(actor_id, &FileManager::on_download_error, query_id, std::move(error));
}));
return;
}
- QueryId query_id = queries_container_.create(Query{file_id, Query::Type::Download});
+ FileDownloadManager::QueryId query_id =
+ download_queries_.create(DownloadQuery{file_id, DownloadQuery::Type::Download});
node->download_id_ = query_id;
node->is_download_started_ = false;
LOG(INFO) << "Run download of file " << file_id << " of size " << node->size_ << " from "
@@ -2511,9 +3128,9 @@ void FileManager::run_download(FileNodePtr node, bool force_update_priority) {
download_limit += download_offset;
download_offset = 0;
}
- send_closure(file_load_manager_, &FileLoadManager::download, query_id, node->remote_.full.value(), node->local_,
- node->size_, node->suggested_path(), node->encryption_key_, node->can_search_locally_, download_offset,
- download_limit, priority);
+ send_closure(file_download_manager_, &FileDownloadManager::download, query_id, node->remote_.full.value(),
+ node->local_, node->size_, node->suggested_path(), node->encryption_key_, node->can_search_locally_,
+ download_offset, download_limit, priority);
}
class FileManager::ForceUploadActor final : public Actor {
@@ -2679,7 +3296,11 @@ void FileManager::resume_upload(FileId file_id, vector<int> bad_parts, std::shar
.release();
return;
}
- LOG(INFO) << "Resume upload of file " << file_id << " with priority " << new_priority << " and force = " << force;
+ if (new_priority == 0) {
+ LOG(INFO) << "Cancel upload of file " << file_id;
+ } else {
+ LOG(INFO) << "Resume upload of file " << file_id << " with priority " << new_priority << " and force = " << force;
+ }
if (force) {
node->remote_.is_full_alive = false;
@@ -2695,21 +3316,22 @@ void FileManager::resume_upload(FileId file_id, vector<int> bad_parts, std::shar
};
FileView file_view(node);
if (file_view.has_active_upload_remote_location() && can_reuse_remote_file(file_view.get_type())) {
- LOG(INFO) << "File " << file_id << " is already uploaded";
+ LOG(INFO) << "Upload of file " << file_id << " has already been completed";
if (callback) {
callback->on_upload_ok(file_id, nullptr);
}
return;
}
- if (file_view.has_local_location() && new_priority != 0) {
+ if (file_view.has_full_local_location() && new_priority != 0) {
auto status = check_local_location(node, false);
if (status.is_error()) {
LOG(INFO) << "Full local location of file " << file_id << " for upload is invalid: " << status;
}
}
- if (!file_view.has_local_location() && !file_view.has_generate_location() && !file_view.has_alive_remote_location()) {
+ if (!file_view.has_full_local_location() && !file_view.has_generate_location() &&
+ !file_view.has_alive_remote_location()) {
LOG(INFO) << "File " << file_id << " can't be uploaded";
if (callback) {
callback->on_upload_error(
@@ -2718,7 +3340,7 @@ void FileManager::resume_upload(FileId file_id, vector<int> bad_parts, std::shar
return;
}
if (file_view.get_type() == FileType::Thumbnail &&
- (!file_view.has_local_location() && file_view.can_download_from_server())) {
+ (!file_view.has_full_local_location() && file_view.can_download_from_server())) {
// TODO
if (callback) {
callback->on_upload_error(file_id, Status::Error(400, "Failed to upload thumbnail without local location"));
@@ -2786,6 +3408,14 @@ bool FileManager::delete_partial_remote_location(FileId file_id) {
return true;
}
+void FileManager::delete_partial_remote_location_if_needed(FileId file_id, const Status &error) {
+ if (error.code() != 429 && error.code() < 500 && !G()->close_flag()) {
+ delete_partial_remote_location(file_id);
+ } else {
+ cancel_upload(file_id);
+ }
+}
+
void FileManager::delete_file_reference(FileId file_id, Slice file_reference) {
VLOG(file_references) << "Delete file reference of file " << file_id << " "
<< tag("reference_base64", base64_encode(file_reference));
@@ -2810,18 +3440,19 @@ void FileManager::delete_file_reference(FileId file_id, Slice file_reference) {
void FileManager::external_file_generate_write_part(int64 generation_id, int64 offset, string data, Promise<> promise) {
send_closure(file_generate_manager_, &FileGenerateManager::external_file_generate_write_part,
- static_cast<uint64>(generation_id), offset, std::move(data), std::move(promise));
+ static_cast<FileGenerateManager::QueryId>(generation_id), offset, std::move(data), std::move(promise));
}
void FileManager::external_file_generate_progress(int64 generation_id, int64 expected_size, int64 local_prefix_size,
Promise<> promise) {
send_closure(file_generate_manager_, &FileGenerateManager::external_file_generate_progress,
- static_cast<uint64>(generation_id), expected_size, local_prefix_size, std::move(promise));
+ static_cast<FileGenerateManager::QueryId>(generation_id), expected_size, local_prefix_size,
+ std::move(promise));
}
void FileManager::external_file_generate_finish(int64 generation_id, Status status, Promise<> promise) {
send_closure(file_generate_manager_, &FileGenerateManager::external_file_generate_finish,
- static_cast<uint64>(generation_id), std::move(status), std::move(promise));
+ static_cast<FileGenerateManager::QueryId>(generation_id), std::move(status), std::move(promise));
}
void FileManager::run_generate(FileNodePtr node) {
@@ -2834,7 +3465,7 @@ void FileManager::run_generate(FileNodePtr node) {
// LOG(INFO) << "Skip run_generate, because file " << node->main_file_id_ << " can't be generated";
return;
}
- if (file_view.has_local_location()) {
+ if (file_view.has_full_local_location()) {
LOG(INFO) << "Skip run_generate, because file " << node->main_file_id_ << " has local location";
return;
}
@@ -2878,30 +3509,31 @@ void FileManager::run_generate(FileNodePtr node) {
return;
}
- QueryId query_id = queries_container_.create(Query{file_id, Query::Type::Generate});
+ FileGenerateManager::QueryId query_id = generate_queries_.create(GenerateQuery{file_id});
node->generate_id_ = query_id;
- send_closure(
- file_generate_manager_, &FileGenerateManager::generate_file, query_id, *node->generate_, node->local_,
- node->suggested_path(), [file_manager = this, query_id] {
- class Callback final : public FileGenerateCallback {
- ActorId<FileManager> actor_;
- uint64 query_id_;
-
- public:
- Callback(ActorId<FileManager> actor, QueryId query_id) : actor_(std::move(actor)), query_id_(query_id) {
- }
- void on_partial_generate(PartialLocalFileLocation partial_local, int64 expected_size) final {
- send_closure(actor_, &FileManager::on_partial_generate, query_id_, std::move(partial_local), expected_size);
- }
- void on_ok(FullLocalFileLocation local) final {
- send_closure(actor_, &FileManager::on_generate_ok, query_id_, std::move(local));
- }
- void on_error(Status error) final {
- send_closure(actor_, &FileManager::on_error, query_id_, std::move(error));
- }
- };
- return make_unique<Callback>(file_manager->actor_id(file_manager), query_id);
- }());
+ send_closure(file_generate_manager_, &FileGenerateManager::generate_file, query_id, *node->generate_, node->local_,
+ node->suggested_path(), [file_manager = this, query_id] {
+ class Callback final : public FileGenerateCallback {
+ ActorId<FileManager> actor_;
+ uint64 query_id_;
+
+ public:
+ Callback(ActorId<FileManager> actor, FileGenerateManager::QueryId query_id)
+ : actor_(std::move(actor)), query_id_(query_id) {
+ }
+ void on_partial_generate(PartialLocalFileLocation partial_local, int64 expected_size) final {
+ send_closure(actor_, &FileManager::on_partial_generate, query_id_, std::move(partial_local),
+ expected_size);
+ }
+ void on_ok(FullLocalFileLocation local) final {
+ send_closure(actor_, &FileManager::on_generate_ok, query_id_, std::move(local));
+ }
+ void on_error(Status error) final {
+ send_closure(actor_, &FileManager::on_generate_error, query_id_, std::move(error));
+ }
+ };
+ return make_unique<Callback>(file_manager->actor_id(file_manager), query_id);
+ }());
LOG(INFO) << "File " << file_id << " generate request has sent to FileGenerateManager";
}
@@ -2938,13 +3570,14 @@ void FileManager::run_upload(FileNodePtr node, vector<int> bad_parts) {
}
FileView file_view(node);
- if (!file_view.has_local_location() && !file_view.has_remote_location()) {
+ if (!file_view.has_full_local_location() && !file_view.has_full_remote_location()) {
if (node->get_by_hash_ || node->generate_id_ == 0 || !node->generate_was_update_) {
LOG(INFO) << "Have no local location for file: get_by_hash = " << node->get_by_hash_
<< ", generate_id = " << node->generate_id_ << ", generate_was_update = " << node->generate_was_update_;
return;
}
- if (file_view.has_generate_location() && file_view.generate_location().file_type_ == FileType::SecureEncrypted) {
+ auto generate_location = file_view.get_generate_location();
+ if (generate_location != nullptr && generate_location->file_type_ == FileType::SecureEncrypted) {
// Can't upload secure file before its size is known
LOG(INFO) << "Can't upload secure file " << node->main_file_id_ << " before it's size is known";
return;
@@ -2953,9 +3586,12 @@ void FileManager::run_upload(FileNodePtr node, vector<int> bad_parts) {
node->set_upload_priority(priority);
+ auto generate_location = file_view.get_generate_location();
+ auto full_local_location = file_view.get_full_local_location();
+
// create encryption key if necessary
- if (((file_view.has_generate_location() && file_view.generate_location().file_type_ == FileType::Encrypted) ||
- (file_view.has_local_location() && file_view.local_location().file_type_ == FileType::Encrypted)) &&
+ if (((generate_location != nullptr && generate_location->file_type_ == FileType::Encrypted) ||
+ (full_local_location != nullptr && full_local_location->file_type_ == FileType::Encrypted)) &&
file_view.encryption_key().empty()) {
CHECK(!node->file_ids_.empty());
bool success = set_encryption_key(node->file_ids_[0], FileEncryptionKey::create());
@@ -2963,7 +3599,7 @@ void FileManager::run_upload(FileNodePtr node, vector<int> bad_parts) {
}
// create encryption key if necessary
- if (file_view.has_local_location() && file_view.local_location().file_type_ == FileType::SecureEncrypted &&
+ if (full_local_location != nullptr && full_local_location->file_type_ == FileType::SecureEncrypted &&
file_view.encryption_key().empty()) {
CHECK(!node->file_ids_.empty());
bool success = set_encryption_key(node->file_ids_[0], FileEncryptionKey::create_secure_key());
@@ -2973,23 +3609,25 @@ void FileManager::run_upload(FileNodePtr node, vector<int> bad_parts) {
if (old_priority != 0) {
LOG(INFO) << "File " << file_id << " is already uploading";
CHECK(node->upload_id_ != 0);
- send_closure(file_load_manager_, &FileLoadManager::update_priority, node->upload_id_, narrow_cast<int8>(-priority));
+ send_closure(file_upload_manager_, &FileUploadManager::update_priority, node->upload_id_,
+ narrow_cast<int8>(-priority));
return;
}
CHECK(node->upload_id_ == 0);
if (file_view.has_alive_remote_location() && !file_view.has_active_upload_remote_location() &&
can_reuse_remote_file(file_view.get_type())) {
- QueryId query_id = queries_container_.create(Query{file_id, Query::Type::UploadWaitFileReference});
+ FileUploadManager::QueryId query_id =
+ upload_queries_.create(UploadQuery{file_id, UploadQuery::Type::UploadWaitFileReference});
node->upload_id_ = query_id;
if (node->upload_was_update_file_reference_) {
- return on_error(query_id, Status::Error("Can't upload file: have no valid file reference"));
+ return on_upload_error(query_id, Status::Error("Can't upload file: have no valid file reference"));
}
node->upload_was_update_file_reference_ = true;
context_->repair_file_reference(node->main_file_id_,
- PromiseCreator::lambda([query_id, actor_id = actor_id(this)](Result<Unit> res) {
- send_closure(actor_id, &FileManager::on_error, query_id,
+ PromiseCreator::lambda([actor_id = actor_id(this), query_id](Result<Unit> res) {
+ send_closure(actor_id, &FileManager::on_upload_error, query_id,
Status::Error("FILE_UPLOAD_RESTART_WITH_FILE_REFERENCE"));
}));
return;
@@ -2997,10 +3635,10 @@ void FileManager::run_upload(FileNodePtr node, vector<int> bad_parts) {
if (!node->remote_.partial && node->get_by_hash_) {
LOG(INFO) << "Get file " << node->main_file_id_ << " by hash";
- QueryId query_id = queries_container_.create(Query{file_id, Query::Type::UploadByHash});
+ FileUploadManager::QueryId query_id = upload_queries_.create(UploadQuery{file_id, UploadQuery::Type::UploadByHash});
node->upload_id_ = query_id;
- send_closure(file_load_manager_, &FileLoadManager::upload_by_hash, query_id, node->local_.full(), node->size_,
+ send_closure(file_upload_manager_, &FileUploadManager::upload_by_hash, query_id, node->local_.full(), node->size_,
narrow_cast<int8>(-priority));
return;
}
@@ -3013,12 +3651,13 @@ void FileManager::run_upload(FileNodePtr node, vector<int> bad_parts) {
expected_size = 10 << 20;
}
- QueryId query_id = queries_container_.create(Query{file_id, Query::Type::Upload});
+ FileUploadManager::QueryId query_id = upload_queries_.create(UploadQuery{file_id, UploadQuery::Type::Upload});
node->upload_id_ = query_id;
- send_closure(file_load_manager_, &FileLoadManager::upload, query_id, node->local_, node->remote_.partial_or_empty(),
- expected_size, node->encryption_key_, new_priority, std::move(bad_parts));
+ send_closure(file_upload_manager_, &FileUploadManager::upload, query_id, node->local_,
+ node->remote_.partial_or_empty(), expected_size, node->encryption_key_, new_priority,
+ std::move(bad_parts));
- LOG(INFO) << "File " << file_id << " upload request has sent to FileLoadManager";
+ LOG(INFO) << "File " << file_id << " upload request has sent to FileUploadManager";
}
void FileManager::upload(FileId file_id, std::shared_ptr<UploadCallback> callback, int32 new_priority,
@@ -3044,7 +3683,7 @@ Result<FileId> FileManager::from_persistent_id(CSlice persistent_id, FileType fi
if (!clean_input_string(url)) {
return Status::Error(400, "URL must be in UTF-8");
}
- return register_url(std::move(url), file_type, FileLocationSource::FromUser, DialogId());
+ return register_url(std::move(url), file_type, DialogId());
}
auto r_binary = base64url_decode(persistent_id);
@@ -3083,10 +3722,8 @@ Result<FileId> FileManager::from_persistent_id_generated(Slice binary, FileType
if (!is_remotely_generated_file(generate_location.conversion_)) {
return Status::Error(400, "Unexpected conversion type");
}
- FileData data;
- data.generate_ = make_unique<FullGenerateFileLocation>(std::move(generate_location));
- return register_file(std::move(data), FileLocationSource::FromUser, FileId(), "from_persistent_id_generated", false)
- .move_as_ok();
+ return do_register_generate(make_unique<FullGenerateFileLocation>(std::move(generate_location)), DialogId(), 0,
+ string());
}
Result<FileId> FileManager::from_persistent_id_v23(Slice binary, FileType file_type, int32 version) {
@@ -3111,11 +3748,7 @@ Result<FileId> FileManager::from_persistent_id_v23(Slice binary, FileType file_t
} else if (real_file_type != file_type && file_type != FileType::Temp) {
return Status::Error(400, PSLICE() << "Can't use file of type " << real_file_type << " as " << file_type);
}
- FileData data;
- data.remote_ = RemoteFileLocation(std::move(remote_location));
- auto file_id = register_file(std::move(data), FileLocationSource::FromUser, FileId(), "from_persistent_id_v23", false)
- .move_as_ok();
- return file_id;
+ return register_remote(std::move(remote_location), FileLocationSource::FromUser, DialogId(), 0, 0, string());
}
Result<FileId> FileManager::from_persistent_id_v2(Slice binary, FileType file_type) {
@@ -3150,45 +3783,50 @@ FileView FileManager::get_sync_file_view(FileId file_id) {
}
td_api::object_ptr<td_api::file> FileManager::get_file_object(FileId file_id, bool with_main_file_id) {
- auto file_view = get_sync_file_view(file_id);
-
- if (file_view.empty()) {
+ auto file_node_ptr = get_sync_file_node(file_id);
+ if (!file_node_ptr) {
return td_api::make_object<td_api::file>(0, 0, 0, td_api::make_object<td_api::localFile>(),
td_api::make_object<td_api::remoteFile>());
}
- string persistent_file_id = file_view.get_persistent_file_id();
- string unique_file_id = file_view.get_unique_file_id();
+ const FileNode *file_node = file_node_ptr.get();
+ string persistent_file_id = file_node->get_persistent_file_id();
+ string unique_file_id = file_node->get_unique_file_id();
+ bool is_downloading_completed = file_node->local_.type() == LocalFileLocation::Type::Full;
bool is_uploading_completed = !persistent_file_id.empty();
- auto size = file_view.size();
- auto expected_size = file_view.expected_size();
- auto download_offset = file_view.download_offset();
- auto local_prefix_size = file_view.local_prefix_size();
- auto local_total_size = file_view.local_total_size();
- auto remote_size = file_view.remote_size();
- string path = file_view.path();
+ auto size = file_node->size_;
+ auto download_offset = file_node->download_offset_;
+ auto expected_size = file_node->expected_size();
+ auto local_prefix_size = file_node->local_prefix_size();
+ auto local_total_size = file_node->local_total_size();
+ auto remote_size = file_node->remote_size();
+ string path = file_node->path();
+ bool can_be_deleted = file_node->can_delete();
+
+ auto file_view = FileView(file_node_ptr);
bool can_be_downloaded = file_view.can_download_from_server() || file_view.can_generate();
- bool can_be_deleted = file_view.can_delete();
auto result_file_id = file_id;
auto *file_info = get_file_id_info(result_file_id);
+ FileId main_file_id;
if (with_main_file_id) {
+ main_file_id = file_node->main_file_id_;
if (!file_info->send_updates_flag_) {
- result_file_id = file_view.get_main_file_id();
+ result_file_id = main_file_id;
}
- file_info = get_file_id_info(file_view.get_main_file_id());
+ file_info = get_file_id_info(main_file_id);
}
file_info->send_updates_flag_ = true;
VLOG(update_file) << "Send file " << file_id << " as " << result_file_id << " and update send_updates_flag_ for file "
- << (with_main_file_id ? file_view.get_main_file_id() : result_file_id);
+ << (with_main_file_id ? main_file_id : result_file_id);
return td_api::make_object<td_api::file>(
result_file_id.get(), size, expected_size,
td_api::make_object<td_api::localFile>(std::move(path), can_be_downloaded, can_be_deleted,
- file_view.is_downloading(), file_view.has_local_location(),
- download_offset, local_prefix_size, local_total_size),
+ file_node->is_downloading(), is_downloading_completed, download_offset,
+ local_prefix_size, local_total_size),
td_api::make_object<td_api::remoteFile>(std::move(persistent_file_id), std::move(unique_file_id),
- file_view.is_uploading(), is_uploading_completed, remote_size));
+ file_node->is_uploading(), is_uploading_completed, remote_size));
}
vector<int32> FileManager::get_file_ids_object(const vector<FileId> &file_ids, bool with_main_file_id) {
@@ -3197,10 +3835,11 @@ vector<int32> FileManager::get_file_ids_object(const vector<FileId> &file_ids, b
auto result_file_id = file_id;
auto *file_info = get_file_id_info(result_file_id);
if (with_main_file_id) {
+ auto main_file_id = file_view.get_main_file_id();
if (!file_info->sent_file_id_flag_ && !file_info->send_updates_flag_) {
- result_file_id = file_view.get_main_file_id();
+ result_file_id = main_file_id;
}
- file_info = get_file_id_info(file_view.get_main_file_id());
+ file_info = get_file_id_info(main_file_id);
}
file_info->sent_file_id_flag_ = true;
@@ -3226,13 +3865,16 @@ Result<FileId> FileManager::check_input_file_id(FileType type, Result<FileId> re
if (real_type != type && !(real_type == FileType::Temp && file_view.has_url()) &&
!(is_document_file_type(real_type) && is_document_file_type(type)) &&
!(is_background_type(real_type) && is_background_type(type)) &&
- !(file_view.is_encrypted() && type == FileType::Ringtone)) {
+ !(file_view.is_encrypted() && type == FileType::Ringtone) &&
+ !(real_type == FileType::PhotoStory && type == FileType::Photo) &&
+ !(real_type == FileType::Photo && type == FileType::PhotoStory)) {
// TODO: send encrypted file to unencrypted chat
return Status::Error(400, PSLICE() << "Can't use file of type " << real_type << " as " << type);
}
}
- if (!file_view.has_remote_location()) {
+ const auto *full_remote_location = file_view.get_full_remote_location();
+ if (full_remote_location == nullptr) {
// There are no reasons to dup file_id, because it will be duped anyway before upload/reupload
// It will not be duped in dup_message_content only if has_input_media(),
// but currently in this case the file never needs to be reuploaded
@@ -3248,7 +3890,7 @@ Result<FileId> FileManager::check_input_file_id(FileType type, Result<FileId> re
int32 remote_id = file_id.get_remote();
if (remote_id == 0 && context_->keep_exact_remote_location()) {
- RemoteInfo info{file_view.remote_location(), FileLocationSource::FromUser, file_id};
+ RemoteInfo info{*full_remote_location, FileLocationSource::FromUser, file_id};
remote_id = remote_location_info_.add(info);
if (remote_location_info_.get(remote_id).file_id_ == file_id) {
get_file_id_info(file_id)->pin_flag_ = true;
@@ -3277,8 +3919,8 @@ Result<FileId> FileManager::get_input_thumbnail_file_id(const tl_object_ptr<td_a
case td_api::inputFileGenerated::ID: {
auto *generated_thumbnail = static_cast<const td_api::inputFileGenerated *>(thumbnail_input_file.get());
return register_generate(is_encrypted ? FileType::EncryptedThumbnail : FileType::Thumbnail,
- FileLocationSource::FromUser, generated_thumbnail->original_path_,
- generated_thumbnail->conversion_, owner_dialog_id, generated_thumbnail->expected_size_);
+ generated_thumbnail->original_path_, generated_thumbnail->conversion_, owner_dialog_id,
+ generated_thumbnail->expected_size_);
}
default:
UNREACHABLE();
@@ -3320,17 +3962,24 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
auto file_id = file_hash_to_file_id_.get(hash);
LOG(INFO) << "Found file " << file_id << " by hash " << hex_encode(hash);
if (file_id.is_valid()) {
- auto file_view = get_file_view(file_id);
+ auto file_node = get_file_node(file_id);
+ auto file_view = FileView(file_node);
if (!file_view.empty()) {
if (force_reuse) {
return file_id;
}
- if (file_view.has_remote_location() && !file_view.remote_location().is_web()) {
+ const auto *full_remote_location = file_view.get_full_remote_location();
+ if (full_remote_location != nullptr && !full_remote_location->is_web()) {
return file_id;
}
if (file_view.is_uploading()) {
+ CHECK(file_node);
+ LOG(DEBUG) << "File " << file_id << " is still uploading: " << file_node->upload_priority_ << ' '
+ << file_node->generate_upload_priority_ << ' ' << file_node->upload_pause_;
hash.clear();
}
+ } else {
+ LOG(DEBUG) << "File " << file_id << " isn't found";
}
}
}
@@ -3358,8 +4007,8 @@ Result<FileId> FileManager::get_input_file_id(FileType type, const tl_object_ptr
}
case td_api::inputFileGenerated::ID: {
auto *generated_file = static_cast<const td_api::inputFileGenerated *>(file.get());
- return register_generate(new_type, FileLocationSource::FromUser, generated_file->original_path_,
- generated_file->conversion_, owner_dialog_id, generated_file->expected_size_);
+ return register_generate(new_type, generated_file->original_path_, generated_file->conversion_, owner_dialog_id,
+ generated_file->expected_size_);
}
default:
UNREACHABLE();
@@ -3400,7 +4049,7 @@ Result<FileId> FileManager::get_map_thumbnail_file_id(Location location, int32 z
<< scale << '#';
return register_generate(
owner_dialog_id.get_type() == DialogType::SecretChat ? FileType::EncryptedThumbnail : FileType::Thumbnail,
- FileLocationSource::FromUser, string(), std::move(conversion), owner_dialog_id, 0);
+ string(), std::move(conversion), owner_dialog_id, 0);
}
Result<FileId> FileManager::get_audio_thumbnail_file_id(string title, string performer, bool is_small,
@@ -3430,7 +4079,7 @@ Result<FileId> FileManager::get_audio_thumbnail_file_id(string title, string per
string conversion = PSTRING() << "#audio_t#" << title << '#' << performer << '#' << (is_small ? '1' : '0') << '#';
return register_generate(
owner_dialog_id.get_type() == DialogType::SecretChat ? FileType::EncryptedThumbnail : FileType::Thumbnail,
- FileLocationSource::FromUser, string(), std::move(conversion), owner_dialog_id, 0);
+ string(), std::move(conversion), owner_dialog_id, 0);
}
FileType FileManager::guess_file_type(const tl_object_ptr<td_api::InputFile> &file) {
@@ -3438,34 +4087,6 @@ FileType FileManager::guess_file_type(const tl_object_ptr<td_api::InputFile> &fi
return FileType::Temp;
}
- auto guess_file_type_by_path = [](const string &file_path) {
- PathView path_view(file_path);
- auto file_name = path_view.file_name();
- auto extension = path_view.extension();
- if (extension == "jpg" || extension == "jpeg") {
- return FileType::Photo;
- }
- if (extension == "ogg" || extension == "oga" || extension == "opus") {
- return FileType::VoiceNote;
- }
- if (extension == "3gp" || extension == "mov") {
- return FileType::Video;
- }
- if (extension == "mp3" || extension == "mpeg3" || extension == "m4a") {
- return FileType::Audio;
- }
- if (extension == "webp" || extension == "tgs" || extension == "webm") {
- return FileType::Sticker;
- }
- if (extension == "gif") {
- return FileType::Animation;
- }
- if (extension == "mp4" || extension == "mpeg4") {
- return to_lower(file_name).find("-gif-") != string::npos ? FileType::Animation : FileType::Video;
- }
- return FileType::Document;
- };
-
switch (file->get_id()) {
case td_api::inputFileLocal::ID:
return guess_file_type_by_path(static_cast<const td_api::inputFileLocal *>(file.get())->path_);
@@ -3503,32 +4124,60 @@ vector<tl_object_ptr<telegram_api::InputDocument>> FileManager::get_input_docume
for (auto file_id : file_ids) {
auto file_view = get_file_view(file_id);
CHECK(!file_view.empty());
- CHECK(file_view.has_remote_location());
- CHECK(!file_view.remote_location().is_web());
- result.push_back(file_view.remote_location().as_input_document());
+ const auto *full_remote_location = file_view.get_full_remote_location();
+ CHECK(full_remote_location != nullptr);
+ CHECK(!full_remote_location->is_web());
+ result.push_back(full_remote_location->as_input_document());
}
return result;
}
-bool FileManager::extract_was_uploaded(const tl_object_ptr<telegram_api::InputMedia> &input_media) {
+bool FileManager::extract_was_uploaded(const telegram_api::object_ptr<telegram_api::InputMedia> &input_media) {
if (input_media == nullptr) {
return false;
}
auto input_media_id = input_media->get_id();
+ if (input_media_id == telegram_api::inputMediaPaidMedia::ID) {
+ auto &extended_media = static_cast<const telegram_api::inputMediaPaidMedia *>(input_media.get())->extended_media_;
+ if (extended_media.size() > 1u) {
+ for (auto &media : extended_media) {
+ CHECK(!extract_was_uploaded(media));
+ }
+ return false;
+ }
+ CHECK(extended_media.size() == 1u);
+ return extract_was_uploaded(extended_media[0]);
+ }
return input_media_id == telegram_api::inputMediaUploadedPhoto::ID ||
input_media_id == telegram_api::inputMediaUploadedDocument::ID;
}
-bool FileManager::extract_was_thumbnail_uploaded(const tl_object_ptr<telegram_api::InputMedia> &input_media) {
- if (input_media == nullptr || input_media->get_id() != telegram_api::inputMediaUploadedDocument::ID) {
+bool FileManager::extract_was_thumbnail_uploaded(
+ const telegram_api::object_ptr<telegram_api::InputMedia> &input_media) {
+ if (input_media == nullptr) {
return false;
}
-
- return static_cast<const telegram_api::inputMediaUploadedDocument *>(input_media.get())->thumb_ != nullptr;
+ switch (input_media->get_id()) {
+ case telegram_api::inputMediaUploadedDocument::ID:
+ return static_cast<const telegram_api::inputMediaUploadedDocument *>(input_media.get())->thumb_ != nullptr;
+ case telegram_api::inputMediaPaidMedia::ID: {
+ auto &extended_media = static_cast<const telegram_api::inputMediaPaidMedia *>(input_media.get())->extended_media_;
+ if (extended_media.size() > 1u) {
+ for (auto &media : extended_media) {
+ CHECK(!extract_was_thumbnail_uploaded(media));
+ }
+ return false;
+ }
+ CHECK(extended_media.size() == 1u);
+ return extract_was_thumbnail_uploaded(extended_media[0]);
+ }
+ default:
+ return false;
+ }
}
-string FileManager::extract_file_reference(const tl_object_ptr<telegram_api::InputMedia> &input_media) {
+string FileManager::extract_file_reference(const telegram_api::object_ptr<telegram_api::InputMedia> &input_media) {
if (input_media == nullptr) {
return string();
}
@@ -3538,12 +4187,43 @@ string FileManager::extract_file_reference(const tl_object_ptr<telegram_api::Inp
return extract_file_reference(static_cast<const telegram_api::inputMediaDocument *>(input_media.get())->id_);
case telegram_api::inputMediaPhoto::ID:
return extract_file_reference(static_cast<const telegram_api::inputMediaPhoto *>(input_media.get())->id_);
+ case telegram_api::inputMediaPaidMedia::ID:
+ UNREACHABLE();
+ return string();
+ case telegram_api::inputMediaUploadedDocument::ID: {
+ auto uploaded_document = static_cast<const telegram_api::inputMediaUploadedDocument *>(input_media.get());
+ if (uploaded_document->file_->get_id() != telegram_api::inputFileStoryDocument::ID) {
+ return string();
+ }
+ return extract_file_reference(
+ static_cast<const telegram_api::inputFileStoryDocument *>(uploaded_document->file_.get())->id_);
+ }
default:
return string();
}
}
-string FileManager::extract_file_reference(const tl_object_ptr<telegram_api::InputDocument> &input_document) {
+vector<string> FileManager::extract_file_references(
+ const telegram_api::object_ptr<telegram_api::InputMedia> &input_media) {
+ if (input_media == nullptr) {
+ return {};
+ }
+ switch (input_media->get_id()) {
+ case telegram_api::inputMediaDocument::ID:
+ case telegram_api::inputMediaPhoto::ID:
+ return {extract_file_reference(input_media)};
+ case telegram_api::inputMediaPaidMedia::ID:
+ return transform(static_cast<const telegram_api::inputMediaPaidMedia *>(input_media.get())->extended_media_,
+ [](const telegram_api::object_ptr<telegram_api::InputMedia> &media) {
+ return extract_file_reference(media);
+ });
+ default:
+ return {};
+ }
+}
+
+string FileManager::extract_file_reference(
+ const telegram_api::object_ptr<telegram_api::InputDocument> &input_document) {
if (input_document == nullptr || input_document->get_id() != telegram_api::inputDocument::ID) {
return string();
}
@@ -3551,7 +4231,7 @@ string FileManager::extract_file_reference(const tl_object_ptr<telegram_api::Inp
return static_cast<const telegram_api::inputDocument *>(input_document.get())->file_reference_.as_slice().str();
}
-string FileManager::extract_file_reference(const tl_object_ptr<telegram_api::InputPhoto> &input_photo) {
+string FileManager::extract_file_reference(const telegram_api::object_ptr<telegram_api::InputPhoto> &input_photo) {
if (input_photo == nullptr || input_photo->get_id() != telegram_api::inputPhoto::ID) {
return string();
}
@@ -3559,11 +4239,12 @@ string FileManager::extract_file_reference(const tl_object_ptr<telegram_api::Inp
return static_cast<const telegram_api::inputPhoto *>(input_photo.get())->file_reference_.as_slice().str();
}
-bool FileManager::extract_was_uploaded(const tl_object_ptr<telegram_api::InputChatPhoto> &input_chat_photo) {
+bool FileManager::extract_was_uploaded(const telegram_api::object_ptr<telegram_api::InputChatPhoto> &input_chat_photo) {
return input_chat_photo != nullptr && input_chat_photo->get_id() == telegram_api::inputChatUploadedPhoto::ID;
}
-string FileManager::extract_file_reference(const tl_object_ptr<telegram_api::InputChatPhoto> &input_chat_photo) {
+string FileManager::extract_file_reference(
+ const telegram_api::object_ptr<telegram_api::InputChatPhoto> &input_chat_photo) {
if (input_chat_photo == nullptr || input_chat_photo->get_id() != telegram_api::inputChatPhoto::ID) {
return string();
}
@@ -3579,7 +4260,7 @@ FileId FileManager::next_file_id() {
}
CHECK(file_id_info_.size() <= static_cast<size_t>(std::numeric_limits<int32>::max()));
FileId res(static_cast<int32>(file_id_info_.size()), 0);
- file_id_info_.push_back({});
+ file_id_info_.push_back(make_unique<FileIdInfo>());
return res;
}
@@ -3590,12 +4271,12 @@ FileManager::FileNodeId FileManager::next_file_node_id() {
return res;
}
-void FileManager::on_start_download(QueryId query_id) {
+void FileManager::on_start_download(FileDownloadManager::QueryId query_id) {
if (is_closed_) {
return;
}
- auto query = queries_container_.get(query_id);
+ auto query = download_queries_.get(query_id);
CHECK(query != nullptr);
auto file_id = query->file_id_;
@@ -3612,19 +4293,19 @@ void FileManager::on_start_download(QueryId query_id) {
file_node->is_download_started_ = true;
}
-void FileManager::on_partial_download(QueryId query_id, PartialLocalFileLocation partial_local, int64 ready_size,
+void FileManager::on_partial_download(FileDownloadManager::QueryId query_id, PartialLocalFileLocation partial_local,
int64 size) {
if (is_closed_) {
return;
}
- auto query = queries_container_.get(query_id);
+ auto query = download_queries_.get(query_id);
CHECK(query != nullptr);
auto file_id = query->file_id_;
auto file_node = get_file_node(file_id);
LOG(DEBUG) << "Receive on_partial_download for file " << file_id << " with " << partial_local
- << ", ready_size = " << ready_size << " and size = " << size;
+ << " and size = " << size;
if (!file_node) {
return;
}
@@ -3638,16 +4319,16 @@ void FileManager::on_partial_download(QueryId query_id, PartialLocalFileLocation
file_node->set_size(size);
}
}
- file_node->set_local_location(LocalFileLocation(std::move(partial_local)), ready_size, -1, -1 /* TODO */);
+ file_node->set_local_location(LocalFileLocation(std::move(partial_local)), -1, -1 /* TODO */);
try_flush_node(file_node, "on_partial_download");
}
-void FileManager::on_hash(QueryId query_id, string hash) {
+void FileManager::on_hash(FileUploadManager::QueryId query_id, string hash) {
if (is_closed_) {
return;
}
- auto query = queries_container_.get(query_id);
+ auto query = upload_queries_.get(query_id);
CHECK(query != nullptr);
auto file_id = query->file_id_;
@@ -3664,18 +4345,17 @@ void FileManager::on_hash(QueryId query_id, string hash) {
file_node->encryption_key_.set_value_hash(secure_storage::ValueHash::create(hash).move_as_ok());
}
-void FileManager::on_partial_upload(QueryId query_id, PartialRemoteFileLocation partial_remote, int64 ready_size) {
+void FileManager::on_partial_upload(FileUploadManager::QueryId query_id, PartialRemoteFileLocation partial_remote) {
if (is_closed_) {
return;
}
- auto query = queries_container_.get(query_id);
+ auto query = upload_queries_.get(query_id);
CHECK(query != nullptr);
auto file_id = query->file_id_;
auto file_node = get_file_node(file_id);
- LOG(DEBUG) << "Receive on_partial_upload for file " << file_id << " with " << partial_remote << " and ready size "
- << ready_size;
+ LOG(DEBUG) << "Receive on_partial_upload for file " << file_id << " with " << partial_remote;
if (!file_node) {
LOG(ERROR) << "Can't find being uploaded file " << file_id;
return;
@@ -3686,21 +4366,22 @@ void FileManager::on_partial_upload(QueryId query_id, PartialRemoteFileLocation
return;
}
- file_node->set_partial_remote_location(std::move(partial_remote), ready_size);
+ file_node->set_partial_remote_location(std::move(partial_remote));
try_flush_node(file_node, "on_partial_upload");
}
-void FileManager::on_download_ok(QueryId query_id, FullLocalFileLocation local, int64 size, bool is_new) {
+void FileManager::on_download_ok(FileDownloadManager::QueryId query_id, FullLocalFileLocation local, int64 size,
+ bool is_new) {
if (is_closed_) {
return;
}
- Query query;
+ DownloadQuery query;
bool was_active;
- std::tie(query, was_active) = finish_query(query_id);
+ std::tie(query, was_active) = finish_download_query(query_id);
auto file_id = query.file_id_;
LOG(INFO) << "ON DOWNLOAD OK of " << (is_new ? "new" : "checked") << " file " << file_id << " of size " << size;
- auto r_new_file_id = register_local(std::move(local), DialogId(), size, false, false, true, file_id);
+ auto r_new_file_id = register_local(std::move(local), DialogId(), size, false, true, file_id);
Status status = Status::OK();
if (r_new_file_id.is_error()) {
status = Status::Error(PSLICE() << "Can't register local file after download: " << r_new_file_id.error().message());
@@ -3711,19 +4392,19 @@ void FileManager::on_download_ok(QueryId query_id, FullLocalFileLocation local,
}
if (status.is_error()) {
LOG(ERROR) << status.message();
- return on_error_impl(get_file_node(file_id), query.type_, was_active, std::move(status));
+ return on_download_error_impl(get_file_node(file_id), query.type_, was_active, std::move(status));
}
}
-void FileManager::on_upload_ok(QueryId query_id, FileType file_type, PartialRemoteFileLocation partial_remote,
- int64 size) {
+void FileManager::on_upload_ok(FileUploadManager::QueryId query_id, FileType file_type,
+ PartialRemoteFileLocation partial_remote) {
if (is_closed_) {
return;
}
CHECK(partial_remote.ready_part_count_ == partial_remote.part_count_);
- auto some_file_id = finish_query(query_id).first.file_id_;
- LOG(INFO) << "ON UPLOAD OK file " << some_file_id << " of size " << size;
+ auto some_file_id = finish_upload_query(query_id).first.file_id_;
+ LOG(INFO) << "ON UPLOAD OK file " << some_file_id;
auto file_node = get_file_node(some_file_id);
if (!file_node) {
@@ -3794,37 +4475,37 @@ void FileManager::on_upload_ok(QueryId query_id, FileType file_type, PartialRemo
}
// for upload by hash
-void FileManager::on_upload_full_ok(QueryId query_id, FullRemoteFileLocation remote) {
+void FileManager::on_upload_full_ok(FileUploadManager::QueryId query_id, FullRemoteFileLocation remote) {
if (is_closed_) {
return;
}
- auto file_id = finish_query(query_id).first.file_id_;
+ auto file_id = finish_upload_query(query_id).first.file_id_;
LOG(INFO) << "ON UPLOAD FULL OK for file " << file_id;
auto new_file_id = register_remote(std::move(remote), FileLocationSource::FromServer, DialogId(), 0, 0, "");
LOG_STATUS(merge(new_file_id, file_id));
}
-void FileManager::on_partial_generate(QueryId query_id, PartialLocalFileLocation partial_local, int64 expected_size) {
+void FileManager::on_partial_generate(FileGenerateManager::QueryId query_id, PartialLocalFileLocation partial_local,
+ int64 expected_size) {
if (is_closed_) {
return;
}
- auto query = queries_container_.get(query_id);
+ auto query = generate_queries_.get(query_id);
CHECK(query != nullptr);
auto file_id = query->file_id_;
auto file_node = get_file_node(file_id);
- auto bitmask = Bitmask(Bitmask::Decode{}, partial_local.ready_bitmask_);
- LOG(DEBUG) << "Receive on_partial_generate for file " << file_id << ": " << partial_local.path_ << " " << bitmask;
+ LOG(DEBUG) << "Receive on_partial_generate for file " << file_id << ": " << partial_local.path_ << " "
+ << partial_local.ready_size_;
if (!file_node) {
return;
}
if (file_node->generate_id_ != query_id) {
return;
}
- auto ready_size = bitmask.get_total_size(partial_local.part_size_, file_node->size_);
- file_node->set_local_location(LocalFileLocation(partial_local), ready_size, -1, -1 /* TODO */);
+ file_node->set_local_location(LocalFileLocation(partial_local), -1, -1 /* TODO */);
// TODO check for size and local_size, abort generation if needed
if (expected_size > 0) {
file_node->set_expected_size(expected_size);
@@ -3834,21 +4515,21 @@ void FileManager::on_partial_generate(QueryId query_id, PartialLocalFileLocation
run_upload(file_node, {});
}
if (file_node->upload_id_ != 0) {
- send_closure(file_load_manager_, &FileLoadManager::update_local_file_location, file_node->upload_id_,
+ send_closure(file_upload_manager_, &FileUploadManager::update_local_file_location, file_node->upload_id_,
LocalFileLocation(std::move(partial_local)));
}
try_flush_node(file_node, "on_partial_generate");
}
-void FileManager::on_generate_ok(QueryId query_id, FullLocalFileLocation local) {
+void FileManager::on_generate_ok(FileGenerateManager::QueryId query_id, FullLocalFileLocation local) {
if (is_closed_) {
return;
}
- Query query;
+ GenerateQuery query;
bool was_active;
- std::tie(query, was_active) = finish_query(query_id);
+ std::tie(query, was_active) = finish_generate_query(query_id);
auto generate_file_id = query.file_id_;
LOG(INFO) << "Receive on_generate_ok for file " << generate_file_id << ": " << local;
@@ -3859,18 +4540,19 @@ void FileManager::on_generate_ok(QueryId query_id, FullLocalFileLocation local)
auto old_upload_id = file_node->upload_id_;
- auto r_new_file_id = register_local(local, DialogId(), 0, false, false, false, generate_file_id);
+ auto r_new_file_id = register_local(local, DialogId(), 0, false, false, generate_file_id);
file_node = get_file_node(generate_file_id);
if (r_new_file_id.is_error()) {
- return on_error_impl(
- file_node, query.type_, was_active,
+ return on_generate_error_impl(
+ file_node, was_active,
Status::Error(PSLICE() << "Can't register local file after generate: " << r_new_file_id.error()));
}
CHECK(file_node);
FileView file_view(file_node);
if (context_->need_notify_on_new_files()) {
- if (!file_view.has_generate_location() || !begins_with(file_view.generate_location().conversion_, "#file_id#")) {
+ auto generate_location = file_view.get_generate_location();
+ if (generate_location == nullptr || !begins_with(generate_location->conversion_, "#file_id#")) {
context_->on_new_file(file_view.size(), file_view.get_allocated_local_size(), 1);
}
}
@@ -3879,66 +4561,75 @@ void FileManager::on_generate_ok(QueryId query_id, FullLocalFileLocation local)
if (was_active) {
if (old_upload_id != 0 && old_upload_id == file_node->upload_id_) {
- send_closure(file_load_manager_, &FileLoadManager::update_local_file_location, file_node->upload_id_,
+ send_closure(file_upload_manager_, &FileUploadManager::update_local_file_location, file_node->upload_id_,
LocalFileLocation(std::move(local)));
}
}
}
-void FileManager::on_error(QueryId query_id, Status status) {
+void FileManager::on_download_error(FileDownloadManager::QueryId query_id, Status status) {
if (is_closed_) {
return;
}
- Query query;
+ DownloadQuery query;
bool was_active;
- std::tie(query, was_active) = finish_query(query_id);
+ std::tie(query, was_active) = finish_download_query(query_id);
auto node = get_file_node(query.file_id_);
if (!node) {
LOG(ERROR) << "Can't find file node for " << query.file_id_ << " " << status;
return;
}
+ on_download_error_impl(node, query.type_, was_active, std::move(status));
+}
- if (query.type_ == Query::Type::UploadByHash && !G()->close_flag()) {
- LOG(INFO) << "Upload By Hash failed: " << status << ", restart upload";
- node->get_by_hash_ = false;
- run_upload(node, {});
+void FileManager::on_generate_error(FileGenerateManager::QueryId query_id, Status status) {
+ if (is_closed_) {
return;
}
- on_error_impl(node, query.type_, was_active, std::move(status));
-}
-void FileManager::on_error_impl(FileNodePtr node, Query::Type type, bool was_active, Status status) {
- SCOPE_EXIT {
- try_flush_node(node, "on_error_impl");
- };
-
- if (status.message() == "FILE_PART_INVALID") {
- bool has_partial_small_location = node->remote_.partial && !node->remote_.partial->is_big_;
- FileView file_view(node);
- auto expected_size = file_view.expected_size(true);
- bool should_be_big_location = is_file_big(file_view.get_type(), expected_size);
+ GenerateQuery query;
+ bool was_active;
+ std::tie(query, was_active) = finish_generate_query(query_id);
+ auto node = get_file_node(query.file_id_);
+ if (!node) {
+ LOG(ERROR) << "Can't find file node for " << query.file_id_ << " " << status;
+ return;
+ }
+ on_generate_error_impl(node, was_active, std::move(status));
+}
- node->delete_partial_remote_location();
- if (has_partial_small_location && should_be_big_location) {
- run_upload(node, {});
- return;
- }
+void FileManager::on_upload_error(FileUploadManager::QueryId query_id, Status status) {
+ if (is_closed_) {
+ return;
+ }
- LOG(ERROR) << "Failed to upload file " << node->main_file_id_ << ": unexpected " << status
- << ", is_small = " << has_partial_small_location << ", should_be_big = " << should_be_big_location
- << ", expected size = " << expected_size;
+ UploadQuery query;
+ bool was_active;
+ std::tie(query, was_active) = finish_upload_query(query_id);
+ auto node = get_file_node(query.file_id_);
+ if (!node) {
+ LOG(ERROR) << "Can't find file node for " << query.file_id_ << " " << status;
+ return;
}
- if (begins_with(status.message(), "FILE_GENERATE_LOCATION_INVALID")) {
- node->set_generate_location(nullptr);
+ if (query.type_ == UploadQuery::Type::UploadByHash && !G()->close_flag()) {
+ LOG(INFO) << "Upload By Hash failed: " << status << ", restart upload";
+ node->get_by_hash_ = false;
+ return run_upload(node, {});
}
+ on_upload_error_impl(node, query.type_, was_active, std::move(status));
+}
+
+void FileManager::on_download_error_impl(FileNodePtr node, DownloadQuery::Type type, bool was_active, Status status) {
+ SCOPE_EXIT {
+ try_flush_node(node, "on_error_impl");
+ };
if ((status.message() == "FILE_ID_INVALID" || status.message() == "LOCATION_INVALID") &&
FileView(node).may_reload_photo()) {
node->need_reload_photo_ = true;
- run_download(node, true);
- return;
+ return run_download(node, true);
}
if (FileReferenceManager::is_file_reference_error(status)) {
@@ -3958,39 +4649,26 @@ void FileManager::on_error_impl(FileNodePtr node, Query::Type type, bool was_act
}
CHECK(!node->file_ids_.empty());
delete_file_reference(node->file_ids_.back(), file_reference);
- run_download(node, true);
- return;
- }
-
- if (begins_with(status.message(), "FILE_UPLOAD_RESTART")) {
- if (ends_with(status.message(), "WITH_FILE_REFERENCE")) {
- node->upload_was_update_file_reference_ = true;
- }
- run_upload(node, {});
- return;
+ return run_download(node, true);
}
if (begins_with(status.message(), "FILE_DOWNLOAD_RESTART")) {
if (ends_with(status.message(), "WITH_FILE_REFERENCE")) {
node->download_was_update_file_reference_ = true;
- run_download(node, true);
- return;
+ return run_download(node, true);
} else if (ends_with(status.message(), "INCREASE_PART_SIZE")) {
if (try_fix_partial_local_location(node)) {
- run_download(node, true);
- return;
+ return run_download(node, true);
}
} else {
node->can_search_locally_ = false;
- run_download(node, true);
- return;
+ return run_download(node, true);
}
}
if (status.message() == "MTPROTO_CLUSTER_INVALID") {
send_closure(G()->config_manager(), &ConfigManager::request_config, true);
- run_download(node, true);
- return;
+ return run_download(node, true);
}
if (!was_active) {
@@ -4002,33 +4680,113 @@ void FileManager::on_error_impl(FileNodePtr node, Query::Type type, bool was_act
status = Global::request_aborted_error();
} else {
if (status.code() != -1) {
- if (type == Query::Type::Generate && node->generate_ != nullptr) {
- LOG(WARNING) << "Failed to generate file " << node->main_file_id_ << " with " << *node->generate_ << ": "
- << status;
- } else {
- LOG(WARNING) << "Failed to " << type << " file " << node->main_file_id_ << " of type "
- << FileView(node).get_type() << ": " << status;
+ LOG(WARNING) << "Failed to " << type << " file " << node->main_file_id_ << " of type "
+ << FileView(node).get_type() << ": " << status;
+ }
+ if (status.code() == 0 && node->local_.type() == LocalFileLocation::Type::Partial &&
+ !begins_with(status.message(), "FILE_DOWNLOAD_ID_INVALID") &&
+ !begins_with(status.message(), "FILE_DOWNLOAD_LIMIT")) {
+ // Remove partial location
+ CSlice path = node->local_.partial().path_;
+ if (begins_with(path, get_files_temp_dir(FileType::SecureDecrypted)) ||
+ begins_with(path, get_files_temp_dir(FileType::Video))) {
+ LOG(INFO) << "Unlink file " << path;
+ send_closure(file_load_manager_, &FileLoadManager::unlink_file, std::move(node->local_.partial().path_),
+ Promise<Unit>());
+ node->drop_local_location();
}
}
+ status = Status::Error(400, status.message());
+ }
+
+ on_file_load_error(node, std::move(status));
+}
+
+void FileManager::on_generate_error_impl(FileNodePtr node, bool was_active, Status status) {
+ SCOPE_EXIT {
+ try_flush_node(node, "on_generate_error_impl");
+ };
+ if (begins_with(status.message(), "FILE_GENERATE_LOCATION_INVALID")) {
+ node->set_generate_location(nullptr);
+ }
+ if (!was_active) {
+ return;
+ }
+
+ if (G()->close_flag() && (status.code() < 400 || (status.code() == Global::request_aborted_error().code() &&
+ status.message() == Global::request_aborted_error().message()))) {
+ status = Global::request_aborted_error();
+ } else {
+ if (status.code() != -1 && node->generate_ != nullptr) {
+ LOG(WARNING) << "Failed to generate file " << node->main_file_id_ << " with " << *node->generate_ << ": "
+ << status;
+ }
if (status.code() == 0) {
// Remove partial locations
- if (node->local_.type() == LocalFileLocation::Type::Partial &&
- !begins_with(status.message(), "FILE_DOWNLOAD_ID_INVALID") &&
- !begins_with(status.message(), "FILE_DOWNLOAD_LIMIT")) {
- CSlice path = node->local_.partial().path_;
- if (begins_with(path, get_files_temp_dir(FileType::SecureDecrypted)) ||
- begins_with(path, get_files_temp_dir(FileType::Video))) {
- LOG(INFO) << "Unlink file " << path;
- send_closure(file_load_manager_, &FileLoadManager::unlink_file, std::move(node->local_.partial().path_),
- Promise<Unit>());
- node->drop_local_location();
- }
+ if (node->local_.type() == LocalFileLocation::Type::Partial) {
+ // the file itself has already been deleted
+ node->drop_local_location();
}
node->delete_partial_remote_location();
}
status = Status::Error(400, status.message());
}
+ on_file_load_error(node, std::move(status));
+}
+
+void FileManager::on_upload_error_impl(FileNodePtr node, UploadQuery::Type type, bool was_active, Status status) {
+ SCOPE_EXIT {
+ try_flush_node(node, "on_upload_error_impl");
+ };
+
+ if (status.message() == "FILE_PART_INVALID") {
+ bool has_partial_small_location = node->remote_.partial && !node->remote_.partial->is_big_;
+ FileView file_view(node);
+ auto expected_size = file_view.expected_size(true);
+ bool should_be_big_location = is_file_big(file_view.get_type(), expected_size);
+
+ node->delete_partial_remote_location();
+ if (has_partial_small_location && should_be_big_location) {
+ return run_upload(node, {});
+ }
+
+ LOG(ERROR) << "Failed to upload file " << node->main_file_id_ << ": unexpected " << status
+ << ", is_small = " << has_partial_small_location << ", should_be_big = " << should_be_big_location
+ << ", expected size = " << expected_size;
+ }
+
+ if (begins_with(status.message(), "FILE_UPLOAD_RESTART")) {
+ if (ends_with(status.message(), "WITH_FILE_REFERENCE")) {
+ node->upload_was_update_file_reference_ = true;
+ } else {
+ node->delete_partial_remote_location();
+ }
+ return run_upload(node, {});
+ }
+
+ if (!was_active) {
+ return;
+ }
+
+ if (G()->close_flag() && (status.code() < 400 || (status.code() == Global::request_aborted_error().code() &&
+ status.message() == Global::request_aborted_error().message()))) {
+ status = Global::request_aborted_error();
+ } else {
+ if (status.code() != -1) {
+ LOG(WARNING) << "Failed to " << type << " file " << node->main_file_id_ << " of type "
+ << FileView(node).get_type() << ": " << status;
+ }
+ if (status.code() == 0) {
+ node->delete_partial_remote_location();
+ }
+ status = Status::Error(400, status.message());
+ }
+
+ on_file_load_error(node, std::move(status));
+}
+
+void FileManager::on_file_load_error(FileNodePtr node, Status status) {
// Stop everything on error
do_cancel_generate(node);
do_cancel_download(node);
@@ -4053,39 +4811,53 @@ void FileManager::on_error_impl(FileNodePtr node, Query::Type type, bool was_act
}
}
-std::pair<FileManager::Query, bool> FileManager::finish_query(QueryId query_id) {
- SCOPE_EXIT {
- queries_container_.erase(query_id);
- };
- auto query = queries_container_.get(query_id);
+std::pair<FileManager::DownloadQuery, bool> FileManager::finish_download_query(FileDownloadManager::QueryId query_id) {
+ auto query = download_queries_.get(query_id);
CHECK(query != nullptr);
-
auto res = *query;
+ download_queries_.erase(query_id);
+
auto node = get_file_node(res.file_id_);
- if (!node) {
- return std::make_pair(res, false);
- }
- bool was_active = false;
- if (node->generate_id_ == query_id) {
- node->generate_id_ = 0;
- node->generate_was_update_ = false;
- node->set_generate_priority(0, 0);
- was_active = true;
- }
- if (node->download_id_ == query_id) {
+ if (node && node->download_id_ == query_id) {
node->download_id_ = 0;
node->download_was_update_file_reference_ = false;
node->is_download_started_ = false;
node->set_download_priority(0);
- was_active = true;
+ return std::make_pair(res, true);
}
- if (node->upload_id_ == query_id) {
+ return std::make_pair(res, false);
+}
+
+std::pair<FileManager::GenerateQuery, bool> FileManager::finish_generate_query(FileGenerateManager::QueryId query_id) {
+ auto query = generate_queries_.get(query_id);
+ CHECK(query != nullptr);
+ auto res = *query;
+ generate_queries_.erase(query_id);
+
+ auto node = get_file_node(res.file_id_);
+ if (node && node->generate_id_ == query_id) {
+ node->generate_id_ = 0;
+ node->generate_was_update_ = false;
+ node->set_generate_priority(0, 0);
+ return std::make_pair(res, true);
+ }
+ return std::make_pair(res, false);
+}
+
+std::pair<FileManager::UploadQuery, bool> FileManager::finish_upload_query(FileUploadManager::QueryId query_id) {
+ auto query = upload_queries_.get(query_id);
+ CHECK(query != nullptr);
+ auto res = *query;
+ upload_queries_.erase(query_id);
+
+ auto node = get_file_node(res.file_id_);
+ if (node && node->upload_id_ == query_id) {
node->upload_id_ = 0;
node->upload_was_update_file_reference_ = false;
node->set_upload_priority(0);
- was_active = true;
+ return std::make_pair(res, true);
}
- return std::make_pair(res, was_active);
+ return std::make_pair(res, false);
}
FullRemoteFileLocation *FileManager::get_remote(int32 key) {
@@ -4095,6 +4867,48 @@ FullRemoteFileLocation *FileManager::get_remote(int32 key) {
return &remote_location_info_.get(key).remote_;
}
+class FileManager::PreliminaryUploadFileCallback final : public UploadCallback {
+ public:
+ void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) final {
+ // cancel file upload of the file to allow next upload with the same file to succeed
+ send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id);
+ }
+
+ void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) final {
+ // cancel file upload of the file to allow next upload with the same file to succeed
+ send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id);
+ }
+
+ void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) final {
+ // cancel file upload of the file to allow next upload with the same file to succeed
+ send_closure(G()->file_manager(), &FileManager::cancel_upload, file_id);
+ }
+
+ void on_upload_error(FileId file_id, Status error) final {
+ }
+};
+
+void FileManager::preliminary_upload_file(const td_api::object_ptr<td_api::InputFile> &input_file, FileType file_type,
+ int32 priority, Promise<td_api::object_ptr<td_api::file>> &&promise) {
+ if (!(1 <= priority && priority <= 32)) {
+ return promise.set_error(Status::Error(400, "Upload priority must be between 1 and 32"));
+ }
+
+ bool is_secret = file_type == FileType::Encrypted || file_type == FileType::EncryptedThumbnail;
+ bool is_secure = file_type == FileType::SecureEncrypted;
+ auto r_file_id =
+ get_input_file_id(file_type, input_file, DialogId(), false, is_secret, !is_secure && !is_secret, is_secure);
+ if (r_file_id.is_error()) {
+ return promise.set_error(Status::Error(r_file_id.error().code(), r_file_id.error().message()));
+ }
+ auto file_id = r_file_id.ok();
+ auto upload_file_id = dup_file_id(file_id, "preliminary_upload_file");
+
+ upload(upload_file_id, std::make_shared<PreliminaryUploadFileCallback>(), priority, 0);
+
+ promise.set_value(get_file_object(upload_file_id, false));
+}
+
Result<string> FileManager::get_suggested_file_name(FileId file_id, const string &directory) {
if (!file_id.is_valid()) {
return Status::Error(400, "Invalid file identifier");
@@ -4110,11 +4924,42 @@ Result<string> FileManager::get_suggested_file_name(FileId file_id, const string
void FileManager::hangup() {
file_db_.reset();
file_generate_manager_.reset();
- file_load_manager_.reset();
- while (!queries_container_.empty()) {
- auto query_ids = queries_container_.ids();
+ file_download_manager_.reset();
+ file_upload_manager_.reset();
+ while (!download_queries_.empty()) {
+ auto query_ids = download_queries_.ids();
for (auto query_id : query_ids) {
- on_error(query_id, Global::request_aborted_error());
+ DownloadQuery query;
+ bool was_active;
+ std::tie(query, was_active) = finish_download_query(static_cast<FileDownloadManager::QueryId>(query_id));
+ auto node = get_file_node(query.file_id_);
+ if (node) {
+ on_download_error_impl(node, query.type_, was_active, Global::request_aborted_error());
+ }
+ }
+ }
+ while (!generate_queries_.empty()) {
+ auto query_ids = generate_queries_.ids();
+ for (auto query_id : query_ids) {
+ GenerateQuery query;
+ bool was_active;
+ std::tie(query, was_active) = finish_generate_query(static_cast<FileGenerateManager::QueryId>(query_id));
+ auto node = get_file_node(query.file_id_);
+ if (node) {
+ on_generate_error_impl(node, was_active, Global::request_aborted_error());
+ }
+ }
+ }
+ while (!upload_queries_.empty()) {
+ auto query_ids = upload_queries_.ids();
+ for (auto query_id : query_ids) {
+ UploadQuery query;
+ bool was_active;
+ std::tie(query, was_active) = finish_upload_query(static_cast<FileUploadManager::QueryId>(query_id));
+ auto node = get_file_node(query.file_id_);
+ if (node) {
+ on_upload_error_impl(node, query.type_, was_active, Global::request_aborted_error());
+ }
}
}
is_closed_ = true;