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)
//
# include "td/telegram/files/FileManager.h"
2019-01-06 21:47:40 +01:00
2018-12-31 20:04:05 +01:00
# include "td/telegram/telegram_api.h"
2018-06-24 22:48:48 +02:00
# include "td/telegram/ConfigShared.h"
2019-01-31 03:05:40 +01:00
# include "td/telegram/FileReferenceManager.h"
2019-01-19 22:26:23 +01:00
# include "td/telegram/files/FileData.h"
2019-01-06 21:47:40 +01:00
# include "td/telegram/files/FileDb.h"
2018-12-31 20:04:05 +01:00
# include "td/telegram/files/FileLoaderUtils.h"
# include "td/telegram/files/FileLocation.h"
2019-02-12 18:48:13 +01:00
# include "td/telegram/files/FileLocation.hpp"
2018-12-31 20:04:05 +01:00
# include "td/telegram/Global.h"
2019-06-12 13:42:06 +02:00
# include "td/telegram/logevent/LogEvent.h"
2018-12-31 20:04:05 +01:00
# include "td/telegram/misc.h"
2018-12-27 19:38:43 +01:00
# include "td/telegram/SecureStorage.h"
2019-01-06 20:59:17 +01:00
# include "td/telegram/TdDb.h"
2019-06-12 15:05:22 +02:00
# include "td/telegram/Version.h"
2018-12-31 20:04:05 +01:00
2019-04-26 00:03:31 +02:00
# include "td/actor/SleepActor.h"
2018-12-31 20:04:05 +01:00
# include "td/utils/base64.h"
2020-04-30 21:21:42 +02:00
# include "td/utils/crypto.h"
2020-04-23 23:50:14 +02:00
# include "td/utils/filesystem.h"
2018-12-31 20:04:05 +01:00
# include "td/utils/format.h"
# include "td/utils/HttpUrl.h"
# include "td/utils/logging.h"
# include "td/utils/misc.h"
# include "td/utils/PathView.h"
# include "td/utils/port/FileFd.h"
# include "td/utils/port/path.h"
# include "td/utils/port/Stat.h"
# include "td/utils/ScopeGuard.h"
2019-02-15 21:09:18 +01:00
# include "td/utils/StringBuilder.h"
2019-11-26 19:57:48 +01:00
# include "td/utils/Time.h"
2018-12-31 20:04:05 +01:00
# include "td/utils/tl_helpers.h"
2019-06-12 15:05:22 +02:00
# include "td/utils/tl_parsers.h"
2018-12-31 20:04:05 +01:00
# include <algorithm>
2018-08-13 22:18:27 +02:00
# include <cmath>
2018-12-31 20:04:05 +01:00
# include <limits>
2019-12-24 16:51:41 +01:00
# include <numeric>
2018-12-31 20:04:05 +01:00
# include <tuple>
2020-06-22 07:43:00 +02:00
# include <unordered_set>
2018-12-31 20:04:05 +01:00
# include <utility>
2020-08-02 00:28:01 +02:00
# define FILE_TTL 120
2020-05-23 21:27:24 +02:00
2018-12-31 20:04:05 +01:00
namespace td {
2018-11-11 12:38:04 +01:00
namespace {
2020-07-03 16:31:06 +02:00
constexpr int64 MAX_FILE_SIZE = 2000 * ( 1 < < 20 ) /* 2000MB */ ;
2018-12-27 20:24:44 +01:00
} // namespace
2018-12-31 20:04:05 +01:00
2019-12-23 15:32:03 +01:00
int VERBOSITY_NAME ( update_file ) = VERBOSITY_NAME ( INFO ) ;
2019-02-15 21:09:18 +01:00
StringBuilder & operator < < ( StringBuilder & string_builder , FileLocationSource source ) {
switch ( source ) {
case FileLocationSource : : None :
return string_builder < < " None " ;
case FileLocationSource : : FromUser :
return string_builder < < " User " ;
2019-02-15 21:22:40 +01:00
case FileLocationSource : : FromBinlog :
return string_builder < < " Binlog " ;
2019-02-15 21:09:18 +01:00
case FileLocationSource : : FromDatabase :
return string_builder < < " Database " ;
case FileLocationSource : : FromServer :
return string_builder < < " Server " ;
default :
UNREACHABLE ( ) ;
return string_builder < < " Unknown " ;
}
}
2019-12-23 15:32:03 +01:00
StringBuilder & operator < < ( StringBuilder & string_builder , FileManager : : Query : : 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 " ;
2020-01-06 16:02:42 +01:00
case FileManager : : Query : : Type : : DownloadWaitFileReference :
return string_builder < < " DownloadWaitFileReference " ;
2019-12-23 15:32:03 +01:00
case FileManager : : Query : : Type : : DownloadReloadDialog :
return string_builder < < " DownloadReloadDialog " ;
case FileManager : : Query : : Type : : Download :
return string_builder < < " Download " ;
case FileManager : : Query : : Type : : SetContent :
return string_builder < < " SetContent " ;
case FileManager : : Query : : Type : : Generate :
return string_builder < < " Generate " ;
default :
UNREACHABLE ( ) ;
return string_builder < < " Unknown " ;
}
}
2019-02-14 12:20:40 +01:00
NewRemoteFileLocation : : NewRemoteFileLocation ( RemoteFileLocation remote , FileLocationSource source ) {
switch ( remote . type ( ) ) {
2019-02-14 22:19:48 +01:00
case RemoteFileLocation : : Type : : Empty :
break ;
case RemoteFileLocation : : Type : : Partial :
2019-02-14 12:20:40 +01:00
partial = make_unique < PartialRemoteFileLocation > ( remote . partial ( ) ) ;
2019-02-14 22:19:48 +01:00
break ;
case RemoteFileLocation : : Type : : Full :
2019-02-14 12:20:40 +01:00
full = remote . full ( ) ;
full_source = source ;
is_full_alive = true ;
2019-02-14 22:19:48 +01:00
break ;
default :
UNREACHABLE ( ) ;
2019-02-14 12:20:40 +01:00
}
}
RemoteFileLocation NewRemoteFileLocation : : partial_or_empty ( ) const {
if ( partial ) {
return RemoteFileLocation ( * partial ) ;
}
return { } ;
}
2018-01-30 21:04:22 +01:00
FileNode * FileNodePtr : : operator - > ( ) const {
return get ( ) ;
}
2018-02-19 23:28:06 +01:00
2018-01-30 21:04:22 +01:00
FileNode & FileNodePtr : : operator * ( ) const {
return * get ( ) ;
}
2018-02-19 23:28:06 +01:00
2018-01-30 21:04:22 +01:00
FileNode * FileNodePtr : : get ( ) const {
auto res = get_unsafe ( ) ;
2020-05-23 21:27:24 +02:00
if ( res = = nullptr ) {
return { } ;
}
2018-01-30 21:04:22 +01:00
return res ;
}
2018-02-19 23:28:06 +01:00
2018-03-06 19:31:20 +01:00
FullRemoteFileLocation * FileNodePtr : : get_remote ( ) const {
return file_manager_ - > get_remote ( file_id_ . get_remote ( ) ) ;
}
2018-01-30 21:04:22 +01:00
FileNode * FileNodePtr : : get_unsafe ( ) const {
2020-05-23 21:27:24 +02:00
if ( file_manager_ = = nullptr ) {
return { } ;
}
2018-01-30 21:04:22 +01:00
return file_manager_ - > get_file_node_raw ( file_id_ ) ;
}
2018-02-19 23:28:06 +01:00
2018-01-30 21:04:22 +01:00
FileNodePtr : : operator bool ( ) const {
return file_manager_ ! = nullptr & & get_unsafe ( ) ! = nullptr ;
}
2018-12-31 20:04:05 +01:00
2018-12-26 17:11:15 +01:00
void FileNode : : recalc_ready_prefix_size ( int64 prefix_offset , int64 ready_prefix_size ) {
2018-11-11 12:38:04 +01:00
if ( local_ . type ( ) ! = LocalFileLocation : : Type : : Partial ) {
return ;
}
int64 new_local_ready_prefix_size ;
2018-12-26 17:11:15 +01:00
if ( download_offset_ = = prefix_offset ) {
new_local_ready_prefix_size = ready_prefix_size ;
2018-11-11 12:38:04 +01:00
} else {
new_local_ready_prefix_size = Bitmask ( Bitmask : : Decode { } , local_ . partial ( ) . ready_bitmask_ )
2018-12-26 17:11:15 +01:00
. get_ready_prefix_size ( download_offset_ , local_ . partial ( ) . part_size_ , size_ ) ;
2018-11-11 12:38:04 +01:00
}
if ( new_local_ready_prefix_size ! = local_ready_prefix_size_ ) {
2018-12-27 01:56:03 +01:00
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed local_ready_prefix_size from "
< < local_ready_prefix_size_ < < " to " < < new_local_ready_prefix_size ;
2018-11-11 12:38:04 +01:00
local_ready_prefix_size_ = new_local_ready_prefix_size ;
on_info_changed ( ) ;
}
}
void FileNode : : init_ready_size ( ) {
if ( local_ . type ( ) ! = LocalFileLocation : : Type : : Partial ) {
return ;
}
auto bitmask = Bitmask ( Bitmask : : Decode { } , local_ . partial ( ) . ready_bitmask_ ) ;
2018-12-26 17:11:15 +01:00
local_ready_prefix_size_ = bitmask . get_ready_prefix_size ( 0 , local_ . partial ( ) . part_size_ , size_ ) ;
2018-12-27 09:34:36 +01:00
local_ready_size_ = bitmask . get_total_size ( local_ . partial ( ) . part_size_ , size_ ) ;
2018-11-11 12:38:04 +01:00
}
void FileNode : : set_download_offset ( int64 download_offset ) {
if ( download_offset < 0 | | download_offset > MAX_FILE_SIZE ) {
return ;
}
if ( download_offset = = download_offset_ ) {
return ;
}
2018-12-27 01:56:03 +01:00
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed download_offset from " < < download_offset_ < < " to "
< < download_offset ;
2018-11-11 12:38:04 +01:00
download_offset_ = download_offset ;
is_download_offset_dirty_ = true ;
2018-12-26 17:11:15 +01:00
recalc_ready_prefix_size ( - 1 , - 1 ) ;
2018-11-11 12:38:04 +01:00
on_info_changed ( ) ;
}
2019-02-18 20:08:05 +01:00
void FileNode : : set_download_limit ( int64 download_limit ) {
if ( download_limit < 0 ) {
return ;
}
if ( download_limit = = download_limit_ ) {
return ;
}
2019-02-26 22:42:54 +01:00
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed download_limit from " < < download_limit_ < < " to "
< < download_limit ;
2019-02-18 20:08:05 +01:00
download_limit_ = download_limit ;
2019-02-26 22:42:54 +01:00
is_download_limit_dirty_ = true ;
2019-02-18 20:08:05 +01:00
}
2018-11-11 12:38:04 +01:00
2018-12-26 17:11:15 +01:00
void FileNode : : drop_local_location ( ) {
set_local_location ( LocalFileLocation ( ) , 0 , - 1 , - 1 ) ;
}
void FileNode : : set_local_location ( const LocalFileLocation & local , int64 ready_size , int64 prefix_offset ,
int64 ready_prefix_size ) {
2018-12-31 20:04:05 +01:00
if ( local_ready_size_ ! = ready_size ) {
2018-12-26 17:11:15 +01:00
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed local ready size from " < < local_ready_size_
< < " to " < < ready_size ;
2018-12-31 20:04:05 +01:00
local_ready_size_ = ready_size ;
on_info_changed ( ) ;
}
if ( local_ ! = local ) {
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed local location " ;
local_ = local ;
2018-11-11 12:38:04 +01:00
2018-12-26 17:11:15 +01:00
recalc_ready_prefix_size ( prefix_offset , ready_prefix_size ) ;
2018-11-11 12:38:04 +01:00
2018-12-31 20:04:05 +01:00
on_changed ( ) ;
}
}
2019-02-14 12:20:40 +01:00
void FileNode : : set_new_remote_location ( NewRemoteFileLocation new_remote ) {
if ( new_remote . full ) {
if ( remote_ . full & & remote_ . full . value ( ) = = new_remote . full . value ( ) ) {
2019-02-14 22:19:48 +01:00
if ( remote_ . full . value ( ) . get_access_hash ( ) ! = new_remote . full . value ( ) . get_access_hash ( ) | |
2019-06-18 17:40:46 +02:00
remote_ . full . value ( ) . get_file_reference ( ) ! = new_remote . full . value ( ) . get_file_reference ( ) | |
remote_ . full . value ( ) . get_source ( ) ! = new_remote . full . value ( ) . get_source ( ) ) {
2019-01-24 20:52:24 +01:00
on_pmc_changed ( ) ;
2018-12-31 20:04:05 +01:00
}
2019-02-14 12:20:40 +01:00
} else {
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed remote location " ;
on_changed ( ) ;
}
remote_ . full = new_remote . full ;
2019-02-15 20:40:09 +01:00
remote_ . full_source = new_remote . full_source ;
2019-02-14 12:20:40 +01:00
remote_ . is_full_alive = new_remote . is_full_alive ;
} else {
if ( remote_ . full ) {
2019-02-14 22:19:48 +01:00
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has lost remote location " ;
2019-02-14 12:20:40 +01:00
remote_ . full = { } ;
remote_ . is_full_alive = false ;
2019-02-15 20:40:09 +01:00
remote_ . full_source = FileLocationSource : : None ;
2019-02-14 12:20:40 +01:00
on_changed ( ) ;
2018-12-31 20:04:05 +01:00
}
}
2019-02-14 12:20:40 +01:00
if ( new_remote . partial ) {
set_partial_remote_location ( * new_remote . partial , new_remote . ready_size ) ;
} else {
delete_partial_remote_location ( ) ;
}
}
void FileNode : : delete_partial_remote_location ( ) {
if ( remote_ . partial ) {
2019-02-14 22:19:48 +01:00
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has lost partial remote location " ;
2019-02-14 12:20:40 +01:00
remote_ . partial . reset ( ) ;
on_changed ( ) ;
}
}
2019-02-14 22:19:48 +01:00
2019-02-14 12:20:40 +01:00
void FileNode : : set_partial_remote_location ( const PartialRemoteFileLocation & remote , int64 ready_size ) {
if ( remote_ . is_full_alive ) {
2019-02-14 22:19:48 +01:00
VLOG ( update_file ) < < " File " < < main_file_id_ < < " remote is still alive, so there is NO reason to update partial " ;
2019-02-14 12:20:40 +01:00
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 ) {
2019-02-14 22:19:48 +01:00
VLOG ( update_file ) < < " Partial location of " < < main_file_id_ < < " is NOT changed " ;
2019-02-14 12:20:40 +01:00
return ;
}
2019-02-14 22:19:48 +01:00
if ( ! remote_ . partial & & remote . ready_part_count_ = = 0 ) {
// empty partial remote is equal to empty remote
VLOG ( update_file ) < < " Partial location of " < < main_file_id_
< < " is still empty, so there is NO reason to update it " ;
return ;
}
VLOG ( update_file ) < < " File " < < main_file_id_ < < " partial location has changed to " < < remote ;
2019-02-14 12:20:40 +01:00
remote_ . partial = make_unique < PartialRemoteFileLocation > ( remote ) ;
2018-12-31 20:04:05 +01:00
on_changed ( ) ;
}
2020-08-02 00:28:01 +02:00
bool FileNode : : delete_file_reference_internal ( Slice file_reference ) {
2019-02-14 12:20:40 +01:00
if ( ! remote_ . full ) {
2019-01-31 13:24:32 +01:00
VLOG ( file_references ) < < " Can't delete file reference, because there is no remote location " ;
2019-01-31 00:57:14 +01:00
return false ;
}
2019-02-14 12:20:40 +01:00
if ( ! remote_ . full . value ( ) . delete_file_reference ( file_reference ) ) {
2019-01-31 13:24:32 +01:00
VLOG ( file_references ) < < " Can't delete unmatching file reference " < < format : : escaped ( file_reference ) < < " , have "
2019-06-17 04:37:57 +02:00
< < format : : escaped ( remote_ . full . value ( ) . get_file_reference ( ) ) ;
2019-01-31 09:33:35 +01:00
return false ;
2018-12-05 10:32:31 +01:00
}
2019-01-31 09:33:35 +01:00
VLOG ( file_references ) < < " Do delete file reference of main file " < < main_file_id_ ;
upload_was_update_file_reference_ = false ;
download_was_update_file_reference_ = false ;
on_pmc_changed ( ) ;
return true ;
2018-12-05 10:32:31 +01:00
}
2018-02-04 18:27:05 +01:00
void FileNode : : set_generate_location ( unique_ptr < FullGenerateFileLocation > & & generate ) {
bool is_changed = generate_ = = nullptr ? generate ! = nullptr : generate = = nullptr | | * generate_ ! = * generate ;
if ( is_changed ) {
generate_ = std : : move ( generate ) ;
2018-12-31 20:04:05 +01:00
on_pmc_changed ( ) ;
}
}
void FileNode : : set_size ( int64 size ) {
if ( size_ ! = size ) {
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed size to " < < size ;
size_ = size ;
on_changed ( ) ;
}
}
void FileNode : : set_expected_size ( int64 expected_size ) {
if ( expected_size_ ! = expected_size ) {
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed expected size to " < < expected_size ;
expected_size_ = expected_size ;
on_changed ( ) ;
}
}
2018-02-18 17:29:44 +01:00
void FileNode : : set_remote_name ( string remote_name ) {
if ( remote_name_ ! = remote_name ) {
remote_name_ = std : : move ( remote_name ) ;
2018-12-31 20:04:05 +01:00
on_pmc_changed ( ) ;
}
}
void FileNode : : set_url ( string url ) {
if ( url_ ! = url ) {
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed URL to " < < url ;
url_ = std : : move ( url ) ;
on_changed ( ) ;
}
}
void FileNode : : set_owner_dialog_id ( DialogId owner_id ) {
if ( owner_dialog_id_ ! = owner_id ) {
owner_dialog_id_ = owner_id ;
on_pmc_changed ( ) ;
}
}
void FileNode : : set_encryption_key ( FileEncryptionKey key ) {
if ( encryption_key_ ! = key ) {
encryption_key_ = std : : move ( key ) ;
on_pmc_changed ( ) ;
}
}
2019-01-10 22:12:51 +01:00
void FileNode : : set_upload_pause ( FileId upload_pause ) {
if ( upload_pause_ ! = upload_pause ) {
LOG ( INFO ) < < " Change file " < < main_file_id_ < < " upload_pause from " < < upload_pause_ < < " to " < < upload_pause ;
upload_pause_ = upload_pause ;
}
}
2018-01-20 12:47:53 +01:00
void FileNode : : set_download_priority ( int8 priority ) {
2018-12-31 20:04:05 +01:00
if ( ( download_priority_ = = 0 ) ! = ( priority = = 0 ) ) {
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed download priority to " < < priority ;
on_info_changed ( ) ;
}
download_priority_ = priority ;
}
2018-01-20 12:47:53 +01:00
void FileNode : : set_upload_priority ( int8 priority ) {
2019-02-14 12:20:40 +01:00
if ( ! remote_ . is_full_alive & & ( upload_priority_ = = 0 ) ! = ( priority = = 0 ) ) {
2018-12-31 20:04:05 +01:00
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed upload priority to " < < priority ;
on_info_changed ( ) ;
}
upload_priority_ = priority ;
}
2018-01-20 12:47:53 +01:00
void FileNode : : set_generate_priority ( int8 download_priority , int8 upload_priority ) {
2018-08-13 22:18:27 +02:00
if ( ( generate_download_priority_ = = 0 ) ! = ( download_priority = = 0 ) | |
( generate_upload_priority_ = = 0 ) ! = ( upload_priority = = 0 ) ) {
2018-12-31 20:04:05 +01:00
VLOG ( update_file ) < < " File " < < main_file_id_ < < " has changed generate priority to " < < download_priority < < " / "
< < upload_priority ;
on_info_changed ( ) ;
}
2018-02-12 11:37:54 +01:00
generate_priority_ = max ( download_priority , upload_priority ) ;
2018-12-31 20:04:05 +01:00
generate_download_priority_ = download_priority ;
generate_upload_priority_ = upload_priority ;
}
void FileNode : : on_changed ( ) {
on_pmc_changed ( ) ;
on_info_changed ( ) ;
}
2019-02-14 22:19:48 +01:00
2018-12-31 20:04:05 +01:00
void FileNode : : on_info_changed ( ) {
info_changed_flag_ = true ;
}
2019-02-14 22:19:48 +01:00
2018-12-31 20:04:05 +01:00
void FileNode : : on_pmc_changed ( ) {
pmc_changed_flag_ = true ;
}
bool FileNode : : need_info_flush ( ) const {
return info_changed_flag_ ;
}
bool FileNode : : need_pmc_flush ( ) const {
if ( ! pmc_changed_flag_ ) {
return false ;
}
// already in pmc
2019-01-06 21:39:10 +01:00
if ( pmc_id_ . is_valid ( ) ) {
2018-12-31 20:04:05 +01:00
return true ;
}
// We must save encryption key
if ( ! encryption_key_ . empty ( ) ) {
2018-01-20 15:57:52 +01:00
// && remote_.type() != RemoteFileLocation::Type::Empty
2018-12-31 20:04:05 +01:00
return true ;
}
2018-02-04 18:27:05 +01:00
bool has_generate_location = generate_ ! = nullptr ;
2018-12-31 20:04:05 +01:00
// Do not save "#file_id#" conversion.
2018-02-04 18:27:05 +01:00
if ( has_generate_location & & begins_with ( generate_ - > conversion_ , " #file_id# " ) ) {
2018-12-31 20:04:05 +01:00
has_generate_location = false ;
}
2019-02-14 12:20:40 +01:00
if ( remote_ . full /* &&
2019-01-30 22:37:38 +01:00
( has_generate_location | | local_ . type ( ) ! = LocalFileLocation : : Type : : Empty ) */ ) {
// we need to always save file sources
2018-12-31 20:04:05 +01:00
return true ;
}
2019-02-14 12:20:40 +01:00
if ( local_ . type ( ) = = LocalFileLocation : : Type : : Full & & ( has_generate_location | | remote_ . full | | remote_ . partial ) ) {
2018-12-31 20:04:05 +01:00
return true ;
}
// TODO: Generate location with constant conversion
return false ;
}
void FileNode : : on_pmc_flushed ( ) {
pmc_changed_flag_ = false ;
}
void FileNode : : on_info_flushed ( ) {
info_changed_flag_ = false ;
}
2018-02-20 00:29:19 +01:00
string FileNode : : suggested_name ( ) const {
2018-02-19 23:28:06 +01:00
if ( ! remote_name_ . empty ( ) ) {
return remote_name_ ;
}
if ( ! url_ . empty ( ) ) {
2018-02-20 00:29:19 +01:00
auto file_name = get_url_file_name ( url_ ) ;
if ( ! file_name . empty ( ) ) {
return file_name ;
}
2018-02-19 23:28:06 +01:00
}
if ( generate_ ! = nullptr ) {
2018-02-20 00:29:19 +01:00
if ( ! generate_ - > original_path_ . empty ( ) ) {
return generate_ - > original_path_ ;
2018-02-19 23:28:06 +01:00
}
}
2018-02-20 00:29:19 +01:00
return local_ . file_name ( ) . str ( ) ;
2018-02-19 23:28:06 +01:00
}
2018-12-31 20:04:05 +01:00
/*** FileView ***/
bool FileView : : has_local_location ( ) const {
2018-01-20 15:57:52 +01:00
return node_ - > local_ . type ( ) = = LocalFileLocation : : Type : : Full ;
2018-12-31 20:04:05 +01:00
}
2019-01-05 16:13:27 +01:00
2018-12-31 20:04:05 +01:00
const FullLocalFileLocation & FileView : : local_location ( ) const {
CHECK ( has_local_location ( ) ) ;
return node_ - > local_ . full ( ) ;
}
2019-01-05 16:13:27 +01:00
2018-12-31 20:04:05 +01:00
bool FileView : : has_remote_location ( ) const {
2019-06-18 02:21:55 +02:00
return static_cast < bool > ( node_ - > remote_ . full ) ;
2019-02-14 12:20:40 +01:00
}
2019-10-09 01:59:25 +02:00
2019-02-14 12:20:40 +01:00
bool FileView : : has_alive_remote_location ( ) const {
return node_ - > remote_ . is_full_alive ;
2018-12-31 20:04:05 +01:00
}
2019-01-05 16:13:27 +01:00
2019-01-30 17:08:50 +01:00
bool FileView : : has_active_upload_remote_location ( ) const {
2019-11-17 20:41:28 +01:00
if ( ! has_remote_location ( ) ) {
return false ;
}
2019-02-14 12:20:40 +01:00
if ( ! has_alive_remote_location ( ) ) {
2018-12-05 10:32:31 +01:00
return false ;
}
2019-11-17 20:41:28 +01:00
if ( main_remote_location ( ) . is_encrypted_any ( ) ) {
2018-12-05 10:32:31 +01:00
return true ;
}
2019-11-17 20:41:28 +01:00
return main_remote_location ( ) . has_file_reference ( ) ;
2019-01-30 17:08:50 +01:00
}
bool FileView : : has_active_download_remote_location ( ) const {
if ( ! has_remote_location ( ) ) {
return false ;
}
if ( remote_location ( ) . is_encrypted_any ( ) ) {
return true ;
}
2019-06-17 04:37:57 +02:00
return remote_location ( ) . has_file_reference ( ) ;
2018-12-05 10:32:31 +01:00
}
2019-01-05 16:13:27 +01:00
2018-12-31 20:04:05 +01:00
const FullRemoteFileLocation & FileView : : remote_location ( ) const {
CHECK ( has_remote_location ( ) ) ;
2018-03-06 19:31:20 +01:00
auto * remote = node_ . get_remote ( ) ;
if ( remote ) {
return * remote ;
}
2019-02-14 12:20:40 +01:00
return node_ - > remote_ . full . value ( ) ;
2018-12-31 20:04:05 +01:00
}
2019-01-05 16:13:27 +01:00
2019-11-17 20:41:28 +01:00
const FullRemoteFileLocation & FileView : : main_remote_location ( ) const {
CHECK ( has_remote_location ( ) ) ;
return node_ - > remote_ . full . value ( ) ;
}
2018-12-31 20:04:05 +01:00
bool FileView : : has_generate_location ( ) const {
2018-02-04 18:27:05 +01:00
return node_ - > generate_ ! = nullptr ;
2018-12-31 20:04:05 +01:00
}
2019-01-05 16:13:27 +01:00
2018-12-31 20:04:05 +01:00
const FullGenerateFileLocation & FileView : : generate_location ( ) const {
CHECK ( has_generate_location ( ) ) ;
2018-02-04 18:27:05 +01:00
return * node_ - > generate_ ;
2018-12-31 20:04:05 +01:00
}
int64 FileView : : size ( ) const {
return node_ - > size_ ;
}
2020-01-03 02:08:22 +01:00
int64 FileView : : get_allocated_local_size ( ) const {
auto file_path = path ( ) ;
if ( file_path . empty ( ) ) {
return 0 ;
}
auto r_stat = stat ( file_path ) ;
if ( r_stat . is_error ( ) ) {
return 0 ;
}
return r_stat . ok ( ) . real_size_ ;
}
2018-12-27 09:34:36 +01:00
int64 FileView : : expected_size ( bool may_guess ) const {
2018-12-31 20:04:05 +01:00
if ( node_ - > size_ ! = 0 ) {
return node_ - > size_ ;
}
2018-12-27 09:34:36 +01:00
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 ( may_guess & & node_ - > local_ . type ( ) = = LocalFileLocation : : Type : : Partial ) {
current_size * = 3 ;
}
return current_size ;
2018-12-31 20:04:05 +01:00
}
bool FileView : : is_downloading ( ) const {
return node_ - > download_priority_ ! = 0 | | node_ - > generate_download_priority_ ! = 0 ;
}
2018-11-11 12:38:04 +01:00
int64 FileView : : download_offset ( ) const {
return node_ - > download_offset_ ;
}
2018-12-27 02:21:08 +01:00
2018-11-11 12:38:04 +01:00
int64 FileView : : downloaded_prefix ( int64 offset ) const {
switch ( node_ - > local_ . type ( ) ) {
case LocalFileLocation : : Type : : Empty :
return 0 ;
case LocalFileLocation : : Type : : Full :
if ( offset < node_ - > size_ ) {
return node_ - > size_ - offset ;
}
return 0 ;
case LocalFileLocation : : Type : : Partial :
2018-12-26 17:11:15 +01:00
if ( is_encrypted_secure ( ) ) {
// File is not decrypted and verified yet
return 0 ;
}
2018-11-11 12:38:04 +01:00
return Bitmask ( Bitmask : : Decode { } , node_ - > local_ . partial ( ) . ready_bitmask_ )
2018-12-26 17:11:15 +01:00
. get_ready_prefix_size ( offset , node_ - > local_ . partial ( ) . part_size_ , node_ - > size_ ) ;
2018-11-11 12:38:04 +01:00
default :
UNREACHABLE ( ) ;
return 0 ;
}
}
2018-12-26 17:11:15 +01:00
int64 FileView : : local_prefix_size ( ) const {
2018-01-20 15:57:52 +01:00
switch ( node_ - > local_ . type ( ) ) {
2018-12-31 20:04:05 +01:00
case LocalFileLocation : : Type : : Full :
2018-12-26 17:11:15 +01:00
return node_ - > download_offset_ < = node_ - > size_ ? node_ - > size_ - node_ - > download_offset_ : 0 ;
2018-04-03 19:49:07 +02:00
case LocalFileLocation : : Type : : Partial : {
if ( is_encrypted_secure ( ) ) {
2018-12-26 17:11:15 +01:00
// File is not decrypted and verified yet
2018-04-03 19:49:07 +02:00
return 0 ;
}
2018-11-11 12:38:04 +01:00
return node_ - > local_ready_prefix_size_ ;
2018-04-03 19:49:07 +02:00
}
2018-12-31 20:04:05 +01:00
default :
return 0 ;
}
}
int64 FileView : : local_total_size ( ) const {
2018-01-20 15:57:52 +01:00
switch ( node_ - > local_ . type ( ) ) {
2018-12-31 20:04:05 +01:00
case LocalFileLocation : : Type : : Empty :
return 0 ;
case LocalFileLocation : : Type : : Full :
return node_ - > size_ ;
case LocalFileLocation : : Type : : Partial :
2018-12-27 16:37:57 +01:00
VLOG ( update_file ) < < " Have local_ready_prefix_size = " < < node_ - > local_ready_prefix_size_
< < " and local_ready_size = " < < node_ - > local_ready_size_ ;
2018-11-11 12:38:04 +01:00
return max ( node_ - > local_ready_prefix_size_ , node_ - > local_ready_size_ ) ;
2018-12-31 20:04:05 +01:00
default :
UNREACHABLE ( ) ;
return 0 ;
}
}
bool FileView : : is_uploading ( ) const {
return node_ - > upload_priority_ ! = 0 | | node_ - > generate_upload_priority_ ! = 0 ;
}
int64 FileView : : remote_size ( ) const {
2019-02-14 12:20:40 +01:00
if ( node_ - > remote_ . is_full_alive ) {
return node_ - > 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 ( ) ;
2018-12-31 20:04:05 +01:00
}
2019-02-14 12:20:40 +01:00
return res ;
2018-12-31 20:04:05 +01:00
}
2019-02-14 12:20:40 +01:00
return node_ - > remote_ . ready_size ; //???
2018-12-31 20:04:05 +01:00
}
string FileView : : path ( ) const {
2018-01-20 15:57:52 +01:00
switch ( node_ - > local_ . type ( ) ) {
2018-12-31 20:04:05 +01:00
case LocalFileLocation : : Type : : Full :
return node_ - > local_ . full ( ) . path_ ;
case LocalFileLocation : : Type : : Partial :
return node_ - > local_ . partial ( ) . path_ ;
default :
return " " ;
}
}
bool FileView : : has_url ( ) const {
return ! node_ - > url_ . empty ( ) ;
}
const string & FileView : : url ( ) const {
return node_ - > url_ ;
}
2018-02-18 17:29:44 +01:00
const string & FileView : : remote_name ( ) const {
return node_ - > remote_name_ ;
2018-12-31 20:04:05 +01:00
}
2018-02-20 00:29:19 +01:00
string FileView : : suggested_name ( ) const {
2018-02-19 23:28:06 +01:00
return node_ - > suggested_name ( ) ;
}
2018-01-20 11:49:06 +01:00
DialogId FileView : : owner_dialog_id ( ) const {
2018-12-31 20:04:05 +01:00
return node_ - > owner_dialog_id_ ;
}
bool FileView : : get_by_hash ( ) const {
return node_ - > get_by_hash_ ;
}
2018-01-30 17:54:17 +01:00
FileView : : FileView ( ConstFileNodePtr node ) : node_ ( node ) {
2018-12-31 20:04:05 +01:00
}
bool FileView : : empty ( ) const {
2018-01-30 21:04:22 +01:00
return ! node_ ;
2018-12-31 20:04:05 +01:00
}
bool FileView : : can_download_from_server ( ) const {
if ( ! has_remote_location ( ) ) {
return false ;
}
2018-01-20 15:57:52 +01:00
if ( remote_location ( ) . file_type_ = = FileType : : Encrypted & & encryption_key ( ) . empty ( ) ) {
2018-12-31 20:04:05 +01:00
return false ;
}
2018-06-25 23:10:53 +02:00
if ( remote_location ( ) . is_web ( ) ) {
return true ;
}
2018-12-31 20:04:05 +01:00
if ( remote_location ( ) . get_dc_id ( ) . is_empty ( ) ) {
return false ;
}
2019-10-18 03:31:28 +02:00
if ( ! remote_location ( ) . is_encrypted_any ( ) & & ! remote_location ( ) . has_file_reference ( ) & &
( ( node_ - > download_id_ = = 0 & & node_ - > download_was_update_file_reference_ ) | | ! node_ - > remote_ . is_full_alive ) ) {
return false ;
}
2018-12-31 20:04:05 +01:00
return true ;
}
2018-06-25 23:10:53 +02:00
2018-12-31 20:04:05 +01:00
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 ( ) ) ) ;
}
2018-01-20 15:57:52 +01:00
return node_ - > local_ . type ( ) = = LocalFileLocation : : Type : : Partial ;
2018-12-31 20:04:05 +01:00
}
2020-07-06 17:31:26 +02:00
string FileView : : get_unique_id ( const FullGenerateFileLocation & location ) {
return base64url_encode ( zero_encode ( ' \xff ' + serialize ( location ) ) ) ;
}
string FileView : : get_unique_id ( const FullRemoteFileLocation & location ) {
return base64url_encode ( zero_encode ( serialize ( location . as_unique ( ) ) ) ) ;
}
string FileView : : get_persistent_id ( const FullGenerateFileLocation & location ) {
auto binary = serialize ( location ) ;
binary = zero_encode ( binary ) ;
binary . push_back ( FileNode : : PERSISTENT_ID_VERSION_MAP ) ;
return base64url_encode ( binary ) ;
}
string FileView : : 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 ) ;
return base64url_encode ( binary ) ;
}
string FileView : : get_persistent_file_id ( ) const {
2020-07-06 17:40:58 +02:00
if ( ! empty ( ) ) {
if ( has_alive_remote_location ( ) ) {
return get_persistent_id ( remote_location ( ) ) ;
} else if ( has_url ( ) ) {
return url ( ) ;
} else if ( has_generate_location ( ) & & begins_with ( generate_location ( ) . conversion_ , " #map# " ) ) {
return get_persistent_id ( generate_location ( ) ) ;
}
2020-07-06 17:31:26 +02:00
}
return string ( ) ;
}
string FileView : : get_unique_file_id ( ) const {
2020-07-06 17:40:58 +02:00
if ( ! empty ( ) ) {
if ( has_alive_remote_location ( ) ) {
if ( ! remote_location ( ) . is_web ( ) ) {
return get_unique_id ( remote_location ( ) ) ;
}
} else if ( has_generate_location ( ) & & begins_with ( generate_location ( ) . conversion_ , " #map# " ) ) {
return get_unique_id ( generate_location ( ) ) ;
2020-07-06 17:31:26 +02:00
}
}
return string ( ) ;
}
2018-12-31 20:04:05 +01:00
/*** FileManager ***/
2019-02-14 12:20:40 +01:00
static int merge_choose_remote_location ( const FullRemoteFileLocation & x , FileLocationSource x_source ,
const FullRemoteFileLocation & y , FileLocationSource y_source ) ;
2019-02-04 16:59:01 +01:00
2018-12-31 20:04:05 +01:00
namespace {
void prepare_path_for_pmc ( FileType file_type , string & path ) {
path = PathView : : relative ( path , get_files_base_dir ( file_type ) ) . str ( ) ;
}
} // namespace
2018-09-27 03:19:03 +02:00
FileManager : : FileManager ( unique_ptr < Context > context ) : context_ ( std : : move ( context ) ) {
2018-12-31 20:04:05 +01:00
if ( G ( ) - > parameters ( ) . use_file_db ) {
file_db_ = G ( ) - > td_db ( ) - > get_file_db_shared ( ) ;
}
parent_ = context_ - > create_reference ( ) ;
2020-06-22 07:43:00 +02:00
std : : unordered_set < string > dir_paths ;
for ( int32 i = 0 ; i < MAX_FILE_TYPE ; i + + ) {
dir_paths . insert ( get_files_dir ( static_cast < FileType > ( i ) ) ) ;
}
// add both temp dirs
dir_paths . insert ( get_files_temp_dir ( FileType : : Encrypted ) ) ;
dir_paths . insert ( get_files_temp_dir ( FileType : : Video ) ) ;
for ( const auto & path : dir_paths ) {
2018-12-31 20:04:05 +01:00
auto status = mkdir ( path , 0750 ) ;
if ( status . is_error ( ) ) {
2018-01-31 13:43:36 +01:00
auto r_stat = stat ( path ) ;
if ( r_stat . is_ok ( ) & & r_stat . ok ( ) . is_dir_ ) {
2019-02-21 16:58:20 +01:00
LOG ( ERROR ) < < " Creation of directory \" " < < path < < " \" failed with " < < status < < " , but directory exists " ;
2018-01-31 13:43:36 +01:00
} else {
2019-02-21 16:58:20 +01:00
LOG ( ERROR ) < < " Creation of directory \" " < < path < < " \" failed with " < < status ;
2018-01-31 13:43:36 +01:00
}
2018-12-31 20:04:05 +01:00
}
# if TD_ANDROID
2020-06-22 07:43:00 +02:00
FileFd : : open ( path + " .nomedia " , FileFd : : Create | FileFd : : Read ) . ignore ( ) ;
2018-12-31 20:04:05 +01:00
# endif
} ;
G ( ) - > td_db ( ) - > with_db_path ( [ this ] ( CSlice path ) { this - > bad_paths_ . insert ( path . str ( ) ) ; } ) ;
}
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_generate_manager_ = create_actor_on_scheduler < FileGenerateManager > (
" FileGenerateManager " , G ( ) - > get_slow_net_scheduler_id ( ) , context_ - > create_reference ( ) ) ;
}
2019-01-03 16:26:44 +01:00
2018-12-31 20:04:05 +01:00
FileManager : : ~ FileManager ( ) {
}
string FileManager : : fix_file_extension ( Slice file_name , Slice file_type , Slice file_extension ) {
return ( file_name . empty ( ) ? file_type : file_name ) . str ( ) + " . " + file_extension . str ( ) ;
}
string FileManager : : get_file_name ( FileType file_type , Slice path ) {
PathView path_view ( path ) ;
auto file_name = path_view . file_name ( ) ;
auto extension = path_view . extension ( ) ;
switch ( file_type ) {
case FileType : : Thumbnail :
if ( extension ! = " jpg " & & extension ! = " jpeg " & & extension ! = " webp " ) {
return fix_file_extension ( file_name , " thumbnail " , " jpg " ) ;
}
break ;
case FileType : : ProfilePhoto :
case FileType : : Photo :
if ( extension ! = " jpg " & & extension ! = " jpeg " & & extension ! = " gif " & & extension ! = " png " & & extension ! = " tif " & &
extension ! = " bmp " ) {
return fix_file_extension ( file_name , " photo " , " jpg " ) ;
}
break ;
case FileType : : VoiceNote :
if ( extension ! = " ogg " & & extension ! = " oga " & & extension ! = " mp3 " & & extension ! = " mpeg3 " & &
extension ! = " m4a " ) {
return fix_file_extension ( file_name , " voice " , " oga " ) ;
}
break ;
case FileType : : Video :
case FileType : : VideoNote :
if ( extension ! = " mov " & & extension ! = " 3gp " & & extension ! = " mpeg4 " & & 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 " ) {
return fix_file_extension ( file_name , " audio " , " mp3 " ) ;
}
break ;
2019-05-07 04:51:56 +02:00
case FileType : : Wallpaper :
case FileType : : Background :
if ( extension ! = " jpg " & & extension ! = " jpeg " & & extension ! = " png " ) {
return fix_file_extension ( file_name , " wallpaper " , " jpg " ) ;
}
break ;
2018-12-31 20:04:05 +01:00
case FileType : : Sticker :
2019-07-15 02:43:05 +02:00
if ( extension ! = " webp " & & extension ! = " tgs " ) {
return fix_file_extension ( file_name , " sticker " , " webp " ) ;
}
break ;
case FileType : : Document :
2018-12-31 20:04:05 +01:00
case FileType : : Animation :
case FileType : : Encrypted :
case FileType : : Temp :
case FileType : : EncryptedThumbnail :
2018-04-03 19:49:07 +02:00
case FileType : : Secure :
case FileType : : SecureRaw :
2020-06-22 01:02:21 +02:00
case FileType : : DocumentAsFile :
2018-12-31 20:04:05 +01:00
break ;
default :
UNREACHABLE ( ) ;
}
return file_name . str ( ) ;
}
2019-03-15 19:52:54 +01:00
bool FileManager : : are_modification_times_equal ( int64 old_mtime , int64 new_mtime ) {
if ( old_mtime = = new_mtime ) {
return true ;
}
if ( old_mtime < new_mtime ) {
return false ;
}
if ( old_mtime - new_mtime = = 1000000000 & & old_mtime % 1000000000 = = 0 & & new_mtime % 2000000000 = = 0 ) {
// FAT32 has 2 seconds mtime resolution, but file system sometimes reports odd modification time
return true ;
}
return false ;
}
2020-06-01 20:35:06 +02:00
Status FileManager : : check_local_location ( FullLocalFileLocation & location , int64 & size , bool skip_file_size_checks ) {
2020-06-03 20:22:58 +02:00
constexpr int64 MAX_THUMBNAIL_SIZE = 200 * ( 1 < < 10 ) - 1 /* 200 KB - 1 B */ ;
2019-01-07 18:41:05 +01:00
constexpr int64 MAX_PHOTO_SIZE = 10 * ( 1 < < 20 ) /* 10 MB */ ;
2018-12-31 20:04:05 +01:00
if ( location . path_ . empty ( ) ) {
return Status : : Error ( " File must have non-empty path " ) ;
}
2018-01-26 14:47:46 +01:00
TRY_RESULT ( path , realpath ( location . path_ , true ) ) ;
2018-12-31 20:04:05 +01:00
if ( bad_paths_ . count ( path ) ! = 0 ) {
return Status : : Error ( " Sending of internal database files is forbidden " ) ;
}
location . path_ = std : : move ( path ) ;
TRY_RESULT ( stat , stat ( location . path_ ) ) ;
if ( ! stat . is_reg_ ) {
return Status : : Error ( " File must be a regular file " ) ;
}
if ( stat . size_ < 0 ) {
// TODO is it possible?
return Status : : Error ( " File is too big " ) ;
}
if ( stat . size_ = = 0 ) {
return Status : : Error ( " File must be non-empty " ) ;
}
if ( size = = 0 ) {
size = stat . size_ ;
}
if ( location . mtime_nsec_ = = 0 ) {
2019-03-15 20:11:56 +01:00
VLOG ( files ) < < " Set file \" " < < location . path_ < < " \" modification time to " < < stat . mtime_nsec_ ;
2018-12-31 20:04:05 +01:00
location . mtime_nsec_ = stat . mtime_nsec_ ;
2019-03-15 19:52:54 +01:00
} else if ( ! are_modification_times_equal ( location . mtime_nsec_ , stat . mtime_nsec_ ) ) {
2019-03-15 20:11:56 +01:00
VLOG ( files ) < < " File \" " < < location . path_ < < " \" was modified: old mtime = " < < location . mtime_nsec_
< < " , new mtime = " < < stat . mtime_nsec_ ;
2018-03-16 13:33:44 +01:00
return Status : : Error ( PSLICE ( ) < < " File \" " < < location . path_ < < " \" was modified " ) ;
2018-12-31 20:04:05 +01:00
}
2020-06-01 20:35:06 +02:00
if ( skip_file_size_checks ) {
return Status : : OK ( ) ;
}
2018-01-20 15:57:52 +01:00
if ( ( location . file_type_ = = FileType : : Thumbnail | | location . file_type_ = = FileType : : EncryptedThumbnail ) & &
2020-06-03 20:22:58 +02:00
size > MAX_THUMBNAIL_SIZE & & ! begins_with ( PathView ( location . path_ ) . file_name ( ) , " map " ) ) {
2019-01-07 18:41:05 +01:00
return Status : : Error ( PSLICE ( ) < < " File \" " < < location . path_ < < " \" is too big for a thumbnail "
< < tag ( " size " , format : : as_size ( size ) ) ) ;
}
2020-06-03 20:22:58 +02:00
if ( location . file_type_ = = FileType : : Photo & & size > MAX_PHOTO_SIZE ) {
2019-01-07 18:41:05 +01:00
return Status : : Error ( PSLICE ( ) < < " File \" " < < location . path_ < < " \" is too big for a photo "
2018-03-16 13:33:44 +01:00
< < tag ( " size " , format : : as_size ( size ) ) ) ;
2018-12-31 20:04:05 +01:00
}
2020-06-03 20:22:58 +02:00
if ( size > MAX_FILE_SIZE ) {
2018-03-16 13:33:44 +01:00
return Status : : Error ( PSLICE ( ) < < " File \" " < < location . path_ < < " \" is too big "
< < tag ( " size " , format : : as_size ( size ) ) ) ;
2018-12-31 20:04:05 +01:00
}
return Status : : OK ( ) ;
}
static Status check_partial_local_location ( const PartialLocalFileLocation & location ) {
TRY_RESULT ( stat , stat ( location . path_ ) ) ;
if ( ! stat . is_reg_ ) {
2018-03-16 13:33:44 +01:00
if ( stat . is_dir_ ) {
return Status : : Error ( PSLICE ( ) < < " Can't use directory \" " < < location . path_ < < " \" as a file path " ) ;
}
2018-12-31 20:04:05 +01:00
return Status : : Error ( " File must be a regular file " ) ;
}
// can't check mtime. Hope nobody will mess with this file in our temporary dir.
return Status : : OK ( ) ;
}
2018-01-30 17:54:17 +01:00
Status FileManager : : check_local_location ( FileNodePtr node ) {
2018-12-31 20:04:05 +01:00
Status status ;
2018-01-20 15:57:52 +01:00
if ( node - > local_ . type ( ) = = LocalFileLocation : : Type : : Full ) {
2020-06-01 20:35:06 +02:00
status = check_local_location ( node - > local_ . full ( ) , node - > size_ , false ) ;
2018-01-20 15:57:52 +01:00
} else if ( node - > local_ . type ( ) = = LocalFileLocation : : Type : : Partial ) {
2018-12-31 20:04:05 +01:00
status = check_partial_local_location ( node - > local_ . partial ( ) ) ;
}
if ( status . is_error ( ) ) {
2018-12-26 17:11:15 +01:00
node - > drop_local_location ( ) ;
2018-12-27 18:23:19 +01:00
try_flush_node ( node , " check_local_location " ) ;
2018-12-31 20:04:05 +01:00
}
return status ;
}
2019-08-30 03:56:01 +02:00
bool FileManager : : try_fix_partial_local_location ( FileNodePtr node ) {
2019-08-19 11:31:25 +02:00
LOG ( INFO ) < < " Trying to fix partial local location " ;
if ( node - > local_ . type ( ) ! = LocalFileLocation : : Type : : Partial ) {
LOG ( INFO ) < < " failed - not a partial location " ;
return false ;
}
auto partial = node - > local_ . partial ( ) ;
if ( ! partial . iv_ . empty ( ) ) {
// can't recalc iv_
LOG ( INFO ) < < " failed - partial location has nonempty iv " ;
return false ;
}
if ( partial . part_size_ > = 512 * ( 1 < < 10 ) ) {
LOG ( INFO ) < < " failed - too big part_size already: " < < partial . part_size_ ;
return false ;
}
auto old_part_size = partial . part_size_ ;
int new_part_size = 512 * ( 1 < < 10 ) ;
auto k = new_part_size / old_part_size ;
Bitmask mask ( Bitmask : : Decode ( ) , partial . ready_bitmask_ ) ;
auto new_mask = mask . compress ( k ) ;
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 ( partial ) , ready_size , - 1 , - 1 ) ;
LOG ( INFO ) < < " ok: increase part_size " < < old_part_size < < " -> " < < new_part_size ;
return true ;
}
2018-12-31 20:04:05 +01:00
FileManager : : FileIdInfo * FileManager : : get_file_id_info ( FileId file_id ) {
2020-05-23 21:27:24 +02:00
file_id . set_time ( ) ;
2018-12-31 20:04:05 +01:00
return & file_id_info_ [ file_id . get ( ) ] ;
}
FileId FileManager : : dup_file_id ( FileId file_id ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
return dup_file_id_internal ( file_id ) ;
}
FileId FileManager : : dup_file_id_internal ( FileId file_id ) {
2018-12-31 20:04:05 +01:00
int32 file_node_id ;
2018-01-30 21:04:22 +01:00
auto * file_node = get_file_node_raw ( file_id , & file_node_id ) ;
2018-12-31 20:04:05 +01:00
if ( ! file_node ) {
return FileId ( ) ;
}
2019-02-10 00:39:58 +01:00
auto result = FileId ( create_file_id ( file_node_id , file_node ) . get ( ) , file_id . get_remote ( ) ) ;
2018-12-31 20:04:05 +01:00
LOG ( INFO ) < < " Dup file " < < file_id < < " to " < < result ;
return result ;
}
2018-01-30 21:04:22 +01:00
FileId FileManager : : create_file_id ( int32 file_node_id , FileNode * file_node ) {
2018-12-31 20:04:05 +01:00
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 ;
}
2019-01-21 18:19:02 +01:00
2018-12-31 20:04:05 +01:00
void FileManager : : try_forget_file_id ( FileId file_id ) {
auto * info = get_file_id_info ( file_id ) ;
2019-01-21 18:19:02 +01:00
if ( info - > send_updates_flag_ | | info - > pin_flag_ | | info - > sent_file_id_flag_ ) {
2018-12-31 20:04:05 +01:00
return ;
}
2018-01-30 21:04:22 +01:00
auto file_node = get_file_node ( file_id ) ;
2018-12-31 20:04:05 +01:00
if ( file_node - > main_file_id_ = = file_id ) {
return ;
}
2018-06-05 01:40:00 +02:00
LOG ( DEBUG ) < < " Forget file " < < file_id ;
2019-10-22 01:12:58 +02:00
bool is_removed = td : : remove ( file_node - > file_ids_ , file_id ) ;
CHECK ( is_removed ) ;
2018-01-30 21:04:22 +01:00
* info = FileIdInfo ( ) ;
2020-05-23 21:27:24 +02:00
file_id_info_ . erase ( file_id . get ( ) ) ;
2018-12-31 20:04:05 +01:00
}
FileId FileManager : : register_empty ( FileType type ) {
2020-08-02 00:28:01 +02:00
return register_local_internal ( FullLocalFileLocation ( type , " " , 0 ) , DialogId ( ) , 0 , false , true ) . ok ( ) ;
2018-12-31 20:04:05 +01:00
}
void FileManager : : on_file_unlink ( const FullLocalFileLocation & location ) {
2020-03-02 00:41:47 +01:00
// TODO: remove file from the database too
2018-12-31 20:04:05 +01:00
auto it = local_location_to_file_id_ . find ( location ) ;
if ( it = = local_location_to_file_id_ . end ( ) ) {
return ;
}
auto file_id = it - > second ;
2018-01-30 21:04:22 +01:00
auto file_node = get_sync_file_node ( file_id ) ;
2020-05-23 21:27:24 +02:00
if ( ! file_node ) {
return ;
}
2018-12-26 17:11:15 +01:00
file_node - > drop_local_location ( ) ;
2018-12-27 18:23:19 +01:00
try_flush_node_info ( file_node , " on_file_unlink " ) ;
2018-12-31 20:04:05 +01:00
}
Result < FileId > FileManager : : register_local ( FullLocalFileLocation location , DialogId owner_dialog_id , int64 size ,
2020-06-01 20:35:06 +02:00
bool get_by_hash , bool force , bool skip_file_size_checks ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
return register_local_internal ( location , owner_dialog_id , size , get_by_hash , force , skip_file_size_checks ) ;
}
Result < FileId > FileManager : : register_local_internal ( FullLocalFileLocation location , DialogId owner_dialog_id , int64 size ,
bool get_by_hash , bool force , bool skip_file_size_checks ) {
2018-12-31 20:04:05 +01:00
// TODO: use get_by_hash
FileData data ;
data . local_ = LocalFileLocation ( std : : move ( location ) ) ;
data . owner_dialog_id_ = owner_dialog_id ;
data . size_ = size ;
2020-06-01 20:35:06 +02:00
return register_file ( std : : move ( data ) , FileLocationSource : : None /*won't be used*/ , " register_local " , force ,
skip_file_size_checks ) ;
2018-12-31 20:04:05 +01:00
}
2018-01-26 13:56:19 +01:00
FileId FileManager : : register_remote ( const FullRemoteFileLocation & location , FileLocationSource file_location_source ,
2020-08-02 00:28:01 +02:00
DialogId owner_dialog_id , int64 size , int64 expected_size , string remote_name ) {
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
return register_remote_internal ( location , file_location_source , owner_dialog_id , size , expected_size , std : : move ( remote_name ) ) ;
}
FileId FileManager : : register_remote_internal ( const FullRemoteFileLocation & location , FileLocationSource file_location_source ,
2020-07-20 16:46:54 +02:00
DialogId owner_dialog_id , int64 size , int64 expected_size , string remote_name ) {
2018-12-31 20:04:05 +01:00
FileData data ;
data . remote_ = RemoteFileLocation ( location ) ;
data . owner_dialog_id_ = owner_dialog_id ;
data . size_ = size ;
data . expected_size_ = expected_size ;
2020-07-20 16:46:54 +02:00
data . remote_name_ = std : : move ( remote_name ) ;
2018-04-01 22:15:44 +02:00
auto file_id = register_file ( std : : move ( data ) , file_location_source , " register_remote " , false ) . move_as_ok ( ) ;
auto url = location . get_url ( ) ;
if ( ! url . empty ( ) ) {
auto file_node = get_file_node ( file_id ) ;
CHECK ( file_node ) ;
file_node - > set_url ( url ) ;
}
return file_id ;
2018-12-31 20:04:05 +01:00
}
2018-01-26 13:56:19 +01:00
FileId FileManager : : register_url ( string url , FileType file_type , FileLocationSource file_location_source ,
DialogId owner_dialog_id ) {
2020-08-02 00:28:01 +02:00
auto file_id = register_generate_internal ( file_type , file_location_source , url , " #url# " , owner_dialog_id , 0 ) . ok ( ) ;
2018-01-30 21:04:22 +01:00
auto file_node = get_file_node ( file_id ) ;
2018-12-31 20:04:05 +01:00
CHECK ( file_node ) ;
file_node - > set_url ( url ) ;
return file_id ;
}
2018-01-26 13:56:19 +01:00
Result < FileId > FileManager : : register_generate ( FileType file_type , FileLocationSource file_location_source ,
string original_path , string conversion , DialogId owner_dialog_id ,
int64 expected_size ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
return register_generate_internal ( file_type , file_location_source , std : : move ( original_path ) , std : : move ( conversion ) , owner_dialog_id , expected_size ) ;
}
Result < FileId > FileManager : : register_generate_internal ( FileType file_type , FileLocationSource file_location_source ,
string original_path , string conversion , DialogId owner_dialog_id ,
int64 expected_size ) {
2018-10-30 15:25:31 +01:00
// add #mtime# into conversion
2018-11-01 16:54:08 +01:00
if ( ! original_path . empty ( ) & & conversion [ 0 ] ! = ' # ' & & PathView ( original_path ) . is_absolute ( ) ) {
2019-01-17 23:25:11 +01:00
auto file_paths = log_interface - > get_file_paths ( ) ;
2019-10-22 01:12:58 +02:00
if ( ! td : : contains ( file_paths , original_path ) ) {
2019-01-17 23:25:11 +01:00
auto r_stat = stat ( original_path ) ;
uint64 mtime = r_stat . is_ok ( ) ? r_stat . ok ( ) . mtime_nsec_ : 0 ;
conversion = PSTRING ( ) < < " #mtime# " < < lpad0 ( to_string ( mtime ) , 20 ) < < ' # ' < < conversion ;
}
2018-10-30 15:25:31 +01:00
}
2018-12-31 20:04:05 +01:00
FileData data ;
2018-09-27 03:19:03 +02:00
data . generate_ =
td : : make_unique < FullGenerateFileLocation > ( file_type , std : : move ( original_path ) , std : : move ( conversion ) ) ;
2018-12-31 20:04:05 +01:00
data . owner_dialog_id_ = owner_dialog_id ;
data . expected_size_ = expected_size ;
2018-01-26 13:56:19 +01:00
return register_file ( std : : move ( data ) , file_location_source , " register_generate " , false ) ;
2018-12-31 20:04:05 +01:00
}
2019-01-19 22:26:23 +01:00
Result < FileId > FileManager : : register_file ( FileData & & data , FileLocationSource file_location_source , const char * source ,
2020-06-01 20:35:06 +02:00
bool force , bool skip_file_size_checks ) {
2018-01-20 15:57:52 +01:00
bool has_remote = data . remote_ . type ( ) = = RemoteFileLocation : : Type : : Full ;
2018-02-04 18:27:05 +01:00
bool has_generate = data . generate_ ! = nullptr ;
2018-01-20 15:57:52 +01:00
if ( data . local_ . type ( ) = = LocalFileLocation : : Type : : Full & & ! force ) {
2019-02-15 21:22:40 +01:00
if ( file_location_source = = FileLocationSource : : FromBinlog | |
file_location_source = = FileLocationSource : : FromDatabase ) {
2018-12-31 20:04:05 +01:00
PathView path_view ( data . local_ . full ( ) . path_ ) ;
if ( path_view . is_relative ( ) ) {
2019-01-19 23:59:37 +01:00
data . local_ . full ( ) . path_ = PSTRING ( )
< < get_files_base_dir ( data . local_ . full ( ) . file_type_ ) < < data . local_ . full ( ) . path_ ;
2018-12-31 20:04:05 +01:00
}
}
2020-06-01 20:35:06 +02:00
auto status = check_local_location ( data . local_ . full ( ) , data . size_ , skip_file_size_checks ) ;
2018-12-31 20:04:05 +01:00
if ( status . is_error ( ) ) {
2019-04-22 00:25:18 +02:00
LOG ( WARNING ) < < " Invalid " < < data . local_ . full ( ) < < " : " < < status < < " from " < < source ;
2018-12-31 20:04:05 +01:00
data . local_ = LocalFileLocation ( ) ;
2018-01-30 13:33:02 +01:00
if ( data . remote_ . type ( ) = = RemoteFileLocation : : Type : : Partial ) {
data . remote_ = { } ;
}
2018-12-31 20:04:05 +01:00
if ( ! has_remote & & ! has_generate ) {
return std : : move ( status ) ;
}
}
}
2018-01-20 15:57:52 +01:00
bool has_local = data . local_ . type ( ) = = LocalFileLocation : : Type : : Full ;
2018-12-31 20:04:05 +01:00
bool has_location = has_local | | has_remote | | has_generate ;
if ( ! has_location ) {
return Status : : Error ( " No location " ) ;
}
FileId file_id = next_file_id ( ) ;
LOG ( INFO ) < < " Register file data " < < data < < " as " < < file_id < < " from " < < source ;
// create FileNode
auto file_node_id = next_file_node_id ( ) ;
auto & node = file_nodes_ [ file_node_id ] ;
2020-08-02 00:28:01 +02:00
node = td : : make_unique < FileNode > ( std : : move ( data . local_ ) , NewRemoteFileLocation ( data . remote_ , file_location_source ) ,
2019-02-14 12:20:40 +01:00
std : : move ( data . generate_ ) , data . size_ , data . expected_size_ ,
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 ) ) ;
2020-08-02 00:28:01 +02:00
node - > pmc_id_ = FileDbId ( data . pmc_id_ ) ;
2018-12-31 20:04:05 +01:00
get_file_id_info ( file_id ) - > node_id_ = file_node_id ;
2020-08-02 00:28:01 +02:00
node - > file_ids_ . push_back ( file_id ) ;
2018-12-31 20:04:05 +01:00
2018-01-30 21:04:22 +01:00
FileView file_view ( get_file_node ( file_id ) ) ;
2018-12-31 20:04:05 +01:00
std : : vector < FileId > to_merge ;
auto register_location = [ & ] ( const auto & location , auto & mp ) {
auto & other_id = mp [ location ] ;
if ( other_id . empty ( ) ) {
other_id = file_id ;
get_file_id_info ( file_id ) - > pin_flag_ = true ;
return true ;
} else {
to_merge . push_back ( other_id ) ;
return false ;
}
} ;
bool new_remote = false ;
2018-03-06 19:31:20 +01:00
int32 remote_key = 0 ;
2018-12-31 20:04:05 +01:00
if ( file_view . has_remote_location ( ) ) {
2019-02-04 16:59:01 +01:00
RemoteInfo info { file_view . remote_location ( ) , file_location_source , file_id } ;
2018-03-06 19:31:20 +01:00
remote_key = remote_location_info_ . add ( info ) ;
auto & stored_info = remote_location_info_ . get ( remote_key ) ;
2018-03-07 00:23:09 +01:00
if ( stored_info . file_id_ = = file_id ) {
2018-03-06 19:31:20 +01:00
get_file_id_info ( file_id ) - > pin_flag_ = true ;
new_remote = true ;
} else {
2018-03-07 00:23:09 +01:00
to_merge . push_back ( stored_info . file_id_ ) ;
2019-02-14 12:20:40 +01:00
if ( merge_choose_remote_location ( file_view . remote_location ( ) , file_location_source , stored_info . remote_ ,
stored_info . file_location_source_ ) = = 0 ) {
2018-03-06 19:31:20 +01:00
stored_info . remote_ = file_view . remote_location ( ) ;
2019-02-04 16:59:01 +01:00
stored_info . file_location_source_ = file_location_source ;
2018-03-06 19:31:20 +01:00
}
}
2018-12-31 20:04:05 +01:00
}
bool new_local = false ;
if ( file_view . has_local_location ( ) ) {
new_local = register_location ( file_view . local_location ( ) , local_location_to_file_id_ ) ;
}
bool new_generate = false ;
if ( file_view . has_generate_location ( ) ) {
new_generate = register_location ( file_view . generate_location ( ) , generate_location_to_file_id_ ) ;
}
std : : sort ( to_merge . begin ( ) , to_merge . end ( ) ) ;
to_merge . erase ( std : : unique ( to_merge . begin ( ) , to_merge . end ( ) ) , to_merge . end ( ) ) ;
int new_cnt = new_remote + new_local + new_generate ;
if ( data . pmc_id_ = = 0 & & file_db_ & & new_cnt > 0 ) {
2020-08-02 00:28:01 +02:00
node - > need_load_from_pmc_ = true ;
2018-12-31 20:04:05 +01:00
}
bool no_sync_merge = to_merge . size ( ) = = 1 & & new_cnt = = 0 ;
for ( auto id : to_merge ) {
2018-01-25 14:11:05 +01:00
// may invalidate node
2020-08-02 00:28:01 +02:00
merge_internal ( file_id , id , no_sync_merge ) . ignore ( ) ;
2018-12-31 20:04:05 +01:00
}
2018-12-27 18:23:19 +01:00
try_flush_node ( get_file_node ( file_id ) , " register_file " ) ;
2018-12-31 20:04:05 +01:00
auto main_file_id = get_file_node ( file_id ) - > main_file_id_ ;
try_forget_file_id ( file_id ) ;
2019-01-30 22:37:38 +01:00
for ( auto file_source_id : data . file_source_ids_ ) {
VLOG ( file_references ) < < " Loaded " < < data . file_source_ids_ < < " for file " < < main_file_id < < " from " < < source ;
if ( file_source_id . is_valid ( ) ) {
context_ - > add_file_source ( main_file_id , file_source_id ) ;
}
}
2018-03-06 19:31:20 +01:00
return FileId ( main_file_id . get ( ) , remote_key ) ;
2018-12-31 20:04:05 +01:00
}
// 0 -- choose x
// 1 -- choose y
// 2 -- choose any
2018-09-07 18:29:18 +02:00
static int merge_choose_local_location ( const LocalFileLocation & x , const LocalFileLocation & y ) {
2018-01-20 15:57:52 +01:00
int32 x_type = static_cast < int32 > ( x . type ( ) ) ;
int32 y_type = static_cast < int32 > ( y . type ( ) ) ;
2018-12-31 20:04:05 +01:00
if ( x_type ! = y_type ) {
return x_type < y_type ;
}
return 2 ;
}
2019-02-14 12:20:40 +01:00
static int merge_choose_file_source_location ( FileLocationSource x , FileLocationSource y ) {
return static_cast < int > ( x ) < static_cast < int > ( y ) ;
}
static int merge_choose_remote_location ( const FullRemoteFileLocation & x , FileLocationSource x_source ,
const FullRemoteFileLocation & y , FileLocationSource y_source ) {
2019-02-15 21:09:18 +01:00
LOG ( INFO ) < < " Choose between " < < x < < " from " < < x_source < < " and " < < y < < " from " < < y_source ;
2019-02-04 16:59:01 +01:00
if ( x . is_web ( ) ! = y . is_web ( ) ) {
return x . is_web ( ) ; // prefer non-web
}
2019-06-17 04:37:57 +02:00
auto x_ref = x . has_file_reference ( ) ;
auto y_ref = y . has_file_reference ( ) ;
2019-02-04 16:59:01 +01:00
if ( x_ref | | y_ref ) {
if ( x_ref ! = y_ref ) {
return ! x_ref ;
}
2019-06-17 04:37:57 +02:00
if ( x . get_file_reference ( ) ! = y . get_file_reference ( ) ) {
2019-02-14 12:20:40 +01:00
return merge_choose_file_source_location ( x_source , y_source ) ;
2019-02-04 16:59:01 +01:00
}
}
2019-06-18 17:40:46 +02:00
if ( ( x . get_access_hash ( ) ! = y . get_access_hash ( ) | | x . get_source ( ) ! = y . get_source ( ) ) & &
( x_source ! = y_source | | x . is_web ( ) | | x . get_id ( ) = = y . get_id ( ) ) ) {
2019-02-14 12:20:40 +01:00
return merge_choose_file_source_location ( x_source , y_source ) ;
2019-02-04 16:59:01 +01:00
}
return 2 ;
}
2019-02-15 21:09:18 +01:00
2019-02-14 12:20:40 +01:00
static int merge_choose_remote_location ( const NewRemoteFileLocation & x , const NewRemoteFileLocation & y ) {
if ( x . is_full_alive ! = y . is_full_alive ) {
return ! x . is_full_alive ;
}
if ( x . is_full_alive ) {
return merge_choose_remote_location ( x . full . value ( ) , x . full_source , y . full . value ( ) , y . full_source ) ;
2018-12-31 20:04:05 +01:00
}
2019-02-14 12:20:40 +01:00
if ( ! x . partial ! = ! y . partial ) {
return ! x . partial ;
2018-12-31 20:04:05 +01:00
}
return 2 ;
}
2018-10-31 19:11:02 +01:00
2018-09-07 18:29:18 +02:00
static int merge_choose_generate_location ( const unique_ptr < FullGenerateFileLocation > & x ,
const unique_ptr < FullGenerateFileLocation > & y ) {
2018-10-31 19:11:02 +01:00
int x_empty = ( x = = nullptr ) ;
int y_empty = ( y = = nullptr ) ;
if ( x_empty ! = y_empty ) {
return x_empty ? 1 : 0 ;
}
2019-01-19 20:42:06 +01:00
if ( ! x_empty & & * x ! = * y ) {
2018-10-31 19:11:02 +01:00
bool x_has_mtime = begins_with ( x - > conversion_ , " #mtime# " ) ;
bool y_has_mtime = begins_with ( y - > conversion_ , " #mtime# " ) ;
if ( x_has_mtime ! = y_has_mtime ) {
return x_has_mtime ? 0 : 1 ;
}
2019-01-19 20:42:06 +01:00
return x - > conversion_ > = y - > conversion_
? 0
: 1 ; // the bigger conversion, the bigger mtime or at least more stable choise
2018-12-31 20:04:05 +01:00
}
return 2 ;
}
// -1 -- error
static int merge_choose_size ( int64 x , int64 y ) {
if ( x = = 0 ) {
return 1 ;
}
if ( y = = 0 ) {
return 0 ;
}
if ( x ! = y ) {
return - 1 ;
}
return 2 ;
}
2019-01-11 03:45:03 +01:00
2018-12-31 20:04:05 +01:00
static int merge_choose_expected_size ( int64 x , int64 y ) {
if ( x = = 0 ) {
return 1 ;
}
if ( y = = 0 ) {
return 0 ;
}
return 2 ;
}
static int merge_choose_name ( Slice x , Slice y ) {
if ( x . empty ( ) ! = y . empty ( ) ) {
return x . empty ( ) > y . empty ( ) ;
}
return 2 ;
}
static int merge_choose_owner ( DialogId x , DialogId y ) {
if ( x . is_valid ( ) ! = y . is_valid ( ) ) {
return x . is_valid ( ) < y . is_valid ( ) ;
}
return 2 ;
}
2018-01-20 11:49:06 +01:00
static int merge_choose_main_file_id ( FileId a , int8 a_priority , FileId b , int8 b_priority ) {
2018-12-31 20:04:05 +01:00
if ( a_priority ! = b_priority ) {
return a_priority < b_priority ;
}
return a . get ( ) > b . get ( ) ;
}
static int merge_choose_encryption_key ( const FileEncryptionKey & a , const FileEncryptionKey & b ) {
if ( a . empty ( ) ! = b . empty ( ) ) {
return a . empty ( ) > b . empty ( ) ;
}
2019-10-24 19:17:37 +02:00
if ( a ! = b ) {
2018-12-31 20:04:05 +01:00
return - 1 ;
}
return 2 ;
}
2019-01-25 02:52:38 +01:00
void FileManager : : do_cancel_download ( FileNodePtr node ) {
2018-12-31 20:04:05 +01:00
if ( node - > download_id_ = = 0 ) {
return ;
}
send_closure ( file_load_manager_ , & FileLoadManager : : cancel , node - > download_id_ ) ;
node - > download_id_ = 0 ;
2018-01-09 12:57:11 +01:00
node - > is_download_started_ = false ;
2019-01-17 21:42:00 +01:00
node - > download_was_update_file_reference_ = false ;
2018-12-31 20:04:05 +01:00
node - > set_download_priority ( 0 ) ;
}
2019-01-25 02:52:38 +01:00
void FileManager : : do_cancel_upload ( FileNodePtr node ) {
2018-12-31 20:04:05 +01:00
if ( node - > upload_id_ = = 0 ) {
return ;
}
send_closure ( file_load_manager_ , & FileLoadManager : : cancel , node - > upload_id_ ) ;
node - > upload_id_ = 0 ;
2019-01-17 21:42:00 +01:00
node - > upload_was_update_file_reference_ = false ;
2018-12-31 20:04:05 +01:00
node - > set_upload_priority ( 0 ) ;
}
2019-01-25 02:52:38 +01:00
void FileManager : : do_cancel_generate ( FileNodePtr node ) {
2018-12-31 20:04:05 +01:00
if ( node - > generate_id_ = = 0 ) {
return ;
}
send_closure ( file_generate_manager_ , & FileGenerateManager : : cancel , node - > generate_id_ ) ;
node - > generate_id_ = 0 ;
node - > generate_was_update_ = false ;
node - > set_generate_priority ( 0 , 0 ) ;
}
Result < FileId > FileManager : : merge ( FileId x_file_id , FileId y_file_id , bool no_sync ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
return merge_internal ( x_file_id , y_file_id , no_sync ) ;
}
Result < FileId > FileManager : : merge_internal ( FileId x_file_id , FileId y_file_id , bool no_sync ) {
2019-02-15 21:09:18 +01:00
LOG ( DEBUG ) < < " Merge new file " < < x_file_id < < " and old file " < < y_file_id ;
2018-12-31 20:04:05 +01:00
if ( ! x_file_id . is_valid ( ) ) {
return Status : : Error ( " First file_id is invalid " ) ;
}
2018-01-30 21:04:22 +01:00
FileNodePtr x_node = no_sync ? get_file_node ( x_file_id ) : get_sync_file_node ( x_file_id ) ;
2018-12-31 20:04:05 +01:00
if ( ! x_node ) {
return Status : : Error ( PSLICE ( ) < < " Can't merge files. First id is invalid: " < < x_file_id < < " and " < < y_file_id ) ;
}
if ( ! y_file_id . is_valid ( ) ) {
2019-11-16 23:43:47 +01:00
LOG ( DEBUG ) < < " Old file is invalid " ;
2018-12-31 20:04:05 +01:00
return x_node - > main_file_id_ ;
}
2018-03-20 13:18:16 +01:00
FileNodePtr y_node = get_file_node ( y_file_id ) ;
2018-12-31 20:04:05 +01:00
if ( ! y_node ) {
return Status : : Error ( PSLICE ( ) < < " Can't merge files. Second id is invalid: " < < x_file_id < < " and " < < y_file_id ) ;
}
if ( x_file_id = = x_node - > upload_pause_ ) {
2019-01-10 22:12:51 +01:00
x_node - > set_upload_pause ( FileId ( ) ) ;
2018-12-31 20:04:05 +01:00
}
2018-01-30 21:04:22 +01:00
if ( x_node . get ( ) = = y_node . get ( ) ) {
2019-11-16 23:43:47 +01:00
LOG ( DEBUG ) < < " Files are already merged " ;
2018-12-31 20:04:05 +01:00
return x_node - > main_file_id_ ;
}
if ( y_file_id = = y_node - > upload_pause_ ) {
2019-01-10 22:12:51 +01:00
y_node - > set_upload_pause ( FileId ( ) ) ;
2018-12-31 20:04:05 +01:00
}
2019-02-14 12:20:40 +01:00
if ( x_node - > remote_ . full & & y_node - > remote_ . full & & ! x_node - > remote_ . full . value ( ) . is_web ( ) & &
2019-02-15 21:09:18 +01:00
! y_node - > remote_ . full . value ( ) . is_web ( ) & & y_node - > remote_ . is_full_alive & &
2020-03-31 01:16:23 +02:00
x_node - > remote_ . full_source = = FileLocationSource : : FromServer & &
y_node - > remote_ . full_source = = FileLocationSource : : FromServer & &
2019-02-14 12:20:40 +01:00
x_node - > remote_ . full . value ( ) . get_dc_id ( ) ! = y_node - > remote_ . full . value ( ) . get_dc_id ( ) ) {
2020-08-02 02:08:24 +02:00
LOG ( ERROR ) < < " File remote location was changed from " < < y_node - > remote_ . full . value ( ) < < " to "
< < x_node - > remote_ . full . value ( ) ;
2018-12-31 20:04:05 +01:00
}
2020-04-10 02:43:35 +02:00
bool drop_last_successful_force_reupload_time = x_node - > last_successful_force_reupload_time_ < = 0 & &
x_node - > remote_ . full & &
x_node - > remote_ . full_source = = FileLocationSource : : FromServer ;
2019-12-24 16:51:41 +01:00
auto count_local = [ ] ( auto & node ) {
return std : : accumulate ( node - > file_ids_ . begin ( ) , node - > file_ids_ . end ( ) , 0 ,
[ ] ( const auto & x , const auto & y ) { return x + ( y . get_remote ( ) ! = 0 ) ; } ) ;
} ;
if ( count_local ( x_node ) + count_local ( y_node ) > 100 ) {
}
2018-12-31 20:04:05 +01:00
2018-01-30 17:54:17 +01:00
FileNodePtr nodes [ ] = { x_node , y_node , x_node } ;
2018-01-30 21:04:22 +01:00
FileNodeId node_ids [ ] = { get_file_id_info ( x_file_id ) - > node_id_ , get_file_id_info ( y_file_id ) - > node_id_ } ;
2019-02-14 12:20:40 +01:00
int trusted_by_source = merge_choose_file_source_location ( x_node - > remote_ . full_source , y_node - > remote_ . full_source ) ;
2018-12-31 20:04:05 +01:00
2018-09-07 18:29:18 +02:00
int local_i = merge_choose_local_location ( x_node - > local_ , y_node - > local_ ) ;
2019-02-14 12:20:40 +01:00
int remote_i = merge_choose_remote_location ( x_node - > remote_ , y_node - > remote_ ) ;
2018-09-07 18:29:18 +02:00
int generate_i = merge_choose_generate_location ( x_node - > generate_ , y_node - > generate_ ) ;
2018-12-31 20:04:05 +01:00
int size_i = merge_choose_size ( x_node - > size_ , y_node - > size_ ) ;
int expected_size_i = merge_choose_expected_size ( x_node - > expected_size_ , y_node - > expected_size_ ) ;
2018-02-18 17:29:44 +01:00
int remote_name_i = merge_choose_name ( x_node - > remote_name_ , y_node - > remote_name_ ) ;
2018-12-31 20:04:05 +01:00
int url_i = merge_choose_name ( x_node - > url_ , y_node - > url_ ) ;
int owner_i = merge_choose_owner ( x_node - > owner_dialog_id_ , y_node - > owner_dialog_id_ ) ;
int encryption_key_i = merge_choose_encryption_key ( x_node - > encryption_key_ , y_node - > encryption_key_ ) ;
int main_file_id_i = merge_choose_main_file_id ( x_node - > main_file_id_ , x_node - > main_file_id_priority_ ,
y_node - > main_file_id_ , y_node - > main_file_id_priority_ ) ;
if ( size_i = = - 1 ) {
return Status : : Error ( PSLICE ( ) < < " Can't merge files. Different size: " < < x_node - > size_ < < " and "
< < y_node - > size_ ) ;
}
if ( encryption_key_i = = - 1 ) {
2019-02-14 12:20:40 +01:00
if ( nodes [ remote_i ] - > remote_ . full & & nodes [ local_i ] - > local_ . type ( ) ! = LocalFileLocation : : Type : : Partial ) {
2019-02-15 21:09:18 +01:00
LOG ( ERROR ) < < " Different encryption key in files, but lets choose same key as remote location " ;
2018-12-31 20:04:05 +01:00
encryption_key_i = remote_i ;
} else {
return Status : : Error ( " Can't merge files. Different encryption keys " ) ;
}
}
2019-07-18 18:47:29 +02:00
// prefer more trusted source
if ( remote_name_i = = 2 ) {
remote_name_i = trusted_by_source ;
}
if ( url_i = = 2 ) {
url_i = trusted_by_source ;
}
if ( expected_size_i = = 2 ) {
expected_size_i = trusted_by_source ;
2018-06-01 00:21:35 +02:00
}
2018-12-31 20:04:05 +01:00
2019-01-06 21:39:10 +01:00
int node_i =
std : : make_tuple ( y_node - > pmc_id_ . is_valid ( ) , x_node - > pmc_id_ , y_node - > file_ids_ . size ( ) , main_file_id_i = = 1 ) >
std : : make_tuple ( x_node - > pmc_id_ . is_valid ( ) , y_node - > pmc_id_ , x_node - > file_ids_ . size ( ) , main_file_id_i = = 0 ) ;
2018-12-31 20:04:05 +01:00
auto other_node_i = 1 - node_i ;
2018-01-30 17:54:17 +01:00
FileNodePtr node = nodes [ node_i ] ;
FileNodePtr other_node = nodes [ other_node_i ] ;
2018-12-31 20:04:05 +01:00
auto file_view = FileView ( node ) ;
2019-02-21 16:58:20 +01:00
LOG ( DEBUG ) < < " Have x_node->pmc_id_ = " < < x_node - > pmc_id_ . get ( ) < < " , y_node->pmc_id_ = " < < y_node - > pmc_id_ . get ( )
2018-06-05 01:40:00 +02:00
< < " , x_node_size = " < < x_node - > file_ids_ . size ( ) < < " , y_node_size = " < < y_node - > file_ids_ . size ( )
< < " , node_i = " < < node_i < < " , local_i = " < < local_i < < " , remote_i = " < < remote_i
< < " , generate_i = " < < generate_i < < " , size_i = " < < size_i < < " , remote_name_i = " < < remote_name_i
< < " , url_i = " < < url_i < < " , owner_i = " < < owner_i < < " , encryption_key_i = " < < encryption_key_i
2019-02-15 21:09:18 +01:00
< < " , main_file_id_i = " < < main_file_id_i < < " , trusted_by_source = " < < trusted_by_source
< < " , x_source = " < < x_node - > remote_ . full_source < < " , y_source = " < < y_node - > remote_ . full_source ;
2018-12-31 20:04:05 +01:00
if ( local_i = = other_node_i ) {
2019-01-25 02:52:38 +01:00
do_cancel_download ( node ) ;
2018-12-26 17:11:15 +01:00
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_ ) ;
2018-12-31 20:04:05 +01:00
node - > download_id_ = other_node - > download_id_ ;
2019-01-17 21:42:00 +01:00
node - > download_was_update_file_reference_ = other_node - > download_was_update_file_reference_ ;
2018-01-09 12:57:11 +01:00
node - > is_download_started_ | = other_node - > is_download_started_ ;
2018-12-31 20:04:05 +01:00
node - > set_download_priority ( other_node - > download_priority_ ) ;
other_node - > download_id_ = 0 ;
2019-01-17 21:42:00 +01:00
other_node - > download_was_update_file_reference_ = false ;
2018-01-09 12:57:11 +01:00
other_node - > is_download_started_ = false ;
2018-12-31 20:04:05 +01:00
other_node - > download_priority_ = 0 ;
2018-11-11 12:38:04 +01:00
other_node - > download_offset_ = 0 ;
2018-12-26 17:11:15 +01:00
other_node - > local_ready_prefix_size_ = 0 ;
2018-12-31 20:04:05 +01:00
2019-01-25 02:52:38 +01:00
//do_cancel_generate(node);
2018-02-04 18:27:05 +01:00
//node->set_generate_location(std::move(other_node->generate_));
2018-12-31 20:04:05 +01:00
//node->generate_id_ = other_node->generate_id_;
//node->set_generate_priority(other_node->generate_download_priority_, other_node->generate_upload_priority_);
//other_node->generate_id_ = 0;
//other_node->generate_was_update_ = false;
//other_node->generate_priority_ = 0;
//other_node->generate_download_priority_ = 0;
//other_node->generate_upload_priority_ = 0;
} else {
2019-01-25 02:52:38 +01:00
do_cancel_download ( other_node ) ;
//do_cancel_generate(other_node);
2018-12-31 20:04:05 +01:00
}
if ( remote_i = = other_node_i ) {
2019-01-25 02:52:38 +01:00
do_cancel_upload ( node ) ;
2019-02-14 12:20:40 +01:00
node - > set_new_remote_location ( std : : move ( other_node - > remote_ ) ) ;
2018-12-31 20:04:05 +01:00
node - > upload_id_ = other_node - > upload_id_ ;
2019-01-17 21:42:00 +01:00
node - > upload_was_update_file_reference_ = other_node - > upload_was_update_file_reference_ ;
2018-12-31 20:04:05 +01:00
node - > set_upload_priority ( other_node - > upload_priority_ ) ;
2019-01-10 22:12:51 +01:00
node - > set_upload_pause ( other_node - > upload_pause_ ) ;
2018-12-31 20:04:05 +01:00
other_node - > upload_id_ = 0 ;
2019-01-17 21:42:00 +01:00
other_node - > upload_was_update_file_reference_ = false ;
2018-12-31 20:04:05 +01:00
other_node - > upload_priority_ = 0 ;
2019-01-10 22:12:51 +01:00
other_node - > set_upload_pause ( FileId ( ) ) ;
2018-12-31 20:04:05 +01:00
} else {
2019-01-25 02:52:38 +01:00
do_cancel_upload ( other_node ) ;
2018-12-31 20:04:05 +01:00
}
if ( generate_i = = other_node_i ) {
2019-01-25 02:52:38 +01:00
do_cancel_generate ( node ) ;
2018-02-04 18:27:05 +01:00
node - > set_generate_location ( std : : move ( other_node - > generate_ ) ) ;
2018-12-31 20:04:05 +01:00
node - > generate_id_ = other_node - > generate_id_ ;
node - > set_generate_priority ( other_node - > generate_download_priority_ , other_node - > generate_upload_priority_ ) ;
other_node - > generate_id_ = 0 ;
other_node - > generate_priority_ = 0 ;
other_node - > generate_download_priority_ = 0 ;
other_node - > generate_upload_priority_ = 0 ;
} else {
2019-01-25 02:52:38 +01:00
do_cancel_generate ( other_node ) ;
2018-12-31 20:04:05 +01:00
}
if ( size_i = = other_node_i ) {
node - > set_size ( other_node - > size_ ) ;
}
if ( expected_size_i = = other_node_i ) {
node - > set_expected_size ( other_node - > expected_size_ ) ;
}
2018-02-18 17:29:44 +01:00
if ( remote_name_i = = other_node_i ) {
node - > set_remote_name ( other_node - > remote_name_ ) ;
2018-12-31 20:04:05 +01:00
}
if ( url_i = = other_node_i ) {
node - > set_url ( other_node - > url_ ) ;
}
if ( owner_i = = other_node_i ) {
node - > set_owner_dialog_id ( other_node - > owner_dialog_id_ ) ;
}
if ( encryption_key_i = = other_node_i ) {
node - > set_encryption_key ( other_node - > encryption_key_ ) ;
nodes [ node_i ] - > set_encryption_key ( nodes [ encryption_key_i ] - > encryption_key_ ) ;
}
node - > need_load_from_pmc_ | = other_node - > need_load_from_pmc_ ;
2018-02-26 11:05:14 +01:00
node - > can_search_locally_ & = other_node - > can_search_locally_ ;
2018-12-31 20:04:05 +01:00
2020-04-10 02:43:35 +02:00
if ( drop_last_successful_force_reupload_time ) {
node - > last_successful_force_reupload_time_ = - 1e10 ;
} else if ( other_node - > last_successful_force_reupload_time_ > node - > last_successful_force_reupload_time_ ) {
2019-11-16 18:09:27 +01:00
node - > last_successful_force_reupload_time_ = other_node - > last_successful_force_reupload_time_ ;
}
2018-12-31 20:04:05 +01:00
if ( main_file_id_i = = other_node_i ) {
2019-01-30 22:37:38 +01:00
context_ - > on_merge_files ( other_node - > main_file_id_ , node - > main_file_id_ ) ;
2018-12-31 20:04:05 +01:00
node - > main_file_id_ = other_node - > main_file_id_ ;
node - > main_file_id_priority_ = other_node - > main_file_id_priority_ ;
2019-01-17 21:42:00 +01:00
} else {
2019-01-30 22:37:38 +01:00
context_ - > on_merge_files ( node - > main_file_id_ , other_node - > main_file_id_ ) ;
2018-12-31 20:04:05 +01:00
}
bool send_updates_flag = false ;
2018-01-30 21:04:22 +01:00
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 ( ) ) ;
2018-12-31 20:04:05 +01:00
for ( auto file_id : other_node - > file_ids_ ) {
auto file_id_info = get_file_id_info ( file_id ) ;
2019-02-12 17:17:20 +01:00
LOG_CHECK ( file_id_info - > node_id_ = = node_ids [ other_node_i ] )
2018-01-28 21:38:55 +01:00
< < node_ids [ node_i ] < < " " < < node_ids [ other_node_i ] < < " " < < file_id < < " " < < file_id_info - > node_id_ ;
2018-12-31 20:04:05 +01:00
file_id_info - > node_id_ = node_ids [ node_i ] ;
send_updates_flag | = file_id_info - > send_updates_flag_ ;
}
2020-08-02 00:28:01 +02:00
other_node = { } ;
2018-12-31 20:04:05 +01:00
if ( send_updates_flag ) {
// node might not changed, but other_node might changed, so we need to send update anyway
VLOG ( update_file ) < < " File " < < node - > main_file_id_ < < " has been merged " ;
node - > on_info_changed ( ) ;
}
// Check is some download/upload queries are ready
2018-02-01 15:12:32 +01:00
for ( auto file_id : vector < FileId > ( node - > file_ids_ ) ) {
2018-12-31 20:04:05 +01:00
auto * info = get_file_id_info ( file_id ) ;
if ( info - > download_priority_ ! = 0 & & file_view . has_local_location ( ) ) {
info - > download_priority_ = 0 ;
if ( info - > download_callback_ ) {
info - > download_callback_ - > on_download_ok ( file_id ) ;
info - > download_callback_ . reset ( ) ;
}
}
2019-02-15 10:25:21 +01:00
if ( info - > upload_priority_ ! = 0 & & file_view . has_active_upload_remote_location ( ) ) {
2018-12-31 20:04:05 +01:00
info - > upload_priority_ = 0 ;
if ( info - > upload_callback_ ) {
info - > upload_callback_ - > on_upload_ok ( file_id , nullptr ) ;
info - > upload_callback_ . reset ( ) ;
}
}
}
2020-05-23 21:27:24 +02:00
file_nodes_ . erase ( node_ids [ other_node_i ] ) ;
2018-12-31 20:04:05 +01:00
run_generate ( node ) ;
run_download ( node ) ;
run_upload ( node , { } ) ;
2019-01-06 21:39:10 +01:00
if ( other_pmc_id . is_valid ( ) ) {
2018-12-31 20:04:05 +01:00
// node might not changed, but we need to merge nodes in pmc anyway
node - > on_pmc_changed ( ) ;
}
2018-12-27 18:23:19 +01:00
try_flush_node_full ( node , node_i ! = remote_i , node_i ! = local_i , node_i ! = generate_i , other_pmc_id ) ;
2018-12-31 20:04:05 +01:00
return node - > main_file_id_ ;
}
2018-12-05 10:32:31 +01:00
void FileManager : : add_file_source ( FileId file_id , FileSourceId file_source_id ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
return add_file_source_internal ( file_id , file_source_id ) ;
}
void FileManager : : add_file_source_internal ( FileId file_id , FileSourceId file_source_id ) {
2018-12-05 10:32:31 +01:00
auto node = get_file_node ( file_id ) ;
if ( ! node ) {
return ;
}
2019-01-17 21:42:00 +01:00
2019-01-18 23:19:15 +01:00
CHECK ( file_source_id . is_valid ( ) ) ;
2019-01-30 22:37:38 +01:00
if ( context_ - > add_file_source ( node - > main_file_id_ , file_source_id ) ) {
node - > on_pmc_changed ( ) ;
try_flush_node_pmc ( node , " add_file_source " ) ;
}
2018-12-05 10:32:31 +01:00
}
void FileManager : : remove_file_source ( FileId file_id , FileSourceId file_source_id ) {
auto node = get_file_node ( file_id ) ;
if ( ! node ) {
return ;
}
2019-01-18 23:19:15 +01:00
CHECK ( file_source_id . is_valid ( ) ) ;
2019-01-30 22:37:38 +01:00
if ( context_ - > remove_file_source ( node - > main_file_id_ , file_source_id ) ) {
node - > on_pmc_changed ( ) ;
try_flush_node_pmc ( node , " remove_file_source " ) ;
}
2018-12-05 10:32:31 +01:00
}
2019-01-18 21:12:09 +01:00
void FileManager : : change_files_source ( FileSourceId file_source_id , const vector < FileId > & old_file_ids ,
const vector < FileId > & new_file_ids ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2019-01-18 21:40:23 +01:00
if ( old_file_ids = = new_file_ids ) {
return ;
}
2019-01-18 23:19:15 +01:00
CHECK ( file_source_id . is_valid ( ) ) ;
2019-01-18 21:40:23 +01:00
2019-01-18 21:12:09 +01:00
auto old_main_file_ids = get_main_file_ids ( old_file_ids ) ;
auto new_main_file_ids = get_main_file_ids ( new_file_ids ) ;
for ( auto file_id : old_main_file_ids ) {
auto it = new_main_file_ids . find ( file_id ) ;
if ( it = = new_main_file_ids . end ( ) ) {
2019-01-29 12:07:58 +01:00
remove_file_source ( file_id , file_source_id ) ;
2019-01-18 21:12:09 +01:00
} else {
new_main_file_ids . erase ( it ) ;
}
}
for ( auto file_id : new_main_file_ids ) {
2020-08-02 00:28:01 +02:00
add_file_source_internal ( file_id , file_source_id ) ;
2019-01-18 21:12:09 +01:00
}
}
2020-07-04 11:00:14 +02:00
void FileManager : : on_file_reference_repaired ( FileId file_id , FileSourceId file_source_id , Result < Unit > & & result ,
Promise < Unit > & & promise ) {
auto file_view = get_file_view ( file_id ) ;
CHECK ( ! file_view . empty ( ) ) ;
if ( result . is_ok ( ) & &
( ! file_view . has_active_upload_remote_location ( ) | | ! file_view . has_active_download_remote_location ( ) ) ) {
result = Status : : Error ( " No active remote location " ) ;
}
if ( result . is_error ( ) & & result . error ( ) . code ( ) ! = 429 & & result . error ( ) . code ( ) < 500 ) {
VLOG ( file_references ) < < " Invalid " < < file_source_id < < " " < < result . error ( ) ;
remove_file_source ( file_id , file_source_id ) ;
}
promise . set_result ( std : : move ( result ) ) ;
}
2019-01-18 21:12:09 +01:00
std : : unordered_set < FileId , FileIdHash > FileManager : : get_main_file_ids ( const vector < FileId > & file_ids ) {
std : : unordered_set < FileId , FileIdHash > result ;
for ( auto file_id : file_ids ) {
auto node = get_file_node ( file_id ) ;
if ( node ) {
result . insert ( node - > main_file_id_ ) ;
}
}
return result ;
}
2018-12-27 18:23:19 +01:00
void FileManager : : try_flush_node_full ( FileNodePtr node , bool new_remote , bool new_local , bool new_generate ,
FileDbId other_pmc_id ) {
2018-12-31 20:04:05 +01:00
if ( node - > need_pmc_flush ( ) ) {
if ( file_db_ ) {
2018-01-30 21:04:22 +01:00
load_from_pmc ( node , true , true , true ) ;
2019-01-30 22:37:38 +01:00
flush_to_pmc ( node , new_remote , new_local , new_generate , " try_flush_node_full " ) ;
2019-01-06 21:39:10 +01:00
if ( other_pmc_id . is_valid ( ) & & node - > pmc_id_ ! = other_pmc_id ) {
2018-12-31 20:04:05 +01:00
file_db_ - > set_file_data_ref ( other_pmc_id , node - > pmc_id_ ) ;
}
}
node - > on_pmc_flushed ( ) ;
}
2018-12-27 18:23:19 +01:00
try_flush_node_info ( node , " try_flush_node_full " ) ;
2018-12-31 20:04:05 +01:00
}
2018-12-27 18:23:19 +01:00
void FileManager : : try_flush_node ( FileNodePtr node , const char * source ) {
2019-01-30 17:40:23 +01:00
try_flush_node_pmc ( node , source ) ;
try_flush_node_info ( node , source ) ;
}
void FileManager : : try_flush_node_pmc ( FileNodePtr node , const char * source ) {
2018-12-27 18:23:19 +01:00
if ( node - > need_pmc_flush ( ) ) {
if ( file_db_ ) {
load_from_pmc ( node , true , true , true ) ;
2019-01-30 22:37:38 +01:00
flush_to_pmc ( node , false , false , false , source ) ;
2018-12-27 18:23:19 +01:00
}
node - > on_pmc_flushed ( ) ;
}
}
void FileManager : : try_flush_node_info ( FileNodePtr node , const char * source ) {
2018-12-31 20:04:05 +01:00
if ( node - > need_info_flush ( ) ) {
2018-02-01 15:12:32 +01:00
for ( auto file_id : vector < FileId > ( node - > file_ids_ ) ) {
2018-12-31 20:04:05 +01:00
auto * info = get_file_id_info ( file_id ) ;
if ( info - > send_updates_flag_ ) {
2018-12-27 18:23:19 +01:00
VLOG ( update_file ) < < " Send UpdateFile about file " < < file_id < < " from " < < source ;
2018-12-31 20:04:05 +01:00
context_ - > on_file_updated ( file_id ) ;
}
}
node - > on_info_flushed ( ) ;
}
}
2018-01-30 17:54:17 +01:00
void FileManager : : clear_from_pmc ( FileNodePtr node ) {
2018-12-31 20:04:05 +01:00
if ( ! file_db_ ) {
return ;
}
2019-01-06 21:39:10 +01:00
if ( node - > pmc_id_ . empty ( ) ) {
2018-12-31 20:04:05 +01:00
return ;
}
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 ( ) ) {
data . local_ = node - > local_ ;
}
if ( file_view . has_remote_location ( ) ) {
2019-02-14 12:20:40 +01:00
data . remote_ = RemoteFileLocation ( * node - > remote_ . full ) ;
2018-12-31 20:04:05 +01:00
}
if ( file_view . has_generate_location ( ) ) {
2018-09-27 03:19:03 +02:00
data . generate_ = make_unique < FullGenerateFileLocation > ( * node - > generate_ ) ;
2018-12-31 20:04:05 +01:00
}
file_db_ - > clear_file_data ( node - > pmc_id_ , data ) ;
2019-01-06 21:39:10 +01:00
node - > pmc_id_ = FileDbId ( ) ;
2018-12-31 20:04:05 +01:00
}
2019-01-30 22:37:38 +01:00
void FileManager : : flush_to_pmc ( FileNodePtr node , bool new_remote , bool new_local , bool new_generate ,
const char * source ) {
2018-12-31 20:04:05 +01:00
if ( ! file_db_ ) {
return ;
}
FileView view ( node ) ;
bool create_flag = false ;
2019-01-06 21:39:10 +01:00
if ( node - > pmc_id_ . empty ( ) ) {
2018-12-31 20:04:05 +01:00
create_flag = true ;
node - > pmc_id_ = file_db_ - > create_pmc_id ( ) ;
}
FileData data ;
2019-01-06 21:39:10 +01:00
data . pmc_id_ = node - > pmc_id_ . get ( ) ;
2018-12-31 20:04:05 +01:00
data . local_ = node - > local_ ;
2018-01-20 15:57:52 +01:00
if ( data . local_ . type ( ) = = LocalFileLocation : : Type : : Full ) {
prepare_path_for_pmc ( data . local_ . full ( ) . file_type_ , data . local_ . full ( ) . path_ ) ;
2018-12-31 20:04:05 +01:00
}
2019-02-14 22:19:48 +01:00
if ( node - > remote_ . full ) {
2019-02-14 12:20:40 +01:00
data . remote_ = RemoteFileLocation ( node - > remote_ . full . value ( ) ) ;
} else if ( node - > remote_ . partial ) {
data . remote_ = RemoteFileLocation ( * node - > remote_ . partial ) ;
}
2018-02-04 18:27:05 +01:00
if ( node - > generate_ ! = nullptr & & ! begins_with ( node - > generate_ - > conversion_ , " #file_id# " ) ) {
2018-09-27 03:19:03 +02:00
data . generate_ = make_unique < FullGenerateFileLocation > ( * node - > generate_ ) ;
2018-12-31 20:04:05 +01:00
}
2018-09-27 20:14:32 +02:00
// TODO: not needed when GenerateLocation has constant conversion
2018-01-20 15:57:52 +01:00
if ( data . remote_ . type ( ) ! = RemoteFileLocation : : Type : : Full & & data . local_ . type ( ) ! = LocalFileLocation : : Type : : Full ) {
2018-12-31 20:04:05 +01:00
data . local_ = LocalFileLocation ( ) ;
data . remote_ = RemoteFileLocation ( ) ;
}
2018-04-03 19:49:07 +02:00
if ( data . remote_ . type ( ) ! = RemoteFileLocation : : Type : : Full & & node - > encryption_key_ . is_secure ( ) ) {
data . remote_ = RemoteFileLocation ( ) ;
}
2018-12-31 20:04:05 +01:00
data . size_ = node - > size_ ;
data . expected_size_ = node - > expected_size_ ;
2018-02-18 17:29:44 +01:00
data . remote_name_ = node - > remote_name_ ;
2018-12-31 20:04:05 +01:00
data . encryption_key_ = node - > encryption_key_ ;
data . url_ = node - > url_ ;
data . owner_dialog_id_ = node - > owner_dialog_id_ ;
2019-01-30 22:37:38 +01:00
data . file_source_ids_ = context_ - > get_some_file_sources ( view . file_id ( ) ) ;
2019-01-31 00:57:14 +01:00
VLOG ( file_references ) < < " Save file " < < view . file_id ( ) < < " to database with " < < data . file_source_ids_ < < " from "
2019-01-30 22:37:38 +01:00
< < source ;
2018-12-31 20:04:05 +01:00
file_db_ - > set_file_data ( node - > pmc_id_ , data , ( create_flag | | new_remote ) , ( create_flag | | new_local ) ,
( create_flag | | new_generate ) ) ;
}
2018-01-30 21:04:22 +01:00
FileNode * FileManager : : get_file_node_raw ( FileId file_id , FileNodeId * file_node_id ) {
2020-05-23 21:27:24 +02:00
if ( file_id . get ( ) < = 0 ) {
2018-12-31 20:04:05 +01:00
return nullptr ;
}
FileNodeId node_id = file_id_info_ [ file_id . get ( ) ] . node_id_ ;
if ( node_id = = 0 ) {
return nullptr ;
}
if ( file_node_id ! = nullptr ) {
* file_node_id = node_id ;
}
2020-08-02 00:28:01 +02:00
return file_nodes_ [ node_id ] . get ( ) ;
2018-12-31 20:04:05 +01:00
}
2018-01-30 21:04:22 +01:00
FileNodePtr FileManager : : get_sync_file_node ( FileId file_id ) {
auto file_node = get_file_node ( file_id ) ;
2018-12-31 20:04:05 +01:00
if ( ! file_node ) {
2020-08-02 02:08:24 +02:00
return { } ;
2018-12-31 20:04:05 +01:00
}
2018-01-30 21:04:22 +01:00
load_from_pmc ( file_node , true , true , true ) ;
return file_node ;
2018-12-31 20:04:05 +01:00
}
2018-01-30 21:04:22 +01:00
void FileManager : : load_from_pmc ( FileNodePtr node , bool new_remote , bool new_local , bool new_generate ) {
2018-12-31 20:04:05 +01:00
if ( ! node - > need_load_from_pmc_ ) {
2018-01-30 21:04:22 +01:00
return ;
2018-12-31 20:04:05 +01:00
}
auto file_id = node - > main_file_id_ ;
node - > need_load_from_pmc_ = false ;
if ( ! file_db_ ) {
2018-01-30 21:04:22 +01:00
return ;
2018-12-31 20:04:05 +01:00
}
auto file_view = get_file_view ( file_id ) ;
FullRemoteFileLocation remote ;
FullLocalFileLocation local ;
FullGenerateFileLocation generate ;
new_remote & = file_view . has_remote_location ( ) ;
if ( new_remote ) {
remote = file_view . remote_location ( ) ;
}
new_local & = file_view . has_local_location ( ) ;
if ( new_local ) {
local = get_file_view ( file_id ) . local_location ( ) ;
2018-01-20 15:57:52 +01:00
prepare_path_for_pmc ( local . file_type_ , local . path_ ) ;
2018-12-31 20:04:05 +01:00
}
new_generate & = file_view . has_generate_location ( ) ;
if ( new_generate ) {
generate = file_view . generate_location ( ) ;
}
2018-06-05 01:40:00 +02:00
LOG ( DEBUG ) < < " Load from pmc " < < file_id < < " / " < < file_view . file_id ( ) < < " , new_remote = " < < new_remote
< < " , new_local = " < < new_local < < " , new_generate = " < < new_generate ;
2018-12-31 20:04:05 +01:00
auto load = [ & ] ( auto location ) {
TRY_RESULT ( file_data , file_db_ - > get_file_data_sync ( location ) ) ;
2019-02-15 21:09:18 +01:00
TRY_RESULT ( new_file_id ,
register_file ( std : : move ( file_data ) , FileLocationSource : : FromDatabase , " load_from_pmc " , false ) ) ;
2020-08-02 00:28:01 +02:00
TRY_RESULT ( main_file_id , merge_internal ( file_id , new_file_id ) ) ;
2018-01-25 14:11:05 +01:00
file_id = main_file_id ;
2018-12-31 20:04:05 +01:00
return Status : : OK ( ) ;
} ;
if ( new_remote ) {
2019-04-28 14:00:06 +02:00
load ( remote ) . ignore ( ) ;
2018-12-31 20:04:05 +01:00
}
if ( new_local ) {
2019-04-28 14:00:06 +02:00
load ( local ) . ignore ( ) ;
2018-12-31 20:04:05 +01:00
}
if ( new_generate ) {
2019-04-28 14:00:06 +02:00
load ( generate ) . ignore ( ) ;
2018-12-31 20:04:05 +01:00
}
}
bool FileManager : : set_encryption_key ( FileId file_id , FileEncryptionKey key ) {
auto node = get_sync_file_node ( file_id ) ;
if ( ! node ) {
return false ;
}
auto view = FileView ( node ) ;
if ( view . has_local_location ( ) & & view . has_remote_location ( ) ) {
return false ;
}
if ( ! node - > encryption_key_ . empty ( ) ) {
return false ;
}
node - > set_encryption_key ( std : : move ( key ) ) ;
2019-01-30 17:40:23 +01:00
try_flush_node_pmc ( node , " set_encryption_key " ) ;
2018-12-31 20:04:05 +01:00
return true ;
}
bool FileManager : : set_content ( FileId file_id , BufferSlice bytes ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-06-24 22:48:48 +02:00
if ( G ( ) - > shared_config ( ) . get_option_boolean ( " ignore_inline_thumbnails " ) ) {
return false ;
}
2018-12-31 20:04:05 +01:00
auto node = get_sync_file_node ( file_id ) ;
if ( ! node ) {
return false ;
}
2018-01-20 15:57:52 +01:00
if ( node - > local_ . type ( ) = = LocalFileLocation : : Type : : Full ) {
2018-12-31 20:04:05 +01:00
// There was no download so we don't need an update
return true ;
}
if ( node - > download_priority_ = = FROM_BYTES_PRIORITY ) {
return true ;
}
2019-01-25 02:52:38 +01:00
do_cancel_download ( node ) ;
2018-12-31 20:04:05 +01:00
auto * file_info = get_file_id_info ( file_id ) ;
file_info - > download_priority_ = FROM_BYTES_PRIORITY ;
node - > set_download_priority ( FROM_BYTES_PRIORITY ) ;
2019-12-23 15:32:03 +01:00
QueryId id = queries_container_ . create ( Query { file_id , Query : : Type : : SetContent } ) ;
2018-12-31 20:04:05 +01:00
node - > download_id_ = id ;
2018-01-09 12:57:11 +01:00
node - > is_download_started_ = true ;
2019-02-14 12:20:40 +01:00
send_closure ( file_load_manager_ , & FileLoadManager : : from_bytes , id , node - > remote_ . full . value ( ) . file_type_ ,
std : : move ( bytes ) , node - > suggested_name ( ) ) ;
2018-12-31 20:04:05 +01:00
return true ;
}
void FileManager : : get_content ( FileId file_id , Promise < BufferSlice > promise ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-12-31 20:04:05 +01:00
auto node = get_sync_file_node ( file_id ) ;
if ( ! node ) {
return promise . set_error ( Status : : Error ( " Unknown file_id " ) ) ;
}
auto status = check_local_location ( node ) ;
status . ignore ( ) ;
auto file_view = FileView ( node ) ;
if ( ! file_view . has_local_location ( ) ) {
return promise . set_error ( Status : : Error ( " No local location " ) ) ;
}
send_closure ( file_load_manager_ , & FileLoadManager : : get_content , node - > local_ . full ( ) , std : : move ( promise ) ) ;
}
2019-04-26 00:03:31 +02:00
void FileManager : : read_file_part ( FileId file_id , int32 offset , int32 count , int left_tries ,
Promise < td_api : : object_ptr < td_api : : filePart > > promise ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2019-04-26 00:03:31 +02:00
if ( G ( ) - > close_flag ( ) ) {
return promise . set_error ( Status : : Error ( 500 , " Request aborted " ) ) ;
}
if ( ! file_id . is_valid ( ) ) {
2020-04-19 12:45:37 +02:00
return promise . set_error ( Status : : Error ( 400 , " File identifier is invalid " ) ) ;
2019-04-26 00:03:31 +02:00
}
auto node = get_sync_file_node ( file_id ) ;
if ( ! node ) {
return promise . set_error ( Status : : Error ( 400 , " File not found " ) ) ;
}
if ( offset < 0 ) {
return promise . set_error ( Status : : Error ( 400 , " Parameter offset must be non-negative " ) ) ;
}
2019-04-27 16:14:45 +02:00
if ( count < 0 ) {
return promise . set_error ( Status : : Error ( 400 , " Parameter count must be non-negative " ) ) ;
2019-04-26 00:03:31 +02:00
}
auto file_view = FileView ( node ) ;
2019-04-27 16:14:45 +02:00
if ( count = = 0 ) {
count = narrow_cast < int32 > ( file_view . downloaded_prefix ( offset ) ) ;
if ( count = = 0 ) {
return promise . set_value ( td_api : : make_object < td_api : : filePart > ( ) ) ;
}
} else if ( file_view . downloaded_prefix ( offset ) < static_cast < int64 > ( count ) ) {
// TODO this check is safer to do in another thread
2019-04-26 00:03:31 +02:00
return promise . set_error ( Status : : Error ( 400 , " There is not enough downloaded bytes in the file to read " ) ) ;
}
const string * path = nullptr ;
bool is_partial = false ;
if ( file_view . has_local_location ( ) ) {
path = & file_view . 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 " ) ) ;
}
} else {
CHECK ( node - > local_ . type ( ) = = LocalFileLocation : : Type : : Partial ) ;
path = & node - > local_ . partial ( ) . path_ ;
is_partial = true ;
}
// TODO move file reading to another thread
auto r_bytes = [ & ] ( ) - > Result < string > {
TRY_RESULT ( fd , FileFd : : open ( * path , FileFd : : Read ) ) ;
string data ;
data . resize ( count ) ;
TRY_RESULT ( read_bytes , fd . pread ( data , offset ) ) ;
if ( read_bytes ! = static_cast < size_t > ( count ) ) {
return Status : : Error ( " Read less bytes than expected " ) ;
}
return std : : move ( data ) ;
} ( ) ;
if ( r_bytes . is_error ( ) ) {
LOG ( INFO ) < < " Failed to read file bytes: " < < r_bytes . error ( ) ;
if ( - - left_tries = = 0 | | ! is_partial ) {
return promise . set_error ( Status : : Error ( 400 , " Failed to read the file " ) ) ;
}
// the temporary file could be moved from temp to persistent folder
// we need to wait for the corresponding update and repeat the reading
create_actor < SleepActor > ( " RepeatReadFilePartActor " , 0.01 ,
PromiseCreator : : lambda ( [ actor_id = actor_id ( this ) , file_id , offset , count , left_tries ,
promise = std : : move ( promise ) ] ( Result < Unit > result ) mutable {
send_closure ( actor_id , & FileManager : : read_file_part , file_id , offset , count , left_tries ,
std : : move ( promise ) ) ;
} ) )
. release ( ) ;
return ;
}
auto result = td_api : : make_object < td_api : : filePart > ( ) ;
result - > data_ = r_bytes . move_as_ok ( ) ;
promise . set_value ( std : : move ( result ) ) ;
}
2018-12-31 20:04:05 +01:00
void FileManager : : delete_file ( FileId file_id , Promise < Unit > promise , const char * source ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-12-31 20:04:05 +01:00
LOG ( INFO ) < < " Trying to delete file " < < file_id < < " from " < < source ;
auto node = get_sync_file_node ( file_id ) ;
if ( ! node ) {
return promise . set_value ( Unit ( ) ) ;
}
auto file_view = FileView ( node ) ;
2019-01-18 23:32:05 +01:00
// TODO review delete condition
2018-12-31 20:04:05 +01:00
if ( file_view . has_local_location ( ) ) {
if ( begins_with ( file_view . local_location ( ) . path_ , get_files_dir ( file_view . get_type ( ) ) ) ) {
2018-01-05 15:45:17 +01:00
LOG ( INFO ) < < " Unlink file " < < file_id < < " at " < < file_view . local_location ( ) . path_ ;
2018-12-31 20:04:05 +01:00
clear_from_pmc ( node ) ;
2020-02-19 15:57:30 +01:00
context_ - > on_new_file ( - file_view . size ( ) , - file_view . get_allocated_local_size ( ) , - 1 ) ;
2018-12-31 20:04:05 +01:00
unlink ( file_view . local_location ( ) . path_ ) . ignore ( ) ;
2018-12-26 17:11:15 +01:00
node - > drop_local_location ( ) ;
2018-12-27 18:23:19 +01:00
try_flush_node ( node , " delete_file 1 " ) ;
2018-12-31 20:04:05 +01:00
}
} else {
if ( file_view . get_type ( ) = = FileType : : Encrypted ) {
clear_from_pmc ( node ) ;
}
2018-01-20 15:57:52 +01:00
if ( node - > local_ . type ( ) = = LocalFileLocation : : Type : : Partial ) {
2018-01-05 15:45:17 +01:00
LOG ( INFO ) < < " Unlink partial file " < < file_id < < " at " < < node - > local_ . partial ( ) . path_ ;
2018-12-31 20:04:05 +01:00
unlink ( node - > local_ . partial ( ) . path_ ) . ignore ( ) ;
2018-12-26 17:11:15 +01:00
node - > drop_local_location ( ) ;
2018-12-27 18:23:19 +01:00
try_flush_node ( node , " delete_file 2 " ) ;
2018-12-31 20:04:05 +01:00
}
}
promise . set_value ( Unit ( ) ) ;
}
2019-02-18 20:08:05 +01:00
void FileManager : : download ( FileId file_id , std : : shared_ptr < DownloadCallback > callback , int32 new_priority , int64 offset ,
int64 limit ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-04-24 19:10:12 +02:00
LOG ( INFO ) < < " Download file " < < file_id < < " with priority " < < new_priority ;
2018-12-31 20:04:05 +01:00
auto node = get_sync_file_node ( file_id ) ;
if ( ! node ) {
2018-04-24 19:10:12 +02:00
LOG ( INFO ) < < " File " < < file_id < < " not found " ;
2018-12-31 20:04:05 +01:00
if ( callback ) {
callback - > on_download_error ( file_id , Status : : Error ( " File not found " ) ) ;
}
return ;
}
2018-01-20 15:57:52 +01:00
if ( node - > local_ . type ( ) = = LocalFileLocation : : Type : : Full ) {
2018-12-31 20:04:05 +01:00
auto status = check_local_location ( node ) ;
if ( status . is_error ( ) ) {
LOG ( WARNING ) < < " Need to redownload file " < < file_id < < " : " < < status . error ( ) ;
} else {
2018-04-24 19:10:12 +02:00
LOG ( INFO ) < < " File " < < file_id < < " is already downloaded " ;
2018-12-31 20:04:05 +01:00
if ( callback ) {
callback - > on_download_ok ( file_id ) ;
}
return ;
}
2018-01-20 15:57:52 +01:00
} else if ( node - > local_ . type ( ) = = LocalFileLocation : : Type : : Partial ) {
2018-12-31 20:04:05 +01:00
auto status = check_local_location ( node ) ;
if ( status . is_error ( ) ) {
LOG ( WARNING ) < < " Need to download file " < < file_id < < " from beginning: " < < status . error ( ) ;
}
}
FileView file_view ( node ) ;
if ( ! file_view . can_download_from_server ( ) & & ! file_view . can_generate ( ) ) {
2018-04-24 19:10:12 +02:00
LOG ( INFO ) < < " File " < < file_id < < " can't be downloaded " ;
2018-12-31 20:04:05 +01:00
if ( callback ) {
callback - > on_download_error ( file_id , Status : : Error ( " Can't download or generate file " ) ) ;
}
return ;
}
2018-01-16 15:41:47 +01:00
if ( new_priority = = - 1 ) {
if ( node - > is_download_started_ ) {
2018-04-24 19:10:12 +02:00
LOG ( INFO ) < < " File " < < file_id < < " is being downloaded " ;
2018-01-16 15:41:47 +01:00
return ;
}
new_priority = 0 ;
}
2018-04-24 19:10:12 +02:00
LOG ( INFO ) < < " Change download priority of file " < < file_id < < " to " < < new_priority ;
2018-11-11 12:38:04 +01:00
node - > set_download_offset ( offset ) ;
2019-02-18 20:08:05 +01:00
node - > set_download_limit ( limit ) ;
2018-12-31 20:04:05 +01:00
auto * file_info = get_file_id_info ( file_id ) ;
CHECK ( new_priority = = 0 | | callback ) ;
2019-03-27 19:43:46 +01:00
if ( file_info - > download_callback_ ! = nullptr & & file_info - > download_callback_ . get ( ) ! = callback . get ( ) ) {
// the callback will be destroyed soon and lost forever
// this would be an error and should never happen, unless we cancel previous download query
// in that case we send an error to the callback
CHECK ( new_priority = = 0 ) ;
file_info - > download_callback_ - > on_download_error ( file_id , Status : : Error ( 200 , " Cancelled " ) ) ;
}
2018-01-20 12:47:53 +01:00
file_info - > download_priority_ = narrow_cast < int8 > ( new_priority ) ;
2018-12-31 20:04:05 +01:00
file_info - > download_callback_ = std : : move ( callback ) ;
// TODO: send current progress?
run_generate ( node ) ;
run_download ( node ) ;
2018-12-27 18:23:19 +01:00
try_flush_node ( node , " download " ) ;
2018-12-31 20:04:05 +01:00
}
2018-01-30 17:54:17 +01:00
void FileManager : : run_download ( FileNodePtr node ) {
2018-01-20 12:47:53 +01:00
int8 priority = 0 ;
2018-12-31 20:04:05 +01:00
for ( auto id : node - > file_ids_ ) {
auto * info = get_file_id_info ( id ) ;
if ( info - > download_priority_ > priority ) {
priority = info - > download_priority_ ;
}
}
auto old_priority = node - > download_priority_ ;
if ( priority = = 0 ) {
2020-04-09 11:53:00 +02:00
node - > set_download_priority ( priority ) ;
2019-10-18 03:31:28 +02:00
LOG ( INFO ) < < " Cancel downloading of file " < < node - > main_file_id_ ;
2018-12-31 20:04:05 +01:00
if ( old_priority ! = 0 ) {
2019-01-25 02:52:38 +01:00
do_cancel_download ( node ) ;
2018-12-31 20:04:05 +01:00
}
return ;
}
2020-04-09 11:53:00 +02:00
if ( node - > need_load_from_pmc_ ) {
LOG ( INFO ) < < " Skip run_download, because file " < < node - > main_file_id_ < < " needs to be loaded from PMC " ;
return ;
}
if ( node - > generate_id_ ) {
LOG ( INFO ) < < " Skip run_download, because file " < < node - > main_file_id_ < < " is being generated " ;
return ;
}
auto file_view = FileView ( node ) ;
if ( ! file_view . can_download_from_server ( ) ) {
LOG ( INFO ) < < " Skip run_download, because file " < < node - > main_file_id_ < < " can't be downloaded from server " ;
return ;
}
node - > set_download_priority ( priority ) ;
2018-11-11 12:38:04 +01:00
bool need_update_offset = node - > is_download_offset_dirty_ ;
node - > is_download_offset_dirty_ = false ;
2018-12-31 20:04:05 +01:00
2019-02-18 20:08:05 +01:00
bool need_update_limit = node - > is_download_limit_dirty_ ;
node - > is_download_limit_dirty_ = false ;
2018-12-31 20:04:05 +01:00
if ( old_priority ! = 0 ) {
2019-10-18 03:31:28 +02:00
LOG ( INFO ) < < " Update download offset and limits of file " < < node - > main_file_id_ ;
2018-12-31 20:04:05 +01:00
CHECK ( node - > download_id_ ! = 0 ) ;
send_closure ( file_load_manager_ , & FileLoadManager : : update_priority , node - > download_id_ , priority ) ;
2019-02-18 20:08:05 +01:00
if ( need_update_limit ) {
auto download_limit = node - > download_limit_ ;
send_closure ( file_load_manager_ , & FileLoadManager : : update_download_limit , node - > download_id_ , download_limit ) ;
}
2018-11-11 12:38:04 +01:00
if ( need_update_offset ) {
2018-12-27 23:48:21 +01:00
auto download_offset = file_view . is_encrypted_any ( ) ? 0 : node - > download_offset_ ;
send_closure ( file_load_manager_ , & FileLoadManager : : update_download_offset , node - > download_id_ , download_offset ) ;
2018-11-11 12:38:04 +01:00
}
2018-12-31 20:04:05 +01:00
return ;
}
CHECK ( node - > download_id_ = = 0 ) ;
CHECK ( ! node - > file_ids_ . empty ( ) ) ;
2019-01-17 21:42:00 +01:00
auto file_id = node - > main_file_id_ ;
2018-12-05 10:32:31 +01:00
2019-07-30 16:42:36 +02:00
if ( node - > need_reload_photo_ & & file_view . may_reload_photo ( ) ) {
2019-10-18 03:31:28 +02:00
LOG ( INFO ) < < " Reload photo from file " < < node - > main_file_id_ ;
2019-12-23 15:32:03 +01:00
QueryId id = queries_container_ . create ( Query { file_id , Query : : Type : : DownloadReloadDialog } ) ;
2019-07-30 16:42:36 +02:00
node - > download_id_ = id ;
context_ - > reload_photo ( file_view . remote_location ( ) . get_source ( ) ,
PromiseCreator : : lambda ( [ id , actor_id = actor_id ( this ) , file_id ] ( Result < Unit > res ) {
Status error ;
if ( res . is_ok ( ) ) {
error = Status : : Error ( " FILE_DOWNLOAD_ID_INVALID " ) ;
} else {
error = res . move_as_error ( ) ;
}
VLOG ( file_references )
< < " Got result from reload photo for file " < < file_id < < " : " < < error ;
send_closure ( actor_id , & FileManager : : on_error , id , std : : move ( error ) ) ;
} ) ) ;
node - > need_reload_photo_ = false ;
return ;
}
2018-12-05 10:32:31 +01:00
// If file reference is needed
2019-01-30 17:08:50 +01:00
if ( ! file_view . has_active_download_remote_location ( ) ) {
2019-02-21 16:58:20 +01:00
VLOG ( file_references ) < < " Do not have valid file_reference for file " < < file_id ;
2020-01-06 16:02:42 +01:00
QueryId id = queries_container_ . create ( Query { file_id , Query : : Type : : DownloadWaitFileReference } ) ;
2018-12-05 10:32:31 +01:00
node - > download_id_ = id ;
2019-01-17 21:42:00 +01:00
if ( node - > download_was_update_file_reference_ ) {
2019-01-22 16:07:21 +01:00
on_error ( id , Status : : Error ( " Can't download file: have no valid file reference " ) ) ;
2018-12-09 08:05:26 +01:00
return ;
}
2019-01-17 21:42:00 +01:00
node - > download_was_update_file_reference_ = true ;
2018-12-05 10:32:31 +01:00
2019-01-30 22:37:38 +01:00
context_ - > repair_file_reference (
file_id , PromiseCreator : : lambda ( [ id , actor_id = actor_id ( this ) , file_id ] ( Result < Unit > res ) {
Status error ;
if ( res . is_ok ( ) ) {
error = Status : : Error ( " FILE_DOWNLOAD_RESTART_WITH_FILE_REFERENCE " ) ;
} else {
error = res . move_as_error ( ) ;
}
2019-02-21 16:58:20 +01:00
VLOG ( file_references ) < < " Got result from FileSourceManager for file " < < file_id < < " : " < < error ;
2019-01-30 22:37:38 +01:00
send_closure ( actor_id , & FileManager : : on_error , id , std : : move ( error ) ) ;
} ) ) ;
2018-12-05 10:32:31 +01:00
return ;
}
2019-12-23 15:32:03 +01:00
QueryId id = queries_container_ . create ( Query { file_id , Query : : Type : : Download } ) ;
2018-12-31 20:04:05 +01:00
node - > download_id_ = id ;
2018-01-09 12:57:11 +01:00
node - > is_download_started_ = false ;
2019-10-18 03:31:28 +02:00
LOG ( INFO ) < < " Run download of file " < < file_id < < " of size " < < node - > size_ < < " from "
< < node - > remote_ . full . value ( ) < < " with suggested name " < < node - > suggested_name ( ) < < " and encyption key "
< < node - > encryption_key_ ;
2018-12-27 23:48:21 +01:00
auto download_offset = file_view . is_encrypted_any ( ) ? 0 : node - > download_offset_ ;
2019-02-18 20:08:05 +01:00
auto download_limit = node - > download_limit_ ;
2019-02-14 12:20:40 +01:00
send_closure ( file_load_manager_ , & FileLoadManager : : download , id , node - > remote_ . full . value ( ) , node - > local_ ,
node - > size_ , node - > suggested_name ( ) , node - > encryption_key_ , node - > can_search_locally_ , download_offset ,
2019-02-18 20:08:05 +01:00
download_limit , priority ) ;
2018-12-31 20:04:05 +01:00
}
2019-11-16 18:09:27 +01:00
class FileManager : : ForceUploadActor : public Actor {
2019-02-14 12:20:40 +01:00
public :
2019-02-17 14:52:34 +01:00
ForceUploadActor ( FileManager * file_manager , FileId file_id , std : : shared_ptr < FileManager : : UploadCallback > callback ,
int32 new_priority , uint64 upload_order , ActorShared < > parent )
: file_manager_ ( file_manager )
, file_id_ ( file_id )
2019-02-14 12:20:40 +01:00
, callback_ ( std : : move ( callback ) )
, new_priority_ ( new_priority )
, upload_order_ ( upload_order )
, parent_ ( std : : move ( parent ) ) {
}
private :
2019-02-17 14:52:34 +01:00
FileManager * file_manager_ ;
2019-02-14 12:20:40 +01:00
FileId file_id_ ;
std : : shared_ptr < FileManager : : UploadCallback > callback_ ;
int32 new_priority_ ;
uint64 upload_order_ ;
ActorShared < > parent_ ;
bool is_active_ { false } ;
int attempt_ { 0 } ;
class UploadCallback : public FileManager : : UploadCallback {
public :
2019-02-14 22:19:48 +01:00
explicit UploadCallback ( ActorId < ForceUploadActor > callback ) : callback_ ( std : : move ( callback ) ) {
2019-02-14 12:20:40 +01:00
}
void on_upload_ok ( FileId file_id , tl_object_ptr < telegram_api : : InputFile > input_file ) override {
send_closure ( callback_ , & ForceUploadActor : : on_upload_ok , std : : move ( input_file ) ) ;
}
void on_upload_encrypted_ok ( FileId file_id , tl_object_ptr < telegram_api : : InputEncryptedFile > input_file ) override {
send_closure ( callback_ , & ForceUploadActor : : on_upload_encrypted_ok , std : : move ( input_file ) ) ;
}
void on_upload_secure_ok ( FileId file_id , tl_object_ptr < telegram_api : : InputSecureFile > input_file ) override {
send_closure ( callback_ , & ForceUploadActor : : on_upload_secure_ok , std : : move ( input_file ) ) ;
}
void on_upload_error ( FileId file_id , Status error ) override {
send_closure ( callback_ , & ForceUploadActor : : on_upload_error , std : : move ( error ) ) ;
}
private :
ActorId < ForceUploadActor > callback_ ;
} ;
void on_upload_ok ( tl_object_ptr < telegram_api : : InputFile > input_file ) {
is_active_ = false ;
if ( input_file | | is_ready ( ) ) {
callback_ - > on_upload_ok ( file_id_ , std : : move ( input_file ) ) ;
on_ok ( ) ;
} else {
loop ( ) ;
}
}
void on_upload_encrypted_ok ( tl_object_ptr < telegram_api : : InputEncryptedFile > input_file ) {
is_active_ = false ;
if ( input_file | | is_ready ( ) ) {
callback_ - > on_upload_encrypted_ok ( file_id_ , std : : move ( input_file ) ) ;
on_ok ( ) ;
} else {
loop ( ) ;
}
}
void on_upload_secure_ok ( tl_object_ptr < telegram_api : : InputSecureFile > input_file ) {
is_active_ = false ;
if ( input_file | | is_ready ( ) ) {
callback_ - > on_upload_secure_ok ( file_id_ , std : : move ( input_file ) ) ;
on_ok ( ) ;
} else {
loop ( ) ;
}
}
2019-02-14 22:19:48 +01:00
bool is_ready ( ) const {
2019-02-17 14:52:34 +01:00
return ! G ( ) - > close_flag ( ) & & file_manager_ - > get_file_view ( file_id_ ) . has_active_upload_remote_location ( ) ;
2019-02-14 12:20:40 +01:00
}
void on_ok ( ) {
callback_ . reset ( ) ;
2019-11-16 18:09:27 +01:00
send_closure ( G ( ) - > file_manager ( ) , & FileManager : : on_force_reupload_success , file_id_ ) ;
2019-02-14 12:20:40 +01:00
stop ( ) ;
}
void on_upload_error ( Status error ) {
if ( attempt_ = = 2 ) {
callback_ - > on_upload_error ( file_id_ , std : : move ( error ) ) ;
callback_ . reset ( ) ;
stop ( ) ;
2019-02-14 22:19:48 +01:00
} else {
is_active_ = false ;
loop ( ) ;
2019-02-14 12:20:40 +01:00
}
}
auto create_callback ( ) {
return std : : make_shared < UploadCallback > ( actor_id ( this ) ) ;
}
2019-02-14 22:19:48 +01:00
2019-02-14 12:20:40 +01:00
void loop ( ) override {
if ( is_active_ ) {
return ;
}
is_active_ = true ;
attempt_ + + ;
send_closure ( G ( ) - > file_manager ( ) , & FileManager : : resume_upload , file_id_ , std : : vector < int > ( ) , create_callback ( ) ,
2019-02-14 22:19:48 +01:00
new_priority_ , upload_order_ , attempt_ = = 2 ) ;
2019-02-14 12:20:40 +01:00
}
void tear_down ( ) override {
if ( callback_ ) {
callback_ - > on_upload_error ( file_id_ , Status : : Error ( " Cancelled " ) ) ;
}
}
} ;
2019-11-16 18:09:27 +01:00
void FileManager : : on_force_reupload_success ( FileId file_id ) {
auto node = get_sync_file_node ( file_id ) ;
CHECK ( node ) ;
2020-04-11 02:56:19 +02:00
if ( ! node - > remote_ . is_full_alive ) { // do not update for multiple simultaneous uploads
node - > last_successful_force_reupload_time_ = Time : : now ( ) ;
}
2019-11-16 18:09:27 +01:00
}
2018-12-31 20:04:05 +01:00
void FileManager : : 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 ) {
2018-01-30 21:04:22 +01:00
auto node = get_sync_file_node ( file_id ) ;
2018-12-31 20:04:05 +01:00
if ( ! node ) {
2018-04-24 19:10:12 +02:00
LOG ( INFO ) < < " File " < < file_id < < " not found " ;
2018-12-31 20:04:05 +01:00
if ( callback ) {
2018-04-24 19:10:12 +02:00
callback - > on_upload_error ( file_id , Status : : Error ( " File not found " ) ) ;
2018-12-31 20:04:05 +01:00
}
return ;
}
2019-11-16 18:09:27 +01:00
if ( bad_parts . size ( ) = = 1 & & bad_parts [ 0 ] = = - 1 ) {
if ( node - > last_successful_force_reupload_time_ > = Time : : now ( ) - 60 ) {
LOG ( INFO ) < < " Recently reuploaded file " < < file_id < < " , do not try again " ;
if ( callback ) {
callback - > on_upload_error ( file_id , Status : : Error ( " Failed to reupload file " ) ) ;
}
return ;
}
create_actor < ForceUploadActor > ( " ForceUploadActor " , this , file_id , std : : move ( callback ) , new_priority , upload_order ,
context_ - > create_reference ( ) )
. release ( ) ;
return ;
}
LOG ( INFO ) < < " Resume upload of file " < < file_id < < " with priority " < < new_priority < < " and force = " < < force ;
2019-02-14 12:20:40 +01:00
if ( force ) {
node - > remote_ . is_full_alive = false ;
}
2018-12-31 20:04:05 +01:00
if ( node - > upload_pause_ = = file_id ) {
2019-01-10 22:12:51 +01:00
node - > set_upload_pause ( FileId ( ) ) ;
2018-12-31 20:04:05 +01:00
}
FileView file_view ( node ) ;
2019-01-30 17:08:50 +01:00
if ( file_view . has_active_upload_remote_location ( ) & & file_view . get_type ( ) ! = FileType : : Thumbnail & &
2019-05-10 14:36:37 +02:00
file_view . get_type ( ) ! = FileType : : EncryptedThumbnail & & file_view . get_type ( ) ! = FileType : : Background ) {
2018-04-24 19:10:12 +02:00
LOG ( INFO ) < < " File " < < file_id < < " is already uploaded " ;
2018-12-31 20:04:05 +01:00
if ( callback ) {
callback - > on_upload_ok ( file_id , nullptr ) ;
}
return ;
}
if ( file_view . has_local_location ( ) ) {
auto status = check_local_location ( node ) ;
if ( status . is_error ( ) ) {
LOG ( INFO ) < < " Full local location of file " < < file_id < < " for upload is invalid: " < < status ;
}
}
2019-02-14 12:20:40 +01:00
if ( ! file_view . has_local_location ( ) & & ! file_view . has_generate_location ( ) & & ! file_view . has_alive_remote_location ( ) ) {
2018-04-24 19:10:12 +02:00
LOG ( INFO ) < < " File " < < file_id < < " can't be uploaded " ;
2018-12-31 20:04:05 +01:00
if ( callback ) {
2019-01-25 12:03:17 +01:00
callback - > on_upload_error ( file_id ,
Status : : Error ( " Need full local (or generate, or inactive remote) location for upload " ) ) ;
2018-12-31 20:04:05 +01:00
}
return ;
}
2019-10-18 03:31:28 +02:00
if ( file_view . get_type ( ) = = FileType : : Thumbnail & &
( ! file_view . has_local_location ( ) & & file_view . can_download_from_server ( ) ) ) {
// TODO
if ( callback ) {
callback - > on_upload_error ( file_id , Status : : Error ( " Failed to upload thumbnail without local location " ) ) ;
}
return ;
}
2018-12-31 20:04:05 +01:00
2018-04-24 19:10:12 +02:00
LOG ( INFO ) < < " Change upload priority of file " < < file_id < < " to " < < new_priority ;
2018-12-31 20:04:05 +01:00
auto * file_info = get_file_id_info ( file_id ) ;
CHECK ( new_priority = = 0 | | callback ) ;
file_info - > upload_order_ = upload_order ;
2018-01-20 12:47:53 +01:00
file_info - > upload_priority_ = narrow_cast < int8 > ( new_priority ) ;
2018-12-31 20:04:05 +01:00
file_info - > upload_callback_ = std : : move ( callback ) ;
// TODO: send current progress?
run_generate ( node ) ;
run_upload ( node , std : : move ( bad_parts ) ) ;
2018-12-27 18:23:19 +01:00
try_flush_node ( node , " resume_upload " ) ;
2018-12-31 20:04:05 +01:00
}
bool FileManager : : delete_partial_remote_location ( FileId file_id ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-01-30 21:04:22 +01:00
auto node = get_sync_file_node ( file_id ) ;
2018-12-31 20:04:05 +01:00
if ( ! node ) {
2020-04-19 12:45:37 +02:00
LOG ( INFO ) < < " Wrong file identifier " < < file_id ;
2018-12-31 20:04:05 +01:00
return false ;
}
if ( node - > upload_pause_ = = file_id ) {
2019-01-10 22:12:51 +01:00
node - > set_upload_pause ( FileId ( ) ) ;
2018-12-31 20:04:05 +01:00
}
2019-02-14 12:20:40 +01:00
if ( node - > remote_ . is_full_alive ) {
2018-12-31 20:04:05 +01:00
LOG ( INFO ) < < " File " < < file_id < < " is already uploaded " ;
return true ;
}
2019-02-14 12:20:40 +01:00
node - > delete_partial_remote_location ( ) ;
2018-12-31 20:04:05 +01:00
auto * file_info = get_file_id_info ( file_id ) ;
file_info - > upload_priority_ = 0 ;
2018-01-20 15:57:52 +01:00
if ( node - > local_ . type ( ) ! = LocalFileLocation : : Type : : Full ) {
2018-12-31 20:04:05 +01:00
LOG ( INFO ) < < " Need full local location to upload file " < < file_id ;
return false ;
}
auto status = check_local_location ( node ) ;
if ( status . is_error ( ) ) {
LOG ( INFO ) < < " Need full local location to upload file " < < file_id < < " : " < < status ;
return false ;
}
run_upload ( node , std : : vector < int > ( ) ) ;
2018-12-27 18:23:19 +01:00
try_flush_node ( node , " delete_partial_remote_location " ) ;
2018-12-31 20:04:05 +01:00
return true ;
}
2019-01-14 19:46:04 +01:00
void FileManager : : delete_file_reference ( FileId file_id , string file_reference ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
return delete_file_reference_internal ( file_id , file_reference ) ;
}
void FileManager : : delete_file_reference_internal ( FileId file_id , string file_reference ) {
2019-01-14 19:46:04 +01:00
VLOG ( file_references ) < < " Delete file reference of file " < < file_id < < " "
2019-01-23 20:20:48 +01:00
< < tag ( " reference_base64 " , base64_encode ( file_reference ) ) ;
2018-12-05 10:32:31 +01:00
auto node = get_sync_file_node ( file_id ) ;
if ( ! node ) {
2020-04-19 12:45:37 +02:00
LOG ( ERROR ) < < " Wrong file identifier " < < file_id ;
2018-12-05 10:32:31 +01:00
return ;
}
2020-08-02 00:28:01 +02:00
node - > delete_file_reference_internal ( file_reference ) ;
2019-01-31 00:57:14 +01:00
auto remote = get_remote ( file_id . get_remote ( ) ) ;
if ( remote ! = nullptr ) {
VLOG ( file_references ) < < " Do delete file reference of remote file " < < file_id ;
if ( remote - > delete_file_reference ( file_reference ) ) {
2019-11-16 23:43:47 +01:00
VLOG ( file_references ) < < " Successfully deleted file reference of remote file " < < file_id ;
2019-01-31 00:57:14 +01:00
node - > upload_was_update_file_reference_ = false ;
node - > download_was_update_file_reference_ = false ;
node - > on_pmc_changed ( ) ;
}
}
2019-01-30 17:40:23 +01:00
try_flush_node_pmc ( node , " delete_file_reference " ) ;
2018-12-05 10:32:31 +01:00
}
2019-04-26 02:18:00 +02:00
void FileManager : : external_file_generate_write_part ( int64 id , int32 offset , string data , Promise < > promise ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2019-04-26 02:18:00 +02:00
send_closure ( file_generate_manager_ , & FileGenerateManager : : external_file_generate_write_part , id , offset ,
std : : move ( data ) , std : : move ( promise ) ) ;
}
2018-12-31 20:04:05 +01:00
void FileManager : : external_file_generate_progress ( int64 id , int32 expected_size , int32 local_prefix_size ,
Promise < > promise ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-12-31 20:04:05 +01:00
send_closure ( file_generate_manager_ , & FileGenerateManager : : external_file_generate_progress , id , expected_size ,
local_prefix_size , std : : move ( promise ) ) ;
}
2019-01-11 03:45:03 +01:00
2018-12-31 20:04:05 +01:00
void FileManager : : external_file_generate_finish ( int64 id , Status status , Promise < > promise ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-12-31 20:04:05 +01:00
send_closure ( file_generate_manager_ , & FileGenerateManager : : external_file_generate_finish , id , std : : move ( status ) ,
std : : move ( promise ) ) ;
}
2018-01-30 17:54:17 +01:00
void FileManager : : run_generate ( FileNodePtr node ) {
2018-12-31 20:04:05 +01:00
if ( node - > need_load_from_pmc_ ) {
2019-10-18 03:31:28 +02:00
LOG ( INFO ) < < " Skip run_generate, because file " < < node - > main_file_id_ < < " needs to be loaded from PMC " ;
2018-12-31 20:04:05 +01:00
return ;
}
FileView file_view ( node ) ;
2020-05-24 20:35:47 +02:00
if ( ! file_view . can_generate ( ) ) {
LOG ( INFO ) < < " Skip run_generate, because file " < < node - > main_file_id_ < < " can't be generated " ;
return ;
}
2019-10-18 03:31:28 +02:00
if ( file_view . has_local_location ( ) ) {
LOG ( INFO ) < < " Skip run_generate, because file " < < node - > main_file_id_ < < " has local location " ;
return ;
}
if ( file_view . can_download_from_server ( ) ) {
LOG ( INFO ) < < " Skip run_generate, because file " < < node - > main_file_id_ < < " can be downloaded from server " ;
return ;
}
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-03-18 11:45:59 +01:00
FileId file_id = node - > main_file_id_ ;
2018-12-31 20:04:05 +01:00
for ( auto id : node - > file_ids_ ) {
auto * info = get_file_id_info ( id ) ;
if ( info - > download_priority_ > download_priority ) {
download_priority = info - > download_priority_ ;
if ( download_priority > upload_priority ) {
file_id = id ;
}
}
if ( info - > upload_priority_ > upload_priority ) {
upload_priority = info - > upload_priority_ ;
if ( upload_priority > download_priority ) {
file_id = id ;
}
}
}
auto old_priority = node - > generate_priority_ ;
node - > set_generate_priority ( download_priority , upload_priority ) ;
if ( node - > generate_priority_ = = 0 ) {
if ( old_priority ! = 0 ) {
LOG ( INFO ) < < " Cancel file " < < file_id < < " generation " ;
2019-01-25 02:52:38 +01:00
do_cancel_generate ( node ) ;
2018-12-31 20:04:05 +01:00
}
return ;
}
if ( old_priority ! = 0 ) {
LOG ( INFO ) < < " TODO: change file " < < file_id < < " generation priority " ;
return ;
}
2019-12-23 15:32:03 +01:00
QueryId id = queries_container_ . create ( Query { file_id , Query : : Type : : Generate } ) ;
2018-12-31 20:04:05 +01:00
node - > generate_id_ = id ;
2018-02-04 18:27:05 +01:00
send_closure ( file_generate_manager_ , & FileGenerateManager : : generate_file , id , * node - > generate_ , node - > local_ ,
2018-02-20 00:29:19 +01:00
node - > suggested_name ( ) , [ file_manager = this , id ] {
2018-12-31 20:04:05 +01:00
class Callback : public FileGenerateCallback {
ActorId < FileManager > actor_ ;
uint64 query_id_ ;
public :
Callback ( ActorId < FileManager > actor , QueryId id ) : actor_ ( std : : move ( actor ) ) , query_id_ ( id ) {
}
void on_partial_generate ( const PartialLocalFileLocation & partial_local ,
int32 expected_size ) override {
send_closure ( actor_ , & FileManager : : on_partial_generate , query_id_ , partial_local , expected_size ) ;
}
void on_ok ( const FullLocalFileLocation & local ) override {
send_closure ( actor_ , & FileManager : : on_generate_ok , query_id_ , local ) ;
}
void on_error ( Status error ) override {
send_closure ( actor_ , & FileManager : : on_error , query_id_ , std : : move ( error ) ) ;
}
} ;
2018-09-27 03:19:03 +02:00
return make_unique < Callback > ( file_manager - > actor_id ( file_manager ) , id ) ;
2018-12-31 20:04:05 +01:00
} ( ) ) ;
LOG ( INFO ) < < " File " < < file_id < < " generate request has sent to FileGenerateManager " ;
}
2018-01-30 17:54:17 +01:00
void FileManager : : run_upload ( FileNodePtr node , std : : vector < int > bad_parts ) {
2020-04-09 11:53:00 +02:00
int8 priority = 0 ;
FileId file_id = node - > main_file_id_ ;
for ( auto id : node - > file_ids_ ) {
auto * info = get_file_id_info ( id ) ;
if ( info - > upload_priority_ > priority ) {
priority = info - > upload_priority_ ;
file_id = id ;
}
}
auto old_priority = node - > upload_priority_ ;
if ( priority = = 0 ) {
node - > set_upload_priority ( priority ) ;
if ( old_priority ! = 0 ) {
LOG ( INFO ) < < " Cancel file " < < file_id < < " uploading " ;
do_cancel_upload ( node ) ;
} else {
LOG ( INFO ) < < " File " < < file_id < < " upload priority is still 0 " ;
}
return ;
}
2018-12-31 20:04:05 +01:00
if ( node - > need_load_from_pmc_ ) {
2019-01-10 22:12:51 +01:00
LOG ( INFO ) < < " File " < < node - > main_file_id_ < < " needs to be loaded from database before upload " ;
2018-12-31 20:04:05 +01:00
return ;
}
if ( node - > upload_pause_ . is_valid ( ) ) {
2019-01-10 22:12:51 +01:00
LOG ( INFO ) < < " File " < < node - > main_file_id_ < < " upload is paused: " < < node - > upload_pause_ ;
2018-12-31 20:04:05 +01:00
return ;
}
2020-04-09 11:53:00 +02:00
2018-12-31 20:04:05 +01:00
FileView file_view ( node ) ;
2019-01-25 12:03:17 +01:00
if ( ! file_view . has_local_location ( ) & & ! file_view . has_remote_location ( ) ) {
2018-12-31 20:04:05 +01:00
if ( node - > get_by_hash_ | | node - > generate_id_ = = 0 | | ! node - > generate_was_update_ ) {
2019-01-10 22:12:51 +01:00
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_ ;
2018-12-31 20:04:05 +01:00
return ;
}
2018-04-03 19:49:07 +02:00
if ( file_view . has_generate_location ( ) & & file_view . generate_location ( ) . file_type_ = = FileType : : Secure ) {
2020-05-24 20:35:47 +02:00
// Can't upload secure file before its size is known
2019-01-10 22:12:51 +01:00
LOG ( INFO ) < < " Can't upload secure file " < < node - > main_file_id_ < < " before it's size is known " ;
2018-04-03 19:49:07 +02:00
return ;
}
2018-12-31 20:04:05 +01:00
}
node - > set_upload_priority ( priority ) ;
// create encryption key if necessary
2018-01-20 15:57:52 +01:00
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 ) ) & &
2018-12-31 20:04:05 +01:00
file_view . encryption_key ( ) . empty ( ) ) {
CHECK ( ! node - > file_ids_ . empty ( ) ) ;
bool success = set_encryption_key ( node - > file_ids_ [ 0 ] , FileEncryptionKey : : create ( ) ) ;
LOG_IF ( FATAL , ! success ) < < " Failed to set encryption key for file " < < file_id ;
}
2018-04-03 19:49:07 +02:00
// create encryption key if necessary
if ( file_view . has_local_location ( ) & & file_view . local_location ( ) . file_type_ = = FileType : : Secure & &
file_view . encryption_key ( ) . empty ( ) ) {
CHECK ( ! node - > file_ids_ . empty ( ) ) ;
bool success = set_encryption_key ( node - > file_ids_ [ 0 ] , FileEncryptionKey : : create_secure_key ( ) ) ;
LOG_IF ( FATAL , ! success ) < < " Failed to set encryption key for file " < < file_id ;
}
2018-12-31 20:04:05 +01:00
if ( old_priority ! = 0 ) {
LOG ( INFO ) < < " File " < < file_id < < " is already uploading " ;
CHECK ( node - > upload_id_ ! = 0 ) ;
2018-01-20 12:47:53 +01:00
send_closure ( file_load_manager_ , & FileLoadManager : : update_priority , node - > upload_id_ , narrow_cast < int8 > ( - priority ) ) ;
2018-12-31 20:04:05 +01:00
return ;
}
CHECK ( node - > upload_id_ = = 0 ) ;
2019-02-15 10:25:21 +01:00
if ( file_view . has_alive_remote_location ( ) & & ! file_view . has_active_upload_remote_location ( ) & &
2019-05-10 14:36:37 +02:00
file_view . get_type ( ) ! = FileType : : Thumbnail & & file_view . get_type ( ) ! = FileType : : EncryptedThumbnail & &
file_view . get_type ( ) ! = FileType : : Background ) {
2019-12-23 15:32:03 +01:00
QueryId id = queries_container_ . create ( Query { file_id , Query : : Type : : UploadWaitFileReference } ) ;
2018-12-05 10:32:31 +01:00
node - > upload_id_ = id ;
2019-02-15 10:25:21 +01:00
if ( node - > upload_was_update_file_reference_ ) {
on_error ( id , Status : : Error ( " Can't upload file: have no valid file reference " ) ) ;
return ;
}
2019-01-17 21:42:00 +01:00
node - > upload_was_update_file_reference_ = true ;
2018-12-09 08:05:26 +01:00
2019-02-10 00:39:58 +01:00
context_ - > repair_file_reference (
node - > main_file_id_ , PromiseCreator : : lambda ( [ id , actor_id = actor_id ( this ) ] ( Result < Unit > res ) {
send_closure ( actor_id , & FileManager : : on_error , id , Status : : Error ( " FILE_UPLOAD_RESTART_WITH_FILE_REFERENCE " ) ) ;
} ) ) ;
2018-12-05 10:32:31 +01:00
return ;
}
2019-02-14 12:20:40 +01:00
if ( ! node - > remote_ . partial & & node - > get_by_hash_ ) {
2019-01-10 22:12:51 +01:00
LOG ( INFO ) < < " Get file " < < node - > main_file_id_ < < " by hash " ;
2019-12-23 15:32:03 +01:00
QueryId id = queries_container_ . create ( Query { file_id , Query : : Type : : UploadByHash } ) ;
2018-12-31 20:04:05 +01:00
node - > upload_id_ = id ;
2018-01-20 12:47:53 +01:00
send_closure ( file_load_manager_ , & FileLoadManager : : upload_by_hash , id , node - > local_ . full ( ) , node - > size_ ,
narrow_cast < int8 > ( - priority ) ) ;
2018-12-31 20:04:05 +01:00
return ;
}
2019-01-25 15:31:06 +01:00
auto new_priority = narrow_cast < int8 > ( bad_parts . empty ( ) ? - priority : priority ) ;
2019-10-21 15:25:56 +02:00
td : : remove_if ( bad_parts , [ ] ( auto part_id ) { return part_id < 0 ; } ) ;
2019-01-25 04:01:09 +01:00
2019-12-23 15:32:03 +01:00
QueryId id = queries_container_ . create ( Query { file_id , Query : : Type : : Upload } ) ;
2018-12-31 20:04:05 +01:00
node - > upload_id_ = id ;
2019-02-14 12:20:40 +01:00
send_closure ( file_load_manager_ , & FileLoadManager : : upload , id , node - > local_ , node - > remote_ . partial_or_empty ( ) ,
2019-01-25 04:01:09 +01:00
file_view . expected_size ( true ) , node - > encryption_key_ , new_priority , std : : move ( bad_parts ) ) ;
2018-12-31 20:04:05 +01:00
LOG ( INFO ) < < " File " < < file_id < < " upload request has sent to FileLoadManager " ;
}
void FileManager : : upload ( FileId file_id , std : : shared_ptr < UploadCallback > callback , int32 new_priority ,
uint64 upload_order ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-12-31 20:04:05 +01:00
return resume_upload ( file_id , std : : vector < int > ( ) , std : : move ( callback ) , new_priority , upload_order ) ;
}
2019-01-25 02:52:38 +01:00
void FileManager : : cancel_upload ( FileId file_id ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2019-01-25 02:52:38 +01:00
return resume_upload ( file_id , std : : vector < int > ( ) , nullptr , 0 , 0 ) ;
}
2018-12-31 20:04:05 +01:00
static bool is_document_type ( FileType type ) {
return type = = FileType : : Document | | type = = FileType : : Sticker | | type = = FileType : : Audio | |
2020-06-22 01:02:21 +02:00
type = = FileType : : Animation | | type = = FileType : : Background | | type = = FileType : : DocumentAsFile ;
2019-05-07 04:51:56 +02:00
}
static bool is_background_type ( FileType type ) {
return type = = FileType : : Wallpaper | | type = = FileType : : Background ;
2018-12-31 20:04:05 +01:00
}
Result < FileId > FileManager : : from_persistent_id ( CSlice persistent_id , FileType file_type ) {
if ( persistent_id . find ( ' . ' ) ! = string : : npos ) {
2019-08-05 11:56:28 +02:00
TRY_RESULT ( http_url , parse_url ( persistent_id ) ) ;
2018-12-31 20:04:05 +01:00
auto url = http_url . get_url ( ) ;
if ( ! clean_input_string ( url ) ) {
return Status : : Error ( 400 , " URL must be in UTF-8 " ) ;
}
2018-01-26 13:56:19 +01:00
return register_url ( std : : move ( url ) , file_type , FileLocationSource : : FromUser , DialogId ( ) ) ;
2018-12-31 20:04:05 +01:00
}
auto r_binary = base64url_decode ( persistent_id ) ;
if ( r_binary . is_error ( ) ) {
2020-04-19 12:45:37 +02:00
return Status : : Error ( 10 , PSLICE ( ) < < " Wrong remote file identifier specified: " < < r_binary . error ( ) . message ( ) ) ;
2018-12-31 20:04:05 +01:00
}
auto binary = r_binary . move_as_ok ( ) ;
if ( binary . empty ( ) ) {
2020-04-19 12:45:37 +02:00
return Status : : Error ( 10 , " Remote file identifier can't be empty " ) ;
2018-12-31 20:04:05 +01:00
}
2020-07-06 17:31:26 +02:00
if ( binary . back ( ) = = FileNode : : PERSISTENT_ID_VERSION_OLD ) {
2018-12-17 20:56:47 +01:00
return from_persistent_id_v2 ( binary , file_type ) ;
}
2020-07-06 17:31:26 +02:00
if ( binary . back ( ) = = FileNode : : PERSISTENT_ID_VERSION ) {
2019-06-12 16:28:00 +02:00
return from_persistent_id_v3 ( binary , file_type ) ;
}
2020-07-06 17:31:26 +02:00
if ( binary . back ( ) = = FileNode : : PERSISTENT_ID_VERSION_MAP ) {
2018-12-17 20:56:47 +01:00
return from_persistent_id_map ( binary , file_type ) ;
}
2020-04-19 12:45:37 +02:00
return Status : : Error ( 10 , " Wrong remote file identifier specified: can't unserialize it. Wrong last symbol " ) ;
2018-12-17 20:56:47 +01:00
}
Result < FileId > FileManager : : from_persistent_id_map ( Slice binary , FileType file_type ) {
binary . remove_suffix ( 1 ) ;
2018-12-17 21:59:24 +01:00
auto decoded_binary = zero_decode ( binary ) ;
2018-12-17 20:56:47 +01:00
FullGenerateFileLocation generate_location ;
2018-12-17 21:59:24 +01:00
auto status = unserialize ( generate_location , decoded_binary ) ;
2018-12-17 20:56:47 +01:00
if ( status . is_error ( ) ) {
2020-04-19 12:45:37 +02:00
return Status : : Error ( 10 , " Wrong remote file identifier specified: can't unserialize it " ) ;
2018-12-31 20:04:05 +01:00
}
2018-12-17 20:56:47 +01:00
auto real_file_type = generate_location . file_type_ ;
2018-12-17 21:59:24 +01:00
if ( ( real_file_type ! = file_type & & file_type ! = FileType : : Temp ) | |
( real_file_type ! = FileType : : Thumbnail & & real_file_type ! = FileType : : EncryptedThumbnail ) ) {
2018-12-17 20:56:47 +01:00
return Status : : Error ( 10 , " Type of file mismatch " ) ;
}
if ( ! begins_with ( generate_location . conversion_ , " #map# " ) ) {
2018-12-17 21:59:24 +01:00
return Status : : Error ( 10 , " Unexpected conversion type " ) ;
2018-12-17 20:56:47 +01:00
}
FileData data ;
data . generate_ = make_unique < FullGenerateFileLocation > ( std : : move ( generate_location ) ) ;
return register_file ( std : : move ( data ) , FileLocationSource : : FromUser , " from_persistent_id_map " , false ) . move_as_ok ( ) ;
}
2019-06-12 16:28:00 +02:00
Result < FileId > FileManager : : from_persistent_id_v23 ( Slice binary , FileType file_type , int32 version ) {
if ( version < 0 | | version > = static_cast < int32 > ( Version : : Next ) ) {
2020-04-19 12:45:37 +02:00
return Status : : Error ( " Invalid remote file identifier " ) ;
2019-06-12 16:28:00 +02:00
}
2018-12-17 21:59:24 +01:00
auto decoded_binary = zero_decode ( binary ) ;
2018-12-31 20:04:05 +01:00
FullRemoteFileLocation remote_location ;
2019-06-11 12:10:14 +02:00
logevent : : WithVersion < TlParser > parser ( decoded_binary ) ;
2019-06-12 16:28:00 +02:00
parser . set_version ( version ) ;
2019-06-11 12:10:14 +02:00
parse ( remote_location , parser ) ;
parser . fetch_end ( ) ;
auto status = parser . get_status ( ) ;
2018-12-31 20:04:05 +01:00
if ( status . is_error ( ) ) {
2020-04-19 12:45:37 +02:00
return Status : : Error ( 10 , " Wrong remote file identifier specified: can't unserialize it " ) ;
2018-12-31 20:04:05 +01:00
}
2018-01-20 15:57:52 +01:00
auto & real_file_type = remote_location . file_type_ ;
if ( is_document_type ( real_file_type ) & & is_document_type ( file_type ) ) {
real_file_type = file_type ;
2019-05-07 04:51:56 +02:00
} else if ( is_background_type ( real_file_type ) & & is_background_type ( file_type ) ) {
2019-06-27 02:13:27 +02:00
// type of file matches, but real type is in the stored remote location
2018-01-20 15:57:52 +01:00
} else if ( real_file_type ! = file_type & & file_type ! = FileType : : Temp ) {
2018-12-31 20:04:05 +01:00
return Status : : Error ( 10 , " Type of file mismatch " ) ;
}
FileData data ;
data . remote_ = RemoteFileLocation ( std : : move ( remote_location ) ) ;
2019-01-22 15:35:29 +01:00
auto file_id =
2019-07-21 20:07:07 +02:00
register_file ( std : : move ( data ) , FileLocationSource : : FromUser , " from_persistent_id_v23 " , false ) . move_as_ok ( ) ;
2019-01-22 15:35:29 +01:00
return file_id ;
2018-12-31 20:04:05 +01:00
}
2019-07-21 20:07:07 +02:00
2019-06-12 16:28:00 +02:00
Result < FileId > FileManager : : from_persistent_id_v2 ( Slice binary , FileType file_type ) {
binary . remove_suffix ( 1 ) ;
return from_persistent_id_v23 ( binary , file_type , 0 ) ;
}
2019-07-21 20:07:07 +02:00
2019-06-12 16:28:00 +02:00
Result < FileId > FileManager : : from_persistent_id_v3 ( Slice binary , FileType file_type ) {
binary . remove_suffix ( 1 ) ;
if ( binary . empty ( ) ) {
2020-04-19 12:45:37 +02:00
return Status : : Error ( " Invalid remote file identifier " ) ;
2019-06-12 16:28:00 +02:00
}
2019-07-01 18:52:48 +02:00
int32 version = static_cast < uint8 > ( binary . back ( ) ) ;
2019-06-12 16:28:00 +02:00
binary . remove_suffix ( 1 ) ;
return from_persistent_id_v23 ( binary , file_type , version ) ;
}
2018-12-31 20:04:05 +01:00
FileView FileManager : : get_file_view ( FileId file_id ) const {
2018-01-30 21:04:22 +01:00
auto file_node = get_file_node ( file_id ) ;
if ( ! file_node ) {
2018-12-31 20:04:05 +01:00
return FileView ( ) ;
}
return FileView ( file_node ) ;
}
2019-07-21 20:07:07 +02:00
2018-12-31 20:04:05 +01:00
FileView FileManager : : get_sync_file_view ( FileId file_id ) {
2018-01-30 21:04:22 +01:00
auto file_node = get_sync_file_node ( file_id ) ;
if ( ! file_node ) {
2018-12-31 20:04:05 +01:00
return FileView ( ) ;
}
return FileView ( file_node ) ;
}
2019-01-21 18:19:02 +01:00
td_api : : object_ptr < td_api : : file > FileManager : : get_file_object ( FileId file_id , bool with_main_file_id ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-12-31 20:04:05 +01:00
auto file_view = get_sync_file_view ( file_id ) ;
if ( file_view . empty ( ) ) {
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 > ( ) ) ;
}
2020-07-06 17:31:26 +02:00
string persistent_file_id = file_view . get_persistent_file_id ( ) ;
string unique_file_id = file_view . get_unique_file_id ( ) ;
2018-12-17 20:56:47 +01:00
bool is_uploading_completed = ! persistent_file_id . empty ( ) ;
2018-12-31 20:04:05 +01:00
int32 size = narrow_cast < int32 > ( file_view . size ( ) ) ;
int32 expected_size = narrow_cast < int32 > ( file_view . expected_size ( ) ) ;
2018-11-11 12:38:04 +01:00
int32 download_offset = narrow_cast < int32 > ( file_view . download_offset ( ) ) ;
2018-12-26 17:11:15 +01:00
int32 local_prefix_size = narrow_cast < int32 > ( file_view . local_prefix_size ( ) ) ;
2018-12-31 20:04:05 +01:00
int32 local_total_size = narrow_cast < int32 > ( file_view . local_total_size ( ) ) ;
int32 remote_size = narrow_cast < int32 > ( file_view . remote_size ( ) ) ;
string path = file_view . path ( ) ;
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 ) ;
if ( with_main_file_id ) {
if ( ! file_info - > send_updates_flag_ ) {
result_file_id = file_view . file_id ( ) ;
}
file_info = get_file_id_info ( file_view . file_id ( ) ) ;
}
file_info - > send_updates_flag_ = true ;
2018-01-25 23:09:07 +01:00
VLOG ( update_file ) < < " Send file " < < file_id < < " as " < < result_file_id < < " and update send_updates_flag_ for file "
2018-12-31 20:04:05 +01:00
< < ( with_main_file_id ? file_view . 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 ,
2018-11-11 12:38:04 +01:00
file_view . is_downloading ( ) , file_view . has_local_location ( ) ,
2018-12-26 17:11:15 +01:00
download_offset , local_prefix_size , local_total_size ) ,
2019-10-25 16:04:01 +02:00
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 ) ) ;
2018-12-31 20:04:05 +01:00
}
2019-01-21 18:19:02 +01:00
vector < int32 > FileManager : : get_file_ids_object ( const vector < FileId > & file_ids , bool with_main_file_id ) {
return transform ( file_ids , [ this , with_main_file_id ] ( FileId file_id ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2019-01-21 18:19:02 +01:00
auto file_view = get_sync_file_view ( file_id ) ;
auto result_file_id = file_id ;
auto * file_info = get_file_id_info ( result_file_id ) ;
if ( with_main_file_id ) {
if ( ! file_info - > sent_file_id_flag_ & & ! file_info - > send_updates_flag_ ) {
result_file_id = file_view . file_id ( ) ;
}
file_info = get_file_id_info ( file_view . file_id ( ) ) ;
}
file_info - > sent_file_id_flag_ = true ;
return result_file_id . get ( ) ;
} ) ;
2018-03-27 15:11:15 +02:00
}
2018-01-05 15:24:41 +01:00
Result < FileId > FileManager : : check_input_file_id ( FileType type , Result < FileId > result , bool is_encrypted ,
2018-04-03 19:49:07 +02:00
bool allow_zero , bool is_secure ) {
2018-12-31 20:04:05 +01:00
TRY_RESULT ( file_id , std : : move ( result ) ) ;
2018-01-05 15:24:41 +01:00
if ( allow_zero & & ! file_id . is_valid ( ) ) {
return FileId ( ) ;
}
2018-12-31 20:04:05 +01:00
2019-02-14 22:19:48 +01:00
auto file_node = get_sync_file_node ( file_id ) ; // we need full data about sent files
2018-01-30 21:04:22 +01:00
if ( ! file_node ) {
2018-12-31 20:04:05 +01:00
return Status : : Error ( 6 , " File not found " ) ;
}
auto file_view = FileView ( file_node ) ;
FileType real_type = file_view . get_type ( ) ;
2020-05-04 02:01:01 +02:00
LOG ( INFO ) < < " Checking file " < < file_id < < " of type " < < type < < " / " < < real_type ;
2018-04-03 19:49:07 +02:00
if ( ! is_encrypted & & ! is_secure ) {
2018-12-31 20:04:05 +01:00
if ( real_type ! = type & & ! ( real_type = = FileType : : Temp & & file_view . has_url ( ) ) & &
2019-05-07 04:51:56 +02:00
! ( is_document_type ( real_type ) & & is_document_type ( type ) ) & &
! ( is_background_type ( real_type ) & & is_background_type ( type ) ) ) {
2018-12-31 20:04:05 +01:00
// TODO: send encrypted file to unencrypted chat
return Status : : Error ( 6 , " Type of file mismatch " ) ;
}
}
if ( ! file_view . has_remote_location ( ) ) {
// TODO why not return file_id here? We will dup it anyway
2018-01-05 11:33:08 +01:00
// But it will not be duped if has_input_media(), so for now we can't return main_file_id
2020-08-02 00:28:01 +02:00
return dup_file_id_internal ( file_id ) ;
2018-12-31 20:04:05 +01:00
}
2019-02-16 03:29:28 +01:00
int32 remote_id = file_id . get_remote ( ) ;
if ( remote_id = = 0 ) {
RemoteInfo info { file_view . 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 ;
}
}
return FileId ( file_node - > main_file_id_ . get ( ) , remote_id ) ;
2018-12-31 20:04:05 +01:00
}
Result < FileId > FileManager : : get_input_thumbnail_file_id ( const tl_object_ptr < td_api : : InputFile > & thumbnail_input_file ,
DialogId owner_dialog_id , bool is_encrypted ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-12-31 20:04:05 +01:00
if ( thumbnail_input_file = = nullptr ) {
return Status : : Error ( 6 , " inputThumbnail not specified " ) ;
}
switch ( thumbnail_input_file - > get_id ( ) ) {
case td_api : : inputFileLocal : : ID : {
const string & path = static_cast < const td_api : : inputFileLocal * > ( thumbnail_input_file . get ( ) ) - > path_ ;
2020-08-02 00:28:01 +02:00
return register_local_internal (
2018-12-31 20:04:05 +01:00
FullLocalFileLocation ( is_encrypted ? FileType : : EncryptedThumbnail : FileType : : Thumbnail , path , 0 ) ,
owner_dialog_id , 0 , false ) ;
}
case td_api : : inputFileId : : ID :
return Status : : Error ( 6 , " InputFileId is not supported for thumbnails " ) ;
case td_api : : inputFileRemote : : ID :
return Status : : Error ( 6 , " InputFileRemote is not supported for thumbnails " ) ;
case td_api : : inputFileGenerated : : ID : {
auto * generated_thumbnail = static_cast < const td_api : : inputFileGenerated * > ( thumbnail_input_file . get ( ) ) ;
2020-08-02 00:28:01 +02:00
return register_generate_internal ( is_encrypted ? FileType : : EncryptedThumbnail : FileType : : Thumbnail ,
2018-01-26 13:56:19 +01:00
FileLocationSource : : FromUser , generated_thumbnail - > original_path_ ,
generated_thumbnail - > conversion_ , owner_dialog_id , generated_thumbnail - > expected_size_ ) ;
2018-12-31 20:04:05 +01:00
}
default :
UNREACHABLE ( ) ;
return Status : : Error ( 500 , " Unreachable " ) ;
}
}
Result < FileId > FileManager : : 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 , bool is_secure ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2020-03-20 14:36:07 +01:00
if ( file = = nullptr ) {
2018-12-31 20:04:05 +01:00
if ( allow_zero ) {
return FileId ( ) ;
}
2020-03-20 14:36:07 +01:00
return Status : : Error ( 6 , " InputFile is not specified " ) ;
2018-12-31 20:04:05 +01:00
}
2018-04-11 16:21:24 +02:00
if ( is_encrypted | | is_secure ) {
get_by_hash = false ;
}
2018-04-03 19:49:07 +02:00
auto new_type = is_encrypted ? FileType : : Encrypted : ( is_secure ? FileType : : Secure : type ) ;
2018-01-05 15:24:41 +01:00
auto r_file_id = [ & ] ( ) - > Result < FileId > {
switch ( file - > get_id ( ) ) {
case td_api : : inputFileLocal : : ID : {
const string & path = static_cast < const td_api : : inputFileLocal * > ( file . get ( ) ) - > path_ ;
if ( allow_zero & & path . empty ( ) ) {
return FileId ( ) ;
}
2020-04-23 23:50:14 +02:00
string hash ;
if ( false & & new_type = = FileType : : Photo ) {
auto r_stat = stat ( path ) ;
2020-05-07 17:37:49 +02:00
if ( r_stat . is_ok ( ) & & r_stat . ok ( ) . size_ > 0 & & r_stat . ok ( ) . size_ < 5000000 ) {
2020-04-23 23:50:14 +02:00
auto r_file_content = read_file_str ( path , r_stat . ok ( ) . size_ ) ;
if ( r_file_content . is_ok ( ) ) {
hash = sha256 ( r_file_content . ok ( ) ) ;
auto it = file_hash_to_file_id_ . find ( hash ) ;
if ( it ! = file_hash_to_file_id_ . end ( ) ) {
2020-05-04 15:01:35 +02:00
auto file_view = get_file_view ( it - > second ) ;
if ( file_view . has_remote_location ( ) & & ! file_view . remote_location ( ) . is_web ( ) ) {
return it - > second ;
}
2020-04-23 23:50:14 +02:00
}
}
}
}
2020-08-02 00:28:01 +02:00
TRY_RESULT ( file_id , register_local_internal ( FullLocalFileLocation ( new_type , path , 0 ) , owner_dialog_id , 0 , get_by_hash ) ) ;
2020-04-23 23:50:14 +02:00
if ( ! hash . empty ( ) ) {
file_hash_to_file_id_ [ hash ] = file_id ;
}
return file_id ;
2018-12-31 20:04:05 +01:00
}
2018-01-05 15:24:41 +01:00
case td_api : : inputFileId : : ID : {
2018-03-06 19:31:20 +01:00
FileId file_id ( static_cast < const td_api : : inputFileId * > ( file . get ( ) ) - > id_ , 0 ) ;
2018-01-05 15:24:41 +01:00
if ( ! file_id . is_valid ( ) ) {
return FileId ( ) ;
}
return file_id ;
2018-12-31 20:04:05 +01:00
}
2018-01-05 15:24:41 +01:00
case td_api : : inputFileRemote : : ID : {
const string & file_persistent_id = static_cast < const td_api : : inputFileRemote * > ( file . get ( ) ) - > id_ ;
if ( allow_zero & & file_persistent_id . empty ( ) ) {
return FileId ( ) ;
}
return from_persistent_id ( file_persistent_id , type ) ;
2018-12-31 20:04:05 +01:00
}
2018-01-05 15:24:41 +01:00
case td_api : : inputFileGenerated : : ID : {
auto * generated_file = static_cast < const td_api : : inputFileGenerated * > ( file . get ( ) ) ;
2020-08-02 00:28:01 +02:00
return register_generate_internal ( new_type , FileLocationSource : : FromUser , generated_file - > original_path_ ,
2018-04-03 19:49:07 +02:00
generated_file - > conversion_ , owner_dialog_id , generated_file - > expected_size_ ) ;
2018-01-05 15:24:41 +01:00
}
default :
UNREACHABLE ( ) ;
return Status : : Error ( 500 , " Unreachable " ) ;
2018-12-31 20:04:05 +01:00
}
2018-01-05 15:24:41 +01:00
} ( ) ;
2018-04-03 19:49:07 +02:00
return check_input_file_id ( type , std : : move ( r_file_id ) , is_encrypted , allow_zero , is_secure ) ;
2018-12-31 20:04:05 +01:00
}
2018-08-13 22:18:27 +02:00
Result < FileId > FileManager : : get_map_thumbnail_file_id ( Location location , int32 zoom , int32 width , int32 height ,
int32 scale , DialogId owner_dialog_id ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-08-13 22:18:27 +02:00
if ( ! location . is_valid_map_point ( ) ) {
return Status : : Error ( 6 , " Invalid location specified " ) ;
}
if ( zoom < 13 | | zoom > 20 ) {
return Status : : Error ( 6 , " Wrong zoom " ) ;
}
if ( width < 16 | | width > 1024 ) {
return Status : : Error ( 6 , " Wrong width " ) ;
}
if ( height < 16 | | height > 1024 ) {
return Status : : Error ( 6 , " Wrong height " ) ;
}
if ( scale < 1 | | scale > 3 ) {
return Status : : Error ( 6 , " Wrong scale " ) ;
}
const double PI = 3.14159265358979323846 ;
double sin_latitude = std : : sin ( location . get_latitude ( ) * PI / 180 ) ;
int32 size = 256 * ( 1 < < zoom ) ;
int32 x = static_cast < int32 > ( ( location . get_longitude ( ) + 180 ) / 360 * size ) ;
int32 y = static_cast < int32 > ( ( 0.5 - std : : log ( ( 1 + sin_latitude ) / ( 1 - sin_latitude ) ) / ( 4 * PI ) ) * size ) ;
x = clamp ( x , 0 , size - 1 ) ; // just in case
y = clamp ( y , 0 , size - 1 ) ; // just in case
string conversion = PSTRING ( ) < < " #map# " < < zoom < < " # " < < x < < " # " < < y < < " # " < < width < < " # " < < height < < " # "
< < scale < < " # " ;
2020-08-02 00:28:01 +02:00
return register_generate_internal (
2018-12-17 21:59:24 +01:00
owner_dialog_id . get_type ( ) = = DialogType : : SecretChat ? FileType : : EncryptedThumbnail : FileType : : Thumbnail ,
FileLocationSource : : FromUser , string ( ) , std : : move ( conversion ) , owner_dialog_id , 0 ) ;
2018-08-13 22:18:27 +02:00
}
2018-12-31 20:04:05 +01:00
vector < tl_object_ptr < telegram_api : : InputDocument > > FileManager : : get_input_documents ( const vector < FileId > & file_ids ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-12-31 20:04:05 +01:00
vector < tl_object_ptr < telegram_api : : InputDocument > > result ;
result . reserve ( file_ids . size ( ) ) ;
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 ( ) ) ;
}
return result ;
}
2019-01-25 02:38:11 +01:00
bool FileManager : : extract_was_uploaded ( const tl_object_ptr < telegram_api : : InputMedia > & input_media ) {
if ( input_media = = nullptr ) {
return false ;
}
auto input_media_id = input_media - > get_id ( ) ;
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 ) {
return false ;
}
return static_cast < const telegram_api : : inputMediaUploadedDocument * > ( input_media . get ( ) ) - > thumb_ ! = nullptr ;
}
2019-01-25 04:01:09 +01:00
string FileManager : : extract_file_reference ( const tl_object_ptr < telegram_api : : InputMedia > & input_media ) {
2020-08-02 00:28:01 +02:00
// don't lock this method because now it only calls the other extract_file_reference
2019-01-29 00:32:26 +01:00
if ( input_media = = nullptr ) {
return string ( ) ;
}
switch ( input_media - > get_id ( ) ) {
case telegram_api : : inputMediaDocument : : ID :
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_ ) ;
default :
return string ( ) ;
}
}
string FileManager : : extract_file_reference ( const tl_object_ptr < telegram_api : : InputDocument > & input_document ) {
if ( input_document = = nullptr | | input_document - > get_id ( ) ! = telegram_api : : inputDocument : : ID ) {
return string ( ) ;
2019-01-25 04:01:09 +01:00
}
2019-01-29 00:32:26 +01:00
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 ) {
if ( input_photo = = nullptr | | input_photo - > get_id ( ) ! = telegram_api : : inputPhoto : : ID ) {
return string ( ) ;
}
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 ) {
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 ) {
2020-08-02 00:28:01 +02:00
// don't lock this method because now it only calls the other extract_file_reference
2019-01-29 00:32:26 +01:00
if ( input_chat_photo = = nullptr | | input_chat_photo - > get_id ( ) ! = telegram_api : : inputChatPhoto : : ID ) {
return string ( ) ;
}
return extract_file_reference ( static_cast < const telegram_api : : inputChatPhoto * > ( input_chat_photo . get ( ) ) - > id_ ) ;
2019-01-25 04:01:09 +01:00
}
2018-12-31 20:04:05 +01:00
FileId FileManager : : next_file_id ( ) {
2020-05-23 21:27:24 +02:00
auto id = file_id_seqno + + ;
FileId res ( static_cast < int32 > ( id ) , 0 ) ;
file_id_info_ [ id ] = { } ;
res . set_time ( ) ;
2018-12-31 20:04:05 +01:00
return res ;
}
FileManager : : FileNodeId FileManager : : next_file_node_id ( ) {
2020-08-02 02:08:24 +02:00
auto id = file_node_seqno + + ;
auto res = static_cast < FileNodeId > ( id ) ;
file_nodes_ [ id ] = nullptr ;
2018-12-31 20:04:05 +01:00
return res ;
}
2018-01-09 12:57:11 +01:00
void FileManager : : on_start_download ( QueryId query_id ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-05-24 12:43:50 +02:00
if ( is_closed_ ) {
return ;
}
2018-01-09 12:57:11 +01:00
auto query = queries_container_ . get ( query_id ) ;
2020-05-23 21:27:24 +02:00
if ( query = = nullptr ) {
return ;
}
2018-01-09 12:57:11 +01:00
auto file_id = query - > file_id_ ;
2018-01-30 21:04:22 +01:00
auto file_node = get_file_node ( file_id ) ;
2018-05-30 21:45:42 +02:00
LOG ( DEBUG ) < < " Receive on_start_download for file " < < file_id ;
2018-01-30 21:04:22 +01:00
if ( ! file_node ) {
2018-01-09 12:57:11 +01:00
return ;
}
if ( file_node - > download_id_ ! = query_id ) {
return ;
}
LOG ( DEBUG ) < < " Start to download part of file " < < file_id ;
file_node - > is_download_started_ = true ;
}
2018-12-26 22:42:26 +01:00
void FileManager : : on_partial_download ( QueryId query_id , const PartialLocalFileLocation & partial_local , int64 ready_size ,
int64 size ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-05-24 12:43:50 +02:00
if ( is_closed_ ) {
return ;
}
2018-12-31 20:04:05 +01:00
auto query = queries_container_ . get ( query_id ) ;
2020-05-23 21:27:24 +02:00
if ( query = = nullptr ) {
return ;
}
2018-12-31 20:04:05 +01:00
auto file_id = query - > file_id_ ;
2018-01-30 21:04:22 +01:00
auto file_node = get_file_node ( file_id ) ;
2018-12-27 18:46:28 +01:00
LOG ( DEBUG ) < < " Receive on_partial_download for file " < < file_id < < " with " < < partial_local
< < " , ready_size = " < < ready_size < < " and size = " < < size ;
2018-01-30 21:04:22 +01:00
if ( ! file_node ) {
2018-12-31 20:04:05 +01:00
return ;
}
if ( file_node - > download_id_ ! = query_id ) {
return ;
}
2018-12-26 22:42:26 +01:00
if ( size ! = 0 ) {
2018-12-28 00:29:03 +01:00
FileView file_view ( file_node ) ;
if ( ! file_view . is_encrypted_secure ( ) ) {
file_node - > set_size ( size ) ;
}
2018-12-26 22:42:26 +01:00
}
2018-12-26 17:11:15 +01:00
file_node - > set_local_location ( LocalFileLocation ( partial_local ) , ready_size , - 1 , - 1 /* TODO */ ) ;
2018-12-27 18:23:19 +01:00
try_flush_node ( file_node , " on_partial_download " ) ;
2018-12-31 20:04:05 +01:00
}
2018-04-03 19:49:07 +02:00
void FileManager : : on_hash ( QueryId query_id , string hash ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-05-24 12:43:50 +02:00
if ( is_closed_ ) {
return ;
}
2018-04-03 19:49:07 +02:00
auto query = queries_container_ . get ( query_id ) ;
2020-05-23 21:27:24 +02:00
if ( query = = nullptr ) {
return ;
}
2018-04-03 19:49:07 +02:00
auto file_id = query - > file_id_ ;
auto file_node = get_file_node ( file_id ) ;
2018-05-30 21:45:42 +02:00
LOG ( DEBUG ) < < " Receive on_hash for file " < < file_id ;
2018-04-03 19:49:07 +02:00
if ( ! file_node ) {
return ;
}
if ( file_node - > upload_id_ ! = query_id ) {
return ;
}
file_node - > encryption_key_ . set_value_hash ( secure_storage : : ValueHash : : create ( hash ) . move_as_ok ( ) ) ;
}
2018-12-31 20:04:05 +01:00
void FileManager : : on_partial_upload ( QueryId query_id , const PartialRemoteFileLocation & partial_remote ,
int64 ready_size ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-05-24 12:43:50 +02:00
if ( is_closed_ ) {
return ;
}
2018-12-31 20:04:05 +01:00
auto query = queries_container_ . get ( query_id ) ;
2020-05-23 21:27:24 +02:00
if ( query = = nullptr ) {
return ;
}
2018-12-31 20:04:05 +01:00
auto file_id = query - > file_id_ ;
2018-01-30 21:04:22 +01:00
auto file_node = get_file_node ( file_id ) ;
2018-12-27 17:50:45 +01:00
LOG ( DEBUG ) < < " Receive on_partial_upload for file " < < file_id < < " with " < < partial_remote ;
2018-01-30 21:04:22 +01:00
if ( ! file_node ) {
2018-12-31 20:04:05 +01:00
return ;
}
if ( file_node - > upload_id_ ! = query_id ) {
return ;
}
2019-02-14 12:20:40 +01:00
file_node - > set_partial_remote_location ( partial_remote , ready_size ) ;
2018-12-27 18:23:19 +01:00
try_flush_node ( file_node , " on_partial_upload " ) ;
2018-12-31 20:04:05 +01:00
}
2018-05-24 12:43:50 +02:00
2019-01-11 18:08:56 +01:00
void FileManager : : on_download_ok ( QueryId query_id , const FullLocalFileLocation & local , int64 size , bool is_new ) {
2020-08-02 00:28:01 +02:00
std : : shared_lock < std : : shared_timed_mutex > readerLock ( memory_cleanup_mutex ) ;
2018-05-24 12:43:50 +02:00
if ( is_closed_ ) {
return ;
}
2020-06-01 19:48:18 +02:00
Query query ;
bool was_active ;
std : : tie ( query , was_active ) = finish_query ( query_id ) ;
2019-01-11 03:45:03 +01:00
auto file_id = query . file_id_ ;
2019-01-11 18:08:56 +01:00
LOG ( INFO ) < < " ON DOWNLOAD OK of " < < ( is_new ? " new " : " checked " ) < < " file " < < file_id < < " of size " < < size ;
2020-08-02 00:28:01 +02:00
auto r_new_file_id = register_local_internal ( local , DialogId ( ) , size , false , false , true ) ;
2020-06-01 19:48:18 +02:00
Status status = Status : : OK ( ) ;
2018-12-31 20:04:05 +01:00
if ( r_new_file_id . is_error ( ) ) {
2020-06-01 20:35:06 +02:00
status = Status : : Error ( PSLICE ( ) < < " Can't register local file after download: " < < r_new_file_id . error ( ) . message ( ) ) ;
2018-12-31 20:04:05 +01:00
} else {
2019-01-11 18:08:56 +01:00
if ( is_new ) {
2020-02-19 15:57:30 +01:00
context_ - > on_new_file ( size , get_file_view ( r_new_file_id . ok ( ) ) . get_allocated_local_size ( ) , 1 ) ;
2019-01-11 18:08:56 +01:00
}
2020-08-02 00:28:01 +02:00
auto r_file_id = merge_internal ( r_new_file_id . ok ( ) , file_id ) ;
2020-06-01 19:48:18 +02:00
if ( r_file_id . is_error ( ) ) {
status = r_file_id . move_as_error ( ) ;
}
}
if ( status . is_error ( ) ) {
LOG ( ERROR ) < < status . message ( ) ;
return on_error_impl ( get_file_node ( file_id ) , query . type_ , was_active , std : : move ( status ) ) ;
2018-12-31 20:04:05 +01:00
}
}
2018-05-24 12:43:50 +02:00
2018-12-31 20:04:05 +01:00
void FileManager : : on_upload_ok ( QueryId query_id , FileType file_type , const PartialRemoteFileLocation & partial_remote ,
int64 size ) {
2018-05-24 12:43:50 +02:00
if ( is_closed_ ) {
return ;
}
2018-12-31 20:04:05 +01:00
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 ;
2018-01-30 21:04:22 +01:00
auto file_node = get_file_node ( some_file_id ) ;
if ( ! file_node ) {
2018-12-31 20:04:05 +01:00
return ;
}
FileId file_id ;
uint64 file_id_upload_order { std : : numeric_limits < uint64 > : : max ( ) } ;
for ( auto id : file_node - > file_ids_ ) {
auto * info = get_file_id_info ( id ) ;
if ( info - > upload_priority_ ! = 0 & & info - > upload_order_ < file_id_upload_order ) {
file_id = id ;
file_id_upload_order = info - > upload_order_ ;
}
}
if ( ! file_id . is_valid ( ) ) {
return ;
}
auto * file_info = get_file_id_info ( file_id ) ;
2019-01-10 22:12:51 +01:00
LOG ( INFO ) < < " Found being uploaded file " < < file_id < < " with priority " < < file_info - > upload_priority_ ;
2018-12-31 20:04:05 +01:00
file_info - > upload_priority_ = 0 ;
file_info - > download_priority_ = 0 ;
FileView file_view ( file_node ) ;
2018-02-20 00:29:19 +01:00
string file_name = get_file_name ( file_type , file_view . suggested_name ( ) ) ;
2018-12-31 20:04:05 +01:00
2018-03-27 15:11:15 +02:00
if ( file_view . is_encrypted_secret ( ) ) {
2018-12-31 20:04:05 +01:00
tl_object_ptr < telegram_api : : InputEncryptedFile > input_file ;
if ( partial_remote . is_big_ ) {
input_file = make_tl_object < telegram_api : : inputEncryptedFileBigUploaded > (
partial_remote . file_id_ , partial_remote . part_count_ , file_view . encryption_key ( ) . calc_fingerprint ( ) ) ;
} else {
input_file = make_tl_object < telegram_api : : inputEncryptedFileUploaded > (
partial_remote . file_id_ , partial_remote . part_count_ , " " , file_view . encryption_key ( ) . calc_fingerprint ( ) ) ;
}
if ( file_info - > upload_callback_ ) {
file_info - > upload_callback_ - > on_upload_encrypted_ok ( file_id , std : : move ( input_file ) ) ;
2019-01-10 22:12:51 +01:00
file_node - > set_upload_pause ( file_id ) ;
2018-12-31 20:04:05 +01:00
file_info - > upload_callback_ . reset ( ) ;
}
2018-03-27 15:11:15 +02:00
} else if ( file_view . is_secure ( ) ) {
tl_object_ptr < telegram_api : : InputSecureFile > input_file ;
input_file = make_tl_object < telegram_api : : inputSecureFileUploaded > (
partial_remote . file_id_ , partial_remote . part_count_ , " " /*md5*/ , BufferSlice ( ) /*file_hash*/ ,
BufferSlice ( ) /*encrypted_secret*/ ) ;
if ( file_info - > upload_callback_ ) {
file_info - > upload_callback_ - > on_upload_secure_ok ( file_id , std : : move ( input_file ) ) ;
file_node - > upload_pause_ = file_id ;
file_info - > upload_callback_ . reset ( ) ;
}
2018-12-31 20:04:05 +01:00
} else {
tl_object_ptr < telegram_api : : InputFile > input_file ;
if ( partial_remote . is_big_ ) {
input_file = make_tl_object < telegram_api : : inputFileBig > ( partial_remote . file_id_ , partial_remote . part_count_ ,
std : : move ( file_name ) ) ;
} else {
input_file = make_tl_object < telegram_api : : inputFile > ( partial_remote . file_id_ , partial_remote . part_count_ ,
std : : move ( file_name ) , " " ) ;
}
if ( file_info - > upload_callback_ ) {
file_info - > upload_callback_ - > on_upload_ok ( file_id , std : : move ( input_file ) ) ;
2019-01-10 22:12:51 +01:00
file_node - > set_upload_pause ( file_id ) ;
2018-12-31 20:04:05 +01:00
file_info - > upload_callback_ . reset ( ) ;
}
}
}
void FileManager : : on_upload_full_ok ( QueryId query_id , const FullRemoteFileLocation & remote ) {
2018-05-24 12:43:50 +02:00
if ( is_closed_ ) {
return ;
}
2018-12-31 20:04:05 +01:00
auto file_id = finish_query ( query_id ) . first . file_id_ ;
2018-05-30 19:50:11 +02:00
LOG ( INFO ) < < " ON UPLOAD FULL OK for file " < < file_id ;
2020-08-02 00:28:01 +02:00
auto new_file_id = register_remote_internal ( remote , FileLocationSource : : FromServer , DialogId ( ) , 0 , 0 , " " ) ;
LOG_STATUS ( merge_internal ( new_file_id , file_id ) ) ;
2018-12-31 20:04:05 +01:00
}
void FileManager : : on_partial_generate ( QueryId query_id , const PartialLocalFileLocation & partial_local ,
int32 expected_size ) {
2018-05-24 12:43:50 +02:00
if ( is_closed_ ) {
return ;
}
2018-12-31 20:04:05 +01:00
auto query = queries_container_ . get ( query_id ) ;
2020-05-23 21:27:24 +02:00
if ( query = = nullptr ) {
return ;
}
2018-12-31 20:04:05 +01:00
auto file_id = query - > file_id_ ;
2018-01-30 21:04:22 +01:00
auto file_node = get_file_node ( file_id ) ;
2018-12-27 17:50:45 +01:00
auto bitmask = Bitmask ( Bitmask : : Decode { } , partial_local . ready_bitmask_ ) ;
LOG ( DEBUG ) < < " Receive on_partial_generate for file " < < file_id < < " : " < < partial_local . path_ < < " " < < bitmask ;
2018-01-30 21:04:22 +01:00
if ( ! file_node ) {
2018-12-31 20:04:05 +01:00
return ;
}
if ( file_node - > generate_id_ ! = query_id ) {
return ;
}
2018-12-27 17:50:45 +01:00
auto ready_size = bitmask . get_total_size ( partial_local . part_size_ , file_node - > size_ ) ;
2018-12-27 16:37:57 +01:00
file_node - > set_local_location ( LocalFileLocation ( partial_local ) , ready_size , - 1 , - 1 /* TODO */ ) ;
2018-12-31 20:04:05 +01:00
// TODO check for size and local_size, abort generation if needed
2018-08-16 19:31:42 +02:00
if ( expected_size > 0 ) {
2018-12-31 20:04:05 +01:00
file_node - > set_expected_size ( expected_size ) ;
}
if ( ! file_node - > generate_was_update_ ) {
file_node - > generate_was_update_ = true ;
run_upload ( file_node , { } ) ;
}
if ( file_node - > upload_id_ ! = 0 ) {
send_closure ( file_load_manager_ , & FileLoadManager : : update_local_file_location , file_node - > upload_id_ ,
LocalFileLocation ( partial_local ) ) ;
}
2018-12-27 18:23:19 +01:00
try_flush_node ( file_node , " on_partial_generate " ) ;
2018-12-31 20:04:05 +01:00
}
2018-05-24 12:43:50 +02:00
2018-12-31 20:04:05 +01:00
void FileManager : : on_generate_ok ( QueryId query_id , const FullLocalFileLocation & local ) {
2018-05-24 12:43:50 +02:00
if ( is_closed_ ) {
return ;
}
2018-12-31 20:04:05 +01:00
Query query ;
bool was_active ;
std : : tie ( query , was_active ) = finish_query ( query_id ) ;
auto generate_file_id = query . file_id_ ;
2018-05-30 19:50:11 +02:00
LOG ( INFO ) < < " Receive on_generate_ok for file " < < generate_file_id < < " : " < < local ;
2018-01-30 21:04:22 +01:00
auto file_node = get_file_node ( generate_file_id ) ;
if ( ! file_node ) {
2018-12-31 20:04:05 +01:00
return ;
}
auto old_upload_id = file_node - > upload_id_ ;
2020-08-02 00:28:01 +02:00
auto r_new_file_id = register_local_internal ( local , DialogId ( ) , 0 ) ;
2018-12-31 20:04:05 +01:00
Status status ;
if ( r_new_file_id . is_error ( ) ) {
status = Status : : Error ( PSLICE ( ) < < " Can't register local file after generate: " < < r_new_file_id . error ( ) ) ;
} else {
2020-08-02 00:28:01 +02:00
auto result = merge_internal ( r_new_file_id . ok ( ) , generate_file_id ) ;
2018-12-31 20:04:05 +01:00
if ( result . is_error ( ) ) {
status = result . move_as_error ( ) ;
}
}
2018-01-25 14:11:05 +01:00
file_node = get_file_node ( generate_file_id ) ;
2018-12-31 20:04:05 +01:00
if ( status . is_error ( ) ) {
return on_error_impl ( file_node , query . type_ , was_active , std : : move ( status ) ) ;
}
2018-01-30 21:04:22 +01:00
CHECK ( file_node ) ;
2019-01-11 18:54:27 +01:00
FileView file_view ( file_node ) ;
if ( ! file_view . has_generate_location ( ) | | ! begins_with ( file_view . generate_location ( ) . conversion_ , " #file_id# " ) ) {
2020-02-19 15:57:30 +01:00
context_ - > on_new_file ( file_view . size ( ) , file_view . get_allocated_local_size ( ) , 1 ) ;
2019-01-11 18:54:27 +01:00
}
2018-12-31 20:04:05 +01:00
run_upload ( file_node , { } ) ;
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_ ,
LocalFileLocation ( local ) ) ;
}
}
}
void FileManager : : on_error ( QueryId query_id , Status status ) {
2018-05-24 12:43:50 +02:00
if ( is_closed_ ) {
return ;
}
2018-12-31 20:04:05 +01:00
Query query ;
bool was_active ;
std : : tie ( query , was_active ) = finish_query ( query_id ) ;
2018-01-30 21:04:22 +01:00
auto node = get_file_node ( query . file_id_ ) ;
2018-12-31 20:04:05 +01:00
if ( ! node ) {
2018-02-27 09:48:47 +01:00
LOG ( ERROR ) < < " Can't find file node for " < < query . file_id_ < < " " < < status ;
2018-12-31 20:04:05 +01:00
return ;
}
2019-12-23 15:32:03 +01:00
if ( query . type_ = = Query : : Type : : UploadByHash & & ! G ( ) - > close_flag ( ) ) {
2018-12-31 20:04:05 +01:00
LOG ( INFO ) < < " Upload By Hash failed: " < < status < < " , restart upload " ;
node - > get_by_hash_ = false ;
run_upload ( node , { } ) ;
return ;
}
on_error_impl ( node , query . type_ , was_active , std : : move ( status ) ) ;
}
2019-12-23 15:32:03 +01:00
void FileManager : : on_error_impl ( FileNodePtr node , Query : : Type type , bool was_active , Status status ) {
2018-12-31 20:04:05 +01:00
SCOPE_EXIT {
2018-12-27 18:23:19 +01:00
try_flush_node ( node , " on_error " ) ;
2018-12-31 20:04:05 +01:00
} ;
2018-05-24 00:30:47 +02:00
if ( status . code ( ) ! = 1 & & ! G ( ) - > close_flag ( ) ) {
2020-01-06 15:54:16 +01:00
LOG ( WARNING ) < < " Failed to " < < type < < " file " < < node - > main_file_id_ < < " of type " < < FileView ( node ) . get_type ( )
< < " : " < < status ;
2018-12-31 20:04:05 +01:00
if ( status . code ( ) = = 0 ) {
// Remove partial locations
2019-02-10 00:39:58 +01:00
if ( node - > local_ . type ( ) = = LocalFileLocation : : Type : : Partial & &
2019-02-18 20:08:05 +01:00
! begins_with ( status . message ( ) , " FILE_UPLOAD_RESTART " ) & &
! begins_with ( status . message ( ) , " FILE_DOWNLOAD_RESTART " ) & &
2020-06-27 18:48:08 +02:00
! begins_with ( status . message ( ) , " FILE_DOWNLOAD_ID_INVALID " ) & &
2019-02-18 20:08:05 +01:00
! begins_with ( status . message ( ) , " FILE_DOWNLOAD_LIMIT " ) ) {
2018-12-28 17:54:46 +01:00
CSlice path = node - > local_ . partial ( ) . path_ ;
if ( begins_with ( path , get_files_temp_dir ( FileType : : Encrypted ) ) | |
begins_with ( path , get_files_temp_dir ( FileType : : Video ) ) ) {
LOG ( INFO ) < < " Unlink file " < < path ;
unlink ( path ) . ignore ( ) ;
node - > drop_local_location ( ) ;
}
2018-12-31 20:04:05 +01:00
}
2019-02-14 12:20:40 +01:00
node - > delete_partial_remote_location ( ) ;
2018-12-31 20:04:05 +01:00
status = Status : : Error ( 400 , status . message ( ) ) ;
}
}
2018-12-27 09:34:36 +01:00
if ( status . message ( ) = = " FILE_PART_INVALID " ) {
2019-02-14 12:20:40 +01:00
bool has_partial_small_location = node - > remote_ . partial & & ! node - > remote_ . partial - > is_big_ ;
2018-12-27 16:09:09 +01:00
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 ) ;
2018-12-27 09:34:36 +01:00
2019-02-14 12:20:40 +01:00
node - > delete_partial_remote_location ( ) ;
2018-12-27 09:34:36 +01:00
if ( has_partial_small_location & & should_be_big_location ) {
run_upload ( node , { } ) ;
return ;
}
2019-02-10 00:39:58 +01:00
LOG ( WARNING ) < < " 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 ;
2018-12-27 09:34:36 +01:00
}
2018-11-06 17:02:19 +01:00
if ( begins_with ( status . message ( ) , " FILE_GENERATE_LOCATION_INVALID " ) ) {
node - > set_generate_location ( nullptr ) ;
}
2019-07-30 16:42:36 +02:00
2020-01-27 12:39:19 +01:00
if ( ( status . message ( ) = = " FILE_ID_INVALID " | | status . message ( ) = = " LOCATION_INVALID " ) & &
FileView ( node ) . may_reload_photo ( ) ) {
2019-07-30 16:42:36 +02:00
node - > need_reload_photo_ = true ;
run_download ( node ) ;
return ;
}
2019-01-23 17:00:56 +01:00
if ( FileReferenceManager : : is_file_reference_error ( status ) ) {
2018-12-05 10:32:31 +01:00
string file_reference ;
2019-01-23 17:00:56 +01:00
Slice prefix = " #BASE64 " ;
auto pos = status . message ( ) . rfind ( ' # ' ) ;
if ( pos < status . message ( ) . size ( ) & & begins_with ( status . message ( ) . substr ( pos ) , prefix ) ) {
auto r_file_reference = base64_decode ( status . message ( ) . substr ( pos + prefix . size ( ) ) ) ;
2019-01-05 16:13:27 +01:00
if ( r_file_reference . is_ok ( ) ) {
file_reference = r_file_reference . move_as_ok ( ) ;
} else {
LOG ( ERROR ) < < " Can't decode file reference from error " < < status < < " : " < < r_file_reference . error ( ) ;
2018-12-05 10:32:31 +01:00
}
2018-12-08 23:00:27 +01:00
} else {
LOG ( ERROR ) < < " Unexpected error, file_reference will be deleted just in case " < < status ;
2018-12-05 10:32:31 +01:00
}
CHECK ( ! node - > file_ids_ . empty ( ) ) ;
2020-08-02 00:28:01 +02:00
delete_file_reference_internal ( node - > file_ids_ . back ( ) , file_reference ) ;
2018-12-05 10:32:31 +01:00
run_download ( node ) ;
return ;
}
2018-11-06 17:02:19 +01:00
2019-02-10 00:39:58 +01:00
if ( begins_with ( status . message ( ) , " FILE_UPLOAD_RESTART " ) ) {
2019-01-17 21:42:00 +01:00
if ( ends_with ( status . message ( ) , " WITH_FILE_REFERENCE " ) ) {
node - > upload_was_update_file_reference_ = true ;
}
2018-01-29 18:46:06 +01:00
run_upload ( node , { } ) ;
return ;
}
2018-12-05 10:32:31 +01:00
if ( begins_with ( status . message ( ) , " FILE_DOWNLOAD_RESTART " ) ) {
2019-01-17 21:42:00 +01:00
if ( ends_with ( status . message ( ) , " WITH_FILE_REFERENCE " ) ) {
node - > download_was_update_file_reference_ = true ;
2019-08-19 11:31:25 +02:00
run_download ( node ) ;
return ;
} else if ( ends_with ( status . message ( ) , " INCREASE_PART_SIZE " ) ) {
2019-08-30 03:56:01 +02:00
if ( try_fix_partial_local_location ( node ) ) {
2019-08-19 11:31:25 +02:00
run_download ( node ) ;
return ;
}
2019-01-17 21:42:00 +01:00
} else {
2018-12-05 10:32:31 +01:00
node - > can_search_locally_ = false ;
2019-08-19 11:31:25 +02:00
run_download ( node ) ;
return ;
2018-12-05 10:32:31 +01:00
}
2018-02-26 11:05:14 +01:00
}
2018-01-29 18:46:06 +01:00
2018-12-31 20:04:05 +01:00
if ( ! was_active ) {
return ;
}
// Stop everything on error
2019-01-25 02:52:38 +01:00
do_cancel_generate ( node ) ;
do_cancel_download ( node ) ;
do_cancel_upload ( node ) ;
2018-12-31 20:04:05 +01:00
2018-02-01 15:12:32 +01:00
for ( auto file_id : vector < FileId > ( node - > file_ids_ ) ) {
2018-12-31 20:04:05 +01:00
auto * info = get_file_id_info ( file_id ) ;
if ( info - > download_priority_ ! = 0 ) {
info - > download_priority_ = 0 ;
if ( info - > download_callback_ ) {
info - > download_callback_ - > on_download_error ( file_id , status . clone ( ) ) ;
info - > download_callback_ . reset ( ) ;
}
}
if ( info - > upload_priority_ ! = 0 ) {
info - > upload_priority_ = 0 ;
if ( info - > upload_callback_ ) {
info - > upload_callback_ - > on_upload_error ( file_id , status . clone ( ) ) ;
info - > upload_callback_ . reset ( ) ;
}
}
}
}
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 ) ;
CHECK ( query ! = nullptr ) ;
auto res = * query ;
2018-01-30 21:04:22 +01:00
auto node = get_file_node ( res . file_id_ ) ;
2018-12-31 20:04:05 +01:00
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 ) {
node - > download_id_ = 0 ;
2019-01-17 21:42:00 +01:00
node - > download_was_update_file_reference_ = false ;
2018-01-09 12:57:11 +01:00
node - > is_download_started_ = false ;
2018-12-31 20:04:05 +01:00
node - > set_download_priority ( 0 ) ;
was_active = true ;
}
if ( node - > upload_id_ = = query_id ) {
node - > upload_id_ = 0 ;
2019-01-17 21:42:00 +01:00
node - > upload_was_update_file_reference_ = false ;
2018-12-31 20:04:05 +01:00
node - > set_upload_priority ( 0 ) ;
was_active = true ;
}
return std : : make_pair ( res , was_active ) ;
}
2018-01-20 12:47:53 +01:00
2018-03-06 19:31:20 +01:00
FullRemoteFileLocation * FileManager : : get_remote ( int32 key ) {
if ( key = = 0 ) {
return nullptr ;
}
return & remote_location_info_ . get ( key ) . remote_ ;
}
2018-12-31 20:04:05 +01:00
void FileManager : : hangup ( ) {
file_db_ . reset ( ) ;
file_generate_manager_ . reset ( ) ;
file_load_manager_ . reset ( ) ;
2018-05-24 00:30:47 +02:00
while ( ! queries_container_ . empty ( ) ) {
auto ids = queries_container_ . ids ( ) ;
for ( auto id : ids ) {
2018-06-28 23:06:17 +02:00
on_error ( id , Status : : Error ( 500 , " Request aborted " ) ) ;
2018-05-24 00:30:47 +02:00
}
}
2018-05-24 12:43:50 +02:00
is_closed_ = true ;
2018-12-31 20:04:05 +01:00
stop ( ) ;
}
2018-01-20 12:47:53 +01:00
2020-05-23 21:27:24 +02:00
void FileManager : : destroy_query ( int32 file_id ) {
for ( auto & query_id : queries_container_ . ids ( ) ) {
auto query = queries_container_ . get ( query_id ) ;
if ( query ! = nullptr & & file_id = = query - > file_id_ . fast_get ( ) ) {
on_error ( query_id , Status : : Error ( 400 , " FILE_DOWNLOAD_RESTART " ) ) ;
}
}
}
void FileManager : : memory_cleanup ( ) {
2020-08-03 12:23:50 +02:00
LOG ( ERROR ) < < " Initial registered ids: " < < file_id_info_ . size ( ) < < " registered nodes: " < < file_nodes_ . size ( ) ;
2020-05-23 21:27:24 +02:00
/* DESTROY OLD file_id_info_ */
2020-08-03 13:29:20 +02:00
if ( true ) {
2020-08-02 00:28:01 +02:00
std : : lock_guard < std : : shared_timed_mutex > writerLock ( memory_cleanup_mutex ) ;
2020-05-23 21:27:24 +02:00
auto it = file_id_info_ . begin ( ) ;
auto time = std : : time ( nullptr ) ;
std : : vector < int32 > file_to_be_deleted = { } ;
while ( it ! = file_id_info_ . end ( ) ) {
if ( it - > second . node_id_ ! = 0 ) {
2020-08-03 13:29:20 +02:00
auto find_node = file_nodes_ . find ( it - > second . node_id_ ) ;
if ( find_node ! = file_nodes_ . end ( ) ) {
auto & node = find_node - > second ;
if ( time - node - > main_file_id_ . get_time ( ) > FILE_TTL ) {
auto can_reset = node - > download_priority_ = = 0 ;
can_reset & = node - > generate_download_priority_ = = 0 ;
can_reset & = node - > download_id_ = = 0 ;
if ( can_reset ) {
auto file_ids_it = node - > file_ids_ . begin ( ) ;
while ( file_ids_it ! = node - > file_ids_ . end ( ) & & can_reset ) {
auto find_file = file_id_info_ . find ( file_ids_it - > fast_get ( ) ) ;
if ( find_file ! = file_id_info_ . end ( ) ) {
auto & file = find_file - > second ;
can_reset & = file . download_priority_ = = 0 ;
can_reset & = time - file_ids_it - > get_time ( ) > FILE_TTL ;
}
file_ids_it + + ;
}
2020-05-23 21:27:24 +02:00
}
2020-08-03 13:29:20 +02:00
if ( can_reset ) {
node - > main_file_id_ . reset_time ( ) ;
2020-05-23 21:27:24 +02:00
2020-08-03 13:29:20 +02:00
for ( auto & file_id : node - > file_ids_ ) {
file_id . reset_time ( ) ;
2020-05-23 21:27:24 +02:00
2020-08-03 13:29:20 +02:00
/* DESTROY ASSOCIATED QUERIES */
destroy_query ( file_id . fast_get ( ) ) ;
2020-05-23 21:27:24 +02:00
2020-08-03 13:29:20 +02:00
/* DESTROY ASSOCIATED LATE */
file_to_be_deleted . push_back ( file_id . fast_get ( ) ) ;
}
2020-05-23 21:27:24 +02:00
2020-08-03 13:29:20 +02:00
/* DESTROY MAIN QUERY */
destroy_query ( it - > first ) ;
2020-05-23 21:27:24 +02:00
2020-08-03 13:29:20 +02:00
/* DESTROY MAIN NODE */
file_nodes_ . erase ( it - > first ) ;
2020-05-23 21:27:24 +02:00
2020-08-03 13:29:20 +02:00
/* DESTROY MAIN FILE LATE */
file_to_be_deleted . push_back ( it - > first ) ;
}
2020-05-23 21:27:24 +02:00
}
2020-08-03 13:29:20 +02:00
} else {
/* The file has a nonexistent node associated */
file_to_be_deleted . push_back ( it - > first ) ;
2020-05-23 21:27:24 +02:00
}
} else {
2020-08-03 13:29:20 +02:00
// todo: When the program starts there is a file that points to the node 0. It shouldn't happen but it happens, so don't delete it, maybe that file is used by tdlib for some reason.
// file_to_be_deleted.push_back(it->first);
2020-05-23 21:27:24 +02:00
}
2020-08-03 13:29:20 +02:00
it + + ;
2020-05-23 21:27:24 +02:00
}
for ( auto file_id : file_to_be_deleted ) {
2020-05-24 18:01:52 +02:00
context_ - > destroy_file_source ( { file_id , 0 } ) ;
2020-05-23 21:27:24 +02:00
file_id_info_ . erase ( file_id ) ;
}
}
/* DESTROY INVALID FILES */
2020-08-03 13:29:20 +02:00
if ( true ) {
2020-05-23 21:27:24 +02:00
auto it = file_id_info_ . begin ( ) ;
while ( it ! = file_id_info_ . end ( ) ) {
2020-08-03 13:29:20 +02:00
auto is_invalid = false ;
2020-05-23 21:27:24 +02:00
if ( it - > second . node_id_ ! = 0 ) {
2020-08-02 00:28:01 +02:00
auto find_file_node = file_nodes_ . find ( it - > second . node_id_ ) ;
if ( find_file_node = = file_nodes_ . end ( ) | | find_file_node - > second - > empty ) {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
2020-05-23 21:27:24 +02:00
destroy_query ( it - > first ) ;
context_ - > destroy_file_source ( { it - > first , 0 } ) ;
file_nodes_ . erase ( it - > second . node_id_ ) ;
}
} else {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
}
if ( is_invalid ) {
it = file_id_info_ . erase ( it ) ;
} else {
it + + ;
2020-05-23 21:27:24 +02:00
}
}
}
/* DESTROY INVALID file_nodes_ */
2020-08-03 13:29:20 +02:00
if ( true ) {
2020-05-23 21:27:24 +02:00
auto it = file_nodes_ . begin ( ) ;
while ( it ! = file_nodes_ . end ( ) ) {
2020-08-03 13:29:20 +02:00
auto is_invalid = false ;
2020-08-03 12:23:50 +02:00
if ( it - > second = = nullptr | | it - > second - > empty ) {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
2020-05-23 21:27:24 +02:00
} else {
2020-08-02 00:28:01 +02:00
if ( it - > second - > main_file_id_ . empty ( ) ) {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
2020-05-23 21:27:24 +02:00
} else {
2020-08-02 00:28:01 +02:00
if ( file_id_info_ [ it - > second - > main_file_id_ . get ( ) ] . node_id_ = = 0 ) {
for ( auto & file_id : it - > second - > file_ids_ ) {
2020-05-24 18:01:52 +02:00
context_ - > destroy_file_source ( file_id ) ;
file_id_info_ . erase ( file_id . get ( ) ) ;
}
2020-08-02 00:28:01 +02:00
file_id_info_ . erase ( it - > second - > main_file_id_ . get ( ) ) ;
2020-08-03 13:29:20 +02:00
is_invalid = true ;
2020-05-23 21:27:24 +02:00
}
}
}
2020-08-03 13:29:20 +02:00
if ( is_invalid ) {
it = file_nodes_ . erase ( it ) ;
} else {
it + + ;
}
2020-05-23 21:27:24 +02:00
}
}
/* DESTROY INVALID file_hash_to_file_id_ */
2020-08-03 13:29:20 +02:00
if ( true ) {
2020-05-23 21:27:24 +02:00
auto it = file_hash_to_file_id_ . begin ( ) ;
while ( it ! = file_hash_to_file_id_ . end ( ) ) {
2020-08-03 13:29:20 +02:00
auto is_invalid = false ;
2020-08-03 12:23:50 +02:00
auto find_file = file_id_info_ . find ( it - > second . fast_get ( ) ) ;
if ( find_file ! = file_id_info_ . end ( ) ) {
auto & file = find_file - > second ;
auto find_file_node = file_nodes_ . find ( file . node_id_ ) ;
if ( find_file_node = = file_nodes_ . end ( ) | | find_file_node - > second - > empty ) {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
2020-08-03 12:23:50 +02:00
file_nodes_ . erase ( file . node_id_ ) ;
}
2020-05-23 21:27:24 +02:00
} else {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
}
if ( is_invalid ) {
it = file_hash_to_file_id_ . erase ( it ) ;
} else {
it + + ;
2020-05-23 21:27:24 +02:00
}
}
}
/* DESTROY INVALID local_location_to_file_id_ */
2020-08-03 13:29:20 +02:00
if ( true ) {
2020-05-23 21:27:24 +02:00
auto it = local_location_to_file_id_ . begin ( ) ;
while ( it ! = local_location_to_file_id_ . end ( ) ) {
2020-08-03 13:29:20 +02:00
auto is_invalid = false ;
2020-08-03 12:23:50 +02:00
auto find_file = file_id_info_ . find ( it - > second . fast_get ( ) ) ;
if ( find_file ! = file_id_info_ . end ( ) ) {
auto & file = find_file - > second ;
auto find_file_node = file_nodes_ . find ( file . node_id_ ) ;
if ( find_file_node = = file_nodes_ . end ( ) | | find_file_node - > second - > empty ) {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
2020-08-03 12:23:50 +02:00
file_nodes_ . erase ( file . node_id_ ) ;
}
2020-05-23 21:27:24 +02:00
} else {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
}
if ( is_invalid ) {
it = local_location_to_file_id_ . erase ( it ) ;
} else {
it + + ;
2020-05-23 21:27:24 +02:00
}
}
}
/* DESTROY INVALID generate_location_to_file_id_ */
2020-08-03 13:29:20 +02:00
if ( true ) {
2020-05-23 21:27:24 +02:00
auto it = generate_location_to_file_id_ . begin ( ) ;
while ( it ! = generate_location_to_file_id_ . end ( ) ) {
2020-08-03 13:29:20 +02:00
auto is_invalid = false ;
2020-08-03 12:23:50 +02:00
auto find_file = file_id_info_ . find ( it - > second . fast_get ( ) ) ;
if ( find_file ! = file_id_info_ . end ( ) ) {
auto & file = find_file - > second ;
auto find_file_node = file_nodes_ . find ( file . node_id_ ) ;
if ( find_file_node = = file_nodes_ . end ( ) | | find_file_node - > second - > empty ) {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
2020-08-03 12:23:50 +02:00
file_nodes_ . erase ( file . node_id_ ) ;
}
2020-05-23 21:27:24 +02:00
} else {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
}
if ( is_invalid ) {
it = generate_location_to_file_id_ . erase ( it ) ;
} else {
it + + ;
2020-05-23 21:27:24 +02:00
}
}
}
/* DESTROY INVALID remote_location_info_ */
2020-08-03 13:29:20 +02:00
if ( true ) {
2020-05-23 21:27:24 +02:00
auto map = remote_location_info_ . get_map ( ) ;
auto it = map . begin ( ) ;
while ( it ! = map . end ( ) ) {
2020-08-03 13:29:20 +02:00
auto is_invalid = false ;
2020-08-03 12:23:50 +02:00
auto find_file = file_id_info_ . find ( it - > first . file_id_ . fast_get ( ) ) ;
if ( find_file ! = file_id_info_ . end ( ) ) {
auto & file = find_file - > second ;
auto find_file_node = file_nodes_ . find ( file . node_id_ ) ;
if ( find_file_node = = file_nodes_ . end ( ) | | find_file_node - > second - > empty ) {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
2020-08-03 12:23:50 +02:00
file_nodes_ . erase ( file . node_id_ ) ;
}
2020-05-23 21:27:24 +02:00
} else {
2020-08-03 13:29:20 +02:00
is_invalid = true ;
}
if ( is_invalid ) {
remote_location_info_ . erase ( it - > second ) ;
// Todo: check if if the map must be emptied, or if it's ok to just add the emptied id with Enumerator erase
// it = map.erase(it);
it + + ;
} else {
it + + ;
2020-05-23 21:27:24 +02:00
}
}
}
/* DESTROY NULL file_id_info_ */
2020-08-03 13:29:20 +02:00
if ( true ) {
2020-05-23 21:27:24 +02:00
auto it = file_id_info_ . begin ( ) ;
while ( it ! = file_id_info_ . end ( ) ) {
2020-08-03 13:29:20 +02:00
auto is_invalid = false ;
if ( it - > second . node_id_ ! = 0 ) {
auto find_file_node = file_nodes_ . find ( it - > second . node_id_ ) ;
if ( find_file_node = = file_nodes_ . end ( ) | | find_file_node - > second - > empty ) {
is_invalid = true ;
context_ - > destroy_file_source ( { it - > first , 0 } ) ;
}
} else {
is_invalid = true ;
}
if ( is_invalid ) {
it = file_id_info_ . erase ( it ) ;
2020-05-23 21:27:24 +02:00
} else {
2020-08-03 13:29:20 +02:00
it + + ;
2020-05-23 21:27:24 +02:00
}
}
}
2020-08-02 00:28:01 +02:00
file_nodes_ . rehash ( file_nodes_ . size ( ) + 1 ) ;
file_hash_to_file_id_ . rehash ( file_hash_to_file_id_ . size ( ) + 1 ) ;
file_id_info_ . rehash ( file_id_info_ . size ( ) + 1 ) ;
2020-05-23 21:27:24 +02:00
2020-08-03 12:23:50 +02:00
LOG ( ERROR ) < < " Final registered ids: " < < file_id_info_ . size ( ) < < " registered nodes: " < < file_nodes_ . size ( ) ;
2020-05-23 21:27:24 +02:00
}
2018-12-31 20:04:05 +01:00
void FileManager : : tear_down ( ) {
parent_ . reset ( ) ;
}
} // namespace td