v2.0.4-rc (#37)
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				BlockStorage/repertory/pipeline/head This commit looks good
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	BlockStorage/repertory/pipeline/head This commit looks good
				
			# Changelog ## v2.0.4-rc ### BREAKING CHANGES * `renterd` v2.0.0+ is now required. Prior versions will fail to mount. ### Issues * \#35 [bug] Low frequency check is set to '0' instead of 1 hour by default * \#36 [bug] Max cache size bytes is set to '0' by default ### Changes from v2.0.3-rc * Added Sia API version check prior to mounting * Added back `-cv` (check version) CLI option * Continue documentation updates * Fixed setting `ApiAuth` via `set_value_by_name` * Fixed setting `HostConfig.ApiUser` via `set_value_by_name` * Fixed setting `HostConfig.Path` via `set_value_by_name` * Fixed setting `HostConfig.Protocol` via `set_value_by_name` * Improved ring buffer read-ahead * Integrated `renterd` version 2.0.0 * Prefer using local cache file when opening files * Refactored `app_config` unit tests * Refactored polling to be more accurate on scheduling tasks Reviewed-on: #37
This commit is contained in:
		@@ -192,6 +192,7 @@ secp256k1
 | 
				
			|||||||
secur32
 | 
					secur32
 | 
				
			||||||
sfml_project
 | 
					sfml_project
 | 
				
			||||||
shlwapi
 | 
					shlwapi
 | 
				
			||||||
 | 
					skynet
 | 
				
			||||||
source_subdir
 | 
					source_subdir
 | 
				
			||||||
spdlog
 | 
					spdlog
 | 
				
			||||||
spdlog_project
 | 
					spdlog_project
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,7 +1,34 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## v2.0.4-rc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### BREAKING CHANGES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `renterd` v2.0.0+ is now required. Prior versions will fail to mount.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Issues
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* \#35 [bug] Low frequency check is set to '0' instead of 1 hour by default
 | 
				
			||||||
 | 
					* \#36 [bug] Max cache size bytes is set to '0' by default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Changes from v2.0.3-rc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Added Sia API version check prior to mounting
 | 
				
			||||||
 | 
					* Added back `-cv` (check version) CLI option
 | 
				
			||||||
 | 
					* Continue documentation updates
 | 
				
			||||||
 | 
					* Fixed setting `ApiAuth` via `set_value_by_name`
 | 
				
			||||||
 | 
					* Fixed setting `HostConfig.ApiUser` via `set_value_by_name`
 | 
				
			||||||
 | 
					* Fixed setting `HostConfig.Path` via `set_value_by_name`
 | 
				
			||||||
 | 
					* Fixed setting `HostConfig.Protocol` via `set_value_by_name`
 | 
				
			||||||
 | 
					* Improved ring buffer read-ahead
 | 
				
			||||||
 | 
					* Integrated `renterd` version 2.0.0
 | 
				
			||||||
 | 
					* Prefer using local cache file when opening files
 | 
				
			||||||
 | 
					* Refactored `app_config` unit tests
 | 
				
			||||||
 | 
					* Refactored polling to be more accurate on scheduling tasks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## v2.0.3-rc
 | 
					## v2.0.3-rc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!-- markdownlint-disable-next-line -->
 | 
				
			||||||
### Issues
 | 
					### Issues
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* \#28 \[bug\] Address slow directory responses in S3 mounts for deeply nested directories
 | 
					* \#28 \[bug\] Address slow directory responses in S3 mounts for deeply nested directories
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,6 +58,10 @@ if(PROJECT_IS_MINGW)
 | 
				
			|||||||
  endif()
 | 
					  endif()
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					  add_definitions(-DPROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include(cmake/settings.cmake)
 | 
					include(cmake/settings.cmake)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
include(cmake/flags.cmake)
 | 
					include(cmake/flags.cmake)
 | 
				
			||||||
@@ -143,6 +147,7 @@ endif()
 | 
				
			|||||||
      -DPROJECT_COPYRIGHT=${PROJECT_COPYRIGHT}
 | 
					      -DPROJECT_COPYRIGHT=${PROJECT_COPYRIGHT}
 | 
				
			||||||
      -DPROJECT_DESC=${PROJECT_DESC}
 | 
					      -DPROJECT_DESC=${PROJECT_DESC}
 | 
				
			||||||
      -DPROJECT_DIST_DIR=${PROJECT_DIST_DIR}
 | 
					      -DPROJECT_DIST_DIR=${PROJECT_DIST_DIR}
 | 
				
			||||||
 | 
					      -DPROJECT_ENABLE_V2_ERRORS=${PROJECT_ENABLE_V2_ERRORS}
 | 
				
			||||||
      -DPROJECT_ENABLE_WIN32_LONG_PATH_NAMES=${PROJECT_ENABLE_WIN32_LONG_PATH_NAMES}
 | 
					      -DPROJECT_ENABLE_WIN32_LONG_PATH_NAMES=${PROJECT_ENABLE_WIN32_LONG_PATH_NAMES}
 | 
				
			||||||
      -DPROJECT_ENABLE_BOOST=${PROJECT_ENABLE_BOOST}
 | 
					      -DPROJECT_ENABLE_BOOST=${PROJECT_ENABLE_BOOST}
 | 
				
			||||||
      -DPROJECT_ENABLE_CPP_HTTPLIB=${PROJECT_ENABLE_CPP_HTTPLIB}
 | 
					      -DPROJECT_ENABLE_CPP_HTTPLIB=${PROJECT_ENABLE_CPP_HTTPLIB}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ on Windows.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Minimum Requirements
 | 
					## Minimum Requirements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v0.4.0+ for Sia support
 | 
					* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v2.0.0+ for Sia support
 | 
				
			||||||
* Only 64-bit operating systems are supported
 | 
					* Only 64-bit operating systems are supported
 | 
				
			||||||
  * By default, Linux requires `fusermount3`; otherwise, `repertory` must be manually compiled with `libfuse2` support
 | 
					  * By default, Linux requires `fusermount3`; otherwise, `repertory` must be manually compiled with `libfuse2` support
 | 
				
			||||||
  * Windows requires the following dependencies to be installed:
 | 
					  * Windows requires the following dependencies to be installed:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,15 @@
 | 
				
			|||||||
set(BINUTILS_VERSION 2.43)
 | 
					set(BINUTILS_VERSION 2.43)
 | 
				
			||||||
set(BOOST_MAJOR_VERSION 1)
 | 
					 | 
				
			||||||
set(BOOST_MINOR_VERSION 87)
 | 
					 | 
				
			||||||
set(BOOST_PATCH_VERSION 0)
 | 
					 | 
				
			||||||
set(BOOST2_MAJOR_VERSION 1)
 | 
					set(BOOST2_MAJOR_VERSION 1)
 | 
				
			||||||
set(BOOST2_MINOR_VERSION 76)
 | 
					set(BOOST2_MINOR_VERSION 76)
 | 
				
			||||||
set(BOOST2_PATCH_VERSION 0)
 | 
					set(BOOST2_PATCH_VERSION 0)
 | 
				
			||||||
 | 
					set(BOOST_MAJOR_VERSION 1)
 | 
				
			||||||
 | 
					set(BOOST_MINOR_VERSION 87)
 | 
				
			||||||
 | 
					set(BOOST_PATCH_VERSION 0)
 | 
				
			||||||
set(CPP_HTTPLIB_VERSION 0.18.1)
 | 
					set(CPP_HTTPLIB_VERSION 0.18.1)
 | 
				
			||||||
set(CURL_VERSION 8.11.0)
 | 
					 | 
				
			||||||
set(CURL2_VERSION 8_11_0)
 | 
					set(CURL2_VERSION 8_11_0)
 | 
				
			||||||
set(EXPAT_VERSION 2.6.4)
 | 
					set(CURL_VERSION 8.11.0)
 | 
				
			||||||
set(EXPAT2_VERSION 2_6_4)
 | 
					set(EXPAT2_VERSION 2_6_4)
 | 
				
			||||||
 | 
					set(EXPAT_VERSION 2.6.4)
 | 
				
			||||||
set(GCC_VERSION 14.2.0)
 | 
					set(GCC_VERSION 14.2.0)
 | 
				
			||||||
set(GTEST_VERSION 1.15.2)
 | 
					set(GTEST_VERSION 1.15.2)
 | 
				
			||||||
set(ICU_VERSION 76-1)
 | 
					set(ICU_VERSION 76-1)
 | 
				
			||||||
@@ -22,7 +22,7 @@ set(PKG_CONFIG_VERSION 0.29.2)
 | 
				
			|||||||
set(PUGIXML_VERSION 1.14)
 | 
					set(PUGIXML_VERSION 1.14)
 | 
				
			||||||
set(ROCKSDB_VERSION 9.7.4)
 | 
					set(ROCKSDB_VERSION 9.7.4)
 | 
				
			||||||
set(SPDLOG_VERSION 1.15.0)
 | 
					set(SPDLOG_VERSION 1.15.0)
 | 
				
			||||||
set(SQLITE_VERSION 3460100)
 | 
					 | 
				
			||||||
set(SQLITE2_VERSION 3.46.1)
 | 
					set(SQLITE2_VERSION 3.46.1)
 | 
				
			||||||
 | 
					set(SQLITE_VERSION 3460100)
 | 
				
			||||||
set(STDUUID_VERSION 1.2.3)
 | 
					set(STDUUID_VERSION 1.2.3)
 | 
				
			||||||
set(ZLIB_VERSION 1.3.1)
 | 
					set(ZLIB_VERSION 1.3.1)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ PROJECT_DESC="Mount utility for Sia and S3"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
PROJECT_MAJOR_VERSION=2
 | 
					PROJECT_MAJOR_VERSION=2
 | 
				
			||||||
PROJECT_MINOR_VERSION=0
 | 
					PROJECT_MINOR_VERSION=0
 | 
				
			||||||
PROJECT_REVISION_VERSION=3
 | 
					PROJECT_REVISION_VERSION=4
 | 
				
			||||||
PROJECT_RELEASE_NUM=0
 | 
					PROJECT_RELEASE_NUM=0
 | 
				
			||||||
PROJECT_RELEASE_ITER=rc
 | 
					PROJECT_RELEASE_ITER=rc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
FROM         arm64v8/alpine:3.21.0
 | 
					#comment
 | 
				
			||||||
 | 
					FROM         arm64v8/alpine:3.21.3
 | 
				
			||||||
MAINTAINER   Scott E. Graves <scott.e.graves@protonmail.com>
 | 
					MAINTAINER   Scott E. Graves <scott.e.graves@protonmail.com>
 | 
				
			||||||
CMD          bash
 | 
					CMD          bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
FROM         alpine:3.21.0
 | 
					#comment
 | 
				
			||||||
 | 
					FROM         alpine:3.21.3
 | 
				
			||||||
MAINTAINER   Scott E. Graves <scott.e.graves@protonmail.com>
 | 
					MAINTAINER   Scott E. Graves <scott.e.graves@protonmail.com>
 | 
				
			||||||
CMD          bash
 | 
					CMD          bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
#comment
 | 
					#comment
 | 
				
			||||||
FROM alpine:3.21.0
 | 
					FROM alpine:3.21.3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN apk update
 | 
					RUN apk update
 | 
				
			||||||
RUN apk upgrade
 | 
					RUN apk upgrade
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,26 +31,26 @@ private:
 | 
				
			|||||||
  static stop_type stop_requested;
 | 
					  static stop_type stop_requested;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  [[nodiscard]] static auto
 | 
					  [[nodiscard]] static auto default_agent_name(const provider_type &prov)
 | 
				
			||||||
  default_agent_name(const provider_type &prov) -> std::string;
 | 
					      -> std::string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] static auto
 | 
					  [[nodiscard]] static auto default_api_port(const provider_type &prov)
 | 
				
			||||||
  default_api_port(const provider_type &prov) -> std::uint16_t;
 | 
					      -> std::uint16_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] static auto
 | 
					  [[nodiscard]] static auto default_data_directory(const provider_type &prov)
 | 
				
			||||||
  default_data_directory(const provider_type &prov) -> std::string;
 | 
					      -> std::string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] static auto
 | 
					  [[nodiscard]] static auto default_remote_api_port(const provider_type &prov)
 | 
				
			||||||
  default_remote_api_port(const provider_type &prov) -> std::uint16_t;
 | 
					      -> std::uint16_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] static auto
 | 
					  [[nodiscard]] static auto default_rpc_port(const provider_type &prov)
 | 
				
			||||||
  default_rpc_port(const provider_type &prov) -> std::uint16_t;
 | 
					      -> std::uint16_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] static auto
 | 
					  [[nodiscard]] static auto get_provider_display_name(const provider_type &prov)
 | 
				
			||||||
  get_provider_display_name(const provider_type &prov) -> std::string;
 | 
					      -> std::string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] static auto
 | 
					  [[nodiscard]] static auto get_provider_name(const provider_type &prov)
 | 
				
			||||||
  get_provider_name(const provider_type &prov) -> std::string;
 | 
					      -> std::string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  [[nodiscard]] static auto get_stop_requested() -> bool;
 | 
					  [[nodiscard]] static auto get_stop_requested() -> bool;
 | 
				
			||||||
@@ -91,7 +91,6 @@ private:
 | 
				
			|||||||
  std::atomic<std::uint8_t> max_upload_count_;
 | 
					  std::atomic<std::uint8_t> max_upload_count_;
 | 
				
			||||||
  std::atomic<std::uint16_t> med_freq_interval_secs_;
 | 
					  std::atomic<std::uint16_t> med_freq_interval_secs_;
 | 
				
			||||||
  std::atomic<std::uint16_t> online_check_retry_secs_;
 | 
					  std::atomic<std::uint16_t> online_check_retry_secs_;
 | 
				
			||||||
  std::atomic<std::uint16_t> orphaned_file_retention_days_;
 | 
					 | 
				
			||||||
  std::atomic<download_type> preferred_download_type_;
 | 
					  std::atomic<download_type> preferred_download_type_;
 | 
				
			||||||
  std::atomic<std::uint16_t> retry_read_count_;
 | 
					  std::atomic<std::uint16_t> retry_read_count_;
 | 
				
			||||||
  std::atomic<std::uint16_t> ring_buffer_file_size_;
 | 
					  std::atomic<std::uint16_t> ring_buffer_file_size_;
 | 
				
			||||||
@@ -172,8 +171,6 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] auto get_online_check_retry_secs() const -> std::uint16_t;
 | 
					  [[nodiscard]] auto get_online_check_retry_secs() const -> std::uint16_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] auto get_orphaned_file_retention_days() const -> std::uint16_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  [[nodiscard]] auto get_preferred_download_type() const -> download_type;
 | 
					  [[nodiscard]] auto get_preferred_download_type() const -> download_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] auto get_provider_type() const -> provider_type;
 | 
					  [[nodiscard]] auto get_provider_type() const -> provider_type;
 | 
				
			||||||
@@ -192,8 +189,11 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] auto get_task_wait_ms() const -> std::uint16_t;
 | 
					  [[nodiscard]] auto get_task_wait_ms() const -> std::uint16_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] auto
 | 
					  [[nodiscard]] auto get_value_by_name(const std::string &name) const
 | 
				
			||||||
  get_value_by_name(const std::string &name) const -> std::string;
 | 
					      -> std::string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [[nodiscard]] auto get_raw_value_by_name(const std::string &name) const
 | 
				
			||||||
 | 
					      -> std::string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] auto get_version() const -> std::uint64_t;
 | 
					  [[nodiscard]] auto get_version() const -> std::uint64_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -239,8 +239,6 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  void set_online_check_retry_secs(std::uint16_t value);
 | 
					  void set_online_check_retry_secs(std::uint16_t value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void set_orphaned_file_retention_days(std::uint16_t value);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void set_preferred_download_type(const download_type &value);
 | 
					  void set_preferred_download_type(const download_type &value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void set_remote_config(remote::remote_config value);
 | 
					  void set_remote_config(remote::remote_config value);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,7 +57,7 @@ using json = nlohmann::json;
 | 
				
			|||||||
inline constexpr const std::string_view REPERTORY = "repertory";
 | 
					inline constexpr const std::string_view REPERTORY = "repertory";
 | 
				
			||||||
inline constexpr const std::wstring_view REPERTORY_W = L"repertory";
 | 
					inline constexpr const std::wstring_view REPERTORY_W = L"repertory";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline constexpr const std::uint64_t REPERTORY_CONFIG_VERSION = 0ULL;
 | 
					inline constexpr const std::uint64_t REPERTORY_CONFIG_VERSION = 1ULL;
 | 
				
			||||||
inline constexpr const std::string_view REPERTORY_DATA_NAME = "repertory2";
 | 
					inline constexpr const std::string_view REPERTORY_DATA_NAME = "repertory2";
 | 
				
			||||||
inline constexpr const std::string_view REPERTORY_MIN_REMOTE_VERSION = "2.0.0";
 | 
					inline constexpr const std::string_view REPERTORY_MIN_REMOTE_VERSION = "2.0.0";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -221,44 +221,25 @@ using WCHAR = wchar_t;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define MAX_PATH 260
 | 
					#define MAX_PATH 260
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STATUS_SUCCESS                                                         \
 | 
					#define STATUS_SUCCESS std::uint32_t{0U}
 | 
				
			||||||
  std::uint32_t { 0U }
 | 
					#define STATUS_ACCESS_DENIED std::uint32_t{0xC0000022L}
 | 
				
			||||||
#define STATUS_ACCESS_DENIED                                                   \
 | 
					#define STATUS_DEVICE_BUSY std::uint32_t{0x80000011L}
 | 
				
			||||||
  std::uint32_t { 0xC0000022L }
 | 
					#define STATUS_DEVICE_INSUFFICIENT_RESOURCES std::uint32_t{0xC0000468L}
 | 
				
			||||||
#define STATUS_DEVICE_BUSY                                                     \
 | 
					#define STATUS_DIRECTORY_NOT_EMPTY std::uint32_t{0xC0000101L}
 | 
				
			||||||
  std::uint32_t { 0x80000011L }
 | 
					#define STATUS_FILE_IS_A_DIRECTORY std::uint32_t{0xC00000BAL}
 | 
				
			||||||
#define STATUS_DEVICE_INSUFFICIENT_RESOURCES                                   \
 | 
					#define STATUS_FILE_TOO_LARGE std::uint32_t{0xC0000904L}
 | 
				
			||||||
  std::uint32_t { 0xC0000468L }
 | 
					#define STATUS_INSUFFICIENT_RESOURCES std::uint32_t{0xC000009AL}
 | 
				
			||||||
#define STATUS_DIRECTORY_NOT_EMPTY                                             \
 | 
					#define STATUS_INTERNAL_ERROR std::uint32_t{0xC00000E5L}
 | 
				
			||||||
  std::uint32_t { 0xC0000101L }
 | 
					#define STATUS_INVALID_ADDRESS std::uint32_t{0xC0000141L}
 | 
				
			||||||
#define STATUS_FILE_IS_A_DIRECTORY                                             \
 | 
					#define STATUS_INVALID_HANDLE std::uint32_t{0xC0000006L}
 | 
				
			||||||
  std::uint32_t { 0xC00000BAL }
 | 
					#define STATUS_INVALID_IMAGE_FORMAT std::uint32_t{0xC000007BL}
 | 
				
			||||||
#define STATUS_FILE_TOO_LARGE                                                  \
 | 
					#define STATUS_INVALID_PARAMETER std::uint32_t{0xC000000DL}
 | 
				
			||||||
  std::uint32_t { 0xC0000904L }
 | 
					#define STATUS_NO_MEMORY std::uint32_t{0xC0000017L}
 | 
				
			||||||
#define STATUS_INSUFFICIENT_RESOURCES                                          \
 | 
					#define STATUS_NOT_IMPLEMENTED std::uint32_t{0xC0000002L}
 | 
				
			||||||
  std::uint32_t { 0xC000009AL }
 | 
					#define STATUS_OBJECT_NAME_EXISTS std::uint32_t{0x40000000L}
 | 
				
			||||||
#define STATUS_INTERNAL_ERROR                                                  \
 | 
					#define STATUS_OBJECT_NAME_NOT_FOUND std::uint32_t{0xC0000034L}
 | 
				
			||||||
  std::uint32_t { 0xC00000E5L }
 | 
					#define STATUS_OBJECT_PATH_INVALID std::uint32_t{0xC0000039L}
 | 
				
			||||||
#define STATUS_INVALID_ADDRESS                                                 \
 | 
					#define STATUS_UNEXPECTED_IO_ERROR std::uint32_t{0xC00000E9L}
 | 
				
			||||||
  std::uint32_t { 0xC0000141L }
 | 
					 | 
				
			||||||
#define STATUS_INVALID_HANDLE                                                  \
 | 
					 | 
				
			||||||
  std::uint32_t { 0xC0000006L }
 | 
					 | 
				
			||||||
#define STATUS_INVALID_IMAGE_FORMAT                                            \
 | 
					 | 
				
			||||||
  std::uint32_t { 0xC000007BL }
 | 
					 | 
				
			||||||
#define STATUS_INVALID_PARAMETER                                               \
 | 
					 | 
				
			||||||
  std::uint32_t { 0xC000000DL }
 | 
					 | 
				
			||||||
#define STATUS_NO_MEMORY                                                       \
 | 
					 | 
				
			||||||
  std::uint32_t { 0xC0000017L }
 | 
					 | 
				
			||||||
#define STATUS_NOT_IMPLEMENTED                                                 \
 | 
					 | 
				
			||||||
  std::uint32_t { 0xC0000002L }
 | 
					 | 
				
			||||||
#define STATUS_OBJECT_NAME_EXISTS                                              \
 | 
					 | 
				
			||||||
  std::uint32_t { 0x40000000L }
 | 
					 | 
				
			||||||
#define STATUS_OBJECT_NAME_NOT_FOUND                                           \
 | 
					 | 
				
			||||||
  std::uint32_t { 0xC0000034L }
 | 
					 | 
				
			||||||
#define STATUS_OBJECT_PATH_INVALID                                             \
 | 
					 | 
				
			||||||
  std::uint32_t { 0xC0000039L }
 | 
					 | 
				
			||||||
#define STATUS_UNEXPECTED_IO_ERROR                                             \
 | 
					 | 
				
			||||||
  std::uint32_t { 0xC00000E9L }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CONVERT_STATUS_NOT_IMPLEMENTED(e)                                      \
 | 
					#define CONVERT_STATUS_NOT_IMPLEMENTED(e)                                      \
 | 
				
			||||||
  ((std::uint32_t(e) == STATUS_NOT_IMPLEMENTED) ? -ENOTSUP : e)
 | 
					  ((std::uint32_t(e) == STATUS_NOT_IMPLEMENTED) ? -ENOTSUP : e)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@
 | 
				
			|||||||
#include "comm/packet/packet_client.hpp"
 | 
					#include "comm/packet/packet_client.hpp"
 | 
				
			||||||
#include "drives/remote/remote_open_file_table.hpp"
 | 
					#include "drives/remote/remote_open_file_table.hpp"
 | 
				
			||||||
#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
 | 
					#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
 | 
				
			||||||
 | 
					#include "types/remote.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
class app_config;
 | 
					class app_config;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					  Copyright <2018-2025> <scott.e.graves@protonmail.com>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					  of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					  in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					  copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					  furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					  copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					  SOFTWARE.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#ifndef REPERTORY_INCLUDE_EVENTS_TYPES_PRODIVER_INVALID_VERSION_HPP_
 | 
				
			||||||
 | 
					#define REPERTORY_INCLUDE_EVENTS_TYPES_PRODIVER_INVALID_VERSION_HPP_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "events/i_event.hpp"
 | 
				
			||||||
 | 
					#include "types/repertory.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace repertory {
 | 
				
			||||||
 | 
					struct provider_invalid_version final : public i_event {
 | 
				
			||||||
 | 
					  provider_invalid_version() = default;
 | 
				
			||||||
 | 
					  provider_invalid_version(std::string_view function_name_,
 | 
				
			||||||
 | 
					                           std::string required_version_,
 | 
				
			||||||
 | 
					                           std::string returned_version_)
 | 
				
			||||||
 | 
					      : function_name(std::string(function_name_)),
 | 
				
			||||||
 | 
					        required_version(std::move(required_version_)),
 | 
				
			||||||
 | 
					        returned_version(std::move(returned_version_)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static constexpr const event_level level{event_level::error};
 | 
				
			||||||
 | 
					  static constexpr const std::string_view name{"provider_invalid_version"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::string function_name;
 | 
				
			||||||
 | 
					  std::string required_version;
 | 
				
			||||||
 | 
					  std::string returned_version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [[nodiscard]] auto get_event_level() const -> event_level override {
 | 
				
			||||||
 | 
					    return level;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [[nodiscard]] auto get_name() const -> std::string_view override {
 | 
				
			||||||
 | 
					    return name;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [[nodiscard]] auto get_single_line() const -> std::string override {
 | 
				
			||||||
 | 
					    return fmt::format("{}|func|{}|required|{}|returned|{}", name,
 | 
				
			||||||
 | 
					                       function_name, required_version, returned_version);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					} // namespace repertory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NLOHMANN_JSON_NAMESPACE_BEGIN
 | 
				
			||||||
 | 
					template <> struct adl_serializer<repertory::provider_invalid_version> {
 | 
				
			||||||
 | 
					  static void to_json(json &data,
 | 
				
			||||||
 | 
					                      const repertory::provider_invalid_version &value) {
 | 
				
			||||||
 | 
					    data["function_name"] = value.function_name;
 | 
				
			||||||
 | 
					    data["required_version"] = value.required_version;
 | 
				
			||||||
 | 
					    data["returned_version"] = value.returned_version;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static void from_json(const json &data,
 | 
				
			||||||
 | 
					                        repertory::provider_invalid_version &value) {
 | 
				
			||||||
 | 
					    data.at("function_name").get_to(value.function_name);
 | 
				
			||||||
 | 
					    data.at("required_version").get_to(value.required_version);
 | 
				
			||||||
 | 
					    data.at("returned_version").get_to(value.returned_version);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					NLOHMANN_JSON_NAMESPACE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // REPERTORY_INCLUDE_EVENTS_TYPES_PRODIVER_INVALID_VERSION_HPP_
 | 
				
			||||||
@@ -85,6 +85,13 @@ private:
 | 
				
			|||||||
  void remove_deleted_files(stop_type &stop_requested);
 | 
					  void remove_deleted_files(stop_type &stop_requested);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					  [[nodiscard]] auto check_version(std::string &required_version,
 | 
				
			||||||
 | 
					                                   std::string &returned_version) const
 | 
				
			||||||
 | 
					      -> bool override {
 | 
				
			||||||
 | 
					    required_version = returned_version = "";
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] auto create_directory(const std::string &api_path,
 | 
					  [[nodiscard]] auto create_directory(const std::string &api_path,
 | 
				
			||||||
                                      api_meta_map &meta) -> api_error override;
 | 
					                                      api_meta_map &meta) -> api_error override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,10 @@ class i_provider {
 | 
				
			|||||||
  INTERFACE_SETUP(i_provider);
 | 
					  INTERFACE_SETUP(i_provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					  [[nodiscard]] virtual auto check_version(std::string &required_version,
 | 
				
			||||||
 | 
					                                           std::string &returned_version) const
 | 
				
			||||||
 | 
					      -> bool = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] virtual auto create_directory(const std::string &api_path,
 | 
					  [[nodiscard]] virtual auto create_directory(const std::string &api_path,
 | 
				
			||||||
                                              api_meta_map &meta)
 | 
					                                              api_meta_map &meta)
 | 
				
			||||||
      -> api_error = 0;
 | 
					      -> api_error = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -113,6 +113,13 @@ protected:
 | 
				
			|||||||
      -> api_error override;
 | 
					      -> api_error override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					  [[nodiscard]] auto check_version(std::string &required_version,
 | 
				
			||||||
 | 
					                                   std::string &returned_version) const
 | 
				
			||||||
 | 
					      -> bool override {
 | 
				
			||||||
 | 
					    required_version = returned_version = "";
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] static auto convert_api_date(std::string_view date)
 | 
					  [[nodiscard]] static auto convert_api_date(std::string_view date)
 | 
				
			||||||
      -> std::uint64_t;
 | 
					      -> std::uint64_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,6 +80,10 @@ protected:
 | 
				
			|||||||
      -> api_error override;
 | 
					      -> api_error override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					  [[nodiscard]] auto check_version(std::string &required_version,
 | 
				
			||||||
 | 
					                                   std::string &returned_version) const
 | 
				
			||||||
 | 
					      -> bool override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  [[nodiscard]] auto get_directory_item_count(const std::string &api_path) const
 | 
					  [[nodiscard]] auto get_directory_item_count(const std::string &api_path) const
 | 
				
			||||||
      -> std::uint64_t override;
 | 
					      -> std::uint64_t override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,30 +24,27 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
constexpr const auto default_api_auth_size{48U};
 | 
					constexpr const auto default_api_auth_size{48U};
 | 
				
			||||||
constexpr const auto default_download_timeout_ces{30U};
 | 
					constexpr const auto default_download_timeout_secs{30U};
 | 
				
			||||||
constexpr const auto default_eviction_delay_mins{1U};
 | 
					constexpr const auto default_eviction_delay_mins{1U};
 | 
				
			||||||
constexpr const auto default_high_freq_interval_secs{30U};
 | 
					constexpr const auto default_high_freq_interval_secs{std::uint16_t{30U}};
 | 
				
			||||||
constexpr const auto default_low_freq_interval_secs{0U * 60U};
 | 
					constexpr const auto default_low_freq_interval_secs{std::uint16_t(60U * 60U)};
 | 
				
			||||||
constexpr const auto default_max_cache_size_bytes{
 | 
					constexpr const auto default_max_cache_size_bytes{
 | 
				
			||||||
    std::uint64_t(20UL * 1024UL * 1024UL * 1024UL),
 | 
					    std::uint64_t(20ULL * 1024ULL * 1024ULL * 1024ULL),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
constexpr const auto default_max_upload_count{5U};
 | 
					constexpr const auto default_max_upload_count{5U};
 | 
				
			||||||
constexpr const auto default_med_freq_interval_secs{2U * 60U};
 | 
					constexpr const auto default_med_freq_interval_secs{std::uint16_t{2U * 60U}};
 | 
				
			||||||
constexpr const auto default_online_check_retry_secs{60U};
 | 
					constexpr const auto default_online_check_retry_secs{60U};
 | 
				
			||||||
constexpr const auto default_orphaned_file_retention_days{15U};
 | 
					 | 
				
			||||||
constexpr const auto default_retry_read_count{6U};
 | 
					constexpr const auto default_retry_read_count{6U};
 | 
				
			||||||
constexpr const auto default_ring_buffer_file_size{512U};
 | 
					constexpr const auto default_ring_buffer_file_size{512U};
 | 
				
			||||||
constexpr const auto default_task_wait_ms{100U};
 | 
					constexpr const auto default_task_wait_ms{100U};
 | 
				
			||||||
constexpr const auto default_timeout_ms{60000U};
 | 
					constexpr const auto default_timeout_ms{60000U};
 | 
				
			||||||
constexpr const auto max_orphaned_file_retention_days{std::uint16_t(31U)};
 | 
					 | 
				
			||||||
constexpr const auto max_ring_buffer_file_size{std::uint16_t(1024U)};
 | 
					constexpr const auto max_ring_buffer_file_size{std::uint16_t(1024U)};
 | 
				
			||||||
constexpr const auto max_s3_object_name_length{1024U};
 | 
					constexpr const auto max_s3_object_name_length{1024U};
 | 
				
			||||||
constexpr const auto min_cache_size_bytes{
 | 
					constexpr const auto min_cache_size_bytes{
 | 
				
			||||||
    std::uint64_t(100UL * 1024UL * 1024UL),
 | 
					    std::uint64_t(100ULL * 1024ULL * 1024ULL),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
constexpr const auto min_download_timeout_secs{std::uint8_t(5U)};
 | 
					constexpr const auto min_download_timeout_secs{std::uint8_t(5U)};
 | 
				
			||||||
constexpr const auto min_online_check_retry_secs{std::uint16_t(15U)};
 | 
					constexpr const auto min_online_check_retry_secs{std::uint16_t(15U)};
 | 
				
			||||||
constexpr const auto min_orphaned_file_retention_days{std::uint16_t(1U)};
 | 
					 | 
				
			||||||
constexpr const auto min_retry_read_count{std::uint16_t(2U)};
 | 
					constexpr const auto min_retry_read_count{std::uint16_t(2U)};
 | 
				
			||||||
constexpr const auto min_ring_buffer_file_size{std::uint16_t(64U)};
 | 
					constexpr const auto min_ring_buffer_file_size{std::uint16_t(64U)};
 | 
				
			||||||
constexpr const auto min_task_wait_ms{std::uint16_t(50U)};
 | 
					constexpr const auto min_task_wait_ms{std::uint16_t(50U)};
 | 
				
			||||||
@@ -333,7 +330,6 @@ struct directory_item final {
 | 
				
			|||||||
  bool directory{false};
 | 
					  bool directory{false};
 | 
				
			||||||
  std::uint64_t size{};
 | 
					  std::uint64_t size{};
 | 
				
			||||||
  api_meta_map meta;
 | 
					  api_meta_map meta;
 | 
				
			||||||
  bool resolved{false};
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct encrypt_config final {
 | 
					struct encrypt_config final {
 | 
				
			||||||
@@ -493,8 +489,6 @@ inline constexpr const auto JSON_MED_FREQ_INTERVAL_SECS{
 | 
				
			|||||||
inline constexpr const auto JSON_META{"Meta"};
 | 
					inline constexpr const auto JSON_META{"Meta"};
 | 
				
			||||||
inline constexpr const auto JSON_ONLINE_CHECK_RETRY_SECS{
 | 
					inline constexpr const auto JSON_ONLINE_CHECK_RETRY_SECS{
 | 
				
			||||||
    "OnlineCheckRetrySeconds"};
 | 
					    "OnlineCheckRetrySeconds"};
 | 
				
			||||||
inline constexpr const auto JSON_ORPHANED_FILE_RETENTION_DAYS{
 | 
					 | 
				
			||||||
    "OrphanedFileRetentionDays"};
 | 
					 | 
				
			||||||
inline constexpr const auto JSON_PATH{"Path"};
 | 
					inline constexpr const auto JSON_PATH{"Path"};
 | 
				
			||||||
inline constexpr const auto JSON_PREFERRED_DOWNLOAD_TYPE{
 | 
					inline constexpr const auto JSON_PREFERRED_DOWNLOAD_TYPE{
 | 
				
			||||||
    "PreferredDownloadType"};
 | 
					    "PreferredDownloadType"};
 | 
				
			||||||
@@ -619,6 +613,16 @@ template <typename data_t> struct adl_serializer<repertory::atomic<data_t>> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <> struct adl_serializer<std::atomic<std::uint64_t>> {
 | 
				
			||||||
 | 
					  static void to_json(json &data, const std::atomic<std::uint64_t> &value) {
 | 
				
			||||||
 | 
					    data = value.load();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static void from_json(const json &data, std::atomic<std::uint64_t> &value) {
 | 
				
			||||||
 | 
					    value.store(data.get<std::uint64_t>());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename primitive_t>
 | 
					template <typename primitive_t>
 | 
				
			||||||
struct adl_serializer<std::atomic<primitive_t>> {
 | 
					struct adl_serializer<std::atomic<primitive_t>> {
 | 
				
			||||||
  static void to_json(json &data, const std::atomic<primitive_t> &value) {
 | 
					  static void to_json(json &data, const std::atomic<primitive_t> &value) {
 | 
				
			||||||
@@ -642,6 +646,18 @@ template <> struct adl_serializer<std::atomic<repertory::database_type>> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <> struct adl_serializer<std::atomic<repertory::event_level>> {
 | 
				
			||||||
 | 
					  static void to_json(json &data,
 | 
				
			||||||
 | 
					                      const std::atomic<repertory::event_level> &value) {
 | 
				
			||||||
 | 
					    data = repertory::event_level_to_string(value.load());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static void from_json(const json &data,
 | 
				
			||||||
 | 
					                        std::atomic<repertory::event_level> &value) {
 | 
				
			||||||
 | 
					    value.store(repertory::event_level_from_string(data.get<std::string>()));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <> struct adl_serializer<std::atomic<repertory::download_type>> {
 | 
					template <> struct adl_serializer<std::atomic<repertory::download_type>> {
 | 
				
			||||||
  static void to_json(json &data,
 | 
					  static void to_json(json &data,
 | 
				
			||||||
                      const std::atomic<repertory::download_type> &value) {
 | 
					                      const std::atomic<repertory::download_type> &value) {
 | 
				
			||||||
@@ -674,15 +690,13 @@ template <> struct adl_serializer<repertory::download_type> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <> struct adl_serializer<std::atomic<repertory::event_level>> {
 | 
					template <> struct adl_serializer<repertory::event_level> {
 | 
				
			||||||
  static void to_json(json &data,
 | 
					  static void to_json(json &data, const repertory::event_level &value) {
 | 
				
			||||||
                      const std::atomic<repertory::event_level> &value) {
 | 
					    data = repertory::event_level_to_string(value);
 | 
				
			||||||
    data = repertory::event_level_to_string(value.load());
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static void from_json(const json &data,
 | 
					  static void from_json(const json &data, repertory::event_level &value) {
 | 
				
			||||||
                        std::atomic<repertory::event_level> &value) {
 | 
					    value = repertory::event_level_from_string(data.get<std::string>());
 | 
				
			||||||
    value.store(repertory::event_level_from_string(data.get<std::string>()));
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
NLOHMANN_JSON_NAMESPACE_END
 | 
					NLOHMANN_JSON_NAMESPACE_END
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,7 +70,7 @@ app_config::app_config(const provider_type &prov,
 | 
				
			|||||||
      api_port_(default_rpc_port(prov)),
 | 
					      api_port_(default_rpc_port(prov)),
 | 
				
			||||||
      api_user_(std::string{REPERTORY}),
 | 
					      api_user_(std::string{REPERTORY}),
 | 
				
			||||||
      config_changed_(false),
 | 
					      config_changed_(false),
 | 
				
			||||||
      download_timeout_secs_(default_download_timeout_ces),
 | 
					      download_timeout_secs_(default_download_timeout_secs),
 | 
				
			||||||
      enable_download_timeout_(true),
 | 
					      enable_download_timeout_(true),
 | 
				
			||||||
      enable_drive_events_(false),
 | 
					      enable_drive_events_(false),
 | 
				
			||||||
#if defined(_WIN32)
 | 
					#if defined(_WIN32)
 | 
				
			||||||
@@ -85,7 +85,6 @@ app_config::app_config(const provider_type &prov,
 | 
				
			|||||||
      max_upload_count_(default_max_upload_count),
 | 
					      max_upload_count_(default_max_upload_count),
 | 
				
			||||||
      med_freq_interval_secs_(default_med_freq_interval_secs),
 | 
					      med_freq_interval_secs_(default_med_freq_interval_secs),
 | 
				
			||||||
      online_check_retry_secs_(default_online_check_retry_secs),
 | 
					      online_check_retry_secs_(default_online_check_retry_secs),
 | 
				
			||||||
      orphaned_file_retention_days_(default_orphaned_file_retention_days),
 | 
					 | 
				
			||||||
      preferred_download_type_(download_type::default_),
 | 
					      preferred_download_type_(download_type::default_),
 | 
				
			||||||
      retry_read_count_(default_retry_read_count),
 | 
					      retry_read_count_(default_retry_read_count),
 | 
				
			||||||
      ring_buffer_file_size_(default_ring_buffer_file_size),
 | 
					      ring_buffer_file_size_(default_ring_buffer_file_size),
 | 
				
			||||||
@@ -166,8 +165,14 @@ app_config::app_config(const provider_type &prov,
 | 
				
			|||||||
       [this]() { return get_host_config().api_password; }},
 | 
					       [this]() { return get_host_config().api_password; }},
 | 
				
			||||||
      {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PORT),
 | 
					      {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PORT),
 | 
				
			||||||
       [this]() { return std::to_string(get_host_config().api_port); }},
 | 
					       [this]() { return std::to_string(get_host_config().api_port); }},
 | 
				
			||||||
 | 
					      {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_USER),
 | 
				
			||||||
 | 
					       [this]() { return get_host_config().api_user; }},
 | 
				
			||||||
      {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP),
 | 
					      {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP),
 | 
				
			||||||
       [this]() { return get_host_config().host_name_or_ip; }},
 | 
					       [this]() { return get_host_config().host_name_or_ip; }},
 | 
				
			||||||
 | 
					      {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PATH),
 | 
				
			||||||
 | 
					       [this]() { return get_host_config().path; }},
 | 
				
			||||||
 | 
					      {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PROTOCOL),
 | 
				
			||||||
 | 
					       [this]() { return get_host_config().protocol; }},
 | 
				
			||||||
      {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS),
 | 
					      {fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS),
 | 
				
			||||||
       [this]() { return std::to_string(get_host_config().timeout_ms); }},
 | 
					       [this]() { return std::to_string(get_host_config().timeout_ms); }},
 | 
				
			||||||
      {JSON_LOW_FREQ_INTERVAL_SECS,
 | 
					      {JSON_LOW_FREQ_INTERVAL_SECS,
 | 
				
			||||||
@@ -180,8 +185,6 @@ app_config::app_config(const provider_type &prov,
 | 
				
			|||||||
       [this]() { return std::to_string(get_med_frequency_interval_secs()); }},
 | 
					       [this]() { return std::to_string(get_med_frequency_interval_secs()); }},
 | 
				
			||||||
      {JSON_ONLINE_CHECK_RETRY_SECS,
 | 
					      {JSON_ONLINE_CHECK_RETRY_SECS,
 | 
				
			||||||
       [this]() { return std::to_string(get_online_check_retry_secs()); }},
 | 
					       [this]() { return std::to_string(get_online_check_retry_secs()); }},
 | 
				
			||||||
      {JSON_ORPHANED_FILE_RETENTION_DAYS,
 | 
					 | 
				
			||||||
       [this]() { return std::to_string(get_orphaned_file_retention_days()); }},
 | 
					 | 
				
			||||||
      {JSON_PREFERRED_DOWNLOAD_TYPE,
 | 
					      {JSON_PREFERRED_DOWNLOAD_TYPE,
 | 
				
			||||||
       [this]() {
 | 
					       [this]() {
 | 
				
			||||||
         return download_type_to_string(get_preferred_download_type());
 | 
					         return download_type_to_string(get_preferred_download_type());
 | 
				
			||||||
@@ -250,7 +253,7 @@ app_config::app_config(const provider_type &prov,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  value_set_lookup_ = {
 | 
					  value_set_lookup_ = {
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
          JSON_API_PATH,
 | 
					          JSON_API_AUTH,
 | 
				
			||||||
          [this](const std::string &value) {
 | 
					          [this](const std::string &value) {
 | 
				
			||||||
            set_api_auth(value);
 | 
					            set_api_auth(value);
 | 
				
			||||||
            return get_api_auth();
 | 
					            return get_api_auth();
 | 
				
			||||||
@@ -349,7 +352,7 @@ app_config::app_config(const provider_type &prov,
 | 
				
			|||||||
      {
 | 
					      {
 | 
				
			||||||
          JSON_HIGH_FREQ_INTERVAL_SECS,
 | 
					          JSON_HIGH_FREQ_INTERVAL_SECS,
 | 
				
			||||||
          [this](const std::string &value) {
 | 
					          [this](const std::string &value) {
 | 
				
			||||||
            set_high_frequency_interval_secs(utils::string::to_uint8(value));
 | 
					            set_high_frequency_interval_secs(utils::string::to_uint16(value));
 | 
				
			||||||
            return std::to_string(get_high_frequency_interval_secs());
 | 
					            return std::to_string(get_high_frequency_interval_secs());
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@@ -380,6 +383,15 @@ app_config::app_config(const provider_type &prov,
 | 
				
			|||||||
            return std::to_string(get_host_config().api_port);
 | 
					            return std::to_string(get_host_config().api_port);
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					          fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_USER),
 | 
				
			||||||
 | 
					          [this](const std::string &value) {
 | 
				
			||||||
 | 
					            auto cfg = get_host_config();
 | 
				
			||||||
 | 
					            cfg.api_user = value;
 | 
				
			||||||
 | 
					            set_host_config(cfg);
 | 
				
			||||||
 | 
					            return get_host_config().api_user;
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
          fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP),
 | 
					          fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP),
 | 
				
			||||||
          [this](const std::string &value) {
 | 
					          [this](const std::string &value) {
 | 
				
			||||||
@@ -389,6 +401,24 @@ app_config::app_config(const provider_type &prov,
 | 
				
			|||||||
            return get_host_config().host_name_or_ip;
 | 
					            return get_host_config().host_name_or_ip;
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					          fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PATH),
 | 
				
			||||||
 | 
					          [this](const std::string &value) {
 | 
				
			||||||
 | 
					            auto cfg = get_host_config();
 | 
				
			||||||
 | 
					            cfg.path = value;
 | 
				
			||||||
 | 
					            set_host_config(cfg);
 | 
				
			||||||
 | 
					            return get_host_config().path;
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					          fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PROTOCOL),
 | 
				
			||||||
 | 
					          [this](const std::string &value) {
 | 
				
			||||||
 | 
					            auto cfg = get_host_config();
 | 
				
			||||||
 | 
					            cfg.protocol = value;
 | 
				
			||||||
 | 
					            set_host_config(cfg);
 | 
				
			||||||
 | 
					            return get_host_config().protocol;
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
          fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS),
 | 
					          fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS),
 | 
				
			||||||
          [this](const std::string &value) {
 | 
					          [this](const std::string &value) {
 | 
				
			||||||
@@ -401,14 +431,14 @@ app_config::app_config(const provider_type &prov,
 | 
				
			|||||||
      {
 | 
					      {
 | 
				
			||||||
          JSON_LOW_FREQ_INTERVAL_SECS,
 | 
					          JSON_LOW_FREQ_INTERVAL_SECS,
 | 
				
			||||||
          [this](const std::string &value) {
 | 
					          [this](const std::string &value) {
 | 
				
			||||||
            set_low_frequency_interval_secs(utils::string::to_uint8(value));
 | 
					            set_low_frequency_interval_secs(utils::string::to_uint16(value));
 | 
				
			||||||
            return std::to_string(get_low_frequency_interval_secs());
 | 
					            return std::to_string(get_low_frequency_interval_secs());
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
          JSON_MED_FREQ_INTERVAL_SECS,
 | 
					          JSON_MED_FREQ_INTERVAL_SECS,
 | 
				
			||||||
          [this](const std::string &value) {
 | 
					          [this](const std::string &value) {
 | 
				
			||||||
            set_med_frequency_interval_secs(utils::string::to_uint8(value));
 | 
					            set_med_frequency_interval_secs(utils::string::to_uint16(value));
 | 
				
			||||||
            return std::to_string(get_med_frequency_interval_secs());
 | 
					            return std::to_string(get_med_frequency_interval_secs());
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@@ -433,13 +463,6 @@ app_config::app_config(const provider_type &prov,
 | 
				
			|||||||
            return std::to_string(get_online_check_retry_secs());
 | 
					            return std::to_string(get_online_check_retry_secs());
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
          JSON_ORPHANED_FILE_RETENTION_DAYS,
 | 
					 | 
				
			||||||
          [this](const std::string &value) {
 | 
					 | 
				
			||||||
            set_orphaned_file_retention_days(utils::string::to_uint16(value));
 | 
					 | 
				
			||||||
            return std::to_string(get_orphaned_file_retention_days());
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
          JSON_PREFERRED_DOWNLOAD_TYPE,
 | 
					          JSON_PREFERRED_DOWNLOAD_TYPE,
 | 
				
			||||||
          [this](const std::string &value) {
 | 
					          [this](const std::string &value) {
 | 
				
			||||||
@@ -812,7 +835,6 @@ auto app_config::get_json() const -> json {
 | 
				
			|||||||
      {JSON_MAX_UPLOAD_COUNT, max_upload_count_},
 | 
					      {JSON_MAX_UPLOAD_COUNT, max_upload_count_},
 | 
				
			||||||
      {JSON_MED_FREQ_INTERVAL_SECS, med_freq_interval_secs_},
 | 
					      {JSON_MED_FREQ_INTERVAL_SECS, med_freq_interval_secs_},
 | 
				
			||||||
      {JSON_ONLINE_CHECK_RETRY_SECS, online_check_retry_secs_},
 | 
					      {JSON_ONLINE_CHECK_RETRY_SECS, online_check_retry_secs_},
 | 
				
			||||||
      {JSON_ORPHANED_FILE_RETENTION_DAYS, orphaned_file_retention_days_},
 | 
					 | 
				
			||||||
      {JSON_PREFERRED_DOWNLOAD_TYPE, preferred_download_type_},
 | 
					      {JSON_PREFERRED_DOWNLOAD_TYPE, preferred_download_type_},
 | 
				
			||||||
      {JSON_REMOTE_CONFIG, remote_config_},
 | 
					      {JSON_REMOTE_CONFIG, remote_config_},
 | 
				
			||||||
      {JSON_REMOTE_MOUNT, remote_mount_},
 | 
					      {JSON_REMOTE_MOUNT, remote_mount_},
 | 
				
			||||||
@@ -834,7 +856,6 @@ auto app_config::get_json() const -> json {
 | 
				
			|||||||
    ret.erase(JSON_MAX_CACHE_SIZE_BYTES);
 | 
					    ret.erase(JSON_MAX_CACHE_SIZE_BYTES);
 | 
				
			||||||
    ret.erase(JSON_MAX_UPLOAD_COUNT);
 | 
					    ret.erase(JSON_MAX_UPLOAD_COUNT);
 | 
				
			||||||
    ret.erase(JSON_ONLINE_CHECK_RETRY_SECS);
 | 
					    ret.erase(JSON_ONLINE_CHECK_RETRY_SECS);
 | 
				
			||||||
    ret.erase(JSON_ORPHANED_FILE_RETENTION_DAYS);
 | 
					 | 
				
			||||||
    ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
 | 
					    ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
 | 
				
			||||||
    ret.erase(JSON_REMOTE_CONFIG);
 | 
					    ret.erase(JSON_REMOTE_CONFIG);
 | 
				
			||||||
    ret.erase(JSON_RETRY_READ_COUNT);
 | 
					    ret.erase(JSON_RETRY_READ_COUNT);
 | 
				
			||||||
@@ -856,7 +877,6 @@ auto app_config::get_json() const -> json {
 | 
				
			|||||||
    ret.erase(JSON_MAX_UPLOAD_COUNT);
 | 
					    ret.erase(JSON_MAX_UPLOAD_COUNT);
 | 
				
			||||||
    ret.erase(JSON_MED_FREQ_INTERVAL_SECS);
 | 
					    ret.erase(JSON_MED_FREQ_INTERVAL_SECS);
 | 
				
			||||||
    ret.erase(JSON_ONLINE_CHECK_RETRY_SECS);
 | 
					    ret.erase(JSON_ONLINE_CHECK_RETRY_SECS);
 | 
				
			||||||
    ret.erase(JSON_ORPHANED_FILE_RETENTION_DAYS);
 | 
					 | 
				
			||||||
    ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
 | 
					    ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
 | 
				
			||||||
    ret.erase(JSON_REMOTE_MOUNT);
 | 
					    ret.erase(JSON_REMOTE_MOUNT);
 | 
				
			||||||
    ret.erase(JSON_RETRY_READ_COUNT);
 | 
					    ret.erase(JSON_RETRY_READ_COUNT);
 | 
				
			||||||
@@ -912,12 +932,6 @@ auto app_config::get_online_check_retry_secs() const -> std::uint16_t {
 | 
				
			|||||||
  return std::max(min_online_check_retry_secs, online_check_retry_secs_.load());
 | 
					  return std::max(min_online_check_retry_secs, online_check_retry_secs_.load());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto app_config::get_orphaned_file_retention_days() const -> std::uint16_t {
 | 
					 | 
				
			||||||
  return std::min(max_orphaned_file_retention_days,
 | 
					 | 
				
			||||||
                  std::max(min_orphaned_file_retention_days,
 | 
					 | 
				
			||||||
                           orphaned_file_retention_days_.load()));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto app_config::get_preferred_download_type() const -> download_type {
 | 
					auto app_config::get_preferred_download_type() const -> download_type {
 | 
				
			||||||
  return preferred_download_type_;
 | 
					  return preferred_download_type_;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1053,8 +1067,6 @@ auto app_config::load() -> bool {
 | 
				
			|||||||
              med_freq_interval_secs_, found);
 | 
					              med_freq_interval_secs_, found);
 | 
				
			||||||
    get_value(json_document, JSON_ONLINE_CHECK_RETRY_SECS,
 | 
					    get_value(json_document, JSON_ONLINE_CHECK_RETRY_SECS,
 | 
				
			||||||
              online_check_retry_secs_, found);
 | 
					              online_check_retry_secs_, found);
 | 
				
			||||||
    get_value(json_document, JSON_ORPHANED_FILE_RETENTION_DAYS,
 | 
					 | 
				
			||||||
              orphaned_file_retention_days_, found);
 | 
					 | 
				
			||||||
    get_value(json_document, JSON_PREFERRED_DOWNLOAD_TYPE,
 | 
					    get_value(json_document, JSON_PREFERRED_DOWNLOAD_TYPE,
 | 
				
			||||||
              preferred_download_type_, found);
 | 
					              preferred_download_type_, found);
 | 
				
			||||||
    get_value(json_document, JSON_REMOTE_CONFIG, remote_config_, found);
 | 
					    get_value(json_document, JSON_REMOTE_CONFIG, remote_config_, found);
 | 
				
			||||||
@@ -1069,10 +1081,17 @@ auto app_config::load() -> bool {
 | 
				
			|||||||
    std::uint64_t version{};
 | 
					    std::uint64_t version{};
 | 
				
			||||||
    get_value(json_document, JSON_VERSION, version, found);
 | 
					    get_value(json_document, JSON_VERSION, version, found);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Handle configuration defaults for new config versions
 | 
					 | 
				
			||||||
    if (version != REPERTORY_CONFIG_VERSION) {
 | 
					    if (version != REPERTORY_CONFIG_VERSION) {
 | 
				
			||||||
      version_ = REPERTORY_CONFIG_VERSION;
 | 
					      version_ = REPERTORY_CONFIG_VERSION;
 | 
				
			||||||
      // TODO upgrade future version
 | 
					      if (version_ == 1U) {
 | 
				
			||||||
 | 
					        if (low_freq_interval_secs_ == 0UL) {
 | 
				
			||||||
 | 
					          set_value(low_freq_interval_secs_, default_low_freq_interval_secs);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (max_cache_size_bytes_ == 0UL) {
 | 
				
			||||||
 | 
					          set_value(max_cache_size_bytes_, default_max_cache_size_bytes);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      found = false;
 | 
					      found = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1199,10 +1218,6 @@ void app_config::set_online_check_retry_secs(std::uint16_t value) {
 | 
				
			|||||||
  set_value(online_check_retry_secs_, value);
 | 
					  set_value(online_check_retry_secs_, value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void app_config::set_orphaned_file_retention_days(std::uint16_t value) {
 | 
					 | 
				
			||||||
  set_value(orphaned_file_retention_days_, value);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void app_config::set_preferred_download_type(const download_type &value) {
 | 
					void app_config::set_preferred_download_type(const download_type &value) {
 | 
				
			||||||
  set_value(preferred_download_type_, value);
 | 
					  set_value(preferred_download_type_, value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,8 +43,8 @@
 | 
				
			|||||||
#include "utils/utils.hpp"
 | 
					#include "utils/utils.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory::remote_fuse {
 | 
					namespace repertory::remote_fuse {
 | 
				
			||||||
auto remote_fuse_drive::access_impl(std::string api_path,
 | 
					auto remote_fuse_drive::access_impl(std::string api_path, int mask)
 | 
				
			||||||
                                    int mask) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  return utils::to_api_error(
 | 
					  return utils::to_api_error(
 | 
				
			||||||
      remote_instance_->fuse_access(api_path.c_str(), mask));
 | 
					      remote_instance_->fuse_access(api_path.c_str(), mask));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -62,8 +62,8 @@ auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode,
 | 
				
			|||||||
                                   struct fuse_file_info * /*f_info*/)
 | 
					                                   struct fuse_file_info * /*f_info*/)
 | 
				
			||||||
    -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
auto remote_fuse_drive::chmod_impl(std::string api_path,
 | 
					auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode)
 | 
				
			||||||
                                   mode_t mode) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  return utils::to_api_error(remote_instance_->fuse_chmod(
 | 
					  return utils::to_api_error(remote_instance_->fuse_chmod(
 | 
				
			||||||
      api_path.c_str(), static_cast<remote::file_mode>(mode)));
 | 
					      api_path.c_str(), static_cast<remote::file_mode>(mode)));
 | 
				
			||||||
@@ -74,8 +74,8 @@ auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid,
 | 
				
			|||||||
                                   struct fuse_file_info * /*f_info*/)
 | 
					                                   struct fuse_file_info * /*f_info*/)
 | 
				
			||||||
    -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid,
 | 
					auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
 | 
				
			||||||
                                   gid_t gid) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  return utils::to_api_error(
 | 
					  return utils::to_api_error(
 | 
				
			||||||
      remote_instance_->fuse_chown(api_path.c_str(), uid, gid));
 | 
					      remote_instance_->fuse_chown(api_path.c_str(), uid, gid));
 | 
				
			||||||
@@ -94,7 +94,7 @@ void remote_fuse_drive::destroy_impl(void *ptr) {
 | 
				
			|||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  event_system::instance().raise<drive_unmount_pending>(function_name,
 | 
					  event_system::instance().raise<drive_unmount_pending>(function_name,
 | 
				
			||||||
                                                         get_mount_location());
 | 
					                                                        get_mount_location());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (server_) {
 | 
					  if (server_) {
 | 
				
			||||||
    server_->stop();
 | 
					    server_->stop();
 | 
				
			||||||
@@ -116,14 +116,15 @@ void remote_fuse_drive::destroy_impl(void *ptr) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  event_system::instance().raise<drive_unmounted>(function_name,
 | 
					  event_system::instance().raise<drive_unmounted>(function_name,
 | 
				
			||||||
                                                   get_mount_location());
 | 
					                                                  get_mount_location());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fuse_base::destroy_impl(ptr);
 | 
					  fuse_base::destroy_impl(ptr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto remote_fuse_drive::fgetattr_impl(
 | 
					auto remote_fuse_drive::fgetattr_impl(std::string api_path,
 | 
				
			||||||
    std::string api_path, struct stat *unix_st,
 | 
					                                      struct stat *unix_st,
 | 
				
			||||||
    struct fuse_file_info *f_info) -> api_error {
 | 
					                                      struct fuse_file_info *f_info)
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  remote::stat r_stat{};
 | 
					  remote::stat r_stat{};
 | 
				
			||||||
  auto directory = false;
 | 
					  auto directory = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -184,8 +185,8 @@ auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st,
 | 
				
			|||||||
                                     struct fuse_file_info * /*f_info*/)
 | 
					                                     struct fuse_file_info * /*f_info*/)
 | 
				
			||||||
    -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
auto remote_fuse_drive::getattr_impl(std::string api_path,
 | 
					auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st)
 | 
				
			||||||
                                     struct stat *unix_st) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  bool directory = false;
 | 
					  bool directory = false;
 | 
				
			||||||
  remote::stat r_stat{};
 | 
					  remote::stat r_stat{};
 | 
				
			||||||
@@ -263,14 +264,14 @@ auto remote_fuse_drive::init_impl(struct fuse_conn_info *conn) -> void * {
 | 
				
			|||||||
    server_ = std::make_shared<server>(config_);
 | 
					    server_ = std::make_shared<server>(config_);
 | 
				
			||||||
    server_->start();
 | 
					    server_->start();
 | 
				
			||||||
    event_system::instance().raise<drive_mounted>(function_name,
 | 
					    event_system::instance().raise<drive_mounted>(function_name,
 | 
				
			||||||
                                                   get_mount_location());
 | 
					                                                  get_mount_location());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return ret;
 | 
					  return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto remote_fuse_drive::mkdir_impl(std::string api_path,
 | 
					auto remote_fuse_drive::mkdir_impl(std::string api_path, mode_t mode)
 | 
				
			||||||
                                   mode_t mode) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  return utils::to_api_error(remote_instance_->fuse_mkdir(
 | 
					  return utils::to_api_error(remote_instance_->fuse_mkdir(
 | 
				
			||||||
      api_path.c_str(), static_cast<remote::file_mode>(mode)));
 | 
					      api_path.c_str(), static_cast<remote::file_mode>(mode)));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -295,8 +296,9 @@ auto remote_fuse_drive::open_impl(std::string api_path,
 | 
				
			|||||||
      f_info->fh));
 | 
					      f_info->fh));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto remote_fuse_drive::opendir_impl(
 | 
					auto remote_fuse_drive::opendir_impl(std::string api_path,
 | 
				
			||||||
    std::string api_path, struct fuse_file_info *f_info) -> api_error {
 | 
					                                     struct fuse_file_info *f_info)
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  if ((f_info->flags & O_APPEND) == O_APPEND ||
 | 
					  if ((f_info->flags & O_APPEND) == O_APPEND ||
 | 
				
			||||||
      (f_info->flags & O_EXCL) == O_EXCL) {
 | 
					      (f_info->flags & O_EXCL) == O_EXCL) {
 | 
				
			||||||
    return api_error::directory_exists;
 | 
					    return api_error::directory_exists;
 | 
				
			||||||
@@ -309,12 +311,14 @@ auto remote_fuse_drive::opendir_impl(
 | 
				
			|||||||
void remote_fuse_drive::populate_stat(const remote::stat &r_stat,
 | 
					void remote_fuse_drive::populate_stat(const remote::stat &r_stat,
 | 
				
			||||||
                                      bool directory, struct stat &unix_st) {
 | 
					                                      bool directory, struct stat &unix_st) {
 | 
				
			||||||
  std::memset(&unix_st, 0, sizeof(struct stat));
 | 
					  std::memset(&unix_st, 0, sizeof(struct stat));
 | 
				
			||||||
  unix_st.st_blksize = r_stat.st_blksize;
 | 
					  unix_st.st_blksize =
 | 
				
			||||||
  unix_st.st_blocks = static_cast<blkcnt_t>(r_stat.st_blocks);
 | 
					      static_cast<decltype(unix_st.st_blksize)>(r_stat.st_blksize);
 | 
				
			||||||
 | 
					  unix_st.st_blocks =
 | 
				
			||||||
 | 
					      static_cast<decltype(unix_st.st_blocks)>(r_stat.st_blocks);
 | 
				
			||||||
  unix_st.st_gid = r_stat.st_gid;
 | 
					  unix_st.st_gid = r_stat.st_gid;
 | 
				
			||||||
  unix_st.st_mode = (directory ? S_IFDIR : S_IFREG) | r_stat.st_mode;
 | 
					  unix_st.st_mode = (directory ? S_IFDIR : S_IFREG) | r_stat.st_mode;
 | 
				
			||||||
  unix_st.st_nlink = r_stat.st_nlink;
 | 
					  unix_st.st_nlink = r_stat.st_nlink;
 | 
				
			||||||
  unix_st.st_size = static_cast<off_t>(r_stat.st_size);
 | 
					  unix_st.st_size = static_cast<decltype(unix_st.st_size)>(r_stat.st_size);
 | 
				
			||||||
  unix_st.st_uid = r_stat.st_uid;
 | 
					  unix_st.st_uid = r_stat.st_uid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__APPLE__)
 | 
					#if defined(__APPLE__)
 | 
				
			||||||
@@ -373,14 +377,18 @@ auto remote_fuse_drive::read_impl(std::string api_path, char *buffer,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if FUSE_USE_VERSION >= 30
 | 
					#if FUSE_USE_VERSION >= 30
 | 
				
			||||||
auto remote_fuse_drive::readdir_impl(
 | 
					auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
 | 
				
			||||||
    std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir,
 | 
					                                     fuse_fill_dir_t fuse_fill_dir,
 | 
				
			||||||
    off_t offset, struct fuse_file_info *f_info,
 | 
					                                     off_t offset,
 | 
				
			||||||
    fuse_readdir_flags /*flags*/) -> api_error {
 | 
					                                     struct fuse_file_info *f_info,
 | 
				
			||||||
 | 
					                                     fuse_readdir_flags /*flags*/)
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
auto remote_fuse_drive::readdir_impl(
 | 
					auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
 | 
				
			||||||
    std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir,
 | 
					                                     fuse_fill_dir_t fuse_fill_dir,
 | 
				
			||||||
    off_t offset, struct fuse_file_info *f_info) -> api_error {
 | 
					                                     off_t offset,
 | 
				
			||||||
 | 
					                                     struct fuse_file_info *f_info)
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  std::string item_path;
 | 
					  std::string item_path;
 | 
				
			||||||
  int res = 0;
 | 
					  int res = 0;
 | 
				
			||||||
@@ -408,14 +416,16 @@ auto remote_fuse_drive::readdir_impl(
 | 
				
			|||||||
  return utils::to_api_error(res);
 | 
					  return utils::to_api_error(res);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto remote_fuse_drive::release_impl(
 | 
					auto remote_fuse_drive::release_impl(std::string api_path,
 | 
				
			||||||
    std::string api_path, struct fuse_file_info *f_info) -> api_error {
 | 
					                                     struct fuse_file_info *f_info)
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  return utils::to_api_error(
 | 
					  return utils::to_api_error(
 | 
				
			||||||
      remote_instance_->fuse_release(api_path.c_str(), f_info->fh));
 | 
					      remote_instance_->fuse_release(api_path.c_str(), f_info->fh));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto remote_fuse_drive::releasedir_impl(
 | 
					auto remote_fuse_drive::releasedir_impl(std::string api_path,
 | 
				
			||||||
    std::string api_path, struct fuse_file_info *f_info) -> api_error {
 | 
					                                        struct fuse_file_info *f_info)
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  return utils::to_api_error(
 | 
					  return utils::to_api_error(
 | 
				
			||||||
      remote_instance_->fuse_releasedir(api_path.c_str(), f_info->fh));
 | 
					      remote_instance_->fuse_releasedir(api_path.c_str(), f_info->fh));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -512,8 +522,8 @@ api_error remote_fuse_drive::statfs_x_impl(std::string api_path,
 | 
				
			|||||||
  return utils::to_api_error(res);
 | 
					  return utils::to_api_error(res);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else  // __APPLE__
 | 
					#else  // __APPLE__
 | 
				
			||||||
auto remote_fuse_drive::statfs_impl(std::string api_path,
 | 
					auto remote_fuse_drive::statfs_impl(std::string api_path, struct statvfs *stbuf)
 | 
				
			||||||
                                    struct statvfs *stbuf) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  auto res = statvfs(config_.get_data_directory().c_str(), stbuf);
 | 
					  auto res = statvfs(config_.get_data_directory().c_str(), stbuf);
 | 
				
			||||||
  if (res == 0) {
 | 
					  if (res == 0) {
 | 
				
			||||||
    remote::statfs r_stat{};
 | 
					    remote::statfs r_stat{};
 | 
				
			||||||
@@ -540,8 +550,8 @@ auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size,
 | 
				
			|||||||
                                      struct fuse_file_info * /*f_info*/)
 | 
					                                      struct fuse_file_info * /*f_info*/)
 | 
				
			||||||
    -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
auto remote_fuse_drive::truncate_impl(std::string api_path,
 | 
					auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size)
 | 
				
			||||||
                                      off_t size) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  return utils::to_api_error(remote_instance_->fuse_truncate(
 | 
					  return utils::to_api_error(remote_instance_->fuse_truncate(
 | 
				
			||||||
      api_path.c_str(), static_cast<remote::file_offset>(size)));
 | 
					      api_path.c_str(), static_cast<remote::file_offset>(size)));
 | 
				
			||||||
@@ -552,9 +562,10 @@ auto remote_fuse_drive::unlink_impl(std::string api_path) -> api_error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if FUSE_USE_VERSION >= 30
 | 
					#if FUSE_USE_VERSION >= 30
 | 
				
			||||||
auto remote_fuse_drive::utimens_impl(
 | 
					auto remote_fuse_drive::utimens_impl(std::string api_path,
 | 
				
			||||||
    std::string api_path, const struct timespec tv[2],
 | 
					                                     const struct timespec tv[2],
 | 
				
			||||||
    struct fuse_file_info * /*f_info*/) -> api_error {
 | 
					                                     struct fuse_file_info * /*f_info*/)
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
auto remote_fuse_drive::utimens_impl(std::string api_path,
 | 
					auto remote_fuse_drive::utimens_impl(std::string api_path,
 | 
				
			||||||
                                     const struct timespec tv[2]) -> api_error {
 | 
					                                     const struct timespec tv[2]) -> api_error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,13 +22,11 @@
 | 
				
			|||||||
#include "drives/winfsp/remotewinfsp/remote_client.hpp"
 | 
					#include "drives/winfsp/remotewinfsp/remote_client.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "app_config.hpp"
 | 
					#include "app_config.hpp"
 | 
				
			||||||
#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
 | 
					 | 
				
			||||||
#include "events/event_system.hpp"
 | 
					#include "events/event_system.hpp"
 | 
				
			||||||
#include "events/types/drive_mounted.hpp"
 | 
					#include "events/types/drive_mounted.hpp"
 | 
				
			||||||
#include "events/types/drive_unmount_pending.hpp"
 | 
					#include "events/types/drive_unmount_pending.hpp"
 | 
				
			||||||
#include "events/types/drive_unmounted.hpp"
 | 
					#include "events/types/drive_unmounted.hpp"
 | 
				
			||||||
#include "types/repertory.hpp"
 | 
					#include "utils/string.hpp"
 | 
				
			||||||
#include "utils/path.hpp"
 | 
					 | 
				
			||||||
#include "version.hpp"
 | 
					#include "version.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory::remote_winfsp {
 | 
					namespace repertory::remote_winfsp {
 | 
				
			||||||
@@ -44,11 +42,7 @@ auto remote_client::winfsp_can_delete(PVOID file_desc, PWSTR file_name)
 | 
				
			|||||||
  request.encode(file_name);
 | 
					  request.encode(file_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::uint32_t service_flags{};
 | 
					  std::uint32_t service_flags{};
 | 
				
			||||||
  auto ret{
 | 
					  return packet_client_.send(function_name, request, service_flags);
 | 
				
			||||||
      packet_client_.send(function_name, request, service_flags),
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto remote_client::json_create_directory_snapshot(const std::string &path,
 | 
					auto remote_client::json_create_directory_snapshot(const std::string &path,
 | 
				
			||||||
@@ -103,11 +97,7 @@ auto remote_client::json_release_directory_snapshot(
 | 
				
			|||||||
  request.encode(handle);
 | 
					  request.encode(handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::uint32_t service_flags{};
 | 
					  std::uint32_t service_flags{};
 | 
				
			||||||
  auto ret{
 | 
					  return packet_client_.send(function_name, request, service_flags);
 | 
				
			||||||
      packet_client_.send(function_name, request, service_flags),
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto remote_client::winfsp_cleanup(PVOID file_desc, PWSTR file_name,
 | 
					auto remote_client::winfsp_cleanup(PVOID file_desc, PWSTR file_name,
 | 
				
			||||||
@@ -273,8 +263,8 @@ auto remote_client::winfsp_get_security_by_name(PWSTR file_name,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  packet request;
 | 
					  packet request;
 | 
				
			||||||
  request.encode(file_name);
 | 
					  request.encode(file_name);
 | 
				
			||||||
  request.encode(static_cast<std::uint64_t>(
 | 
					  request.encode(descriptor_size == nullptr ? std::uint64_t(0U)
 | 
				
			||||||
      descriptor_size == nullptr ? 0 : *descriptor_size));
 | 
					                                            : *descriptor_size);
 | 
				
			||||||
  request.encode(static_cast<std::uint8_t>(attributes != nullptr));
 | 
					  request.encode(static_cast<std::uint8_t>(attributes != nullptr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  packet response;
 | 
					  packet response;
 | 
				
			||||||
@@ -417,7 +407,7 @@ auto remote_client::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
 | 
				
			|||||||
    ret = response.decode(buffer, *bytes_transferred);
 | 
					    ret = response.decode(buffer, *bytes_transferred);
 | 
				
			||||||
#if defined(_WIN32)
 | 
					#if defined(_WIN32)
 | 
				
			||||||
    if ((ret == STATUS_SUCCESS) &&
 | 
					    if ((ret == STATUS_SUCCESS) &&
 | 
				
			||||||
        (not*bytes_transferred || (*bytes_transferred != length))) {
 | 
					        ((*bytes_transferred == 0U) || (*bytes_transferred != length))) {
 | 
				
			||||||
      ::SetLastError(ERROR_HANDLE_EOF);
 | 
					      ::SetLastError(ERROR_HANDLE_EOF);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -461,11 +451,7 @@ auto remote_client::winfsp_rename(PVOID file_desc, PWSTR file_name,
 | 
				
			|||||||
  request.encode(replace_if_exists);
 | 
					  request.encode(replace_if_exists);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::uint32_t service_flags{};
 | 
					  std::uint32_t service_flags{};
 | 
				
			||||||
  auto ret{
 | 
					  return packet_client_.send(function_name, request, service_flags);
 | 
				
			||||||
      packet_client_.send(function_name, request, service_flags),
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return ret;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto remote_client::winfsp_set_basic_info(
 | 
					auto remote_client::winfsp_set_basic_info(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -466,6 +466,13 @@ auto file_manager::open(const std::string &api_path, bool directory,
 | 
				
			|||||||
        return download_type::default_;
 | 
					        return download_type::default_;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (utils::file::file{fsi.source_path}.exists()) {
 | 
				
			||||||
 | 
					        auto size = utils::file::file{fsi.source_path}.size();
 | 
				
			||||||
 | 
					        if (size.has_value() && *size == fsi.size) {
 | 
				
			||||||
 | 
					          return download_type::default_;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (type == download_type::direct) {
 | 
					      if (type == download_type::direct) {
 | 
				
			||||||
        return type;
 | 
					        return type;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,19 +98,23 @@ auto ring_buffer_base::close() -> bool {
 | 
				
			|||||||
  return res;
 | 
					  return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto ring_buffer_base::download_chunk(std::size_t chunk,
 | 
					auto ring_buffer_base::download_chunk(std::size_t chunk, bool skip_active)
 | 
				
			||||||
                                      bool skip_active) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  unique_mutex_lock chunk_lock(chunk_mtx_);
 | 
					  unique_mutex_lock chunk_lock(chunk_mtx_);
 | 
				
			||||||
  const auto unlock_and_notify = [this, &chunk_lock]() {
 | 
					  if (not skip_active) {
 | 
				
			||||||
 | 
					    ring_pos_ = chunk;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const auto notify_and_unlock = [this, &chunk_lock]() {
 | 
				
			||||||
    chunk_notify_.notify_all();
 | 
					    chunk_notify_.notify_all();
 | 
				
			||||||
    chunk_lock.unlock();
 | 
					    chunk_lock.unlock();
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const auto unlock_and_return =
 | 
					  const auto unlock_and_return =
 | 
				
			||||||
      [&unlock_and_notify](api_error res) -> api_error {
 | 
					      [¬ify_and_unlock](api_error res) -> api_error {
 | 
				
			||||||
    unlock_and_notify();
 | 
					    notify_and_unlock();
 | 
				
			||||||
    return res;
 | 
					    return res;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -124,7 +128,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto active_download = get_active_downloads().at(chunk);
 | 
					    auto active_download = get_active_downloads().at(chunk);
 | 
				
			||||||
    unlock_and_notify();
 | 
					    notify_and_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return active_download->wait();
 | 
					    return active_download->wait();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -142,7 +146,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk,
 | 
				
			|||||||
        chunk == (total_chunks_ - 1U) ? get_last_chunk_size()
 | 
					        chunk == (total_chunks_ - 1U) ? get_last_chunk_size()
 | 
				
			||||||
                                      : get_chunk_size(),
 | 
					                                      : get_chunk_size(),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    unlock_and_notify();
 | 
					    notify_and_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto result{
 | 
					    auto result{
 | 
				
			||||||
        get_provider().read_file_bytes(get_api_path(), data_size, data_offset,
 | 
					        get_provider().read_file_bytes(get_api_path(), data_size, data_offset,
 | 
				
			||||||
@@ -167,7 +171,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    get_active_downloads().erase(chunk);
 | 
					    get_active_downloads().erase(chunk);
 | 
				
			||||||
    unlock_and_notify();
 | 
					    notify_and_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    active_download->notify(result);
 | 
					    active_download->notify(result);
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
@@ -226,7 +230,6 @@ auto ring_buffer_base::read(std::size_t read_size, std::uint64_t read_offset,
 | 
				
			|||||||
    } else if (chunk < ring_pos_) {
 | 
					    } else if (chunk < ring_pos_) {
 | 
				
			||||||
      reverse(ring_pos_ - chunk);
 | 
					      reverse(ring_pos_ - chunk);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    res = download_chunk(chunk, false);
 | 
					    res = download_chunk(chunk, false);
 | 
				
			||||||
    if (res != api_error::success) {
 | 
					    if (res != api_error::success) {
 | 
				
			||||||
      if (res == api_error::invalid_ring_buffer_position) {
 | 
					      if (res == api_error::invalid_ring_buffer_position) {
 | 
				
			||||||
@@ -264,38 +267,46 @@ void ring_buffer_base::reader_thread() {
 | 
				
			|||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  unique_mutex_lock chunk_lock(chunk_mtx_);
 | 
					  unique_mutex_lock chunk_lock(chunk_mtx_);
 | 
				
			||||||
  auto next_chunk{ring_pos_};
 | 
					  const auto notify_and_unlock = [this, &chunk_lock]() {
 | 
				
			||||||
  chunk_notify_.notify_all();
 | 
					    chunk_notify_.notify_all();
 | 
				
			||||||
  chunk_lock.unlock();
 | 
					    chunk_lock.unlock();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto last_pos = ring_pos_;
 | 
				
			||||||
 | 
					  auto next_chunk = ring_pos_;
 | 
				
			||||||
 | 
					  notify_and_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while (not get_stop_requested()) {
 | 
					  while (not get_stop_requested()) {
 | 
				
			||||||
    chunk_lock.lock();
 | 
					    chunk_lock.lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    next_chunk = next_chunk + 1U > ring_end_ ? ring_begin_ : next_chunk + 1U;
 | 
					    if (last_pos == ring_pos_) {
 | 
				
			||||||
    const auto check_and_wait = [this, &chunk_lock, &next_chunk]() {
 | 
					      ++next_chunk;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      next_chunk = ring_pos_ + 1U;
 | 
				
			||||||
 | 
					      last_pos = ring_pos_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (next_chunk > ring_end_) {
 | 
				
			||||||
 | 
					      next_chunk = ring_begin_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (read_state_[next_chunk % read_state_.size()]) {
 | 
				
			||||||
      if (get_stop_requested()) {
 | 
					      if (get_stop_requested()) {
 | 
				
			||||||
        chunk_notify_.notify_all();
 | 
					        notify_and_unlock();
 | 
				
			||||||
        chunk_lock.unlock();
 | 
					 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (get_read_state().all()) {
 | 
					      if (get_read_state().all()) {
 | 
				
			||||||
        chunk_notify_.wait(chunk_lock);
 | 
					        chunk_notify_.wait(chunk_lock);
 | 
				
			||||||
 | 
					        last_pos = ring_pos_;
 | 
				
			||||||
        next_chunk = ring_pos_;
 | 
					        next_chunk = ring_pos_;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      chunk_notify_.notify_all();
 | 
					      notify_and_unlock();
 | 
				
			||||||
      chunk_lock.unlock();
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (read_state_[next_chunk % read_state_.size()]) {
 | 
					 | 
				
			||||||
      check_and_wait();
 | 
					 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    chunk_notify_.notify_all();
 | 
					    notify_and_unlock();
 | 
				
			||||||
    chunk_lock.unlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    download_chunk(next_chunk, true);
 | 
					    download_chunk(next_chunk, true);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -351,30 +362,31 @@ void ring_buffer_base::update_position(std::size_t count, bool is_forward) {
 | 
				
			|||||||
  if (is_forward ? (ring_pos_ + count) <= ring_end_
 | 
					  if (is_forward ? (ring_pos_ + count) <= ring_end_
 | 
				
			||||||
                 : (ring_pos_ - count) >= ring_begin_) {
 | 
					                 : (ring_pos_ - count) >= ring_begin_) {
 | 
				
			||||||
    ring_pos_ += is_forward ? count : -count;
 | 
					    ring_pos_ += is_forward ? count : -count;
 | 
				
			||||||
  } else {
 | 
					    chunk_notify_.notify_all();
 | 
				
			||||||
    auto delta = is_forward ? count - (ring_end_ - ring_pos_)
 | 
					    return;
 | 
				
			||||||
                            : count - (ring_pos_ - ring_begin_);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (delta >= read_state_.size()) {
 | 
					 | 
				
			||||||
      read_state_.set(0U, read_state_.size(), false);
 | 
					 | 
				
			||||||
      ring_pos_ += is_forward ? count : -count;
 | 
					 | 
				
			||||||
      ring_begin_ += is_forward ? delta : -delta;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      for (std::size_t idx = 0U; idx < delta; ++idx) {
 | 
					 | 
				
			||||||
        if (is_forward) {
 | 
					 | 
				
			||||||
          read_state_[(ring_begin_ + idx) % read_state_.size()] = false;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          read_state_[(ring_end_ - idx) % read_state_.size()] = false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      ring_begin_ += is_forward ? delta : -delta;
 | 
					 | 
				
			||||||
      ring_pos_ += is_forward ? count : -count;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ring_end_ =
 | 
					 | 
				
			||||||
        std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto delta = is_forward ? count - (ring_end_ - ring_pos_)
 | 
				
			||||||
 | 
					                          : count - (ring_pos_ - ring_begin_);
 | 
				
			||||||
 | 
					  if (delta >= read_state_.size()) {
 | 
				
			||||||
 | 
					    read_state_.set(0U, read_state_.size(), false);
 | 
				
			||||||
 | 
					    ring_pos_ += is_forward ? count : -count;
 | 
				
			||||||
 | 
					    ring_begin_ += is_forward ? delta : -delta;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    for (std::size_t idx = 0U; idx < delta; ++idx) {
 | 
				
			||||||
 | 
					      if (is_forward) {
 | 
				
			||||||
 | 
					        read_state_[(ring_begin_ + idx) % read_state_.size()] = false;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        read_state_[(ring_end_ - idx) % read_state_.size()] = false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ring_begin_ += is_forward ? delta : -delta;
 | 
				
			||||||
 | 
					    ring_pos_ += is_forward ? count : -count;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ring_end_ =
 | 
				
			||||||
 | 
					      std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  chunk_notify_.notify_all();
 | 
					  chunk_notify_.notify_all();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
} // namespace repertory
 | 
					} // namespace repertory
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,10 +50,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
auto project_initialize() -> bool {
 | 
					auto project_initialize() -> bool {
 | 
				
			||||||
  spdlog::drop_all();
 | 
					 | 
				
			||||||
  spdlog::flush_every(std::chrono::seconds(10));
 | 
					 | 
				
			||||||
  spdlog::set_pattern("%Y-%m-%d|%T.%e|%^%l%$|%v");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(PROJECT_REQUIRE_ALPINE) && !defined(PROJECT_IS_MINGW)
 | 
					#if defined(PROJECT_REQUIRE_ALPINE) && !defined(PROJECT_IS_MINGW)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    static constexpr const auto guard_size{4096U};
 | 
					    static constexpr const auto guard_size{4096U};
 | 
				
			||||||
@@ -68,6 +64,10 @@ auto project_initialize() -> bool {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
#endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW)
 | 
					#endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  spdlog::drop_all();
 | 
				
			||||||
 | 
					  spdlog::flush_every(std::chrono::seconds(10));
 | 
				
			||||||
 | 
					  spdlog::set_pattern("%Y-%m-%d|%T.%e|%^%l%$|%v");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(PROJECT_ENABLE_LIBSODIUM)
 | 
					#if defined(PROJECT_ENABLE_LIBSODIUM)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (sodium_init() == -1) {
 | 
					    if (sodium_init() == -1) {
 | 
				
			||||||
@@ -77,7 +77,9 @@ auto project_initialize() -> bool {
 | 
				
			|||||||
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
 | 
					#endif // defined(PROJECT_ENABLE_LIBSODIUM)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(PROJECT_ENABLE_OPENSSL)
 | 
					#if defined(PROJECT_ENABLE_OPENSSL)
 | 
				
			||||||
  { SSL_library_init(); }
 | 
					  {
 | 
				
			||||||
 | 
					    SSL_library_init();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
#endif // defined(PROJECT_ENABLE_OPENSSL)
 | 
					#endif // defined(PROJECT_ENABLE_OPENSSL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(PROJECT_ENABLE_CURL)
 | 
					#if defined(PROJECT_ENABLE_CURL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@
 | 
				
			|||||||
#include "events/types/orphaned_file_processing_failed.hpp"
 | 
					#include "events/types/orphaned_file_processing_failed.hpp"
 | 
				
			||||||
#include "events/types/orphaned_source_file_detected.hpp"
 | 
					#include "events/types/orphaned_source_file_detected.hpp"
 | 
				
			||||||
#include "events/types/orphaned_source_file_removed.hpp"
 | 
					#include "events/types/orphaned_source_file_removed.hpp"
 | 
				
			||||||
 | 
					#include "events/types/provider_invalid_version.hpp"
 | 
				
			||||||
#include "events/types/provider_offline.hpp"
 | 
					#include "events/types/provider_offline.hpp"
 | 
				
			||||||
#include "events/types/provider_upload_begin.hpp"
 | 
					#include "events/types/provider_upload_begin.hpp"
 | 
				
			||||||
#include "events/types/provider_upload_end.hpp"
 | 
					#include "events/types/provider_upload_end.hpp"
 | 
				
			||||||
@@ -69,8 +70,8 @@ void base_provider::add_all_items(stop_type &stop_requested) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto base_provider::create_api_file(std::string path, std::string key,
 | 
					auto base_provider::create_api_file(std::string path, std::string key,
 | 
				
			||||||
                                    std::uint64_t size,
 | 
					                                    std::uint64_t size, std::uint64_t file_time)
 | 
				
			||||||
                                    std::uint64_t file_time) -> api_file {
 | 
					    -> api_file {
 | 
				
			||||||
  api_file file{};
 | 
					  api_file file{};
 | 
				
			||||||
  file.api_path = utils::path::create_api_path(path);
 | 
					  file.api_path = utils::path::create_api_path(path);
 | 
				
			||||||
  file.api_parent = utils::path::get_parent_api_path(file.api_path);
 | 
					  file.api_parent = utils::path::get_parent_api_path(file.api_path);
 | 
				
			||||||
@@ -102,8 +103,8 @@ auto base_provider::create_api_file(std::string path, std::uint64_t size,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto base_provider::create_directory_clone_source_meta(
 | 
					auto base_provider::create_directory_clone_source_meta(
 | 
				
			||||||
    const std::string &source_api_path,
 | 
					    const std::string &source_api_path, const std::string &api_path)
 | 
				
			||||||
    const std::string &api_path) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool exists{};
 | 
					  bool exists{};
 | 
				
			||||||
@@ -201,8 +202,8 @@ auto base_provider::create_directory(const std::string &api_path,
 | 
				
			|||||||
  return api_error::error;
 | 
					  return api_error::error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto base_provider::create_file(const std::string &api_path,
 | 
					auto base_provider::create_file(const std::string &api_path, api_meta_map &meta)
 | 
				
			||||||
                                api_meta_map &meta) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
@@ -259,8 +260,9 @@ auto base_provider::create_file(const std::string &api_path,
 | 
				
			|||||||
  return api_error::error;
 | 
					  return api_error::error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto base_provider::get_api_path_from_source(
 | 
					auto base_provider::get_api_path_from_source(const std::string &source_path,
 | 
				
			||||||
    const std::string &source_path, std::string &api_path) const -> api_error {
 | 
					                                             std::string &api_path) const
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (source_path.empty()) {
 | 
					  if (source_path.empty()) {
 | 
				
			||||||
@@ -273,8 +275,9 @@ auto base_provider::get_api_path_from_source(
 | 
				
			|||||||
  return db3_->get_api_path(source_path, api_path);
 | 
					  return db3_->get_api_path(source_path, api_path);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto base_provider::get_directory_items(
 | 
					auto base_provider::get_directory_items(const std::string &api_path,
 | 
				
			||||||
    const std::string &api_path, directory_item_list &list) const -> api_error {
 | 
					                                        directory_item_list &list) const
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
@@ -283,8 +286,15 @@ auto base_provider::get_directory_items(
 | 
				
			|||||||
    if (res != api_error::success) {
 | 
					    if (res != api_error::success) {
 | 
				
			||||||
      return res;
 | 
					      return res;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (not exists) {
 | 
					    if (not exists) {
 | 
				
			||||||
      return api_error::directory_not_found;
 | 
					      res = is_file(api_path, exists);
 | 
				
			||||||
 | 
					      if (res != api_error::success) {
 | 
				
			||||||
 | 
					        utils::error::raise_api_path_error(
 | 
				
			||||||
 | 
					            function_name, api_path, res, "failed to determine if file exists");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return exists ? api_error::item_exists : api_error::directory_not_found;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res = get_directory_items_impl(api_path, list);
 | 
					    res = get_directory_items_impl(api_path, list);
 | 
				
			||||||
@@ -342,9 +352,10 @@ auto base_provider::get_file_size(const std::string &api_path,
 | 
				
			|||||||
  return api_error::success;
 | 
					  return api_error::success;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto base_provider::get_filesystem_item(
 | 
					auto base_provider::get_filesystem_item(const std::string &api_path,
 | 
				
			||||||
    const std::string &api_path, bool directory,
 | 
					                                        bool directory,
 | 
				
			||||||
    filesystem_item &fsi) const -> api_error {
 | 
					                                        filesystem_item &fsi) const
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  bool exists{};
 | 
					  bool exists{};
 | 
				
			||||||
  auto res = is_directory(api_path, exists);
 | 
					  auto res = is_directory(api_path, exists);
 | 
				
			||||||
  if (res != api_error::success) {
 | 
					  if (res != api_error::success) {
 | 
				
			||||||
@@ -377,9 +388,10 @@ auto base_provider::get_filesystem_item(
 | 
				
			|||||||
  return api_error::success;
 | 
					  return api_error::success;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto base_provider::get_filesystem_item_and_file(
 | 
					auto base_provider::get_filesystem_item_and_file(const std::string &api_path,
 | 
				
			||||||
    const std::string &api_path, api_file &file,
 | 
					                                                 api_file &file,
 | 
				
			||||||
    filesystem_item &fsi) const -> api_error {
 | 
					                                                 filesystem_item &fsi) const
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  auto res = get_file(api_path, file);
 | 
					  auto res = get_file(api_path, file);
 | 
				
			||||||
  if (res != api_error::success) {
 | 
					  if (res != api_error::success) {
 | 
				
			||||||
    return res;
 | 
					    return res;
 | 
				
			||||||
@@ -829,6 +841,14 @@ auto base_provider::start(api_item_added_callback api_item_added,
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::string returned_version;
 | 
				
			||||||
 | 
					  std::string required_version;
 | 
				
			||||||
 | 
					  if (not check_version(required_version, returned_version)) {
 | 
				
			||||||
 | 
					    event_system::instance().raise<provider_invalid_version>(
 | 
				
			||||||
 | 
					        function_name, required_version, returned_version);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  cache_size_mgr::instance().initialize(&config_);
 | 
					  cache_size_mgr::instance().initialize(&config_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  polling::instance().set_callback({
 | 
					  polling::instance().set_callback({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,6 +40,7 @@
 | 
				
			|||||||
#include "utils/file_utils.hpp"
 | 
					#include "utils/file_utils.hpp"
 | 
				
			||||||
#include "utils/path.hpp"
 | 
					#include "utils/path.hpp"
 | 
				
			||||||
#include "utils/polling.hpp"
 | 
					#include "utils/polling.hpp"
 | 
				
			||||||
 | 
					#include <spdlog/fmt/bundled/base.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
encrypt_provider::encrypt_provider(app_config &config)
 | 
					encrypt_provider::encrypt_provider(app_config &config)
 | 
				
			||||||
@@ -262,7 +263,6 @@ auto encrypt_provider::get_directory_items(const std::string &api_path,
 | 
				
			|||||||
              dir_item.api_parent = file.api_parent;
 | 
					              dir_item.api_parent = file.api_parent;
 | 
				
			||||||
              dir_item.api_path = file.api_path;
 | 
					              dir_item.api_path = file.api_path;
 | 
				
			||||||
              dir_item.directory = dir_entry->is_directory_item();
 | 
					              dir_item.directory = dir_entry->is_directory_item();
 | 
				
			||||||
              dir_item.resolved = true;
 | 
					 | 
				
			||||||
              dir_item.size = file.file_size;
 | 
					              dir_item.size = file.file_size;
 | 
				
			||||||
              create_item_meta(dir_item.meta, dir_item.directory, file);
 | 
					              create_item_meta(dir_item.meta, dir_item.directory, file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -342,13 +342,23 @@ auto encrypt_provider::get_file_list(api_file_list &list,
 | 
				
			|||||||
  const auto &cfg{get_encrypt_config()};
 | 
					  const auto &cfg{get_encrypt_config()};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    for (const auto &dir_entry : utils::file::directory{cfg.path}.get_items()) {
 | 
					    using func = std::function<void(std::string path)>;
 | 
				
			||||||
      std::string api_path{};
 | 
					    const func process_directory = [&](std::string path) {
 | 
				
			||||||
      if (process_directory_entry(*dir_entry.get(), cfg, api_path)) {
 | 
					      for (const auto &dir_entry : utils::file::directory{path}.get_items()) {
 | 
				
			||||||
        list.emplace_back(create_api_file(
 | 
					        std::string api_path{};
 | 
				
			||||||
            api_path, dir_entry->is_directory_item(), dir_entry->get_path()));
 | 
					        if (dir_entry->is_directory_item()) {
 | 
				
			||||||
 | 
					          process_directory_entry(*dir_entry.get(), cfg, api_path);
 | 
				
			||||||
 | 
					          process_directory(dir_entry->get_path());
 | 
				
			||||||
 | 
					          continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (process_directory_entry(*dir_entry.get(), cfg, api_path)) {
 | 
				
			||||||
 | 
					          list.emplace_back(create_api_file(
 | 
				
			||||||
 | 
					              api_path, dir_entry->is_directory_item(), dir_entry->get_path()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
 | 
					    process_directory(cfg.path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return api_error::success;
 | 
					    return api_error::success;
 | 
				
			||||||
  } catch (const std::exception &ex) {
 | 
					  } catch (const std::exception &ex) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,9 +43,9 @@
 | 
				
			|||||||
#include "utils/time.hpp"
 | 
					#include "utils/time.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
[[nodiscard]] auto
 | 
					[[nodiscard]] auto set_request_path(auto &request,
 | 
				
			||||||
set_request_path(auto &request,
 | 
					                                    const std::string &object_name)
 | 
				
			||||||
                 const std::string &object_name) -> repertory::api_error {
 | 
					    -> repertory::api_error {
 | 
				
			||||||
  request.path = object_name;
 | 
					  request.path = object_name;
 | 
				
			||||||
  if (request.path.substr(1U).size() > repertory::max_s3_object_name_length) {
 | 
					  if (request.path.substr(1U).size() > repertory::max_s3_object_name_length) {
 | 
				
			||||||
    return repertory::api_error::name_too_long;
 | 
					    return repertory::api_error::name_too_long;
 | 
				
			||||||
@@ -59,8 +59,9 @@ namespace repertory {
 | 
				
			|||||||
s3_provider::s3_provider(app_config &config, i_http_comm &comm)
 | 
					s3_provider::s3_provider(app_config &config, i_http_comm &comm)
 | 
				
			||||||
    : base_provider(config, comm) {}
 | 
					    : base_provider(config, comm) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::add_if_not_found(
 | 
					auto s3_provider::add_if_not_found(api_file &file,
 | 
				
			||||||
    api_file &file, const std::string &object_name) const -> api_error {
 | 
					                                   const std::string &object_name) const
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  api_meta_map meta{};
 | 
					  api_meta_map meta{};
 | 
				
			||||||
  auto res{get_item_meta(file.api_path, meta)};
 | 
					  auto res{get_item_meta(file.api_path, meta)};
 | 
				
			||||||
  if (res == api_error::item_not_found) {
 | 
					  if (res == api_error::item_not_found) {
 | 
				
			||||||
@@ -88,7 +89,7 @@ auto s3_provider::convert_api_date(std::string_view date) -> std::uint64_t {
 | 
				
			|||||||
                1000000UL,
 | 
					                1000000UL,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct tm tm1 {};
 | 
					  struct tm tm1{};
 | 
				
			||||||
#if defined(_WIN32)
 | 
					#if defined(_WIN32)
 | 
				
			||||||
  utils::time::strptime(date_time.c_str(), "%Y-%m-%dT%T", &tm1);
 | 
					  utils::time::strptime(date_time.c_str(), "%Y-%m-%dT%T", &tm1);
 | 
				
			||||||
  return nanos + utils::time::windows_time_t_to_unix_time(_mkgmtime(&tm1));
 | 
					  return nanos + utils::time::windows_time_t_to_unix_time(_mkgmtime(&tm1));
 | 
				
			||||||
@@ -157,8 +158,9 @@ auto s3_provider::create_directory_impl(const std::string &api_path,
 | 
				
			|||||||
      utils::path::create_api_path(is_encrypted ? meta[META_KEY] : api_path));
 | 
					      utils::path::create_api_path(is_encrypted ? meta[META_KEY] : api_path));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::create_directory_paths(
 | 
					auto s3_provider::create_directory_paths(const std::string &api_path,
 | 
				
			||||||
    const std::string &api_path, const std::string &key) const -> api_error {
 | 
					                                         const std::string &key) const
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (api_path == "/") {
 | 
					  if (api_path == "/") {
 | 
				
			||||||
@@ -321,8 +323,9 @@ auto s3_provider::get_directory_item_count(const std::string &api_path) const
 | 
				
			|||||||
  return 0U;
 | 
					  return 0U;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::get_directory_items_impl(
 | 
					auto s3_provider::get_directory_items_impl(const std::string &api_path,
 | 
				
			||||||
    const std::string &api_path, directory_item_list &list) const -> api_error {
 | 
					                                           directory_item_list &list) const
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const auto &cfg{get_s3_config()};
 | 
					  const auto &cfg{get_s3_config()};
 | 
				
			||||||
@@ -480,8 +483,8 @@ auto s3_provider::get_directory_items_impl(
 | 
				
			|||||||
  return api_error::success;
 | 
					  return api_error::success;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::get_file(const std::string &api_path,
 | 
					auto s3_provider::get_file(const std::string &api_path, api_file &file) const
 | 
				
			||||||
                           api_file &file) const -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
@@ -492,7 +495,19 @@ auto s3_provider::get_file(const std::string &api_path,
 | 
				
			|||||||
        get_object_info(false, api_path, is_encrypted, object_name, result),
 | 
					        get_object_info(false, api_path, is_encrypted, object_name, result),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    if (res != api_error::success) {
 | 
					    if (res != api_error::success) {
 | 
				
			||||||
      return res;
 | 
					      if (res != api_error::item_not_found) {
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      bool exists{};
 | 
				
			||||||
 | 
					      res = is_directory(api_path, exists);
 | 
				
			||||||
 | 
					      if (res != api_error::success) {
 | 
				
			||||||
 | 
					        utils::error::raise_api_path_error(
 | 
				
			||||||
 | 
					            function_name, api_path, res,
 | 
				
			||||||
 | 
					            "failed to determine if directory exists");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return exists ? api_error::directory_exists : api_error::item_not_found;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    file.api_path = api_path;
 | 
					    file.api_path = api_path;
 | 
				
			||||||
@@ -521,8 +536,8 @@ auto s3_provider::get_file(const std::string &api_path,
 | 
				
			|||||||
  return api_error::error;
 | 
					  return api_error::error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::get_file_list(api_file_list &list,
 | 
					auto s3_provider::get_file_list(api_file_list &list, std::string &marker) const
 | 
				
			||||||
                                std::string &marker) const -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
@@ -612,8 +627,9 @@ auto s3_provider::get_file_list(api_file_list &list,
 | 
				
			|||||||
  return api_error::error;
 | 
					  return api_error::error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::get_last_modified(
 | 
					auto s3_provider::get_last_modified(bool directory,
 | 
				
			||||||
    bool directory, const std::string &api_path) const -> std::uint64_t {
 | 
					                                    const std::string &api_path) const
 | 
				
			||||||
 | 
					    -> std::uint64_t {
 | 
				
			||||||
  bool is_encrypted{};
 | 
					  bool is_encrypted{};
 | 
				
			||||||
  std::string object_name;
 | 
					  std::string object_name;
 | 
				
			||||||
  head_object_result result{};
 | 
					  head_object_result result{};
 | 
				
			||||||
@@ -623,9 +639,10 @@ auto s3_provider::get_last_modified(
 | 
				
			|||||||
             : utils::time::get_time_now();
 | 
					             : utils::time::get_time_now();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::get_object_info(
 | 
					auto s3_provider::get_object_info(bool directory, const std::string &api_path,
 | 
				
			||||||
    bool directory, const std::string &api_path, bool &is_encrypted,
 | 
					                                  bool &is_encrypted, std::string &object_name,
 | 
				
			||||||
    std::string &object_name, head_object_result &result) const -> api_error {
 | 
					                                  head_object_result &result) const
 | 
				
			||||||
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
@@ -685,10 +702,12 @@ auto s3_provider::get_object_info(
 | 
				
			|||||||
  return api_error::error;
 | 
					  return api_error::error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::get_object_list(
 | 
					auto s3_provider::get_object_list(std::string &response_data,
 | 
				
			||||||
    std::string &response_data, long &response_code,
 | 
					                                  long &response_code,
 | 
				
			||||||
    std::optional<std::string> delimiter, std::optional<std::string> prefix,
 | 
					                                  std::optional<std::string> delimiter,
 | 
				
			||||||
    std::optional<std::string> token) const -> bool {
 | 
					                                  std::optional<std::string> prefix,
 | 
				
			||||||
 | 
					                                  std::optional<std::string> token) const
 | 
				
			||||||
 | 
					    -> bool {
 | 
				
			||||||
  curl::requests::http_get get{};
 | 
					  curl::requests::http_get get{};
 | 
				
			||||||
  get.allow_timeout = true;
 | 
					  get.allow_timeout = true;
 | 
				
			||||||
  get.aws_service = "aws:amz:" + get_s3_config().region + ":s3";
 | 
					  get.aws_service = "aws:amz:" + get_s3_config().region + ":s3";
 | 
				
			||||||
@@ -716,8 +735,8 @@ auto s3_provider::get_total_drive_space() const -> std::uint64_t {
 | 
				
			|||||||
  return std::numeric_limits<std::int64_t>::max() / std::int64_t(2);
 | 
					  return std::numeric_limits<std::int64_t>::max() / std::int64_t(2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::is_directory(const std::string &api_path,
 | 
					auto s3_provider::is_directory(const std::string &api_path, bool &exists) const
 | 
				
			||||||
                               bool &exists) const -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
@@ -745,8 +764,8 @@ auto s3_provider::is_directory(const std::string &api_path,
 | 
				
			|||||||
  return api_error::error;
 | 
					  return api_error::error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::is_file(const std::string &api_path,
 | 
					auto s3_provider::is_file(const std::string &api_path, bool &exists) const
 | 
				
			||||||
                          bool &exists) const -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
@@ -1004,8 +1023,8 @@ auto s3_provider::rename_file(const std::string & /* from_api_path */,
 | 
				
			|||||||
  return api_error::not_implemented;
 | 
					  return api_error::not_implemented;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto s3_provider::set_meta_key(const std::string &api_path,
 | 
					auto s3_provider::set_meta_key(const std::string &api_path, api_meta_map &meta)
 | 
				
			||||||
                               api_meta_map &meta) -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const auto &cfg{get_s3_config()};
 | 
					  const auto &cfg{get_s3_config()};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,8 +32,8 @@
 | 
				
			|||||||
#include "providers/base_provider.hpp"
 | 
					#include "providers/base_provider.hpp"
 | 
				
			||||||
#include "providers/s3/s3_provider.hpp"
 | 
					#include "providers/s3/s3_provider.hpp"
 | 
				
			||||||
#include "types/repertory.hpp"
 | 
					#include "types/repertory.hpp"
 | 
				
			||||||
 | 
					#include "utils/common.hpp"
 | 
				
			||||||
#include "utils/error_utils.hpp"
 | 
					#include "utils/error_utils.hpp"
 | 
				
			||||||
#include "utils/file_utils.hpp"
 | 
					 | 
				
			||||||
#include "utils/path.hpp"
 | 
					#include "utils/path.hpp"
 | 
				
			||||||
#include "utils/polling.hpp"
 | 
					#include "utils/polling.hpp"
 | 
				
			||||||
#include "utils/string.hpp"
 | 
					#include "utils/string.hpp"
 | 
				
			||||||
@@ -63,6 +63,54 @@ namespace repertory {
 | 
				
			|||||||
sia_provider::sia_provider(app_config &config, i_http_comm &comm)
 | 
					sia_provider::sia_provider(app_config &config, i_http_comm &comm)
 | 
				
			||||||
    : base_provider(config, comm) {}
 | 
					    : base_provider(config, comm) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto sia_provider::check_version(std::string &required_version,
 | 
				
			||||||
 | 
					                                 std::string &returned_version) const -> bool {
 | 
				
			||||||
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  required_version = "2.0.0";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    curl::requests::http_get get{};
 | 
				
			||||||
 | 
					    get.allow_timeout = true;
 | 
				
			||||||
 | 
					    get.path = "/api/bus/state";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nlohmann::json state_data;
 | 
				
			||||||
 | 
					    std::string error_data;
 | 
				
			||||||
 | 
					    get.response_handler = [&error_data, &state_data](auto &&data,
 | 
				
			||||||
 | 
					                                                      long response_code) {
 | 
				
			||||||
 | 
					      if (response_code == http_error_codes::ok) {
 | 
				
			||||||
 | 
					        state_data = nlohmann::json::parse(data.begin(), data.end());
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      error_data = std::string(data.begin(), data.end());
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    long response_code{};
 | 
				
			||||||
 | 
					    stop_type stop_requested{};
 | 
				
			||||||
 | 
					    if (not get_comm().make_request(get, response_code, stop_requested)) {
 | 
				
			||||||
 | 
					      utils::error::raise_error(function_name, response_code,
 | 
				
			||||||
 | 
					                                "failed to check state");
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (response_code != http_error_codes::ok) {
 | 
				
			||||||
 | 
					      utils::error::raise_error(
 | 
				
			||||||
 | 
					          function_name, response_code,
 | 
				
			||||||
 | 
					          fmt::format("failed to check state|response|{}", error_data));
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    returned_version = state_data.at("version").get<std::string>().substr(1U);
 | 
				
			||||||
 | 
					    return utils::compare_version_strings(returned_version, required_version) >=
 | 
				
			||||||
 | 
					           0;
 | 
				
			||||||
 | 
					  } catch (const std::exception &e) {
 | 
				
			||||||
 | 
					    utils::error::raise_error(function_name, e, "failed to check version");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto sia_provider::create_directory_impl(const std::string &api_path,
 | 
					auto sia_provider::create_directory_impl(const std::string &api_path,
 | 
				
			||||||
                                         api_meta_map & /* meta */)
 | 
					                                         api_meta_map & /* meta */)
 | 
				
			||||||
    -> api_error {
 | 
					    -> api_error {
 | 
				
			||||||
@@ -70,7 +118,7 @@ auto sia_provider::create_directory_impl(const std::string &api_path,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  curl::requests::http_put_file put_file{};
 | 
					  curl::requests::http_put_file put_file{};
 | 
				
			||||||
  put_file.allow_timeout = true;
 | 
					  put_file.allow_timeout = true;
 | 
				
			||||||
  put_file.path = "/api/worker/objects" + api_path + "/";
 | 
					  put_file.path = "/api/worker/object" + api_path + "/";
 | 
				
			||||||
  put_file.query["bucket"] = get_bucket(get_sia_config());
 | 
					  put_file.query["bucket"] = get_bucket(get_sia_config());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string error_data;
 | 
					  std::string error_data;
 | 
				
			||||||
@@ -112,10 +160,10 @@ auto sia_provider::get_directory_item_count(const std::string &api_path) const
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::uint64_t item_count{};
 | 
					    std::uint64_t item_count{};
 | 
				
			||||||
    if (object_list.contains("entries")) {
 | 
					    if (object_list.contains("objects")) {
 | 
				
			||||||
      for (const auto &entry : object_list.at("entries")) {
 | 
					      for (const auto &entry : object_list.at("objects")) {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
          auto name{entry.at("name").get<std::string>()};
 | 
					          auto name{entry.at("key").get<std::string>()};
 | 
				
			||||||
          auto entry_api_path{utils::path::create_api_path(name)};
 | 
					          auto entry_api_path{utils::path::create_api_path(name)};
 | 
				
			||||||
          if (utils::string::ends_with(name, "/") &&
 | 
					          if (utils::string::ends_with(name, "/") &&
 | 
				
			||||||
              (entry_api_path == api_path)) {
 | 
					              (entry_api_path == api_path)) {
 | 
				
			||||||
@@ -149,10 +197,10 @@ auto sia_provider::get_directory_items_impl(const std::string &api_path,
 | 
				
			|||||||
    return api_error::comm_error;
 | 
					    return api_error::comm_error;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (object_list.contains("entries")) {
 | 
					  if (object_list.contains("objects")) {
 | 
				
			||||||
    for (const auto &entry : object_list.at("entries")) {
 | 
					    for (const auto &entry : object_list.at("objects")) {
 | 
				
			||||||
      try {
 | 
					      try {
 | 
				
			||||||
        auto name{entry.at("name").get<std::string>()};
 | 
					        auto name{entry.at("key").get<std::string>()};
 | 
				
			||||||
        auto entry_api_path{utils::path::create_api_path(name)};
 | 
					        auto entry_api_path{utils::path::create_api_path(name)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto directory{utils::string::ends_with(name, "/")};
 | 
					        auto directory{utils::string::ends_with(name, "/")};
 | 
				
			||||||
@@ -185,7 +233,6 @@ auto sia_provider::get_directory_items_impl(const std::string &api_path,
 | 
				
			|||||||
        dir_item.api_path = file.api_path;
 | 
					        dir_item.api_path = file.api_path;
 | 
				
			||||||
        dir_item.directory = directory;
 | 
					        dir_item.directory = directory;
 | 
				
			||||||
        dir_item.meta = meta;
 | 
					        dir_item.meta = meta;
 | 
				
			||||||
        dir_item.resolved = true;
 | 
					 | 
				
			||||||
        dir_item.size = file.file_size;
 | 
					        dir_item.size = file.file_size;
 | 
				
			||||||
        list.emplace_back(std::move(dir_item));
 | 
					        list.emplace_back(std::move(dir_item));
 | 
				
			||||||
      } catch (const std::exception &e) {
 | 
					      } catch (const std::exception &e) {
 | 
				
			||||||
@@ -207,22 +254,28 @@ auto sia_provider::get_file(const std::string &api_path, api_file &file) const
 | 
				
			|||||||
    json file_data{};
 | 
					    json file_data{};
 | 
				
			||||||
    auto res{get_object_info(api_path, file_data)};
 | 
					    auto res{get_object_info(api_path, file_data)};
 | 
				
			||||||
    if (res != api_error::success) {
 | 
					    if (res != api_error::success) {
 | 
				
			||||||
      return res;
 | 
					      if (res != api_error::item_not_found) {
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      bool exists{};
 | 
				
			||||||
 | 
					      res = is_directory(api_path, exists);
 | 
				
			||||||
 | 
					      if (res != api_error::success) {
 | 
				
			||||||
 | 
					        utils::error::raise_api_path_error(
 | 
				
			||||||
 | 
					            function_name, api_path, res,
 | 
				
			||||||
 | 
					            "failed to determine if directory exists");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return exists ? api_error::directory_exists : api_error::item_not_found;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto slabs{file_data["object"]["Slabs"]};
 | 
					 | 
				
			||||||
    auto size{
 | 
					    auto size{
 | 
				
			||||||
        std::accumulate(
 | 
					        file_data.at("size").get<std::uint64_t>(),
 | 
				
			||||||
            slabs.begin(), slabs.end(), std::uint64_t(0U),
 | 
					 | 
				
			||||||
            [](auto &&total_size, const json &slab) -> std::uint64_t {
 | 
					 | 
				
			||||||
              return total_size + slab["Length"].get<std::uint64_t>();
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    api_meta_map meta{};
 | 
					    api_meta_map meta{};
 | 
				
			||||||
    if (get_item_meta(api_path, meta) == api_error::item_not_found) {
 | 
					    if (get_item_meta(api_path, meta) == api_error::item_not_found) {
 | 
				
			||||||
      file = create_api_file(api_path, "", size,
 | 
					      file = create_api_file(api_path, "", size, get_last_modified(file_data));
 | 
				
			||||||
                             get_last_modified(file_data["object"]));
 | 
					 | 
				
			||||||
      get_api_item_added()(false, file);
 | 
					      get_api_item_added()(false, file);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      file = create_api_file(api_path, size, meta);
 | 
					      file = create_api_file(api_path, size, meta);
 | 
				
			||||||
@@ -250,9 +303,9 @@ auto sia_provider::get_file_list(api_file_list &list,
 | 
				
			|||||||
        return api_error::comm_error;
 | 
					        return api_error::comm_error;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (object_list.contains("entries")) {
 | 
					      if (object_list.contains("objects")) {
 | 
				
			||||||
        for (const auto &entry : object_list.at("entries")) {
 | 
					        for (const auto &entry : object_list.at("objects")) {
 | 
				
			||||||
          auto name{entry.at("name").get<std::string>()};
 | 
					          auto name{entry.at("key").get<std::string>()};
 | 
				
			||||||
          auto entry_api_path{utils::path::create_api_path(name)};
 | 
					          auto entry_api_path{utils::path::create_api_path(name)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (utils::string::ends_with(name, "/")) {
 | 
					          if (utils::string::ends_with(name, "/")) {
 | 
				
			||||||
@@ -313,8 +366,9 @@ auto sia_provider::get_object_info(const std::string &api_path,
 | 
				
			|||||||
  try {
 | 
					  try {
 | 
				
			||||||
    curl::requests::http_get get{};
 | 
					    curl::requests::http_get get{};
 | 
				
			||||||
    get.allow_timeout = true;
 | 
					    get.allow_timeout = true;
 | 
				
			||||||
    get.path = "/api/bus/objects" + api_path;
 | 
					    get.path = "/api/bus/object" + api_path;
 | 
				
			||||||
    get.query["bucket"] = get_bucket(get_sia_config());
 | 
					    get.query["bucket"] = get_bucket(get_sia_config());
 | 
				
			||||||
 | 
					    get.query["onlymetadata"] = "true";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string error_data;
 | 
					    std::string error_data;
 | 
				
			||||||
    get.response_handler = [&error_data, &object_info](auto &&data,
 | 
					    get.response_handler = [&error_data, &object_info](auto &&data,
 | 
				
			||||||
@@ -362,6 +416,7 @@ auto sia_provider::get_object_list(const std::string &api_path,
 | 
				
			|||||||
    get.allow_timeout = true;
 | 
					    get.allow_timeout = true;
 | 
				
			||||||
    get.path = "/api/bus/objects" + api_path + "/";
 | 
					    get.path = "/api/bus/objects" + api_path + "/";
 | 
				
			||||||
    get.query["bucket"] = get_bucket(get_sia_config());
 | 
					    get.query["bucket"] = get_bucket(get_sia_config());
 | 
				
			||||||
 | 
					    get.query["delimiter"] = "/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string error_data;
 | 
					    std::string error_data;
 | 
				
			||||||
    get.response_handler = [&error_data, &object_list](auto &&data,
 | 
					    get.response_handler = [&error_data, &object_list](auto &&data,
 | 
				
			||||||
@@ -405,7 +460,7 @@ auto sia_provider::get_total_drive_space() const -> std::uint64_t {
 | 
				
			|||||||
  try {
 | 
					  try {
 | 
				
			||||||
    curl::requests::http_get get{};
 | 
					    curl::requests::http_get get{};
 | 
				
			||||||
    get.allow_timeout = true;
 | 
					    get.allow_timeout = true;
 | 
				
			||||||
    get.path = "/api/autopilot/config";
 | 
					    get.path = "/api/bus/autopilot";
 | 
				
			||||||
    get.query["bucket"] = get_bucket(get_sia_config());
 | 
					    get.query["bucket"] = get_bucket(get_sia_config());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    json config_data;
 | 
					    json config_data;
 | 
				
			||||||
@@ -455,17 +510,18 @@ auto sia_provider::is_directory(const std::string &api_path, bool &exists) const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    exists = false;
 | 
					    exists = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    json object_list{};
 | 
					    json file_data{};
 | 
				
			||||||
    if (not get_object_list(utils::path::get_parent_api_path(api_path),
 | 
					    auto res{get_object_info(api_path + '/', file_data)};
 | 
				
			||||||
                            object_list)) {
 | 
					    if (res == api_error::item_not_found) {
 | 
				
			||||||
      return api_error::comm_error;
 | 
					      return api_error::success;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    exists = object_list.contains("entries") &&
 | 
					    if (res != api_error::success) {
 | 
				
			||||||
             std::ranges::find_if(object_list.at("entries"),
 | 
					      return res;
 | 
				
			||||||
                                  [&api_path](auto &&entry) -> bool {
 | 
					    }
 | 
				
			||||||
                                    return entry.at("name") == (api_path + "/");
 | 
					
 | 
				
			||||||
                                  }) != object_list.at("entries").end();
 | 
					    exists =
 | 
				
			||||||
 | 
					        utils::string::ends_with(file_data.at("key").get<std::string>(), "/");
 | 
				
			||||||
    return api_error::success;
 | 
					    return api_error::success;
 | 
				
			||||||
  } catch (const std::exception &e) {
 | 
					  } catch (const std::exception &e) {
 | 
				
			||||||
    utils::error::raise_api_path_error(
 | 
					    utils::error::raise_api_path_error(
 | 
				
			||||||
@@ -481,6 +537,7 @@ auto sia_provider::is_file(const std::string &api_path, bool &exists) const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    exists = false;
 | 
					    exists = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (api_path == "/") {
 | 
					    if (api_path == "/") {
 | 
				
			||||||
      return api_error::success;
 | 
					      return api_error::success;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -495,7 +552,8 @@ auto sia_provider::is_file(const std::string &api_path, bool &exists) const
 | 
				
			|||||||
      return res;
 | 
					      return res;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    exists = not file_data.contains("entries");
 | 
					    exists = not utils::string::ends_with(
 | 
				
			||||||
 | 
					        file_data.at("key").get<std::string>(), "/");
 | 
				
			||||||
    return api_error::success;
 | 
					    return api_error::success;
 | 
				
			||||||
  } catch (const std::exception &e) {
 | 
					  } catch (const std::exception &e) {
 | 
				
			||||||
    utils::error::raise_api_path_error(function_name, api_path, e,
 | 
					    utils::error::raise_api_path_error(function_name, api_path, e,
 | 
				
			||||||
@@ -559,8 +617,9 @@ auto sia_provider::read_file_bytes(const std::string &api_path,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    curl::requests::http_get get{};
 | 
					    curl::requests::http_get get{};
 | 
				
			||||||
    get.path = "/api/worker/objects" + api_path;
 | 
					    get.path = "/api/worker/object" + api_path;
 | 
				
			||||||
    get.query["bucket"] = get_bucket(get_sia_config());
 | 
					    get.query["bucket"] = get_bucket(get_sia_config());
 | 
				
			||||||
 | 
					    get.headers["accept"] = "application/octet-stream";
 | 
				
			||||||
    get.range = {{
 | 
					    get.range = {{
 | 
				
			||||||
        offset,
 | 
					        offset,
 | 
				
			||||||
        offset + size - 1U,
 | 
					        offset + size - 1U,
 | 
				
			||||||
@@ -577,6 +636,7 @@ auto sia_provider::read_file_bytes(const std::string &api_path,
 | 
				
			|||||||
         ++idx) {
 | 
					         ++idx) {
 | 
				
			||||||
      long response_code{};
 | 
					      long response_code{};
 | 
				
			||||||
      const auto notify_retry = [&]() {
 | 
					      const auto notify_retry = [&]() {
 | 
				
			||||||
 | 
					        fmt::println("{}", std::string(buffer.begin(), buffer.end()));
 | 
				
			||||||
        if (response_code == 0) {
 | 
					        if (response_code == 0) {
 | 
				
			||||||
          utils::error::raise_api_path_error(
 | 
					          utils::error::raise_api_path_error(
 | 
				
			||||||
              function_name, api_path, api_error::comm_error,
 | 
					              function_name, api_path, api_error::comm_error,
 | 
				
			||||||
@@ -622,7 +682,7 @@ auto sia_provider::remove_directory_impl(const std::string &api_path)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  curl::requests::http_delete del{};
 | 
					  curl::requests::http_delete del{};
 | 
				
			||||||
  del.allow_timeout = true;
 | 
					  del.allow_timeout = true;
 | 
				
			||||||
  del.path = "/api/bus/objects" + api_path + "/";
 | 
					  del.path = "/api/bus/object" + api_path + "/";
 | 
				
			||||||
  del.query["bucket"] = get_bucket(get_sia_config());
 | 
					  del.query["bucket"] = get_bucket(get_sia_config());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string error_data;
 | 
					  std::string error_data;
 | 
				
			||||||
@@ -658,7 +718,7 @@ auto sia_provider::remove_file_impl(const std::string &api_path) -> api_error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  curl::requests::http_delete del{};
 | 
					  curl::requests::http_delete del{};
 | 
				
			||||||
  del.allow_timeout = true;
 | 
					  del.allow_timeout = true;
 | 
				
			||||||
  del.path = "/api/bus/objects" + api_path;
 | 
					  del.path = "/api/bus/object" + api_path;
 | 
				
			||||||
  del.query["bucket"] = get_bucket(get_sia_config());
 | 
					  del.query["bucket"] = get_bucket(get_sia_config());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string error_data;
 | 
					  std::string error_data;
 | 
				
			||||||
@@ -697,12 +757,12 @@ auto sia_provider::rename_file(const std::string &from_api_path,
 | 
				
			|||||||
  try {
 | 
					  try {
 | 
				
			||||||
    curl::requests::http_post post{};
 | 
					    curl::requests::http_post post{};
 | 
				
			||||||
    post.json = nlohmann::json({
 | 
					    post.json = nlohmann::json({
 | 
				
			||||||
 | 
					        {"bucket", get_bucket(get_sia_config())},
 | 
				
			||||||
        {"from", from_api_path},
 | 
					        {"from", from_api_path},
 | 
				
			||||||
        {"to", to_api_path},
 | 
					        {"to", to_api_path},
 | 
				
			||||||
        {"mode", "single"},
 | 
					        {"mode", "single"},
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    post.path = "/api/bus/objects/rename";
 | 
					    post.path = "/api/bus/objects/rename";
 | 
				
			||||||
    post.query["bucket"] = get_bucket(get_sia_config());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string error_data;
 | 
					    std::string error_data;
 | 
				
			||||||
    post.response_handler = [&error_data](auto &&data, long response_code) {
 | 
					    post.response_handler = [&error_data](auto &&data, long response_code) {
 | 
				
			||||||
@@ -770,8 +830,9 @@ auto sia_provider::upload_file_impl(const std::string &api_path,
 | 
				
			|||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  curl::requests::http_put_file put_file{};
 | 
					  curl::requests::http_put_file put_file{};
 | 
				
			||||||
  put_file.path = "/api/worker/objects" + api_path;
 | 
					  put_file.path = "/api/worker/object" + api_path;
 | 
				
			||||||
  put_file.query["bucket"] = get_bucket(get_sia_config());
 | 
					  put_file.query["bucket"] = get_bucket(get_sia_config());
 | 
				
			||||||
 | 
					  put_file.headers["content-type"] = "application/octet-stream";
 | 
				
			||||||
  put_file.source_path = source_path;
 | 
					  put_file.source_path = source_path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string error_data;
 | 
					  std::string error_data;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,47 +38,58 @@ void polling::frequency_thread(
 | 
				
			|||||||
    std::function<std::uint32_t()> get_frequency_seconds, frequency freq) {
 | 
					    std::function<std::uint32_t()> get_frequency_seconds, frequency freq) {
 | 
				
			||||||
  REPERTORY_USES_FUNCTION_NAME();
 | 
					  REPERTORY_USES_FUNCTION_NAME();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto last_run = std::chrono::system_clock::time_point::min();
 | 
				
			||||||
  while (not get_stop_requested()) {
 | 
					  while (not get_stop_requested()) {
 | 
				
			||||||
    unique_mutex_lock lock(mutex_);
 | 
					    auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(
 | 
				
			||||||
    auto futures = std::accumulate(
 | 
					        std::chrono::system_clock::now() - last_run);
 | 
				
			||||||
        items_.begin(), items_.end(), std::deque<tasks::task_ptr>{},
 | 
					    auto max_elapsed = std::chrono::seconds(get_frequency_seconds());
 | 
				
			||||||
        [this, &freq](auto &&list, auto &&item) -> auto {
 | 
					
 | 
				
			||||||
          if (item.second.freq != freq) {
 | 
					    if (last_run == std::chrono::system_clock::time_point::min() ||
 | 
				
			||||||
 | 
					        elapsed >= max_elapsed) {
 | 
				
			||||||
 | 
					      unique_mutex_lock lock(mutex_);
 | 
				
			||||||
 | 
					      auto futures = std::accumulate(
 | 
				
			||||||
 | 
					          items_.begin(), items_.end(), std::deque<tasks::task_ptr>{},
 | 
				
			||||||
 | 
					          [this, &freq](auto &&list, auto &&item) -> auto {
 | 
				
			||||||
 | 
					            if (item.second.freq != freq) {
 | 
				
			||||||
 | 
					              return list;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            auto future = tasks::instance().schedule({
 | 
				
			||||||
 | 
					                [this, &freq, item](auto &&task_stopped) {
 | 
				
			||||||
 | 
					                  if (config_->get_event_level() == event_level::trace ||
 | 
				
			||||||
 | 
					                      freq != frequency::second) {
 | 
				
			||||||
 | 
					                    event_system::instance().raise<polling_item_begin>(
 | 
				
			||||||
 | 
					                        function_name, item.first);
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  item.second.action(task_stopped);
 | 
				
			||||||
 | 
					                  if (config_->get_event_level() == event_level::trace ||
 | 
				
			||||||
 | 
					                      freq != frequency::second) {
 | 
				
			||||||
 | 
					                    event_system::instance().raise<polling_item_end>(
 | 
				
			||||||
 | 
					                        function_name, item.first);
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            list.emplace_back(future);
 | 
				
			||||||
            return list;
 | 
					            return list;
 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          auto future = tasks::instance().schedule({
 | 
					 | 
				
			||||||
              [this, &freq, item](auto &&task_stopped) {
 | 
					 | 
				
			||||||
                if (config_->get_event_level() == event_level::trace ||
 | 
					 | 
				
			||||||
                    freq != frequency::second) {
 | 
					 | 
				
			||||||
                  event_system::instance().raise<polling_item_begin>(
 | 
					 | 
				
			||||||
                      function_name, item.first);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                item.second.action(task_stopped);
 | 
					 | 
				
			||||||
                if (config_->get_event_level() == event_level::trace ||
 | 
					 | 
				
			||||||
                    freq != frequency::second) {
 | 
					 | 
				
			||||||
                  event_system::instance().raise<polling_item_end>(
 | 
					 | 
				
			||||||
                      function_name, item.first);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
 | 
					      lock.unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          list.emplace_back(future);
 | 
					      while (not futures.empty()) {
 | 
				
			||||||
          return list;
 | 
					        futures.front()->wait();
 | 
				
			||||||
        });
 | 
					        futures.pop_front();
 | 
				
			||||||
    lock.unlock();
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (not futures.empty()) {
 | 
					      last_run = std::chrono::system_clock::now();
 | 
				
			||||||
      futures.front()->wait();
 | 
					      elapsed = std::chrono::seconds(0U);
 | 
				
			||||||
      futures.pop_front();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unique_mutex_lock lock(mutex_);
 | 
				
			||||||
    if (get_stop_requested()) {
 | 
					    if (get_stop_requested()) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    lock.lock();
 | 
					    notify_.wait_for(lock, max_elapsed - elapsed);
 | 
				
			||||||
    notify_.wait_for(lock, std::chrono::seconds(get_frequency_seconds()));
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,50 +23,38 @@
 | 
				
			|||||||
#define REPERTORY_INCLUDE_CLI_CHECK_VERSION_HPP_
 | 
					#define REPERTORY_INCLUDE_CLI_CHECK_VERSION_HPP_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "app_config.hpp"
 | 
					#include "app_config.hpp"
 | 
				
			||||||
 | 
					#include "comm/curl/curl_comm.hpp"
 | 
				
			||||||
 | 
					#include "providers/sia/sia_provider.hpp"
 | 
				
			||||||
#include "types/repertory.hpp"
 | 
					#include "types/repertory.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory::cli::actions {
 | 
					namespace repertory::cli::actions {
 | 
				
			||||||
[[nodiscard]] inline auto
 | 
					[[nodiscard]] inline auto check_version(std::vector<const char *> /* args */,
 | 
				
			||||||
check_version(std::vector<const char *> /* args */,
 | 
					                                        const std::string &data_directory,
 | 
				
			||||||
              const std::string & /* data_directory */,
 | 
					                                        const provider_type &prov,
 | 
				
			||||||
              const provider_type & /* pt */, const std::string & /*unique_id*/,
 | 
					                                        const std::string & /*unique_id*/,
 | 
				
			||||||
              std::string /*user*/, std::string /*password*/) -> exit_code {
 | 
					                                        std::string /*user*/,
 | 
				
			||||||
  auto ret = exit_code::success;
 | 
					                                        std::string /*password*/) -> exit_code {
 | 
				
			||||||
 | 
					  if (prov != provider_type::sia) {
 | 
				
			||||||
 | 
					    fmt::println("Success:\n\tNo specific version is required for {} providers",
 | 
				
			||||||
 | 
					                 app_config::get_provider_display_name(prov));
 | 
				
			||||||
 | 
					    return exit_code::success;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO need to updated way to check version
 | 
					  app_config config(prov, data_directory);
 | 
				
			||||||
  // if (not((pt == provider_type::remote) || (pt == provider_type::s3))) {
 | 
					  curl_comm comm(config.get_host_config());
 | 
				
			||||||
  //   app_config config(pt, data_directory);
 | 
					  sia_provider provider(config, comm);
 | 
				
			||||||
  //   curl_comm comm(config);
 | 
					 | 
				
			||||||
  //   json data, err;
 | 
					 | 
				
			||||||
  //
 | 
					 | 
				
			||||||
  //   if (comm.get("/daemon/version", data, err) == api_error::success) {
 | 
					 | 
				
			||||||
  //     const auto res = utils::compare_version_strings(
 | 
					 | 
				
			||||||
  //         data["version"].get<std::string>(),
 | 
					 | 
				
			||||||
  //         app_config::get_provider_minimum_version(pt));
 | 
					 | 
				
			||||||
  //     if (res < 0) {
 | 
					 | 
				
			||||||
  //       ret = exit_code::incompatible_version;
 | 
					 | 
				
			||||||
  //       std::cerr << "Failed!" << std::endl;
 | 
					 | 
				
			||||||
  //       std::cerr << "   Actual: " << data["version"].get<std::string>()
 | 
					 | 
				
			||||||
  //                 << std::endl;
 | 
					 | 
				
			||||||
  //       std::cerr << "  Minimum: "
 | 
					 | 
				
			||||||
  //                 << app_config::get_provider_minimum_version(pt) <<
 | 
					 | 
				
			||||||
  //                 std::endl;
 | 
					 | 
				
			||||||
  //     } else {
 | 
					 | 
				
			||||||
  //       std::cout << "Success!" << std::endl;
 | 
					 | 
				
			||||||
  //       std::cout << "   Actual: " << data["version"].get<std::string>()
 | 
					 | 
				
			||||||
  //                 << std::endl;
 | 
					 | 
				
			||||||
  //       std::cout << "  Minimum: "
 | 
					 | 
				
			||||||
  //                 << app_config::get_provider_minimum_version(pt) <<
 | 
					 | 
				
			||||||
  //                 std::endl;
 | 
					 | 
				
			||||||
  //     }
 | 
					 | 
				
			||||||
  //   } else {
 | 
					 | 
				
			||||||
  //     std::cerr << "Failed!" << std::endl;
 | 
					 | 
				
			||||||
  //     std::cerr << err.dump(2) << std::endl;
 | 
					 | 
				
			||||||
  //     ret = exit_code::communication_error;
 | 
					 | 
				
			||||||
  //   }
 | 
					 | 
				
			||||||
  // }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return ret;
 | 
					  std::string required_version;
 | 
				
			||||||
 | 
					  std::string returned_version;
 | 
				
			||||||
 | 
					  if (provider.check_version(required_version, returned_version)) {
 | 
				
			||||||
 | 
					    fmt::println("Success:\n\tRequired: {}\n\tActual: {}", required_version,
 | 
				
			||||||
 | 
					                 returned_version);
 | 
				
			||||||
 | 
					    return exit_code::success;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fmt::println("Failed:\n\tRequired: {}\n\tActual: {}", required_version,
 | 
				
			||||||
 | 
					               returned_version);
 | 
				
			||||||
 | 
					  return exit_code::incompatible_version;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
} // namespace repertory::cli::actions
 | 
					} // namespace repertory::cli::actions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -268,8 +268,8 @@ public:
 | 
				
			|||||||
    return file_path;
 | 
					    return file_path;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static auto create_file_and_test(std::string &file_name,
 | 
					  static auto create_file_and_test(std::string &file_name, mode_t perms)
 | 
				
			||||||
                                   mode_t perms) -> std::string {
 | 
					      -> std::string {
 | 
				
			||||||
    file_name += std::to_string(++provider_idx);
 | 
					    file_name += std::to_string(++provider_idx);
 | 
				
			||||||
    auto file_path = utils::path::combine(mount_location, {file_name});
 | 
					    auto file_path = utils::path::combine(mount_location, {file_name});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -287,7 +287,7 @@ public:
 | 
				
			|||||||
    EXPECT_TRUE(utils::file::file(file_path).exists());
 | 
					    EXPECT_TRUE(utils::file::file(file_path).exists());
 | 
				
			||||||
    EXPECT_FALSE(utils::file::directory(file_path).exists());
 | 
					    EXPECT_FALSE(utils::file::directory(file_path).exists());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct stat64 unix_st {};
 | 
					    struct stat64 unix_st{};
 | 
				
			||||||
    EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
 | 
					    EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
 | 
				
			||||||
    EXPECT_EQ(getgid(), unix_st.st_gid);
 | 
					    EXPECT_EQ(getgid(), unix_st.st_gid);
 | 
				
			||||||
    EXPECT_EQ(getuid(), unix_st.st_uid);
 | 
					    EXPECT_EQ(getuid(), unix_st.st_uid);
 | 
				
			||||||
@@ -299,8 +299,8 @@ public:
 | 
				
			|||||||
    return create_file_and_test(file_name, ACCESSPERMS);
 | 
					    return create_file_and_test(file_name, ACCESSPERMS);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static auto create_directory_and_test(std::string &dir_name,
 | 
					  static auto create_directory_and_test(std::string &dir_name, mode_t perms)
 | 
				
			||||||
                                        mode_t perms) -> std::string {
 | 
					      -> std::string {
 | 
				
			||||||
    dir_name += std::to_string(++provider_idx);
 | 
					    dir_name += std::to_string(++provider_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto dir_path = utils::path::combine(mount_location, {dir_name});
 | 
					    auto dir_path = utils::path::combine(mount_location, {dir_name});
 | 
				
			||||||
@@ -309,7 +309,7 @@ public:
 | 
				
			|||||||
    EXPECT_TRUE(utils::file::directory(dir_path).exists());
 | 
					    EXPECT_TRUE(utils::file::directory(dir_path).exists());
 | 
				
			||||||
    EXPECT_FALSE(utils::file::file(dir_path).exists());
 | 
					    EXPECT_FALSE(utils::file::file(dir_path).exists());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct stat64 unix_st {};
 | 
					    struct stat64 unix_st{};
 | 
				
			||||||
    EXPECT_EQ(0, stat64(dir_path.c_str(), &unix_st));
 | 
					    EXPECT_EQ(0, stat64(dir_path.c_str(), &unix_st));
 | 
				
			||||||
    EXPECT_EQ(getgid(), unix_st.st_gid);
 | 
					    EXPECT_EQ(getgid(), unix_st.st_gid);
 | 
				
			||||||
    EXPECT_EQ(getuid(), unix_st.st_uid);
 | 
					    EXPECT_EQ(getuid(), unix_st.st_uid);
 | 
				
			||||||
@@ -410,9 +410,9 @@ std::string fuse_test<provider_t>::mount_location;
 | 
				
			|||||||
template <typename provider_t>
 | 
					template <typename provider_t>
 | 
				
			||||||
std::string fuse_test<provider_t>::mount_location2;
 | 
					std::string fuse_test<provider_t>::mount_location2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using fuse_provider_types = ::testing::Types<local_s3, remote_s3>;
 | 
					// using fuse_provider_types = ::testing::Types<local_s3, remote_s3>;
 | 
				
			||||||
// using fuse_provider_types =
 | 
					using fuse_provider_types =
 | 
				
			||||||
//     ::testing::Types<local_s3, remote_s3, local_sia, remote_sia>;
 | 
					    ::testing::Types<local_s3, remote_s3, local_sia, remote_sia>;
 | 
				
			||||||
} // namespace repertory
 | 
					} // namespace repertory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // !defined(_WIN32)
 | 
					#endif // !defined(_WIN32)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,10 @@ private:
 | 
				
			|||||||
  const bool allow_rename_;
 | 
					  const bool allow_rename_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
 | 
					  MOCK_METHOD(bool, check_version,
 | 
				
			||||||
 | 
					              (std::string & required_version, std::string &returned_version),
 | 
				
			||||||
 | 
					              (const, override));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  MOCK_METHOD(api_error, create_directory,
 | 
					  MOCK_METHOD(api_error, create_directory,
 | 
				
			||||||
              (const std::string &api_path, api_meta_map &meta), (override));
 | 
					              (const std::string &api_path, api_meta_map &meta), (override));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										763
									
								
								repertory/repertory_test/src/app_config_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										763
									
								
								repertory/repertory_test/src/app_config_test.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,763 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 Copyright <2018-2025> <scott.e.graves@protonmail.com>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					  of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					  in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					  copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					  furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					  copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					  SOFTWARE.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#include "test_common.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "app_config.hpp"
 | 
				
			||||||
 | 
					#include "utils/path.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace repertory {
 | 
				
			||||||
 | 
					class app_config_test : public ::testing::Test {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  static std::atomic<std::uint64_t> idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::string encrypt_directory;
 | 
				
			||||||
 | 
					  std::string remote_directory;
 | 
				
			||||||
 | 
					  std::string s3_directory;
 | 
				
			||||||
 | 
					  std::string sia_directory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void SetUp() override {
 | 
				
			||||||
 | 
					    encrypt_directory = utils::path::combine(test::get_test_output_dir(),
 | 
				
			||||||
 | 
					                                             {
 | 
				
			||||||
 | 
					                                                 "app_config_test",
 | 
				
			||||||
 | 
					                                                 "encrypt",
 | 
				
			||||||
 | 
					                                                 std::to_string(++idx),
 | 
				
			||||||
 | 
					                                             });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    remote_directory = utils::path::combine(test::get_test_output_dir(),
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                "app_config_test",
 | 
				
			||||||
 | 
					                                                "remote",
 | 
				
			||||||
 | 
					                                                std::to_string(++idx),
 | 
				
			||||||
 | 
					                                            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s3_directory = utils::path::combine(test::get_test_output_dir(),
 | 
				
			||||||
 | 
					                                        {
 | 
				
			||||||
 | 
					                                            "app_config_test",
 | 
				
			||||||
 | 
					                                            "s3",
 | 
				
			||||||
 | 
					                                            std::to_string(++idx),
 | 
				
			||||||
 | 
					                                        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sia_directory = utils::path::combine(test::get_test_output_dir(),
 | 
				
			||||||
 | 
					                                         {
 | 
				
			||||||
 | 
					                                             "app_config_test",
 | 
				
			||||||
 | 
					                                             "sia",
 | 
				
			||||||
 | 
					                                             std::to_string(++idx),
 | 
				
			||||||
 | 
					                                         });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void remove_unused_types(auto &data, provider_type prov) {
 | 
				
			||||||
 | 
					  switch (prov) {
 | 
				
			||||||
 | 
					  case provider_type::encrypt:
 | 
				
			||||||
 | 
					    data.erase(JSON_DOWNLOAD_TIMEOUT_SECS);
 | 
				
			||||||
 | 
					    data.erase(JSON_ENABLE_DOWNLOAD_TIMEOUT);
 | 
				
			||||||
 | 
					    data.erase(JSON_EVICTION_DELAY_MINS);
 | 
				
			||||||
 | 
					    data.erase(JSON_EVICTION_USE_ACCESS_TIME);
 | 
				
			||||||
 | 
					    data.erase(JSON_HOST_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_MAX_CACHE_SIZE_BYTES);
 | 
				
			||||||
 | 
					    data.erase(JSON_MAX_UPLOAD_COUNT);
 | 
				
			||||||
 | 
					    data.erase(JSON_ONLINE_CHECK_RETRY_SECS);
 | 
				
			||||||
 | 
					    data.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
 | 
				
			||||||
 | 
					    data.erase(JSON_REMOTE_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_RETRY_READ_COUNT);
 | 
				
			||||||
 | 
					    data.erase(JSON_RING_BUFFER_FILE_SIZE);
 | 
				
			||||||
 | 
					    data.erase(JSON_S3_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_SIA_CONFIG);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  case provider_type::remote:
 | 
				
			||||||
 | 
					    data.erase(JSON_DATABASE_TYPE);
 | 
				
			||||||
 | 
					    data.erase(JSON_DOWNLOAD_TIMEOUT_SECS);
 | 
				
			||||||
 | 
					    data.erase(JSON_ENABLE_DOWNLOAD_TIMEOUT);
 | 
				
			||||||
 | 
					    data.erase(JSON_ENCRYPT_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_EVICTION_DELAY_MINS);
 | 
				
			||||||
 | 
					    data.erase(JSON_EVICTION_USE_ACCESS_TIME);
 | 
				
			||||||
 | 
					    data.erase(JSON_HIGH_FREQ_INTERVAL_SECS);
 | 
				
			||||||
 | 
					    data.erase(JSON_HOST_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_LOW_FREQ_INTERVAL_SECS);
 | 
				
			||||||
 | 
					    data.erase(JSON_MAX_CACHE_SIZE_BYTES);
 | 
				
			||||||
 | 
					    data.erase(JSON_MAX_UPLOAD_COUNT);
 | 
				
			||||||
 | 
					    data.erase(JSON_MED_FREQ_INTERVAL_SECS);
 | 
				
			||||||
 | 
					    data.erase(JSON_ONLINE_CHECK_RETRY_SECS);
 | 
				
			||||||
 | 
					    data.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
 | 
				
			||||||
 | 
					    data.erase(JSON_REMOTE_MOUNT);
 | 
				
			||||||
 | 
					    data.erase(JSON_RETRY_READ_COUNT);
 | 
				
			||||||
 | 
					    data.erase(JSON_RING_BUFFER_FILE_SIZE);
 | 
				
			||||||
 | 
					    data.erase(JSON_S3_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_SIA_CONFIG);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  case provider_type::s3:
 | 
				
			||||||
 | 
					    data.erase(JSON_ENCRYPT_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_HOST_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_REMOTE_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_SIA_CONFIG);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  case provider_type::sia:
 | 
				
			||||||
 | 
					    data.erase(JSON_ENCRYPT_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_REMOTE_CONFIG);
 | 
				
			||||||
 | 
					    data.erase(JSON_S3_CONFIG);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::atomic<std::uint64_t> app_config_test::idx{0U};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void defaults_tests(const json &json_data, provider_type prov) {
 | 
				
			||||||
 | 
					  json json_defaults = {
 | 
				
			||||||
 | 
					      {JSON_API_PORT, app_config::default_rpc_port(prov)},
 | 
				
			||||||
 | 
					      {JSON_API_USER, std::string{REPERTORY}},
 | 
				
			||||||
 | 
					      {JSON_DOWNLOAD_TIMEOUT_SECS, default_download_timeout_secs},
 | 
				
			||||||
 | 
					      {JSON_DATABASE_TYPE, database_type::rocksdb},
 | 
				
			||||||
 | 
					      {JSON_ENABLE_DOWNLOAD_TIMEOUT, true},
 | 
				
			||||||
 | 
					      {JSON_ENABLE_DRIVE_EVENTS, false},
 | 
				
			||||||
 | 
					#if defined(_WIN32)
 | 
				
			||||||
 | 
					      {JSON_ENABLE_MOUNT_MANAGER, false},
 | 
				
			||||||
 | 
					#endif // defined(_WIN32)
 | 
				
			||||||
 | 
					      {JSON_ENCRYPT_CONFIG, encrypt_config{}},
 | 
				
			||||||
 | 
					      {JSON_EVENT_LEVEL, event_level::info},
 | 
				
			||||||
 | 
					      {JSON_EVICTION_DELAY_MINS, default_eviction_delay_mins},
 | 
				
			||||||
 | 
					      {JSON_EVICTION_USE_ACCESS_TIME, false},
 | 
				
			||||||
 | 
					      {JSON_HIGH_FREQ_INTERVAL_SECS, default_high_freq_interval_secs},
 | 
				
			||||||
 | 
					      {JSON_HOST_CONFIG, host_config{}},
 | 
				
			||||||
 | 
					      {JSON_LOW_FREQ_INTERVAL_SECS, default_low_freq_interval_secs},
 | 
				
			||||||
 | 
					      {JSON_MAX_CACHE_SIZE_BYTES, default_max_cache_size_bytes},
 | 
				
			||||||
 | 
					      {JSON_MAX_UPLOAD_COUNT, default_max_upload_count},
 | 
				
			||||||
 | 
					      {JSON_MED_FREQ_INTERVAL_SECS, default_med_freq_interval_secs},
 | 
				
			||||||
 | 
					      {JSON_ONLINE_CHECK_RETRY_SECS, default_online_check_retry_secs},
 | 
				
			||||||
 | 
					      {JSON_PREFERRED_DOWNLOAD_TYPE, download_type::default_},
 | 
				
			||||||
 | 
					      {JSON_REMOTE_CONFIG, remote::remote_config{}},
 | 
				
			||||||
 | 
					      {JSON_REMOTE_MOUNT, remote::remote_mount{}},
 | 
				
			||||||
 | 
					      {JSON_RETRY_READ_COUNT, default_retry_read_count},
 | 
				
			||||||
 | 
					      {JSON_RING_BUFFER_FILE_SIZE, default_ring_buffer_file_size},
 | 
				
			||||||
 | 
					      {JSON_S3_CONFIG, s3_config{}},
 | 
				
			||||||
 | 
					      {JSON_SIA_CONFIG, sia_config{}},
 | 
				
			||||||
 | 
					      {JSON_TASK_WAIT_MS, default_task_wait_ms},
 | 
				
			||||||
 | 
					      {JSON_VERSION, REPERTORY_CONFIG_VERSION},
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  remove_unused_types(json_defaults, prov);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  switch (prov) {
 | 
				
			||||||
 | 
					  case provider_type::encrypt:
 | 
				
			||||||
 | 
					    json_defaults[JSON_REMOTE_MOUNT][JSON_API_PORT] =
 | 
				
			||||||
 | 
					        app_config::default_remote_api_port(prov);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    json_defaults[JSON_REMOTE_MOUNT][JSON_API_PORT] =
 | 
				
			||||||
 | 
					        app_config::default_remote_api_port(prov);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  case provider_type::sia:
 | 
				
			||||||
 | 
					    json_defaults[JSON_HOST_CONFIG][JSON_API_PORT] =
 | 
				
			||||||
 | 
					        app_config::default_api_port(prov);
 | 
				
			||||||
 | 
					    json_defaults[JSON_HOST_CONFIG][JSON_AGENT_STRING] =
 | 
				
			||||||
 | 
					        app_config::default_agent_name(prov);
 | 
				
			||||||
 | 
					    json_defaults[JSON_REMOTE_MOUNT][JSON_API_PORT] =
 | 
				
			||||||
 | 
					        app_config::default_remote_api_port(prov);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fmt::println("testing default|{}-{}", app_config::get_provider_name(prov),
 | 
				
			||||||
 | 
					               JSON_API_AUTH);
 | 
				
			||||||
 | 
					  ASSERT_EQ(std::size_t(default_api_auth_size),
 | 
				
			||||||
 | 
					            json_data.at(JSON_API_AUTH).get<std::string>().size());
 | 
				
			||||||
 | 
					  for (const auto &[key, value] : json_defaults.items()) {
 | 
				
			||||||
 | 
					    fmt::println("testing default|{}-{}", app_config::get_provider_name(prov),
 | 
				
			||||||
 | 
					                 key);
 | 
				
			||||||
 | 
					    EXPECT_EQ(value, json_data.at(key));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename get_t, typename set_t, typename val_t>
 | 
				
			||||||
 | 
					static void test_getter_setter(app_config &cfg, get_t getter, set_t setter,
 | 
				
			||||||
 | 
					                               val_t val1, val_t val2, const std::string &key,
 | 
				
			||||||
 | 
					                               const std::string &val_str) {
 | 
				
			||||||
 | 
					  (cfg.*setter)(val1);
 | 
				
			||||||
 | 
					  ASSERT_TRUE((cfg.*getter)() == val1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  (cfg.*setter)(val2);
 | 
				
			||||||
 | 
					  ASSERT_TRUE((cfg.*getter)() == val2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (key.empty()) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_STREQ(val_str.c_str(), cfg.set_value_by_name(key, val_str).c_str());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void common_tests(app_config &config, provider_type prov) {
 | 
				
			||||||
 | 
					  ASSERT_EQ(config.get_provider_type(), prov);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::map<std::string_view, std::function<void(app_config &)>> methods{
 | 
				
			||||||
 | 
					      {JSON_API_AUTH,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_api_auth,
 | 
				
			||||||
 | 
					                            &app_config::set_api_auth, "", "auth",
 | 
				
			||||||
 | 
					                            JSON_API_AUTH, "auth2");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_API_PORT,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_api_port,
 | 
				
			||||||
 | 
					                            &app_config::set_api_port, std::uint16_t{0U},
 | 
				
			||||||
 | 
					                            std::uint16_t{1024U}, JSON_API_PORT, "1025");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_API_USER,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_api_user,
 | 
				
			||||||
 | 
					                            &app_config::set_api_user, "", "user",
 | 
				
			||||||
 | 
					                            JSON_API_USER, "user2");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_DOWNLOAD_TIMEOUT_SECS,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_download_timeout_secs,
 | 
				
			||||||
 | 
					                            &app_config::set_download_timeout_secs,
 | 
				
			||||||
 | 
					                            std::uint8_t{min_download_timeout_secs + 1U},
 | 
				
			||||||
 | 
					                            std::uint8_t{min_download_timeout_secs + 2U},
 | 
				
			||||||
 | 
					                            JSON_DOWNLOAD_TIMEOUT_SECS,
 | 
				
			||||||
 | 
					                            std::to_string(min_download_timeout_secs + 2U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_download_timeout_secs(min_download_timeout_secs - 1U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(min_download_timeout_secs, cfg.get_download_timeout_secs());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_DATABASE_TYPE,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_database_type,
 | 
				
			||||||
 | 
					                            &app_config::set_database_type,
 | 
				
			||||||
 | 
					                            database_type::rocksdb, database_type::sqlite,
 | 
				
			||||||
 | 
					                            JSON_DATABASE_TYPE, "rocksdb");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_ENABLE_DOWNLOAD_TIMEOUT,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_enable_download_timeout,
 | 
				
			||||||
 | 
					                            &app_config::set_enable_download_timeout, true,
 | 
				
			||||||
 | 
					                            false, JSON_ENABLE_DOWNLOAD_TIMEOUT, "1");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_ENABLE_DRIVE_EVENTS,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_enable_drive_events,
 | 
				
			||||||
 | 
					                            &app_config::set_enable_drive_events, true, false,
 | 
				
			||||||
 | 
					                            JSON_ENABLE_DRIVE_EVENTS, "1");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					#if defined(_WIN32)
 | 
				
			||||||
 | 
					      {JSON_ENABLE_MOUNT_MANAGER,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_enable_mount_manager,
 | 
				
			||||||
 | 
					                            &app_config::set_enable_mount_manager, true, false,
 | 
				
			||||||
 | 
					                            JSON_ENABLE_MOUNT_MANAGER, "1");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					#endif // defined(_WIN32)
 | 
				
			||||||
 | 
					      {JSON_ENCRYPT_CONFIG,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         encrypt_config cfg1{};
 | 
				
			||||||
 | 
					         cfg1.encryption_token = "1";
 | 
				
			||||||
 | 
					         cfg1.path = "2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         encrypt_config cfg2{};
 | 
				
			||||||
 | 
					         cfg2.encryption_token = "2";
 | 
				
			||||||
 | 
					         cfg2.path = "1";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         ASSERT_NE(cfg1, cfg2);
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_encrypt_config,
 | 
				
			||||||
 | 
					                            &app_config::set_encrypt_config, cfg1, cfg2, "",
 | 
				
			||||||
 | 
					                            "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         encrypt_config cfg3{};
 | 
				
			||||||
 | 
					         cfg3.encryption_token = "3";
 | 
				
			||||||
 | 
					         cfg3.path = "4";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         auto value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_ENCRYPT_CONFIG, JSON_ENCRYPTION_TOKEN),
 | 
				
			||||||
 | 
					             cfg3.encryption_token);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.encryption_token.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_ENCRYPT_CONFIG, JSON_PATH), cfg3.path);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.path.c_str(), value.c_str());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_EVENT_LEVEL,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_event_level,
 | 
				
			||||||
 | 
					                            &app_config::set_event_level, event_level::critical,
 | 
				
			||||||
 | 
					                            event_level::debug, JSON_EVENT_LEVEL, "info");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_EVICTION_DELAY_MINS,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_eviction_delay_mins,
 | 
				
			||||||
 | 
					                            &app_config::set_eviction_delay_mins,
 | 
				
			||||||
 | 
					                            std::uint32_t{0U}, std::uint32_t{1U},
 | 
				
			||||||
 | 
					                            JSON_EVICTION_DELAY_MINS, "2");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_EVICTION_USE_ACCESS_TIME,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_eviction_uses_accessed_time,
 | 
				
			||||||
 | 
					                            &app_config::set_eviction_uses_accessed_time, true,
 | 
				
			||||||
 | 
					                            false, JSON_EVICTION_USE_ACCESS_TIME, "1");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_HIGH_FREQ_INTERVAL_SECS,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(
 | 
				
			||||||
 | 
					             cfg, &app_config::get_high_frequency_interval_secs,
 | 
				
			||||||
 | 
					             &app_config::set_high_frequency_interval_secs,
 | 
				
			||||||
 | 
					             std::uint16_t{default_high_freq_interval_secs + 1U},
 | 
				
			||||||
 | 
					             std::uint16_t{default_high_freq_interval_secs + 2U},
 | 
				
			||||||
 | 
					             JSON_HIGH_FREQ_INTERVAL_SECS,
 | 
				
			||||||
 | 
					             std::to_string(default_high_freq_interval_secs + 3U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_high_frequency_interval_secs(0U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(1U, cfg.get_high_frequency_interval_secs());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_HOST_CONFIG,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         host_config cfg1{};
 | 
				
			||||||
 | 
					         cfg1.agent_string = "1";
 | 
				
			||||||
 | 
					         cfg1.api_password = "2";
 | 
				
			||||||
 | 
					         cfg1.api_user = "3";
 | 
				
			||||||
 | 
					         cfg1.api_port = 4U;
 | 
				
			||||||
 | 
					         cfg1.host_name_or_ip = "5";
 | 
				
			||||||
 | 
					         cfg1.path = "6";
 | 
				
			||||||
 | 
					         cfg1.protocol = "http";
 | 
				
			||||||
 | 
					         cfg1.timeout_ms = 8U;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         host_config cfg2{};
 | 
				
			||||||
 | 
					         cfg2.agent_string = "9";
 | 
				
			||||||
 | 
					         cfg2.api_password = "10";
 | 
				
			||||||
 | 
					         cfg2.api_user = "11";
 | 
				
			||||||
 | 
					         cfg2.api_port = 12U;
 | 
				
			||||||
 | 
					         cfg2.host_name_or_ip = "13";
 | 
				
			||||||
 | 
					         cfg2.path = "14";
 | 
				
			||||||
 | 
					         cfg2.protocol = "https";
 | 
				
			||||||
 | 
					         cfg2.timeout_ms = 16U;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         ASSERT_NE(cfg1, cfg2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_host_config,
 | 
				
			||||||
 | 
					                            &app_config::set_host_config, cfg1, cfg2, "", "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         host_config cfg3{};
 | 
				
			||||||
 | 
					         cfg3.agent_string = "17";
 | 
				
			||||||
 | 
					         cfg3.api_password = "18";
 | 
				
			||||||
 | 
					         cfg3.api_user = "19";
 | 
				
			||||||
 | 
					         cfg3.api_port = 20U;
 | 
				
			||||||
 | 
					         cfg3.host_name_or_ip = "21";
 | 
				
			||||||
 | 
					         cfg3.path = "22";
 | 
				
			||||||
 | 
					         cfg3.protocol = "http";
 | 
				
			||||||
 | 
					         cfg3.timeout_ms = 24;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         auto value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_AGENT_STRING),
 | 
				
			||||||
 | 
					             cfg3.agent_string);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.agent_string.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PASSWORD),
 | 
				
			||||||
 | 
					             cfg3.api_password);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.api_password.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_USER),
 | 
				
			||||||
 | 
					             cfg3.api_user);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.api_user.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PORT),
 | 
				
			||||||
 | 
					             std::to_string(cfg3.api_port));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(std::to_string(cfg3.api_port).c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP),
 | 
				
			||||||
 | 
					             cfg3.host_name_or_ip);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.host_name_or_ip.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PATH), cfg3.path);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.path.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PROTOCOL),
 | 
				
			||||||
 | 
					             cfg3.protocol);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.protocol.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS),
 | 
				
			||||||
 | 
					             std::to_string(cfg3.timeout_ms));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(std::to_string(cfg3.timeout_ms).c_str(), value.c_str());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_LOW_FREQ_INTERVAL_SECS,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(
 | 
				
			||||||
 | 
					             cfg, &app_config::get_low_frequency_interval_secs,
 | 
				
			||||||
 | 
					             &app_config::set_low_frequency_interval_secs,
 | 
				
			||||||
 | 
					             std::uint16_t{default_low_freq_interval_secs + 1U},
 | 
				
			||||||
 | 
					             std::uint16_t{default_low_freq_interval_secs + 2U},
 | 
				
			||||||
 | 
					             JSON_LOW_FREQ_INTERVAL_SECS,
 | 
				
			||||||
 | 
					             std::to_string(default_low_freq_interval_secs + 3U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_low_frequency_interval_secs(0U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(1U, cfg.get_low_frequency_interval_secs());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_MAX_CACHE_SIZE_BYTES,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(
 | 
				
			||||||
 | 
					             cfg, &app_config::get_max_cache_size_bytes,
 | 
				
			||||||
 | 
					             &app_config::set_max_cache_size_bytes, min_cache_size_bytes + 1U,
 | 
				
			||||||
 | 
					             min_cache_size_bytes + 2U, JSON_MAX_CACHE_SIZE_BYTES,
 | 
				
			||||||
 | 
					             std::to_string(min_cache_size_bytes + 3U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_max_cache_size_bytes(min_cache_size_bytes - 1U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(min_cache_size_bytes, cfg.get_max_cache_size_bytes());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_MAX_UPLOAD_COUNT,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_max_upload_count,
 | 
				
			||||||
 | 
					                            &app_config::set_max_upload_count, std::uint8_t{1U},
 | 
				
			||||||
 | 
					                            std::uint8_t{2U}, JSON_MAX_UPLOAD_COUNT, "3");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_max_upload_count(0U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(1U, cfg.get_max_upload_count());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_MED_FREQ_INTERVAL_SECS,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(
 | 
				
			||||||
 | 
					             cfg, &app_config::get_med_frequency_interval_secs,
 | 
				
			||||||
 | 
					             &app_config::set_med_frequency_interval_secs,
 | 
				
			||||||
 | 
					             std::uint16_t{default_med_freq_interval_secs + 1U},
 | 
				
			||||||
 | 
					             std::uint16_t{default_med_freq_interval_secs + 2U},
 | 
				
			||||||
 | 
					             JSON_MED_FREQ_INTERVAL_SECS,
 | 
				
			||||||
 | 
					             std::to_string(default_med_freq_interval_secs + 3U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_med_frequency_interval_secs(0U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(1U, cfg.get_med_frequency_interval_secs());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_ONLINE_CHECK_RETRY_SECS,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_online_check_retry_secs,
 | 
				
			||||||
 | 
					                            &app_config::set_online_check_retry_secs,
 | 
				
			||||||
 | 
					                            std::uint16_t{min_online_check_retry_secs + 1U},
 | 
				
			||||||
 | 
					                            std::uint16_t{min_online_check_retry_secs + 2U},
 | 
				
			||||||
 | 
					                            JSON_ONLINE_CHECK_RETRY_SECS,
 | 
				
			||||||
 | 
					                            std::to_string(min_online_check_retry_secs + 3U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_online_check_retry_secs(min_online_check_retry_secs - 1U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(min_online_check_retry_secs,
 | 
				
			||||||
 | 
					                   cfg.get_online_check_retry_secs());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_PREFERRED_DOWNLOAD_TYPE,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_preferred_download_type,
 | 
				
			||||||
 | 
					                            &app_config::set_preferred_download_type,
 | 
				
			||||||
 | 
					                            download_type::direct, download_type::default_,
 | 
				
			||||||
 | 
					                            JSON_PREFERRED_DOWNLOAD_TYPE, "ring_buffer");
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_REMOTE_CONFIG,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         remote::remote_config remote_cfg1{};
 | 
				
			||||||
 | 
					         remote_cfg1.api_port = 1U;
 | 
				
			||||||
 | 
					         remote_cfg1.encryption_token = "2";
 | 
				
			||||||
 | 
					         remote_cfg1.host_name_or_ip = "3";
 | 
				
			||||||
 | 
					         remote_cfg1.max_connections = 4U;
 | 
				
			||||||
 | 
					         remote_cfg1.recv_timeout_ms = 5U;
 | 
				
			||||||
 | 
					         remote_cfg1.send_timeout_ms = 6U;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         remote::remote_config remote_cfg2{};
 | 
				
			||||||
 | 
					         remote_cfg1.api_port = 6U;
 | 
				
			||||||
 | 
					         remote_cfg1.encryption_token = "5";
 | 
				
			||||||
 | 
					         remote_cfg1.host_name_or_ip = "4";
 | 
				
			||||||
 | 
					         remote_cfg1.max_connections = 3U;
 | 
				
			||||||
 | 
					         remote_cfg1.recv_timeout_ms = 2U;
 | 
				
			||||||
 | 
					         remote_cfg1.send_timeout_ms = 1U;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         ASSERT_NE(remote_cfg1, remote_cfg2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_remote_config,
 | 
				
			||||||
 | 
					                            &app_config::set_remote_config, remote_cfg1,
 | 
				
			||||||
 | 
					                            remote_cfg2, "", "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         remote::remote_config remote_cfg3{};
 | 
				
			||||||
 | 
					         remote_cfg1.api_port = 7U;
 | 
				
			||||||
 | 
					         remote_cfg1.encryption_token = "8";
 | 
				
			||||||
 | 
					         remote_cfg1.host_name_or_ip = "9";
 | 
				
			||||||
 | 
					         remote_cfg1.max_connections = 10U;
 | 
				
			||||||
 | 
					         remote_cfg1.recv_timeout_ms = 11U;
 | 
				
			||||||
 | 
					         remote_cfg1.send_timeout_ms = 12U;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         auto value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_API_PORT),
 | 
				
			||||||
 | 
					             std::to_string(remote_cfg3.api_port));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(std::to_string(remote_cfg3.api_port).c_str(),
 | 
				
			||||||
 | 
					                      value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_ENCRYPTION_TOKEN),
 | 
				
			||||||
 | 
					             remote_cfg3.encryption_token);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(remote_cfg3.encryption_token.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_HOST_NAME_OR_IP),
 | 
				
			||||||
 | 
					             remote_cfg3.host_name_or_ip);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(remote_cfg3.host_name_or_ip.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_MAX_CONNECTIONS),
 | 
				
			||||||
 | 
					             std::to_string(remote_cfg3.max_connections));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(std::to_string(remote_cfg3.max_connections).c_str(),
 | 
				
			||||||
 | 
					                      value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_RECV_TIMEOUT_MS),
 | 
				
			||||||
 | 
					             std::to_string(remote_cfg3.recv_timeout_ms));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(std::to_string(remote_cfg3.recv_timeout_ms).c_str(),
 | 
				
			||||||
 | 
					                      value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_SEND_TIMEOUT_MS),
 | 
				
			||||||
 | 
					             std::to_string(remote_cfg3.send_timeout_ms));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(std::to_string(remote_cfg3.send_timeout_ms).c_str(),
 | 
				
			||||||
 | 
					                      value.c_str());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_REMOTE_MOUNT,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         remote::remote_mount mnt_cfg1{};
 | 
				
			||||||
 | 
					         mnt_cfg1.api_port = 1U;
 | 
				
			||||||
 | 
					         mnt_cfg1.client_pool_size = 2U;
 | 
				
			||||||
 | 
					         mnt_cfg1.enable = false;
 | 
				
			||||||
 | 
					         mnt_cfg1.encryption_token = "3";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         remote::remote_mount mnt_cfg2{};
 | 
				
			||||||
 | 
					         mnt_cfg2.api_port = 3U;
 | 
				
			||||||
 | 
					         mnt_cfg2.client_pool_size = 4U;
 | 
				
			||||||
 | 
					         mnt_cfg2.enable = true;
 | 
				
			||||||
 | 
					         mnt_cfg2.encryption_token = "5";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         ASSERT_NE(mnt_cfg1, mnt_cfg2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_remote_mount,
 | 
				
			||||||
 | 
					                            &app_config::set_remote_mount, mnt_cfg1, mnt_cfg2,
 | 
				
			||||||
 | 
					                            "", "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         remote::remote_mount mnt_cfg3{};
 | 
				
			||||||
 | 
					         mnt_cfg3.api_port = 9U;
 | 
				
			||||||
 | 
					         mnt_cfg3.client_pool_size = 10U;
 | 
				
			||||||
 | 
					         mnt_cfg3.enable = false;
 | 
				
			||||||
 | 
					         mnt_cfg3.encryption_token = "11";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         auto value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_API_PORT),
 | 
				
			||||||
 | 
					             std::to_string(mnt_cfg3.api_port));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(std::to_string(mnt_cfg3.api_port).c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_CLIENT_POOL_SIZE),
 | 
				
			||||||
 | 
					             std::to_string(mnt_cfg3.client_pool_size));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(std::to_string(mnt_cfg3.client_pool_size).c_str(),
 | 
				
			||||||
 | 
					                      value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_ENABLE_REMOTE_MOUNT),
 | 
				
			||||||
 | 
					             utils::string::from_bool(mnt_cfg3.enable));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(utils::string::from_bool(mnt_cfg3.enable).c_str(),
 | 
				
			||||||
 | 
					                      value.c_str());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_RETRY_READ_COUNT,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_retry_read_count,
 | 
				
			||||||
 | 
					                            &app_config::set_retry_read_count,
 | 
				
			||||||
 | 
					                            std::uint16_t{min_retry_read_count + 1U},
 | 
				
			||||||
 | 
					                            std::uint16_t{min_retry_read_count + 2U},
 | 
				
			||||||
 | 
					                            JSON_RETRY_READ_COUNT,
 | 
				
			||||||
 | 
					                            std::to_string(min_retry_read_count + 3U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_retry_read_count(min_retry_read_count - 1U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(min_retry_read_count, cfg.get_retry_read_count());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_RING_BUFFER_FILE_SIZE,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_ring_buffer_file_size,
 | 
				
			||||||
 | 
					                            &app_config::set_ring_buffer_file_size,
 | 
				
			||||||
 | 
					                            std::uint16_t{min_ring_buffer_file_size + 1U},
 | 
				
			||||||
 | 
					                            std::uint16_t{min_ring_buffer_file_size + 2U},
 | 
				
			||||||
 | 
					                            JSON_RING_BUFFER_FILE_SIZE,
 | 
				
			||||||
 | 
					                            std::to_string(min_ring_buffer_file_size + 3U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_ring_buffer_file_size(min_ring_buffer_file_size - 1U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(min_ring_buffer_file_size, cfg.get_ring_buffer_file_size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_ring_buffer_file_size(max_ring_buffer_file_size + 1U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(max_ring_buffer_file_size, cfg.get_ring_buffer_file_size());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_S3_CONFIG,
 | 
				
			||||||
 | 
					       [](auto &&cfg) {
 | 
				
			||||||
 | 
					         s3_config cfg1{};
 | 
				
			||||||
 | 
					         cfg1.access_key = "1";
 | 
				
			||||||
 | 
					         cfg1.bucket = "2";
 | 
				
			||||||
 | 
					         cfg1.encryption_token = "3";
 | 
				
			||||||
 | 
					         cfg1.region = "4";
 | 
				
			||||||
 | 
					         cfg1.secret_key = "5";
 | 
				
			||||||
 | 
					         cfg1.timeout_ms = 6U;
 | 
				
			||||||
 | 
					         cfg1.url = "7";
 | 
				
			||||||
 | 
					         cfg1.use_path_style = false;
 | 
				
			||||||
 | 
					         cfg1.use_region_in_url = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         s3_config cfg2{};
 | 
				
			||||||
 | 
					         cfg2.access_key = "8";
 | 
				
			||||||
 | 
					         cfg2.bucket = "9";
 | 
				
			||||||
 | 
					         cfg2.encryption_token = "10";
 | 
				
			||||||
 | 
					         cfg2.region = "11";
 | 
				
			||||||
 | 
					         cfg2.secret_key = "12";
 | 
				
			||||||
 | 
					         cfg2.timeout_ms = 13U;
 | 
				
			||||||
 | 
					         cfg2.url = "14";
 | 
				
			||||||
 | 
					         cfg2.use_path_style = true;
 | 
				
			||||||
 | 
					         cfg2.use_region_in_url = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         ASSERT_NE(cfg1, cfg2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_s3_config,
 | 
				
			||||||
 | 
					                            &app_config::set_s3_config, cfg1, cfg2, "", "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         s3_config cfg3{};
 | 
				
			||||||
 | 
					         cfg3.access_key = "8";
 | 
				
			||||||
 | 
					         cfg3.bucket = "9";
 | 
				
			||||||
 | 
					         cfg3.encryption_token = "10";
 | 
				
			||||||
 | 
					         cfg3.region = "11";
 | 
				
			||||||
 | 
					         cfg3.secret_key = "12";
 | 
				
			||||||
 | 
					         cfg3.timeout_ms = 13U;
 | 
				
			||||||
 | 
					         cfg3.url = "14";
 | 
				
			||||||
 | 
					         cfg3.use_path_style = true;
 | 
				
			||||||
 | 
					         cfg3.use_region_in_url = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         auto value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_S3_CONFIG, JSON_ACCESS_KEY),
 | 
				
			||||||
 | 
					             cfg3.access_key);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.access_key.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_S3_CONFIG, JSON_BUCKET), cfg3.bucket);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.bucket.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_S3_CONFIG, JSON_ENCRYPTION_TOKEN),
 | 
				
			||||||
 | 
					             cfg3.encryption_token);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.encryption_token.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_S3_CONFIG, JSON_REGION), cfg3.region);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.region.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_S3_CONFIG, JSON_SECRET_KEY),
 | 
				
			||||||
 | 
					             cfg3.secret_key);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.secret_key.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_S3_CONFIG, JSON_TIMEOUT_MS),
 | 
				
			||||||
 | 
					             std::to_string(cfg3.timeout_ms));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(std::to_string(cfg3.timeout_ms).c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_S3_CONFIG, JSON_URL), cfg3.url);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.url.c_str(), value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_S3_CONFIG, JSON_USE_PATH_STYLE),
 | 
				
			||||||
 | 
					             utils::string::from_bool(cfg3.use_path_style));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(utils::string::from_bool(cfg3.use_path_style).c_str(),
 | 
				
			||||||
 | 
					                      value.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_S3_CONFIG, JSON_USE_REGION_IN_URL),
 | 
				
			||||||
 | 
					             utils::string::from_bool(cfg3.use_region_in_url));
 | 
				
			||||||
 | 
					         EXPECT_STREQ(utils::string::from_bool(cfg3.use_region_in_url).c_str(),
 | 
				
			||||||
 | 
					                      value.c_str());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_SIA_CONFIG,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         sia_config cfg1{};
 | 
				
			||||||
 | 
					         cfg1.bucket = "1";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         sia_config cfg2{};
 | 
				
			||||||
 | 
					         cfg2.bucket = "2";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         ASSERT_NE(cfg1, cfg2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         test_getter_setter(cfg, &app_config::get_sia_config,
 | 
				
			||||||
 | 
					                            &app_config::set_sia_config, cfg1, cfg2, "", "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         sia_config cfg3{};
 | 
				
			||||||
 | 
					         cfg3.bucket = "3";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         auto value = cfg.set_value_by_name(
 | 
				
			||||||
 | 
					             fmt::format("{}.{}", JSON_SIA_CONFIG, JSON_BUCKET), cfg3.bucket);
 | 
				
			||||||
 | 
					         EXPECT_STREQ(cfg3.bucket.c_str(), value.c_str());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					      {JSON_TASK_WAIT_MS,
 | 
				
			||||||
 | 
					       [](app_config &cfg) {
 | 
				
			||||||
 | 
					         test_getter_setter(
 | 
				
			||||||
 | 
					             cfg, &app_config::get_task_wait_ms, &app_config::set_task_wait_ms,
 | 
				
			||||||
 | 
					             std::uint16_t{min_task_wait_ms + 1U},
 | 
				
			||||||
 | 
					             std::uint16_t{min_task_wait_ms + 2U}, JSON_TASK_WAIT_MS,
 | 
				
			||||||
 | 
					             std::to_string(min_task_wait_ms + 3U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         cfg.set_task_wait_ms(min_task_wait_ms - 1U);
 | 
				
			||||||
 | 
					         EXPECT_EQ(min_task_wait_ms, cfg.get_task_wait_ms());
 | 
				
			||||||
 | 
					       }},
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  remove_unused_types(methods, prov);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (const auto &[key, test_function] : methods) {
 | 
				
			||||||
 | 
					    fmt::println("testing setting|{}-{}", app_config::get_provider_name(prov),
 | 
				
			||||||
 | 
					                 key);
 | 
				
			||||||
 | 
					    test_function(config);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(app_config_test, encrypt_config) {
 | 
				
			||||||
 | 
					  app_config config(provider_type::encrypt, encrypt_directory);
 | 
				
			||||||
 | 
					  defaults_tests(config.get_json(), provider_type::encrypt);
 | 
				
			||||||
 | 
					  common_tests(config, provider_type::encrypt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(app_config_test, remote_config) {
 | 
				
			||||||
 | 
					  app_config config(provider_type::remote, remote_directory);
 | 
				
			||||||
 | 
					  defaults_tests(config.get_json(), provider_type::remote);
 | 
				
			||||||
 | 
					  common_tests(config, provider_type::remote);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(app_config_test, s3_config) {
 | 
				
			||||||
 | 
					  app_config config(provider_type::s3, s3_directory);
 | 
				
			||||||
 | 
					  defaults_tests(config.get_json(), provider_type::s3);
 | 
				
			||||||
 | 
					  common_tests(config, provider_type::s3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(app_config_test, sia_config) {
 | 
				
			||||||
 | 
					  app_config config(provider_type::sia, sia_directory);
 | 
				
			||||||
 | 
					  defaults_tests(config.get_json(), provider_type::sia);
 | 
				
			||||||
 | 
					  common_tests(config, provider_type::sia);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					} // namespace repertory
 | 
				
			||||||
@@ -24,7 +24,7 @@
 | 
				
			|||||||
#include "types/repertory.hpp"
 | 
					#include "types/repertory.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
TEST(atomic, atomic_primitive) {
 | 
					TEST(atomic_test, atomic_primitive) {
 | 
				
			||||||
  atomic<std::uint16_t> value;
 | 
					  atomic<std::uint16_t> value;
 | 
				
			||||||
  value = 5U;
 | 
					  value = 5U;
 | 
				
			||||||
  EXPECT_EQ(5U, static_cast<std::uint16_t>(value));
 | 
					  EXPECT_EQ(5U, static_cast<std::uint16_t>(value));
 | 
				
			||||||
@@ -35,7 +35,7 @@ TEST(atomic, atomic_primitive) {
 | 
				
			|||||||
  EXPECT_EQ(6U, value.load());
 | 
					  EXPECT_EQ(6U, value.load());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(atomic, atomic_primitive_equality) {
 | 
					TEST(atomic_test, atomic_primitive_equality) {
 | 
				
			||||||
  atomic<std::uint16_t> value1{5U};
 | 
					  atomic<std::uint16_t> value1{5U};
 | 
				
			||||||
  atomic<std::uint16_t> value2{5U};
 | 
					  atomic<std::uint16_t> value2{5U};
 | 
				
			||||||
  EXPECT_EQ(value1, value1);
 | 
					  EXPECT_EQ(value1, value1);
 | 
				
			||||||
@@ -45,7 +45,7 @@ TEST(atomic, atomic_primitive_equality) {
 | 
				
			|||||||
  EXPECT_EQ(static_cast<std::uint16_t>(value2), 5U);
 | 
					  EXPECT_EQ(static_cast<std::uint16_t>(value2), 5U);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(atomic, atomic_primitive_inequality) {
 | 
					TEST(atomic_test, atomic_primitive_inequality) {
 | 
				
			||||||
  atomic<std::uint16_t> value1{5U};
 | 
					  atomic<std::uint16_t> value1{5U};
 | 
				
			||||||
  atomic<std::uint16_t> value2{6U};
 | 
					  atomic<std::uint16_t> value2{6U};
 | 
				
			||||||
  EXPECT_NE(value1, value2);
 | 
					  EXPECT_NE(value1, value2);
 | 
				
			||||||
@@ -53,7 +53,7 @@ TEST(atomic, atomic_primitive_inequality) {
 | 
				
			|||||||
  EXPECT_NE(static_cast<std::uint16_t>(value2), 5U);
 | 
					  EXPECT_NE(static_cast<std::uint16_t>(value2), 5U);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(atomic, atomic_struct) {
 | 
					TEST(atomic_test, atomic_struct) {
 | 
				
			||||||
  atomic<encrypt_config> value{
 | 
					  atomic<encrypt_config> value{
 | 
				
			||||||
      encrypt_config{
 | 
					      encrypt_config{
 | 
				
			||||||
          .encryption_token = "token",
 | 
					          .encryption_token = "token",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,696 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 Copyright <2018-2025> <scott.e.graves@protonmail.com>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 | 
				
			||||||
  of this software and associated documentation files (the "Software"), to deal
 | 
					 | 
				
			||||||
  in the Software without restriction, including without limitation the rights
 | 
					 | 
				
			||||||
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					 | 
				
			||||||
  copies of the Software, and to permit persons to whom the Software is
 | 
					 | 
				
			||||||
  furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  The above copyright notice and this permission notice shall be included in all
 | 
					 | 
				
			||||||
  copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
					 | 
				
			||||||
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					 | 
				
			||||||
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
					 | 
				
			||||||
  SOFTWARE.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
#include "test_common.hpp"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "app_config.hpp"
 | 
					 | 
				
			||||||
#include "events/event_system.hpp"
 | 
					 | 
				
			||||||
#include "utils/common.hpp"
 | 
					 | 
				
			||||||
#include "utils/file_utils.hpp"
 | 
					 | 
				
			||||||
#include "utils/path.hpp"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace repertory {
 | 
					 | 
				
			||||||
class config_test : public ::testing::Test {
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
  console_consumer cs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static std::atomic<std::uint64_t> idx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::string s3_directory;
 | 
					 | 
				
			||||||
  std::string sia_directory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void SetUp() override {
 | 
					 | 
				
			||||||
    s3_directory = utils::path::combine(test::get_test_output_dir(),
 | 
					 | 
				
			||||||
                                        {
 | 
					 | 
				
			||||||
                                            "config_test",
 | 
					 | 
				
			||||||
                                            "s3",
 | 
					 | 
				
			||||||
                                            std::to_string(++idx),
 | 
					 | 
				
			||||||
                                        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sia_directory = utils::path::combine(test::get_test_output_dir(),
 | 
					 | 
				
			||||||
                                         {
 | 
					 | 
				
			||||||
                                             "config_test",
 | 
					 | 
				
			||||||
                                             "sia",
 | 
					 | 
				
			||||||
                                             std::to_string(++idx),
 | 
					 | 
				
			||||||
                                         });
 | 
					 | 
				
			||||||
    event_system::instance().start();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void TearDown() override {
 | 
					 | 
				
			||||||
    event_system::instance().stop();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::atomic<std::uint64_t> config_test::idx{0U};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, api_path) {
 | 
					 | 
				
			||||||
  std::string original_value;
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_api_auth();
 | 
					 | 
				
			||||||
    EXPECT_EQ(48U, original_value.size());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, api_auth) {
 | 
					 | 
				
			||||||
  std::string original_value;
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_api_auth();
 | 
					 | 
				
			||||||
    config.set_api_auth(original_value.substr(0, 20));
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value.substr(0, 20), config.get_api_auth());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value.substr(0, 20), config.get_api_auth());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, api_port) {
 | 
					 | 
				
			||||||
  std::uint16_t original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_api_port();
 | 
					 | 
				
			||||||
    config.set_api_port(original_value + 5);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5, config.get_api_port());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5, config.get_api_port());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, api_user) {
 | 
					 | 
				
			||||||
  std::string original_value;
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_api_user();
 | 
					 | 
				
			||||||
    config.set_api_user(original_value.substr(0, 2));
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value.substr(0, 2), config.get_api_user());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value.substr(0, 2), config.get_api_user());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, download_timeout_secs) {
 | 
					 | 
				
			||||||
  std::uint8_t original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_download_timeout_secs();
 | 
					 | 
				
			||||||
    config.set_download_timeout_secs(original_value + 5);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5, config.get_download_timeout_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5, config.get_download_timeout_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, enable_download_timeout) {
 | 
					 | 
				
			||||||
  bool original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_enable_download_timeout();
 | 
					 | 
				
			||||||
    config.set_enable_download_timeout(not original_value);
 | 
					 | 
				
			||||||
    EXPECT_EQ(not original_value, config.get_enable_download_timeout());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(not original_value, config.get_enable_download_timeout());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, enable_drive_events) {
 | 
					 | 
				
			||||||
  bool original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_enable_drive_events();
 | 
					 | 
				
			||||||
    config.set_enable_drive_events(not original_value);
 | 
					 | 
				
			||||||
    EXPECT_EQ(not original_value, config.get_enable_drive_events());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(not original_value, config.get_enable_drive_events());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(_WIN32)
 | 
					 | 
				
			||||||
TEST_F(config_test, enable_mount_manager) {
 | 
					 | 
				
			||||||
  bool original_value;
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_enable_mount_manager();
 | 
					 | 
				
			||||||
    config.set_enable_mount_manager(not original_value);
 | 
					 | 
				
			||||||
    EXPECT_EQ(not original_value, config.get_enable_mount_manager());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(not original_value, config.get_enable_mount_manager());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
TEST_F(config_test, event_level) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_event_level(event_level::debug);
 | 
					 | 
				
			||||||
    EXPECT_EQ(event_level::debug, config.get_event_level());
 | 
					 | 
				
			||||||
    config.set_event_level(event_level::warn);
 | 
					 | 
				
			||||||
    EXPECT_EQ(event_level::warn, config.get_event_level());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(event_level::warn, config.get_event_level());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, eviction_delay_mins) {
 | 
					 | 
				
			||||||
  std::uint32_t original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_eviction_delay_mins();
 | 
					 | 
				
			||||||
    config.set_eviction_delay_mins(original_value + 5);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5, config.get_eviction_delay_mins());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5, config.get_eviction_delay_mins());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, eviction_uses_accessed_time) {
 | 
					 | 
				
			||||||
  bool original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_eviction_uses_accessed_time();
 | 
					 | 
				
			||||||
    config.set_eviction_uses_accessed_time(not original_value);
 | 
					 | 
				
			||||||
    EXPECT_EQ(not original_value, config.get_eviction_uses_accessed_time());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(not original_value, config.get_eviction_uses_accessed_time());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, high_frequency_interval_secs) {
 | 
					 | 
				
			||||||
  std::uint16_t original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_high_frequency_interval_secs();
 | 
					 | 
				
			||||||
    config.set_high_frequency_interval_secs(original_value + 5U);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5U, config.get_high_frequency_interval_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5U, config.get_high_frequency_interval_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, low_frequency_interval_secs) {
 | 
					 | 
				
			||||||
  std::uint16_t original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_low_frequency_interval_secs();
 | 
					 | 
				
			||||||
    config.set_low_frequency_interval_secs(original_value + 5U);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5U, config.get_low_frequency_interval_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5U, config.get_low_frequency_interval_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, med_frequency_interval_secs) {
 | 
					 | 
				
			||||||
  std::uint16_t original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_med_frequency_interval_secs();
 | 
					 | 
				
			||||||
    config.set_med_frequency_interval_secs(original_value + 5U);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5U, config.get_med_frequency_interval_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5U, config.get_med_frequency_interval_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, max_cache_size_bytes) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_max_cache_size_bytes(100 * 1024 * 1024);
 | 
					 | 
				
			||||||
    EXPECT_EQ(100U * 1024 * 1024, config.get_max_cache_size_bytes());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(100U * 1024 * 1024, config.get_max_cache_size_bytes());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, max_upload_count) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_max_upload_count(8U);
 | 
					 | 
				
			||||||
    EXPECT_EQ(std::uint8_t(8U), config.get_max_upload_count());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(std::uint8_t(8U), config.get_max_upload_count());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_max_upload_count(0U);
 | 
					 | 
				
			||||||
    EXPECT_EQ(std::uint8_t(1U), config.get_max_upload_count());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, online_check_retry_secs) {
 | 
					 | 
				
			||||||
  std::uint16_t original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_online_check_retry_secs();
 | 
					 | 
				
			||||||
    config.set_online_check_retry_secs(original_value + 1);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 1, config.get_online_check_retry_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 1, config.get_online_check_retry_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, online_check_retry_secs_minimum_value) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_online_check_retry_secs(14);
 | 
					 | 
				
			||||||
    EXPECT_EQ(15, config.get_online_check_retry_secs());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, orphaned_file_retention_days) {
 | 
					 | 
				
			||||||
  std::uint16_t original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_orphaned_file_retention_days();
 | 
					 | 
				
			||||||
    config.set_orphaned_file_retention_days(original_value + 1);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 1, config.get_orphaned_file_retention_days());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 1, config.get_orphaned_file_retention_days());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, orphaned_file_retention_days_minimum_value) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_orphaned_file_retention_days(0);
 | 
					 | 
				
			||||||
    EXPECT_EQ(1, config.get_orphaned_file_retention_days());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, orphaned_file_retention_days_maximum_value) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_orphaned_file_retention_days(32);
 | 
					 | 
				
			||||||
    EXPECT_EQ(31, config.get_orphaned_file_retention_days());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, get_cache_directory) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_STREQ(utils::path::combine(sia_directory, {"cache"}).c_str(),
 | 
					 | 
				
			||||||
                 config.get_cache_directory().c_str());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, get_config_file_path) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    const auto config_file = utils::path::absolute(
 | 
					 | 
				
			||||||
        utils::path::combine(sia_directory, {"config.json"}));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_STREQ(config_file.c_str(), config.get_config_file_path().c_str());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, get_data_directory) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_STREQ(sia_directory.c_str(), config.get_data_directory().c_str());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, get_log_directory) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_STREQ(utils::path::combine(sia_directory, {"logs"}).c_str(),
 | 
					 | 
				
			||||||
                 config.get_log_directory().c_str());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, ring_buffer_file_size) {
 | 
					 | 
				
			||||||
  std::uint16_t original_value;
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_ring_buffer_file_size();
 | 
					 | 
				
			||||||
    config.set_ring_buffer_file_size(original_value + 5u);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5u, config.get_ring_buffer_file_size());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 5u, config.get_ring_buffer_file_size());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, ring_buffer_file_size_minimum_size) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_ring_buffer_file_size(63u);
 | 
					 | 
				
			||||||
    EXPECT_EQ(64u, config.get_ring_buffer_file_size());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(64u, config.get_ring_buffer_file_size());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, ring_buffer_file_size_maximum_size) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_ring_buffer_file_size(1025u);
 | 
					 | 
				
			||||||
    EXPECT_EQ(1024u, config.get_ring_buffer_file_size());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(1024u, config.get_ring_buffer_file_size());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, preferred_download_type) {
 | 
					 | 
				
			||||||
  download_type original_value;
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_preferred_download_type();
 | 
					 | 
				
			||||||
    config.set_preferred_download_type(download_type::ring_buffer);
 | 
					 | 
				
			||||||
    EXPECT_NE(original_value, config.get_preferred_download_type());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_NE(original_value, config.get_preferred_download_type());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, default_agent_name) {
 | 
					 | 
				
			||||||
  EXPECT_STREQ("Sia-Agent",
 | 
					 | 
				
			||||||
               app_config::default_agent_name(provider_type::sia).c_str());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, default_api_port) {
 | 
					 | 
				
			||||||
  EXPECT_EQ(9980U, app_config::default_api_port(provider_type::sia));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, default_data_directory) {
 | 
					 | 
				
			||||||
  const std::array<std::string, 1U> data_directory = {
 | 
					 | 
				
			||||||
      app_config::default_data_directory(provider_type::sia),
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(_WIN32)
 | 
					 | 
				
			||||||
  const auto local_app_data = utils::get_environment_variable("localappdata");
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#if defined(__linux__)
 | 
					 | 
				
			||||||
  const auto local_app_data =
 | 
					 | 
				
			||||||
      utils::path::combine(utils::get_environment_variable("HOME"), {".local"});
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#if defined(__APPLE__)
 | 
					 | 
				
			||||||
  const auto local_app_data = utils::path::combine(
 | 
					 | 
				
			||||||
      utils::get_environment_variable("HOME"), {"Library/Application Support"});
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  auto expected_directory =
 | 
					 | 
				
			||||||
      utils::path::combine(local_app_data, {"/repertory2/sia"});
 | 
					 | 
				
			||||||
  EXPECT_STREQ(expected_directory.c_str(), data_directory[0].c_str());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, default_rpc_port) {
 | 
					 | 
				
			||||||
  EXPECT_EQ(10000U, app_config::default_rpc_port(provider_type::sia));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, get_provider_display_name) {
 | 
					 | 
				
			||||||
  EXPECT_STREQ(
 | 
					 | 
				
			||||||
      "Sia", app_config::get_provider_display_name(provider_type::sia).c_str());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, get_provider_name) {
 | 
					 | 
				
			||||||
  EXPECT_STREQ("sia",
 | 
					 | 
				
			||||||
               app_config::get_provider_name(provider_type::sia).c_str());
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, get_version) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(REPERTORY_CONFIG_VERSION, config.get_version());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, enable_remote_mount) {
 | 
					 | 
				
			||||||
//   bool original_value{};
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     original_value = config.get_enable_remote_mount();
 | 
					 | 
				
			||||||
//     config.set_enable_remote_mount(not original_value);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(not original_value, config.get_enable_remote_mount());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(not original_value, config.get_enable_remote_mount());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, is_remote_mount) {
 | 
					 | 
				
			||||||
//   bool original_value{};
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     original_value = config.get_is_remote_mount();
 | 
					 | 
				
			||||||
//     config.set_is_remote_mount(not original_value);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(not original_value, config.get_is_remote_mount());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(not original_value, config.get_is_remote_mount());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, enable_remote_mount_fails_if_remote_mount_is_true) {
 | 
					 | 
				
			||||||
//   app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//   config.set_is_remote_mount(true);
 | 
					 | 
				
			||||||
//   config.set_enable_remote_mount(true);
 | 
					 | 
				
			||||||
//   EXPECT_FALSE(config.get_enable_remote_mount());
 | 
					 | 
				
			||||||
//   EXPECT_TRUE(config.get_is_remote_mount());
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, set_is_remote_mount_fails_if_enable_remote_mount_is_true)
 | 
					 | 
				
			||||||
// {
 | 
					 | 
				
			||||||
//   app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//   config.set_enable_remote_mount(true);
 | 
					 | 
				
			||||||
//   config.set_is_remote_mount(true);
 | 
					 | 
				
			||||||
//   EXPECT_FALSE(config.get_is_remote_mount());
 | 
					 | 
				
			||||||
//   EXPECT_TRUE(config.get_enable_remote_mount());
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, remote_host_name_or_ip) {
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     config.set_remote_host_name_or_ip("my.host.name");
 | 
					 | 
				
			||||||
//     EXPECT_STREQ("my.host.name",
 | 
					 | 
				
			||||||
//     config.get_remote_host_name_or_ip().c_str());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_STREQ("my.host.name",
 | 
					 | 
				
			||||||
//     config.get_remote_host_name_or_ip().c_str());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, remote_api_port) {
 | 
					 | 
				
			||||||
//   std::uint16_t original_value{};
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     original_value = config.get_remote_api_port();
 | 
					 | 
				
			||||||
//     config.set_remote_api_port(original_value + 5);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(original_value + 5, config.get_remote_api_port());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(original_value + 5, config.get_remote_api_port());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, remote_receive_timeout_secs) {
 | 
					 | 
				
			||||||
//   std::uint16_t original_value{};
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     original_value = config.get_remote_receive_timeout_secs();
 | 
					 | 
				
			||||||
//     config.set_remote_receive_timeout_secs(original_value + 5);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(original_value + 5, config.get_remote_receive_timeout_secs());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(original_value + 5, config.get_remote_receive_timeout_secs());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, remote_send_timeout_secs) {
 | 
					 | 
				
			||||||
//   std::uint16_t original_value{};
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     original_value = config.get_remote_send_timeout_secs();
 | 
					 | 
				
			||||||
//     config.set_remote_send_timeout_secs(original_value + 5);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, remote_encryption_token) {
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     config.set_remote_encryption_token("myToken");
 | 
					 | 
				
			||||||
//     EXPECT_STREQ("myToken", config.get_remote_encryption_token().c_str());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_STREQ("myToken", config.get_remote_encryption_token().c_str());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// TEST_F(config_test, remote_client_pool_size) {
 | 
					 | 
				
			||||||
//   std::uint8_t original_value{};
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     original_value = config.get_remote_client_pool_size();
 | 
					 | 
				
			||||||
//     config.set_remote_client_pool_size(original_value + 5);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(original_value + 5, config.get_remote_client_pool_size());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(original_value + 5, config.get_remote_client_pool_size());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// TEST_F(config_test, remote_client_pool_size_minimum_value) {
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     config.set_remote_client_pool_size(0);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(5, config.get_remote_client_pool_size());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(5, config.get_remote_client_pool_size());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, remote_max_connections) {
 | 
					 | 
				
			||||||
//   std::uint8_t original_value{};
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     original_value = config.get_remote_max_connections();
 | 
					 | 
				
			||||||
//     config.set_remote_max_connections(original_value + 5);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(original_value + 5, config.get_remote_max_connections());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(original_value + 5, config.get_remote_max_connections());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TEST_F(config_test, remote_max_connections_minimum_value) {
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     config.set_remote_max_connections(0);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(1, config.get_remote_max_connections());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
//   {
 | 
					 | 
				
			||||||
//     app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
//     EXPECT_EQ(1, config.get_remote_max_connections());
 | 
					 | 
				
			||||||
//   }
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, retry_read_count) {
 | 
					 | 
				
			||||||
  std::uint16_t original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_retry_read_count();
 | 
					 | 
				
			||||||
    config.set_retry_read_count(original_value + 1);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 1, config.get_retry_read_count());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 1, config.get_retry_read_count());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, retry_read_count_minimum_value) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_retry_read_count(1);
 | 
					 | 
				
			||||||
    EXPECT_EQ(2, config.get_retry_read_count());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, task_wait_ms) {
 | 
					 | 
				
			||||||
  std::uint16_t original_value{};
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    original_value = config.get_task_wait_ms();
 | 
					 | 
				
			||||||
    config.set_task_wait_ms(original_value + 1U);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 1U, config.get_task_wait_ms());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    EXPECT_EQ(original_value + 1U, config.get_task_wait_ms());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, task_wait_ms_minimum_value) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_task_wait_ms(1U);
 | 
					 | 
				
			||||||
    EXPECT_EQ(50U, config.get_task_wait_ms());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TEST_F(config_test, can_set_database_type) {
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    app_config config(provider_type::sia, sia_directory);
 | 
					 | 
				
			||||||
    config.set_database_type(database_type::rocksdb);
 | 
					 | 
				
			||||||
    EXPECT_EQ(database_type::rocksdb, config.get_database_type());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    config.set_database_type(database_type::sqlite);
 | 
					 | 
				
			||||||
    EXPECT_EQ(database_type::sqlite, config.get_database_type());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    config.set_database_type(database_type::rocksdb);
 | 
					 | 
				
			||||||
    EXPECT_EQ(database_type::rocksdb, config.get_database_type());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
} // namespace repertory
 | 
					 | 
				
			||||||
@@ -25,7 +25,7 @@
 | 
				
			|||||||
#include "types/repertory.hpp"
 | 
					#include "types/repertory.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
TEST(curl_comm, can_create_s3_host_config) {
 | 
					TEST(curl_comm_test, can_create_s3_host_config) {
 | 
				
			||||||
  s3_config config{};
 | 
					  s3_config config{};
 | 
				
			||||||
  config.bucket = "repertory";
 | 
					  config.bucket = "repertory";
 | 
				
			||||||
  config.url = "https://s3.test.com";
 | 
					  config.url = "https://s3.test.com";
 | 
				
			||||||
@@ -37,7 +37,7 @@ TEST(curl_comm, can_create_s3_host_config) {
 | 
				
			|||||||
  EXPECT_TRUE(hc.path.empty());
 | 
					  EXPECT_TRUE(hc.path.empty());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(curl_comm, can_create_s3_host_config_with_path_style) {
 | 
					TEST(curl_comm_test, can_create_s3_host_config_with_path_style) {
 | 
				
			||||||
  s3_config config{};
 | 
					  s3_config config{};
 | 
				
			||||||
  config.bucket = "repertory";
 | 
					  config.bucket = "repertory";
 | 
				
			||||||
  config.url = "https://s3.test.com";
 | 
					  config.url = "https://s3.test.com";
 | 
				
			||||||
@@ -49,7 +49,7 @@ TEST(curl_comm, can_create_s3_host_config_with_path_style) {
 | 
				
			|||||||
  EXPECT_STREQ("/repertory", hc.path.c_str());
 | 
					  EXPECT_STREQ("/repertory", hc.path.c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(curl_comm, can_create_s3_host_config_with_region) {
 | 
					TEST(curl_comm_test, can_create_s3_host_config_with_region) {
 | 
				
			||||||
  s3_config config{};
 | 
					  s3_config config{};
 | 
				
			||||||
  config.bucket = "repertory";
 | 
					  config.bucket = "repertory";
 | 
				
			||||||
  config.url = "https://s3.test.com";
 | 
					  config.url = "https://s3.test.com";
 | 
				
			||||||
@@ -62,7 +62,7 @@ TEST(curl_comm, can_create_s3_host_config_with_region) {
 | 
				
			|||||||
  EXPECT_TRUE(hc.path.empty());
 | 
					  EXPECT_TRUE(hc.path.empty());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(curl_comm, can_create_s3_host_config_with_region_and_path_style) {
 | 
					TEST(curl_comm_test, can_create_s3_host_config_with_region_and_path_style) {
 | 
				
			||||||
  s3_config config{};
 | 
					  s3_config config{};
 | 
				
			||||||
  config.bucket = "repertory";
 | 
					  config.bucket = "repertory";
 | 
				
			||||||
  config.url = "https://s3.test.com";
 | 
					  config.url = "https://s3.test.com";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,7 @@
 | 
				
			|||||||
#include "types/repertory.hpp"
 | 
					#include "types/repertory.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
TEST(json_serialize, can_handle_directory_item) {
 | 
					TEST(json_serialize_test, can_handle_directory_item) {
 | 
				
			||||||
  directory_item cfg{
 | 
					  directory_item cfg{
 | 
				
			||||||
      "api", "parent", true, 2U, {{META_DIRECTORY, "true"}},
 | 
					      "api", "parent", true, 2U, {{META_DIRECTORY, "true"}},
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@@ -47,7 +47,7 @@ TEST(json_serialize, can_handle_directory_item) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_encrypt_config) {
 | 
					TEST(json_serialize_test, can_handle_encrypt_config) {
 | 
				
			||||||
  encrypt_config cfg{
 | 
					  encrypt_config cfg{
 | 
				
			||||||
      "token",
 | 
					      "token",
 | 
				
			||||||
      "path",
 | 
					      "path",
 | 
				
			||||||
@@ -65,7 +65,7 @@ TEST(json_serialize, can_handle_encrypt_config) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_host_config) {
 | 
					TEST(json_serialize_test, can_handle_host_config) {
 | 
				
			||||||
  host_config cfg{
 | 
					  host_config cfg{
 | 
				
			||||||
      "agent", "pwd", "user", 1024U, "host", "path", "http", 11U,
 | 
					      "agent", "pwd", "user", 1024U, "host", "path", "http", 11U,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@@ -94,7 +94,7 @@ TEST(json_serialize, can_handle_host_config) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_remote_config) {
 | 
					TEST(json_serialize_test, can_handle_remote_config) {
 | 
				
			||||||
  remote::remote_config cfg{
 | 
					  remote::remote_config cfg{
 | 
				
			||||||
      1024U, "token", "host", 11U, 20U, 21U,
 | 
					      1024U, "token", "host", 11U, 20U, 21U,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@@ -120,7 +120,7 @@ TEST(json_serialize, can_handle_remote_config) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_remote_mount) {
 | 
					TEST(json_serialize_test, can_handle_remote_mount) {
 | 
				
			||||||
  remote::remote_mount cfg{1024U, 21U, true, "token"};
 | 
					  remote::remote_mount cfg{1024U, 21U, true, "token"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  json data(cfg);
 | 
					  json data(cfg);
 | 
				
			||||||
@@ -139,7 +139,7 @@ TEST(json_serialize, can_handle_remote_mount) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_s3_config) {
 | 
					TEST(json_serialize_test, can_handle_s3_config) {
 | 
				
			||||||
  s3_config cfg{
 | 
					  s3_config cfg{
 | 
				
			||||||
      "access", "bucket", "token", "region", "secret", 31U, "url", true, false,
 | 
					      "access", "bucket", "token", "region", "secret", 31U, "url", true, false,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@@ -170,7 +170,7 @@ TEST(json_serialize, can_handle_s3_config) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_sia_config) {
 | 
					TEST(json_serialize_test, can_handle_sia_config) {
 | 
				
			||||||
  sia_config cfg{
 | 
					  sia_config cfg{
 | 
				
			||||||
      "bucket",
 | 
					      "bucket",
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@@ -184,7 +184,7 @@ TEST(json_serialize, can_handle_sia_config) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_atomic) {
 | 
					TEST(json_serialize_test, can_handle_atomic) {
 | 
				
			||||||
  atomic<sia_config> cfg({
 | 
					  atomic<sia_config> cfg({
 | 
				
			||||||
      "bucket",
 | 
					      "bucket",
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
@@ -198,7 +198,7 @@ TEST(json_serialize, can_handle_atomic) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_database_type) {
 | 
					TEST(json_serialize_test, can_handle_database_type) {
 | 
				
			||||||
  json data(database_type::rocksdb);
 | 
					  json data(database_type::rocksdb);
 | 
				
			||||||
  EXPECT_EQ(database_type::rocksdb, data.get<database_type>());
 | 
					  EXPECT_EQ(database_type::rocksdb, data.get<database_type>());
 | 
				
			||||||
  EXPECT_STREQ("rocksdb", data.get<std::string>().c_str());
 | 
					  EXPECT_STREQ("rocksdb", data.get<std::string>().c_str());
 | 
				
			||||||
@@ -208,7 +208,7 @@ TEST(json_serialize, can_handle_database_type) {
 | 
				
			|||||||
  EXPECT_STREQ("sqlite", data.get<std::string>().c_str());
 | 
					  EXPECT_STREQ("sqlite", data.get<std::string>().c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_download_type) {
 | 
					TEST(json_serialize_test, can_handle_download_type) {
 | 
				
			||||||
  json data(download_type::direct);
 | 
					  json data(download_type::direct);
 | 
				
			||||||
  EXPECT_EQ(download_type::direct, data.get<download_type>());
 | 
					  EXPECT_EQ(download_type::direct, data.get<download_type>());
 | 
				
			||||||
  EXPECT_STREQ("direct", data.get<std::string>().c_str());
 | 
					  EXPECT_STREQ("direct", data.get<std::string>().c_str());
 | 
				
			||||||
@@ -222,7 +222,33 @@ TEST(json_serialize, can_handle_download_type) {
 | 
				
			|||||||
  EXPECT_STREQ("ring_buffer", data.get<std::string>().c_str());
 | 
					  EXPECT_STREQ("ring_buffer", data.get<std::string>().c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_atomic_database_type) {
 | 
					TEST(json_serialize_test, can_handle_event_level) {
 | 
				
			||||||
 | 
					  json data(event_level{event_level::critical});
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::critical, data.get<event_level>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("critical", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = event_level(event_level::error);
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::error, data.get<event_level>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("error", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = event_level(event_level::warn);
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::warn, data.get<event_level>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("warn", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = event_level(event_level::info);
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::info, data.get<event_level>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("info", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = event_level(event_level::debug);
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::debug, data.get<event_level>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("debug", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = event_level(event_level::trace);
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::trace, data.get<event_level>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("trace", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(json_serialize_test, can_handle_atomic_database_type) {
 | 
				
			||||||
  json data(atomic<database_type>{database_type::rocksdb});
 | 
					  json data(atomic<database_type>{database_type::rocksdb});
 | 
				
			||||||
  EXPECT_EQ(database_type::rocksdb, data.get<atomic<database_type>>());
 | 
					  EXPECT_EQ(database_type::rocksdb, data.get<atomic<database_type>>());
 | 
				
			||||||
  EXPECT_STREQ("rocksdb", data.get<std::string>().c_str());
 | 
					  EXPECT_STREQ("rocksdb", data.get<std::string>().c_str());
 | 
				
			||||||
@@ -232,7 +258,7 @@ TEST(json_serialize, can_handle_atomic_database_type) {
 | 
				
			|||||||
  EXPECT_STREQ("sqlite", data.get<std::string>().c_str());
 | 
					  EXPECT_STREQ("sqlite", data.get<std::string>().c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(json_serialize, can_handle_atomic_download_type) {
 | 
					TEST(json_serialize_test, can_handle_atomic_download_type) {
 | 
				
			||||||
  json data(atomic<download_type>{download_type::direct});
 | 
					  json data(atomic<download_type>{download_type::direct});
 | 
				
			||||||
  EXPECT_EQ(download_type::direct, data.get<atomic<download_type>>());
 | 
					  EXPECT_EQ(download_type::direct, data.get<atomic<download_type>>());
 | 
				
			||||||
  EXPECT_STREQ("direct", data.get<std::string>().c_str());
 | 
					  EXPECT_STREQ("direct", data.get<std::string>().c_str());
 | 
				
			||||||
@@ -245,4 +271,30 @@ TEST(json_serialize, can_handle_atomic_download_type) {
 | 
				
			|||||||
  EXPECT_EQ(download_type::ring_buffer, data.get<atomic<download_type>>());
 | 
					  EXPECT_EQ(download_type::ring_buffer, data.get<atomic<download_type>>());
 | 
				
			||||||
  EXPECT_STREQ("ring_buffer", data.get<std::string>().c_str());
 | 
					  EXPECT_STREQ("ring_buffer", data.get<std::string>().c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(json_serialize_test, can_handle_atomic_event_level) {
 | 
				
			||||||
 | 
					  json data(atomic<event_level>{event_level::critical});
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::critical, data.get<atomic<event_level>>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("critical", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = atomic<event_level>(event_level::error);
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::error, data.get<atomic<event_level>>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("error", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = atomic<event_level>(event_level::warn);
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::warn, data.get<atomic<event_level>>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("warn", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = atomic<event_level>(event_level::info);
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::info, data.get<atomic<event_level>>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("info", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = atomic<event_level>(event_level::debug);
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::debug, data.get<atomic<event_level>>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("debug", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data = atomic<event_level>(event_level::trace);
 | 
				
			||||||
 | 
					  EXPECT_EQ(event_level::trace, data.get<atomic<event_level>>());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("trace", data.get<std::string>().c_str());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
} // namespace repertory
 | 
					} // namespace repertory
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@
 | 
				
			|||||||
#include "platform/platform.hpp"
 | 
					#include "platform/platform.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
TEST(lock_data, lock_and_unlock) {
 | 
					TEST(lock_data_test, lock_and_unlock) {
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    lock_data l(provider_type::sia, "1");
 | 
					    lock_data l(provider_type::sia, "1");
 | 
				
			||||||
    EXPECT_EQ(lock_result::success, l.grab_lock());
 | 
					    EXPECT_EQ(lock_result::success, l.grab_lock());
 | 
				
			||||||
@@ -50,7 +50,7 @@ TEST(lock_data, lock_and_unlock) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(_WIN32)
 | 
					#if defined(_WIN32)
 | 
				
			||||||
TEST(lock_data, set_and_unset_mount_state) {
 | 
					TEST(lock_data_test, set_and_unset_mount_state) {
 | 
				
			||||||
  lock_data l(provider_type::sia, "1");
 | 
					  lock_data l(provider_type::sia, "1");
 | 
				
			||||||
  EXPECT_TRUE(l.set_mount_state(true, "C:", 99));
 | 
					  EXPECT_TRUE(l.set_mount_state(true, "C:", 99));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -83,7 +83,7 @@ TEST(lock_data, set_and_unset_mount_state) {
 | 
				
			|||||||
               mount_state["Remote2"].dump().c_str());
 | 
					               mount_state["Remote2"].dump().c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
TEST(lock_data, set_and_unset_mount_state) {
 | 
					TEST(lock_data_test, set_and_unset_mount_state) {
 | 
				
			||||||
  lock_data l(provider_type::sia, "1");
 | 
					  lock_data l(provider_type::sia, "1");
 | 
				
			||||||
  EXPECT_TRUE(l.set_mount_state(true, "/mnt/1", 99));
 | 
					  EXPECT_TRUE(l.set_mount_state(true, "/mnt/1", 99));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@
 | 
				
			|||||||
#include "comm/packet/packet.hpp"
 | 
					#include "comm/packet/packet.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
TEST(packet, encrypt_and_decrypt) {
 | 
					TEST(packet_test, encrypt_and_decrypt) {
 | 
				
			||||||
  packet test_packet;
 | 
					  packet test_packet;
 | 
				
			||||||
  test_packet.encode("test");
 | 
					  test_packet.encode("test");
 | 
				
			||||||
  test_packet.encrypt("moose");
 | 
					  test_packet.encrypt("moose");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,8 +19,6 @@
 | 
				
			|||||||
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
					  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
  SOFTWARE.
 | 
					  SOFTWARE.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "test_common.hpp"
 | 
					#include "test_common.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "comm/curl/curl_comm.hpp"
 | 
					#include "comm/curl/curl_comm.hpp"
 | 
				
			||||||
@@ -99,8 +97,6 @@ const auto create_directory = [](repertory::i_provider &provider,
 | 
				
			|||||||
      repertory::utils::string::to_bool(meta2[repertory::META_PINNED]));
 | 
					      repertory::utils::string::to_bool(meta2[repertory::META_PINNED]));
 | 
				
			||||||
  EXPECT_EQ(std::uint64_t(0U),
 | 
					  EXPECT_EQ(std::uint64_t(0U),
 | 
				
			||||||
            repertory::utils::string::to_uint64(meta2[repertory::META_SIZE]));
 | 
					            repertory::utils::string::to_uint64(meta2[repertory::META_SIZE]));
 | 
				
			||||||
  EXPECT_STREQ((api_path + "_src").c_str(),
 | 
					 | 
				
			||||||
               meta2[repertory::META_SOURCE].c_str());
 | 
					 | 
				
			||||||
  EXPECT_EQ(getuid(), static_cast<uid_t>(repertory::utils::string::to_uint32(
 | 
					  EXPECT_EQ(getuid(), static_cast<uid_t>(repertory::utils::string::to_uint32(
 | 
				
			||||||
                          meta2[repertory::META_UID])));
 | 
					                          meta2[repertory::META_UID])));
 | 
				
			||||||
  EXPECT_EQ(date + 4U, repertory::utils::string::to_uint64(
 | 
					  EXPECT_EQ(date + 4U, repertory::utils::string::to_uint64(
 | 
				
			||||||
@@ -178,6 +174,9 @@ const auto decrypt_parts = [](const repertory::app_config &cfg,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
static void can_create_and_remove_directory(i_provider &provider) {
 | 
					static void can_create_and_remove_directory(i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.is_read_only()) {
 | 
					  if (provider.is_read_only()) {
 | 
				
			||||||
    api_meta_map meta{};
 | 
					    api_meta_map meta{};
 | 
				
			||||||
    EXPECT_EQ(api_error::not_implemented,
 | 
					    EXPECT_EQ(api_error::not_implemented,
 | 
				
			||||||
@@ -196,6 +195,9 @@ static void can_create_and_remove_directory(i_provider &provider) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void create_directory_fails_if_already_exists(i_provider &provider) {
 | 
					static void create_directory_fails_if_already_exists(i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.is_read_only()) {
 | 
					  if (provider.is_read_only()) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -210,6 +212,9 @@ static void create_directory_fails_if_already_exists(i_provider &provider) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
create_directory_fails_if_file_already_exists(i_provider &provider) {
 | 
					create_directory_fails_if_file_already_exists(i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.is_read_only()) {
 | 
					  if (provider.is_read_only()) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -223,6 +228,9 @@ create_directory_fails_if_file_already_exists(i_provider &provider) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void create_directory_clone_source_meta(i_provider &provider) {
 | 
					static void create_directory_clone_source_meta(i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.is_read_only()) {
 | 
					  if (provider.is_read_only()) {
 | 
				
			||||||
    EXPECT_EQ(api_error::not_implemented,
 | 
					    EXPECT_EQ(api_error::not_implemented,
 | 
				
			||||||
              provider.create_directory_clone_source_meta("/moose", "/moose"));
 | 
					              provider.create_directory_clone_source_meta("/moose", "/moose"));
 | 
				
			||||||
@@ -257,6 +265,9 @@ static void create_directory_clone_source_meta(i_provider &provider) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void create_directory_clone_source_meta_fails_if_already_exists(
 | 
					static void create_directory_clone_source_meta_fails_if_already_exists(
 | 
				
			||||||
    i_provider &provider) {
 | 
					    i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.is_read_only()) {
 | 
					  if (provider.is_read_only()) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -272,6 +283,9 @@ static void create_directory_clone_source_meta_fails_if_already_exists(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void create_directory_clone_source_meta_fails_if_directory_not_found(
 | 
					static void create_directory_clone_source_meta_fails_if_directory_not_found(
 | 
				
			||||||
    i_provider &provider) {
 | 
					    i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.is_read_only()) {
 | 
					  if (provider.is_read_only()) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -282,6 +296,9 @@ static void create_directory_clone_source_meta_fails_if_directory_not_found(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void create_directory_clone_source_meta_fails_if_file_already_exists(
 | 
					static void create_directory_clone_source_meta_fails_if_file_already_exists(
 | 
				
			||||||
    i_provider &provider) {
 | 
					    i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.is_read_only()) {
 | 
					  if (provider.is_read_only()) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -297,6 +314,9 @@ static void create_directory_clone_source_meta_fails_if_file_already_exists(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void can_create_and_remove_file(i_provider &provider) {
 | 
					static void can_create_and_remove_file(i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.is_read_only()) {
 | 
					  if (provider.is_read_only()) {
 | 
				
			||||||
    api_meta_map meta{};
 | 
					    api_meta_map meta{};
 | 
				
			||||||
    EXPECT_EQ(api_error::not_implemented,
 | 
					    EXPECT_EQ(api_error::not_implemented,
 | 
				
			||||||
@@ -317,6 +337,9 @@ static void can_create_and_remove_file(i_provider &provider) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void create_file_fails_if_already_exists(i_provider &provider) {
 | 
					static void create_file_fails_if_already_exists(i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.is_read_only()) {
 | 
					  if (provider.is_read_only()) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -331,6 +354,9 @@ static void create_file_fails_if_already_exists(i_provider &provider) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
create_file_fails_if_directory_already_exists(i_provider &provider) {
 | 
					create_file_fails_if_directory_already_exists(i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.is_read_only()) {
 | 
					  if (provider.is_read_only()) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -345,9 +371,12 @@ create_file_fails_if_directory_already_exists(i_provider &provider) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void get_api_path_from_source(const app_config &cfg,
 | 
					static void get_api_path_from_source(const app_config &cfg,
 | 
				
			||||||
                                     i_provider &provider) {
 | 
					                                     i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
					  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
				
			||||||
    const auto source_path =
 | 
					    auto source_path =
 | 
				
			||||||
        utils::path::combine("./test_date/encrypt", {"test.txt"});
 | 
					        utils::path::combine("./test_input/encrypt", {"test.txt"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string api_path{};
 | 
					    std::string api_path{};
 | 
				
			||||||
    EXPECT_EQ(api_error::success,
 | 
					    EXPECT_EQ(api_error::success,
 | 
				
			||||||
@@ -376,6 +405,9 @@ static void get_api_path_from_source(const app_config &cfg,
 | 
				
			|||||||
static void
 | 
					static void
 | 
				
			||||||
get_api_path_from_source_fails_if_file_not_found(const app_config &cfg,
 | 
					get_api_path_from_source_fails_if_file_not_found(const app_config &cfg,
 | 
				
			||||||
                                                 i_provider &provider) {
 | 
					                                                 i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  std::string source_path{};
 | 
					  std::string source_path{};
 | 
				
			||||||
  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
					  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
				
			||||||
    source_path = utils::path::combine(cfg.get_encrypt_config().path,
 | 
					    source_path = utils::path::combine(cfg.get_encrypt_config().path,
 | 
				
			||||||
@@ -391,28 +423,50 @@ get_api_path_from_source_fails_if_file_not_found(const app_config &cfg,
 | 
				
			|||||||
  EXPECT_TRUE(api_path.empty());
 | 
					  EXPECT_TRUE(api_path.empty());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void get_directory_item_count(const app_config &cfg,
 | 
					static void get_directory_item_count(const app_config & /* cfg */,
 | 
				
			||||||
                                     i_provider &provider) {
 | 
					                                     i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
					  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
				
			||||||
    EXPECT_EQ(std::size_t(2U), provider.get_directory_item_count("/"));
 | 
					    EXPECT_EQ(std::size_t(2U), provider.get_directory_item_count("/"));
 | 
				
			||||||
    EXPECT_EQ(std::size_t(0U), provider.get_directory_item_count("/not_found"));
 | 
					    EXPECT_EQ(std::size_t(0U), provider.get_directory_item_count("/not_found"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const auto source_path =
 | 
					    auto source_path =
 | 
				
			||||||
        utils::path::combine(test::get_test_input_dir(), {"encrypt", "sub10"});
 | 
					        utils::path::combine(test::get_test_input_dir(), {"encrypt", "sub10"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string api_path{};
 | 
					    std::string api_path{};
 | 
				
			||||||
    EXPECT_EQ(api_error::success,
 | 
					    EXPECT_EQ(api_error::success,
 | 
				
			||||||
              provider.get_api_path_from_source(source_path, api_path));
 | 
					              provider.get_api_path_from_source(source_path, api_path));
 | 
				
			||||||
    EXPECT_EQ(std::size_t(1U), provider.get_directory_item_count(api_path));
 | 
					    EXPECT_EQ(std::size_t(1U), provider.get_directory_item_count(api_path));
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void get_directory_items(const app_config &cfg, i_provider &provider) {
 | 
					  create_file(provider, "/pt01.txt");
 | 
				
			||||||
 | 
					  create_file(provider, "/pt02.txt");
 | 
				
			||||||
 | 
					  create_directory(provider, "/dir01");
 | 
				
			||||||
 | 
					  create_directory(provider, "/dir02");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  directory_item_list list{};
 | 
					  directory_item_list list{};
 | 
				
			||||||
  EXPECT_EQ(api_error::success, provider.get_directory_items("/", list));
 | 
					  EXPECT_EQ(api_error::success, provider.get_directory_items("/", list));
 | 
				
			||||||
  check_forced_dirs(list);
 | 
					  check_forced_dirs(list);
 | 
				
			||||||
 | 
					  EXPECT_GE(list.size(), std::size_t(6U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_file("/pt02.txt"));
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_directory("/dir01"));
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_directory("/dir02"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void get_directory_items(const app_config &cfg, i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
					  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
				
			||||||
 | 
					    directory_item_list list{};
 | 
				
			||||||
 | 
					    EXPECT_EQ(api_error::success, provider.get_directory_items("/", list));
 | 
				
			||||||
 | 
					    check_forced_dirs(list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    EXPECT_EQ(std::size_t(4U), list.size());
 | 
					    EXPECT_EQ(std::size_t(4U), list.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    directory_item_list list_decrypted{list.begin() + 2U, list.end()};
 | 
					    directory_item_list list_decrypted{list.begin() + 2U, list.end()};
 | 
				
			||||||
@@ -443,7 +497,7 @@ static void get_directory_items(const app_config &cfg, i_provider &provider) {
 | 
				
			|||||||
    EXPECT_EQ(std::size_t(46U), file->size);
 | 
					    EXPECT_EQ(std::size_t(46U), file->size);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const auto source_path =
 | 
					    auto source_path =
 | 
				
			||||||
        utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
 | 
					        utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
 | 
				
			||||||
    std::string api_path{};
 | 
					    std::string api_path{};
 | 
				
			||||||
    EXPECT_EQ(api_error::success,
 | 
					    EXPECT_EQ(api_error::success,
 | 
				
			||||||
@@ -472,11 +526,58 @@ static void get_directory_items(const app_config &cfg, i_provider &provider) {
 | 
				
			|||||||
#else
 | 
					#else
 | 
				
			||||||
    EXPECT_EQ(std::size_t(45U), file2->size);
 | 
					    EXPECT_EQ(std::size_t(45U), file2->size);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  create_file(provider, "/pt01.txt");
 | 
				
			||||||
 | 
					  create_file(provider, "/pt02.txt");
 | 
				
			||||||
 | 
					  create_directory(provider, "/dir01");
 | 
				
			||||||
 | 
					  create_directory(provider, "/dir02");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  directory_item_list list{};
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.get_directory_items("/", list));
 | 
				
			||||||
 | 
					  check_forced_dirs(list);
 | 
				
			||||||
 | 
					  EXPECT_GE(list.size(), std::size_t(6U));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto iter = std::ranges::find_if(
 | 
				
			||||||
 | 
					      list, [](auto &&item) -> bool { return item.api_path == "/pt01.txt"; });
 | 
				
			||||||
 | 
					  EXPECT_NE(iter, list.end());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("/", (*iter).api_parent.c_str());
 | 
				
			||||||
 | 
					  EXPECT_FALSE((*iter).directory);
 | 
				
			||||||
 | 
					  EXPECT_EQ(std::uint64_t{0U}, (*iter).size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  iter = std::ranges::find_if(
 | 
				
			||||||
 | 
					      list, [](auto &&item) -> bool { return item.api_path == "/pt02.txt"; });
 | 
				
			||||||
 | 
					  EXPECT_NE(iter, list.end());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("/", (*iter).api_parent.c_str());
 | 
				
			||||||
 | 
					  EXPECT_FALSE((*iter).directory);
 | 
				
			||||||
 | 
					  EXPECT_EQ(std::uint64_t{0U}, (*iter).size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  iter = std::ranges::find_if(
 | 
				
			||||||
 | 
					      list, [](auto &&item) -> bool { return item.api_path == "/dir01"; });
 | 
				
			||||||
 | 
					  EXPECT_NE(iter, list.end());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("/", (*iter).api_parent.c_str());
 | 
				
			||||||
 | 
					  EXPECT_TRUE((*iter).directory);
 | 
				
			||||||
 | 
					  EXPECT_EQ(std::uint64_t{0U}, (*iter).size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  iter = std::ranges::find_if(
 | 
				
			||||||
 | 
					      list, [](auto &&item) -> bool { return item.api_path == "/dir02"; });
 | 
				
			||||||
 | 
					  EXPECT_NE(iter, list.end());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("/", (*iter).api_parent.c_str());
 | 
				
			||||||
 | 
					  EXPECT_TRUE((*iter).directory);
 | 
				
			||||||
 | 
					  EXPECT_EQ(std::uint64_t{0U}, (*iter).size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_file("/pt02.txt"));
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_directory("/dir01"));
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_directory("/dir02"));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
get_directory_items_fails_if_directory_not_found(i_provider &provider) {
 | 
					get_directory_items_fails_if_directory_not_found(i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  directory_item_list list{};
 | 
					  directory_item_list list{};
 | 
				
			||||||
  EXPECT_EQ(api_error::directory_not_found,
 | 
					  EXPECT_EQ(api_error::directory_not_found,
 | 
				
			||||||
            provider.get_directory_items("/not_found", list));
 | 
					            provider.get_directory_items("/not_found", list));
 | 
				
			||||||
@@ -485,8 +586,11 @@ get_directory_items_fails_if_directory_not_found(i_provider &provider) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void get_directory_items_fails_if_item_is_file(const app_config &cfg,
 | 
					static void get_directory_items_fails_if_item_is_file(const app_config &cfg,
 | 
				
			||||||
                                                      i_provider &provider) {
 | 
					                                                      i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
					  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
				
			||||||
    const auto source_path =
 | 
					    auto source_path =
 | 
				
			||||||
        utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
 | 
					        utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string api_path{};
 | 
					    std::string api_path{};
 | 
				
			||||||
@@ -497,12 +601,24 @@ static void get_directory_items_fails_if_item_is_file(const app_config &cfg,
 | 
				
			|||||||
    EXPECT_EQ(api_error::item_exists,
 | 
					    EXPECT_EQ(api_error::item_exists,
 | 
				
			||||||
              provider.get_directory_items(api_path, list));
 | 
					              provider.get_directory_items(api_path, list));
 | 
				
			||||||
    EXPECT_TRUE(list.empty());
 | 
					    EXPECT_TRUE(list.empty());
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  create_file(provider, "/pt01.txt");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  directory_item_list list{};
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::item_exists,
 | 
				
			||||||
 | 
					            provider.get_directory_items("/pt01.txt", list));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void get_file(const app_config &cfg, i_provider &provider) {
 | 
					static void get_file(const app_config &cfg, i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
					  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
				
			||||||
    const auto source_path =
 | 
					    auto source_path =
 | 
				
			||||||
        utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
 | 
					        utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string api_path{};
 | 
					    std::string api_path{};
 | 
				
			||||||
@@ -522,18 +638,43 @@ static void get_file(const app_config &cfg, i_provider &provider) {
 | 
				
			|||||||
    EXPECT_EQ(std::size_t(46U), file.file_size);
 | 
					    EXPECT_EQ(std::size_t(46U), file.file_size);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    EXPECT_STREQ(source_path.c_str(), file.source_path.c_str());
 | 
					    EXPECT_STREQ(source_path.c_str(), file.source_path.c_str());
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  create_file(provider, "/pt01.txt");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  api_file file{};
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.get_file("/pt01.txt", file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_STREQ("/pt01.txt", file.api_path.c_str());
 | 
				
			||||||
 | 
					  EXPECT_STREQ("/", file.api_parent.c_str());
 | 
				
			||||||
 | 
					  EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
 | 
				
			||||||
 | 
					            file.accessed_date);
 | 
				
			||||||
 | 
					  EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
 | 
				
			||||||
 | 
					            file.changed_date);
 | 
				
			||||||
 | 
					  EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
 | 
				
			||||||
 | 
					            file.creation_date);
 | 
				
			||||||
 | 
					  EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
 | 
				
			||||||
 | 
					            file.modified_date);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void get_file_fails_if_file_not_found(i_provider &provider) {
 | 
					static void get_file_fails_if_file_not_found(i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  api_file file{};
 | 
					  api_file file{};
 | 
				
			||||||
  EXPECT_EQ(api_error::item_not_found, provider.get_file("/not_found", file));
 | 
					  EXPECT_EQ(api_error::item_not_found, provider.get_file("/not_found", file));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void get_file_fails_if_item_is_directory(const app_config &cfg,
 | 
					static void get_file_fails_if_item_is_directory(const app_config &cfg,
 | 
				
			||||||
                                                i_provider &provider) {
 | 
					                                                i_provider &provider) {
 | 
				
			||||||
 | 
					  fmt::println("testing|{}|{}",
 | 
				
			||||||
 | 
					               app_config::get_provider_name(provider.get_provider_type()),
 | 
				
			||||||
 | 
					               __FUNCTION__);
 | 
				
			||||||
  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
					  if (provider.get_provider_type() == provider_type::encrypt) {
 | 
				
			||||||
    const auto source_path =
 | 
					    auto source_path =
 | 
				
			||||||
        utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
 | 
					        utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string api_path{};
 | 
					    std::string api_path{};
 | 
				
			||||||
@@ -542,7 +683,15 @@ static void get_file_fails_if_item_is_directory(const app_config &cfg,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    api_file file{};
 | 
					    api_file file{};
 | 
				
			||||||
    EXPECT_EQ(api_error::directory_exists, provider.get_file(api_path, file));
 | 
					    EXPECT_EQ(api_error::directory_exists, provider.get_file(api_path, file));
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  create_directory(provider, "/dir01");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  api_file file{};
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::directory_exists, provider.get_file("/dir01", file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_EQ(api_error::success, provider.remove_directory("/dir01"));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void get_file_list(const app_config &cfg, i_provider &provider) {
 | 
					static void get_file_list(const app_config &cfg, i_provider &provider) {
 | 
				
			||||||
@@ -593,7 +742,6 @@ static void run_tests(const app_config &cfg, i_provider &provider) {
 | 
				
			|||||||
  get_api_path_from_source(cfg, provider);
 | 
					  get_api_path_from_source(cfg, provider);
 | 
				
			||||||
  get_api_path_from_source_fails_if_file_not_found(cfg, provider);
 | 
					  get_api_path_from_source_fails_if_file_not_found(cfg, provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO: continue here
 | 
					 | 
				
			||||||
  get_directory_items(cfg, provider);
 | 
					  get_directory_items(cfg, provider);
 | 
				
			||||||
  get_directory_items_fails_if_directory_not_found(provider);
 | 
					  get_directory_items_fails_if_directory_not_found(provider);
 | 
				
			||||||
  get_directory_items_fails_if_item_is_file(cfg, provider);
 | 
					  get_directory_items_fails_if_item_is_file(cfg, provider);
 | 
				
			||||||
@@ -629,17 +777,16 @@ static void run_tests(const app_config &cfg, i_provider &provider) {
 | 
				
			|||||||
  upload_file(provider); */
 | 
					  upload_file(provider); */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(providers, encrypt_provider) {
 | 
					TEST(providers_test, encrypt_provider) {
 | 
				
			||||||
  const auto config_path =
 | 
					  auto config_path = utils::path::combine(test::get_test_output_dir(),
 | 
				
			||||||
      utils::path::combine(test::get_test_output_dir(), {"encrypt_provider"});
 | 
					                                          {"provider", "encrypt"});
 | 
				
			||||||
 | 
					 | 
				
			||||||
  console_consumer consumer{};
 | 
					  console_consumer consumer{};
 | 
				
			||||||
  event_system::instance().start();
 | 
					  event_system::instance().start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    app_config cfg(provider_type::encrypt, config_path);
 | 
					    app_config cfg(provider_type::encrypt, config_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const auto encrypt_path =
 | 
					    auto encrypt_path =
 | 
				
			||||||
        utils::path::combine(test::get_test_input_dir(), {"encrypt"});
 | 
					        utils::path::combine(test::get_test_input_dir(), {"encrypt"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    EXPECT_STREQ(
 | 
					    EXPECT_STREQ(
 | 
				
			||||||
@@ -673,9 +820,9 @@ TEST(providers, encrypt_provider) {
 | 
				
			|||||||
  event_system::instance().stop();
 | 
					  event_system::instance().stop();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(providers, s3_provider) {
 | 
					TEST(providers_test, s3_provider) {
 | 
				
			||||||
  const auto config_path =
 | 
					  auto config_path =
 | 
				
			||||||
      utils::path::combine(test::get_test_output_dir(), {"s3_provider"});
 | 
					      utils::path::combine(test::get_test_output_dir(), {"provider", "s3"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console_consumer consumer{};
 | 
					  console_consumer consumer{};
 | 
				
			||||||
  event_system::instance().start();
 | 
					  event_system::instance().start();
 | 
				
			||||||
@@ -685,7 +832,7 @@ TEST(providers, s3_provider) {
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
      app_config src_cfg(
 | 
					      app_config src_cfg(
 | 
				
			||||||
          provider_type::s3,
 | 
					          provider_type::s3,
 | 
				
			||||||
          utils::path::combine(test::get_test_config_dir(), {"storj"}));
 | 
					          utils::path::combine(test::get_test_config_dir(), {"s3"}));
 | 
				
			||||||
      cfg.set_s3_config(src_cfg.get_s3_config());
 | 
					      cfg.set_s3_config(src_cfg.get_s3_config());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -713,9 +860,9 @@ TEST(providers, s3_provider) {
 | 
				
			|||||||
  event_system::instance().stop();
 | 
					  event_system::instance().stop();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(providers, sia_provider) {
 | 
					TEST(providers_test, sia_provider) {
 | 
				
			||||||
  const auto config_path =
 | 
					  auto config_path =
 | 
				
			||||||
      utils::path::combine(test::get_test_output_dir(), {"sia_provider"});
 | 
					      utils::path::combine(test::get_test_output_dir(), {"sia", "provider"});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console_consumer consumer{};
 | 
					  console_consumer consumer{};
 | 
				
			||||||
  event_system::instance().start();
 | 
					  event_system::instance().start();
 | 
				
			||||||
@@ -753,5 +900,3 @@ TEST(providers, sia_provider) {
 | 
				
			|||||||
  event_system::instance().stop();
 | 
					  event_system::instance().stop();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
} // namespace repertory
 | 
					} // namespace repertory
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif // 0
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,7 @@
 | 
				
			|||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
static constexpr const std::size_t test_chunk_size{1024U};
 | 
					static constexpr const std::size_t test_chunk_size{1024U};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(upload, can_upload_a_valid_file) {
 | 
					TEST(upload_test, can_upload_a_valid_file) {
 | 
				
			||||||
  console_consumer con;
 | 
					  console_consumer con;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  event_system::instance().start();
 | 
					  event_system::instance().start();
 | 
				
			||||||
@@ -71,7 +71,7 @@ TEST(upload, can_upload_a_valid_file) {
 | 
				
			|||||||
  event_system::instance().stop();
 | 
					  event_system::instance().stop();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(upload, can_cancel_upload) {
 | 
					TEST(upload_test, can_cancel_upload) {
 | 
				
			||||||
  console_consumer con;
 | 
					  console_consumer con;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  event_system::instance().start();
 | 
					  event_system::instance().start();
 | 
				
			||||||
@@ -135,7 +135,7 @@ TEST(upload, can_cancel_upload) {
 | 
				
			|||||||
  event_system::instance().stop();
 | 
					  event_system::instance().stop();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(upload, can_stop_upload) {
 | 
					TEST(upload_test, can_stop_upload) {
 | 
				
			||||||
  console_consumer con;
 | 
					  console_consumer con;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  event_system::instance().start();
 | 
					  event_system::instance().start();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,7 @@
 | 
				
			|||||||
#include "utils/file.hpp"
 | 
					#include "utils/file.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory {
 | 
					namespace repertory {
 | 
				
			||||||
TEST(utils, convert_api_date) {
 | 
					TEST(utils_test, convert_api_date) {
 | 
				
			||||||
#if defined(_WIN32)
 | 
					#if defined(_WIN32)
 | 
				
			||||||
  auto file_time = utils::time::unix_time_to_filetime(
 | 
					  auto file_time = utils::time::unix_time_to_filetime(
 | 
				
			||||||
      s3_provider::convert_api_date("2009-10-12T17:50:30.111Z"));
 | 
					      s3_provider::convert_api_date("2009-10-12T17:50:30.111Z"));
 | 
				
			||||||
@@ -63,7 +63,7 @@ TEST(utils, convert_api_date) {
 | 
				
			|||||||
#endif // defined(_WIN32)
 | 
					#endif // defined(_WIN32)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(utils, generate_sha256) {
 | 
					TEST(utils_test, generate_sha256) {
 | 
				
			||||||
  auto res = utils::file::file{__FILE__}.sha256();
 | 
					  auto res = utils::file::file{__FILE__}.sha256();
 | 
				
			||||||
  EXPECT_TRUE(res.has_value());
 | 
					  EXPECT_TRUE(res.has_value());
 | 
				
			||||||
  if (res.has_value()) {
 | 
					  if (res.has_value()) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ done
 | 
				
			|||||||
PROJECT_APP_LIST=()
 | 
					PROJECT_APP_LIST=()
 | 
				
			||||||
PROJECT_CMAKE_OPTS=""
 | 
					PROJECT_CMAKE_OPTS=""
 | 
				
			||||||
PROJECT_ENABLE_WIN32_LONG_PATH_NAMES=OFF
 | 
					PROJECT_ENABLE_WIN32_LONG_PATH_NAMES=OFF
 | 
				
			||||||
 | 
					PROJECT_ENABLE_V2_ERRORS=OFF
 | 
				
			||||||
PROJECT_IS_ALPINE=0
 | 
					PROJECT_IS_ALPINE=0
 | 
				
			||||||
PROJECT_IS_ARM64=0
 | 
					PROJECT_IS_ARM64=0
 | 
				
			||||||
PROJECT_MINGW64_COPY_DEPENDENCIES=()
 | 
					PROJECT_MINGW64_COPY_DEPENDENCIES=()
 | 
				
			||||||
@@ -234,6 +235,7 @@ PROJECT_CMAKE_OPTS="-DPROJECT_BUILD_DIR=${PROJECT_BUILD_DIR} ${PROJECT_CMAKE_OPT
 | 
				
			|||||||
PROJECT_CMAKE_OPTS="-DPROJECT_BUILD_SHARED_LIBS=${PROJECT_BUILD_SHARED_LIBS} ${PROJECT_CMAKE_OPTS}"
 | 
					PROJECT_CMAKE_OPTS="-DPROJECT_BUILD_SHARED_LIBS=${PROJECT_BUILD_SHARED_LIBS} ${PROJECT_CMAKE_OPTS}"
 | 
				
			||||||
PROJECT_CMAKE_OPTS="-DPROJECT_CMAKE_BUILD_TYPE=${PROJECT_CMAKE_BUILD_TYPE} ${PROJECT_CMAKE_OPTS}"
 | 
					PROJECT_CMAKE_OPTS="-DPROJECT_CMAKE_BUILD_TYPE=${PROJECT_CMAKE_BUILD_TYPE} ${PROJECT_CMAKE_OPTS}"
 | 
				
			||||||
PROJECT_CMAKE_OPTS="-DPROJECT_DIST_DIR=${PROJECT_DIST_DIR} ${PROJECT_CMAKE_OPTS}"
 | 
					PROJECT_CMAKE_OPTS="-DPROJECT_DIST_DIR=${PROJECT_DIST_DIR} ${PROJECT_CMAKE_OPTS}"
 | 
				
			||||||
 | 
					PROJECT_CMAKE_OPTS="-DPROJECT_ENABLE_V2_ERRORS=${PROJECT_ENABLE_V2_ERRORS} ${PROJECT_CMAKE_OPTS}"
 | 
				
			||||||
PROJECT_CMAKE_OPTS="-DPROJECT_ENABLE_WIN32_LONG_PATH_NAMES=${PROJECT_ENABLE_WIN32_LONG_PATH_NAMES} ${PROJECT_CMAKE_OPTS}"
 | 
					PROJECT_CMAKE_OPTS="-DPROJECT_ENABLE_WIN32_LONG_PATH_NAMES=${PROJECT_ENABLE_WIN32_LONG_PATH_NAMES} ${PROJECT_CMAKE_OPTS}"
 | 
				
			||||||
PROJECT_CMAKE_OPTS="-DPROJECT_EXTERNAL_BUILD_ROOT=${PROJECT_EXTERNAL_BUILD_ROOT} ${PROJECT_CMAKE_OPTS}"
 | 
					PROJECT_CMAKE_OPTS="-DPROJECT_EXTERNAL_BUILD_ROOT=${PROJECT_EXTERNAL_BUILD_ROOT} ${PROJECT_CMAKE_OPTS}"
 | 
				
			||||||
PROJECT_CMAKE_OPTS="-DPROJECT_GIT_REV=${PROJECT_GIT_REV} ${PROJECT_CMAKE_OPTS}"
 | 
					PROJECT_CMAKE_OPTS="-DPROJECT_GIT_REV=${PROJECT_GIT_REV} ${PROJECT_CMAKE_OPTS}"
 | 
				
			||||||
@@ -305,6 +307,7 @@ export PROJECT_COPYRIGHT
 | 
				
			|||||||
export PROJECT_DESC
 | 
					export PROJECT_DESC
 | 
				
			||||||
export PROJECT_DIST_DIR
 | 
					export PROJECT_DIST_DIR
 | 
				
			||||||
export PROJECT_ENABLE_WIN32_LONG_PATH_NAMES
 | 
					export PROJECT_ENABLE_WIN32_LONG_PATH_NAMES
 | 
				
			||||||
 | 
					export PROJECT_ENABLE_V2_ERRORS
 | 
				
			||||||
export PROJECT_FILE_PART
 | 
					export PROJECT_FILE_PART
 | 
				
			||||||
export PROJECT_GIT_REV
 | 
					export PROJECT_GIT_REV
 | 
				
			||||||
export PROJECT_IS_ALPINE
 | 
					export PROJECT_IS_ALPINE
 | 
				
			||||||
@@ -355,6 +358,7 @@ echo "  Company name: ${PROJECT_COMPANY_NAME}"
 | 
				
			|||||||
echo "  Copyright: ${PROJECT_COPYRIGHT}"
 | 
					echo "  Copyright: ${PROJECT_COPYRIGHT}"
 | 
				
			||||||
echo "  Description: ${PROJECT_DESC}"
 | 
					echo "  Description: ${PROJECT_DESC}"
 | 
				
			||||||
echo "  Dist dir: ${PROJECT_DIST_DIR}"
 | 
					echo "  Dist dir: ${PROJECT_DIST_DIR}"
 | 
				
			||||||
 | 
					echo "  Enable v2 errors: ${PROJECT_ENABLE_V2_ERRORS}"
 | 
				
			||||||
echo "  External build root: ${PROJECT_EXTERNAL_BUILD_ROOT}"
 | 
					echo "  External build root: ${PROJECT_EXTERNAL_BUILD_ROOT}"
 | 
				
			||||||
echo "  File part: ${PROJECT_FILE_PART}"
 | 
					echo "  File part: ${PROJECT_FILE_PART}"
 | 
				
			||||||
echo "  Is ARM64: ${PROJECT_IS_ARM64}"
 | 
					echo "  Is ARM64: ${PROJECT_IS_ARM64}"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,12 +25,16 @@
 | 
				
			|||||||
#include "utils/config.hpp"
 | 
					#include "utils/config.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory::utils::error {
 | 
					namespace repertory::utils::error {
 | 
				
			||||||
[[nodiscard]] auto
 | 
					[[nodiscard]] auto create_error_message(std::vector<std::string_view> items)
 | 
				
			||||||
create_error_message(std::vector<std::string_view> items) -> std::string;
 | 
					    -> std::string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[nodiscard]] auto
 | 
					[[nodiscard]] auto create_error_message(std::string_view function_name,
 | 
				
			||||||
create_exception(std::string_view function_name,
 | 
					                                        std::vector<std::string_view> items)
 | 
				
			||||||
                 std::vector<std::string_view> items) -> std::runtime_error;
 | 
					    -> std::string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[nodiscard]] auto create_exception(std::string_view function_name,
 | 
				
			||||||
 | 
					                                    std::vector<std::string_view> items)
 | 
				
			||||||
 | 
					    -> std::runtime_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct i_exception_handler {
 | 
					struct i_exception_handler {
 | 
				
			||||||
  virtual ~i_exception_handler() {}
 | 
					  virtual ~i_exception_handler() {}
 | 
				
			||||||
@@ -40,6 +44,11 @@ struct i_exception_handler {
 | 
				
			|||||||
  auto operator=(const i_exception_handler &) noexcept = delete;
 | 
					  auto operator=(const i_exception_handler &) noexcept = delete;
 | 
				
			||||||
  auto operator=(i_exception_handler &&) noexcept = delete;
 | 
					  auto operator=(i_exception_handler &&) noexcept = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					  virtual void handle_debug(std::string_view function_name,
 | 
				
			||||||
 | 
					                            std::string_view msg) const = 0;
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual void handle_error(std::string_view function_name,
 | 
					  virtual void handle_error(std::string_view function_name,
 | 
				
			||||||
                            std::string_view msg) const = 0;
 | 
					                            std::string_view msg) const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -48,56 +57,107 @@ struct i_exception_handler {
 | 
				
			|||||||
  virtual void handle_exception(std::string_view function_name,
 | 
					  virtual void handle_exception(std::string_view function_name,
 | 
				
			||||||
                                const std::exception &ex) const = 0;
 | 
					                                const std::exception &ex) const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					  virtual void handle_info(std::string_view function_name,
 | 
				
			||||||
 | 
					                           std::string_view msg) const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual void handle_trace(std::string_view function_name,
 | 
				
			||||||
 | 
					                            std::string_view msg) const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual void handle_warn(std::string_view function_name,
 | 
				
			||||||
 | 
					                           std::string_view msg) const = 0;
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
  i_exception_handler() = default;
 | 
					  i_exception_handler() = default;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct iostream_exception_handler final : i_exception_handler {
 | 
					struct iostream_exception_handler final : public i_exception_handler {
 | 
				
			||||||
  void handle_error(std::string_view function_name,
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
                    std::string_view msg) const override {
 | 
					  void handle_debug(std::string_view function_name,
 | 
				
			||||||
    std::cerr << create_error_message({
 | 
					                    std::string_view msg) const override;
 | 
				
			||||||
                     function_name,
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
                     msg,
 | 
					 | 
				
			||||||
                 })
 | 
					 | 
				
			||||||
              << std::endl;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void handle_exception(std::string_view function_name) const override {
 | 
					  void handle_error(std::string_view function_name,
 | 
				
			||||||
    std::cerr << create_error_message({
 | 
					                    std::string_view msg) const override;
 | 
				
			||||||
                     function_name,
 | 
					
 | 
				
			||||||
                     "exception",
 | 
					  void handle_exception(std::string_view function_name) const override;
 | 
				
			||||||
                     "unknown",
 | 
					 | 
				
			||||||
                 })
 | 
					 | 
				
			||||||
              << std::endl;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void handle_exception(std::string_view function_name,
 | 
					  void handle_exception(std::string_view function_name,
 | 
				
			||||||
                        const std::exception &ex) const override {
 | 
					                        const std::exception &ex) const override;
 | 
				
			||||||
    std::cerr << create_error_message({
 | 
					 | 
				
			||||||
                     function_name,
 | 
					 | 
				
			||||||
                     "exception",
 | 
					 | 
				
			||||||
                     (ex.what() == nullptr ? "unknown" : ex.what()),
 | 
					 | 
				
			||||||
                 })
 | 
					 | 
				
			||||||
              << std::endl;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
inline const iostream_exception_handler default_exception_handler{};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern std::atomic<const i_exception_handler *> exception_handler;
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					  void handle_info(std::string_view function_name,
 | 
				
			||||||
 | 
					                   std::string_view msg) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void handle_trace(std::string_view function_name,
 | 
				
			||||||
 | 
					                    std::string_view msg) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void handle_warn(std::string_view function_name,
 | 
				
			||||||
 | 
					                   std::string_view msg) const override;
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					struct spdlog_exception_handler final : public i_exception_handler {
 | 
				
			||||||
 | 
					  void handle_debug(std::string_view function_name,
 | 
				
			||||||
 | 
					                    std::string_view msg) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void handle_error(std::string_view function_name,
 | 
				
			||||||
 | 
					                    std::string_view msg) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void handle_exception(std::string_view function_name) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void handle_exception(std::string_view function_name,
 | 
				
			||||||
 | 
					                        const std::exception &ex) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void handle_info(std::string_view function_name,
 | 
				
			||||||
 | 
					                   std::string_view msg) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void handle_trace(std::string_view function_name,
 | 
				
			||||||
 | 
					                    std::string_view msg) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void handle_warn(std::string_view function_name,
 | 
				
			||||||
 | 
					                   std::string_view msg) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					  iostream_exception_handler fallback{};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					inline const spdlog_exception_handler default_exception_handler{};
 | 
				
			||||||
 | 
					#else  // !defined(PROJECT_ENABLE_SPDLOG) || !defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					inline const iostream_exception_handler default_exception_handler{};
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(PROJECT_ENABLE_TESTING)
 | 
					#if defined(PROJECT_ENABLE_TESTING)
 | 
				
			||||||
[[nodiscard]] inline auto
 | 
					extern std::atomic<const i_exception_handler *> exception_handler;
 | 
				
			||||||
get_exception_handler() -> const i_exception_handler * {
 | 
					
 | 
				
			||||||
 | 
					[[nodiscard]] inline auto get_exception_handler()
 | 
				
			||||||
 | 
					    -> const i_exception_handler * {
 | 
				
			||||||
  return exception_handler;
 | 
					  return exception_handler;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif // defined(PROJECT_ENABLE_TESTING)
 | 
					#endif // defined(PROJECT_ENABLE_TESTING)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					void handle_debug(std::string_view function_name, std::string_view msg);
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_error(std::string_view function_name, std::string_view msg);
 | 
					void handle_error(std::string_view function_name, std::string_view msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_exception(std::string_view function_name);
 | 
					void handle_exception(std::string_view function_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_exception(std::string_view function_name, const std::exception &ex);
 | 
					void handle_exception(std::string_view function_name, const std::exception &ex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					void handle_info(std::string_view function_name, std::string_view msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle_trace(std::string_view function_name, std::string_view msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle_warn(std::string_view function_name, std::string_view msg);
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void set_exception_handler(const i_exception_handler *handler);
 | 
					void set_exception_handler(const i_exception_handler *handler);
 | 
				
			||||||
} // namespace repertory::utils::error
 | 
					} // namespace repertory::utils::error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,9 +22,6 @@
 | 
				
			|||||||
#include "utils/error.hpp"
 | 
					#include "utils/error.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace repertory::utils::error {
 | 
					namespace repertory::utils::error {
 | 
				
			||||||
std::atomic<const i_exception_handler *> exception_handler{
 | 
					 | 
				
			||||||
    &default_exception_handler};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto create_error_message(std::vector<std::string_view> items) -> std::string {
 | 
					auto create_error_message(std::vector<std::string_view> items) -> std::string {
 | 
				
			||||||
  std::stringstream stream{};
 | 
					  std::stringstream stream{};
 | 
				
			||||||
  for (std::size_t idx = 0U; idx < items.size(); ++idx) {
 | 
					  for (std::size_t idx = 0U; idx < items.size(); ++idx) {
 | 
				
			||||||
@@ -38,13 +35,30 @@ auto create_error_message(std::vector<std::string_view> items) -> std::string {
 | 
				
			|||||||
  return stream.str();
 | 
					  return stream.str();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					auto create_error_message(std::string_view function_name,
 | 
				
			||||||
 | 
					                          std::vector<std::string_view> items) -> std::string {
 | 
				
			||||||
 | 
					  items.insert(items.begin(), function_name);
 | 
				
			||||||
 | 
					  return create_error_message(items);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto create_exception(std::string_view function_name,
 | 
					auto create_exception(std::string_view function_name,
 | 
				
			||||||
                      std::vector<std::string_view> items)
 | 
					                      std::vector<std::string_view> items)
 | 
				
			||||||
    -> std::runtime_error {
 | 
					    -> std::runtime_error {
 | 
				
			||||||
  items.insert(items.begin(), function_name);
 | 
					  return std::runtime_error(create_error_message(function_name, items));
 | 
				
			||||||
  return std::runtime_error(create_error_message(items));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					void handle_debug(std::string_view function_name, std::string_view msg) {
 | 
				
			||||||
 | 
					  const i_exception_handler *handler{exception_handler};
 | 
				
			||||||
 | 
					  if (handler != nullptr) {
 | 
				
			||||||
 | 
					    handler->handle_debug(function_name, msg);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  default_exception_handler.handle_debug(function_name, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_error(std::string_view function_name, std::string_view msg) {
 | 
					void handle_error(std::string_view function_name, std::string_view msg) {
 | 
				
			||||||
  const i_exception_handler *handler{exception_handler};
 | 
					  const i_exception_handler *handler{exception_handler};
 | 
				
			||||||
  if (handler != nullptr) {
 | 
					  if (handler != nullptr) {
 | 
				
			||||||
@@ -76,6 +90,38 @@ void handle_exception(std::string_view function_name,
 | 
				
			|||||||
  default_exception_handler.handle_exception(function_name, ex);
 | 
					  default_exception_handler.handle_exception(function_name, ex);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					void handle_info(std::string_view function_name, std::string_view msg) {
 | 
				
			||||||
 | 
					  const i_exception_handler *handler{exception_handler};
 | 
				
			||||||
 | 
					  if (handler != nullptr) {
 | 
				
			||||||
 | 
					    handler->handle_info(function_name, msg);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  default_exception_handler.handle_info(function_name, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle_trace(std::string_view function_name, std::string_view msg) {
 | 
				
			||||||
 | 
					  const i_exception_handler *handler{exception_handler};
 | 
				
			||||||
 | 
					  if (handler != nullptr) {
 | 
				
			||||||
 | 
					    handler->handle_trace(function_name, msg);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  default_exception_handler.handle_trace(function_name, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle_warn(std::string_view function_name, std::string_view msg) {
 | 
				
			||||||
 | 
					  const i_exception_handler *handler{exception_handler};
 | 
				
			||||||
 | 
					  if (handler != nullptr) {
 | 
				
			||||||
 | 
					    handler->handle_warn(function_name, msg);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  default_exception_handler.handle_warn(function_name, msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void set_exception_handler(const i_exception_handler *handler) {
 | 
					void set_exception_handler(const i_exception_handler *handler) {
 | 
				
			||||||
  exception_handler = handler;
 | 
					  exception_handler = handler;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										241
									
								
								support/src/utils/error_handler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								support/src/utils/error_handler.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,241 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					  Copyright <2018-2025> <scott.e.graves@protonmail.com>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 | 
					  of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
 | 
					  in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					  copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					  furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The above copyright notice and this permission notice shall be included in all
 | 
				
			||||||
 | 
					  copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
				
			||||||
 | 
					  SOFTWARE.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#include "utils/config.hpp"
 | 
				
			||||||
 | 
					#include "utils/error.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace repertory::utils::error {
 | 
				
			||||||
 | 
					std::atomic<const i_exception_handler *> exception_handler{
 | 
				
			||||||
 | 
					    &default_exception_handler};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					void iostream_exception_handler::handle_debug(std::string_view function_name,
 | 
				
			||||||
 | 
					                                              std::string_view msg) const {
 | 
				
			||||||
 | 
					  std::cout << create_error_message({
 | 
				
			||||||
 | 
					                   "debug",
 | 
				
			||||||
 | 
					                   function_name,
 | 
				
			||||||
 | 
					                   msg,
 | 
				
			||||||
 | 
					               })
 | 
				
			||||||
 | 
					            << std::endl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void iostream_exception_handler::handle_error(std::string_view function_name,
 | 
				
			||||||
 | 
					                                              std::string_view msg) const {
 | 
				
			||||||
 | 
					  std::cerr << create_error_message({
 | 
				
			||||||
 | 
					                   "error",
 | 
				
			||||||
 | 
					                   function_name,
 | 
				
			||||||
 | 
					                   msg,
 | 
				
			||||||
 | 
					               })
 | 
				
			||||||
 | 
					            << std::endl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void iostream_exception_handler::handle_exception(
 | 
				
			||||||
 | 
					    std::string_view function_name) const {
 | 
				
			||||||
 | 
					  std::cerr << create_error_message({
 | 
				
			||||||
 | 
					                   "error",
 | 
				
			||||||
 | 
					                   function_name,
 | 
				
			||||||
 | 
					                   "exception",
 | 
				
			||||||
 | 
					                   "unknown",
 | 
				
			||||||
 | 
					               })
 | 
				
			||||||
 | 
					            << std::endl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void iostream_exception_handler::handle_exception(
 | 
				
			||||||
 | 
					    std::string_view function_name, const std::exception &ex) const {
 | 
				
			||||||
 | 
					  std::cerr << create_error_message({
 | 
				
			||||||
 | 
					                   "error",
 | 
				
			||||||
 | 
					                   function_name,
 | 
				
			||||||
 | 
					                   "exception",
 | 
				
			||||||
 | 
					                   (ex.what() == nullptr ? "unknown" : ex.what()),
 | 
				
			||||||
 | 
					               })
 | 
				
			||||||
 | 
					            << std::endl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					void iostream_exception_handler::handle_info(std::string_view function_name,
 | 
				
			||||||
 | 
					                                             std::string_view msg) const {
 | 
				
			||||||
 | 
					  std::cout << create_error_message({
 | 
				
			||||||
 | 
					                   "info",
 | 
				
			||||||
 | 
					                   function_name,
 | 
				
			||||||
 | 
					                   msg,
 | 
				
			||||||
 | 
					               })
 | 
				
			||||||
 | 
					            << std::endl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void iostream_exception_handler::handle_trace(std::string_view function_name,
 | 
				
			||||||
 | 
					                                              std::string_view msg) const {
 | 
				
			||||||
 | 
					  std::cout << create_error_message({
 | 
				
			||||||
 | 
					                   "trace",
 | 
				
			||||||
 | 
					                   function_name,
 | 
				
			||||||
 | 
					                   msg,
 | 
				
			||||||
 | 
					               })
 | 
				
			||||||
 | 
					            << std::endl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void iostream_exception_handler::handle_warn(std::string_view function_name,
 | 
				
			||||||
 | 
					                                             std::string_view msg) const {
 | 
				
			||||||
 | 
					  std::cout << create_error_message({
 | 
				
			||||||
 | 
					                   "warn",
 | 
				
			||||||
 | 
					                   function_name,
 | 
				
			||||||
 | 
					                   msg,
 | 
				
			||||||
 | 
					               })
 | 
				
			||||||
 | 
					            << std::endl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					void spdlog_exception_handler::handle_debug(std::string_view function_name,
 | 
				
			||||||
 | 
					                                            std::string_view msg) const {
 | 
				
			||||||
 | 
					  auto console = spdlog::get("console");
 | 
				
			||||||
 | 
					  if (console) {
 | 
				
			||||||
 | 
					    console->debug(utils::error::create_error_message(function_name, {msg}));
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    fallback.handle_debug(function_name, msg);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto file = spdlog::get("file");
 | 
				
			||||||
 | 
					  if (not file) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  file->debug(utils::error::create_error_message(function_name, {msg}));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void spdlog_exception_handler::handle_error(std::string_view function_name,
 | 
				
			||||||
 | 
					                                            std::string_view msg) const {
 | 
				
			||||||
 | 
					  auto console = spdlog::get("console");
 | 
				
			||||||
 | 
					  if (console) {
 | 
				
			||||||
 | 
					    console->error(utils::error::create_error_message(function_name, {msg}));
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    fallback.handle_error(function_name, msg);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto file = spdlog::get("file");
 | 
				
			||||||
 | 
					  if (not file) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  file->error(utils::error::create_error_message(function_name, {msg}));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void spdlog_exception_handler::handle_exception(
 | 
				
			||||||
 | 
					    std::string_view function_name) const {
 | 
				
			||||||
 | 
					  auto console = spdlog::get("console");
 | 
				
			||||||
 | 
					  if (console) {
 | 
				
			||||||
 | 
					    console->error(utils::error::create_error_message(function_name,
 | 
				
			||||||
 | 
					                                                      {
 | 
				
			||||||
 | 
					                                                          "exception",
 | 
				
			||||||
 | 
					                                                          "unknown exception",
 | 
				
			||||||
 | 
					                                                      }));
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    fallback.handle_exception(function_name);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto file = spdlog::get("file");
 | 
				
			||||||
 | 
					  if (not file) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  file->error(
 | 
				
			||||||
 | 
					      utils::error::create_error_message(function_name, {
 | 
				
			||||||
 | 
					                                                            "exception",
 | 
				
			||||||
 | 
					                                                            "unknown exception",
 | 
				
			||||||
 | 
					                                                        }));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void spdlog_exception_handler::handle_exception(
 | 
				
			||||||
 | 
					    std::string_view function_name, const std::exception &ex) const {
 | 
				
			||||||
 | 
					  auto console = spdlog::get("console");
 | 
				
			||||||
 | 
					  if (console) {
 | 
				
			||||||
 | 
					    console->error(utils::error::create_error_message(
 | 
				
			||||||
 | 
					        function_name, {
 | 
				
			||||||
 | 
					                           "exception",
 | 
				
			||||||
 | 
					                           (ex.what() == nullptr ? "unknown" : ex.what()),
 | 
				
			||||||
 | 
					                       }));
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    fallback.handle_exception(function_name, ex);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto file = spdlog::get("file");
 | 
				
			||||||
 | 
					  if (not file) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  file->error(utils::error::create_error_message(
 | 
				
			||||||
 | 
					      function_name, {
 | 
				
			||||||
 | 
					                         "exception",
 | 
				
			||||||
 | 
					                         (ex.what() == nullptr ? "unknown" : ex.what()),
 | 
				
			||||||
 | 
					                     }));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void spdlog_exception_handler::handle_info(std::string_view function_name,
 | 
				
			||||||
 | 
					                                           std::string_view msg) const {
 | 
				
			||||||
 | 
					  auto console = spdlog::get("console");
 | 
				
			||||||
 | 
					  if (console) {
 | 
				
			||||||
 | 
					    console->info(utils::error::create_error_message(function_name, {msg}));
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    fallback.handle_info(function_name, msg);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto file = spdlog::get("file");
 | 
				
			||||||
 | 
					  if (not file) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  file->info(utils::error::create_error_message(function_name, {msg}));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void spdlog_exception_handler::handle_trace(std::string_view function_name,
 | 
				
			||||||
 | 
					                                            std::string_view msg) const {
 | 
				
			||||||
 | 
					  auto console = spdlog::get("console");
 | 
				
			||||||
 | 
					  if (console) {
 | 
				
			||||||
 | 
					    console->trace(utils::error::create_error_message(function_name, {msg}));
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    fallback.handle_trace(function_name, msg);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto file = spdlog::get("file");
 | 
				
			||||||
 | 
					  if (not file) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  file->trace(utils::error::create_error_message(function_name, {msg}));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void spdlog_exception_handler::handle_warn(std::string_view function_name,
 | 
				
			||||||
 | 
					                                           std::string_view msg) const {
 | 
				
			||||||
 | 
					  auto console = spdlog::get("console");
 | 
				
			||||||
 | 
					  if (console) {
 | 
				
			||||||
 | 
					    console->warn(utils::error::create_error_message(function_name, {msg}));
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    fallback.handle_warn(function_name, msg);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto file = spdlog::get("file");
 | 
				
			||||||
 | 
					  if (not file) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  file->warn(utils::error::create_error_message(function_name, {msg}));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					} // namespace repertory::utils::error
 | 
				
			||||||
@@ -41,8 +41,16 @@ auto change_to_process_directory() -> bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ::GetModuleFileNameA(nullptr, file_name.data(),
 | 
					    ::GetModuleFileNameA(nullptr, file_name.data(),
 | 
				
			||||||
                         static_cast<DWORD>(file_name.size() - 1U));
 | 
					                         static_cast<DWORD>(file_name.size() - 1U));
 | 
				
			||||||
    auto path = utils::path::strip_to_file_name(file_name.c_str());
 | 
					    auto path = utils::path::get_parent_path(file_name.c_str());
 | 
				
			||||||
    ::SetCurrentDirectoryA(path.c_str());
 | 
					    auto res = ::SetCurrentDirectoryA(path.c_str()) != 0;
 | 
				
			||||||
 | 
					    if (not res) {
 | 
				
			||||||
 | 
					      throw utils::error::create_exception(
 | 
				
			||||||
 | 
					          function_name, {
 | 
				
			||||||
 | 
					                             "failed to set current directory",
 | 
				
			||||||
 | 
					                             std::to_string(utils::get_last_error_code()),
 | 
				
			||||||
 | 
					                             path,
 | 
				
			||||||
 | 
					                         });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
#else // !defined(_WIN32)
 | 
					#else // !defined(_WIN32)
 | 
				
			||||||
    std::string path;
 | 
					    std::string path;
 | 
				
			||||||
    path.resize(PATH_MAX + 1);
 | 
					    path.resize(PATH_MAX + 1);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,15 +29,28 @@ TEST(utils_error, check_default_exception_handler) {
 | 
				
			|||||||
  EXPECT_TRUE(utils::error::get_exception_handler() != nullptr);
 | 
					  EXPECT_TRUE(utils::error::get_exception_handler() != nullptr);
 | 
				
			||||||
  if (&utils::error::default_exception_handler ==
 | 
					  if (&utils::error::default_exception_handler ==
 | 
				
			||||||
      utils::error::get_exception_handler()) {
 | 
					      utils::error::get_exception_handler()) {
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					    auto default_handler_is_spdlog =
 | 
				
			||||||
 | 
					        is_decay_equ<decltype(utils::error::default_exception_handler),
 | 
				
			||||||
 | 
					                     utils::error::spdlog_exception_handler>;
 | 
				
			||||||
 | 
					    EXPECT_TRUE(default_handler_is_spdlog);
 | 
				
			||||||
 | 
					#else // !defined(PROJECT_ENABLE_SPDLOG) || !defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
    auto default_handler_is_iostream =
 | 
					    auto default_handler_is_iostream =
 | 
				
			||||||
        is_decay_equ<decltype(utils::error::default_exception_handler),
 | 
					        is_decay_equ<decltype(utils::error::default_exception_handler),
 | 
				
			||||||
                     utils::error::iostream_exception_handler>;
 | 
					                     utils::error::iostream_exception_handler>;
 | 
				
			||||||
    EXPECT_TRUE(default_handler_is_iostream);
 | 
					    EXPECT_TRUE(default_handler_is_iostream);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST(utils_error, can_override_exception_handler) {
 | 
					TEST(utils_error, can_override_exception_handler) {
 | 
				
			||||||
  struct my_exc_handler final : public utils::error::i_exception_handler {
 | 
					  struct my_exc_handler final : public utils::error::i_exception_handler {
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					    MOCK_METHOD(void, handle_debug,
 | 
				
			||||||
 | 
					                (std::string_view function_name, std::string_view msg),
 | 
				
			||||||
 | 
					                (const, override));
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    MOCK_METHOD(void, handle_error,
 | 
					    MOCK_METHOD(void, handle_error,
 | 
				
			||||||
                (std::string_view function_name, std::string_view msg),
 | 
					                (std::string_view function_name, std::string_view msg),
 | 
				
			||||||
                (const, override));
 | 
					                (const, override));
 | 
				
			||||||
@@ -48,11 +61,30 @@ TEST(utils_error, can_override_exception_handler) {
 | 
				
			|||||||
    MOCK_METHOD(void, handle_exception,
 | 
					    MOCK_METHOD(void, handle_exception,
 | 
				
			||||||
                (std::string_view function_name, const std::exception &ex),
 | 
					                (std::string_view function_name, const std::exception &ex),
 | 
				
			||||||
                (const, override));
 | 
					                (const, override));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					    MOCK_METHOD(void, handle_info,
 | 
				
			||||||
 | 
					                (std::string_view function_name, std::string_view msg),
 | 
				
			||||||
 | 
					                (const, override));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MOCK_METHOD(void, handle_trace,
 | 
				
			||||||
 | 
					                (std::string_view function_name, std::string_view msg),
 | 
				
			||||||
 | 
					                (const, override));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MOCK_METHOD(void, handle_warn,
 | 
				
			||||||
 | 
					                (std::string_view function_name, std::string_view msg),
 | 
				
			||||||
 | 
					                (const, override));
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  my_exc_handler handler{};
 | 
					  my_exc_handler handler{};
 | 
				
			||||||
  utils::error::set_exception_handler(&handler);
 | 
					  utils::error::set_exception_handler(&handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					  EXPECT_CALL(handler, handle_debug("test_func", "debug")).WillOnce(Return());
 | 
				
			||||||
 | 
					  utils::error::handle_debug("test_func", "debug");
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  EXPECT_CALL(handler, handle_error("test_func", "error")).WillOnce(Return());
 | 
					  EXPECT_CALL(handler, handle_error("test_func", "error")).WillOnce(Return());
 | 
				
			||||||
  utils::error::handle_error("test_func", "error");
 | 
					  utils::error::handle_error("test_func", "error");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -68,6 +100,17 @@ TEST(utils_error, can_override_exception_handler) {
 | 
				
			|||||||
          });
 | 
					          });
 | 
				
			||||||
  utils::error::handle_exception("test_func_ex", ex);
 | 
					  utils::error::handle_exception("test_func_ex", ex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					  EXPECT_CALL(handler, handle_info("test_func", "info")).WillOnce(Return());
 | 
				
			||||||
 | 
					  utils::error::handle_info("test_func", "info");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_CALL(handler, handle_trace("test_func", "trace")).WillOnce(Return());
 | 
				
			||||||
 | 
					  utils::error::handle_trace("test_func", "trace");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXPECT_CALL(handler, handle_warn("test_func", "warn")).WillOnce(Return());
 | 
				
			||||||
 | 
					  utils::error::handle_warn("test_func", "warn");
 | 
				
			||||||
 | 
					#endif // defined(PROJECT_ENABLE_V2_ERRORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  utils::error::set_exception_handler(&utils::error::default_exception_handler);
 | 
					  utils::error::set_exception_handler(&utils::error::default_exception_handler);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
} // namespace repertory
 | 
					} // namespace repertory
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user