77 Commits

Author SHA1 Message Date
7d1574d042 make text selectable
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-03-01 16:34:47 -06:00
43280b2913 updates
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-03-01 16:25:41 -06:00
788aefdf86 layout changes 2025-03-01 16:22:54 -06:00
3453bd0b50 refactor 2025-03-01 15:51:55 -06:00
96df3168fc updates
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-03-01 15:50:01 -06:00
45381c3d0c updates 2025-03-01 15:48:40 -06:00
4c82b87b07 gui changes 2025-03-01 15:48:32 -06:00
c29072d84d gui changes 2025-03-01 15:47:34 -06:00
311a2688cb gui changes 2025-03-01 15:43:36 -06:00
968633a5b9 added status
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-03-01 15:18:30 -06:00
bcda2abfd2 fix
Some checks are pending
BlockStorage/repertory/pipeline/head Build queued...
2025-03-01 11:22:21 -06:00
7d5c252e89 test
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-03-01 11:09:11 -06:00
0aeb69a050 grab mount settings and status 2025-03-01 10:34:13 -06:00
7d441964e9 fixes
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-03-01 07:32:23 -06:00
1d78ee88b8 continue mgmt portal 2025-03-01 07:26:38 -06:00
d54ba8203a continue management portal 2025-03-01 07:13:08 -06:00
52f0d755ba refactor
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-28 23:14:37 -06:00
343c324050 fix sorting 2025-02-28 22:45:32 -06:00
e446757f7e flutter changes
Some checks are pending
BlockStorage/repertory/pipeline/head Build queued...
2025-02-28 22:35:46 -06:00
513bc09944 flutter changes 2025-02-28 20:49:14 -06:00
a79e696315 fix 2025-02-28 20:43:15 -06:00
26dbda290e flutter changes 2025-02-28 20:36:35 -06:00
d06b965dc1 updated build system
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-28 18:19:16 -06:00
6aee374725 updated build system
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-28 17:42:26 -06:00
a7d570d5a0 updated build system
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-28 17:34:16 -06:00
c93e6bedcc updated build system
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-28 15:00:05 -06:00
93b4237e4f fix
Some checks failed
BlockStorage/repertory/pipeline/head There was a failure building this commit
2025-02-28 13:25:33 -06:00
4013ed692e fixes
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-28 13:18:34 -06:00
99914382f4 fix
Some checks failed
BlockStorage/repertory/pipeline/head There was a failure building this commit
2025-02-28 12:58:51 -06:00
3a468d72ce fix
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-28 10:45:18 -06:00
0611f0c9dd updated build system
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-28 10:41:19 -06:00
5567e665cc updated build system
Some checks failed
BlockStorage/repertory/pipeline/head There was a failure building this commit
2025-02-28 10:06:19 -06:00
13ebd7b8b0 updated build system 2025-02-28 09:25:09 -06:00
c2e9960ad5 fix
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-27 21:15:07 -06:00
86918595b3 refactor data directory
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-27 21:09:47 -06:00
9f90494efb fixes
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-27 20:44:45 -06:00
b3ee609e09 flutter items
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-27 15:16:34 -06:00
7dc2ce8702 updated build system
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-27 14:52:03 -06:00
ed5f1f04ad change base href 2025-02-27 14:48:41 -06:00
863e0b2165 refactor 2025-02-27 14:42:38 -06:00
122b4998d6 added signal handler 2025-02-27 14:35:37 -06:00
722357388c added signal handler 2025-02-27 14:29:21 -06:00
0e21d93bb3 refactor
Some checks reported errors
BlockStorage/repertory/pipeline/head Something is wrong with the build of this commit
2025-02-27 14:12:03 -06:00
e8118bac89 fix 2025-02-27 14:09:14 -06:00
c4af929d7a basic authentication 2025-02-27 13:47:52 -06:00
3826afd3bf setup and fixes 2025-02-27 13:43:21 -06:00
4a15e2f827 updated build system 2025-02-27 12:25:18 -06:00
48b6012f97 fixes 2025-02-27 12:20:10 -06:00
d37c6598c4 fixes 2025-02-27 12:18:50 -06:00
c95242e016 fixes and setup 2025-02-27 11:13:06 -06:00
6ed4db0737 initial setup 2025-02-27 09:53:14 -06:00
1560804df8 fixed config name
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-24 09:49:26 -06:00
cc3c0febc3 updated README.md
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-23 18:23:04 -06:00
0458f12e17 Update README.md 2025-02-23 18:21:57 -06:00
ae43cedb45 Update README.md 2025-02-23 18:21:15 -06:00
191eb1620b Update README.md
Some checks are pending
BlockStorage/repertory/pipeline/head Build queued...
2025-02-23 18:20:52 -06:00
9c648583fb Complete initial v2.0 documentation #33
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-23 18:19:52 -06:00
14d78d0b65 cleanup
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-23 16:34:12 -06:00
54efde0497 Complete initial v2.0 documentation #33
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-23 16:31:33 -06:00
5f593ab86d Complete initial v2.0 documentation #33 2025-02-23 16:30:23 -06:00
feb09746f5 Complete initial v2.0 documentation #33
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-23 11:19:16 -06:00
faad98c11e Complete initial v2.0 documentation #33
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-23 11:18:18 -06:00
12f04c6064 revert
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-23 00:32:04 -06:00
ca307c3bf2 update
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-23 00:29:44 -06:00
ac6f4bcade Complete initial v2.0 documentation #33
Some checks are pending
BlockStorage/repertory/pipeline/head Build queued...
2025-02-23 00:27:11 -06:00
9d48cd97e3 Complete initial v2.0 documentation #33
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-23 00:20:51 -06:00
6c6fb0554f updated CHANGELOG.md
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-23 00:01:24 -06:00
a134f01436 updated CHANGELOG.md
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-22 23:56:21 -06:00
44c33652fa cleanup 2025-02-22 23:55:46 -06:00
131c36415d Complete initial v2.0 documentation #33
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-22 23:06:38 -06:00
9456c8b1d2 Complete initial v2.0 documentation #33
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-22 23:00:26 -06:00
b8c62612d8 refactor 2025-02-22 22:01:37 -06:00
521874a56f Complete initial v2.0 documentation #33
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-22 19:59:22 -06:00
f41ad47262 updated CHANGES.md
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
2025-02-22 11:36:20 -06:00
8bb2eeb88c updated CHANGELOG.md
Some checks failed
BlockStorage/repertory/pipeline/head There was a failure building this commit
2025-02-22 10:07:52 -06:00
b1aca46034 updated version 2025-02-22 09:58:57 -06:00
24418ba03d v2.0.4-rc (#37)
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
2025-02-22 09:48:00 -06:00
132 changed files with 4250 additions and 1485 deletions

View File

@ -154,6 +154,7 @@ mtune
musl-libc
nana
ncrypt
nlohmann
nlohmann_json
nmakeprg
nominmax
@ -192,6 +193,7 @@ secp256k1
secur32
sfml_project
shlwapi
skynet
source_subdir
spdlog
spdlog_project

View File

@ -1,7 +1,47 @@
# Changelog
## v2.0.5-rc
### Issues
* ~~\#12 [Unit Test] Complete all providers unit tests~~
* ~~\#21 [Unit Test] Complete WinFSP unit tests~~
* ~~\#22 [Unit Test] Complete FUSE unit tests~~
### Changes from v2.0.4-rc
* Continue documentation updates
## v2.0.4-rc
### BREAKING CHANGES
* `renterd` v2.0.0+ is now required. Prior versions will fail to mount.
<!-- markdownlint-disable-next-line -->
### 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
<!-- markdownlint-disable-next-line -->
### Issues
* \#28 \[bug\] Address slow directory responses in S3 mounts for deeply nested directories

View File

@ -58,6 +58,10 @@ if(PROJECT_IS_MINGW)
endif()
endif()
if (PROJECT_ENABLE_V2_ERRORS)
add_definitions(-DPROJECT_ENABLE_V2_ERRORS)
endif()
include(cmake/settings.cmake)
include(cmake/flags.cmake)
@ -143,6 +147,7 @@ endif()
-DPROJECT_COPYRIGHT=${PROJECT_COPYRIGHT}
-DPROJECT_DESC=${PROJECT_DESC}
-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_BOOST=${PROJECT_ENABLE_BOOST}
-DPROJECT_ENABLE_CPP_HTTPLIB=${PROJECT_ENABLE_CPP_HTTPLIB}

471
README.md
View File

@ -3,24 +3,55 @@
Repertory allows you to mount S3 and Sia via FUSE on Linux or via WinFSP
on Windows.
## Contents
1. [Details and Features](#details-and-features)
2. [Minimum Requirements](#minimum-requirements)
1. [Supported Operating Systems](#supported-operating-systems)
3. [Usage](#usage)
1. [Important Options](#important-options)
2. [Sia](#sia)
* [Sia Initial Configuration](#sia-initial-configuration)
* [Sia Mounting](#sia-mounting)
* [Sia Configuration File](#sia-configuration-file)
3. [S3](#s3)
* [S3 Initial Configuration](#s3-initial-configuration)
* [S3 Mounting](#s3-mounting)
* [S3 Configuration File](#s3-configuration-file)
4. [Data Directories](#data-directories)
1. [Linux Directories](#linux-directories)
2. [Windows Directories](#windows-directories)
5. [Remote Mounting](#remote-mounting)
1. [Server Setup](#server-setup)
* [Remote Mount Configuration File Section](#remote-mount-configuration-file-section)
2. [Client Setup](#client-setup)
* [Client Remote Mounting](#client-remote-mounting)
* [Remote Mount Configuration File](#remote-mount-configuration-file)
6. [Compiling](#compiling)
1. [Linux Compilation](#linux-compilation)
2. [Windows Setup](#windows-compilation)
7. [Credits](#credits)
8. [Developer Public Key](#developer-public-key)
9. [Consult the Wiki for additional information](https://git.fifthgrid.com/BlockStorage/repertory/wiki)
## Details and Features
* Optimized for [Plex Media Server](https://www.plex.tv/)
* Single application to mount S3 and/or Sia
* Remote mounting of Repertory instances on Linux and Windows
* Remote mounting of `repertory` instances on Linux and Windows
* Securely share your mounts over TCP/IP via `XChaCha20-Poly1305` with other systems on your network or over the internet.
* Cross-platform support (Linux 64-bit, Linux arm64/aarch64, Windows 64-bit)
* Optionally encrypt file names and file data via `XChaCha20-Poly1305` in S3 mounts
## Minimum Requirements
* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v0.4.0+ for Sia support
* Only 64-bit operating systems are supported
* By default, Linux requires `fusermount3`; otherwise, `repertory` must be manually compiled with `libfuse2` support
* Windows requires the following dependencies to be installed:
* [WinFSP 2023](https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi)
* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v2.0.0+ for Sia support
* Linux requires `fusermount3`; otherwise, `repertory` must be manually compiled with `libfuse2` support
* Windows requires the following dependencies to be installed:
* [WinFSP 2023](https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi)
## Supported Operating Systems
### Supported Operating Systems
Only 64-bit operating systems are supported
* Linux `arm64/aarch64`
* Linux `amd64`
@ -28,124 +59,356 @@ on Windows.
## Usage
### Sia
* Initial Configuration
* Sia steps:
* Set the appropriate bucket name and `renterd` API password in `repertory` configuration:
* To use `default` as the bucket name and configuration name:
* `repertory -set HostConfig.ApiPassword '<my password>'`
* To use a different bucket name with `default` as the configuration name:
* `repertory -set HostConfig.ApiPassword '<my password>'`
* `repertory -set SiaConfig.Bucket '<my bucket>'`
* For all other configurations:
* `repertory --name '<my config name>' -set HostConfig.ApiPassword '<my password>'`
* `repertory --name '<my config name>' -set SiaConfig.Bucket '<my bucket name>'`
* To verify/view all configuration options:
* `repertory -dc`
* `repertory --name '<my config name>' -dc`
* Example:
* `repertory --name default -dc`
* Mounting on Linux:
* `repertory /mnt/location`
* `repertory --name '<my config name>' /mnt/location`
* Example:
* `repertory --name default /mnt/location`
* Mounting on Windows:
* `repertory t:`
* `repertory --name '<my config name>' t:`
* Example:
* `repertory --name default t:`
### S3
* Initial Configuration
* S3 steps:
* Set the appropriate base URL:
* `repertory -s3 --name '<my config name>' -set S3Config.URL '<my url>'`
* Example:
* `repertory -s3 --name minio -set S3Config.URL 'http://localhost:9000'`
* Set the appropriate bucket name:
* `repertory -s3 --name '<my config name>' -set S3Config.Bucket '<my bucket name>'`
* Set the appropriate access key:
* `repertory -s3 --name '<my config name>' -set S3Config.AccessKey '<my access key>'`
* Set the appropriate secret key:
* `repertory -s3 --name '<my config name>' -set S3Config.SecretKey '<my secret key>'`
* For Sia and most local S3 gateway instances, enable path style URL's:
* `repertory -s3 --name '<my config name>' -set S3Config.UsePathStyle true`
* Optional steps:
* Set an appropriate region. Default is set to `any`:
* `repertory -s3 --name '<my config name>' -set S3Config.Region '<my region>'`
* Enable encrypted file names and file data. Set a strong, random encryption token and be sure to store it in a secure backup location:
* `repertory -s3 --name '<my config name>' -set S3Config.EncryptionToken '<my strong password>'`
* To verify/view all configuration options:
* `repertory -s3 --name '<my config name>' -dc`
* Example:
* `repertory -s3 --name minio -dc`
* Mounting on Linux:
* `repertory -s3 --name '<my config name>' /mnt/location`
* Example:
* `repertory -s3 --name minio /mnt/location`
* Mounting on Windows:
* `repertory -s3 --name '<my config name>' t:`
* Example:
* `repertory -s3 --name minio t:`
### Notable Options
### Important Options
* `--help`
* Display all mount utility options
* `-f`
* Keep process in foreground on Linux.
* `--name, -na [name]`
* Identifies a unique configuration name to support multiple mounts.
* The `--name` option can be set to any valid value allowed as a file name for your filesystem.
* For Sia, the bucket name will be set to the same value if it is empty in the configuration file.
* If the `--name` option is not specified, `default` will be used.
* For S3, the `--name` option is required and does not affect the bucket name.
* `-dc`
* Display mount configuration
* For Sia, `--name` is optional
* For S3, the `-s3` option is required along with `--name`
### Sia
#### Sia Initial Configuration
* Required steps:
* Set the appropriate bucket name and `renterd` API password in `repertory` configuration:
* To use `default` as the bucket name and configuration name, you only need to set the `renterd` API password:
* `repertory -set HostConfig.ApiPassword '<my password>'`
* To specify a different bucket name while using `default` as the configuration name:
* `repertory -set HostConfig.ApiPassword '<my password>'`
* `repertory -set SiaConfig.Bucket '<my bucket>'`
* For all other configurations:
* `repertory --name '<my config name>' -set HostConfig.ApiPassword '<my password>'`
* `repertory --name '<my config name>' -set SiaConfig.Bucket '<my bucket name>'`
* Optional steps:
* Set a user name used during `renterd` basic authentication:
* `repertory -set HostConfig.ApiUser '<my user>'`
* `repertory --name '<my config name>' -set HostConfig.ApiUser '<my user>'`
* Set a custom agent string (default `Sia-Agent`):
* `repertory -set HostConfig.AgentString '<my agent>'`
* `repertory --name '<my config name>' -set HostConfig.AgentString '<my agent>'`
* Set the host name or IP of the `renterd` instance (default `localhost`):
* `repertory -set HostConfig.HostNameOrIp '<my host name>'`
* `repertory --name '<my config name>' -set HostConfig.HostNameOrIp '<my host name>'`
* Set the `renterd` API port (default `9980`):
* `repertory -set HostConfig.ApiPort 9981`
* `repertory --name '<my config name>' -set HostConfig.ApiPort 9981`
* To verify/view all configuration options:
* `repertory -dc`
* `repertory --name '<my config name>' -dc`
* Example:
* `repertory --name default -dc`
#### Sia Mounting
* Linux:
* `repertory /mnt/location`
* `repertory --name '<my config name>' /mnt/location`
* Example:
* `repertory --name default /mnt/location`
* Windows:
* `repertory t:`
* `repertory --name '<my config name>' t:`
* Example:
* `repertory --name default t:`
#### Sia Configuration File
```json
{
"ApiAuth": "<random generated rpc password>",
"ApiPort": 10000,
"ApiUser": "repertory",
"DatabaseType": "rocksdb",
"DownloadTimeoutSeconds": 30,
"EnableDownloadTimeout": true,
"EnableDriveEvents": false,
"EventLevel": "info",
"EvictionDelayMinutes": 1,
"EvictionUseAccessedTime": false,
"HighFreqIntervalSeconds": 30,
"HostConfig": {
"AgentString": "Sia-Agent",
"ApiPassword": "<renterd api password>",
"ApiPort": 9980,
"ApiUser": "",
"HostNameOrIp": "localhost",
"Path": "",
"Protocol": "http",
"TimeoutMs": 60000
},
"LowFreqIntervalSeconds": 3600,
"MaxCacheSizeBytes": 21474836480,
"MaxUploadCount": 5,
"MedFreqIntervalSeconds": 120,
"OnlineCheckRetrySeconds": 60,
"PreferredDownloadType": "default",
"RemoteMount": {
"ApiPort": 20000,
"ClientPoolSize": 20,
"Enable": false,
"EncryptionToken": ""
},
"RetryReadCount": 6,
"RingBufferFileSize": 512,
"SiaConfig": {
"Bucket": "default"
},
"TaskWaitMs": 100,
"Version": 1
}
```
### S3
#### S3 Initial Configuration
* Required steps:
* Set the appropriate base URL:
* `repertory -s3 --name '<my config name>' -set S3Config.URL '<my url>'`
* Example:
* `repertory -s3 --name minio -set S3Config.URL 'http://localhost:9000'`
* Set the appropriate bucket name:
* `repertory -s3 --name '<my config name>' -set S3Config.Bucket '<my bucket name>'`
* Set the appropriate access key:
* `repertory -s3 --name '<my config name>' -set S3Config.AccessKey '<my access key>'`
* Set the appropriate secret key:
* `repertory -s3 --name '<my config name>' -set S3Config.SecretKey '<my secret key>'`
* For Sia and most local S3 gateway instances, enable path style URL's:
* `repertory -s3 --name '<my config name>' -set S3Config.UsePathStyle true`
* Optional steps:
* Set an appropriate region. Default is set to `any`:
* `repertory -s3 --name '<my config name>' -set S3Config.Region '<my region>'`
* Enable encrypted file names and file data. Set a strong, random encryption token and be sure to store it in a secure backup location:
* `repertory -s3 --name '<my config name>' -set S3Config.EncryptionToken '<my strong password>'`
* To verify/view all configuration options:
* `repertory -s3 --name '<my config name>' -dc`
* Example:
* `repertory -s3 --name minio -dc`
#### S3 Mounting
* Linux:
* `repertory -s3 --name '<my config name>' /mnt/location`
* Example:
* `repertory -s3 --name minio /mnt/location`
* Windows:
* `repertory -s3 --name '<my config name>' t:`
* Example:
* `repertory -s3 --name minio t:`
#### S3 Configuration File
```json
{
"ApiAuth": "<random generated rpc password>",
"ApiPort": 10100,
"ApiUser": "repertory",
"DatabaseType": "rocksdb",
"DownloadTimeoutSeconds": 30,
"EnableDownloadTimeout": true,
"EnableDriveEvents": false,
"EventLevel": "info",
"EvictionDelayMinutes": 1,
"EvictionUseAccessedTime": false,
"HighFreqIntervalSeconds": 30,
"LowFreqIntervalSeconds": 3600,
"MaxCacheSizeBytes": 21474836480,
"MaxUploadCount": 5,
"MedFreqIntervalSeconds": 120,
"OnlineCheckRetrySeconds": 60,
"PreferredDownloadType": "default",
"RemoteMount": {
"ApiPort": 20100,
"ClientPoolSize": 20,
"Enable": false,
"EncryptionToken": ""
},
"RetryReadCount": 6,
"RingBufferFileSize": 512,
"S3Config": {
"AccessKey": "<my access key>",
"Bucket": "<my bucket name>",
"EncryptionToken": "",
"Region": "any",
"SecretKey": "<my secret key>",
"TimeoutMs": 60000,
"URL": "http://localhost:9000",
"UsePathStyle": true,
"UseRegionInURL": false
},
"TaskWaitMs": 100,
"Version": 1
}
```
### Data Directories
* Linux
* `~/.local/repertory2`
* Windows
* `%LOCALAPPDATA%\repertory2`
* Example:
* `C:\Users\Tom\AppData\Local\repertory2`
* IMPORTANT:
* It is highly recommended to exclude this folder from any anti-virus/anti-malware applications as severe performance issues may arise.
* Excluding the mounted drive letter is also highly recommended.
#### Linux Directories
* `~/.local/repertory2/s3`
* `~/.local/repertory2/sia`
#### Windows Directories
* `%LOCALAPPDATA%\repertory2\s3`
* `%LOCALAPPDATA%\repertory2\sia`
* Examples:
* `C:\Users\Tom\AppData\Local\repertory2\s3`
* `C:\Users\Tom\AppData\Local\repertory2\sia`
* IMPORTANT:
* It is highly recommended to exclude this folder from any anti-virus/anti-malware applications as severe performance issues may arise.
* Excluding the mounted drive letter is also highly recommended.
## Remote Mounting
`Repertory` allows local mounts to be shared with other computers on your network.
This option is referred to as remote mounting. Instructions TBD.
`repertory` allows local mounts to be shared with other computers on your network
or over the internet. This option is referred to as remote mounting.
### Server Setup
The following steps must be performed on the mount you wish to share with
other systems. Changes to configuration will not take affect while a mount is
active, so it is recommended to unmount beforehand.
* Required steps:
* Enable remote mount:
* Sia
* `repertory -set RemoteMount.Enable true`
* `repertory --name '<my config name>' -set RemoteMount.Enable true`
* S3:
* `repertory -s3 --name '<my config name>' -set RemoteMount.Enable true`
* Set a secure encryption token:
* Sia:
* `repertory -set RemoteMount.EncryptionToken '<my secure password>'`
* `repertory --name '<my config name>' -set RemoteMount.EncryptionToken '<my secure password>'`
* S3:
* `repertory -s3 --name '<my config name>' -set RemoteMount.EncryptionToken '<my secure password>'`
* Optional steps:
* Change the port clients will use to connect to your mount:
* Sia:
* `repertory -set RemoteMount.ApiPort 20000`
* `repertory --name '<my config name>' -set RemoteMount.ApiPort 20000`
* S3:
* `repertory -s3 --name '<my config name>' -set RemoteMount.ApiPort 20000`
* IMPORTANT:
* Be sure to configure your firewall to allow incoming TCP connections on the port configured in `RemoteMount.ApiPort`.
#### Remote Mount Configuration File Section
```json
{
...
"RemoteMount": {
"ApiPort": 20000,
"ClientPoolSize": 20,
"Enable": true,
"EncryptionToken": "<my secure password>"
},
...
}
```
### Client Setup
Client configuration is provider agnostic, so there's no need to specify `-s3`
for S3 providers.
* Required steps:
* Set the encryption token to the same value configured during server setup:
* `repertory -rm <host name or IP>:<port> -set RemoteConfig.EncryptionToken '<my secure password>'`
* Replace `<host name or IP>` with the host name or IP of the server
* Replace `<port>` with the value of `RemoteMount.ApiPort` used in the server configuration
* Example:
* `repertory -rm 192.168.1.10:20000 -set RemoteConfig.EncryptionToken '<my secure password>'`
* `repertory -rm my.host.com:20000 -set RemoteConfig.EncryptionToken '<my secure password>'`
#### Client Remote Mounting
* Linux:
* `repertory -rm <host name or IP>:<port> /mnt/location`
* Example:
* `repertory -rm 192.168.1.10:20000 /mnt/location`
* Windows:
* `repertory -rm <host name or IP>:<port> t:`
* Example:
* `repertory -rm 192.168.1.10:20000 t:`
#### Remote Mount Configuration File
```json
{
"ApiAuth": "<random generated rpc password>",
"ApiPort": 10010,
"ApiUser": "repertory",
"EnableDriveEvents": false,
"EventLevel": "info",
"RemoteConfig": {
"ApiPort": 20000,
"EncryptionToken": "<my secure password>",
"HostNameOrIp": "192.168.1.10",
"MaxConnections": 20,
"ReceiveTimeoutMs": 120000,
"SendTimeoutMs": 30000
},
"TaskWaitMs": 100,
"Version": 1
}
```
## Compiling
* Successful compilation will result in all required files being placed in the `dist/` directory
* Linux
Successful compilation will result in all files required for execution to be placed
in the `dist/` directory
### Linux Compilation
* Ensure `docker` is installed
* For x86_64:
* RelWithDebInfo: `scripts/make_unix.sh`
* Release: `scripts/make_unix.sh x86_64 Release`
* Debug: `scripts/make_unix.sh x86_64 Debug`
* For aarch64:
* RelWithDebInfo: `scripts/make_unix.sh aarch64`
* Release: `scripts/make_unix.sh aarch64 Release`
* Debug: `scripts/make_unix.sh aarch64 Debug`
### Windows Compilation
* OFFICIAL: Cross-compiling on Linux
* Ensure `docker` is installed
* For x86_64:
* RelWithDebInfo: `scripts/make_unix.sh`
* Release: `scripts/make_unix.sh x86_64 Release`
* Debug: `scripts/make_unix.sh x86_64 Debug`
* For aarch64:
* RelWithDebInfo: `scripts/make_unix.sh aarch64`
* Release: `scripts/make_unix.sh aarch64 Release`
* Debug: `scripts/make_unix.sh aarch64 Debug`
* Windows
* OFFICIAL: Cross-compiling on Linux
* Ensure `docker` is installed
* RelWithDebInfo: `scripts/make_win32.sh`
* Release: `scripts/make_win32.sh x86_64 Release`
* Debug: `scripts/make_win32.sh x86_64 Debug`
* UNOFFICIAL: Compiling on Windows
* Ensure latest [MSYS2](https://www.msys2.org/) is installed
* RelWithDebInfo: `scripts\make_win32.cmd`
* Release: `scripts\make_win32.cmd x86_64 Release`
* Debug: `scripts\make_win32.cmd x86_64 Debug`
* RelWithDebInfo: `scripts/make_win32.sh`
* Release: `scripts/make_win32.sh x86_64 Release`
* Debug: `scripts/make_win32.sh x86_64 Debug`
* UNOFFICIAL: Compiling on Windows
* Ensure latest [MSYS2](https://www.msys2.org/) is installed
* RelWithDebInfo: `scripts\make_win32.cmd`
* Release: `scripts\make_win32.cmd x86_64 Release`
* Debug: `scripts\make_win32.cmd x86_64 Debug`
## Credits

View File

@ -1,20 +1,20 @@
set(BINUTILS_HASH b53606f443ac8f01d1d5fc9c39497f2af322d99e14cea5c0b4b124d630379365)
set(BOOST2_HASH 7bd7ddceec1a1dfdcbdb3e609b60d01739c38390a5f956385a12f3122049f0ca)
set(BOOST_HASH f55c340aa49763b1925ccf02b2e83f35fdcf634c9d5164a2acb87540173c741d)
set(CPP_HTTPLIB_HASH 405abd8170f2a446fc8612ac635d0db5947c0d2e156e32603403a4496255ff00)
set(CURL_HASH 5a231145114589491fc52da118f9c7ef8abee885d1cb1ced99c7290e9a352f07)
set(BOOST2_HASH 7bd7ddceec1a1dfdcbdb3e609b60d01739c38390a5f956385a12f3122049f0ca)
set(CPP_HTTPLIB_HASH c9b9e0524666e1cd088f0874c57c1ce7c0eaa8552f9f4e15c755d5201fc8c608)
set(CURL_HASH 6edc063d1ebaf9cf3b3b46e9fef2f3cd8932694989ecd43d005d6e828426d09f)
set(EXPAT_HASH 372b18f6527d162fa9658f1c74d22a37429b82d822f5a1e1fc7e00f6045a06a2)
set(GCC_HASH 7d376d445f93126dc545e2c0086d0f647c3094aae081cdb78f42ce2bc25e7293)
set(GTEST_HASH 7b42b4d6ed48810c5362c265a17faebe90dc2373c885e5216439d37927f02926)
set(GTEST_HASH 78c676fc63881529bf97bf9d45948d905a66833fbfa5318ea2cd7478cb98f399)
set(ICU_HASH a2c443404f00098e9e90acf29dc318e049d2dc78d9ae5f46efb261934a730ce2)
set(JSON_HASH 0d8ef5af7f9794e3263480193c491549b2ba6cc74bb018906202ada498a79406)
set(LIBSODIUM_HASH 8e5aeca07a723a27bbecc3beef14b0068d37e7fc0e97f51b3f1c82d2a58005c1)
set(MINGW_HASH 30e5aad2c48dd318150f79cff47661232c4175876d6b4d6b270961cf2b49a48b)
set(OPENSSL_HASH e15dda82fe2fe8139dc2ac21a36d4ca01d5313c75f99f46c4e8a27709b7294bf)
set(MINGW_HASH cc41898aac4b6e8dd5cffd7331b9d9515b912df4420a3a612b5ea2955bbeed2f)
set(OPENSSL_HASH 002a2d6b30b58bf4bea46c43bdd96365aaf8daa6c428782aa4feee06da197df3)
set(PKG_CONFIG_HASH 6fc69c01688c9458a57eb9a1664c9aba372ccda420a02bf4429fe610e7e7d591)
set(PUGIXML_HASH 2f10e276870c64b1db6809050a75e11a897a8d7456c4be5c6b2e35a11168a015)
set(ROCKSDB_HASH 9b810c81731835fda0d4bbdb51d3199d901fa4395733ab63752d297da84c5a47)
set(SPDLOG_HASH 9962648c9b4f1a7bbc76fd8d9172555bad1871fdb14ff4f842ef87949682caa5)
set(SQLITE_HASH 77823cb110929c2bcb0f5d48e4833b5c59a8a6e40cdea3936b99e199dbbe5784)
set(PUGIXML_HASH 655ade57fa703fb421c2eb9a0113b5064bddb145d415dd1f88c79353d90d511a)
set(ROCKSDB_HASH fdccab16133c9d927a183c2648bcea8d956fb41eb1df2aacaa73eb0b95e43724)
set(SPDLOG_HASH 25c843860f039a1600f232c6eb9e01e6627f7d030a2ae5e232bdd3c9205d26cc)
set(SQLITE_HASH 6cebd1d8403fc58c30e93939b246f3e6e58d0765a5cd50546f16c00fd805d2c3)
set(STDUUID_HASH b1176597e789531c38481acbbed2a6894ad419aab0979c10410d59eb0ebf40d3)
set(ZLIB_HASH 17e88863f3600672ab49182f217281b6fc4d3c762bde361935e436a95214d05c)

View File

@ -120,11 +120,11 @@ if(PROJECT_ENABLE_BOOST)
--with-libraries=atomic,chrono,date_time,filesystem,iostreams,locale,log,program_options,random,regex,serialization,system,test,thread
BUILD_COMMAND
./b2
-j1
-j$ENV{CMAKE_BUILD_PARALLEL_LEVEL}
${BOOST_BUILD_ARGS}
INSTALL_COMMAND
./b2
-j1
-j$ENV{CMAKE_BUILD_PARALLEL_LEVEL}
${BOOST_BUILD_ARGS}
install
)

View File

@ -15,10 +15,13 @@ if(PROJECT_ENABLE_CPP_HTTPLIB)
CMAKE_ARGS ${PROJECT_EXTERNAL_CMAKE_FLAGS}
-DBUILD_SHARED_LIBS=${PROJECT_BUILD_SHARED_LIBS}
-DBUILD_STATIC_LIBS=ON
-DHTTPLIB_REQUIRE_OPENSSL=${PROJECT_ENABLE_OPENSSL}
-DHTTPLIB_REQUIRE_ZLIB=ON
-DHTTPLIB_REQUIRE_BROTLI=OFF
-DHTTPLIB_REQUIRE_OPENSSL=ON
-DHTTPLIB_REQUIRE_ZLIB=ON
-DHTTPLIB_TEST=OFF
-DHTTPLIB_USE_BROTLI_IF_AVAILABLE=OFF
-DHTTPLIB_USE_OPENSSL_IF_AVAILABLE=ON
-DHTTPLIB_USE_ZLIB_IF_AVAILABLE=ON
-DOPENSSL_USE_STATIC_LIBS=${OPENSSL_USE_STATIC_LIBS}
)

View File

@ -18,8 +18,9 @@ if(PROJECT_ENABLE_CURL)
URL ${PROJECT_3RD_PARTY_DIR}/curl-${CURL_VERSION}.tar.gz
URL_HASH SHA256=${CURL_HASH}
LIST_SEPARATOR |
CMAKE_ARGS
${PROJECT_EXTERNAL_CMAKE_FLAGS}
BUILD_COMMAND
${CMAKE_COMMAND} --build . -- -j$ENV{CMAKE_BUILD_PARALLEL_LEVEL}
CMAKE_ARGS ${PROJECT_EXTERNAL_CMAKE_FLAGS}
-DBUILD_CURL_EXE=OFF
-DBUILD_LIBCURL_DOCS=OFF
-DBUILD_MISC_DOCS=OFF
@ -28,6 +29,7 @@ if(PROJECT_ENABLE_CURL)
-DBUILD_STATIC_LIBS=ON
-DBUILD_STATIC_LIBS=ON
-DBUILD_TESTING=OFF
-DCURL_BROTLI=OFF
-DCURL_CA_BUNDLE=./cacert.pem
-DCURL_CA_FALLBACK=ON
-DCURL_DISABLE_LDAP=ON

View File

@ -9,6 +9,8 @@ if(PROJECT_ENABLE_ROCKSDB)
URL ${PROJECT_3RD_PARTY_DIR}/rocksdb-${ROCKSDB_VERSION}.tar.gz
URL_HASH SHA256=${ROCKSDB_HASH}
LIST_SEPARATOR |
BUILD_COMMAND
${CMAKE_COMMAND} --build . -- -j$ENV{CMAKE_BUILD_PARALLEL_LEVEL}
CMAKE_ARGS ${PROJECT_EXTERNAL_CMAKE_FLAGS}
-DBUILD_SHARED_LIBS=OFF
-DBUILD_STATIC_LIBS=ON
@ -31,4 +33,4 @@ if(PROJECT_ENABLE_ROCKSDB)
list(APPEND PROJECT_DEPENDENCIES rocksdb_project)
endif()
endif()
endif()

View File

@ -2,7 +2,7 @@ if(PROJECT_ENABLE_SQLITE)
if(PROJECT_BUILD)
add_definitions(-DPROJECT_ENABLE_SQLITE)
if (PROJECT_IS_MINGW AND NOT PROJECT_IS_MINGW_UNIX)
pkg_check_modules(SQLITE3 REQUIRED sqlite3>=${SQLITE2_VERSION})
pkg_check_modules(SQLITE3 REQUIRED sqlite3)
include_directories(SYSTEM BEFORE ${SQLITE3_INCLUDE_DIRS})
link_libraries(${SQLITE3_LIBRARIES})
else()

View File

@ -1,28 +1,28 @@
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_MINOR_VERSION 76)
set(BOOST2_PATCH_VERSION 0)
set(CPP_HTTPLIB_VERSION 0.18.1)
set(CURL_VERSION 8.11.0)
set(CURL2_VERSION 8_11_0)
set(EXPAT_VERSION 2.6.4)
set(BOOST_MAJOR_VERSION 1)
set(BOOST_MINOR_VERSION 87)
set(BOOST_PATCH_VERSION 0)
set(CPP_HTTPLIB_VERSION 0.19.0)
set(CURL2_VERSION 8_12_1)
set(CURL_VERSION 8.12.1)
set(EXPAT2_VERSION 2_6_4)
set(EXPAT_VERSION 2.6.4)
set(GCC_VERSION 14.2.0)
set(GTEST_VERSION 1.15.2)
set(GTEST_VERSION 1.16.0)
set(ICU_VERSION 76-1)
set(JSON_VERSION 3.11.3)
set(LIBSODIUM_VERSION 1.0.20)
set(MESA_VERSION 23.3.3)
set(MINGW_VERSION 12.0.0)
set(OPENSSL_VERSION 3.4.0)
set(OPENSSL_VERSION 3.4.1)
set(PKG_CONFIG_VERSION 0.29.2)
set(PUGIXML_VERSION 1.14)
set(ROCKSDB_VERSION 9.7.4)
set(SPDLOG_VERSION 1.15.0)
set(SQLITE_VERSION 3460100)
set(SQLITE2_VERSION 3.46.1)
set(PUGIXML_VERSION 1.15)
set(ROCKSDB_VERSION 9.10.0)
set(SPDLOG_VERSION 1.15.1)
set(SQLITE2_VERSION 3.49.1)
set(SQLITE_VERSION 3490100)
set(STDUUID_VERSION 1.2.3)
set(ZLIB_VERSION 1.3.1)

View File

@ -10,7 +10,7 @@ PROJECT_DESC="Mount utility for Sia and S3"
PROJECT_MAJOR_VERSION=2
PROJECT_MINOR_VERSION=0
PROJECT_REVISION_VERSION=3
PROJECT_REVISION_VERSION=5
PROJECT_RELEASE_NUM=0
PROJECT_RELEASE_ITER=rc
@ -19,6 +19,8 @@ PROJECT_APP_LIST=(${PROJECT_NAME})
PROJECT_PRIVATE_KEY=${DEVELOPER_PRIVATE_KEY}
PROJECT_PUBLIC_KEY=${DEVELOPER_PUBLIC_KEY}
PROJECT_FLUTTER_BASE_HREF="/ui/"
PROJECT_ENABLE_WIN32_LONG_PATH_NAMES=OFF
PROJECT_ENABLE_BACKWARD_CPP=OFF

View File

@ -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>
CMD bash

View File

@ -1,4 +1,5 @@
FROM alpine:3.21.0
#comment
FROM alpine:3.21.3
MAINTAINER Scott E. Graves <scott.e.graves@protonmail.com>
CMD bash

48
docker/x86_64/flutter Normal file
View File

@ -0,0 +1,48 @@
FROM debian:latest
ARG UID=0
ARG GID=0
RUN apt-get update
RUN apt-get install -y \
bash \
curl \
fonts-droid-fallback \
gdb \
git \
lib32stdc++6 \
libgconf-2-4 \
libglu1-mesa \
libstdc++6 \
python3 \
unzip \
wget
RUN apt-get clean
RUN git clone https://github.com/flutter/flutter.git /flutter
RUN git config --system --add safe.directory /flutter
ENV PATH="/flutter/bin:/flutter/bin/cache/dart-sdk/bin:${PATH}"
RUN flutter doctor -v
RUN flutter channel master
RUN flutter upgrade
RUN flutter --disable-analytics
RUN flutter config --no-analytics
RUN flutter config --enable-web
RUN flutter config --no-cli-animations
RUN mkdir /nonexistent
RUN chown -R $UID:$GID /nonexistent
RUN mkdir /.config
RUN chown -R $UID:$GID /.config
RUN mkdir /.dart-tool
RUN chown -R $UID:$GID /.dart-tool
RUN mkdir /.pub-cache
RUN chown -R $UID:$GID /.pub-cache
RUN chown -R $UID:$GID /flutter

View File

@ -1,5 +1,5 @@
#comment
FROM alpine:3.21.0
FROM alpine:3.21.3
RUN apk update
RUN apk upgrade
@ -679,6 +679,7 @@ RUN if [ -f "/3rd_party/curl-${MY_CURL_VERSION}.tar.gz" ]; then \
-DCMAKE_CXX_STANDARD=${MY_CXX_STANDARD} \
-DCMAKE_INSTALL_PREFIX=${MY_MINGW_DIR} \
-DCMAKE_TOOLCHAIN_FILE=${MY_TOOLCHAIN_FILE_CMAKE} \
-DCURL_BROTLI=OFF \
-DCURL_CA_BUNDLE=./cacert.pem \
-DCURL_CA_FALLBACK=ON \
-DCURL_DISABLE_LDAP=ON \
@ -714,6 +715,9 @@ RUN if [ -f "/3rd_party/cpp-httplib-${MY_CPP_HTTPLIB_VERSION}.tar.gz" ]; then \
-DHTTPLIB_REQUIRE_OPENSSL=ON \
-DHTTPLIB_REQUIRE_ZLIB=ON \
-DHTTPLIB_TEST=OFF \
-DHTTPLIB_USE_BROTLI_IF_AVAILABLE=OFF \
-DHTTPLIB_USE_OPENSSL_IF_AVAILABLE=YES \
-DHTTPLIB_USE_ZLIB_IF_AVAILABLE=ON \
&& make -j${MY_NUM_JOBS} \
&& make install \
&& cd ${MY_WORKDIR} \

View File

@ -31,26 +31,28 @@ private:
static stop_type stop_requested;
public:
[[nodiscard]] static auto
default_agent_name(const provider_type &prov) -> std::string;
[[nodiscard]] static auto default_agent_name(const provider_type &prov)
-> std::string;
[[nodiscard]] static auto
default_api_port(const provider_type &prov) -> std::uint16_t;
[[nodiscard]] static auto default_api_port(const provider_type &prov)
-> std::uint16_t;
[[nodiscard]] static auto
default_data_directory(const provider_type &prov) -> std::string;
[[nodiscard]] static auto default_data_directory(const provider_type &prov)
-> std::string;
[[nodiscard]] static auto
default_remote_api_port(const provider_type &prov) -> std::uint16_t;
[[nodiscard]] static auto default_remote_api_port(const provider_type &prov)
-> std::uint16_t;
[[nodiscard]] static auto
default_rpc_port(const provider_type &prov) -> std::uint16_t;
[[nodiscard]] static auto default_rpc_port(const provider_type &prov)
-> std::uint16_t;
[[nodiscard]] static auto
get_provider_display_name(const provider_type &prov) -> std::string;
[[nodiscard]] static auto get_provider_display_name(const provider_type &prov)
-> std::string;
[[nodiscard]] static auto
get_provider_name(const provider_type &prov) -> std::string;
[[nodiscard]] static auto get_provider_name(const provider_type &prov)
-> std::string;
[[nodiscard]] static auto get_root_data_directory() -> std::string;
public:
[[nodiscard]] static auto get_stop_requested() -> bool;
@ -91,7 +93,6 @@ private:
std::atomic<std::uint8_t> max_upload_count_;
std::atomic<std::uint16_t> med_freq_interval_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<std::uint16_t> retry_read_count_;
std::atomic<std::uint16_t> ring_buffer_file_size_;
@ -172,8 +173,6 @@ public:
[[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_provider_type() const -> provider_type;
@ -192,8 +191,11 @@ public:
[[nodiscard]] auto get_task_wait_ms() const -> std::uint16_t;
[[nodiscard]] auto
get_value_by_name(const std::string &name) const -> std::string;
[[nodiscard]] auto get_value_by_name(const std::string &name) const
-> std::string;
[[nodiscard]] auto get_raw_value_by_name(const std::string &name) const
-> std::string;
[[nodiscard]] auto get_version() const -> std::uint64_t;
@ -239,8 +241,6 @@ public:
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_remote_config(remote::remote_config value);

View File

@ -57,7 +57,7 @@ using json = nlohmann::json;
inline constexpr const std::string_view REPERTORY = "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_MIN_REMOTE_VERSION = "2.0.0";
@ -221,44 +221,25 @@ using WCHAR = wchar_t;
#define MAX_PATH 260
#define STATUS_SUCCESS \
std::uint32_t { 0U }
#define STATUS_ACCESS_DENIED \
std::uint32_t { 0xC0000022L }
#define STATUS_DEVICE_BUSY \
std::uint32_t { 0x80000011L }
#define STATUS_DEVICE_INSUFFICIENT_RESOURCES \
std::uint32_t { 0xC0000468L }
#define STATUS_DIRECTORY_NOT_EMPTY \
std::uint32_t { 0xC0000101L }
#define STATUS_FILE_IS_A_DIRECTORY \
std::uint32_t { 0xC00000BAL }
#define STATUS_FILE_TOO_LARGE \
std::uint32_t { 0xC0000904L }
#define STATUS_INSUFFICIENT_RESOURCES \
std::uint32_t { 0xC000009AL }
#define STATUS_INTERNAL_ERROR \
std::uint32_t { 0xC00000E5L }
#define STATUS_INVALID_ADDRESS \
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 STATUS_SUCCESS std::uint32_t{0U}
#define STATUS_ACCESS_DENIED std::uint32_t{0xC0000022L}
#define STATUS_DEVICE_BUSY std::uint32_t{0x80000011L}
#define STATUS_DEVICE_INSUFFICIENT_RESOURCES std::uint32_t{0xC0000468L}
#define STATUS_DIRECTORY_NOT_EMPTY std::uint32_t{0xC0000101L}
#define STATUS_FILE_IS_A_DIRECTORY std::uint32_t{0xC00000BAL}
#define STATUS_FILE_TOO_LARGE std::uint32_t{0xC0000904L}
#define STATUS_INSUFFICIENT_RESOURCES std::uint32_t{0xC000009AL}
#define STATUS_INTERNAL_ERROR std::uint32_t{0xC00000E5L}
#define STATUS_INVALID_ADDRESS 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) \
((std::uint32_t(e) == STATUS_NOT_IMPLEMENTED) ? -ENOTSUP : e)

View File

@ -26,6 +26,7 @@
#include "comm/packet/packet_client.hpp"
#include "drives/remote/remote_open_file_table.hpp"
#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
#include "types/remote.hpp"
namespace repertory {
class app_config;

View File

@ -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_

View File

@ -85,6 +85,13 @@ private:
void remove_deleted_files(stop_type &stop_requested);
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,
api_meta_map &meta) -> api_error override;

View File

@ -31,6 +31,10 @@ class i_provider {
INTERFACE_SETUP(i_provider);
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,
api_meta_map &meta)
-> api_error = 0;

View File

@ -113,6 +113,13 @@ protected:
-> api_error override;
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)
-> std::uint64_t;

View File

@ -80,6 +80,10 @@ protected:
-> api_error override;
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
-> std::uint64_t override;

View File

@ -48,9 +48,9 @@ public:
[[nodiscard]] auto get_pinned_files() -> rpc_response;
[[nodiscard]] auto pin_file(const std::string &api_file) -> rpc_response;
[[nodiscard]] auto pin_file(const std::string &api_path) -> rpc_response;
[[nodiscard]] auto pinned_status(const std::string &api_file) -> rpc_response;
[[nodiscard]] auto pinned_status(const std::string &api_path) -> rpc_response;
[[nodiscard]] auto set_config_value_by_name(const std::string &name,
const std::string &value)
@ -58,7 +58,7 @@ public:
[[nodiscard]] auto unmount() -> rpc_response;
[[nodiscard]] auto unpin_file(const std::string &api_file) -> rpc_response;
[[nodiscard]] auto unpin_file(const std::string &api_path) -> rpc_response;
};
} // namespace repertory

View File

@ -0,0 +1,82 @@
/*
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_RPC_COMMON_HPP_
#define REPERTORY_INCLUDE_RPC_COMMON_HPP_
#include "utils/base64.hpp"
#include "utils/error_utils.hpp"
#include "utils/string.hpp"
namespace repertory::rpc {
[[nodiscard]] auto check_authorization(const auto &cfg,
const httplib::Request &req) -> bool {
REPERTORY_USES_FUNCTION_NAME();
if (cfg.get_api_auth().empty() || cfg.get_api_user().empty()) {
utils::error::raise_error(function_name,
"authorization user or password is not set");
return false;
}
auto authorization = req.get_header_value("Authorization");
if (authorization.empty()) {
utils::error::raise_error(function_name,
"'Authorization' header is not set");
return false;
}
auto auth_parts = utils::string::split(authorization, ' ', true);
if (auth_parts.empty()) {
utils::error::raise_error(function_name, "'Authorization' header is empty");
return false;
}
auto auth_type = auth_parts[0U];
if (auth_type != "Basic") {
utils::error::raise_error(function_name,
"authorization type is not 'Basic'");
return false;
}
auto data = macaron::Base64::Decode(authorization.substr(6U));
auto auth_str = std::string(data.begin(), data.end());
auto auth = utils::string::split(auth_str, ':', false);
if (auth.size() < 2U) {
utils::error::raise_error(function_name, "authorization data is not valid");
return false;
}
auto user = auth.at(0U);
auth.erase(auth.begin());
auto pwd = utils::string::join(auth, ':');
if ((user != cfg.get_api_user()) || (pwd != cfg.get_api_auth())) {
utils::error::raise_error(function_name, "authorization failed");
return false;
}
return true;
}
} // namespace repertory::rpc
#endif // REPERTORY_INCLUDE_RPC_COMMON_HPP_

View File

@ -40,8 +40,6 @@ private:
std::mutex start_stop_mutex_;
private:
[[nodiscard]] auto check_authorization(const httplib::Request &req) -> bool;
void handle_get_config(const httplib::Request &req, httplib::Response &res);
void handle_get_config_value_by_name(const httplib::Request &req,

View File

@ -24,30 +24,28 @@
namespace repertory {
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_high_freq_interval_secs{30U};
constexpr const auto default_low_freq_interval_secs{0U * 60U};
constexpr const auto default_high_freq_interval_secs{std::uint16_t{30U}};
constexpr const auto default_low_freq_interval_secs{std::uint16_t(60U * 60U)};
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_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_orphaned_file_retention_days{15U};
constexpr const auto default_retry_read_count{6U};
constexpr const auto default_ring_buffer_file_size{512U};
constexpr const auto default_task_wait_ms{100U};
constexpr const auto default_timeout_ms{60000U};
constexpr const auto max_orphaned_file_retention_days{std::uint16_t(31U)};
constexpr const auto default_ui_mgmt_port{std::uint16_t{30000U}};
constexpr const auto max_ring_buffer_file_size{std::uint16_t(1024U)};
constexpr const auto max_s3_object_name_length{1024U};
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_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_ring_buffer_file_size{std::uint16_t(64U)};
constexpr const auto min_task_wait_ms{std::uint16_t(50U)};
@ -283,6 +281,8 @@ enum class exit_code : std::int32_t {
pin_failed = -16,
unpin_failed = -17,
init_failed = -18,
ui_mount_failed = -19,
exception = -20,
};
enum http_error_codes : std::int32_t {
@ -307,6 +307,13 @@ enum class provider_type : std::size_t {
unknown,
};
[[nodiscard]] auto
provider_type_from_string(std::string_view type,
provider_type default_type = provider_type::unknown)
-> provider_type;
[[nodiscard]] auto provider_type_to_string(provider_type type) -> std::string;
#if defined(_WIN32)
struct open_file_data final {
PVOID directory_buffer{nullptr};
@ -333,7 +340,6 @@ struct directory_item final {
bool directory{false};
std::uint64_t size{};
api_meta_map meta;
bool resolved{false};
};
struct encrypt_config final {
@ -493,8 +499,6 @@ inline constexpr const auto JSON_MED_FREQ_INTERVAL_SECS{
inline constexpr const auto JSON_META{"Meta"};
inline constexpr const auto JSON_ONLINE_CHECK_RETRY_SECS{
"OnlineCheckRetrySeconds"};
inline constexpr const auto JSON_ORPHANED_FILE_RETENTION_DAYS{
"OrphanedFileRetentionDays"};
inline constexpr const auto JSON_PATH{"Path"};
inline constexpr const auto JSON_PREFERRED_DOWNLOAD_TYPE{
"PreferredDownloadType"};
@ -619,6 +623,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>
struct adl_serializer<std::atomic<primitive_t>> {
static void to_json(json &data, const std::atomic<primitive_t> &value) {
@ -642,6 +656,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>> {
static void to_json(json &data,
const std::atomic<repertory::download_type> &value) {
@ -674,15 +700,13 @@ template <> struct adl_serializer<repertory::download_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());
template <> struct adl_serializer<repertory::event_level> {
static void to_json(json &data, const repertory::event_level &value) {
data = repertory::event_level_to_string(value);
}
static void from_json(const json &data,
std::atomic<repertory::event_level> &value) {
value.store(repertory::event_level_from_string(data.get<std::string>()));
static void from_json(const json &data, repertory::event_level &value) {
value = repertory::event_level_from_string(data.get<std::string>());
}
};
NLOHMANN_JSON_NAMESPACE_END

View File

@ -49,6 +49,8 @@ static const option password_option = {"-pw", "--password"};
static const option remote_mount_option = {"-rm", "--remote_mount"};
static const option set_option = {"-set", "--set"};
static const option status_option = {"-status", "--status"};
static const option ui_option = {"-ui", "--ui"};
static const option ui_port_option = {"-up", "--ui_port"};
static const option unmount_option = {"-unmount", "--unmount"};
static const option unpin_file_option = {"-uf", "--unpin_file"};
static const option user_option = {"-us", "--user"};
@ -75,6 +77,8 @@ static const std::vector<option> option_list = {
remote_mount_option,
set_option,
status_option,
ui_option,
ui_port_option,
unmount_option,
unpin_file_option,
user_option,
@ -87,26 +91,27 @@ void get_api_authentication_data(std::string &user, std::string &password,
std::uint16_t &port, const provider_type &prov,
const std::string &data_directory);
[[nodiscard]] auto
get_provider_type_from_args(std::vector<const char *> args) -> provider_type;
[[nodiscard]] auto get_provider_type_from_args(std::vector<const char *> args)
-> provider_type;
[[nodiscard]] auto has_option(std::vector<const char *> args,
const std::string &option_name) -> bool;
[[nodiscard]] auto has_option(std::vector<const char *> args,
const option &opt) -> bool;
[[nodiscard]] auto has_option(std::vector<const char *> args, const option &opt)
-> bool;
[[nodiscard]] auto parse_option(std::vector<const char *> args,
const std::string &option_name,
std::uint8_t count) -> std::vector<std::string>;
[[nodiscard]] auto parse_string_option(std::vector<const char *> args,
const option &opt,
std::string &value) -> exit_code;
const option &opt, std::string &value)
-> exit_code;
[[nodiscard]] auto
parse_drive_options(std::vector<const char *> args, provider_type &prov,
std::string &data_directory) -> std::vector<std::string>;
[[nodiscard]] auto parse_drive_options(std::vector<const char *> args,
provider_type &prov,
std::string &data_directory)
-> std::vector<std::string>;
} // namespace repertory::utils::cli
#endif // REPERTORY_INCLUDE_UTILS_CLI_UTILS_HPP_

View File

@ -70,7 +70,7 @@ app_config::app_config(const provider_type &prov,
api_port_(default_rpc_port(prov)),
api_user_(std::string{REPERTORY}),
config_changed_(false),
download_timeout_secs_(default_download_timeout_ces),
download_timeout_secs_(default_download_timeout_secs),
enable_download_timeout_(true),
enable_drive_events_(false),
#if defined(_WIN32)
@ -85,7 +85,6 @@ app_config::app_config(const provider_type &prov,
max_upload_count_(default_max_upload_count),
med_freq_interval_secs_(default_med_freq_interval_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_),
retry_read_count_(default_retry_read_count),
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; }},
{fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_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),
[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),
[this]() { return std::to_string(get_host_config().timeout_ms); }},
{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()); }},
{JSON_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,
[this]() {
return download_type_to_string(get_preferred_download_type());
@ -250,7 +253,7 @@ app_config::app_config(const provider_type &prov,
value_set_lookup_ = {
{
JSON_API_PATH,
JSON_API_AUTH,
[this](const std::string &value) {
set_api_auth(value);
return get_api_auth();
@ -349,7 +352,7 @@ app_config::app_config(const provider_type &prov,
{
JSON_HIGH_FREQ_INTERVAL_SECS,
[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());
},
},
@ -380,6 +383,15 @@ app_config::app_config(const provider_type &prov,
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),
[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;
},
},
{
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),
[this](const std::string &value) {
@ -401,14 +431,14 @@ app_config::app_config(const provider_type &prov,
{
JSON_LOW_FREQ_INTERVAL_SECS,
[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());
},
},
{
JSON_MED_FREQ_INTERVAL_SECS,
[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());
},
},
@ -433,13 +463,6 @@ app_config::app_config(const provider_type &prov,
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,
[this](const std::string &value) {
@ -676,36 +699,37 @@ auto app_config::default_api_port(const provider_type &prov) -> std::uint16_t {
return PROVIDER_API_PORTS.at(static_cast<std::size_t>(prov));
}
auto app_config::default_data_directory(const provider_type &prov)
-> std::string {
auto app_config::get_root_data_directory() -> std::string {
#if defined(_WIN32)
auto data_directory =
utils::path::combine(utils::get_local_app_data_directory(),
{
REPERTORY_DATA_NAME,
app_config::get_provider_name(prov),
});
auto data_directory = utils::path::combine(
utils::get_local_app_data_directory(), {
REPERTORY_DATA_NAME,
});
#else // !defined(_WIN32)
#if defined(__APPLE__)
auto data_directory =
utils::path::combine("~", {
"Library",
"Application Support",
REPERTORY_DATA_NAME,
app_config::get_provider_name(prov),
});
auto data_directory = utils::path::combine("~", {
"Library",
"Application Support",
REPERTORY_DATA_NAME,
});
#else // !defined(__APPLE__)
auto data_directory =
utils::path::combine("~", {
".local",
REPERTORY_DATA_NAME,
app_config::get_provider_name(prov),
});
auto data_directory = utils::path::combine("~", {
".local",
REPERTORY_DATA_NAME,
});
#endif // defined(__APPLE__)
#endif // defined(_WIN32)
return data_directory;
}
auto app_config::default_data_directory(const provider_type &prov)
-> std::string {
return utils::path::combine(app_config::get_root_data_directory(),
{
app_config::get_provider_name(prov),
});
}
auto app_config::default_remote_api_port(const provider_type &prov)
-> std::uint16_t {
static const std::array<std::uint16_t,
@ -718,6 +742,7 @@ auto app_config::default_remote_api_port(const provider_type &prov)
};
return PROVIDER_REMOTE_PORTS.at(static_cast<std::size_t>(prov));
}
auto app_config::default_rpc_port(const provider_type &prov) -> std::uint16_t {
static const std::array<std::uint16_t,
static_cast<std::size_t>(provider_type::unknown)>
@ -812,7 +837,6 @@ auto app_config::get_json() const -> json {
{JSON_MAX_UPLOAD_COUNT, max_upload_count_},
{JSON_MED_FREQ_INTERVAL_SECS, med_freq_interval_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_REMOTE_CONFIG, remote_config_},
{JSON_REMOTE_MOUNT, remote_mount_},
@ -834,7 +858,6 @@ auto app_config::get_json() const -> json {
ret.erase(JSON_MAX_CACHE_SIZE_BYTES);
ret.erase(JSON_MAX_UPLOAD_COUNT);
ret.erase(JSON_ONLINE_CHECK_RETRY_SECS);
ret.erase(JSON_ORPHANED_FILE_RETENTION_DAYS);
ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
ret.erase(JSON_REMOTE_CONFIG);
ret.erase(JSON_RETRY_READ_COUNT);
@ -856,7 +879,6 @@ auto app_config::get_json() const -> json {
ret.erase(JSON_MAX_UPLOAD_COUNT);
ret.erase(JSON_MED_FREQ_INTERVAL_SECS);
ret.erase(JSON_ONLINE_CHECK_RETRY_SECS);
ret.erase(JSON_ORPHANED_FILE_RETENTION_DAYS);
ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
ret.erase(JSON_REMOTE_MOUNT);
ret.erase(JSON_RETRY_READ_COUNT);
@ -912,12 +934,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());
}
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 {
return preferred_download_type_;
}
@ -1053,8 +1069,6 @@ auto app_config::load() -> bool {
med_freq_interval_secs_, found);
get_value(json_document, JSON_ONLINE_CHECK_RETRY_SECS,
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,
preferred_download_type_, found);
get_value(json_document, JSON_REMOTE_CONFIG, remote_config_, found);
@ -1069,10 +1083,17 @@ auto app_config::load() -> bool {
std::uint64_t version{};
get_value(json_document, JSON_VERSION, version, found);
// Handle configuration defaults for new config versions
if (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;
}
@ -1199,10 +1220,6 @@ void app_config::set_online_check_retry_secs(std::uint16_t 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) {
set_value(preferred_download_type_, value);
}

View File

@ -43,8 +43,8 @@
#include "utils/utils.hpp"
namespace repertory::remote_fuse {
auto remote_fuse_drive::access_impl(std::string api_path,
int mask) -> api_error {
auto remote_fuse_drive::access_impl(std::string api_path, int mask)
-> api_error {
return utils::to_api_error(
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*/)
-> api_error {
#else
auto remote_fuse_drive::chmod_impl(std::string api_path,
mode_t mode) -> api_error {
auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode)
-> api_error {
#endif
return utils::to_api_error(remote_instance_->fuse_chmod(
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*/)
-> api_error {
#else
auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid,
gid_t gid) -> api_error {
auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
-> api_error {
#endif
return utils::to_api_error(
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();
event_system::instance().raise<drive_unmount_pending>(function_name,
get_mount_location());
get_mount_location());
if (server_) {
server_->stop();
@ -116,14 +116,15 @@ void remote_fuse_drive::destroy_impl(void *ptr) {
}
event_system::instance().raise<drive_unmounted>(function_name,
get_mount_location());
get_mount_location());
fuse_base::destroy_impl(ptr);
}
auto remote_fuse_drive::fgetattr_impl(
std::string api_path, struct stat *unix_st,
struct fuse_file_info *f_info) -> api_error {
auto remote_fuse_drive::fgetattr_impl(std::string api_path,
struct stat *unix_st,
struct fuse_file_info *f_info)
-> api_error {
remote::stat r_stat{};
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*/)
-> api_error {
#else
auto remote_fuse_drive::getattr_impl(std::string api_path,
struct stat *unix_st) -> api_error {
auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st)
-> api_error {
#endif
bool directory = false;
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_->start();
event_system::instance().raise<drive_mounted>(function_name,
get_mount_location());
get_mount_location());
}
return ret;
}
auto remote_fuse_drive::mkdir_impl(std::string api_path,
mode_t mode) -> api_error {
auto remote_fuse_drive::mkdir_impl(std::string api_path, mode_t mode)
-> api_error {
return utils::to_api_error(remote_instance_->fuse_mkdir(
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));
}
auto remote_fuse_drive::opendir_impl(
std::string api_path, struct fuse_file_info *f_info) -> api_error {
auto remote_fuse_drive::opendir_impl(std::string api_path,
struct fuse_file_info *f_info)
-> api_error {
if ((f_info->flags & O_APPEND) == O_APPEND ||
(f_info->flags & O_EXCL) == O_EXCL) {
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,
bool directory, struct stat &unix_st) {
std::memset(&unix_st, 0, sizeof(struct stat));
unix_st.st_blksize = r_stat.st_blksize;
unix_st.st_blocks = static_cast<blkcnt_t>(r_stat.st_blocks);
unix_st.st_blksize =
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_mode = (directory ? S_IFDIR : S_IFREG) | r_stat.st_mode;
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;
#if defined(__APPLE__)
@ -373,14 +377,18 @@ auto remote_fuse_drive::read_impl(std::string api_path, char *buffer,
}
#if FUSE_USE_VERSION >= 30
auto remote_fuse_drive::readdir_impl(
std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir,
off_t offset, struct fuse_file_info *f_info,
fuse_readdir_flags /*flags*/) -> api_error {
auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
fuse_fill_dir_t fuse_fill_dir,
off_t offset,
struct fuse_file_info *f_info,
fuse_readdir_flags /*flags*/)
-> api_error {
#else
auto remote_fuse_drive::readdir_impl(
std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir,
off_t offset, struct fuse_file_info *f_info) -> api_error {
auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
fuse_fill_dir_t fuse_fill_dir,
off_t offset,
struct fuse_file_info *f_info)
-> api_error {
#endif
std::string item_path;
int res = 0;
@ -408,14 +416,16 @@ auto remote_fuse_drive::readdir_impl(
return utils::to_api_error(res);
}
auto remote_fuse_drive::release_impl(
std::string api_path, struct fuse_file_info *f_info) -> api_error {
auto remote_fuse_drive::release_impl(std::string api_path,
struct fuse_file_info *f_info)
-> api_error {
return utils::to_api_error(
remote_instance_->fuse_release(api_path.c_str(), f_info->fh));
}
auto remote_fuse_drive::releasedir_impl(
std::string api_path, struct fuse_file_info *f_info) -> api_error {
auto remote_fuse_drive::releasedir_impl(std::string api_path,
struct fuse_file_info *f_info)
-> api_error {
return utils::to_api_error(
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);
}
#else // __APPLE__
auto remote_fuse_drive::statfs_impl(std::string api_path,
struct statvfs *stbuf) -> api_error {
auto remote_fuse_drive::statfs_impl(std::string api_path, struct statvfs *stbuf)
-> api_error {
auto res = statvfs(config_.get_data_directory().c_str(), stbuf);
if (res == 0) {
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*/)
-> api_error {
#else
auto remote_fuse_drive::truncate_impl(std::string api_path,
off_t size) -> api_error {
auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size)
-> api_error {
#endif
return utils::to_api_error(remote_instance_->fuse_truncate(
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
auto remote_fuse_drive::utimens_impl(
std::string api_path, const struct timespec tv[2],
struct fuse_file_info * /*f_info*/) -> api_error {
auto remote_fuse_drive::utimens_impl(std::string api_path,
const struct timespec tv[2],
struct fuse_file_info * /*f_info*/)
-> api_error {
#else
auto remote_fuse_drive::utimens_impl(std::string api_path,
const struct timespec tv[2]) -> api_error {

View File

@ -22,13 +22,11 @@
#include "drives/winfsp/remotewinfsp/remote_client.hpp"
#include "app_config.hpp"
#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
#include "events/event_system.hpp"
#include "events/types/drive_mounted.hpp"
#include "events/types/drive_unmount_pending.hpp"
#include "events/types/drive_unmounted.hpp"
#include "types/repertory.hpp"
#include "utils/path.hpp"
#include "utils/string.hpp"
#include "version.hpp"
namespace repertory::remote_winfsp {
@ -44,11 +42,7 @@ auto remote_client::winfsp_can_delete(PVOID file_desc, PWSTR file_name)
request.encode(file_name);
std::uint32_t service_flags{};
auto ret{
packet_client_.send(function_name, request, service_flags),
};
return ret;
return packet_client_.send(function_name, request, service_flags);
}
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);
std::uint32_t service_flags{};
auto ret{
packet_client_.send(function_name, request, service_flags),
};
return ret;
return packet_client_.send(function_name, request, service_flags);
}
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;
request.encode(file_name);
request.encode(static_cast<std::uint64_t>(
descriptor_size == nullptr ? 0 : *descriptor_size));
request.encode(descriptor_size == nullptr ? std::uint64_t(0U)
: *descriptor_size);
request.encode(static_cast<std::uint8_t>(attributes != nullptr));
packet response;
@ -417,7 +407,7 @@ auto remote_client::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
ret = response.decode(buffer, *bytes_transferred);
#if defined(_WIN32)
if ((ret == STATUS_SUCCESS) &&
(not*bytes_transferred || (*bytes_transferred != length))) {
((*bytes_transferred == 0U) || (*bytes_transferred != length))) {
::SetLastError(ERROR_HANDLE_EOF);
}
#endif
@ -461,11 +451,7 @@ auto remote_client::winfsp_rename(PVOID file_desc, PWSTR file_name,
request.encode(replace_if_exists);
std::uint32_t service_flags{};
auto ret{
packet_client_.send(function_name, request, service_flags),
};
return ret;
return packet_client_.send(function_name, request, service_flags);
}
auto remote_client::winfsp_set_basic_info(

View File

@ -466,6 +466,13 @@ auto file_manager::open(const std::string &api_path, bool directory,
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) {
return type;
}

View File

@ -98,19 +98,23 @@ auto ring_buffer_base::close() -> bool {
return res;
}
auto ring_buffer_base::download_chunk(std::size_t chunk,
bool skip_active) -> api_error {
auto ring_buffer_base::download_chunk(std::size_t chunk, bool skip_active)
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
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_lock.unlock();
};
const auto unlock_and_return =
[&unlock_and_notify](api_error res) -> api_error {
unlock_and_notify();
[&notify_and_unlock](api_error res) -> api_error {
notify_and_unlock();
return res;
};
@ -124,7 +128,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk,
}
auto active_download = get_active_downloads().at(chunk);
unlock_and_notify();
notify_and_unlock();
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()
: get_chunk_size(),
};
unlock_and_notify();
notify_and_unlock();
auto result{
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);
unlock_and_notify();
notify_and_unlock();
active_download->notify(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_) {
reverse(ring_pos_ - chunk);
}
res = download_chunk(chunk, false);
if (res != api_error::success) {
if (res == api_error::invalid_ring_buffer_position) {
@ -264,38 +267,46 @@ void ring_buffer_base::reader_thread() {
REPERTORY_USES_FUNCTION_NAME();
unique_mutex_lock chunk_lock(chunk_mtx_);
auto next_chunk{ring_pos_};
chunk_notify_.notify_all();
chunk_lock.unlock();
const auto notify_and_unlock = [this, &chunk_lock]() {
chunk_notify_.notify_all();
chunk_lock.unlock();
};
auto last_pos = ring_pos_;
auto next_chunk = ring_pos_;
notify_and_unlock();
while (not get_stop_requested()) {
chunk_lock.lock();
next_chunk = next_chunk + 1U > ring_end_ ? ring_begin_ : next_chunk + 1U;
const auto check_and_wait = [this, &chunk_lock, &next_chunk]() {
if (last_pos == ring_pos_) {
++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()) {
chunk_notify_.notify_all();
chunk_lock.unlock();
notify_and_unlock();
return;
}
if (get_read_state().all()) {
chunk_notify_.wait(chunk_lock);
last_pos = ring_pos_;
next_chunk = ring_pos_;
}
chunk_notify_.notify_all();
chunk_lock.unlock();
};
if (read_state_[next_chunk % read_state_.size()]) {
check_and_wait();
notify_and_unlock();
continue;
}
chunk_notify_.notify_all();
chunk_lock.unlock();
notify_and_unlock();
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_
: (ring_pos_ - count) >= ring_begin_) {
ring_pos_ += is_forward ? count : -count;
} else {
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();
return;
}
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();
}
} // namespace repertory

View File

@ -50,10 +50,6 @@
namespace repertory {
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)
{
static constexpr const auto guard_size{4096U};
@ -68,6 +64,10 @@ auto project_initialize() -> bool {
}
#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 (sodium_init() == -1) {
@ -77,7 +77,9 @@ auto project_initialize() -> bool {
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
#if defined(PROJECT_ENABLE_OPENSSL)
{ SSL_library_init(); }
{
SSL_library_init();
}
#endif // defined(PROJECT_ENABLE_OPENSSL)
#if defined(PROJECT_ENABLE_CURL)

View File

@ -34,6 +34,7 @@
#include "events/types/orphaned_file_processing_failed.hpp"
#include "events/types/orphaned_source_file_detected.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_upload_begin.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,
std::uint64_t size,
std::uint64_t file_time) -> api_file {
std::uint64_t size, std::uint64_t file_time)
-> api_file {
api_file file{};
file.api_path = utils::path::create_api_path(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(
const std::string &source_api_path,
const std::string &api_path) -> api_error {
const std::string &source_api_path, const std::string &api_path)
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
bool exists{};
@ -201,8 +202,8 @@ auto base_provider::create_directory(const std::string &api_path,
return api_error::error;
}
auto base_provider::create_file(const std::string &api_path,
api_meta_map &meta) -> api_error {
auto base_provider::create_file(const std::string &api_path, api_meta_map &meta)
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
try {
@ -259,8 +260,9 @@ auto base_provider::create_file(const std::string &api_path,
return api_error::error;
}
auto base_provider::get_api_path_from_source(
const std::string &source_path, std::string &api_path) const -> api_error {
auto base_provider::get_api_path_from_source(const std::string &source_path,
std::string &api_path) const
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
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);
}
auto base_provider::get_directory_items(
const std::string &api_path, directory_item_list &list) const -> api_error {
auto base_provider::get_directory_items(const std::string &api_path,
directory_item_list &list) const
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
try {
@ -283,8 +286,15 @@ auto base_provider::get_directory_items(
if (res != api_error::success) {
return res;
}
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);
@ -342,9 +352,10 @@ auto base_provider::get_file_size(const std::string &api_path,
return api_error::success;
}
auto base_provider::get_filesystem_item(
const std::string &api_path, bool directory,
filesystem_item &fsi) const -> api_error {
auto base_provider::get_filesystem_item(const std::string &api_path,
bool directory,
filesystem_item &fsi) const
-> api_error {
bool exists{};
auto res = is_directory(api_path, exists);
if (res != api_error::success) {
@ -377,9 +388,10 @@ auto base_provider::get_filesystem_item(
return api_error::success;
}
auto base_provider::get_filesystem_item_and_file(
const std::string &api_path, api_file &file,
filesystem_item &fsi) const -> api_error {
auto base_provider::get_filesystem_item_and_file(const std::string &api_path,
api_file &file,
filesystem_item &fsi) const
-> api_error {
auto res = get_file(api_path, file);
if (res != api_error::success) {
return res;
@ -829,6 +841,14 @@ auto base_provider::start(api_item_added_callback api_item_added,
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_);
polling::instance().set_callback({

View File

@ -40,6 +40,7 @@
#include "utils/file_utils.hpp"
#include "utils/path.hpp"
#include "utils/polling.hpp"
#include <spdlog/fmt/bundled/base.h>
namespace repertory {
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_path = file.api_path;
dir_item.directory = dir_entry->is_directory_item();
dir_item.resolved = true;
dir_item.size = file.file_size;
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()};
try {
for (const auto &dir_entry : utils::file::directory{cfg.path}.get_items()) {
std::string api_path{};
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()));
using func = std::function<void(std::string path)>;
const func process_directory = [&](std::string path) {
for (const auto &dir_entry : utils::file::directory{path}.get_items()) {
std::string api_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;
} catch (const std::exception &ex) {

View File

@ -43,9 +43,9 @@
#include "utils/time.hpp"
namespace {
[[nodiscard]] auto
set_request_path(auto &request,
const std::string &object_name) -> repertory::api_error {
[[nodiscard]] auto set_request_path(auto &request,
const std::string &object_name)
-> repertory::api_error {
request.path = object_name;
if (request.path.substr(1U).size() > repertory::max_s3_object_name_length) {
return repertory::api_error::name_too_long;
@ -59,8 +59,9 @@ namespace repertory {
s3_provider::s3_provider(app_config &config, i_http_comm &comm)
: base_provider(config, comm) {}
auto s3_provider::add_if_not_found(
api_file &file, const std::string &object_name) const -> api_error {
auto s3_provider::add_if_not_found(api_file &file,
const std::string &object_name) const
-> api_error {
api_meta_map meta{};
auto res{get_item_meta(file.api_path, meta)};
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,
};
struct tm tm1 {};
struct tm tm1{};
#if defined(_WIN32)
utils::time::strptime(date_time.c_str(), "%Y-%m-%dT%T", &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));
}
auto s3_provider::create_directory_paths(
const std::string &api_path, const std::string &key) const -> api_error {
auto s3_provider::create_directory_paths(const std::string &api_path,
const std::string &key) const
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
if (api_path == "/") {
@ -321,8 +323,9 @@ auto s3_provider::get_directory_item_count(const std::string &api_path) const
return 0U;
}
auto s3_provider::get_directory_items_impl(
const std::string &api_path, directory_item_list &list) const -> api_error {
auto s3_provider::get_directory_items_impl(const std::string &api_path,
directory_item_list &list) const
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
const auto &cfg{get_s3_config()};
@ -480,8 +483,8 @@ auto s3_provider::get_directory_items_impl(
return api_error::success;
}
auto s3_provider::get_file(const std::string &api_path,
api_file &file) const -> api_error {
auto s3_provider::get_file(const std::string &api_path, api_file &file) const
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
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),
};
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;
@ -521,8 +536,8 @@ auto s3_provider::get_file(const std::string &api_path,
return api_error::error;
}
auto s3_provider::get_file_list(api_file_list &list,
std::string &marker) const -> api_error {
auto s3_provider::get_file_list(api_file_list &list, std::string &marker) const
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
try {
@ -612,8 +627,9 @@ auto s3_provider::get_file_list(api_file_list &list,
return api_error::error;
}
auto s3_provider::get_last_modified(
bool directory, const std::string &api_path) const -> std::uint64_t {
auto s3_provider::get_last_modified(bool directory,
const std::string &api_path) const
-> std::uint64_t {
bool is_encrypted{};
std::string object_name;
head_object_result result{};
@ -623,9 +639,10 @@ auto s3_provider::get_last_modified(
: utils::time::get_time_now();
}
auto s3_provider::get_object_info(
bool directory, const std::string &api_path, bool &is_encrypted,
std::string &object_name, head_object_result &result) const -> api_error {
auto s3_provider::get_object_info(bool directory, const std::string &api_path,
bool &is_encrypted, std::string &object_name,
head_object_result &result) const
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
try {
@ -685,10 +702,12 @@ auto s3_provider::get_object_info(
return api_error::error;
}
auto s3_provider::get_object_list(
std::string &response_data, long &response_code,
std::optional<std::string> delimiter, std::optional<std::string> prefix,
std::optional<std::string> token) const -> bool {
auto s3_provider::get_object_list(std::string &response_data,
long &response_code,
std::optional<std::string> delimiter,
std::optional<std::string> prefix,
std::optional<std::string> token) const
-> bool {
curl::requests::http_get get{};
get.allow_timeout = true;
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);
}
auto s3_provider::is_directory(const std::string &api_path,
bool &exists) const -> api_error {
auto s3_provider::is_directory(const std::string &api_path, bool &exists) const
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
try {
@ -745,8 +764,8 @@ auto s3_provider::is_directory(const std::string &api_path,
return api_error::error;
}
auto s3_provider::is_file(const std::string &api_path,
bool &exists) const -> api_error {
auto s3_provider::is_file(const std::string &api_path, bool &exists) const
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
try {
@ -1004,8 +1023,8 @@ auto s3_provider::rename_file(const std::string & /* from_api_path */,
return api_error::not_implemented;
}
auto s3_provider::set_meta_key(const std::string &api_path,
api_meta_map &meta) -> api_error {
auto s3_provider::set_meta_key(const std::string &api_path, api_meta_map &meta)
-> api_error {
REPERTORY_USES_FUNCTION_NAME();
const auto &cfg{get_s3_config()};

View File

@ -32,8 +32,8 @@
#include "providers/base_provider.hpp"
#include "providers/s3/s3_provider.hpp"
#include "types/repertory.hpp"
#include "utils/common.hpp"
#include "utils/error_utils.hpp"
#include "utils/file_utils.hpp"
#include "utils/path.hpp"
#include "utils/polling.hpp"
#include "utils/string.hpp"
@ -63,6 +63,54 @@ namespace repertory {
sia_provider::sia_provider(app_config &config, i_http_comm &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,
api_meta_map & /* meta */)
-> api_error {
@ -70,7 +118,7 @@ auto sia_provider::create_directory_impl(const std::string &api_path,
curl::requests::http_put_file put_file{};
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());
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{};
if (object_list.contains("entries")) {
for (const auto &entry : object_list.at("entries")) {
if (object_list.contains("objects")) {
for (const auto &entry : object_list.at("objects")) {
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)};
if (utils::string::ends_with(name, "/") &&
(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;
}
if (object_list.contains("entries")) {
for (const auto &entry : object_list.at("entries")) {
if (object_list.contains("objects")) {
for (const auto &entry : object_list.at("objects")) {
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 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.directory = directory;
dir_item.meta = meta;
dir_item.resolved = true;
dir_item.size = file.file_size;
list.emplace_back(std::move(dir_item));
} 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{};
auto res{get_object_info(api_path, file_data)};
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{
std::accumulate(
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>();
}),
file_data.at("size").get<std::uint64_t>(),
};
api_meta_map meta{};
if (get_item_meta(api_path, meta) == api_error::item_not_found) {
file = create_api_file(api_path, "", size,
get_last_modified(file_data["object"]));
file = create_api_file(api_path, "", size, get_last_modified(file_data));
get_api_item_added()(false, file);
} else {
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;
}
if (object_list.contains("entries")) {
for (const auto &entry : object_list.at("entries")) {
auto name{entry.at("name").get<std::string>()};
if (object_list.contains("objects")) {
for (const auto &entry : object_list.at("objects")) {
auto name{entry.at("key").get<std::string>()};
auto entry_api_path{utils::path::create_api_path(name)};
if (utils::string::ends_with(name, "/")) {
@ -313,8 +366,9 @@ auto sia_provider::get_object_info(const std::string &api_path,
try {
curl::requests::http_get get{};
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["onlymetadata"] = "true";
std::string error_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.path = "/api/bus/objects" + api_path + "/";
get.query["bucket"] = get_bucket(get_sia_config());
get.query["delimiter"] = "/";
std::string error_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 {
curl::requests::http_get get{};
get.allow_timeout = true;
get.path = "/api/autopilot/config";
get.path = "/api/bus/autopilot";
get.query["bucket"] = get_bucket(get_sia_config());
json config_data;
@ -455,17 +510,18 @@ auto sia_provider::is_directory(const std::string &api_path, bool &exists) const
exists = false;
json object_list{};
if (not get_object_list(utils::path::get_parent_api_path(api_path),
object_list)) {
return api_error::comm_error;
json file_data{};
auto res{get_object_info(api_path + '/', file_data)};
if (res == api_error::item_not_found) {
return api_error::success;
}
exists = object_list.contains("entries") &&
std::ranges::find_if(object_list.at("entries"),
[&api_path](auto &&entry) -> bool {
return entry.at("name") == (api_path + "/");
}) != object_list.at("entries").end();
if (res != api_error::success) {
return res;
}
exists =
utils::string::ends_with(file_data.at("key").get<std::string>(), "/");
return api_error::success;
} catch (const std::exception &e) {
utils::error::raise_api_path_error(
@ -481,6 +537,7 @@ auto sia_provider::is_file(const std::string &api_path, bool &exists) const
try {
exists = false;
if (api_path == "/") {
return api_error::success;
}
@ -495,7 +552,8 @@ auto sia_provider::is_file(const std::string &api_path, bool &exists) const
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;
} catch (const std::exception &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 {
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.headers["accept"] = "application/octet-stream";
get.range = {{
offset,
offset + size - 1U,
@ -577,6 +636,7 @@ auto sia_provider::read_file_bytes(const std::string &api_path,
++idx) {
long response_code{};
const auto notify_retry = [&]() {
fmt::println("{}", std::string(buffer.begin(), buffer.end()));
if (response_code == 0) {
utils::error::raise_api_path_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{};
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());
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{};
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());
std::string error_data;
@ -697,12 +757,12 @@ auto sia_provider::rename_file(const std::string &from_api_path,
try {
curl::requests::http_post post{};
post.json = nlohmann::json({
{"bucket", get_bucket(get_sia_config())},
{"from", from_api_path},
{"to", to_api_path},
{"mode", "single"},
});
post.path = "/api/bus/objects/rename";
post.query["bucket"] = get_bucket(get_sia_config());
std::string error_data;
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();
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.headers["content-type"] = "application/octet-stream";
put_file.source_path = source_path;
std::string error_data;

View File

@ -22,8 +22,6 @@
#include "rpc/client/client.hpp"
#include "types/repertory.hpp"
#include "utils/base64.hpp"
#include "utils/utils.hpp"
namespace repertory {
client::client(rpc_host_info host_info) : host_info_(std::move(host_info)) {}

View File

@ -28,6 +28,7 @@
#include "events/types/service_stop_begin.hpp"
#include "events/types/service_stop_end.hpp"
#include "events/types/unmount_requested.hpp"
#include "rpc/common.hpp"
#include "utils/base64.hpp"
#include "utils/error_utils.hpp"
#include "utils/string.hpp"
@ -35,54 +36,6 @@
namespace repertory {
server::server(app_config &config) : config_(config) {}
auto server::check_authorization(const httplib::Request &req) -> bool {
REPERTORY_USES_FUNCTION_NAME();
if (config_.get_api_auth().empty() || config_.get_api_user().empty()) {
utils::error::raise_error(function_name,
"authorization user or password is not set");
return false;
}
auto authorization = req.get_header_value("Authorization");
if (authorization.empty()) {
utils::error::raise_error(function_name, "Authorization header is not set");
return false;
}
auto auth_parts = utils::string::split(authorization, ' ', true);
if (auth_parts.empty()) {
utils::error::raise_error(function_name, "Authorization header is empty");
return false;
}
auto auth_type = auth_parts[0U];
if (auth_type != "Basic") {
utils::error::raise_error(function_name, "Authorization is not Basic");
return false;
}
auto data = macaron::Base64::Decode(authorization.substr(6U));
auto auth_str = std::string(data.begin(), data.end());
auto auth = utils::string::split(auth_str, ':', false);
if (auth.size() < 2U) {
utils::error::raise_error(function_name, "Authorization is not valid");
return false;
}
auto user = auth.at(0U);
auth.erase(auth.begin());
auto pwd = utils::string::join(auth, ':');
if ((user != config_.get_api_user()) || (pwd != config_.get_api_auth())) {
utils::error::raise_error(function_name, "Authorization failed");
return false;
}
return true;
}
void server::handle_get_config(const httplib::Request & /*req*/,
httplib::Response &res) {
auto data = config_.get_json();
@ -173,7 +126,7 @@ void server::start() {
server_->set_pre_routing_handler(
[this](auto &&req, auto &&res) -> httplib::Server::HandlerResponse {
if (check_authorization(req)) {
if (rpc::check_authorization(config_, req)) {
return httplib::Server::HandlerResponse::Unhandled;
}

View File

@ -21,6 +21,7 @@
*/
#include "types/repertory.hpp"
#include "app_config.hpp"
#include "types/startup_exception.hpp"
#include "utils/string.hpp"
@ -191,4 +192,34 @@ auto api_error_to_string(const api_error &error) -> const std::string & {
return LOOKUP.at(error);
}
auto provider_type_from_string(std::string_view type,
provider_type default_type) -> provider_type {
auto type_lower = utils::string::to_lower(std::string{type});
if (type_lower == "encrypt") {
return provider_type::encrypt;
}
if (type_lower == "remote") {
return provider_type::remote;
}
if (type_lower == "s3") {
return provider_type::s3;
}
if (type_lower == "sia") {
return provider_type::sia;
}
if (type_lower == "unknown") {
return provider_type::unknown;
}
return default_type;
}
auto provider_type_to_string(provider_type type) -> std::string {
return app_config::get_provider_name(type);
}
} // namespace repertory

View File

@ -44,11 +44,13 @@ struct repertory_exception_handler final
}
};
std::unique_ptr<repertory_exception_handler> handler{([]() -> auto * {
auto *ptr = new repertory_exception_handler{};
repertory::utils::error::set_exception_handler(ptr);
return ptr;
})()};
const auto repertory_handler{
([]() -> auto {
auto ptr = std::make_unique<repertory_exception_handler>();
repertory::utils::error::set_exception_handler(ptr.get());
return ptr;
})(),
};
} // namespace
namespace repertory::utils::error {

View File

@ -38,47 +38,58 @@ void polling::frequency_thread(
std::function<std::uint32_t()> get_frequency_seconds, frequency freq) {
REPERTORY_USES_FUNCTION_NAME();
auto last_run = std::chrono::system_clock::time_point::min();
while (not get_stop_requested()) {
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) {
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now() - last_run);
auto max_elapsed = std::chrono::seconds(get_frequency_seconds());
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;
}
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);
return list;
});
lock.unlock();
while (not futures.empty()) {
futures.front()->wait();
futures.pop_front();
}
while (not futures.empty()) {
futures.front()->wait();
futures.pop_front();
last_run = std::chrono::system_clock::now();
elapsed = std::chrono::seconds(0U);
}
unique_mutex_lock lock(mutex_);
if (get_stop_requested()) {
return;
}
lock.lock();
notify_.wait_for(lock, std::chrono::seconds(get_frequency_seconds()));
notify_.wait_for(lock, max_elapsed - elapsed);
}
}

View File

@ -36,6 +36,7 @@
#include "cli/pinned_status.hpp"
#include "cli/set.hpp"
#include "cli/status.hpp"
#include "cli/ui.hpp"
#include "cli/unmount.hpp"
#include "cli/unpin_file.hpp"
#include "utils/cli_utils.hpp"
@ -70,6 +71,7 @@ static const std::unordered_map<utils::cli::option, action, option_hasher>
cli::actions::pinned_status},
{utils::cli::options::set_option, cli::actions::set},
{utils::cli::options::status_option, cli::actions::status},
{utils::cli::options::ui_option, cli::actions::ui},
{utils::cli::options::unmount_option, cli::actions::unmount},
{utils::cli::options::unpin_file_option, cli::actions::unpin_file},
};

View File

@ -23,50 +23,38 @@
#define REPERTORY_INCLUDE_CLI_CHECK_VERSION_HPP_
#include "app_config.hpp"
#include "comm/curl/curl_comm.hpp"
#include "providers/sia/sia_provider.hpp"
#include "types/repertory.hpp"
namespace repertory::cli::actions {
[[nodiscard]] inline auto
check_version(std::vector<const char *> /* args */,
const std::string & /* data_directory */,
const provider_type & /* pt */, const std::string & /*unique_id*/,
std::string /*user*/, std::string /*password*/) -> exit_code {
auto ret = exit_code::success;
[[nodiscard]] inline auto check_version(std::vector<const char *> /* args */,
const std::string &data_directory,
const provider_type &prov,
const std::string & /*unique_id*/,
std::string /*user*/,
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
// if (not((pt == provider_type::remote) || (pt == provider_type::s3))) {
// app_config config(pt, data_directory);
// 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;
// }
// }
app_config config(prov, data_directory);
curl_comm comm(config.get_host_config());
sia_provider provider(config, comm);
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

View File

@ -79,6 +79,12 @@ template <typename drive> inline void help(std::vector<const char *> args) {
<< std::endl;
std::cout << " -status Display mount status"
<< std::endl;
std::cout
<< " -ui,--ui Run embedded management UI"
<< std::endl;
std::cout << " -up,--ui_port Custom port for embedded "
"management UI"
<< std::endl;
std::cout << " -unmount,--unmount Unmount and shutdown"
<< std::endl;
std::cout << " -uf,--unpin_file [API path] Unpin a file from cache "

View File

@ -0,0 +1,65 @@
/*
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_CLI_UI_HPP_
#define REPERTORY_INCLUDE_CLI_UI_HPP_
#include "types/repertory.hpp"
#include "ui/handlers.hpp"
#include "utils/cli_utils.hpp"
#include "utils/file.hpp"
#include "utils/string.hpp"
namespace repertory::cli::actions {
[[nodiscard]] inline auto
ui(std::vector<const char *> args, const std::string & /*data_directory*/,
const provider_type & /* prov */, const std::string & /* unique_id */,
std::string /* user */, std::string /* password */) -> exit_code {
auto ui_port{default_ui_mgmt_port};
std::string data;
auto res = utils::cli::parse_string_option(
args, utils::cli::options::ui_port_option, data);
if (res == exit_code::success && not data.empty()) {
ui_port = utils::string::to_uint16(data);
}
if (not utils::file::change_to_process_directory()) {
return exit_code::ui_mount_failed;
}
httplib::Server server;
if (not server.set_mount_point("/ui", "./web")) {
return exit_code::ui_mount_failed;
}
ui::mgmt_app_config config{
.api_auth_ = "test",
.api_port_ = ui_port,
.api_user_ = "test",
};
ui::handlers handlers(&config, &server);
return exit_code::success;
}
} // namespace repertory::cli::actions
#endif // REPERTORY_INCLUDE_CLI_UI_HPP_

View File

@ -0,0 +1,74 @@
/*
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_UI_HANDLERS_HPP_
#define REPERTORY_INCLUDE_UI_HANDLERS_HPP_
#include "events/consumers/console_consumer.hpp"
namespace repertory::ui {
struct mgmt_app_config final {
std::string api_auth_{"test"};
std::uint16_t api_port_{default_ui_mgmt_port};
std::string api_user_{"test"};
[[nodiscard]] auto get_api_auth() const -> std::string { return api_auth_; }
[[nodiscard]] auto get_api_port() const -> std::uint16_t { return api_port_; }
[[nodiscard]] auto get_api_user() const -> std::string { return api_user_; }
};
class handlers final {
public:
handlers(mgmt_app_config *config, httplib::Server *server);
handlers() = delete;
handlers(const handlers &) = delete;
handlers(handlers &&) = delete;
~handlers();
auto operator=(const handlers &) -> handlers & = delete;
auto operator=(handlers &&) -> handlers & = delete;
private:
mgmt_app_config *config_;
httplib::Server *server_;
private:
console_consumer console;
private:
void handle_get_mount(auto &&req, auto &&res) const;
void handle_get_mount_list(auto &&res) const;
void handle_get_mount_status(auto &&req, auto &&res) const;
[[nodiscard]] static auto read_process(provider_type prov,
std::string_view name,
std::string_view command)
-> std::vector<std::string>;
};
} // namespace repertory::ui
#endif // REPERTORY_INCLUDE_UI_HANDLERS_HPP_

View File

@ -146,10 +146,17 @@ auto main(int argc, char **argv) -> int {
(res == exit_code::option_not_found) &&
(idx < utils::cli::options::option_list.size());
idx++) {
res = cli::actions::perform_action(
utils::cli::options::option_list[idx], args, data_directory, prov,
unique_id, user, password);
try {
res = cli::actions::perform_action(
utils::cli::options::option_list[idx], args, data_directory, prov,
unique_id, user, password);
} catch (const std::exception &ex) {
res = exit_code::exception;
} catch (...) {
res = exit_code::exception;
}
}
if (res == exit_code::option_not_found) {
res = cli::actions::mount(args, data_directory, mount_result, prov,
remote_host, remote_port, unique_id);

View File

@ -0,0 +1,253 @@
/*
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 "ui/handlers.hpp"
#include "app_config.hpp"
#include "events/event_system.hpp"
#include "rpc/common.hpp"
#include "types/repertory.hpp"
#include "utils/error_utils.hpp"
#include "utils/file.hpp"
#include "utils/path.hpp"
#include "utils/string.hpp"
namespace repertory::ui {
handlers::handlers(mgmt_app_config *config, httplib::Server *server)
: config_(config), server_(server) {
REPERTORY_USES_FUNCTION_NAME();
server_->set_pre_routing_handler(
[this](auto &&req, auto &&res) -> httplib::Server::HandlerResponse {
if (rpc::check_authorization(*config_, req)) {
return httplib::Server::HandlerResponse::Unhandled;
}
res.status = http_error_codes::unauthorized;
res.set_header(
"WWW-Authenticate",
R"(Basic realm="Repertory Management Portal", charset="UTF-8")");
return httplib::Server::HandlerResponse::Handled;
});
server_->set_exception_handler([](const httplib::Request &req,
httplib::Response &res,
std::exception_ptr ptr) {
json data{
{"path", req.path},
};
try {
std::rethrow_exception(ptr);
} catch (const std::exception &e) {
data["error"] = (e.what() == nullptr) ? "unknown error" : e.what();
utils::error::raise_error(function_name, e,
"failed request: " + req.path);
} catch (...) {
data["error"] = "unknown error";
utils::error::raise_error(function_name, "unknown error",
"failed request: " + req.path);
}
res.set_content(data.dump(), "application/json");
res.status = http_error_codes::internal_error;
});
server->Get("/api/v1/mount",
[this](auto &&req, auto &&res) { handle_get_mount(req, res); });
server->Get("/api/v1/mount_list", [this](auto && /* req */, auto &&res) {
handle_get_mount_list(res);
});
server->Get("/api/v1/mount_status",
[this](const httplib::Request &req, auto &&res) {
handle_get_mount_status(req, res);
});
event_system::instance().start();
static std::atomic<httplib::Server *> this_server{server_};
static const auto quit_handler = [](int /* sig */) {
auto *ptr = this_server.load();
if (ptr == nullptr) {
return;
}
this_server = nullptr;
ptr->stop();
};
std::signal(SIGINT, quit_handler);
#if !defined(_WIN32)
std::signal(SIGQUIT, quit_handler);
#endif // !defined(_WIN32)
std::signal(SIGTERM, quit_handler);
server_->listen("127.0.0.1", config_->get_api_port());
this_server = nullptr;
}
handlers::~handlers() { event_system::instance().stop(); }
void handlers::handle_get_mount(auto &&req, auto &&res) const {
REPERTORY_USES_FUNCTION_NAME();
auto prov = provider_type_from_string(req.get_param_value("type"));
auto lines = handlers::read_process(prov, req.get_param_value("name"), "-dc");
if (lines.at(0U) != "0") {
throw utils::error::create_exception(function_name, {
"command failed",
lines.at(0U),
});
}
lines.erase(lines.begin());
auto result = nlohmann::json::parse(utils::string::join(lines, '\n'));
res.set_content(result.dump(), "application/json");
res.status = http_error_codes::ok;
}
void handlers::handle_get_mount_list(auto &&res) const {
auto data_dir = utils::file::directory{app_config::get_root_data_directory()};
nlohmann::json result;
auto encrypt_dir = data_dir.get_directory("encrypt");
if (encrypt_dir && encrypt_dir->get_file("config.json")) {
result["encrypt"].emplace_back("encrypt");
}
const auto process_dir = [&data_dir, &result](std::string_view name) {
auto name_dir = data_dir.get_directory(name);
if (not name_dir) {
return;
}
for (const auto &dir : name_dir->get_directories()) {
if (not dir->get_file("config.json")) {
continue;
}
result[name].emplace_back(
utils::path::strip_to_file_name(dir->get_path()));
}
};
process_dir("remote");
process_dir("s3");
process_dir("sia");
res.set_content(result.dump(), "application/json");
res.status = http_error_codes::ok;
}
void handlers::handle_get_mount_status(auto &&req, auto &&res) const {
REPERTORY_USES_FUNCTION_NAME();
auto type = req.get_param_value("type");
auto prov = provider_type_from_string(type);
auto status_name = app_config::get_provider_display_name(prov);
auto name = req.get_param_value("name");
switch (prov) {
case provider_type::encrypt:
break;
case provider_type::remote: {
auto parts = utils::string::split(name, '_', false);
status_name = fmt::format("{}{}:{}", status_name, parts[0U], parts[1U]);
} break;
case provider_type::sia:
case provider_type::s3:
status_name = fmt::format("{}{}", status_name, name);
break;
default:
throw utils::error::create_exception(
function_name, {
fmt::format("`{}` is not supported", name),
});
}
auto lines = handlers::read_process(prov, name, "-status");
auto result =
nlohmann::json::parse(utils::string::join(lines, '\n')).at(status_name);
res.set_content(result.dump(), "application/json");
res.status = http_error_codes::ok;
}
auto handlers::read_process(provider_type prov, std::string_view name,
std::string_view command)
-> std::vector<std::string> {
REPERTORY_USES_FUNCTION_NAME();
std::string str_type;
switch (prov) {
case provider_type::encrypt:
str_type = "-en";
break;
case provider_type::remote: {
auto parts = utils::string::split(name, '_', false);
str_type = fmt::format("-rm {}:{}", parts[0U], parts[1U]);
} break;
case provider_type::s3:
str_type = fmt::format("-s3 -na {}", name);
break;
case provider_type::sia:
str_type = fmt::format("-na {}", name);
break;
default:
throw utils::error::create_exception(
function_name, {
fmt::format("`{}` is not supported", name),
});
}
auto cmd_line = fmt::format("repertory {} {}", str_type, command);
auto *pipe = popen(cmd_line.c_str(), "r");
if (pipe == nullptr) {
return {};
}
std::string data;
std::array<char, 1024U> buffer{};
while (feof(pipe) == 0) {
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
data += buffer.data();
}
}
pclose(pipe);
return utils::string::split(utils::string::replace(data, "\r", ""), '\n',
false);
}
} // namespace repertory::ui

View File

@ -268,8 +268,8 @@ public:
return file_path;
}
static auto create_file_and_test(std::string &file_name,
mode_t perms) -> std::string {
static auto create_file_and_test(std::string &file_name, mode_t perms)
-> std::string {
file_name += std::to_string(++provider_idx);
auto file_path = utils::path::combine(mount_location, {file_name});
@ -287,7 +287,7 @@ public:
EXPECT_TRUE(utils::file::file(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(getgid(), unix_st.st_gid);
EXPECT_EQ(getuid(), unix_st.st_uid);
@ -299,8 +299,8 @@ public:
return create_file_and_test(file_name, ACCESSPERMS);
}
static auto create_directory_and_test(std::string &dir_name,
mode_t perms) -> std::string {
static auto create_directory_and_test(std::string &dir_name, mode_t perms)
-> std::string {
dir_name += std::to_string(++provider_idx);
auto dir_path = utils::path::combine(mount_location, {dir_name});
@ -309,7 +309,7 @@ public:
EXPECT_TRUE(utils::file::directory(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(getgid(), unix_st.st_gid);
EXPECT_EQ(getuid(), unix_st.st_uid);
@ -410,9 +410,9 @@ std::string fuse_test<provider_t>::mount_location;
template <typename provider_t>
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, local_sia, remote_sia>;
// using fuse_provider_types = ::testing::Types<local_s3, remote_s3>;
using fuse_provider_types =
::testing::Types<local_s3, remote_s3, local_sia, remote_sia>;
} // namespace repertory
#endif // !defined(_WIN32)

View File

@ -36,6 +36,10 @@ private:
const bool allow_rename_;
public:
MOCK_METHOD(bool, check_version,
(std::string & required_version, std::string &returned_version),
(const, override));
MOCK_METHOD(api_error, create_directory,
(const std::string &api_path, api_meta_map &meta), (override));

View 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

View File

@ -24,7 +24,7 @@
#include "types/repertory.hpp"
namespace repertory {
TEST(atomic, atomic_primitive) {
TEST(atomic_test, atomic_primitive) {
atomic<std::uint16_t> value;
value = 5U;
EXPECT_EQ(5U, static_cast<std::uint16_t>(value));
@ -35,7 +35,7 @@ TEST(atomic, atomic_primitive) {
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> value2{5U};
EXPECT_EQ(value1, value1);
@ -45,7 +45,7 @@ TEST(atomic, atomic_primitive_equality) {
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> value2{6U};
EXPECT_NE(value1, value2);
@ -53,7 +53,7 @@ TEST(atomic, atomic_primitive_inequality) {
EXPECT_NE(static_cast<std::uint16_t>(value2), 5U);
}
TEST(atomic, atomic_struct) {
TEST(atomic_test, atomic_struct) {
atomic<encrypt_config> value{
encrypt_config{
.encryption_token = "token",

View File

@ -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

View File

@ -25,7 +25,7 @@
#include "types/repertory.hpp"
namespace repertory {
TEST(curl_comm, can_create_s3_host_config) {
TEST(curl_comm_test, can_create_s3_host_config) {
s3_config config{};
config.bucket = "repertory";
config.url = "https://s3.test.com";
@ -37,7 +37,7 @@ TEST(curl_comm, can_create_s3_host_config) {
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{};
config.bucket = "repertory";
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());
}
TEST(curl_comm, can_create_s3_host_config_with_region) {
TEST(curl_comm_test, can_create_s3_host_config_with_region) {
s3_config config{};
config.bucket = "repertory";
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());
}
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{};
config.bucket = "repertory";
config.url = "https://s3.test.com";

View File

@ -25,7 +25,7 @@
#include "types/repertory.hpp"
namespace repertory {
TEST(json_serialize, can_handle_directory_item) {
TEST(json_serialize_test, can_handle_directory_item) {
directory_item cfg{
"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{
"token",
"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{
"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{
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"};
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{
"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{
"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({
"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);
EXPECT_EQ(database_type::rocksdb, data.get<database_type>());
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());
}
TEST(json_serialize, can_handle_download_type) {
TEST(json_serialize_test, can_handle_download_type) {
json data(download_type::direct);
EXPECT_EQ(download_type::direct, data.get<download_type>());
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());
}
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});
EXPECT_EQ(database_type::rocksdb, data.get<atomic<database_type>>());
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());
}
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});
EXPECT_EQ(download_type::direct, data.get<atomic<download_type>>());
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_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

View File

@ -24,7 +24,7 @@
#include "platform/platform.hpp"
namespace repertory {
TEST(lock_data, lock_and_unlock) {
TEST(lock_data_test, lock_and_unlock) {
{
lock_data l(provider_type::sia, "1");
EXPECT_EQ(lock_result::success, l.grab_lock());
@ -50,7 +50,7 @@ TEST(lock_data, lock_and_unlock) {
}
#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");
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());
}
#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");
EXPECT_TRUE(l.set_mount_state(true, "/mnt/1", 99));

View File

@ -24,7 +24,7 @@
#include "comm/packet/packet.hpp"
namespace repertory {
TEST(packet, encrypt_and_decrypt) {
TEST(packet_test, encrypt_and_decrypt) {
packet test_packet;
test_packet.encode("test");
test_packet.encrypt("moose");

View File

@ -19,8 +19,6 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#if 0
#include "test_common.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]));
EXPECT_EQ(std::uint64_t(0U),
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(
meta2[repertory::META_UID])));
EXPECT_EQ(date + 4U, repertory::utils::string::to_uint64(
@ -178,6 +174,9 @@ const auto decrypt_parts = [](const repertory::app_config &cfg,
namespace repertory {
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()) {
api_meta_map meta{};
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) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
if (provider.is_read_only()) {
return;
}
@ -210,6 +212,9 @@ static void create_directory_fails_if_already_exists(i_provider &provider) {
static void
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()) {
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) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
if (provider.is_read_only()) {
EXPECT_EQ(api_error::not_implemented,
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(
i_provider &provider) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
if (provider.is_read_only()) {
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(
i_provider &provider) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
if (provider.is_read_only()) {
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(
i_provider &provider) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
if (provider.is_read_only()) {
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) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
if (provider.is_read_only()) {
api_meta_map meta{};
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) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
if (provider.is_read_only()) {
return;
}
@ -331,6 +354,9 @@ static void create_file_fails_if_already_exists(i_provider &provider) {
static void
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()) {
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,
i_provider &provider) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
if (provider.get_provider_type() == provider_type::encrypt) {
const auto source_path =
utils::path::combine("./test_date/encrypt", {"test.txt"});
auto source_path =
utils::path::combine("./test_input/encrypt", {"test.txt"});
std::string api_path{};
EXPECT_EQ(api_error::success,
@ -376,6 +405,9 @@ static void get_api_path_from_source(const app_config &cfg,
static void
get_api_path_from_source_fails_if_file_not_found(const app_config &cfg,
i_provider &provider) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
std::string source_path{};
if (provider.get_provider_type() == provider_type::encrypt) {
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());
}
static void get_directory_item_count(const app_config &cfg,
static void get_directory_item_count(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) {
EXPECT_EQ(std::size_t(2U), provider.get_directory_item_count("/"));
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"});
std::string api_path{};
EXPECT_EQ(api_error::success,
provider.get_api_path_from_source(source_path, 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{};
EXPECT_EQ(api_error::success, provider.get_directory_items("/", 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) {
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());
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);
#endif
const auto source_path =
auto source_path =
utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
std::string api_path{};
EXPECT_EQ(api_error::success,
@ -472,11 +526,58 @@ static void get_directory_items(const app_config &cfg, i_provider &provider) {
#else
EXPECT_EQ(std::size_t(45U), file2->size);
#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
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{};
EXPECT_EQ(api_error::directory_not_found,
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,
i_provider &provider) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
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"});
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,
provider.get_directory_items(api_path, list));
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) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
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"});
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);
#endif
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) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
api_file 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,
i_provider &provider) {
fmt::println("testing|{}|{}",
app_config::get_provider_name(provider.get_provider_type()),
__FUNCTION__);
if (provider.get_provider_type() == provider_type::encrypt) {
const auto source_path =
auto source_path =
utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
std::string api_path{};
@ -542,7 +683,15 @@ static void get_file_fails_if_item_is_directory(const app_config &cfg,
api_file 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) {
@ -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_fails_if_file_not_found(cfg, provider);
// TODO: continue here
get_directory_items(cfg, provider);
get_directory_items_fails_if_directory_not_found(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); */
}
TEST(providers, encrypt_provider) {
const auto config_path =
utils::path::combine(test::get_test_output_dir(), {"encrypt_provider"});
TEST(providers_test, encrypt_provider) {
auto config_path = utils::path::combine(test::get_test_output_dir(),
{"provider", "encrypt"});
console_consumer consumer{};
event_system::instance().start();
{
app_config cfg(provider_type::encrypt, config_path);
const auto encrypt_path =
auto encrypt_path =
utils::path::combine(test::get_test_input_dir(), {"encrypt"});
EXPECT_STREQ(
@ -673,9 +820,9 @@ TEST(providers, encrypt_provider) {
event_system::instance().stop();
}
TEST(providers, s3_provider) {
const auto config_path =
utils::path::combine(test::get_test_output_dir(), {"s3_provider"});
TEST(providers_test, s3_provider) {
auto config_path =
utils::path::combine(test::get_test_output_dir(), {"provider", "s3"});
console_consumer consumer{};
event_system::instance().start();
@ -685,7 +832,7 @@ TEST(providers, s3_provider) {
{
app_config src_cfg(
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());
}
@ -713,9 +860,9 @@ TEST(providers, s3_provider) {
event_system::instance().stop();
}
TEST(providers, sia_provider) {
const auto config_path =
utils::path::combine(test::get_test_output_dir(), {"sia_provider"});
TEST(providers_test, sia_provider) {
auto config_path =
utils::path::combine(test::get_test_output_dir(), {"sia", "provider"});
console_consumer consumer{};
event_system::instance().start();
@ -753,5 +900,3 @@ TEST(providers, sia_provider) {
event_system::instance().stop();
}
} // namespace repertory
#endif // 0

View File

@ -29,7 +29,7 @@
namespace repertory {
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;
event_system::instance().start();
@ -71,7 +71,7 @@ TEST(upload, can_upload_a_valid_file) {
event_system::instance().stop();
}
TEST(upload, can_cancel_upload) {
TEST(upload_test, can_cancel_upload) {
console_consumer con;
event_system::instance().start();
@ -135,7 +135,7 @@ TEST(upload, can_cancel_upload) {
event_system::instance().stop();
}
TEST(upload, can_stop_upload) {
TEST(upload_test, can_stop_upload) {
console_consumer con;
event_system::instance().start();

View File

@ -25,7 +25,7 @@
#include "utils/file.hpp"
namespace repertory {
TEST(utils, convert_api_date) {
TEST(utils_test, convert_api_date) {
#if defined(_WIN32)
auto file_time = utils::time::unix_time_to_filetime(
s3_provider::convert_api_date("2009-10-12T17:50:30.111Z"));
@ -63,7 +63,7 @@ TEST(utils, convert_api_date) {
#endif // defined(_WIN32)
}
TEST(utils, generate_sha256) {
TEST(utils_test, generate_sha256) {
auto res = utils::file::file{__FILE__}.sha256();
EXPECT_TRUE(res.has_value());
if (res.has_value()) {

View File

@ -38,14 +38,16 @@ BRANCH=$(git branch --show-current)
RELEASE=$(grep PROJECT_RELEASE_ITER= ./config.sh | sed s/PROJECT_RELEASE_ITER=//g)
popd
if [ "${BRANCH}" == "master" ] || [ "${BRANCH}" == "alpha" ] || [ "${BRANCH}" == "beta" ] || [ "${BRANCH}" == "rc" ]; then
if [ "${BRANCH}" == "master" ] || [ "${BRANCH}" == "alpha" ] ||
[ "${BRANCH}" == "beta" ] || [ "${BRANCH}" == "rc" ]; then
DEST_DIR=${DEST_DIR}/${RELEASE}
else
elif [[ ${BRANCH} = *'-alpha-'* ]] || [[ ${BRANCH} = *'-beta-'* ]] ||
[[ ${BRANCH} = *'-rc-'* ]] || [[ ${BRANCH} = *'-release-'* ]]; then
DEST_DIR=${DEST_DIR}/nightly
else
error_exit "skipping ${PROJECT_FILE_PART}" 0
fi
echo ${DEST_DIR}
pushd "${DIST_DIR}"
if [ ! -f "./${PROJECT_OUT_FILE}" ]; then
error_exit "failed to find file: ${PROJECT_OUT_FILE}" 1

View File

@ -1,6 +1,7 @@
#!/bin/bash
if [ "${PROJECT_BUILD_ARCH}" == "aarch64" ]; then
if [ "${PROJECT_BUILD_ARCH}" == "aarch64" ] &&
[ "${PROJECT_ENABLE_MULTIARCH_DOCKER}" == "1" ]; then
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
fi

View File

@ -7,6 +7,12 @@ PROJECT_IS_MINGW=$4
PROJECT_IS_MINGW_UNIX=$5
DISABLE_CREATE_DIRS=$6
PROJECT_FLUTTER_BASE_HREF="/"
if [ "${PROJECT_IS_MINGW}" != "1" ]; then
PROJECT_IS_MINGW_UNIX=0
fi
PROJECT_SOURCE_DIR=${PROJECT_SCRIPTS_DIR}/..
PROJECT_SOURCE_DIR=$(realpath "${PROJECT_SOURCE_DIR}")
@ -42,6 +48,7 @@ done
PROJECT_APP_LIST=()
PROJECT_CMAKE_OPTS=""
PROJECT_ENABLE_WIN32_LONG_PATH_NAMES=OFF
PROJECT_ENABLE_V2_ERRORS=OFF
PROJECT_IS_ALPINE=0
PROJECT_IS_ARM64=0
PROJECT_MINGW64_COPY_DEPENDENCIES=()
@ -234,6 +241,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_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_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_EXTERNAL_BUILD_ROOT=${PROJECT_EXTERNAL_BUILD_ROOT} ${PROJECT_CMAKE_OPTS}"
PROJECT_CMAKE_OPTS="-DPROJECT_GIT_REV=${PROJECT_GIT_REV} ${PROJECT_CMAKE_OPTS}"
@ -304,8 +312,10 @@ export PROJECT_COMPANY_NAME
export PROJECT_COPYRIGHT
export PROJECT_DESC
export PROJECT_DIST_DIR
export PROJECT_ENABLE_V2_ERRORS
export PROJECT_ENABLE_WIN32_LONG_PATH_NAMES
export PROJECT_FILE_PART
export PROJECT_FLUTTER_BASE_HREF
export PROJECT_GIT_REV
export PROJECT_IS_ALPINE
export PROJECT_IS_ARM64
@ -355,8 +365,10 @@ echo " Company name: ${PROJECT_COMPANY_NAME}"
echo " Copyright: ${PROJECT_COPYRIGHT}"
echo " Description: ${PROJECT_DESC}"
echo " Dist dir: ${PROJECT_DIST_DIR}"
echo " Enable v2 errors: ${PROJECT_ENABLE_V2_ERRORS}"
echo " External build root: ${PROJECT_EXTERNAL_BUILD_ROOT}"
echo " File part: ${PROJECT_FILE_PART}"
echo " Flutter base href: ${PROJECT_FLUTTER_BASE_HREF}"
echo " Is ARM64: ${PROJECT_IS_ARM64}"
echo " Is Alpine: ${PROJECT_IS_ALPINE}"
echo " Is MINGW on Unix: ${PROJECT_IS_MINGW_UNIX}"

View File

@ -59,7 +59,7 @@ PROJECT_DOWNLOADS[PKG_CONFIG]="https://pkgconfig.freedesktop.org/releases/pkg-co
PROJECT_DOWNLOADS[PUGIXML]="https://github.com/zeux/pugixml/releases/download/v${PROJECT_VERSIONS[PUGIXML]}/pugixml-${PROJECT_VERSIONS[PUGIXML]}.tar.gz;pugixml-${PROJECT_VERSIONS[PUGIXML]}.tar.gz;3rd_party"
PROJECT_DOWNLOADS[ROCKSDB]="https://github.com/facebook/rocksdb/archive/refs/tags/v${PROJECT_VERSIONS[ROCKSDB]}.tar.gz;rocksdb-${PROJECT_VERSIONS[ROCKSDB]}.tar.gz;3rd_party"
PROJECT_DOWNLOADS[SPDLOG]="https://github.com/gabime/spdlog/archive/refs/tags/v${PROJECT_VERSIONS[SPDLOG]}.tar.gz;spdlog-${PROJECT_VERSIONS[SPDLOG]}.tar.gz;3rd_party"
PROJECT_DOWNLOADS[SQLITE]="https://www.sqlite.org/2024/sqlite-amalgamation-${PROJECT_VERSIONS[SQLITE]}.zip;sqlite-amalgamation-${PROJECT_VERSIONS[SQLITE]}.zip;3rd_party"
PROJECT_DOWNLOADS[SQLITE]="https://www.sqlite.org/2025/sqlite-amalgamation-${PROJECT_VERSIONS[SQLITE]}.zip;sqlite-amalgamation-${PROJECT_VERSIONS[SQLITE]}.zip;3rd_party"
PROJECT_DOWNLOADS[STDUUID]="https://github.com/mariusbancila/stduuid/archive/refs/tags/v${PROJECT_VERSIONS[STDUUID]}.tar.gz;stduuid-${PROJECT_VERSIONS[STDUUID]}.tar.gz;3rd_party"
PROJECT_DOWNLOADS[ZLIB]="https://github.com/madler/zlib/archive/refs/tags/v${PROJECT_VERSIONS[ZLIB]}.tar.gz;zlib-${PROJECT_VERSIONS[ZLIB]}.tar.gz;3rd_party/mingw64"
export PROJECT_DOWNLOADS

View File

@ -18,6 +18,8 @@ fi
ln -sf "${PROJECT_BUILD_DIR}/build/compile_commands.json" "${PROJECT_SOURCE_DIR}/compile_commands.json"
pushd "${PROJECT_BUILD_DIR}"
export CMAKE_BUILD_PARALLEL_LEVEL=${NUM_JOBS}
cmake "${PROJECT_SOURCE_DIR}" \
-G"Unix Makefiles" \
-DPROJECT_COMPANY_NAME="${PROJECT_COMPANY_NAME}" \
@ -34,10 +36,10 @@ if [ "${PROJECT_BUILD_CLEAN}" == "clean" ]; then
popd
fi
make -j${NUM_JOBS} || exit 1
make || exit 1
pushd build
make -j${NUM_JOBS} || exit 1
make -j${CMAKE_BUILD_PARALLEL_LEVEL} || exit 1
popd
popd
@ -79,6 +81,11 @@ EOF
fi
done
if [ -f "${PROJECT_SOURCE_DIR}/web/${PROJECT_NAME}/pubspec.yaml" ]; then
rsync -av --progress "${PROJECT_SOURCE_DIR}/web/${PROJECT_NAME}/build/web/" \
"${PROJECT_DIST_DIR}/web/"
fi
if [ "${PROJECT_IS_MINGW}" == "1" ]; then
. "${PROJECT_SCRIPTS_DIR}/copy_mingw64_deps.sh" "$1" "$2" "$3" "$4" "$5"
fi

43
scripts/make_flutter.sh Executable file
View File

@ -0,0 +1,43 @@
#!/bin/bash
PROJECT_SCRIPTS_DIR=$(realpath "$0")
PROJECT_SCRIPTS_DIR=$(dirname "${PROJECT_SCRIPTS_DIR}")
. "${PROJECT_SCRIPTS_DIR}/env.sh" "$1" "$2" "$3" "$4" "$5"
if [ -f "${PROJECT_SOURCE_DIR}/web/${PROJECT_NAME}/pubspec.yaml" ]; then
if [ "${PROJECT_IS_MINGW}" == "0" ] || [ "${PROJECT_IS_MINGW_UNIX}" == "1" ]; then
FLUTTER_CONTAINER_NAME="${PROJECT_NAME}_flutter"
FLUTTER_TAG_NAME="${PROJECT_NAME}:flutter"
docker stop ${FLUTTER_CONTAINER_NAME}
docker rm ${FLUTTER_CONTAINER_NAME}
docker build "${PROJECT_SOURCE_DIR}/docker/x86_64/" \
--build-arg UID=$(id -u) \
--build-arg GID=$(id -g) \
-t ${FLUTTER_TAG_NAME} \
-f "${PROJECT_SOURCE_DIR}/docker/x86_64/flutter" || exit 1
docker run -td \
--name ${FLUTTER_CONTAINER_NAME} \
-u $(id -u):$(id -g) \
-v ${PROJECT_SOURCE_DIR}:${PROJECT_SOURCE_DIR}:rw,z \
-w ${PROJECT_SOURCE_DIR}/web/${PROJECT_NAME} \
${FLUTTER_TAG_NAME} || exit 1
docker exec \
${FLUTTER_CONTAINER_NAME} \
/bin/bash -c \
"flutter clean;flutter build web --base-href=${PROJECT_FLUTTER_BASE_HREF}" || exit 1
docker stop ${FLUTTER_CONTAINER_NAME}
docker rm ${FLUTTER_CONTAINER_NAME}
else
pushd "${PROJECT_SOURCE_DIR}/web/${PROJECT_NAME}"
export MSYS_NO_PATHCONV=1
flutter clean
flutter build web --base-href=${PROJECT_FLUTTER_BASE_HREF} || exit 1
export MSYS_NO_PATHCONV=0
popd
fi
fi

View File

@ -9,6 +9,8 @@ if [ -f "${PROJECT_SCRIPTS_DIR}/cleanup.sh" ]; then
rm ${PROJECT_SCRIPTS_DIR}/cleanup.*
fi
"${PROJECT_SOURCE_DIR}/scripts/make_flutter.sh" "${PROJECT_BUILD_ARCH}" "${PROJECT_CMAKE_BUILD_TYPE}" "${PROJECT_BUILD_CLEAN}" 0 0 || exit 1
if [ "${PROJECT_REQUIRE_ALPINE}" == "ON" ] || [ "${PROJECT_IS_ARM64}" == "1" ]; then
DOCKER_NAME=alpine
DOCKER_CONTAINER=${PROJECT_NAME}_${DOCKER_NAME}_${PROJECT_BUILD_ARCH}

View File

@ -12,5 +12,7 @@ pushd "%~dp0%"
call cleanup.cmd "%ARG1%" "%ARG2%" "%ARG3%" 1 0
del cleanup.*
)
call mingw64 -no-start ./make_flutter.sh "%ARG1%" "%ARG2%" "%ARG3%" 1 0 || exit 1
call mingw64 -no-start ./make_common.sh "%ARG1%" "%ARG2%" "%ARG3%" 1 0 || exit 1
popd

View File

@ -8,25 +8,25 @@ PROJECT_VERSIONS[BOOST2_PATCH]="0"
PROJECT_VERSIONS[BOOST_MAJOR]="1"
PROJECT_VERSIONS[BOOST_MINOR]="87"
PROJECT_VERSIONS[BOOST_PATCH]="0"
PROJECT_VERSIONS[CPP_HTTPLIB]="0.18.1"
PROJECT_VERSIONS[CURL]="8.11.0"
PROJECT_VERSIONS[CURL2]="8_11_0"
PROJECT_VERSIONS[CPP_HTTPLIB]="0.19.0"
PROJECT_VERSIONS[CURL]="8.12.1"
PROJECT_VERSIONS[CURL2]="8_12_1"
PROJECT_VERSIONS[EXPAT]="2.6.4"
PROJECT_VERSIONS[EXPAT2]="2_6_4"
PROJECT_VERSIONS[GCC]="14.2.0"
PROJECT_VERSIONS[GTEST]="1.15.2"
PROJECT_VERSIONS[GTEST]="1.16.0"
PROJECT_VERSIONS[ICU]="76-1"
PROJECT_VERSIONS[JSON]="3.11.3"
PROJECT_VERSIONS[LIBSODIUM]="1.0.20"
PROJECT_VERSIONS[MESA]="23.3.3"
PROJECT_VERSIONS[MINGW]="12.0.0"
PROJECT_VERSIONS[OPENSSL]="3.4.0"
PROJECT_VERSIONS[OPENSSL]="3.4.1"
PROJECT_VERSIONS[PKG_CONFIG]="0.29.2"
PROJECT_VERSIONS[PUGIXML]="1.14"
PROJECT_VERSIONS[ROCKSDB]="9.7.4"
PROJECT_VERSIONS[SPDLOG]="1.15.0"
PROJECT_VERSIONS[SQLITE]="3460100"
PROJECT_VERSIONS[SQLITE2]="3.46.1"
PROJECT_VERSIONS[PUGIXML]="1.15"
PROJECT_VERSIONS[ROCKSDB]="9.10.0"
PROJECT_VERSIONS[SPDLOG]="1.15.1"
PROJECT_VERSIONS[SQLITE]="3490100"
PROJECT_VERSIONS[SQLITE2]="3.49.1"
PROJECT_VERSIONS[STDUUID]="1.2.3"
PROJECT_VERSIONS[ZLIB]="1.3.1"
export PROJECT_VERSIONS

Binary file not shown.

View File

@ -1 +0,0 @@
405abd8170f2a446fc8612ac635d0db5947c0d2e156e32603403a4496255ff00 *cpp-httplib-0.18.1.tar.gz

Binary file not shown.

View File

@ -0,0 +1 @@
c9b9e0524666e1cd088f0874c57c1ce7c0eaa8552f9f4e15c755d5201fc8c608 *cpp-httplib-0.19.0.tar.gz

Binary file not shown.

View File

@ -1 +0,0 @@
5a231145114589491fc52da118f9c7ef8abee885d1cb1ced99c7290e9a352f07 *curl-8.11.0.tar.gz

BIN
support/3rd_party/curl-8.12.1.tar.gz vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
6edc063d1ebaf9cf3b3b46e9fef2f3cd8932694989ecd43d005d6e828426d09f *curl-8.12.1.tar.gz

Binary file not shown.

View File

@ -0,0 +1 @@
78c676fc63881529bf97bf9d45948d905a66833fbfa5318ea2cd7478cb98f399 *googletest-1.16.0.tar.gz

View File

@ -1 +0,0 @@
e15dda82fe2fe8139dc2ac21a36d4ca01d5313c75f99f46c4e8a27709b7294bf *openssl-3.4.0.tar.gz

View File

@ -0,0 +1 @@
002a2d6b30b58bf4bea46c43bdd96365aaf8daa6c428782aa4feee06da197df3 *openssl-3.4.1.tar.gz

Binary file not shown.

View File

@ -1 +0,0 @@
2f10e276870c64b1db6809050a75e11a897a8d7456c4be5c6b2e35a11168a015 pugixml-1.14.tar.gz

BIN
support/3rd_party/pugixml-1.15.tar.gz vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
655ade57fa703fb421c2eb9a0113b5064bddb145d415dd1f88c79353d90d511a *pugixml-1.15.tar.gz

View File

@ -0,0 +1 @@
fdccab16133c9d927a183c2648bcea8d956fb41eb1df2aacaa73eb0b95e43724 *rocksdb-9.10.0.tar.gz

View File

@ -1 +0,0 @@
9b810c81731835fda0d4bbdb51d3199d901fa4395733ab63752d297da84c5a47 *rocksdb-9.7.4.tar.gz

Binary file not shown.

View File

@ -1 +0,0 @@
9962648c9b4f1a7bbc76fd8d9172555bad1871fdb14ff4f842ef87949682caa5 *spdlog-1.15.0.tar.gz

BIN
support/3rd_party/spdlog-1.15.1.tar.gz vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
25c843860f039a1600f232c6eb9e01e6627f7d030a2ae5e232bdd3c9205d26cc *spdlog-1.15.1.tar.gz

Binary file not shown.

View File

@ -1 +0,0 @@
77823cb110929c2bcb0f5d48e4833b5c59a8a6e40cdea3936b99e199dbbe5784 sqlite-amalgamation-3460100.zip

Binary file not shown.

View File

@ -0,0 +1 @@
6cebd1d8403fc58c30e93939b246f3e6e58d0765a5cd50546f16c00fd805d2c3 *sqlite-amalgamation-3490100.zip

Some files were not shown because too many files have changed in this diff Show More