2018-12-31 20:04:05 +01:00
|
|
|
//
|
2020-01-01 02:23:48 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "td/telegram/td_api.h"
|
|
|
|
#include "td/telegram/telegram_api.h"
|
|
|
|
|
|
|
|
#include "td/telegram/DialogId.h"
|
2019-01-06 21:39:10 +01:00
|
|
|
#include "td/telegram/files/FileDbId.h"
|
2018-12-27 20:24:44 +01:00
|
|
|
#include "td/telegram/files/FileEncryptionKey.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/telegram/files/FileGenerateManager.h"
|
|
|
|
#include "td/telegram/files/FileId.h"
|
|
|
|
#include "td/telegram/files/FileLoadManager.h"
|
|
|
|
#include "td/telegram/files/FileLocation.h"
|
2019-01-19 03:44:31 +01:00
|
|
|
#include "td/telegram/files/FileSourceId.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/telegram/files/FileStats.h"
|
2019-01-19 22:54:29 +01:00
|
|
|
#include "td/telegram/files/FileType.h"
|
2018-08-13 22:18:27 +02:00
|
|
|
#include "td/telegram/Location.h"
|
2019-08-14 02:13:34 +02:00
|
|
|
#include "td/telegram/PhotoSizeSource.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-07-03 21:29:04 +02:00
|
|
|
#include "td/actor/actor.h"
|
|
|
|
#include "td/actor/PromiseFuture.h"
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/utils/buffer.h"
|
|
|
|
#include "td/utils/common.h"
|
|
|
|
#include "td/utils/Container.h"
|
2018-03-06 19:31:20 +01:00
|
|
|
#include "td/utils/Enumerator.h"
|
2018-09-27 15:37:15 +02:00
|
|
|
#include "td/utils/logging.h"
|
2019-02-14 12:20:40 +01:00
|
|
|
#include "td/utils/optional.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
#include "td/utils/Slice.h"
|
|
|
|
#include "td/utils/Status.h"
|
2019-12-23 18:48:30 +01:00
|
|
|
#include "td/utils/StringBuilder.h"
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <memory>
|
|
|
|
#include <set>
|
2020-04-30 21:21:42 +02:00
|
|
|
#include <unordered_map>
|
2019-01-18 21:12:09 +01:00
|
|
|
#include <unordered_set>
|
2018-12-31 20:04:05 +01:00
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
namespace td {
|
2018-01-20 11:49:06 +01:00
|
|
|
|
2018-09-26 01:59:29 +02:00
|
|
|
extern int VERBOSITY_NAME(update_file);
|
|
|
|
|
2019-01-19 22:26:23 +01:00
|
|
|
class FileData;
|
2019-01-06 21:47:40 +01:00
|
|
|
class FileDbInterface;
|
|
|
|
|
2019-02-15 21:22:40 +01:00
|
|
|
enum class FileLocationSource : int8 { None, FromUser, FromBinlog, FromDatabase, FromServer };
|
2018-01-20 11:49:06 +01:00
|
|
|
|
2019-02-14 12:20:40 +01:00
|
|
|
struct NewRemoteFileLocation {
|
|
|
|
NewRemoteFileLocation() = default;
|
|
|
|
NewRemoteFileLocation(RemoteFileLocation remote, FileLocationSource source);
|
|
|
|
RemoteFileLocation partial_or_empty() const;
|
|
|
|
unique_ptr<PartialRemoteFileLocation> partial;
|
|
|
|
|
|
|
|
//TODO: use RemoteId
|
2020-04-10 02:43:35 +02:00
|
|
|
// hardest part is to determine whether we should flush this location to db.
|
2019-02-14 12:20:40 +01:00
|
|
|
// probably, will need some generation in RemoteInfo
|
|
|
|
optional<FullRemoteFileLocation> full;
|
|
|
|
bool is_full_alive{false}; // if false, then we may try to upload this file
|
|
|
|
FileLocationSource full_source{FileLocationSource::None};
|
|
|
|
int64 ready_size = 0;
|
|
|
|
};
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
class FileNode {
|
|
|
|
public:
|
2019-02-14 12:20:40 +01:00
|
|
|
FileNode(LocalFileLocation local, NewRemoteFileLocation remote, unique_ptr<FullGenerateFileLocation> generate,
|
2018-02-18 17:29:44 +01:00
|
|
|
int64 size, int64 expected_size, string remote_name, string url, DialogId owner_dialog_id,
|
|
|
|
FileEncryptionKey key, FileId main_file_id, int8 main_file_id_priority)
|
2018-12-31 20:04:05 +01:00
|
|
|
: local_(std::move(local))
|
|
|
|
, remote_(std::move(remote))
|
|
|
|
, generate_(std::move(generate))
|
|
|
|
, size_(size)
|
|
|
|
, expected_size_(expected_size)
|
2018-02-18 17:29:44 +01:00
|
|
|
, remote_name_(std::move(remote_name))
|
2018-12-31 20:04:05 +01:00
|
|
|
, url_(std::move(url))
|
|
|
|
, owner_dialog_id_(owner_dialog_id)
|
|
|
|
, encryption_key_(std::move(key))
|
|
|
|
, main_file_id_(main_file_id)
|
|
|
|
, main_file_id_priority_(main_file_id_priority) {
|
2018-11-11 12:38:04 +01:00
|
|
|
init_ready_size();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
2018-12-26 17:11:15 +01:00
|
|
|
void drop_local_location();
|
|
|
|
void set_local_location(const LocalFileLocation &local, int64 ready_size, int64 prefix_offset,
|
|
|
|
int64 ready_prefix_size);
|
2019-02-14 12:20:40 +01:00
|
|
|
void set_new_remote_location(NewRemoteFileLocation remote);
|
|
|
|
void delete_partial_remote_location();
|
|
|
|
void set_partial_remote_location(const PartialRemoteFileLocation &remote, int64 ready_size);
|
|
|
|
|
2019-01-25 02:38:11 +01:00
|
|
|
bool delete_file_reference(Slice file_reference);
|
2018-02-04 18:27:05 +01:00
|
|
|
void set_generate_location(unique_ptr<FullGenerateFileLocation> &&generate);
|
2018-12-31 20:04:05 +01:00
|
|
|
void set_size(int64 size);
|
|
|
|
void set_expected_size(int64 expected_size);
|
2018-02-18 17:29:44 +01:00
|
|
|
void set_remote_name(string remote_name);
|
2018-12-31 20:04:05 +01:00
|
|
|
void set_url(string url);
|
|
|
|
void set_owner_dialog_id(DialogId owner_id);
|
|
|
|
void set_encryption_key(FileEncryptionKey key);
|
2019-01-10 22:12:51 +01:00
|
|
|
void set_upload_pause(FileId file_id);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-01-20 12:47:53 +01:00
|
|
|
void set_download_priority(int8 priority);
|
|
|
|
void set_upload_priority(int8 priority);
|
|
|
|
void set_generate_priority(int8 download_priority, int8 upload_priority);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-11-11 12:38:04 +01:00
|
|
|
void set_download_offset(int64 download_offset);
|
2019-02-18 20:08:05 +01:00
|
|
|
void set_download_limit(int64 download_limit);
|
2018-11-11 12:38:04 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
void on_changed();
|
|
|
|
void on_info_changed();
|
|
|
|
void on_pmc_changed();
|
|
|
|
|
|
|
|
bool need_info_flush() const;
|
|
|
|
bool need_pmc_flush() const;
|
|
|
|
|
|
|
|
void on_pmc_flushed();
|
|
|
|
void on_info_flushed();
|
|
|
|
|
2018-02-20 00:29:19 +01:00
|
|
|
string suggested_name() const;
|
2018-02-19 23:28:06 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
private:
|
|
|
|
friend class FileView;
|
|
|
|
friend class FileManager;
|
|
|
|
|
|
|
|
LocalFileLocation local_;
|
|
|
|
FileLoadManager::QueryId upload_id_ = 0;
|
2018-11-11 12:38:04 +01:00
|
|
|
int64 download_offset_ = 0;
|
2019-02-18 20:08:05 +01:00
|
|
|
int64 download_limit_ = 0;
|
2018-12-27 16:37:57 +01:00
|
|
|
int64 local_ready_size_ = 0; // PartialLocal only
|
2018-12-26 17:11:15 +01:00
|
|
|
int64 local_ready_prefix_size_ = 0; // PartialLocal only
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2019-02-14 12:20:40 +01:00
|
|
|
NewRemoteFileLocation remote_;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
FileLoadManager::QueryId download_id_ = 0;
|
|
|
|
|
2018-02-04 18:27:05 +01:00
|
|
|
unique_ptr<FullGenerateFileLocation> generate_;
|
2018-12-31 20:04:05 +01:00
|
|
|
FileLoadManager::QueryId generate_id_ = 0;
|
|
|
|
|
|
|
|
int64 size_ = 0;
|
|
|
|
int64 expected_size_ = 0;
|
2018-02-18 17:29:44 +01:00
|
|
|
string remote_name_;
|
2018-01-20 11:49:06 +01:00
|
|
|
string url_;
|
2018-12-31 20:04:05 +01:00
|
|
|
DialogId owner_dialog_id_;
|
|
|
|
FileEncryptionKey encryption_key_;
|
2019-01-06 21:39:10 +01:00
|
|
|
FileDbId pmc_id_;
|
2018-12-31 20:04:05 +01:00
|
|
|
std::vector<FileId> file_ids_;
|
|
|
|
|
|
|
|
FileId main_file_id_;
|
2018-01-20 11:49:06 +01:00
|
|
|
|
2019-11-16 18:09:27 +01:00
|
|
|
double last_successful_force_reupload_time_ = -1e10;
|
|
|
|
|
2018-01-20 11:49:06 +01:00
|
|
|
FileId upload_pause_;
|
2018-01-20 12:47:53 +01:00
|
|
|
int8 upload_priority_ = 0;
|
|
|
|
int8 download_priority_ = 0;
|
|
|
|
int8 generate_priority_ = 0;
|
2018-01-20 11:49:06 +01:00
|
|
|
|
2018-01-20 12:47:53 +01:00
|
|
|
int8 generate_download_priority_ = 0;
|
|
|
|
int8 generate_upload_priority_ = 0;
|
2018-01-20 11:49:06 +01:00
|
|
|
|
|
|
|
int8 main_file_id_priority_ = 0;
|
|
|
|
|
2018-12-26 17:11:15 +01:00
|
|
|
bool is_download_offset_dirty_ = false;
|
2019-02-18 20:08:05 +01:00
|
|
|
bool is_download_limit_dirty_ = false;
|
2018-12-26 17:11:15 +01:00
|
|
|
|
2019-07-30 16:42:36 +02:00
|
|
|
bool get_by_hash_{false};
|
2018-02-26 11:05:14 +01:00
|
|
|
bool can_search_locally_{true};
|
2019-07-30 16:42:36 +02:00
|
|
|
bool need_reload_photo_{false};
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-01-20 11:49:06 +01:00
|
|
|
bool is_download_started_ = false;
|
|
|
|
bool generate_was_update_ = false;
|
|
|
|
|
|
|
|
bool need_load_from_pmc_ = false;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
bool pmc_changed_flag_{false};
|
|
|
|
bool info_changed_flag_{false};
|
2018-11-11 12:38:04 +01:00
|
|
|
|
2019-01-17 21:42:00 +01:00
|
|
|
bool upload_was_update_file_reference_{false};
|
|
|
|
bool download_was_update_file_reference_{false};
|
2018-12-09 08:05:26 +01:00
|
|
|
|
2018-11-11 12:38:04 +01:00
|
|
|
void init_ready_size();
|
2018-12-26 17:11:15 +01:00
|
|
|
|
|
|
|
void recalc_ready_prefix_size(int64 prefix_offset, int64 ready_prefix_size);
|
2018-12-31 20:04:05 +01:00
|
|
|
};
|
|
|
|
|
2018-01-30 17:54:17 +01:00
|
|
|
class FileManager;
|
2018-01-30 21:04:22 +01:00
|
|
|
|
|
|
|
class FileNodePtr {
|
|
|
|
public:
|
|
|
|
FileNodePtr() = default;
|
|
|
|
FileNodePtr(FileId file_id, FileManager *file_manager) : file_id_(file_id), file_manager_(file_manager) {
|
|
|
|
}
|
|
|
|
|
|
|
|
FileNode *operator->() const;
|
|
|
|
FileNode &operator*() const;
|
|
|
|
FileNode *get() const;
|
2018-03-06 19:31:20 +01:00
|
|
|
FullRemoteFileLocation *get_remote() const;
|
2018-01-30 22:36:53 +01:00
|
|
|
explicit operator bool() const;
|
2018-01-30 21:04:22 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
FileId file_id_;
|
|
|
|
FileManager *file_manager_ = nullptr;
|
|
|
|
FileNode *get_unsafe() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ConstFileNodePtr {
|
|
|
|
public:
|
|
|
|
ConstFileNodePtr() = default;
|
|
|
|
ConstFileNodePtr(FileNodePtr file_node_ptr) : file_node_ptr_(file_node_ptr) {
|
|
|
|
}
|
|
|
|
|
|
|
|
const FileNode *operator->() const {
|
|
|
|
return file_node_ptr_.operator->();
|
|
|
|
}
|
|
|
|
const FileNode &operator*() const {
|
|
|
|
return file_node_ptr_.operator*();
|
|
|
|
}
|
|
|
|
|
2018-01-30 22:36:53 +01:00
|
|
|
explicit operator bool() const {
|
2019-06-18 02:21:55 +02:00
|
|
|
return static_cast<bool>(file_node_ptr_);
|
2018-01-30 21:04:22 +01:00
|
|
|
}
|
2018-03-06 19:31:20 +01:00
|
|
|
const FullRemoteFileLocation *get_remote() const {
|
|
|
|
return file_node_ptr_.get_remote();
|
|
|
|
}
|
2018-01-30 21:04:22 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
FileNodePtr file_node_ptr_;
|
|
|
|
};
|
2018-01-30 17:54:17 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
class FileView {
|
|
|
|
public:
|
|
|
|
FileView() = default;
|
2018-01-30 17:54:17 +01:00
|
|
|
explicit FileView(ConstFileNodePtr node);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
bool empty() const;
|
|
|
|
|
|
|
|
bool has_local_location() const;
|
|
|
|
const FullLocalFileLocation &local_location() const;
|
|
|
|
bool has_remote_location() const;
|
2019-02-14 12:20:40 +01:00
|
|
|
bool has_alive_remote_location() const;
|
2019-01-30 17:08:50 +01:00
|
|
|
bool has_active_upload_remote_location() const;
|
|
|
|
bool has_active_download_remote_location() const;
|
2018-12-31 20:04:05 +01:00
|
|
|
const FullRemoteFileLocation &remote_location() const;
|
2019-11-17 20:41:28 +01:00
|
|
|
const FullRemoteFileLocation &main_remote_location() const;
|
2018-12-31 20:04:05 +01:00
|
|
|
bool has_generate_location() const;
|
|
|
|
const FullGenerateFileLocation &generate_location() const;
|
|
|
|
|
|
|
|
bool has_url() const;
|
|
|
|
const string &url() const;
|
|
|
|
|
2018-02-18 17:29:44 +01:00
|
|
|
const string &remote_name() const;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-02-20 00:29:19 +01:00
|
|
|
string suggested_name() const;
|
2018-02-19 23:28:06 +01:00
|
|
|
|
2018-01-20 11:49:06 +01:00
|
|
|
DialogId owner_dialog_id() const;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
bool get_by_hash() const;
|
|
|
|
|
|
|
|
FileId file_id() const {
|
|
|
|
return node_->main_file_id_;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64 size() const;
|
2018-12-27 09:34:36 +01:00
|
|
|
int64 expected_size(bool may_guess = false) const;
|
2018-12-31 20:04:05 +01:00
|
|
|
bool is_downloading() const;
|
2018-11-11 12:38:04 +01:00
|
|
|
int64 download_offset() const;
|
|
|
|
int64 downloaded_prefix(int64 offset) const;
|
2018-12-26 17:11:15 +01:00
|
|
|
int64 local_prefix_size() const;
|
2018-12-31 20:04:05 +01:00
|
|
|
int64 local_total_size() const;
|
|
|
|
bool is_uploading() const;
|
|
|
|
int64 remote_size() const;
|
|
|
|
string path() const;
|
|
|
|
|
2020-01-03 02:08:22 +01:00
|
|
|
int64 get_allocated_local_size() const;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
bool can_download_from_server() const;
|
|
|
|
bool can_generate() const;
|
|
|
|
bool can_delete() const;
|
|
|
|
|
|
|
|
FileType get_type() const {
|
|
|
|
if (has_local_location()) {
|
2018-01-20 15:57:52 +01:00
|
|
|
return local_location().file_type_;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
if (has_remote_location()) {
|
2018-01-20 15:57:52 +01:00
|
|
|
return remote_location().file_type_;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
if (has_generate_location()) {
|
2018-01-20 15:57:52 +01:00
|
|
|
return generate_location().file_type_;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
return FileType::Temp;
|
|
|
|
}
|
2018-03-27 15:11:15 +02:00
|
|
|
bool is_encrypted_secret() const {
|
2018-12-31 20:04:05 +01:00
|
|
|
return get_type() == FileType::Encrypted;
|
|
|
|
}
|
2018-03-27 15:11:15 +02:00
|
|
|
bool is_encrypted_secure() const {
|
|
|
|
return get_type() == FileType::Secure;
|
|
|
|
}
|
|
|
|
bool is_secure() const {
|
|
|
|
return get_type() == FileType::Secure || get_type() == FileType::SecureRaw;
|
|
|
|
}
|
|
|
|
bool is_encrypted_any() const {
|
|
|
|
return is_encrypted_secret() || is_encrypted_secure();
|
|
|
|
}
|
|
|
|
bool is_encrypted() const {
|
|
|
|
return is_encrypted_secret() || is_secure();
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
const FileEncryptionKey &encryption_key() const {
|
|
|
|
return node_->encryption_key_;
|
|
|
|
}
|
|
|
|
|
2019-07-30 17:43:29 +02:00
|
|
|
bool may_reload_photo() const {
|
2019-07-30 16:42:36 +02:00
|
|
|
if (!has_remote_location()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!remote_location().is_photo()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto type = remote_location().get_source().get_type();
|
|
|
|
return type == PhotoSizeSource::Type::DialogPhotoBig || type == PhotoSizeSource::Type::DialogPhotoSmall ||
|
|
|
|
type == PhotoSizeSource::Type::StickerSetThumbnail;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
private:
|
2018-01-30 17:54:17 +01:00
|
|
|
ConstFileNodePtr node_{};
|
2018-12-31 20:04:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
class FileManager : public FileLoadManager::Callback {
|
|
|
|
public:
|
|
|
|
class DownloadCallback {
|
|
|
|
public:
|
|
|
|
DownloadCallback() = default;
|
|
|
|
DownloadCallback(const DownloadCallback &) = delete;
|
|
|
|
DownloadCallback &operator=(const DownloadCallback &) = delete;
|
|
|
|
virtual ~DownloadCallback() = default;
|
|
|
|
virtual void on_progress(FileId file_id) {
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void on_download_ok(FileId file_id) = 0;
|
|
|
|
virtual void on_download_error(FileId file_id, Status error) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
class UploadCallback {
|
|
|
|
public:
|
|
|
|
UploadCallback() = default;
|
|
|
|
UploadCallback(const UploadCallback &) = delete;
|
|
|
|
UploadCallback &operator=(const UploadCallback &) = delete;
|
|
|
|
virtual ~UploadCallback() = default;
|
|
|
|
|
|
|
|
virtual void on_progress(FileId file_id) {
|
|
|
|
}
|
|
|
|
|
|
|
|
// After on_upload_ok all uploads of this file will be paused till merge, delete_partial_remote_location or
|
|
|
|
// explicit upload request with the same file_id.
|
|
|
|
// Also upload may be resumed after some other merges.
|
|
|
|
virtual void on_upload_ok(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file) = 0;
|
|
|
|
virtual void on_upload_encrypted_ok(FileId file_id, tl_object_ptr<telegram_api::InputEncryptedFile> input_file) = 0;
|
2018-03-27 15:11:15 +02:00
|
|
|
virtual void on_upload_secure_ok(FileId file_id, tl_object_ptr<telegram_api::InputSecureFile> input_file) = 0;
|
2018-12-31 20:04:05 +01:00
|
|
|
virtual void on_upload_error(FileId file_id, Status error) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Context {
|
|
|
|
public:
|
2020-02-19 15:57:30 +01:00
|
|
|
virtual void on_new_file(int64 size, int64 real_size, int32 cnt) = 0;
|
2019-01-30 22:37:38 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
virtual void on_file_updated(FileId size) = 0;
|
2019-01-30 22:37:38 +01:00
|
|
|
|
|
|
|
virtual bool add_file_source(FileId file_id, FileSourceId file_source_id) = 0;
|
|
|
|
|
|
|
|
virtual bool remove_file_source(FileId file_id, FileSourceId file_source_id) = 0;
|
|
|
|
|
|
|
|
virtual void on_merge_files(FileId to_file_id, FileId from_file_id) = 0;
|
|
|
|
|
|
|
|
virtual vector<FileSourceId> get_some_file_sources(FileId file_id) = 0;
|
|
|
|
|
|
|
|
virtual void repair_file_reference(FileId file_id, Promise<Unit> promise) = 0;
|
|
|
|
|
2019-07-30 16:42:36 +02:00
|
|
|
virtual void reload_photo(PhotoSizeSource source, Promise<Unit> promise) = 0;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
virtual ActorShared<> create_reference() = 0;
|
2019-01-30 22:37:38 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
Context() = default;
|
|
|
|
Context(const Context &) = delete;
|
|
|
|
Context &operator=(const Context &) = delete;
|
|
|
|
virtual ~Context() = default;
|
|
|
|
};
|
|
|
|
|
2018-09-27 03:19:03 +02:00
|
|
|
explicit FileManager(unique_ptr<Context> context);
|
2018-12-31 20:04:05 +01:00
|
|
|
FileManager(const FileManager &other) = delete;
|
|
|
|
FileManager &operator=(const FileManager &other) = delete;
|
|
|
|
FileManager(FileManager &&other) = delete;
|
|
|
|
FileManager &operator=(FileManager &&other) = delete;
|
|
|
|
~FileManager() override;
|
|
|
|
|
2019-03-15 19:52:54 +01:00
|
|
|
static bool are_modification_times_equal(int64 old_mtime, int64 new_mtime);
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
void init_actor();
|
|
|
|
|
|
|
|
FileId dup_file_id(FileId file_id);
|
|
|
|
|
|
|
|
void on_file_unlink(const FullLocalFileLocation &location);
|
|
|
|
|
|
|
|
FileId register_empty(FileType type);
|
|
|
|
Result<FileId> register_local(FullLocalFileLocation location, DialogId owner_dialog_id, int64 size,
|
2020-06-01 20:35:06 +02:00
|
|
|
bool get_by_hash = false, bool force = false,
|
|
|
|
bool skip_file_size_checks = false) TD_WARN_UNUSED_RESULT;
|
2018-01-26 13:56:19 +01:00
|
|
|
FileId register_remote(const FullRemoteFileLocation &location, FileLocationSource file_location_source,
|
2018-02-18 17:29:44 +01:00
|
|
|
DialogId owner_dialog_id, int64 size, int64 expected_size, string name) TD_WARN_UNUSED_RESULT;
|
2018-01-26 13:56:19 +01:00
|
|
|
Result<FileId> register_generate(FileType file_type, FileLocationSource file_location_source, string original_path,
|
|
|
|
string conversion, DialogId owner_dialog_id,
|
|
|
|
int64 expected_size) TD_WARN_UNUSED_RESULT;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
Result<FileId> merge(FileId x_file_id, FileId y_file_id, bool no_sync = false) TD_WARN_UNUSED_RESULT;
|
|
|
|
|
2018-12-05 10:32:31 +01:00
|
|
|
void add_file_source(FileId file_id, FileSourceId file_source_id);
|
|
|
|
|
|
|
|
void remove_file_source(FileId file_id, FileSourceId file_source_id);
|
|
|
|
|
2019-01-18 21:12:09 +01:00
|
|
|
void change_files_source(FileSourceId file_source_id, const vector<FileId> &old_file_ids,
|
|
|
|
const vector<FileId> &new_file_ids);
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
bool set_encryption_key(FileId file_id, FileEncryptionKey key);
|
|
|
|
bool set_content(FileId file_id, BufferSlice bytes);
|
|
|
|
|
2019-02-18 20:08:05 +01:00
|
|
|
void download(FileId file_id, std::shared_ptr<DownloadCallback> callback, int32 new_priority, int64 offset,
|
|
|
|
int64 limit);
|
2018-12-31 20:04:05 +01:00
|
|
|
void upload(FileId file_id, std::shared_ptr<UploadCallback> callback, int32 new_priority, uint64 upload_order);
|
|
|
|
void resume_upload(FileId file_id, std::vector<int> bad_parts, std::shared_ptr<UploadCallback> callback,
|
2019-02-14 12:20:40 +01:00
|
|
|
int32 new_priority, uint64 upload_order, bool force = false);
|
2019-01-25 02:52:38 +01:00
|
|
|
void cancel_upload(FileId file_id);
|
2018-12-31 20:04:05 +01:00
|
|
|
bool delete_partial_remote_location(FileId file_id);
|
2018-12-05 10:32:31 +01:00
|
|
|
void delete_file_reference(FileId file_id, std::string file_reference);
|
2018-12-31 20:04:05 +01:00
|
|
|
void get_content(FileId file_id, Promise<BufferSlice> promise);
|
|
|
|
|
2019-04-26 00:03:31 +02:00
|
|
|
void read_file_part(FileId file_id, int32 offset, int32 count, int left_tries,
|
|
|
|
Promise<td_api::object_ptr<td_api::filePart>> promise);
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
void delete_file(FileId file_id, Promise<Unit> promise, const char *source);
|
|
|
|
|
2019-04-26 02:18:00 +02:00
|
|
|
void external_file_generate_write_part(int64 id, int32 offset, string data, Promise<> promise);
|
2018-12-31 20:04:05 +01:00
|
|
|
void external_file_generate_progress(int64 id, int32 expected_size, int32 local_prefix_size, Promise<> promise);
|
|
|
|
void external_file_generate_finish(int64 id, Status status, Promise<> promise);
|
|
|
|
|
|
|
|
Result<FileId> from_persistent_id(CSlice persistent_id, FileType file_type) TD_WARN_UNUSED_RESULT;
|
|
|
|
FileView get_file_view(FileId file_id) const;
|
|
|
|
FileView get_sync_file_view(FileId file_id);
|
2019-01-21 18:19:02 +01:00
|
|
|
td_api::object_ptr<td_api::file> get_file_object(FileId file_id, bool with_main_file_id = true);
|
|
|
|
vector<int32> get_file_ids_object(const vector<FileId> &file_ids, bool with_main_file_id = true);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
Result<FileId> get_input_thumbnail_file_id(const tl_object_ptr<td_api::InputFile> &thumb_input_file,
|
|
|
|
DialogId owner_dialog_id, bool is_encrypted) TD_WARN_UNUSED_RESULT;
|
|
|
|
Result<FileId> get_input_file_id(FileType type, const tl_object_ptr<td_api::InputFile> &file,
|
|
|
|
DialogId owner_dialog_id, bool allow_zero, bool is_encrypted,
|
2018-04-03 19:49:07 +02:00
|
|
|
bool get_by_hash = false, bool is_secure = false) TD_WARN_UNUSED_RESULT;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-08-13 22:18:27 +02:00
|
|
|
Result<FileId> get_map_thumbnail_file_id(Location location, int32 zoom, int32 width, int32 height, int32 scale,
|
|
|
|
DialogId owner_dialog_id) TD_WARN_UNUSED_RESULT;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
vector<tl_object_ptr<telegram_api::InputDocument>> get_input_documents(const vector<FileId> &file_ids);
|
|
|
|
|
2019-01-25 02:38:11 +01:00
|
|
|
static bool extract_was_uploaded(const tl_object_ptr<telegram_api::InputMedia> &input_media);
|
|
|
|
static bool extract_was_thumbnail_uploaded(const tl_object_ptr<telegram_api::InputMedia> &input_media);
|
2019-01-25 04:01:09 +01:00
|
|
|
static string extract_file_reference(const tl_object_ptr<telegram_api::InputMedia> &input_media);
|
2019-01-25 02:38:11 +01:00
|
|
|
|
2019-01-29 00:32:26 +01:00
|
|
|
static string extract_file_reference(const tl_object_ptr<telegram_api::InputDocument> &input_document);
|
|
|
|
|
|
|
|
static string extract_file_reference(const tl_object_ptr<telegram_api::InputPhoto> &input_photo);
|
|
|
|
|
|
|
|
static bool extract_was_uploaded(const tl_object_ptr<telegram_api::InputChatPhoto> &input_chat_photo);
|
|
|
|
static string extract_file_reference(const tl_object_ptr<telegram_api::InputChatPhoto> &input_chat_photo);
|
|
|
|
|
2019-02-19 14:45:32 +01:00
|
|
|
template <class StorerT>
|
|
|
|
void store_file(FileId file_id, StorerT &storer, int32 ttl = 5) const;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2019-02-21 18:54:20 +01:00
|
|
|
template <class ParserT>
|
|
|
|
FileId parse_file(ParserT &parser);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
private:
|
2019-06-12 16:28:00 +02:00
|
|
|
static constexpr char PERSISTENT_ID_VERSION_OLD = 2;
|
2019-01-25 02:38:11 +01:00
|
|
|
static constexpr char PERSISTENT_ID_VERSION_MAP = 3;
|
2019-06-12 16:28:00 +02:00
|
|
|
static constexpr char PERSISTENT_ID_VERSION = 4;
|
2019-01-25 02:38:11 +01:00
|
|
|
|
2018-04-03 19:49:07 +02:00
|
|
|
Result<FileId> check_input_file_id(FileType type, Result<FileId> result, bool is_encrypted, bool allow_zero,
|
|
|
|
bool is_secure) TD_WARN_UNUSED_RESULT;
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-01-26 13:56:19 +01:00
|
|
|
FileId register_url(string url, FileType file_type, FileLocationSource file_location_source,
|
|
|
|
DialogId owner_dialog_id);
|
2020-06-01 20:35:06 +02:00
|
|
|
Result<FileId> register_file(FileData &&data, FileLocationSource file_location_source, const char *source, bool force,
|
|
|
|
bool skip_file_size_checks = false);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-01-20 12:47:53 +01:00
|
|
|
static constexpr int8 FROM_BYTES_PRIORITY = 10;
|
2019-12-23 15:32:03 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
using FileNodeId = int32;
|
2019-12-23 15:32:03 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
using QueryId = FileLoadManager::QueryId;
|
|
|
|
class Query {
|
|
|
|
public:
|
|
|
|
FileId file_id_;
|
2019-12-23 15:32:03 +01:00
|
|
|
enum class Type : int32 {
|
2018-12-09 08:05:26 +01:00
|
|
|
UploadByHash,
|
|
|
|
UploadWaitFileReference,
|
|
|
|
Upload,
|
2020-01-06 16:02:42 +01:00
|
|
|
DownloadWaitFileReference,
|
2019-07-30 16:42:36 +02:00
|
|
|
DownloadReloadDialog,
|
2018-12-09 08:05:26 +01:00
|
|
|
Download,
|
|
|
|
SetContent,
|
|
|
|
Generate
|
|
|
|
} type_;
|
2018-12-31 20:04:05 +01:00
|
|
|
};
|
2019-12-23 15:32:03 +01:00
|
|
|
|
|
|
|
friend StringBuilder &operator<<(StringBuilder &string_builder, Query::Type type);
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
struct FileIdInfo {
|
|
|
|
FileNodeId node_id_{0};
|
|
|
|
bool send_updates_flag_{false};
|
|
|
|
bool pin_flag_{false};
|
2019-01-21 18:19:02 +01:00
|
|
|
bool sent_file_id_flag_{false};
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-01-20 12:47:53 +01:00
|
|
|
int8 download_priority_{0};
|
|
|
|
int8 upload_priority_{0};
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
uint64 upload_order_;
|
2018-01-20 12:47:53 +01:00
|
|
|
|
|
|
|
std::shared_ptr<DownloadCallback> download_callback_;
|
2018-12-31 20:04:05 +01:00
|
|
|
std::shared_ptr<UploadCallback> upload_callback_;
|
|
|
|
};
|
|
|
|
|
2019-11-16 18:09:27 +01:00
|
|
|
class ForceUploadActor;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
ActorShared<> parent_;
|
2018-09-27 03:19:03 +02:00
|
|
|
unique_ptr<Context> context_;
|
2018-12-31 20:04:05 +01:00
|
|
|
std::shared_ptr<FileDbInterface> file_db_;
|
|
|
|
|
|
|
|
FileIdInfo *get_file_id_info(FileId file_id);
|
|
|
|
|
2018-03-06 19:31:20 +01:00
|
|
|
struct RemoteInfo {
|
2019-02-04 16:59:01 +01:00
|
|
|
// mutable is set to to enable changing of access hash
|
2018-03-07 08:47:33 +01:00
|
|
|
mutable FullRemoteFileLocation remote_;
|
2019-02-04 16:59:01 +01:00
|
|
|
mutable FileLocationSource file_location_source_;
|
2018-03-07 00:23:09 +01:00
|
|
|
FileId file_id_;
|
2018-03-06 19:31:20 +01:00
|
|
|
bool operator==(const RemoteInfo &other) const {
|
|
|
|
return this->remote_ == other.remote_;
|
|
|
|
}
|
|
|
|
bool operator<(const RemoteInfo &other) const {
|
|
|
|
return this->remote_ < other.remote_;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Enumerator<RemoteInfo> remote_location_info_;
|
|
|
|
|
2020-04-23 23:50:14 +02:00
|
|
|
std::unordered_map<string, FileId> file_hash_to_file_id_;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
std::map<FullLocalFileLocation, FileId> local_location_to_file_id_;
|
|
|
|
std::map<FullGenerateFileLocation, FileId> generate_location_to_file_id_;
|
|
|
|
std::map<FileDbId, int32> pmc_id_to_file_node_id_;
|
2018-03-06 19:31:20 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
vector<FileIdInfo> file_id_info_;
|
2018-03-07 00:37:39 +01:00
|
|
|
vector<int32> empty_file_ids_;
|
2018-09-27 03:19:03 +02:00
|
|
|
vector<unique_ptr<FileNode>> file_nodes_;
|
2018-12-31 20:04:05 +01:00
|
|
|
ActorOwn<FileLoadManager> file_load_manager_;
|
|
|
|
ActorOwn<FileGenerateManager> file_generate_manager_;
|
|
|
|
|
|
|
|
Container<Query> queries_container_;
|
|
|
|
|
2018-05-24 12:43:50 +02:00
|
|
|
bool is_closed_ = false;
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
std::set<std::string> bad_paths_;
|
|
|
|
|
|
|
|
FileId next_file_id();
|
|
|
|
FileNodeId next_file_node_id();
|
|
|
|
int32 next_pmc_file_id();
|
2018-01-30 21:04:22 +01:00
|
|
|
FileId create_file_id(int32 file_node_id, FileNode *file_node);
|
2018-12-31 20:04:05 +01:00
|
|
|
void try_forget_file_id(FileId file_id);
|
|
|
|
|
|
|
|
void load_from_pmc(FileId file_id, FullLocalFileLocation full_local);
|
|
|
|
void load_from_pmc(FileId file_id, const FullRemoteFileLocation &full_remote);
|
|
|
|
void load_from_pmc(FileId file_id, const FullGenerateFileLocation &full_generate);
|
|
|
|
template <class LocationT>
|
|
|
|
void load_from_pmc_impl(FileId file_id, const LocationT &location);
|
|
|
|
void load_from_pmc_result(FileId file_id, Result<FileData> &&result);
|
|
|
|
FileId register_pmc_file_data(FileData &&data);
|
|
|
|
|
2018-01-30 17:54:17 +01:00
|
|
|
Status check_local_location(FileNodePtr node);
|
2019-08-30 03:56:01 +02:00
|
|
|
bool try_fix_partial_local_location(FileNodePtr node);
|
2020-06-01 20:35:06 +02:00
|
|
|
Status check_local_location(FullLocalFileLocation &location, int64 &size, bool skip_file_size_checks);
|
2018-12-27 18:23:19 +01:00
|
|
|
void try_flush_node_full(FileNodePtr node, bool new_remote, bool new_local, bool new_generate, FileDbId other_pmc_id);
|
|
|
|
void try_flush_node(FileNodePtr node, const char *source);
|
|
|
|
void try_flush_node_info(FileNodePtr node, const char *source);
|
2019-01-30 17:40:23 +01:00
|
|
|
void try_flush_node_pmc(FileNodePtr node, const char *source);
|
2018-01-30 17:54:17 +01:00
|
|
|
void clear_from_pmc(FileNodePtr node);
|
2019-01-30 22:37:38 +01:00
|
|
|
void flush_to_pmc(FileNodePtr node, bool new_remote, bool new_local, bool new_generate, const char *source);
|
2018-01-30 21:04:22 +01:00
|
|
|
void load_from_pmc(FileNodePtr node, bool new_remote, bool new_local, bool new_generate);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2019-10-25 16:04:01 +02:00
|
|
|
string get_unique_id(const FullGenerateFileLocation &location);
|
|
|
|
string get_unique_id(const FullRemoteFileLocation &location);
|
|
|
|
|
2018-12-17 20:56:47 +01:00
|
|
|
string get_persistent_id(const FullGenerateFileLocation &location);
|
2018-12-31 20:04:05 +01:00
|
|
|
string get_persistent_id(const FullRemoteFileLocation &location);
|
|
|
|
|
2018-12-17 20:56:47 +01:00
|
|
|
Result<FileId> from_persistent_id_map(Slice binary, FileType file_type);
|
|
|
|
Result<FileId> from_persistent_id_v2(Slice binary, FileType file_type);
|
2019-06-12 16:28:00 +02:00
|
|
|
Result<FileId> from_persistent_id_v3(Slice binary, FileType file_type);
|
|
|
|
Result<FileId> from_persistent_id_v23(Slice binary, FileType file_type, int32 version);
|
2018-12-17 20:56:47 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
string fix_file_extension(Slice file_name, Slice file_type, Slice file_extension);
|
|
|
|
string get_file_name(FileType file_type, Slice path);
|
|
|
|
|
2018-01-30 21:04:22 +01:00
|
|
|
ConstFileNodePtr get_file_node(FileId file_id) const {
|
|
|
|
return ConstFileNodePtr{FileNodePtr{file_id, const_cast<FileManager *>(this)}};
|
|
|
|
}
|
|
|
|
FileNodePtr get_file_node(FileId file_id) {
|
|
|
|
return FileNodePtr{file_id, this};
|
|
|
|
}
|
|
|
|
FileNode *get_file_node_raw(FileId file_id, FileNodeId *file_node_id = nullptr);
|
|
|
|
|
|
|
|
FileNodePtr get_sync_file_node(FileId file_id);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2019-11-16 18:09:27 +01:00
|
|
|
void on_force_reupload_success(FileId file_id);
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
// void release_file_node(FileNodeId id);
|
2019-01-25 02:52:38 +01:00
|
|
|
void do_cancel_download(FileNodePtr node);
|
|
|
|
void do_cancel_upload(FileNodePtr node);
|
|
|
|
void do_cancel_generate(FileNodePtr node);
|
2018-01-30 17:54:17 +01:00
|
|
|
void run_upload(FileNodePtr node, std::vector<int> bad_parts);
|
|
|
|
void run_download(FileNodePtr node);
|
|
|
|
void run_generate(FileNodePtr node);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2018-01-09 12:57:11 +01:00
|
|
|
void on_start_download(QueryId query_id) override;
|
2018-12-26 22:42:26 +01:00
|
|
|
void on_partial_download(QueryId query_id, const PartialLocalFileLocation &partial_local, int64 ready_size,
|
|
|
|
int64 size) override;
|
2018-04-03 19:49:07 +02:00
|
|
|
void on_hash(QueryId query_id, string hash) override;
|
2018-12-31 20:04:05 +01:00
|
|
|
void on_partial_upload(QueryId query_id, const PartialRemoteFileLocation &partial_remote, int64 ready_size) override;
|
2019-01-11 18:08:56 +01:00
|
|
|
void on_download_ok(QueryId query_id, const FullLocalFileLocation &local, int64 size, bool is_new) override;
|
2018-12-31 20:04:05 +01:00
|
|
|
void on_upload_ok(QueryId query_id, FileType file_type, const PartialRemoteFileLocation &partial_remote,
|
|
|
|
int64 size) override;
|
|
|
|
void on_upload_full_ok(QueryId query_id, const FullRemoteFileLocation &remote) override;
|
|
|
|
void on_error(QueryId query_id, Status status) override;
|
|
|
|
|
2018-01-30 17:54:17 +01:00
|
|
|
void on_error_impl(FileNodePtr node, Query::Type type, bool was_active, Status status);
|
2018-12-31 20:04:05 +01:00
|
|
|
|
|
|
|
void on_partial_generate(QueryId, const PartialLocalFileLocation &partial_local, int32 expected_size);
|
|
|
|
void on_generate_ok(QueryId, const FullLocalFileLocation &local);
|
|
|
|
|
|
|
|
std::pair<Query, bool> finish_query(QueryId query_id);
|
|
|
|
|
2018-03-06 19:31:20 +01:00
|
|
|
FullRemoteFileLocation *get_remote(int32 key);
|
|
|
|
|
2019-01-18 21:12:09 +01:00
|
|
|
std::unordered_set<FileId, FileIdHash> get_main_file_ids(const vector<FileId> &file_ids);
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
void hangup() override;
|
|
|
|
void tear_down() override;
|
2018-01-30 21:04:22 +01:00
|
|
|
|
|
|
|
friend class FileNodePtr;
|
2018-12-31 20:04:05 +01:00
|
|
|
};
|
2018-12-26 17:11:15 +01:00
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
} // namespace td
|