2020-05-03 08:06:34 -04:00
# pragma once
# include <string>
# include <chrono>
# include <Definitions.h>
# include <condition_variable>
2020-05-13 05:32:08 -04:00
# include <utility>
2020-05-03 08:06:34 -04:00
# include <variant>
# include <deque>
# include <functional>
2020-05-13 05:32:08 -04:00
# include <atomic>
# include "./ExecuteResponse.h"
2020-05-03 08:06:34 -04:00
2020-05-07 15:28:15 -04:00
# define TRANSFER_KEY_LENGTH (32)
2020-06-10 12:13:14 -04:00
# define TRANSFER_MEDIA_BYTES_LENGTH (32)
2020-05-07 15:28:15 -04:00
2020-05-03 08:06:34 -04:00
namespace ts : : server : : file {
2020-05-13 05:32:08 -04:00
class VirtualFileServer ;
2020-05-03 08:06:34 -04:00
namespace filesystem {
template < typename ErrorCodes >
struct DetailedError {
ErrorCodes error_type { ErrorCodes : : UNKNOWN } ;
std : : string error_message { } ;
DetailedError ( ErrorCodes type , std : : string extraMessage ) : error_type { type } , error_message { std : : move ( extraMessage ) } { }
} ;
enum struct DirectoryQueryErrorType {
UNKNOWN ,
PATH_EXCEEDS_ROOT_PATH ,
PATH_IS_A_FILE ,
PATH_DOES_NOT_EXISTS ,
2020-05-13 05:32:08 -04:00
FAILED_TO_LIST_FILES
2020-05-03 08:06:34 -04:00
} ;
2020-05-13 05:32:08 -04:00
constexpr std : : array < std : : string_view , 5 > directory_query_error_messages = {
2020-05-03 08:06:34 -04:00
" unknown error " ,
" path exceeds base path " ,
" path is a file " ,
" path does not exists " ,
" failed to list files "
} ;
typedef DetailedError < DirectoryQueryErrorType > DirectoryQueryError ;
struct DirectoryEntry {
enum Type {
UNKNOWN ,
DIRECTORY ,
FILE
} ;
Type type { Type : : UNKNOWN } ;
std : : string name { } ;
std : : chrono : : system_clock : : time_point modified_at { } ;
2020-06-10 12:13:14 -04:00
size_t size { 0 } ; /* file only */
bool empty { false } ; /* directory only */
2020-05-03 08:06:34 -04:00
} ;
enum struct DirectoryModifyErrorType {
UNKNOWN ,
PATH_EXCEEDS_ROOT_PATH ,
PATH_ALREADY_EXISTS ,
FAILED_TO_CREATE_DIRECTORIES
} ;
typedef DetailedError < DirectoryModifyErrorType > DirectoryModifyError ;
enum struct FileModifyErrorType {
UNKNOWN ,
PATH_EXCEEDS_ROOT_PATH ,
TARGET_PATH_EXCEEDS_ROOT_PATH ,
PATH_DOES_NOT_EXISTS ,
TARGET_PATH_ALREADY_EXISTS ,
FAILED_TO_DELETE_FILES ,
FAILED_TO_RENAME_FILE ,
2020-05-13 05:32:08 -04:00
FAILED_TO_CREATE_DIRECTORIES ,
2020-05-03 08:06:34 -04:00
SOME_FILES_ARE_LOCKED
} ;
typedef DetailedError < FileModifyErrorType > FileModifyError ;
2020-05-13 05:32:08 -04:00
enum struct FileDeleteErrorType {
UNKNOWN ,
} ;
typedef DetailedError < FileDeleteErrorType > FileDeleteError ;
struct FileDeleteResponse {
enum struct StatusType {
SUCCESS ,
PATH_EXCEEDS_ROOT_PATH ,
PATH_DOES_NOT_EXISTS ,
FAILED_TO_DELETE_FILES ,
SOME_FILES_ARE_LOCKED
} ;
struct DeleteResult {
StatusType status { StatusType : : SUCCESS } ;
std : : string error_detail { } ;
DeleteResult ( StatusType status , std : : string errorDetail ) : status { status } ,
error_detail { std : : move ( errorDetail ) } { }
} ;
std : : vector < DeleteResult > delete_results { } ;
} ;
2020-05-03 08:06:34 -04:00
enum struct ServerCommandErrorType {
UNKNOWN ,
FAILED_TO_CREATE_DIRECTORIES ,
FAILED_TO_DELETE_DIRECTORIES
} ;
typedef DetailedError < ServerCommandErrorType > ServerCommandError ;
2020-05-13 05:32:08 -04:00
struct FileInfoResponse {
enum struct StatusType {
SUCCESS ,
PATH_EXCEEDS_ROOT_PATH ,
PATH_DOES_NOT_EXISTS ,
FAILED_TO_QUERY_INFO ,
UNKNOWN_FILE_TYPE
} ;
struct FileInfo {
StatusType status { StatusType : : SUCCESS } ;
std : : string error_detail { } ;
DirectoryEntry info { } ;
FileInfo ( StatusType status , std : : string errorDetail , DirectoryEntry info ) : status { status } ,
error_detail { std : : move ( errorDetail ) } , info { std : : move ( info ) } { }
} ;
std : : vector < FileInfo > file_info { } ;
} ;
enum struct FileInfoErrorType {
UNKNOWN ,
} ;
typedef DetailedError < FileInfoErrorType > FileInfoError ;
2020-05-03 08:06:34 -04:00
class AbstractProvider {
public :
typedef ExecuteResponse < DirectoryQueryError , std : : deque < DirectoryEntry > > directory_query_response_t ;
/* server */
2020-05-13 05:32:08 -04:00
[ [ nodiscard ] ] virtual std : : shared_ptr < ExecuteResponse < ServerCommandError > > initialize_server ( const std : : shared_ptr < VirtualFileServer > & /* server */ ) = 0 ;
[ [ nodiscard ] ] virtual std : : shared_ptr < ExecuteResponse < ServerCommandError > > delete_server ( const std : : shared_ptr < VirtualFileServer > & /* server */ ) = 0 ;
2020-05-03 08:06:34 -04:00
/* channels */
2020-06-10 12:13:14 -04:00
[ [ nodiscard ] ] virtual std : : shared_ptr < ExecuteResponse < FileInfoError , FileInfoResponse > > query_channel_info ( const std : : shared_ptr < VirtualFileServer > & /* server */ , const std : : vector < std : : tuple < ChannelId , std : : string > > & /* files */ ) = 0 ;
2020-05-13 05:32:08 -04:00
[ [ nodiscard ] ] virtual std : : shared_ptr < directory_query_response_t > query_channel_directory ( const std : : shared_ptr < VirtualFileServer > & /* server */ , ChannelId /* channel */ , const std : : string & /* path */ ) = 0 ;
[ [ nodiscard ] ] virtual std : : shared_ptr < ExecuteResponse < DirectoryModifyError > > create_channel_directory ( const std : : shared_ptr < VirtualFileServer > & /* server */ , ChannelId /* channel */ , const std : : string & /* path */ ) = 0 ;
[ [ nodiscard ] ] virtual std : : shared_ptr < ExecuteResponse < FileDeleteError , FileDeleteResponse > > delete_channel_files ( const std : : shared_ptr < VirtualFileServer > & /* server */ , ChannelId /* channel */ , const std : : vector < std : : string > & /* paths */ ) = 0 ;
[ [ nodiscard ] ] virtual std : : shared_ptr < ExecuteResponse < FileModifyError > > rename_channel_file ( const std : : shared_ptr < VirtualFileServer > & /* server */ , ChannelId /* channel */ , const std : : string & /* path */ , ChannelId /* target channel */ , const std : : string & /* target */ ) = 0 ;
2020-05-03 08:06:34 -04:00
/* icons */
2020-05-13 05:32:08 -04:00
[ [ nodiscard ] ] virtual std : : shared_ptr < ExecuteResponse < FileInfoError , FileInfoResponse > > query_icon_info ( const std : : shared_ptr < VirtualFileServer > & /* server */ , const std : : vector < std : : string > & /* names */ ) = 0 ;
[ [ nodiscard ] ] virtual std : : shared_ptr < directory_query_response_t > query_icon_directory ( const std : : shared_ptr < VirtualFileServer > & /* server */ ) = 0 ;
[ [ nodiscard ] ] virtual std : : shared_ptr < ExecuteResponse < FileDeleteError , FileDeleteResponse > > delete_icons ( const std : : shared_ptr < VirtualFileServer > & /* server */ , const std : : vector < std : : string > & /* names */ ) = 0 ;
2020-05-03 08:06:34 -04:00
/* avatars */
2020-05-13 05:32:08 -04:00
[ [ nodiscard ] ] virtual std : : shared_ptr < ExecuteResponse < FileInfoError , FileInfoResponse > > query_avatar_info ( const std : : shared_ptr < VirtualFileServer > & /* server */ , const std : : vector < std : : string > & /* names */ ) = 0 ;
[ [ nodiscard ] ] virtual std : : shared_ptr < directory_query_response_t > query_avatar_directory ( const std : : shared_ptr < VirtualFileServer > & /* server */ ) = 0 ;
[ [ nodiscard ] ] virtual std : : shared_ptr < ExecuteResponse < FileDeleteError , FileDeleteResponse > > delete_avatars ( const std : : shared_ptr < VirtualFileServer > & /* server */ , const std : : vector < std : : string > & /* names */ ) = 0 ;
2020-05-03 08:06:34 -04:00
private :
} ;
}
namespace transfer {
2020-07-23 14:28:43 -04:00
typedef uint16_t transfer_id ;
2020-05-03 08:06:34 -04:00
struct Transfer {
transfer_id server_transfer_id { 0 } ;
transfer_id client_transfer_id { 0 } ;
2020-05-13 05:32:08 -04:00
std : : shared_ptr < VirtualFileServer > server { nullptr } ;
2020-05-03 08:06:34 -04:00
ChannelId channel_id { 0 } ;
2020-05-13 05:32:08 -04:00
ClientId client_id { 0 } ;
std : : string client_unique_id { } ;
2020-05-07 15:28:15 -04:00
char transfer_key [ TRANSFER_KEY_LENGTH ] { } ;
2020-05-03 08:06:34 -04:00
std : : chrono : : system_clock : : time_point initialized_timestamp { } ;
enum Direction {
DIRECTION_UNKNOWN ,
DIRECTION_UPLOAD ,
DIRECTION_DOWNLOAD
} direction { DIRECTION_UNKNOWN } ;
2020-05-07 15:28:15 -04:00
struct Address {
std : : string hostname { } ;
uint16_t port { 0 } ;
} ;
std : : vector < Address > server_addresses { } ;
2020-05-03 08:06:34 -04:00
enum TargetType {
TARGET_TYPE_UNKNOWN ,
TARGET_TYPE_CHANNEL_FILE ,
TARGET_TYPE_ICON ,
TARGET_TYPE_AVATAR
} target_type { TARGET_TYPE_UNKNOWN } ;
std : : string target_file_path { } ;
2020-05-13 05:32:08 -04:00
std : : string absolute_file_path { } ;
std : : string relative_file_path { } ;
std : : string file_name { } ;
2020-05-03 08:06:34 -04:00
int64_t max_bandwidth { - 1 } ;
2020-05-07 15:28:15 -04:00
size_t expected_file_size { 0 } ; /* incl. the offset! */
2020-05-03 08:06:34 -04:00
size_t file_offset { 0 } ;
2020-05-07 15:28:15 -04:00
bool override_exiting { false } ;
2020-05-03 08:06:34 -04:00
} ;
struct TransferStatistics {
2020-05-07 15:28:15 -04:00
uint64_t network_bytes_send { 0 } ;
uint64_t network_bytes_received { 0 } ;
uint64_t delta_network_bytes_send { 0 } ;
uint64_t delta_network_bytes_received { 0 } ;
2020-05-03 08:06:34 -04:00
2020-05-07 15:28:15 -04:00
uint64_t file_bytes_transferred { 0 } ;
uint64_t delta_file_bytes_transferred { 0 } ;
2020-05-03 08:06:34 -04:00
2020-05-07 15:28:15 -04:00
size_t file_start_offset { 0 } ;
size_t file_current_offset { 0 } ;
size_t file_total_size { 0 } ;
2020-06-10 12:13:14 -04:00
double average_speed { 0 } ;
double current_speed { 0 } ;
2020-05-03 08:06:34 -04:00
} ;
struct TransferInitError {
enum Type {
2020-05-13 05:32:08 -04:00
UNKNOWN ,
INVALID_FILE_TYPE ,
FILE_DOES_NOT_EXISTS ,
FILE_IS_NOT_A_FILE ,
CLIENT_TOO_MANY_TRANSFERS ,
SERVER_TOO_MANY_TRANSFERS ,
SERVER_QUOTA_EXCEEDED ,
CLIENT_QUOTA_EXCEEDED ,
IO_ERROR
2020-05-03 08:06:34 -04:00
} error_type { UNKNOWN } ;
std : : string error_message { } ;
2020-05-13 05:32:08 -04:00
TransferInitError ( Type errorType , std : : string errorMessage ) : error_type { errorType } ,
error_message { std : : move ( errorMessage ) } { }
2020-05-03 08:06:34 -04:00
} ;
struct TransferActionError {
enum Type {
UNKNOWN ,
UNKNOWN_TRANSFER
} error_type { UNKNOWN } ;
std : : string error_message { } ;
} ;
struct TransferError {
enum Type {
UNKNOWN ,
2020-05-07 15:28:15 -04:00
TRANSFER_TIMEOUT ,
2020-05-03 08:06:34 -04:00
DISK_IO_ERROR ,
2020-05-07 15:28:15 -04:00
DISK_TIMEOUT ,
DISK_INITIALIZE_ERROR ,
2020-05-03 08:06:34 -04:00
NETWORK_IO_ERROR ,
2020-05-07 15:28:15 -04:00
UNEXPECTED_CLIENT_DISCONNECT ,
2020-05-14 09:08:28 -04:00
UNEXPECTED_DISK_EOF ,
USER_REQUEST
2020-05-03 08:06:34 -04:00
} error_type { UNKNOWN } ;
std : : string error_message { } ;
} ;
2020-05-13 05:32:08 -04:00
struct ActiveFileTransfer {
transfer_id client_transfer_id { 0 } ;
transfer_id server_transfer_id { 0 } ;
Transfer : : Direction direction { Transfer : : DIRECTION_UNKNOWN } ;
ClientId client_id { } ;
std : : string client_unique_id { } ;
std : : string file_path { } ;
std : : string file_name { } ;
size_t expected_size { } ;
size_t size_done { } ;
enum Status {
NOT_STARTED ,
RUNNING ,
INACTIVE /* (not used yet) */
} status { Status : : NOT_STARTED } ;
std : : chrono : : milliseconds runtime { } ;
double average_speed { 0 } ;
double current_speed { 0 } ;
} ;
enum struct TransferListError {
UNKNOWN
} ;
2020-05-03 08:06:34 -04:00
class AbstractProvider {
public :
struct TransferInfo {
std : : string file_path { } ;
2020-05-13 05:32:08 -04:00
std : : string client_unique_id { } ;
ClientId client_id { } ;
2020-05-03 08:06:34 -04:00
bool override_exiting { false } ; /* only for upload valid */
2020-05-13 05:32:08 -04:00
2020-05-03 08:06:34 -04:00
size_t file_offset { 0 } ;
size_t expected_file_size { 0 } ;
2020-05-13 05:32:08 -04:00
2020-05-03 08:06:34 -04:00
int64_t max_bandwidth { - 1 } ;
2020-05-13 05:32:08 -04:00
int64_t max_concurrent_transfers { - 1 } ;
/* only used for upload, for download the quotas could be checked before */
size_t download_server_quota_limit { ( size_t ) - 1 } ;
size_t download_client_quota_limit { ( size_t ) - 1 } ;
2020-05-03 08:06:34 -04:00
} ;
2020-05-13 05:32:08 -04:00
virtual std : : shared_ptr < ExecuteResponse < TransferInitError , std : : shared_ptr < Transfer > > >
initialize_channel_transfer ( Transfer : : Direction /* direction */ , const std : : shared_ptr < VirtualFileServer > & /* server */ , ChannelId /* channel */ , const TransferInfo & /* info */ ) = 0 ;
virtual std : : shared_ptr < ExecuteResponse < TransferInitError , std : : shared_ptr < Transfer > > >
initialize_icon_transfer ( Transfer : : Direction /* direction */ , const std : : shared_ptr < VirtualFileServer > & /* server */ , const TransferInfo & /* info */ ) = 0 ;
2020-05-03 08:06:34 -04:00
2020-05-13 05:32:08 -04:00
virtual std : : shared_ptr < ExecuteResponse < TransferInitError , std : : shared_ptr < Transfer > > >
initialize_avatar_transfer ( Transfer : : Direction /* direction */ , const std : : shared_ptr < VirtualFileServer > & /* server */ , const TransferInfo & /* info */ ) = 0 ;
virtual std : : shared_ptr < ExecuteResponse < TransferListError , std : : vector < ActiveFileTransfer > > > list_transfer ( ) = 0 ;
virtual std : : shared_ptr < ExecuteResponse < TransferActionError > > stop_transfer ( const std : : shared_ptr < VirtualFileServer > & /* server */ , transfer_id /* id */ , bool /* flush */ ) = 0 ;
2020-05-03 08:06:34 -04:00
2020-05-07 15:28:15 -04:00
std : : function < void ( const std : : shared_ptr < Transfer > & ) > callback_transfer_registered { } ; /* transfer has been registered */
2020-05-03 08:06:34 -04:00
std : : function < void ( const std : : shared_ptr < Transfer > & ) > callback_transfer_started { } ; /* transfer has been started */
std : : function < void ( const std : : shared_ptr < Transfer > & ) > callback_transfer_finished { } ; /* transfer has been finished */
std : : function < void ( const std : : shared_ptr < Transfer > & , const TransferStatistics & ) > callback_transfer_statistics { } ;
2020-05-13 12:03:14 -04:00
std : : function < void ( const std : : shared_ptr < Transfer > & , const transfer : : TransferStatistics & , const TransferError & ) > callback_transfer_aborted { } ; /* an error happened while transferring the data */
2020-05-03 08:06:34 -04:00
} ;
}
2020-05-13 05:32:08 -04:00
class VirtualFileServer {
public :
explicit VirtualFileServer ( ServerId server_id , std : : string unique_id ) : server_id_ { server_id } , unique_id_ { std : : move ( unique_id ) } { }
[ [ nodiscard ] ] inline auto unique_id ( ) const - > const std : : string & { return this - > unique_id_ ; }
[ [ nodiscard ] ] inline auto server_id ( ) const - > ServerId { return this - > server_id_ ; }
[ [ nodiscard ] ] inline auto max_networking_upload_bandwidth ( ) const - > int64_t { return this - > max_networking_upload_bandwidth_ ; }
virtual void max_networking_upload_bandwidth ( int64_t value ) {
this - > max_networking_upload_bandwidth_ = value ;
}
[ [ nodiscard ] ] inline auto max_networking_download_bandwidth ( ) const - > int64_t { return this - > max_networking_download_bandwidth_ ; }
virtual void max_networking_download_bandwidth ( int64_t value ) {
this - > max_networking_download_bandwidth_ = value ;
}
[ [ nodiscard ] ] inline auto generate_transfer_id ( ) {
return + + this - > current_transfer_id ;
}
private :
ServerId server_id_ ;
std : : string unique_id_ ;
int64_t max_networking_upload_bandwidth_ { - 1 } ;
int64_t max_networking_download_bandwidth_ { - 1 } ;
std : : atomic < transfer : : transfer_id > current_transfer_id { 0 } ;
} ;
2020-05-03 08:06:34 -04:00
class AbstractFileServer {
public :
2020-05-13 05:32:08 -04:00
[ [ nodiscard ] ] virtual std : : string file_base_path ( ) const = 0 ;
2020-05-03 08:06:34 -04:00
[ [ nodiscard ] ] virtual filesystem : : AbstractProvider & file_system ( ) = 0 ;
2020-05-07 15:28:15 -04:00
[ [ nodiscard ] ] virtual transfer : : AbstractProvider & file_transfer ( ) = 0 ;
2020-05-13 05:32:08 -04:00
[ [ nodiscard ] ] inline auto virtual_servers ( ) const - > std : : deque < std : : shared_ptr < VirtualFileServer > > {
std : : lock_guard slock { this - > servers_mutex } ;
return this - > servers_ ;
}
[ [ nodiscard ] ] inline auto find_virtual_server ( ServerId server_id ) const - > std : : shared_ptr < VirtualFileServer > {
std : : lock_guard slock { this - > servers_mutex } ;
auto it = std : : find_if ( this - > servers_ . begin ( ) , this - > servers_ . end ( ) , [ & ] ( const std : : shared_ptr < VirtualFileServer > & server ) {
return server - > server_id ( ) = = server_id ;
} ) ;
return it = = this - > servers_ . end ( ) ? nullptr : * it ;
}
virtual std : : shared_ptr < VirtualFileServer > register_server ( ServerId /* server id */ ) = 0 ;
virtual void unregister_server ( ServerId /* server id */ ) = 0 ;
protected :
mutable std : : mutex servers_mutex { } ;
std : : deque < std : : shared_ptr < VirtualFileServer > > servers_ { } ;
2020-05-03 08:06:34 -04:00
} ;
2020-06-12 19:08:49 -04:00
extern bool initialize ( std : : string & /* error */ , const std : : string & /* host names */ , uint16_t /* port */ ) ;
2020-05-03 08:06:34 -04:00
extern void finalize ( ) ;
extern std : : shared_ptr < AbstractFileServer > server ( ) ;
}