Compare commits
108 Commits
v2.0.3-rc
...
d664c6a884
Author | SHA1 | Date | |
---|---|---|---|
d664c6a884 | |||
430fc1a651 | |||
314ee5b664 | |||
9eb8b5e682 | |||
bd386314a4 | |||
aee2413440 | |||
307fcb3332 | |||
28fefca765 | |||
3e09adaba3 | |||
e01ed2c1b8 | |||
ece42df528 | |||
45080aa32f | |||
fb9c8c8bb6 | |||
7a3ce13db0 | |||
6945a16f78 | |||
1153598c62 | |||
2afa403c8c | |||
d09210d9c4 | |||
2ca2002423 | |||
011d32f9cf | |||
7487caca2a | |||
f921295dbd | |||
13b2ee6f7a | |||
144baf4371 | |||
c6ade2e5f7 | |||
fb89cc08ae | |||
f08870b03c | |||
711e3f73cf | |||
ebb620fdb2 | |||
fbf9c85d48 | |||
d5e0252ed3 | |||
06b79ffd2d | |||
690902b31d | |||
0bfe1e1ccd | |||
a8723a6b02 | |||
1d88d26d0a | |||
757c880616 | |||
d65bd6af35 | |||
b285478cc5 | |||
31cd5acaee | |||
65036f2957 | |||
2362300bba | |||
f61f3d5fa4 | |||
a2b8998f4a | |||
a4d53c1011 | |||
4b925c15c2 | |||
bbd82e3f0f | |||
37f2cbc78d | |||
1ad3704fa0 | |||
a6e70d93cb | |||
967324a368 | |||
69b31bfde8 | |||
8b4724a9c1 | |||
6a0d50bc66 | |||
69910bef4c | |||
8c298c84c5 | |||
47dea2cc38 | |||
d8b476e80a | |||
c86c6e2ec6 | |||
c397497eb7 | |||
f8803dfbf0 | |||
5d5cacc482 | |||
3ce4210d56 | |||
d109344544 | |||
ff746a7bec | |||
a613ec77ff | |||
00d3dd95a8 | |||
28d1789f04 | |||
0603463885 | |||
88398485e1 | |||
908e75c696 | |||
dab8c61f87 | |||
e0cf58b01e | |||
281d3758e0 | |||
dfa170022a | |||
52c2780283 | |||
c2dbfc970a | |||
6f9b1f8f08 | |||
078d603be9 | |||
983e47103b | |||
8d2024d34b | |||
4f2ee2ad99 | |||
533938bcef | |||
98edf33be4 | |||
a080c9ff86 | |||
e6cdcd74a1 | |||
573ae549be | |||
fca149f998 | |||
76e375c488 | |||
3f9322f659 | |||
c286d496c3 | |||
56ba0fcb83 | |||
dcafb104ea | |||
ab757dfd36 | |||
eec2d2e9a9 | |||
8c1c91e02b | |||
bb85015733 | |||
883de836c6 | |||
bf2bdd1b5d | |||
f1e82d8f9f | |||
f5c4aebdac | |||
f2f9e8fd15 | |||
2a673915af | |||
df3db38ae7 | |||
b0b69c6dd4 | |||
11b118a30f | |||
62555e6125 | |||
24418ba03d |
@ -3,6 +3,7 @@ _mkgmtime
|
|||||||
_sh_denyno
|
_sh_denyno
|
||||||
_sh_denyrd
|
_sh_denyrd
|
||||||
_sh_denyrw
|
_sh_denyrw
|
||||||
|
_spawnv
|
||||||
aarch64
|
aarch64
|
||||||
advapi32
|
advapi32
|
||||||
armv8
|
armv8
|
||||||
@ -114,6 +115,7 @@ googletest
|
|||||||
gpath
|
gpath
|
||||||
gtest_version
|
gtest_version
|
||||||
has_setxattr
|
has_setxattr
|
||||||
|
hkey
|
||||||
httpapi
|
httpapi
|
||||||
httplib
|
httplib
|
||||||
icudata
|
icudata
|
||||||
@ -121,6 +123,7 @@ icui18n
|
|||||||
icuuc
|
icuuc
|
||||||
iostreams
|
iostreams
|
||||||
iphlpapi
|
iphlpapi
|
||||||
|
ipstream
|
||||||
jthread
|
jthread
|
||||||
libbitcoin
|
libbitcoin
|
||||||
libbitcoinsystem
|
libbitcoinsystem
|
||||||
@ -142,6 +145,7 @@ libuuid_include_dirs
|
|||||||
libvlc
|
libvlc
|
||||||
linkflags
|
linkflags
|
||||||
localappdata
|
localappdata
|
||||||
|
lpbyte
|
||||||
lptr
|
lptr
|
||||||
lpwstr
|
lpwstr
|
||||||
markdownlint
|
markdownlint
|
||||||
@ -154,8 +158,10 @@ mtune
|
|||||||
musl-libc
|
musl-libc
|
||||||
nana
|
nana
|
||||||
ncrypt
|
ncrypt
|
||||||
|
nlohmann
|
||||||
nlohmann_json
|
nlohmann_json
|
||||||
nmakeprg
|
nmakeprg
|
||||||
|
nohup
|
||||||
nominmax
|
nominmax
|
||||||
ntstatus
|
ntstatus
|
||||||
nullptr
|
nullptr
|
||||||
@ -163,6 +169,7 @@ nuspell_version
|
|||||||
oleaut32
|
oleaut32
|
||||||
openal_version
|
openal_version
|
||||||
openssldir
|
openssldir
|
||||||
|
pistream
|
||||||
pkgconfig
|
pkgconfig
|
||||||
plarge_integer
|
plarge_integer
|
||||||
plex
|
plex
|
||||||
@ -192,6 +199,7 @@ secp256k1
|
|||||||
secur32
|
secur32
|
||||||
sfml_project
|
sfml_project
|
||||||
shlwapi
|
shlwapi
|
||||||
|
skynet
|
||||||
source_subdir
|
source_subdir
|
||||||
spdlog
|
spdlog
|
||||||
spdlog_project
|
spdlog_project
|
||||||
|
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.tar.gz filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.tar.xz filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.zip filter=lfs diff=lfs merge=lfs -text
|
@ -1,36 +0,0 @@
|
|||||||
{
|
|
||||||
"configurations": {
|
|
||||||
"UnixDebug": {
|
|
||||||
"adapter": "vscode-cpptools",
|
|
||||||
"configuration": {
|
|
||||||
"request": "launch",
|
|
||||||
"program": "${workspaceRoot}/build/debug/repertory",
|
|
||||||
"args": ["-f", "/home/sgraves/mnt"],
|
|
||||||
"cwd": "${workspaceRoot}/build/debug",
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": true,
|
|
||||||
"MIMode": "gdb",
|
|
||||||
"stopAtEntry": true,
|
|
||||||
"logging": {
|
|
||||||
"engineLogging": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"UnixDebugTest": {
|
|
||||||
"adapter": "vscode-cpptools",
|
|
||||||
"configuration": {
|
|
||||||
"request": "launch",
|
|
||||||
"program": "${workspaceRoot}/build/debug/unittests",
|
|
||||||
"args": ["--gtest_filter=file_manager.can_close_after_download_timeout"],
|
|
||||||
"cwd": "${workspaceRoot}/build",
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": true,
|
|
||||||
"MIMode": "gdb",
|
|
||||||
"stopAtEntry": true,
|
|
||||||
"logging": {
|
|
||||||
"engineLogging": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
67
CHANGELOG.md
67
CHANGELOG.md
@ -1,7 +1,73 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v2.0.6-release
|
||||||
|
|
||||||
|
### Issues
|
||||||
|
|
||||||
|
* ~~\#12 [Unit Test] Complete all providers unit tests~~
|
||||||
|
* ~~\#21 [Unit Test] Complete WinFSP unit tests~~
|
||||||
|
* ~~\#22 [Unit Test] Complete FUSE unit tests~~
|
||||||
|
* ~~\#33 Complete initial v2.0 documentation~~
|
||||||
|
* \#42 [bug] Remote mount directory listing on Windows connected to Linux is failing
|
||||||
|
* \#43 [bug] Directories are not importing properly for Sia
|
||||||
|
* \#44 [bug] Windows-to-Linux remote mount ignores `CREATE_NEW`
|
||||||
|
* \#45 [bug] Windows-to-Linux remote mount is not handling attempts to remove a non-empty directory properly
|
||||||
|
* \#46 [bug] Changes to maximum cache size should be updated live
|
||||||
|
* \#47 [bug] Windows-to-Linux remote mount is allowing directory rename when directory is not empty
|
||||||
|
* \#48 [bug] Windows-to-Linux remote mount overlapped I/O is not detecting EOF for read operations
|
||||||
|
|
||||||
|
### Changes from v2.0.5-rc
|
||||||
|
|
||||||
|
* Drive letters in UI should always be lowercase
|
||||||
|
* Migrated to v2 error handling
|
||||||
|
|
||||||
|
## v2.0.5-rc
|
||||||
|
|
||||||
|
<!-- markdownlint-disable-next-line -->
|
||||||
|
### Issues
|
||||||
|
|
||||||
|
* \#39 Create management portal in Flutter
|
||||||
|
|
||||||
|
### Changes from v2.0.4-rc
|
||||||
|
|
||||||
|
* Continue documentation updates
|
||||||
|
* Fixed `-status` command erasing active mount information
|
||||||
|
* Fixed overlapping HTTP REST API port's
|
||||||
|
* Refactored/fixed instance locking
|
||||||
|
* Removed passwords and secret key values from API calls
|
||||||
|
* Renamed setting `ApiAuth` to `ApiPassword`
|
||||||
|
* Require `--name,-na` option for encryption provider
|
||||||
|
|
||||||
|
## 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
|
## v2.0.3-rc
|
||||||
|
|
||||||
|
<!-- markdownlint-disable-next-line -->
|
||||||
### Issues
|
### Issues
|
||||||
|
|
||||||
* \#28 \[bug\] Address slow directory responses in S3 mounts for deeply nested directories
|
* \#28 \[bug\] Address slow directory responses in S3 mounts for deeply nested directories
|
||||||
@ -25,6 +91,7 @@
|
|||||||
|
|
||||||
## v2.0.2-rc
|
## v2.0.2-rc
|
||||||
|
|
||||||
|
<!-- markdownlint-disable-next-line -->
|
||||||
### BREAKING CHANGES
|
### BREAKING CHANGES
|
||||||
|
|
||||||
* Refactored `config.json` - will need to verify configuration settings prior to mounting
|
* Refactored `config.json` - will need to verify configuration settings prior to mounting
|
||||||
|
@ -58,6 +58,10 @@ if(PROJECT_IS_MINGW)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (PROJECT_ENABLE_V2_ERRORS)
|
||||||
|
add_definitions(-DPROJECT_ENABLE_V2_ERRORS)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(cmake/settings.cmake)
|
include(cmake/settings.cmake)
|
||||||
|
|
||||||
include(cmake/flags.cmake)
|
include(cmake/flags.cmake)
|
||||||
@ -143,6 +147,7 @@ endif()
|
|||||||
-DPROJECT_COPYRIGHT=${PROJECT_COPYRIGHT}
|
-DPROJECT_COPYRIGHT=${PROJECT_COPYRIGHT}
|
||||||
-DPROJECT_DESC=${PROJECT_DESC}
|
-DPROJECT_DESC=${PROJECT_DESC}
|
||||||
-DPROJECT_DIST_DIR=${PROJECT_DIST_DIR}
|
-DPROJECT_DIST_DIR=${PROJECT_DIST_DIR}
|
||||||
|
-DPROJECT_ENABLE_V2_ERRORS=${PROJECT_ENABLE_V2_ERRORS}
|
||||||
-DPROJECT_ENABLE_WIN32_LONG_PATH_NAMES=${PROJECT_ENABLE_WIN32_LONG_PATH_NAMES}
|
-DPROJECT_ENABLE_WIN32_LONG_PATH_NAMES=${PROJECT_ENABLE_WIN32_LONG_PATH_NAMES}
|
||||||
-DPROJECT_ENABLE_BOOST=${PROJECT_ENABLE_BOOST}
|
-DPROJECT_ENABLE_BOOST=${PROJECT_ENABLE_BOOST}
|
||||||
-DPROJECT_ENABLE_CPP_HTTPLIB=${PROJECT_ENABLE_CPP_HTTPLIB}
|
-DPROJECT_ENABLE_CPP_HTTPLIB=${PROJECT_ENABLE_CPP_HTTPLIB}
|
||||||
|
490
README.md
490
README.md
@ -3,149 +3,431 @@
|
|||||||
Repertory allows you to mount S3 and Sia via FUSE on Linux or via WinFSP
|
Repertory allows you to mount S3 and Sia via FUSE on Linux or via WinFSP
|
||||||
on Windows.
|
on Windows.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
1. [Details and Features](#details-and-features)
|
||||||
|
2. [Minimum Requirements](#minimum-requirements)
|
||||||
|
1. [Supported Operating Systems](#supported-operating-systems)
|
||||||
|
3. [GUI](#gui)
|
||||||
|
4. [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)
|
||||||
|
5. [Data Directories](#data-directories)
|
||||||
|
1. [Linux Directories](#linux-directories)
|
||||||
|
2. [Windows Directories](#windows-directories)
|
||||||
|
6. [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)
|
||||||
|
7. [Compiling](#compiling)
|
||||||
|
1. [Linux Compilation](#linux-compilation)
|
||||||
|
2. [Windows Setup](#windows-compilation)
|
||||||
|
8. [Credits](#credits)
|
||||||
|
9. [Developer Public Key](#developer-public-key)
|
||||||
|
10. [Consult the Wiki for additional information](https://git.fifthgrid.com/BlockStorage/repertory/wiki)
|
||||||
|
|
||||||
## Details and Features
|
## Details and Features
|
||||||
|
|
||||||
* Optimized for [Plex Media Server](https://www.plex.tv/)
|
* 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.
|
* 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)
|
* 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
|
* Optionally encrypt file names and file data via `XChaCha20-Poly1305` in S3 mounts
|
||||||
|
|
||||||
## Minimum Requirements
|
## Minimum Requirements
|
||||||
|
|
||||||
* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v0.4.0+ for Sia support
|
* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v2.0.0+ for Sia support
|
||||||
* Only 64-bit operating systems are supported
|
* Linux requires `fusermount3`; otherwise, `repertory` must be manually compiled with `libfuse2` support
|
||||||
* By default, Linux requires `fusermount3`; otherwise, `repertory` must be manually compiled with `libfuse2` support
|
* Windows requires the following dependencies to be installed:
|
||||||
* Windows requires the following dependencies to be installed:
|
* [WinFSP 2023](https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi)
|
||||||
* [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 `arm64/aarch64`
|
||||||
* Linux `amd64`
|
* Linux `amd64`
|
||||||
* Windows 64-bit 10, 11
|
* Windows 64-bit 10, 11
|
||||||
|
|
||||||
|
## GUI
|
||||||
|
|
||||||
|
As of `v2.0.5-rc`, mounts can be managed using the `Repertory Management Portal`.
|
||||||
|
To launch the portal, execute the following command:
|
||||||
|
|
||||||
|
* `repertory -ui`
|
||||||
|
* The default username is `repertory`
|
||||||
|
* The default password is `repertory`
|
||||||
|
|
||||||
|
After first launch, `ui.json` will be created in the appropriate data directory.
|
||||||
|
See [Data Directories](#data-directories).
|
||||||
|
You should modify this file directly or use the portal to change the default
|
||||||
|
username and password.
|
||||||
|
|
||||||
|
### Screenshot
|
||||||
|
|
||||||
|
<a href="https://ibb.co/fVyJqnbF"><img src="https://i.ibb.co/fVyJqnbF/repertory-portal.png" alt="repertory-portal" border="0"></a>
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Sia
|
### Important Options
|
||||||
|
|
||||||
* 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
|
|
||||||
|
|
||||||
* `--help`
|
* `--help`
|
||||||
* Display all mount utility options
|
* Display all mount utility options
|
||||||
|
|
||||||
|
* `-f`
|
||||||
|
* Keep process in foreground on Linux.
|
||||||
|
|
||||||
* `--name, -na [name]`
|
* `--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.
|
* 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.
|
* 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.
|
* 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.
|
* For S3, the `--name` option is required and does not affect the bucket name.
|
||||||
|
|
||||||
* `-dc`
|
* `-dc`
|
||||||
* Display mount configuration
|
* Display mount configuration
|
||||||
* For Sia, `--name` is optional
|
* For Sia, `--name` is optional
|
||||||
* For S3, the `-s3` option is required along with `--name`
|
* 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
|
||||||
|
{
|
||||||
|
"ApiPassword": "<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
|
||||||
|
{
|
||||||
|
"ApiPassword": "<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
|
### Data Directories
|
||||||
|
|
||||||
* Linux
|
#### Linux Directories
|
||||||
* `~/.local/repertory2`
|
|
||||||
* Windows
|
* `~/.local/repertory2/s3`
|
||||||
* `%LOCALAPPDATA%\repertory2`
|
* `~/.local/repertory2/sia`
|
||||||
* Example:
|
|
||||||
* `C:\Users\Tom\AppData\Local\repertory2`
|
#### Windows Directories
|
||||||
* IMPORTANT:
|
|
||||||
* It is highly recommended to exclude this folder from any anti-virus/anti-malware applications as severe performance issues may arise.
|
* `%LOCALAPPDATA%\repertory2\s3`
|
||||||
* Excluding the mounted drive letter is also highly recommended.
|
* `%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
|
## Remote Mounting
|
||||||
|
|
||||||
`Repertory` allows local mounts to be shared with other computers on your network.
|
`repertory` allows local mounts to be shared with other computers on your network
|
||||||
This option is referred to as remote mounting. Instructions TBD.
|
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
|
||||||
|
{
|
||||||
|
"ApiPassword": "<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
|
## Compiling
|
||||||
|
|
||||||
* Successful compilation will result in all required files being placed in the `dist/` directory
|
Successful compilation will result in all files required for execution to be placed
|
||||||
* Linux
|
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
|
* Ensure `docker` is installed
|
||||||
* For x86_64:
|
* RelWithDebInfo: `scripts/make_win32.sh`
|
||||||
* RelWithDebInfo: `scripts/make_unix.sh`
|
* Release: `scripts/make_win32.sh x86_64 Release`
|
||||||
* Release: `scripts/make_unix.sh x86_64 Release`
|
* Debug: `scripts/make_win32.sh x86_64 Debug`
|
||||||
* Debug: `scripts/make_unix.sh x86_64 Debug`
|
|
||||||
* For aarch64:
|
* UNOFFICIAL: Compiling on Windows
|
||||||
* RelWithDebInfo: `scripts/make_unix.sh aarch64`
|
* Ensure latest [MSYS2](https://www.msys2.org/) is installed
|
||||||
* Release: `scripts/make_unix.sh aarch64 Release`
|
* RelWithDebInfo: `scripts\make_win32.cmd`
|
||||||
* Debug: `scripts/make_unix.sh aarch64 Debug`
|
* Release: `scripts\make_win32.cmd x86_64 Release`
|
||||||
* Windows
|
* Debug: `scripts\make_win32.cmd x86_64 Debug`
|
||||||
* 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`
|
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
set(BINUTILS_HASH b53606f443ac8f01d1d5fc9c39497f2af322d99e14cea5c0b4b124d630379365)
|
set(BINUTILS_HASH ce2017e059d63e67ddb9240e9d4ec49c2893605035cd60e92ad53177f4377237)
|
||||||
set(BOOST2_HASH 7bd7ddceec1a1dfdcbdb3e609b60d01739c38390a5f956385a12f3122049f0ca)
|
set(BOOST2_HASH 7bd7ddceec1a1dfdcbdb3e609b60d01739c38390a5f956385a12f3122049f0ca)
|
||||||
set(BOOST_HASH f55c340aa49763b1925ccf02b2e83f35fdcf634c9d5164a2acb87540173c741d)
|
set(BOOST_HASH 3621533e820dcab1e8012afd583c0c73cf0f77694952b81352bf38c1488f9cb4)
|
||||||
set(CPP_HTTPLIB_HASH 405abd8170f2a446fc8612ac635d0db5947c0d2e156e32603403a4496255ff00)
|
set(CPP_HTTPLIB_HASH 18064587e0cc6a0d5d56d619f4cbbcaba47aa5d84d86013abbd45d95c6653866)
|
||||||
set(CURL_HASH 5a231145114589491fc52da118f9c7ef8abee885d1cb1ced99c7290e9a352f07)
|
set(CURL_HASH ccc5ba45d9f5320c70ffb24e5411b66ba55ea1f333bf78be0963ed90a9328699)
|
||||||
set(EXPAT_HASH 372b18f6527d162fa9658f1c74d22a37429b82d822f5a1e1fc7e00f6045a06a2)
|
set(EXPAT_HASH 85372797ff0673a8fc4a6be16466bb5a0ca28c0dcf3c6f7ac1686b4a3ba2aabb)
|
||||||
set(GCC_HASH 7d376d445f93126dc545e2c0086d0f647c3094aae081cdb78f42ce2bc25e7293)
|
set(GCC_HASH 7d376d445f93126dc545e2c0086d0f647c3094aae081cdb78f42ce2bc25e7293)
|
||||||
set(GTEST_HASH 7b42b4d6ed48810c5362c265a17faebe90dc2373c885e5216439d37927f02926)
|
set(GTEST_HASH 78c676fc63881529bf97bf9d45948d905a66833fbfa5318ea2cd7478cb98f399)
|
||||||
set(ICU_HASH a2c443404f00098e9e90acf29dc318e049d2dc78d9ae5f46efb261934a730ce2)
|
set(ICU_HASH a2c443404f00098e9e90acf29dc318e049d2dc78d9ae5f46efb261934a730ce2)
|
||||||
set(JSON_HASH 0d8ef5af7f9794e3263480193c491549b2ba6cc74bb018906202ada498a79406)
|
set(JSON_HASH 4b92eb0c06d10683f7447ce9406cb97cd4b453be18d7279320f7b2f025c10187)
|
||||||
set(LIBSODIUM_HASH 8e5aeca07a723a27bbecc3beef14b0068d37e7fc0e97f51b3f1c82d2a58005c1)
|
set(LIBSODIUM_HASH 8e5aeca07a723a27bbecc3beef14b0068d37e7fc0e97f51b3f1c82d2a58005c1)
|
||||||
set(MINGW_HASH 30e5aad2c48dd318150f79cff47661232c4175876d6b4d6b270961cf2b49a48b)
|
set(MINGW_HASH cc41898aac4b6e8dd5cffd7331b9d9515b912df4420a3a612b5ea2955bbeed2f)
|
||||||
set(OPENSSL_HASH e15dda82fe2fe8139dc2ac21a36d4ca01d5313c75f99f46c4e8a27709b7294bf)
|
set(OPENSSL_HASH 344d0a79f1a9b08029b0744e2cc401a43f9c90acd1044d09a530b4885a8e9fc0)
|
||||||
set(PKG_CONFIG_HASH 6fc69c01688c9458a57eb9a1664c9aba372ccda420a02bf4429fe610e7e7d591)
|
set(PKG_CONFIG_HASH 6fc69c01688c9458a57eb9a1664c9aba372ccda420a02bf4429fe610e7e7d591)
|
||||||
set(PUGIXML_HASH 2f10e276870c64b1db6809050a75e11a897a8d7456c4be5c6b2e35a11168a015)
|
set(PUGIXML_HASH 655ade57fa703fb421c2eb9a0113b5064bddb145d415dd1f88c79353d90d511a)
|
||||||
set(ROCKSDB_HASH 9b810c81731835fda0d4bbdb51d3199d901fa4395733ab63752d297da84c5a47)
|
set(ROCKSDB_HASH 3fdc9ca996971c4c039959866382c4a3a6c8ade4abf888f3b2ff77153e07bf28)
|
||||||
set(SPDLOG_HASH 9962648c9b4f1a7bbc76fd8d9172555bad1871fdb14ff4f842ef87949682caa5)
|
set(SPDLOG_HASH 7a80896357f3e8e920e85e92633b14ba0f229c506e6f978578bdc35ba09e9a5d)
|
||||||
set(SQLITE_HASH 77823cb110929c2bcb0f5d48e4833b5c59a8a6e40cdea3936b99e199dbbe5784)
|
set(SQLITE_HASH 6cebd1d8403fc58c30e93939b246f3e6e58d0765a5cd50546f16c00fd805d2c3)
|
||||||
set(STDUUID_HASH b1176597e789531c38481acbbed2a6894ad419aab0979c10410d59eb0ebf40d3)
|
set(STDUUID_HASH b1176597e789531c38481acbbed2a6894ad419aab0979c10410d59eb0ebf40d3)
|
||||||
set(ZLIB_HASH 17e88863f3600672ab49182f217281b6fc4d3c762bde361935e436a95214d05c)
|
set(ZLIB_HASH 17e88863f3600672ab49182f217281b6fc4d3c762bde361935e436a95214d05c)
|
||||||
|
@ -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
|
--with-libraries=atomic,chrono,date_time,filesystem,iostreams,locale,log,program_options,random,regex,serialization,system,test,thread
|
||||||
BUILD_COMMAND
|
BUILD_COMMAND
|
||||||
./b2
|
./b2
|
||||||
-j1
|
-j$ENV{CMAKE_BUILD_PARALLEL_LEVEL}
|
||||||
${BOOST_BUILD_ARGS}
|
${BOOST_BUILD_ARGS}
|
||||||
INSTALL_COMMAND
|
INSTALL_COMMAND
|
||||||
./b2
|
./b2
|
||||||
-j1
|
-j$ENV{CMAKE_BUILD_PARALLEL_LEVEL}
|
||||||
${BOOST_BUILD_ARGS}
|
${BOOST_BUILD_ARGS}
|
||||||
install
|
install
|
||||||
)
|
)
|
||||||
|
@ -15,10 +15,13 @@ if(PROJECT_ENABLE_CPP_HTTPLIB)
|
|||||||
CMAKE_ARGS ${PROJECT_EXTERNAL_CMAKE_FLAGS}
|
CMAKE_ARGS ${PROJECT_EXTERNAL_CMAKE_FLAGS}
|
||||||
-DBUILD_SHARED_LIBS=${PROJECT_BUILD_SHARED_LIBS}
|
-DBUILD_SHARED_LIBS=${PROJECT_BUILD_SHARED_LIBS}
|
||||||
-DBUILD_STATIC_LIBS=ON
|
-DBUILD_STATIC_LIBS=ON
|
||||||
-DHTTPLIB_REQUIRE_OPENSSL=${PROJECT_ENABLE_OPENSSL}
|
|
||||||
-DHTTPLIB_REQUIRE_ZLIB=ON
|
|
||||||
-DHTTPLIB_REQUIRE_BROTLI=OFF
|
-DHTTPLIB_REQUIRE_BROTLI=OFF
|
||||||
|
-DHTTPLIB_REQUIRE_OPENSSL=ON
|
||||||
|
-DHTTPLIB_REQUIRE_ZLIB=ON
|
||||||
-DHTTPLIB_TEST=OFF
|
-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}
|
-DOPENSSL_USE_STATIC_LIBS=${OPENSSL_USE_STATIC_LIBS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,8 +18,9 @@ if(PROJECT_ENABLE_CURL)
|
|||||||
URL ${PROJECT_3RD_PARTY_DIR}/curl-${CURL_VERSION}.tar.gz
|
URL ${PROJECT_3RD_PARTY_DIR}/curl-${CURL_VERSION}.tar.gz
|
||||||
URL_HASH SHA256=${CURL_HASH}
|
URL_HASH SHA256=${CURL_HASH}
|
||||||
LIST_SEPARATOR |
|
LIST_SEPARATOR |
|
||||||
CMAKE_ARGS
|
BUILD_COMMAND
|
||||||
${PROJECT_EXTERNAL_CMAKE_FLAGS}
|
${CMAKE_COMMAND} --build . -- -j$ENV{CMAKE_BUILD_PARALLEL_LEVEL}
|
||||||
|
CMAKE_ARGS ${PROJECT_EXTERNAL_CMAKE_FLAGS}
|
||||||
-DBUILD_CURL_EXE=OFF
|
-DBUILD_CURL_EXE=OFF
|
||||||
-DBUILD_LIBCURL_DOCS=OFF
|
-DBUILD_LIBCURL_DOCS=OFF
|
||||||
-DBUILD_MISC_DOCS=OFF
|
-DBUILD_MISC_DOCS=OFF
|
||||||
@ -28,6 +29,7 @@ if(PROJECT_ENABLE_CURL)
|
|||||||
-DBUILD_STATIC_LIBS=ON
|
-DBUILD_STATIC_LIBS=ON
|
||||||
-DBUILD_STATIC_LIBS=ON
|
-DBUILD_STATIC_LIBS=ON
|
||||||
-DBUILD_TESTING=OFF
|
-DBUILD_TESTING=OFF
|
||||||
|
-DCURL_BROTLI=OFF
|
||||||
-DCURL_CA_BUNDLE=./cacert.pem
|
-DCURL_CA_BUNDLE=./cacert.pem
|
||||||
-DCURL_CA_FALLBACK=ON
|
-DCURL_CA_FALLBACK=ON
|
||||||
-DCURL_DISABLE_LDAP=ON
|
-DCURL_DISABLE_LDAP=ON
|
||||||
|
@ -9,6 +9,8 @@ if(PROJECT_ENABLE_ROCKSDB)
|
|||||||
URL ${PROJECT_3RD_PARTY_DIR}/rocksdb-${ROCKSDB_VERSION}.tar.gz
|
URL ${PROJECT_3RD_PARTY_DIR}/rocksdb-${ROCKSDB_VERSION}.tar.gz
|
||||||
URL_HASH SHA256=${ROCKSDB_HASH}
|
URL_HASH SHA256=${ROCKSDB_HASH}
|
||||||
LIST_SEPARATOR |
|
LIST_SEPARATOR |
|
||||||
|
BUILD_COMMAND
|
||||||
|
${CMAKE_COMMAND} --build . -- -j$ENV{CMAKE_BUILD_PARALLEL_LEVEL}
|
||||||
CMAKE_ARGS ${PROJECT_EXTERNAL_CMAKE_FLAGS}
|
CMAKE_ARGS ${PROJECT_EXTERNAL_CMAKE_FLAGS}
|
||||||
-DBUILD_SHARED_LIBS=OFF
|
-DBUILD_SHARED_LIBS=OFF
|
||||||
-DBUILD_STATIC_LIBS=ON
|
-DBUILD_STATIC_LIBS=ON
|
||||||
@ -31,4 +33,4 @@ if(PROJECT_ENABLE_ROCKSDB)
|
|||||||
|
|
||||||
list(APPEND PROJECT_DEPENDENCIES rocksdb_project)
|
list(APPEND PROJECT_DEPENDENCIES rocksdb_project)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -2,7 +2,7 @@ if(PROJECT_ENABLE_SQLITE)
|
|||||||
if(PROJECT_BUILD)
|
if(PROJECT_BUILD)
|
||||||
add_definitions(-DPROJECT_ENABLE_SQLITE)
|
add_definitions(-DPROJECT_ENABLE_SQLITE)
|
||||||
if (PROJECT_IS_MINGW AND NOT PROJECT_IS_MINGW_UNIX)
|
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})
|
include_directories(SYSTEM BEFORE ${SQLITE3_INCLUDE_DIRS})
|
||||||
link_libraries(${SQLITE3_LIBRARIES})
|
link_libraries(${SQLITE3_LIBRARIES})
|
||||||
else()
|
else()
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
set(BINUTILS_VERSION 2.43)
|
set(BINUTILS_VERSION 2.44)
|
||||||
set(BOOST_MAJOR_VERSION 1)
|
|
||||||
set(BOOST_MINOR_VERSION 87)
|
|
||||||
set(BOOST_PATCH_VERSION 0)
|
|
||||||
set(BOOST2_MAJOR_VERSION 1)
|
set(BOOST2_MAJOR_VERSION 1)
|
||||||
set(BOOST2_MINOR_VERSION 76)
|
set(BOOST2_MINOR_VERSION 76)
|
||||||
set(BOOST2_PATCH_VERSION 0)
|
set(BOOST2_PATCH_VERSION 0)
|
||||||
set(CPP_HTTPLIB_VERSION 0.18.1)
|
set(BOOST_MAJOR_VERSION 1)
|
||||||
set(CURL_VERSION 8.11.0)
|
set(BOOST_MINOR_VERSION 88)
|
||||||
set(CURL2_VERSION 8_11_0)
|
set(BOOST_PATCH_VERSION 0)
|
||||||
set(EXPAT_VERSION 2.6.4)
|
set(CPP_HTTPLIB_VERSION 0.20.0)
|
||||||
set(EXPAT2_VERSION 2_6_4)
|
set(CURL2_VERSION 8_13_0)
|
||||||
|
set(CURL_VERSION 8.13.0)
|
||||||
|
set(EXPAT2_VERSION 2_7_1)
|
||||||
|
set(EXPAT_VERSION 2.7.1)
|
||||||
set(GCC_VERSION 14.2.0)
|
set(GCC_VERSION 14.2.0)
|
||||||
set(GTEST_VERSION 1.15.2)
|
set(GTEST_VERSION 1.16.0)
|
||||||
set(ICU_VERSION 76-1)
|
set(ICU_VERSION 76-1)
|
||||||
set(JSON_VERSION 3.11.3)
|
set(JSON_VERSION 3.12.0)
|
||||||
set(LIBSODIUM_VERSION 1.0.20)
|
set(LIBSODIUM_VERSION 1.0.20)
|
||||||
set(MESA_VERSION 23.3.3)
|
set(MESA_VERSION 23.3.3)
|
||||||
set(MINGW_VERSION 12.0.0)
|
set(MINGW_VERSION 12.0.0)
|
||||||
set(OPENSSL_VERSION 3.4.0)
|
set(OPENSSL_VERSION 3.5.0)
|
||||||
set(PKG_CONFIG_VERSION 0.29.2)
|
set(PKG_CONFIG_VERSION 0.29.2)
|
||||||
set(PUGIXML_VERSION 1.14)
|
set(PUGIXML_VERSION 1.15)
|
||||||
set(ROCKSDB_VERSION 9.7.4)
|
set(ROCKSDB_VERSION 10.0.1)
|
||||||
set(SPDLOG_VERSION 1.15.0)
|
set(SPDLOG_VERSION 1.15.2)
|
||||||
set(SQLITE_VERSION 3460100)
|
set(SQLITE2_VERSION 3.49.1)
|
||||||
set(SQLITE2_VERSION 3.46.1)
|
set(SQLITE_VERSION 3490100)
|
||||||
set(STDUUID_VERSION 1.2.3)
|
set(STDUUID_VERSION 1.2.3)
|
||||||
set(ZLIB_VERSION 1.3.1)
|
set(ZLIB_VERSION 1.3.1)
|
||||||
|
@ -10,7 +10,7 @@ PROJECT_DESC="Mount utility for Sia and S3"
|
|||||||
|
|
||||||
PROJECT_MAJOR_VERSION=2
|
PROJECT_MAJOR_VERSION=2
|
||||||
PROJECT_MINOR_VERSION=0
|
PROJECT_MINOR_VERSION=0
|
||||||
PROJECT_REVISION_VERSION=3
|
PROJECT_REVISION_VERSION=6
|
||||||
PROJECT_RELEASE_NUM=0
|
PROJECT_RELEASE_NUM=0
|
||||||
PROJECT_RELEASE_ITER=rc
|
PROJECT_RELEASE_ITER=rc
|
||||||
|
|
||||||
@ -19,6 +19,9 @@ PROJECT_APP_LIST=(${PROJECT_NAME})
|
|||||||
PROJECT_PRIVATE_KEY=${DEVELOPER_PRIVATE_KEY}
|
PROJECT_PRIVATE_KEY=${DEVELOPER_PRIVATE_KEY}
|
||||||
PROJECT_PUBLIC_KEY=${DEVELOPER_PUBLIC_KEY}
|
PROJECT_PUBLIC_KEY=${DEVELOPER_PUBLIC_KEY}
|
||||||
|
|
||||||
|
PROJECT_FLUTTER_BASE_HREF="/ui/"
|
||||||
|
|
||||||
|
PROJECT_ENABLE_V2_ERRORS=ON
|
||||||
PROJECT_ENABLE_WIN32_LONG_PATH_NAMES=OFF
|
PROJECT_ENABLE_WIN32_LONG_PATH_NAMES=OFF
|
||||||
|
|
||||||
PROJECT_ENABLE_BACKWARD_CPP=OFF
|
PROJECT_ENABLE_BACKWARD_CPP=OFF
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
FROM arm64v8/alpine:3.21.0
|
#comment
|
||||||
|
FROM arm64v8/alpine:3.21.3
|
||||||
MAINTAINER Scott E. Graves <scott.e.graves@protonmail.com>
|
MAINTAINER Scott E. Graves <scott.e.graves@protonmail.com>
|
||||||
CMD bash
|
CMD bash
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ RUN apk add \
|
|||||||
gflags \
|
gflags \
|
||||||
gflags-dev \
|
gflags-dev \
|
||||||
git \
|
git \
|
||||||
|
git-lfs \
|
||||||
icu-dev \
|
icu-dev \
|
||||||
icu-libs \
|
icu-libs \
|
||||||
icu-static \
|
icu-static \
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
FROM alpine:3.21.0
|
#comment
|
||||||
|
FROM alpine:3.21.3
|
||||||
MAINTAINER Scott E. Graves <scott.e.graves@protonmail.com>
|
MAINTAINER Scott E. Graves <scott.e.graves@protonmail.com>
|
||||||
CMD bash
|
CMD bash
|
||||||
|
|
||||||
@ -30,6 +31,7 @@ RUN apk add \
|
|||||||
gflags \
|
gflags \
|
||||||
gflags-dev \
|
gflags-dev \
|
||||||
git \
|
git \
|
||||||
|
git-lfs \
|
||||||
icu-dev \
|
icu-dev \
|
||||||
icu-libs \
|
icu-libs \
|
||||||
icu-static \
|
icu-static \
|
||||||
|
48
docker/x86_64/flutter
Normal file
48
docker/x86_64/flutter
Normal 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
|
@ -1,5 +1,5 @@
|
|||||||
#comment
|
#comment
|
||||||
FROM alpine:3.21.0
|
FROM alpine:3.21.3
|
||||||
|
|
||||||
RUN apk update
|
RUN apk update
|
||||||
RUN apk upgrade
|
RUN apk upgrade
|
||||||
@ -18,6 +18,7 @@ RUN apk add \
|
|||||||
gcc \
|
gcc \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
git-lfs \
|
||||||
gmp \
|
gmp \
|
||||||
gmp-dev \
|
gmp-dev \
|
||||||
gperf \
|
gperf \
|
||||||
@ -350,9 +351,9 @@ RUN cd /3rd_party/mingw64 && sha256sum -c ./expat-${MY_EXPAT_VERSION}.tar.gz.sha
|
|||||||
|
|
||||||
ARG FONTCONFIG_VERSION
|
ARG FONTCONFIG_VERSION
|
||||||
ENV MY_FONTCONFIG_VERSION=${FONTCONFIG_VERSION}
|
ENV MY_FONTCONFIG_VERSION=${FONTCONFIG_VERSION}
|
||||||
RUN if [ -f "/3rd_party/fontconfig-${MY_FONTCONFIG_VERSION}.tar.gz" ]; then \
|
RUN if [ -f "/3rd_party/fontconfig-${MY_FONTCONFIG_VERSION}.tar.xz" ]; then \
|
||||||
cd /3rd_party && sha256sum -c ./fontconfig-${MY_FONTCONFIG_VERSION}.tar.gz.sha256 && cd - \
|
cd /3rd_party && sha256sum -c ./fontconfig-${MY_FONTCONFIG_VERSION}.tar.xz.sha256 && cd - \
|
||||||
&& tar xvzf /3rd_party/fontconfig-${MY_FONTCONFIG_VERSION}.tar.gz \
|
&& tar xvJf /3rd_party/fontconfig-${MY_FONTCONFIG_VERSION}.tar.xz \
|
||||||
&& cd fontconfig-${MY_FONTCONFIG_VERSION} \
|
&& cd fontconfig-${MY_FONTCONFIG_VERSION} \
|
||||||
&& meson setup \
|
&& meson setup \
|
||||||
--cross-file ${MY_TOOLCHAIN_FILE_MESON} \
|
--cross-file ${MY_TOOLCHAIN_FILE_MESON} \
|
||||||
@ -679,6 +680,7 @@ RUN if [ -f "/3rd_party/curl-${MY_CURL_VERSION}.tar.gz" ]; then \
|
|||||||
-DCMAKE_CXX_STANDARD=${MY_CXX_STANDARD} \
|
-DCMAKE_CXX_STANDARD=${MY_CXX_STANDARD} \
|
||||||
-DCMAKE_INSTALL_PREFIX=${MY_MINGW_DIR} \
|
-DCMAKE_INSTALL_PREFIX=${MY_MINGW_DIR} \
|
||||||
-DCMAKE_TOOLCHAIN_FILE=${MY_TOOLCHAIN_FILE_CMAKE} \
|
-DCMAKE_TOOLCHAIN_FILE=${MY_TOOLCHAIN_FILE_CMAKE} \
|
||||||
|
-DCURL_BROTLI=OFF \
|
||||||
-DCURL_CA_BUNDLE=./cacert.pem \
|
-DCURL_CA_BUNDLE=./cacert.pem \
|
||||||
-DCURL_CA_FALLBACK=ON \
|
-DCURL_CA_FALLBACK=ON \
|
||||||
-DCURL_DISABLE_LDAP=ON \
|
-DCURL_DISABLE_LDAP=ON \
|
||||||
@ -714,6 +716,9 @@ RUN if [ -f "/3rd_party/cpp-httplib-${MY_CPP_HTTPLIB_VERSION}.tar.gz" ]; then \
|
|||||||
-DHTTPLIB_REQUIRE_OPENSSL=ON \
|
-DHTTPLIB_REQUIRE_OPENSSL=ON \
|
||||||
-DHTTPLIB_REQUIRE_ZLIB=ON \
|
-DHTTPLIB_REQUIRE_ZLIB=ON \
|
||||||
-DHTTPLIB_TEST=OFF \
|
-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 -j${MY_NUM_JOBS} \
|
||||||
&& make install \
|
&& make install \
|
||||||
&& cd ${MY_WORKDIR} \
|
&& cd ${MY_WORKDIR} \
|
||||||
|
@ -31,26 +31,27 @@ private:
|
|||||||
static stop_type stop_requested;
|
static stop_type stop_requested;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static auto
|
[[nodiscard]] static auto default_agent_name(const provider_type &prov)
|
||||||
default_agent_name(const provider_type &prov) -> std::string;
|
-> std::string;
|
||||||
|
|
||||||
[[nodiscard]] static auto
|
[[nodiscard]] static auto default_api_port(const provider_type &prov)
|
||||||
default_api_port(const provider_type &prov) -> std::uint16_t;
|
-> std::uint16_t;
|
||||||
|
|
||||||
[[nodiscard]] static auto
|
[[nodiscard]] static auto default_data_directory(const provider_type &prov)
|
||||||
default_data_directory(const provider_type &prov) -> std::string;
|
-> std::string;
|
||||||
|
|
||||||
[[nodiscard]] static auto
|
[[nodiscard]] static auto default_remote_api_port(const provider_type &prov)
|
||||||
default_remote_api_port(const provider_type &prov) -> std::uint16_t;
|
-> std::uint16_t;
|
||||||
|
|
||||||
[[nodiscard]] static auto
|
[[nodiscard]] static auto default_rpc_port() -> std::uint16_t;
|
||||||
default_rpc_port(const provider_type &prov) -> std::uint16_t;
|
|
||||||
|
|
||||||
[[nodiscard]] static auto
|
[[nodiscard]] static auto get_provider_display_name(const provider_type &prov)
|
||||||
get_provider_display_name(const provider_type &prov) -> std::string;
|
-> std::string;
|
||||||
|
|
||||||
[[nodiscard]] static auto
|
[[nodiscard]] static auto get_provider_name(const provider_type &prov)
|
||||||
get_provider_name(const provider_type &prov) -> std::string;
|
-> std::string;
|
||||||
|
|
||||||
|
[[nodiscard]] static auto get_root_data_directory() -> std::string;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static auto get_stop_requested() -> bool;
|
[[nodiscard]] static auto get_stop_requested() -> bool;
|
||||||
@ -71,7 +72,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
provider_type prov_;
|
provider_type prov_;
|
||||||
atomic<std::string> api_auth_;
|
atomic<std::string> api_password_;
|
||||||
std::atomic<std::uint16_t> api_port_;
|
std::atomic<std::uint16_t> api_port_;
|
||||||
atomic<std::string> api_user_;
|
atomic<std::string> api_user_;
|
||||||
std::atomic<bool> config_changed_;
|
std::atomic<bool> config_changed_;
|
||||||
@ -91,7 +92,6 @@ private:
|
|||||||
std::atomic<std::uint8_t> max_upload_count_;
|
std::atomic<std::uint8_t> max_upload_count_;
|
||||||
std::atomic<std::uint16_t> med_freq_interval_secs_;
|
std::atomic<std::uint16_t> med_freq_interval_secs_;
|
||||||
std::atomic<std::uint16_t> online_check_retry_secs_;
|
std::atomic<std::uint16_t> online_check_retry_secs_;
|
||||||
std::atomic<std::uint16_t> orphaned_file_retention_days_;
|
|
||||||
std::atomic<download_type> preferred_download_type_;
|
std::atomic<download_type> preferred_download_type_;
|
||||||
std::atomic<std::uint16_t> retry_read_count_;
|
std::atomic<std::uint16_t> retry_read_count_;
|
||||||
std::atomic<std::uint16_t> ring_buffer_file_size_;
|
std::atomic<std::uint16_t> ring_buffer_file_size_;
|
||||||
@ -122,7 +122,7 @@ private:
|
|||||||
auto set_value(dest &dst, const source &src) -> bool;
|
auto set_value(dest &dst, const source &src) -> bool;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] auto get_api_auth() const -> std::string;
|
[[nodiscard]] auto get_api_password() const -> std::string;
|
||||||
|
|
||||||
[[nodiscard]] auto get_api_port() const -> std::uint16_t;
|
[[nodiscard]] auto get_api_port() const -> std::uint16_t;
|
||||||
|
|
||||||
@ -172,8 +172,6 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] auto get_online_check_retry_secs() const -> std::uint16_t;
|
[[nodiscard]] auto get_online_check_retry_secs() const -> std::uint16_t;
|
||||||
|
|
||||||
[[nodiscard]] auto get_orphaned_file_retention_days() const -> std::uint16_t;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_preferred_download_type() const -> download_type;
|
[[nodiscard]] auto get_preferred_download_type() const -> download_type;
|
||||||
|
|
||||||
[[nodiscard]] auto get_provider_type() const -> provider_type;
|
[[nodiscard]] auto get_provider_type() const -> provider_type;
|
||||||
@ -192,14 +190,17 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] auto get_task_wait_ms() const -> std::uint16_t;
|
[[nodiscard]] auto get_task_wait_ms() const -> std::uint16_t;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_value_by_name(const std::string &name) const
|
||||||
get_value_by_name(const std::string &name) const -> std::string;
|
-> std::string;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_raw_value_by_name(const std::string &name) const
|
||||||
|
-> std::string;
|
||||||
|
|
||||||
[[nodiscard]] auto get_version() const -> std::uint64_t;
|
[[nodiscard]] auto get_version() const -> std::uint64_t;
|
||||||
|
|
||||||
void save();
|
void save();
|
||||||
|
|
||||||
void set_api_auth(const std::string &value);
|
void set_api_password(const std::string &value);
|
||||||
|
|
||||||
void set_api_port(std::uint16_t value);
|
void set_api_port(std::uint16_t value);
|
||||||
|
|
||||||
@ -239,8 +240,6 @@ public:
|
|||||||
|
|
||||||
void set_online_check_retry_secs(std::uint16_t value);
|
void set_online_check_retry_secs(std::uint16_t value);
|
||||||
|
|
||||||
void set_orphaned_file_retention_days(std::uint16_t value);
|
|
||||||
|
|
||||||
void set_preferred_download_type(const download_type &value);
|
void set_preferred_download_type(const download_type &value);
|
||||||
|
|
||||||
void set_remote_config(remote::remote_config value);
|
void set_remote_config(remote::remote_config value);
|
||||||
|
@ -225,8 +225,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (curl_code != CURLE_OK) {
|
if (curl_code != CURLE_OK) {
|
||||||
event_system::instance().raise<curl_error>(curl_code, function_name,
|
event_system::instance().raise<curl_error>(curl_code, function_name, url);
|
||||||
url);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,12 +54,13 @@ REPERTORY_IGNORE_WARNINGS_DISABLE()
|
|||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
inline constexpr const std::string_view REPERTORY = "repertory";
|
inline constexpr const std::string_view REPERTORY{"repertory"};
|
||||||
inline constexpr const std::wstring_view REPERTORY_W = L"repertory";
|
inline constexpr const std::string_view REPERTORY_DATA_NAME{"repertory2"};
|
||||||
|
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{2ULL};
|
||||||
inline constexpr const std::string_view REPERTORY_DATA_NAME = "repertory2";
|
inline constexpr const std::string_view REPERTORY_MIN_REMOTE_VERSION{"2.0.0"};
|
||||||
inline constexpr const std::string_view REPERTORY_MIN_REMOTE_VERSION = "2.0.0";
|
inline constexpr const std::string_view RENTERD_MIN_VERSION{"2.0.0"};
|
||||||
|
|
||||||
#define REPERTORY_INVALID_HANDLE INVALID_HANDLE_VALUE
|
#define REPERTORY_INVALID_HANDLE INVALID_HANDLE_VALUE
|
||||||
|
|
||||||
@ -221,44 +222,27 @@ using WCHAR = wchar_t;
|
|||||||
|
|
||||||
#define MAX_PATH 260
|
#define MAX_PATH 260
|
||||||
|
|
||||||
#define STATUS_SUCCESS \
|
#define STATUS_ACCESS_DENIED std::uint32_t{0xC0000022L}
|
||||||
std::uint32_t { 0U }
|
#define STATUS_DEVICE_BUSY std::uint32_t{0x80000011L}
|
||||||
#define STATUS_ACCESS_DENIED \
|
#define STATUS_DEVICE_INSUFFICIENT_RESOURCES std::uint32_t{0xC0000468L}
|
||||||
std::uint32_t { 0xC0000022L }
|
#define STATUS_DIRECTORY_NOT_EMPTY std::uint32_t{0xC0000101L}
|
||||||
#define STATUS_DEVICE_BUSY \
|
#define STATUS_END_OF_FILE std::uint32_t{0xC0000011L}
|
||||||
std::uint32_t { 0x80000011L }
|
#define STATUS_FILE_IS_A_DIRECTORY std::uint32_t{0xC00000BAL}
|
||||||
#define STATUS_DEVICE_INSUFFICIENT_RESOURCES \
|
#define STATUS_FILE_TOO_LARGE std::uint32_t{0xC0000904L}
|
||||||
std::uint32_t { 0xC0000468L }
|
#define STATUS_INSUFFICIENT_RESOURCES std::uint32_t{0xC000009AL}
|
||||||
#define STATUS_DIRECTORY_NOT_EMPTY \
|
#define STATUS_INTERNAL_ERROR std::uint32_t{0xC00000E5L}
|
||||||
std::uint32_t { 0xC0000101L }
|
#define STATUS_INVALID_ADDRESS std::uint32_t{0xC0000141L}
|
||||||
#define STATUS_FILE_IS_A_DIRECTORY \
|
#define STATUS_INVALID_HANDLE std::uint32_t{0xC0000006L}
|
||||||
std::uint32_t { 0xC00000BAL }
|
#define STATUS_INVALID_IMAGE_FORMAT std::uint32_t{0xC000007BL}
|
||||||
#define STATUS_FILE_TOO_LARGE \
|
#define STATUS_INVALID_PARAMETER std::uint32_t{0xC000000DL}
|
||||||
std::uint32_t { 0xC0000904L }
|
#define STATUS_NOT_IMPLEMENTED std::uint32_t{0xC0000002L}
|
||||||
#define STATUS_INSUFFICIENT_RESOURCES \
|
#define STATUS_NO_MEMORY std::uint32_t{0xC0000017L}
|
||||||
std::uint32_t { 0xC000009AL }
|
#define STATUS_OBJECT_NAME_COLLISION std::uint32_t{0xC0000035L}
|
||||||
#define STATUS_INTERNAL_ERROR \
|
#define STATUS_OBJECT_NAME_EXISTS std::uint32_t{0x40000000L}
|
||||||
std::uint32_t { 0xC00000E5L }
|
#define STATUS_OBJECT_NAME_NOT_FOUND std::uint32_t{0xC0000034L}
|
||||||
#define STATUS_INVALID_ADDRESS \
|
#define STATUS_OBJECT_PATH_INVALID std::uint32_t{0xC0000039L}
|
||||||
std::uint32_t { 0xC0000141L }
|
#define STATUS_SUCCESS std::uint32_t{0U}
|
||||||
#define STATUS_INVALID_HANDLE \
|
#define STATUS_UNEXPECTED_IO_ERROR std::uint32_t{0xC00000E9L}
|
||||||
std::uint32_t { 0xC0000006L }
|
|
||||||
#define STATUS_INVALID_IMAGE_FORMAT \
|
|
||||||
std::uint32_t { 0xC000007BL }
|
|
||||||
#define STATUS_INVALID_PARAMETER \
|
|
||||||
std::uint32_t { 0xC000000DL }
|
|
||||||
#define STATUS_NO_MEMORY \
|
|
||||||
std::uint32_t { 0xC0000017L }
|
|
||||||
#define STATUS_NOT_IMPLEMENTED \
|
|
||||||
std::uint32_t { 0xC0000002L }
|
|
||||||
#define STATUS_OBJECT_NAME_EXISTS \
|
|
||||||
std::uint32_t { 0x40000000L }
|
|
||||||
#define STATUS_OBJECT_NAME_NOT_FOUND \
|
|
||||||
std::uint32_t { 0xC0000034L }
|
|
||||||
#define STATUS_OBJECT_PATH_INVALID \
|
|
||||||
std::uint32_t { 0xC0000039L }
|
|
||||||
#define STATUS_UNEXPECTED_IO_ERROR \
|
|
||||||
std::uint32_t { 0xC00000E9L }
|
|
||||||
|
|
||||||
#define CONVERT_STATUS_NOT_IMPLEMENTED(e) \
|
#define CONVERT_STATUS_NOT_IMPLEMENTED(e) \
|
||||||
((std::uint32_t(e) == STATUS_NOT_IMPLEMENTED) ? -ENOTSUP : e)
|
((std::uint32_t(e) == STATUS_NOT_IMPLEMENTED) ? -ENOTSUP : e)
|
||||||
|
@ -73,92 +73,95 @@ private:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
[[nodiscard]] auto chflags_impl(std::string api_path,
|
[[nodiscard]] auto chflags_impl(std::string api_path, uint32_t flags)
|
||||||
uint32_t flags) -> api_error override;
|
-> api_error override;
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto chmod_impl(std::string api_path, mode_t mode,
|
||||||
chmod_impl(std::string api_path, mode_t mode,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] auto chmod_impl(std::string api_path,
|
[[nodiscard]] auto chmod_impl(std::string api_path, mode_t mode)
|
||||||
mode_t mode) -> api_error override;
|
-> api_error override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto chown_impl(std::string api_path, uid_t uid, gid_t gid,
|
||||||
chown_impl(std::string api_path, uid_t uid, gid_t gid,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] auto chown_impl(std::string api_path, uid_t uid,
|
[[nodiscard]] auto chown_impl(std::string api_path, uid_t uid, gid_t gid)
|
||||||
gid_t gid) -> api_error override;
|
-> api_error override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto create_impl(std::string api_path, mode_t mode,
|
||||||
create_impl(std::string api_path, mode_t mode,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
void destroy_impl(void *ptr) override;
|
void destroy_impl(void *ptr) override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto fallocate_impl(std::string api_path, int mode,
|
||||||
fallocate_impl(std::string api_path, int mode, off_t offset, off_t length,
|
off_t offset, off_t length,
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
struct fuse_file_info *file_info)
|
||||||
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto fgetattr_impl(std::string api_path, struct stat *unix_st,
|
||||||
fgetattr_impl(std::string api_path, struct stat *unix_st,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto fsetattr_x_impl(std::string api_path,
|
||||||
fsetattr_x_impl(std::string api_path, struct setattr_x *attr,
|
struct setattr_x *attr,
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
struct fuse_file_info *file_info)
|
||||||
|
-> api_error override;
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto fsync_impl(std::string api_path, int datasync,
|
||||||
fsync_impl(std::string api_path, int datasync,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
#if FUSE_USE_VERSION < 30
|
#if FUSE_USE_VERSION < 30
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto ftruncate_impl(std::string api_path, off_t size,
|
||||||
ftruncate_impl(std::string api_path, off_t size,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto getattr_impl(std::string api_path, struct stat *unix_st,
|
||||||
getattr_impl(std::string api_path, struct stat *unix_st,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] auto getattr_impl(std::string api_path,
|
[[nodiscard]] auto getattr_impl(std::string api_path, struct stat *unix_st)
|
||||||
struct stat *unix_st) -> api_error override;
|
-> api_error override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto getxtimes_impl(std::string api_path,
|
||||||
getxtimes_impl(std::string api_path, struct timespec *bkuptime,
|
struct timespec *bkuptime,
|
||||||
struct timespec *crtime) -> api_error override;
|
struct timespec *crtime)
|
||||||
|
-> api_error override;
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
auto init_impl(struct fuse_conn_info *conn,
|
auto init_impl(struct fuse_conn_info *conn, struct fuse_config *cfg)
|
||||||
struct fuse_config *cfg) -> void * override;
|
-> void * override;
|
||||||
#else
|
#else
|
||||||
auto init_impl(struct fuse_conn_info *conn) -> void * override;
|
auto init_impl(struct fuse_conn_info *conn) -> void * override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[[nodiscard]] auto mkdir_impl(std::string api_path,
|
[[nodiscard]] auto mkdir_impl(std::string api_path, mode_t mode)
|
||||||
mode_t mode) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
void notify_fuse_main_exit(int &ret) override;
|
void notify_fuse_main_exit(int &ret) override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto open_impl(std::string api_path,
|
||||||
open_impl(std::string api_path,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto opendir_impl(std::string api_path,
|
||||||
opendir_impl(std::string api_path,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto read_impl(std::string api_path, char *buffer,
|
[[nodiscard]] auto read_impl(std::string api_path, char *buffer,
|
||||||
size_t read_size, off_t read_offset,
|
size_t read_size, off_t read_offset,
|
||||||
@ -166,29 +169,30 @@ protected:
|
|||||||
std::size_t &bytes_read) -> api_error override;
|
std::size_t &bytes_read) -> api_error override;
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto readdir_impl(std::string api_path, void *buf,
|
||||||
readdir_impl(std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir,
|
fuse_fill_dir_t fuse_fill_dir, off_t offset,
|
||||||
off_t offset, struct fuse_file_info *file_info,
|
struct fuse_file_info *file_info,
|
||||||
fuse_readdir_flags flags) -> api_error override;
|
fuse_readdir_flags flags)
|
||||||
|
-> api_error override;
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto readdir_impl(std::string api_path, void *buf,
|
||||||
readdir_impl(std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir,
|
fuse_fill_dir_t fuse_fill_dir, off_t offset,
|
||||||
off_t offset,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto release_impl(std::string api_path,
|
||||||
release_impl(std::string api_path,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto releasedir_impl(std::string api_path,
|
||||||
releasedir_impl(std::string api_path,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
[[nodiscard]] auto rename_impl(std::string from_api_path,
|
[[nodiscard]] auto rename_impl(std::string from_api_path,
|
||||||
std::string to_api_path,
|
std::string to_api_path, unsigned int flags)
|
||||||
unsigned int flags) -> api_error override;
|
-> api_error override;
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] auto rename_impl(std::string from_api_path,
|
[[nodiscard]] auto rename_impl(std::string from_api_path,
|
||||||
std::string to_api_path) -> api_error override;
|
std::string to_api_path) -> api_error override;
|
||||||
@ -199,8 +203,8 @@ protected:
|
|||||||
#if defined(HAS_SETXATTR)
|
#if defined(HAS_SETXATTR)
|
||||||
[[nodiscard]] auto getxattr_common(std::string api_path, const char *name,
|
[[nodiscard]] auto getxattr_common(std::string api_path, const char *name,
|
||||||
char *value, size_t size,
|
char *value, size_t size,
|
||||||
int &attribute_size,
|
int &attribute_size, uint32_t *position)
|
||||||
uint32_t *position) -> api_error;
|
-> api_error;
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
[[nodiscard]] auto getxattr_impl(std::string api_path, const char *name,
|
[[nodiscard]] auto getxattr_impl(std::string api_path, const char *name,
|
||||||
@ -216,8 +220,8 @@ protected:
|
|||||||
size_t size, int &required_size,
|
size_t size, int &required_size,
|
||||||
bool &return_size) -> api_error override;
|
bool &return_size) -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto removexattr_impl(std::string api_path,
|
[[nodiscard]] auto removexattr_impl(std::string api_path, const char *name)
|
||||||
const char *name) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
[[nodiscard]] auto setxattr_impl(std::string api_path, const char *name,
|
[[nodiscard]] auto setxattr_impl(std::string api_path, const char *name,
|
||||||
@ -225,62 +229,64 @@ protected:
|
|||||||
uint32_t position) -> api_error override;
|
uint32_t position) -> api_error override;
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
[[nodiscard]] auto setxattr_impl(std::string api_path, const char *name,
|
[[nodiscard]] auto setxattr_impl(std::string api_path, const char *name,
|
||||||
const char *value, size_t size,
|
const char *value, size_t size, int flags)
|
||||||
int flags) -> api_error override;
|
-> api_error override;
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
#endif // HAS_SETXATTR
|
#endif // HAS_SETXATTR
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto setattr_x_impl(std::string api_path,
|
||||||
setattr_x_impl(std::string api_path,
|
struct setattr_x *attr)
|
||||||
struct setattr_x *attr) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto setbkuptime_impl(std::string api_path,
|
||||||
setbkuptime_impl(std::string api_path,
|
const struct timespec *bkuptime)
|
||||||
const struct timespec *bkuptime) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto setchgtime_impl(std::string api_path,
|
||||||
setchgtime_impl(std::string api_path,
|
const struct timespec *chgtime)
|
||||||
const struct timespec *chgtime) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto setcrtime_impl(std::string api_path,
|
||||||
setcrtime_impl(std::string api_path,
|
const struct timespec *crtime)
|
||||||
const struct timespec *crtime) -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto setvolname_impl(const char *volname) -> api_error override;
|
[[nodiscard]] auto setvolname_impl(const char *volname) -> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto statfs_x_impl(std::string api_path,
|
[[nodiscard]] auto statfs_x_impl(std::string api_path, struct statfs *stbuf)
|
||||||
struct statfs *stbuf) -> api_error override;
|
-> api_error override;
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
[[nodiscard]] auto statfs_impl(std::string api_path,
|
[[nodiscard]] auto statfs_impl(std::string api_path, struct statvfs *stbuf)
|
||||||
struct statvfs *stbuf) -> api_error override;
|
-> api_error override;
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto truncate_impl(std::string api_path, off_t size,
|
||||||
truncate_impl(std::string api_path, off_t size,
|
struct fuse_file_info *file_info)
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
-> api_error override;
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] auto truncate_impl(std::string api_path,
|
[[nodiscard]] auto truncate_impl(std::string api_path, off_t size)
|
||||||
off_t size) -> api_error override;
|
-> api_error override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[[nodiscard]] auto unlink_impl(std::string api_path) -> api_error override;
|
[[nodiscard]] auto unlink_impl(std::string api_path) -> api_error override;
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto utimens_impl(std::string api_path,
|
||||||
utimens_impl(std::string api_path, const struct timespec tv[2],
|
const struct timespec tv[2],
|
||||||
struct fuse_file_info *file_info) -> api_error override;
|
struct fuse_file_info *file_info)
|
||||||
|
-> api_error override;
|
||||||
#else
|
#else
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto utimens_impl(std::string api_path,
|
||||||
utimens_impl(std::string api_path,
|
const struct timespec tv[2])
|
||||||
const struct timespec tv[2]) -> api_error override;
|
-> api_error override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto write_impl(std::string api_path, const char *buffer,
|
||||||
write_impl(std::string api_path, const char *buffer, size_t write_size,
|
size_t write_size, off_t write_offset,
|
||||||
off_t write_offset, struct fuse_file_info *file_info,
|
struct fuse_file_info *file_info,
|
||||||
std::size_t &bytes_written) -> api_error override;
|
std::size_t &bytes_written)
|
||||||
|
-> api_error override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] auto get_directory_item_count(const std::string &api_path) const
|
[[nodiscard]] auto get_directory_item_count(const std::string &api_path) const
|
||||||
@ -289,16 +295,17 @@ public:
|
|||||||
[[nodiscard]] auto get_directory_items(const std::string &api_path) const
|
[[nodiscard]] auto get_directory_items(const std::string &api_path) const
|
||||||
-> directory_item_list override;
|
-> directory_item_list override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_file_size(const std::string &api_path) const
|
||||||
get_file_size(const std::string &api_path) const -> std::uint64_t override;
|
-> std::uint64_t override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_item_meta(const std::string &api_path,
|
||||||
get_item_meta(const std::string &api_path,
|
api_meta_map &meta) const
|
||||||
api_meta_map &meta) const -> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_item_meta(const std::string &api_path,
|
||||||
get_item_meta(const std::string &api_path, const std::string &name,
|
const std::string &name,
|
||||||
std::string &value) const -> api_error override;
|
std::string &value) const
|
||||||
|
-> api_error override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_total_drive_space() const -> std::uint64_t override;
|
[[nodiscard]] auto get_total_drive_space() const -> std::uint64_t override;
|
||||||
|
|
||||||
@ -309,19 +316,22 @@ public:
|
|||||||
void get_volume_info(UINT64 &total_size, UINT64 &free_size,
|
void get_volume_info(UINT64 &total_size, UINT64 &free_size,
|
||||||
std::string &volume_label) const override;
|
std::string &volume_label) const override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto is_processing(const std::string &api_path) const
|
||||||
is_processing(const std::string &api_path) const -> bool override;
|
-> bool override;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto rename_directory(const std::string &from_api_path,
|
||||||
rename_directory(const std::string &from_api_path,
|
const std::string &to_api_path)
|
||||||
const std::string &to_api_path) -> int override;
|
-> int override;
|
||||||
|
|
||||||
[[nodiscard]] auto rename_file(const std::string &from_api_path,
|
[[nodiscard]] auto rename_file(const std::string &from_api_path,
|
||||||
const std::string &to_api_path,
|
const std::string &to_api_path, bool overwrite)
|
||||||
bool overwrite) -> int override;
|
-> int override;
|
||||||
|
|
||||||
void set_item_meta(const std::string &api_path, const std::string &key,
|
void set_item_meta(const std::string &api_path, const std::string &key,
|
||||||
const std::string &value) override;
|
const std::string &value) override;
|
||||||
|
|
||||||
|
void set_item_meta(const std::string &api_path,
|
||||||
|
const api_meta_map &meta) override;
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
@ -30,29 +30,32 @@ class i_fuse_drive {
|
|||||||
INTERFACE_SETUP(i_fuse_drive);
|
INTERFACE_SETUP(i_fuse_drive);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] virtual auto
|
[[nodiscard]] virtual auto check_owner(const std::string &api_path) const
|
||||||
check_owner(const std::string &api_path) const -> api_error = 0;
|
-> api_error = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual auto check_parent_access(const std::string &api_path,
|
||||||
|
int mask) const
|
||||||
|
-> api_error = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
[[nodiscard]] virtual auto
|
||||||
check_parent_access(const std::string &api_path,
|
get_directory_item_count(const std::string &api_path) const
|
||||||
int mask) const -> api_error = 0;
|
-> std::uint64_t = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_directory_item_count(
|
|
||||||
const std::string &api_path) const -> std::uint64_t = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_directory_items(
|
|
||||||
const std::string &api_path) const -> directory_item_list = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
[[nodiscard]] virtual auto
|
||||||
get_file_size(const std::string &api_path) const -> std::uint64_t = 0;
|
get_directory_items(const std::string &api_path) const
|
||||||
|
-> directory_item_list = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
[[nodiscard]] virtual auto get_file_size(const std::string &api_path) const
|
||||||
get_item_meta(const std::string &api_path,
|
-> std::uint64_t = 0;
|
||||||
api_meta_map &meta) const -> api_error = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
[[nodiscard]] virtual auto get_item_meta(const std::string &api_path,
|
||||||
get_item_meta(const std::string &api_path, const std::string &name,
|
api_meta_map &meta) const
|
||||||
std::string &value) const -> api_error = 0;
|
-> api_error = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual auto get_item_meta(const std::string &api_path,
|
||||||
|
const std::string &name,
|
||||||
|
std::string &value) const
|
||||||
|
-> api_error = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_total_drive_space() const -> std::uint64_t = 0;
|
[[nodiscard]] virtual auto get_total_drive_space() const -> std::uint64_t = 0;
|
||||||
|
|
||||||
@ -63,12 +66,12 @@ public:
|
|||||||
virtual void get_volume_info(UINT64 &total_size, UINT64 &free_size,
|
virtual void get_volume_info(UINT64 &total_size, UINT64 &free_size,
|
||||||
std::string &volume_label) const = 0;
|
std::string &volume_label) const = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
[[nodiscard]] virtual auto is_processing(const std::string &api_path) const
|
||||||
is_processing(const std::string &api_path) const -> bool = 0;
|
-> bool = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto
|
[[nodiscard]] virtual auto rename_directory(const std::string &from_api_path,
|
||||||
rename_directory(const std::string &from_api_path,
|
const std::string &to_api_path)
|
||||||
const std::string &to_api_path) -> int = 0;
|
-> int = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto rename_file(const std::string &from_api_path,
|
[[nodiscard]] virtual auto rename_file(const std::string &from_api_path,
|
||||||
const std::string &to_api_path,
|
const std::string &to_api_path,
|
||||||
@ -77,6 +80,9 @@ public:
|
|||||||
virtual void set_item_meta(const std::string &api_path,
|
virtual void set_item_meta(const std::string &api_path,
|
||||||
const std::string &key,
|
const std::string &key,
|
||||||
const std::string &value) = 0;
|
const std::string &value) = 0;
|
||||||
|
|
||||||
|
virtual void set_item_meta(const std::string &api_path,
|
||||||
|
const api_meta_map &meta) = 0;
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
|
@ -59,7 +59,8 @@ private:
|
|||||||
|
|
||||||
static void populate_stat(const struct stat64 &unix_st, remote::stat &r_stat);
|
static void populate_stat(const struct stat64 &unix_st, remote::stat &r_stat);
|
||||||
|
|
||||||
[[nodiscard]] auto update_to_windows_format(json &item) -> json &;
|
[[nodiscard]] auto update_to_windows_format(const std::string &root_api_path,
|
||||||
|
json &item) -> json &;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// FUSE Layer
|
// FUSE Layer
|
||||||
|
@ -143,14 +143,17 @@ public:
|
|||||||
allocation_size, &file_desc, &file_info,
|
allocation_size, &file_desc, &file_info,
|
||||||
normalized_name, exists);
|
normalized_name, exists);
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
|
if (exists == 0U) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
this->set_client_id(file_desc, client_id);
|
this->set_client_id(file_desc, client_id);
|
||||||
#else // !defined(_WIN32)
|
#else // !defined(_WIN32)
|
||||||
this->set_client_id(
|
this->set_client_id(
|
||||||
static_cast<native_handle>(
|
static_cast<native_handle>(
|
||||||
reinterpret_cast<std::uintptr_t>(file_desc)),
|
reinterpret_cast<std::uintptr_t>(file_desc)),
|
||||||
client_id);
|
client_id);
|
||||||
#endif // defined(_WIN32)
|
#endif // defined(_WIN32)
|
||||||
|
}
|
||||||
|
|
||||||
response.encode(file_desc);
|
response.encode(file_desc);
|
||||||
response.encode(file_info);
|
response.encode(file_info);
|
||||||
response.encode(normalized_name);
|
response.encode(normalized_name);
|
||||||
@ -343,15 +346,16 @@ public:
|
|||||||
DECODE_OR_RETURN(request, length);
|
DECODE_OR_RETURN(request, length);
|
||||||
|
|
||||||
data_buffer buffer(length);
|
data_buffer buffer(length);
|
||||||
UINT32 bytes_transferred{0};
|
UINT32 bytes_transferred{0U};
|
||||||
ret = this->winfsp_read(file_desc, buffer.data(), offset, length,
|
ret = this->winfsp_read(file_desc, buffer.data(), offset, length,
|
||||||
&bytes_transferred);
|
&bytes_transferred);
|
||||||
if (ret == STATUS_SUCCESS) {
|
response.encode(bytes_transferred);
|
||||||
response.encode(bytes_transferred);
|
buffer.resize(bytes_transferred);
|
||||||
if (bytes_transferred != 0U) {
|
|
||||||
response.encode(buffer.data(), bytes_transferred);
|
if ((ret == STATUS_SUCCESS) && (bytes_transferred != 0U)) {
|
||||||
}
|
response.encode(buffer.data(), bytes_transferred);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}});
|
}});
|
||||||
handler_lookup_.insert(
|
handler_lookup_.insert(
|
||||||
@ -589,8 +593,9 @@ public:
|
|||||||
DECODE_OR_RETURN(request, flags);
|
DECODE_OR_RETURN(request, flags);
|
||||||
|
|
||||||
remote::file_handle handle{};
|
remote::file_handle handle{};
|
||||||
if ((ret = this->fuse_create(path.data(), mode, flags, handle)) >=
|
|
||||||
0) {
|
ret = this->fuse_create(path.data(), mode, flags, handle);
|
||||||
|
if (ret >= 0) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
this->set_compat_client_id(handle, client_id);
|
this->set_compat_client_id(handle, client_id);
|
||||||
#else // !defined(_WIN32)
|
#else // !defined(_WIN32)
|
||||||
@ -846,7 +851,8 @@ public:
|
|||||||
DECODE_OR_RETURN(request, flags);
|
DECODE_OR_RETURN(request, flags);
|
||||||
|
|
||||||
remote::file_handle handle;
|
remote::file_handle handle;
|
||||||
if ((ret = this->fuse_open(path.c_str(), flags, handle)) >= 0) {
|
ret = this->fuse_open(path.c_str(), flags, handle);
|
||||||
|
if (ret >= 0) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
this->set_compat_client_id(handle, client_id);
|
this->set_compat_client_id(handle, client_id);
|
||||||
#else // !defined(_WIN32)
|
#else // !defined(_WIN32)
|
||||||
@ -867,7 +873,8 @@ public:
|
|||||||
DECODE_OR_RETURN(request, path);
|
DECODE_OR_RETURN(request, path);
|
||||||
|
|
||||||
remote::file_handle handle{0};
|
remote::file_handle handle{0};
|
||||||
if ((ret = this->fuse_opendir(path.c_str(), handle)) >= 0) {
|
ret = this->fuse_opendir(path.c_str(), handle);
|
||||||
|
if (ret >= 0) {
|
||||||
this->add_directory(client_id, handle);
|
this->add_directory(client_id, handle);
|
||||||
response.encode(handle);
|
response.encode(handle);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "comm/packet/packet_client.hpp"
|
#include "comm/packet/packet_client.hpp"
|
||||||
#include "drives/remote/remote_open_file_table.hpp"
|
#include "drives/remote/remote_open_file_table.hpp"
|
||||||
#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
|
#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
|
||||||
|
#include "types/remote.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class app_config;
|
class app_config;
|
||||||
|
68
repertory/librepertory/include/events/types/info_log.hpp
Normal file
68
repertory/librepertory/include/events/types/info_log.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
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_INFO_LOG_HPP_
|
||||||
|
#define REPERTORY_INCLUDE_EVENTS_TYPES_INFO_LOG_HPP_
|
||||||
|
|
||||||
|
#include "events/i_event.hpp"
|
||||||
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
struct info_log final : public i_event {
|
||||||
|
info_log() = default;
|
||||||
|
info_log(std::string_view function_name_, std::string msg_)
|
||||||
|
: function_name(std::string(function_name_)), msg(std::move(msg_)) {}
|
||||||
|
|
||||||
|
static constexpr const event_level level{event_level::info};
|
||||||
|
static constexpr const std::string_view name{"info_log"};
|
||||||
|
|
||||||
|
std::string function_name;
|
||||||
|
std::string msg;
|
||||||
|
|
||||||
|
[[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|{}|msg|{}", name, function_name, msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace repertory
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
template <> struct adl_serializer<repertory::info_log> {
|
||||||
|
static void to_json(json &data, const repertory::info_log &value) {
|
||||||
|
data["function_name"] = value.function_name;
|
||||||
|
data["msg"] = value.msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void from_json(const json &data, repertory::info_log &value) {
|
||||||
|
data.at("function_name").get_to<std::string>(value.function_name);
|
||||||
|
data.at("msg").get_to<std::string>(value.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // REPERTORY_INCLUDE_EVENTS_TYPES_INFO_LOG_HPP_
|
@ -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_
|
68
repertory/librepertory/include/events/types/trace_log.hpp
Normal file
68
repertory/librepertory/include/events/types/trace_log.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
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_TRACE_LOG_HPP_
|
||||||
|
#define REPERTORY_INCLUDE_EVENTS_TYPES_TRACE_LOG_HPP_
|
||||||
|
|
||||||
|
#include "events/i_event.hpp"
|
||||||
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
struct trace_log final : public i_event {
|
||||||
|
trace_log() = default;
|
||||||
|
trace_log(std::string_view function_name_, std::string msg_)
|
||||||
|
: function_name(std::string(function_name_)), msg(std::move(msg_)) {}
|
||||||
|
|
||||||
|
static constexpr const event_level level{event_level::trace};
|
||||||
|
static constexpr const std::string_view name{"trace_log"};
|
||||||
|
|
||||||
|
std::string function_name;
|
||||||
|
std::string msg;
|
||||||
|
|
||||||
|
[[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|{}|msg|{}", name, function_name, msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace repertory
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
template <> struct adl_serializer<repertory::trace_log> {
|
||||||
|
static void to_json(json &data, const repertory::trace_log &value) {
|
||||||
|
data["function_name"] = value.function_name;
|
||||||
|
data["msg"] = value.msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void from_json(const json &data, repertory::trace_log &value) {
|
||||||
|
data.at("function_name").get_to<std::string>(value.function_name);
|
||||||
|
data.at("msg").get_to<std::string>(value.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // REPERTORY_INCLUDE_EVENTS_TYPES_TRACE_LOG_HPP_
|
68
repertory/librepertory/include/events/types/warn_log.hpp
Normal file
68
repertory/librepertory/include/events/types/warn_log.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
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_WARN_LOG_HPP_
|
||||||
|
#define REPERTORY_INCLUDE_EVENTS_TYPES_WARN_LOG_HPP_
|
||||||
|
|
||||||
|
#include "events/i_event.hpp"
|
||||||
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
struct warn_log final : public i_event {
|
||||||
|
warn_log() = default;
|
||||||
|
warn_log(std::string_view function_name_, std::string msg_)
|
||||||
|
: function_name(std::string(function_name_)), msg(std::move(msg_)) {}
|
||||||
|
|
||||||
|
static constexpr const event_level level{event_level::warn};
|
||||||
|
static constexpr const std::string_view name{"warn_log"};
|
||||||
|
|
||||||
|
std::string function_name;
|
||||||
|
std::string msg;
|
||||||
|
|
||||||
|
[[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|{}|msg|{}", name, function_name, msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace repertory
|
||||||
|
|
||||||
|
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||||
|
template <> struct adl_serializer<repertory::warn_log> {
|
||||||
|
static void to_json(json &data, const repertory::warn_log &value) {
|
||||||
|
data["function_name"] = value.function_name;
|
||||||
|
data["msg"] = value.msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void from_json(const json &data, repertory::warn_log &value) {
|
||||||
|
data.at("function_name").get_to<std::string>(value.function_name);
|
||||||
|
data.at("msg").get_to<std::string>(value.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // REPERTORY_INCLUDE_EVENTS_TYPES_WARN_LOG_HPP_
|
@ -22,6 +22,13 @@
|
|||||||
#ifndef REPERTORY_INCLUDE_PLATFORM_PLATFORM_HPP_
|
#ifndef REPERTORY_INCLUDE_PLATFORM_PLATFORM_HPP_
|
||||||
#define REPERTORY_INCLUDE_PLATFORM_PLATFORM_HPP_
|
#define REPERTORY_INCLUDE_PLATFORM_PLATFORM_HPP_
|
||||||
|
|
||||||
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
[[nodiscard]] auto create_lock_id(provider_type prov,
|
||||||
|
std::string_view unique_id)->std::string;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include "platform/win32_platform.hpp"
|
#include "platform/win32_platform.hpp"
|
||||||
#include "utils/windows.hpp"
|
#include "utils/windows.hpp"
|
||||||
|
@ -30,38 +30,45 @@ class i_provider;
|
|||||||
|
|
||||||
class lock_data final {
|
class lock_data final {
|
||||||
public:
|
public:
|
||||||
explicit lock_data(const provider_type &pt, std::string unique_id /*= ""*/);
|
lock_data(provider_type prov, std::string_view unique_id);
|
||||||
|
|
||||||
lock_data();
|
lock_data(const lock_data &) = delete;
|
||||||
|
lock_data(lock_data &&) = delete;
|
||||||
|
|
||||||
|
auto operator=(const lock_data &) -> lock_data & = delete;
|
||||||
|
auto operator=(lock_data &&) -> lock_data & = delete;
|
||||||
|
|
||||||
~lock_data();
|
~lock_data();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const provider_type pt_;
|
std::string mutex_id_;
|
||||||
const std::string unique_id_;
|
|
||||||
const std::string mutex_id_;
|
private:
|
||||||
int lock_fd_;
|
int handle_{};
|
||||||
int lock_status_ = EWOULDBLOCK;
|
int lock_status_{EWOULDBLOCK};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] static auto get_state_directory() -> std::string;
|
[[nodiscard]] static auto get_state_directory() -> std::string;
|
||||||
|
|
||||||
[[nodiscard]] static auto get_lock_data_file() -> std::string;
|
[[nodiscard]] auto get_lock_data_file() const -> std::string;
|
||||||
|
|
||||||
[[nodiscard]] auto get_lock_file() -> std::string;
|
[[nodiscard]] auto get_lock_file() const -> std::string;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] static auto
|
[[nodiscard]] static auto wait_for_lock(int handle,
|
||||||
wait_for_lock(int fd, std::uint8_t retry_count = 30u) -> int;
|
std::uint8_t retry_count = 30U)
|
||||||
|
-> int;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] auto get_mount_state(json &mount_state) -> bool;
|
[[nodiscard]] auto get_mount_state(json &mount_state) -> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto grab_lock(std::uint8_t retry_count = 30u) -> lock_result;
|
[[nodiscard]] auto grab_lock(std::uint8_t retry_count = 30U) -> lock_result;
|
||||||
|
|
||||||
|
void release();
|
||||||
|
|
||||||
[[nodiscard]] auto set_mount_state(bool active,
|
[[nodiscard]] auto set_mount_state(bool active,
|
||||||
const std::string &mount_location,
|
std::string_view mount_location, int pid)
|
||||||
int pid) -> bool;
|
-> bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] auto create_meta_attributes(
|
[[nodiscard]] auto create_meta_attributes(
|
||||||
@ -76,5 +83,5 @@ public:
|
|||||||
const api_file &file) -> api_error;
|
const api_file &file) -> api_error;
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif // _WIN32
|
#endif // !defined(_WIN32)
|
||||||
#endif // REPERTORY_INCLUDE_PLATFORM_UNIXPLATFORM_HPP_
|
#endif // REPERTORY_INCLUDE_PLATFORM_UNIXPLATFORM_HPP_
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#define REPERTORY_INCLUDE_PLATFORM_WINPLATFORM_HPP_
|
#define REPERTORY_INCLUDE_PLATFORM_WINPLATFORM_HPP_
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
@ -31,43 +30,32 @@ class i_provider;
|
|||||||
|
|
||||||
class lock_data final {
|
class lock_data final {
|
||||||
public:
|
public:
|
||||||
explicit lock_data(const provider_type &pt, std::string unique_id /*= ""*/)
|
explicit lock_data(provider_type prov, std::string unique_id);
|
||||||
: pt_(pt),
|
lock_data(const lock_data &) = delete;
|
||||||
unique_id_(std::move(unique_id)),
|
lock_data(lock_data &&) = delete;
|
||||||
mutex_id_("repertory_" + app_config::get_provider_name(pt) + "_" +
|
|
||||||
unique_id_),
|
|
||||||
mutex_handle_(::CreateMutex(nullptr, FALSE, &mutex_id_[0u])) {}
|
|
||||||
|
|
||||||
lock_data()
|
~lock_data();
|
||||||
: pt_(provider_type::sia),
|
|
||||||
unique_id_(""),
|
|
||||||
mutex_id_(""),
|
|
||||||
mutex_handle_(INVALID_HANDLE_VALUE) {}
|
|
||||||
|
|
||||||
~lock_data() { release(); }
|
auto operator=(const lock_data &) -> lock_data & = delete;
|
||||||
|
auto operator=(lock_data &&) -> lock_data & = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const provider_type pt_;
|
std::string mutex_id_;
|
||||||
const std::string unique_id_;
|
HANDLE mutex_handle_{INVALID_HANDLE_VALUE};
|
||||||
const std::string mutex_id_;
|
DWORD mutex_state_{WAIT_FAILED};
|
||||||
HANDLE mutex_handle_;
|
|
||||||
DWORD mutex_state_ = WAIT_FAILED;
|
[[nodiscard]] auto get_current_mount_state(json &mount_state) -> bool;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] auto get_mount_state(const provider_type &pt,
|
|
||||||
json &mount_state) -> bool;
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_mount_state(json &mount_state) -> bool;
|
[[nodiscard]] auto get_mount_state(json &mount_state) -> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto get_unique_id() const -> std::string { return unique_id_; }
|
[[nodiscard]] auto grab_lock(std::uint8_t retry_count = 30U) -> lock_result;
|
||||||
|
|
||||||
[[nodiscard]] auto grab_lock(std::uint8_t retry_count = 30) -> lock_result;
|
|
||||||
|
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
[[nodiscard]] auto set_mount_state(bool active,
|
[[nodiscard]] auto set_mount_state(bool active,
|
||||||
const std::string &mount_location,
|
std::string_view mount_location,
|
||||||
const std::int64_t &pid) -> bool;
|
std::int64_t pid) -> bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] auto create_meta_attributes(
|
[[nodiscard]] auto create_meta_attributes(
|
||||||
|
@ -85,6 +85,13 @@ private:
|
|||||||
void remove_deleted_files(stop_type &stop_requested);
|
void remove_deleted_files(stop_type &stop_requested);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
[[nodiscard]] auto check_version(std::string &required_version,
|
||||||
|
std::string &returned_version) const
|
||||||
|
-> bool override {
|
||||||
|
required_version = returned_version = "";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto create_directory(const std::string &api_path,
|
[[nodiscard]] auto create_directory(const std::string &api_path,
|
||||||
api_meta_map &meta) -> api_error override;
|
api_meta_map &meta) -> api_error override;
|
||||||
|
|
||||||
|
@ -31,6 +31,10 @@ class i_provider {
|
|||||||
INTERFACE_SETUP(i_provider);
|
INTERFACE_SETUP(i_provider);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
[[nodiscard]] virtual auto check_version(std::string &required_version,
|
||||||
|
std::string &returned_version) const
|
||||||
|
-> bool = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual auto create_directory(const std::string &api_path,
|
[[nodiscard]] virtual auto create_directory(const std::string &api_path,
|
||||||
api_meta_map &meta)
|
api_meta_map &meta)
|
||||||
-> api_error = 0;
|
-> api_error = 0;
|
||||||
|
@ -113,6 +113,13 @@ protected:
|
|||||||
-> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
[[nodiscard]] auto check_version(std::string &required_version,
|
||||||
|
std::string &returned_version) const
|
||||||
|
-> bool override {
|
||||||
|
required_version = returned_version = "";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] static auto convert_api_date(std::string_view date)
|
[[nodiscard]] static auto convert_api_date(std::string_view date)
|
||||||
-> std::uint64_t;
|
-> std::uint64_t;
|
||||||
|
|
||||||
|
@ -49,16 +49,28 @@ private:
|
|||||||
sia_config sia_config_;
|
sia_config sia_config_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
[[nodiscard]] auto create_directory_key(const std::string &api_path) const
|
||||||
|
-> repertory::api_error;
|
||||||
|
|
||||||
|
[[nodiscard]] auto ensure_directory_exists(const std::string &api_path) const
|
||||||
|
-> api_error;
|
||||||
|
|
||||||
[[nodiscard]] auto get_object_info(const std::string &api_path,
|
[[nodiscard]] auto get_object_info(const std::string &api_path,
|
||||||
json &object_info) const -> api_error;
|
json &object_info) const -> api_error;
|
||||||
|
|
||||||
[[nodiscard]] auto get_object_list(const std::string &api_path,
|
[[nodiscard]] auto
|
||||||
nlohmann::json &object_list) const -> bool;
|
get_object_list(const std::string &api_path, nlohmann::json &object_list,
|
||||||
|
std::optional<std::string> marker = std::nullopt) const
|
||||||
|
-> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto get_sia_config() const -> const auto & {
|
[[nodiscard]] auto get_sia_config() const -> const auto & {
|
||||||
return sia_config_;
|
return sia_config_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iterate_objects(
|
||||||
|
const std::string &api_path, const json &object_list,
|
||||||
|
std::function<void(const std::string &, bool, json)> handle_entry) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
[[nodiscard]] auto create_directory_impl(const std::string &api_path,
|
[[nodiscard]] auto create_directory_impl(const std::string &api_path,
|
||||||
api_meta_map &meta)
|
api_meta_map &meta)
|
||||||
@ -80,6 +92,10 @@ protected:
|
|||||||
-> api_error override;
|
-> api_error override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
[[nodiscard]] auto check_version(std::string &required_version,
|
||||||
|
std::string &returned_version) const
|
||||||
|
-> bool override;
|
||||||
|
|
||||||
[[nodiscard]] auto get_directory_item_count(const std::string &api_path) const
|
[[nodiscard]] auto get_directory_item_count(const std::string &api_path) const
|
||||||
-> std::uint64_t override;
|
-> std::uint64_t override;
|
||||||
|
|
||||||
|
@ -48,9 +48,9 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] auto get_pinned_files() -> rpc_response;
|
[[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,
|
[[nodiscard]] auto set_config_value_by_name(const std::string &name,
|
||||||
const std::string &value)
|
const std::string &value)
|
||||||
@ -58,7 +58,7 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] auto unmount() -> rpc_response;
|
[[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
|
} // namespace repertory
|
||||||
|
|
||||||
|
82
repertory/librepertory/include/rpc/common.hpp
Normal file
82
repertory/librepertory/include/rpc/common.hpp
Normal 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_password().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_password())) {
|
||||||
|
utils::error::raise_error(function_name, "authorization failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace repertory::rpc
|
||||||
|
|
||||||
|
#endif // REPERTORY_INCLUDE_RPC_COMMON_HPP_
|
@ -40,8 +40,6 @@ private:
|
|||||||
std::mutex start_stop_mutex_;
|
std::mutex start_stop_mutex_;
|
||||||
|
|
||||||
private:
|
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(const httplib::Request &req, httplib::Response &res);
|
||||||
|
|
||||||
void handle_get_config_value_by_name(const httplib::Request &req,
|
void handle_get_config_value_by_name(const httplib::Request &req,
|
||||||
|
@ -23,31 +23,29 @@
|
|||||||
#define REPERTORY_INCLUDE_TYPES_REPERTORY_HPP_
|
#define REPERTORY_INCLUDE_TYPES_REPERTORY_HPP_
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
constexpr const auto default_api_auth_size{48U};
|
constexpr const auto default_api_password_size{48U};
|
||||||
constexpr const auto default_download_timeout_ces{30U};
|
constexpr const auto default_download_timeout_secs{30U};
|
||||||
constexpr const auto default_eviction_delay_mins{1U};
|
constexpr const auto default_eviction_delay_mins{1U};
|
||||||
constexpr const auto default_high_freq_interval_secs{30U};
|
constexpr const auto default_high_freq_interval_secs{std::uint16_t{30U}};
|
||||||
constexpr const auto default_low_freq_interval_secs{0U * 60U};
|
constexpr const auto default_low_freq_interval_secs{std::uint16_t(60U * 60U)};
|
||||||
constexpr const auto default_max_cache_size_bytes{
|
constexpr const auto default_max_cache_size_bytes{
|
||||||
std::uint64_t(20UL * 1024UL * 1024UL * 1024UL),
|
std::uint64_t(20ULL * 1024ULL * 1024ULL * 1024ULL),
|
||||||
};
|
};
|
||||||
constexpr const auto default_max_upload_count{5U};
|
constexpr const auto default_max_upload_count{5U};
|
||||||
constexpr const auto default_med_freq_interval_secs{2U * 60U};
|
constexpr const auto default_med_freq_interval_secs{std::uint16_t{2U * 60U}};
|
||||||
constexpr const auto default_online_check_retry_secs{60U};
|
constexpr const auto default_online_check_retry_secs{60U};
|
||||||
constexpr const auto default_orphaned_file_retention_days{15U};
|
|
||||||
constexpr const auto default_retry_read_count{6U};
|
constexpr const auto default_retry_read_count{6U};
|
||||||
constexpr const auto default_ring_buffer_file_size{512U};
|
constexpr const auto default_ring_buffer_file_size{512U};
|
||||||
constexpr const auto default_task_wait_ms{100U};
|
constexpr const auto default_task_wait_ms{100U};
|
||||||
constexpr const auto default_timeout_ms{60000U};
|
constexpr const auto default_timeout_ms{60000U};
|
||||||
constexpr const auto max_orphaned_file_retention_days{std::uint16_t(31U)};
|
constexpr const auto default_ui_mgmt_port{std::uint16_t{30000U}};
|
||||||
constexpr const auto max_ring_buffer_file_size{std::uint16_t(1024U)};
|
constexpr const auto max_ring_buffer_file_size{std::uint16_t(1024U)};
|
||||||
constexpr const auto max_s3_object_name_length{1024U};
|
constexpr const auto max_s3_object_name_length{1024U};
|
||||||
constexpr const auto min_cache_size_bytes{
|
constexpr const auto min_cache_size_bytes{
|
||||||
std::uint64_t(100UL * 1024UL * 1024UL),
|
std::uint64_t(100ULL * 1024ULL * 1024ULL),
|
||||||
};
|
};
|
||||||
constexpr const auto min_download_timeout_secs{std::uint8_t(5U)};
|
constexpr const auto min_download_timeout_secs{std::uint8_t(5U)};
|
||||||
constexpr const auto min_online_check_retry_secs{std::uint16_t(15U)};
|
constexpr const auto min_online_check_retry_secs{std::uint16_t(15U)};
|
||||||
constexpr const auto min_orphaned_file_retention_days{std::uint16_t(1U)};
|
|
||||||
constexpr const auto min_retry_read_count{std::uint16_t(2U)};
|
constexpr const auto min_retry_read_count{std::uint16_t(2U)};
|
||||||
constexpr const auto min_ring_buffer_file_size{std::uint16_t(64U)};
|
constexpr const auto min_ring_buffer_file_size{std::uint16_t(64U)};
|
||||||
constexpr const auto min_task_wait_ms{std::uint16_t(50U)};
|
constexpr const auto min_task_wait_ms{std::uint16_t(50U)};
|
||||||
@ -283,6 +281,8 @@ enum class exit_code : std::int32_t {
|
|||||||
pin_failed = -16,
|
pin_failed = -16,
|
||||||
unpin_failed = -17,
|
unpin_failed = -17,
|
||||||
init_failed = -18,
|
init_failed = -18,
|
||||||
|
ui_mount_failed = -19,
|
||||||
|
exception = -20,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum http_error_codes : std::int32_t {
|
enum http_error_codes : std::int32_t {
|
||||||
@ -307,6 +307,18 @@ enum class provider_type : std::size_t {
|
|||||||
unknown,
|
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;
|
||||||
|
|
||||||
|
void clean_json_config(provider_type prov, nlohmann::json &data);
|
||||||
|
|
||||||
|
[[nodiscard]] auto clean_json_value(std::string_view name,
|
||||||
|
std::string_view data) -> std::string;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
struct open_file_data final {
|
struct open_file_data final {
|
||||||
PVOID directory_buffer{nullptr};
|
PVOID directory_buffer{nullptr};
|
||||||
@ -333,7 +345,6 @@ struct directory_item final {
|
|||||||
bool directory{false};
|
bool directory{false};
|
||||||
std::uint64_t size{};
|
std::uint64_t size{};
|
||||||
api_meta_map meta;
|
api_meta_map meta;
|
||||||
bool resolved{false};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct encrypt_config final {
|
struct encrypt_config final {
|
||||||
@ -456,7 +467,6 @@ using meta_provider_callback = std::function<void(directory_item &)>;
|
|||||||
|
|
||||||
inline constexpr const auto JSON_ACCESS_KEY{"AccessKey"};
|
inline constexpr const auto JSON_ACCESS_KEY{"AccessKey"};
|
||||||
inline constexpr const auto JSON_AGENT_STRING{"AgentString"};
|
inline constexpr const auto JSON_AGENT_STRING{"AgentString"};
|
||||||
inline constexpr const auto JSON_API_AUTH{"ApiAuth"};
|
|
||||||
inline constexpr const auto JSON_API_PARENT{"ApiParent"};
|
inline constexpr const auto JSON_API_PARENT{"ApiParent"};
|
||||||
inline constexpr const auto JSON_API_PASSWORD{"ApiPassword"};
|
inline constexpr const auto JSON_API_PASSWORD{"ApiPassword"};
|
||||||
inline constexpr const auto JSON_API_PATH{"ApiPath"};
|
inline constexpr const auto JSON_API_PATH{"ApiPath"};
|
||||||
@ -491,10 +501,9 @@ inline constexpr const auto JSON_MAX_UPLOAD_COUNT{"MaxUploadCount"};
|
|||||||
inline constexpr const auto JSON_MED_FREQ_INTERVAL_SECS{
|
inline constexpr const auto JSON_MED_FREQ_INTERVAL_SECS{
|
||||||
"MedFreqIntervalSeconds"};
|
"MedFreqIntervalSeconds"};
|
||||||
inline constexpr const auto JSON_META{"Meta"};
|
inline constexpr const auto JSON_META{"Meta"};
|
||||||
|
inline constexpr const auto JSON_MOUNT_LOCATIONS{"MountLocations"};
|
||||||
inline constexpr const auto JSON_ONLINE_CHECK_RETRY_SECS{
|
inline constexpr const auto JSON_ONLINE_CHECK_RETRY_SECS{
|
||||||
"OnlineCheckRetrySeconds"};
|
"OnlineCheckRetrySeconds"};
|
||||||
inline constexpr const auto JSON_ORPHANED_FILE_RETENTION_DAYS{
|
|
||||||
"OrphanedFileRetentionDays"};
|
|
||||||
inline constexpr const auto JSON_PATH{"Path"};
|
inline constexpr const auto JSON_PATH{"Path"};
|
||||||
inline constexpr const auto JSON_PREFERRED_DOWNLOAD_TYPE{
|
inline constexpr const auto JSON_PREFERRED_DOWNLOAD_TYPE{
|
||||||
"PreferredDownloadType"};
|
"PreferredDownloadType"};
|
||||||
@ -619,6 +628,16 @@ template <typename data_t> struct adl_serializer<repertory::atomic<data_t>> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct adl_serializer<std::atomic<std::uint64_t>> {
|
||||||
|
static void to_json(json &data, const std::atomic<std::uint64_t> &value) {
|
||||||
|
data = value.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void from_json(const json &data, std::atomic<std::uint64_t> &value) {
|
||||||
|
value.store(data.get<std::uint64_t>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename primitive_t>
|
template <typename primitive_t>
|
||||||
struct adl_serializer<std::atomic<primitive_t>> {
|
struct adl_serializer<std::atomic<primitive_t>> {
|
||||||
static void to_json(json &data, const std::atomic<primitive_t> &value) {
|
static void to_json(json &data, const std::atomic<primitive_t> &value) {
|
||||||
@ -642,6 +661,18 @@ template <> struct adl_serializer<std::atomic<repertory::database_type>> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct adl_serializer<std::atomic<repertory::event_level>> {
|
||||||
|
static void to_json(json &data,
|
||||||
|
const std::atomic<repertory::event_level> &value) {
|
||||||
|
data = repertory::event_level_to_string(value.load());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void from_json(const json &data,
|
||||||
|
std::atomic<repertory::event_level> &value) {
|
||||||
|
value.store(repertory::event_level_from_string(data.get<std::string>()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <> struct adl_serializer<std::atomic<repertory::download_type>> {
|
template <> struct adl_serializer<std::atomic<repertory::download_type>> {
|
||||||
static void to_json(json &data,
|
static void to_json(json &data,
|
||||||
const std::atomic<repertory::download_type> &value) {
|
const std::atomic<repertory::download_type> &value) {
|
||||||
@ -674,15 +705,13 @@ template <> struct adl_serializer<repertory::download_type> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct adl_serializer<std::atomic<repertory::event_level>> {
|
template <> struct adl_serializer<repertory::event_level> {
|
||||||
static void to_json(json &data,
|
static void to_json(json &data, const repertory::event_level &value) {
|
||||||
const std::atomic<repertory::event_level> &value) {
|
data = repertory::event_level_to_string(value);
|
||||||
data = repertory::event_level_to_string(value.load());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void from_json(const json &data,
|
static void from_json(const json &data, repertory::event_level &value) {
|
||||||
std::atomic<repertory::event_level> &value) {
|
value = repertory::event_level_from_string(data.get<std::string>());
|
||||||
value.store(repertory::event_level_from_string(data.get<std::string>()));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
NLOHMANN_JSON_NAMESPACE_END
|
NLOHMANN_JSON_NAMESPACE_END
|
||||||
|
@ -49,6 +49,8 @@ static const option password_option = {"-pw", "--password"};
|
|||||||
static const option remote_mount_option = {"-rm", "--remote_mount"};
|
static const option remote_mount_option = {"-rm", "--remote_mount"};
|
||||||
static const option set_option = {"-set", "--set"};
|
static const option set_option = {"-set", "--set"};
|
||||||
static const option status_option = {"-status", "--status"};
|
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 unmount_option = {"-unmount", "--unmount"};
|
||||||
static const option unpin_file_option = {"-uf", "--unpin_file"};
|
static const option unpin_file_option = {"-uf", "--unpin_file"};
|
||||||
static const option user_option = {"-us", "--user"};
|
static const option user_option = {"-us", "--user"};
|
||||||
@ -75,6 +77,8 @@ static const std::vector<option> option_list = {
|
|||||||
remote_mount_option,
|
remote_mount_option,
|
||||||
set_option,
|
set_option,
|
||||||
status_option,
|
status_option,
|
||||||
|
ui_option,
|
||||||
|
ui_port_option,
|
||||||
unmount_option,
|
unmount_option,
|
||||||
unpin_file_option,
|
unpin_file_option,
|
||||||
user_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,
|
std::uint16_t &port, const provider_type &prov,
|
||||||
const std::string &data_directory);
|
const std::string &data_directory);
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto get_provider_type_from_args(std::vector<const char *> args)
|
||||||
get_provider_type_from_args(std::vector<const char *> args) -> provider_type;
|
-> provider_type;
|
||||||
|
|
||||||
[[nodiscard]] auto has_option(std::vector<const char *> args,
|
[[nodiscard]] auto has_option(std::vector<const char *> args,
|
||||||
const std::string &option_name) -> bool;
|
const std::string &option_name) -> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto has_option(std::vector<const char *> args,
|
[[nodiscard]] auto has_option(std::vector<const char *> args, const option &opt)
|
||||||
const option &opt) -> bool;
|
-> bool;
|
||||||
|
|
||||||
[[nodiscard]] auto parse_option(std::vector<const char *> args,
|
[[nodiscard]] auto parse_option(std::vector<const char *> args,
|
||||||
const std::string &option_name,
|
const std::string &option_name,
|
||||||
std::uint8_t count) -> std::vector<std::string>;
|
std::uint8_t count) -> std::vector<std::string>;
|
||||||
|
|
||||||
[[nodiscard]] auto parse_string_option(std::vector<const char *> args,
|
[[nodiscard]] auto parse_string_option(std::vector<const char *> args,
|
||||||
const option &opt,
|
const option &opt, std::string &value)
|
||||||
std::string &value) -> exit_code;
|
-> exit_code;
|
||||||
|
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto parse_drive_options(std::vector<const char *> args,
|
||||||
parse_drive_options(std::vector<const char *> args, provider_type &prov,
|
provider_type &prov,
|
||||||
std::string &data_directory) -> std::vector<std::string>;
|
std::string &data_directory)
|
||||||
|
-> std::vector<std::string>;
|
||||||
} // namespace repertory::utils::cli
|
} // namespace repertory::utils::cli
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_UTILS_CLI_UTILS_HPP_
|
#endif // REPERTORY_INCLUDE_UTILS_CLI_UTILS_HPP_
|
||||||
|
@ -66,11 +66,11 @@ void app_config::set_stop_requested() { stop_requested.store(true); }
|
|||||||
app_config::app_config(const provider_type &prov,
|
app_config::app_config(const provider_type &prov,
|
||||||
std::string_view data_directory)
|
std::string_view data_directory)
|
||||||
: prov_(prov),
|
: prov_(prov),
|
||||||
api_auth_(utils::generate_random_string(default_api_auth_size)),
|
api_password_(utils::generate_random_string(default_api_password_size)),
|
||||||
api_port_(default_rpc_port(prov)),
|
api_port_(default_rpc_port()),
|
||||||
api_user_(std::string{REPERTORY}),
|
api_user_(std::string{REPERTORY}),
|
||||||
config_changed_(false),
|
config_changed_(false),
|
||||||
download_timeout_secs_(default_download_timeout_ces),
|
download_timeout_secs_(default_download_timeout_secs),
|
||||||
enable_download_timeout_(true),
|
enable_download_timeout_(true),
|
||||||
enable_drive_events_(false),
|
enable_drive_events_(false),
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -85,7 +85,6 @@ app_config::app_config(const provider_type &prov,
|
|||||||
max_upload_count_(default_max_upload_count),
|
max_upload_count_(default_max_upload_count),
|
||||||
med_freq_interval_secs_(default_med_freq_interval_secs),
|
med_freq_interval_secs_(default_med_freq_interval_secs),
|
||||||
online_check_retry_secs_(default_online_check_retry_secs),
|
online_check_retry_secs_(default_online_check_retry_secs),
|
||||||
orphaned_file_retention_days_(default_orphaned_file_retention_days),
|
|
||||||
preferred_download_type_(download_type::default_),
|
preferred_download_type_(download_type::default_),
|
||||||
retry_read_count_(default_retry_read_count),
|
retry_read_count_(default_retry_read_count),
|
||||||
ring_buffer_file_size_(default_ring_buffer_file_size),
|
ring_buffer_file_size_(default_ring_buffer_file_size),
|
||||||
@ -125,7 +124,7 @@ app_config::app_config(const provider_type &prov,
|
|||||||
}
|
}
|
||||||
|
|
||||||
value_get_lookup_ = {
|
value_get_lookup_ = {
|
||||||
{JSON_API_AUTH, [this]() { return get_api_auth(); }},
|
{JSON_API_PASSWORD, [this]() { return get_api_password(); }},
|
||||||
{JSON_API_PORT, [this]() { return std::to_string(get_api_port()); }},
|
{JSON_API_PORT, [this]() { return std::to_string(get_api_port()); }},
|
||||||
{JSON_API_USER, [this]() { return get_api_user(); }},
|
{JSON_API_USER, [this]() { return get_api_user(); }},
|
||||||
{JSON_DATABASE_TYPE,
|
{JSON_DATABASE_TYPE,
|
||||||
@ -166,8 +165,14 @@ app_config::app_config(const provider_type &prov,
|
|||||||
[this]() { return get_host_config().api_password; }},
|
[this]() { return get_host_config().api_password; }},
|
||||||
{fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PORT),
|
{fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PORT),
|
||||||
[this]() { return std::to_string(get_host_config().api_port); }},
|
[this]() { return std::to_string(get_host_config().api_port); }},
|
||||||
|
{fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_USER),
|
||||||
|
[this]() { return get_host_config().api_user; }},
|
||||||
{fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP),
|
{fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP),
|
||||||
[this]() { return get_host_config().host_name_or_ip; }},
|
[this]() { return get_host_config().host_name_or_ip; }},
|
||||||
|
{fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PATH),
|
||||||
|
[this]() { return get_host_config().path; }},
|
||||||
|
{fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PROTOCOL),
|
||||||
|
[this]() { return get_host_config().protocol; }},
|
||||||
{fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS),
|
{fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS),
|
||||||
[this]() { return std::to_string(get_host_config().timeout_ms); }},
|
[this]() { return std::to_string(get_host_config().timeout_ms); }},
|
||||||
{JSON_LOW_FREQ_INTERVAL_SECS,
|
{JSON_LOW_FREQ_INTERVAL_SECS,
|
||||||
@ -180,8 +185,6 @@ app_config::app_config(const provider_type &prov,
|
|||||||
[this]() { return std::to_string(get_med_frequency_interval_secs()); }},
|
[this]() { return std::to_string(get_med_frequency_interval_secs()); }},
|
||||||
{JSON_ONLINE_CHECK_RETRY_SECS,
|
{JSON_ONLINE_CHECK_RETRY_SECS,
|
||||||
[this]() { return std::to_string(get_online_check_retry_secs()); }},
|
[this]() { return std::to_string(get_online_check_retry_secs()); }},
|
||||||
{JSON_ORPHANED_FILE_RETENTION_DAYS,
|
|
||||||
[this]() { return std::to_string(get_orphaned_file_retention_days()); }},
|
|
||||||
{JSON_PREFERRED_DOWNLOAD_TYPE,
|
{JSON_PREFERRED_DOWNLOAD_TYPE,
|
||||||
[this]() {
|
[this]() {
|
||||||
return download_type_to_string(get_preferred_download_type());
|
return download_type_to_string(get_preferred_download_type());
|
||||||
@ -250,10 +253,10 @@ app_config::app_config(const provider_type &prov,
|
|||||||
|
|
||||||
value_set_lookup_ = {
|
value_set_lookup_ = {
|
||||||
{
|
{
|
||||||
JSON_API_PATH,
|
JSON_API_PASSWORD,
|
||||||
[this](const std::string &value) {
|
[this](const std::string &value) {
|
||||||
set_api_auth(value);
|
set_api_password(value);
|
||||||
return get_api_auth();
|
return get_api_password();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -349,7 +352,7 @@ app_config::app_config(const provider_type &prov,
|
|||||||
{
|
{
|
||||||
JSON_HIGH_FREQ_INTERVAL_SECS,
|
JSON_HIGH_FREQ_INTERVAL_SECS,
|
||||||
[this](const std::string &value) {
|
[this](const std::string &value) {
|
||||||
set_high_frequency_interval_secs(utils::string::to_uint8(value));
|
set_high_frequency_interval_secs(utils::string::to_uint16(value));
|
||||||
return std::to_string(get_high_frequency_interval_secs());
|
return std::to_string(get_high_frequency_interval_secs());
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -380,6 +383,15 @@ app_config::app_config(const provider_type &prov,
|
|||||||
return std::to_string(get_host_config().api_port);
|
return std::to_string(get_host_config().api_port);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_USER),
|
||||||
|
[this](const std::string &value) {
|
||||||
|
auto cfg = get_host_config();
|
||||||
|
cfg.api_user = value;
|
||||||
|
set_host_config(cfg);
|
||||||
|
return get_host_config().api_user;
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP),
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP),
|
||||||
[this](const std::string &value) {
|
[this](const std::string &value) {
|
||||||
@ -389,6 +401,24 @@ app_config::app_config(const provider_type &prov,
|
|||||||
return get_host_config().host_name_or_ip;
|
return get_host_config().host_name_or_ip;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PATH),
|
||||||
|
[this](const std::string &value) {
|
||||||
|
auto cfg = get_host_config();
|
||||||
|
cfg.path = value;
|
||||||
|
set_host_config(cfg);
|
||||||
|
return get_host_config().path;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PROTOCOL),
|
||||||
|
[this](const std::string &value) {
|
||||||
|
auto cfg = get_host_config();
|
||||||
|
cfg.protocol = value;
|
||||||
|
set_host_config(cfg);
|
||||||
|
return get_host_config().protocol;
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS),
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS),
|
||||||
[this](const std::string &value) {
|
[this](const std::string &value) {
|
||||||
@ -401,14 +431,14 @@ app_config::app_config(const provider_type &prov,
|
|||||||
{
|
{
|
||||||
JSON_LOW_FREQ_INTERVAL_SECS,
|
JSON_LOW_FREQ_INTERVAL_SECS,
|
||||||
[this](const std::string &value) {
|
[this](const std::string &value) {
|
||||||
set_low_frequency_interval_secs(utils::string::to_uint8(value));
|
set_low_frequency_interval_secs(utils::string::to_uint16(value));
|
||||||
return std::to_string(get_low_frequency_interval_secs());
|
return std::to_string(get_low_frequency_interval_secs());
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
JSON_MED_FREQ_INTERVAL_SECS,
|
JSON_MED_FREQ_INTERVAL_SECS,
|
||||||
[this](const std::string &value) {
|
[this](const std::string &value) {
|
||||||
set_med_frequency_interval_secs(utils::string::to_uint8(value));
|
set_med_frequency_interval_secs(utils::string::to_uint16(value));
|
||||||
return std::to_string(get_med_frequency_interval_secs());
|
return std::to_string(get_med_frequency_interval_secs());
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -433,13 +463,6 @@ app_config::app_config(const provider_type &prov,
|
|||||||
return std::to_string(get_online_check_retry_secs());
|
return std::to_string(get_online_check_retry_secs());
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
JSON_ORPHANED_FILE_RETENTION_DAYS,
|
|
||||||
[this](const std::string &value) {
|
|
||||||
set_orphaned_file_retention_days(utils::string::to_uint16(value));
|
|
||||||
return std::to_string(get_orphaned_file_retention_days());
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
JSON_PREFERRED_DOWNLOAD_TYPE,
|
JSON_PREFERRED_DOWNLOAD_TYPE,
|
||||||
[this](const std::string &value) {
|
[this](const std::string &value) {
|
||||||
@ -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));
|
return PROVIDER_API_PORTS.at(static_cast<std::size_t>(prov));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto app_config::default_data_directory(const provider_type &prov)
|
auto app_config::get_root_data_directory() -> std::string {
|
||||||
-> std::string {
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
auto data_directory =
|
auto data_directory = utils::path::combine(
|
||||||
utils::path::combine(utils::get_local_app_data_directory(),
|
utils::get_local_app_data_directory(), {
|
||||||
{
|
REPERTORY_DATA_NAME,
|
||||||
REPERTORY_DATA_NAME,
|
});
|
||||||
app_config::get_provider_name(prov),
|
|
||||||
});
|
|
||||||
#else // !defined(_WIN32)
|
#else // !defined(_WIN32)
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
auto data_directory =
|
auto data_directory = utils::path::combine("~", {
|
||||||
utils::path::combine("~", {
|
"Library",
|
||||||
"Library",
|
"Application Support",
|
||||||
"Application Support",
|
REPERTORY_DATA_NAME,
|
||||||
REPERTORY_DATA_NAME,
|
});
|
||||||
app_config::get_provider_name(prov),
|
|
||||||
});
|
|
||||||
#else // !defined(__APPLE__)
|
#else // !defined(__APPLE__)
|
||||||
auto data_directory =
|
auto data_directory = utils::path::combine("~", {
|
||||||
utils::path::combine("~", {
|
".local",
|
||||||
".local",
|
REPERTORY_DATA_NAME,
|
||||||
REPERTORY_DATA_NAME,
|
});
|
||||||
app_config::get_provider_name(prov),
|
|
||||||
});
|
|
||||||
#endif // defined(__APPLE__)
|
#endif // defined(__APPLE__)
|
||||||
#endif // defined(_WIN32)
|
#endif // defined(_WIN32)
|
||||||
return data_directory;
|
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)
|
auto app_config::default_remote_api_port(const provider_type &prov)
|
||||||
-> std::uint16_t {
|
-> std::uint16_t {
|
||||||
static const std::array<std::uint16_t,
|
static const std::array<std::uint16_t,
|
||||||
@ -718,19 +742,12 @@ auto app_config::default_remote_api_port(const provider_type &prov)
|
|||||||
};
|
};
|
||||||
return PROVIDER_REMOTE_PORTS.at(static_cast<std::size_t>(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)>
|
|
||||||
PROVIDER_RPC_PORTS = {
|
|
||||||
10000U,
|
|
||||||
10010U,
|
|
||||||
10100U,
|
|
||||||
10002U,
|
|
||||||
};
|
|
||||||
return PROVIDER_RPC_PORTS.at(static_cast<std::size_t>(prov));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto app_config::get_api_auth() const -> std::string { return api_auth_; }
|
auto app_config::default_rpc_port() -> std::uint16_t { return 10000U; }
|
||||||
|
|
||||||
|
auto app_config::get_api_password() const -> std::string {
|
||||||
|
return api_password_;
|
||||||
|
}
|
||||||
|
|
||||||
auto app_config::get_api_port() const -> std::uint16_t { return api_port_; }
|
auto app_config::get_api_port() const -> std::uint16_t { return api_port_; }
|
||||||
|
|
||||||
@ -791,7 +808,7 @@ auto app_config::get_host_config() const -> host_config { return host_config_; }
|
|||||||
|
|
||||||
auto app_config::get_json() const -> json {
|
auto app_config::get_json() const -> json {
|
||||||
json ret = {
|
json ret = {
|
||||||
{JSON_API_AUTH, api_auth_},
|
{JSON_API_PASSWORD, api_password_},
|
||||||
{JSON_API_PORT, api_port_},
|
{JSON_API_PORT, api_port_},
|
||||||
{JSON_API_USER, api_user_},
|
{JSON_API_USER, api_user_},
|
||||||
{JSON_DOWNLOAD_TIMEOUT_SECS, download_timeout_secs_},
|
{JSON_DOWNLOAD_TIMEOUT_SECS, download_timeout_secs_},
|
||||||
@ -812,7 +829,6 @@ auto app_config::get_json() const -> json {
|
|||||||
{JSON_MAX_UPLOAD_COUNT, max_upload_count_},
|
{JSON_MAX_UPLOAD_COUNT, max_upload_count_},
|
||||||
{JSON_MED_FREQ_INTERVAL_SECS, med_freq_interval_secs_},
|
{JSON_MED_FREQ_INTERVAL_SECS, med_freq_interval_secs_},
|
||||||
{JSON_ONLINE_CHECK_RETRY_SECS, online_check_retry_secs_},
|
{JSON_ONLINE_CHECK_RETRY_SECS, online_check_retry_secs_},
|
||||||
{JSON_ORPHANED_FILE_RETENTION_DAYS, orphaned_file_retention_days_},
|
|
||||||
{JSON_PREFERRED_DOWNLOAD_TYPE, preferred_download_type_},
|
{JSON_PREFERRED_DOWNLOAD_TYPE, preferred_download_type_},
|
||||||
{JSON_REMOTE_CONFIG, remote_config_},
|
{JSON_REMOTE_CONFIG, remote_config_},
|
||||||
{JSON_REMOTE_MOUNT, remote_mount_},
|
{JSON_REMOTE_MOUNT, remote_mount_},
|
||||||
@ -834,7 +850,6 @@ auto app_config::get_json() const -> json {
|
|||||||
ret.erase(JSON_MAX_CACHE_SIZE_BYTES);
|
ret.erase(JSON_MAX_CACHE_SIZE_BYTES);
|
||||||
ret.erase(JSON_MAX_UPLOAD_COUNT);
|
ret.erase(JSON_MAX_UPLOAD_COUNT);
|
||||||
ret.erase(JSON_ONLINE_CHECK_RETRY_SECS);
|
ret.erase(JSON_ONLINE_CHECK_RETRY_SECS);
|
||||||
ret.erase(JSON_ORPHANED_FILE_RETENTION_DAYS);
|
|
||||||
ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
|
ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
|
||||||
ret.erase(JSON_REMOTE_CONFIG);
|
ret.erase(JSON_REMOTE_CONFIG);
|
||||||
ret.erase(JSON_RETRY_READ_COUNT);
|
ret.erase(JSON_RETRY_READ_COUNT);
|
||||||
@ -856,7 +871,6 @@ auto app_config::get_json() const -> json {
|
|||||||
ret.erase(JSON_MAX_UPLOAD_COUNT);
|
ret.erase(JSON_MAX_UPLOAD_COUNT);
|
||||||
ret.erase(JSON_MED_FREQ_INTERVAL_SECS);
|
ret.erase(JSON_MED_FREQ_INTERVAL_SECS);
|
||||||
ret.erase(JSON_ONLINE_CHECK_RETRY_SECS);
|
ret.erase(JSON_ONLINE_CHECK_RETRY_SECS);
|
||||||
ret.erase(JSON_ORPHANED_FILE_RETENTION_DAYS);
|
|
||||||
ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
|
ret.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
|
||||||
ret.erase(JSON_REMOTE_MOUNT);
|
ret.erase(JSON_REMOTE_MOUNT);
|
||||||
ret.erase(JSON_RETRY_READ_COUNT);
|
ret.erase(JSON_RETRY_READ_COUNT);
|
||||||
@ -912,12 +926,6 @@ auto app_config::get_online_check_retry_secs() const -> std::uint16_t {
|
|||||||
return std::max(min_online_check_retry_secs, online_check_retry_secs_.load());
|
return std::max(min_online_check_retry_secs, online_check_retry_secs_.load());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto app_config::get_orphaned_file_retention_days() const -> std::uint16_t {
|
|
||||||
return std::min(max_orphaned_file_retention_days,
|
|
||||||
std::max(min_orphaned_file_retention_days,
|
|
||||||
orphaned_file_retention_days_.load()));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto app_config::get_preferred_download_type() const -> download_type {
|
auto app_config::get_preferred_download_type() const -> download_type {
|
||||||
return preferred_download_type_;
|
return preferred_download_type_;
|
||||||
}
|
}
|
||||||
@ -925,24 +933,18 @@ auto app_config::get_preferred_download_type() const -> download_type {
|
|||||||
auto app_config::get_provider_display_name(const provider_type &prov)
|
auto app_config::get_provider_display_name(const provider_type &prov)
|
||||||
-> std::string {
|
-> std::string {
|
||||||
static const std::array<std::string,
|
static const std::array<std::string,
|
||||||
static_cast<std::size_t>(provider_type::unknown)>
|
static_cast<std::size_t>(provider_type::unknown) + 1U>
|
||||||
PROVIDER_DISPLAY_NAMES = {
|
PROVIDER_DISPLAY_NAMES = {
|
||||||
"Sia",
|
"Sia", "Remote", "S3", "Encrypt", "Unknown",
|
||||||
"Remote",
|
|
||||||
"S3",
|
|
||||||
"Encrypt",
|
|
||||||
};
|
};
|
||||||
return PROVIDER_DISPLAY_NAMES.at(static_cast<std::size_t>(prov));
|
return PROVIDER_DISPLAY_NAMES.at(static_cast<std::size_t>(prov));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto app_config::get_provider_name(const provider_type &prov) -> std::string {
|
auto app_config::get_provider_name(const provider_type &prov) -> std::string {
|
||||||
static const std::array<std::string,
|
static const std::array<std::string,
|
||||||
static_cast<std::size_t>(provider_type::unknown)>
|
static_cast<std::size_t>(provider_type::unknown) + 1U>
|
||||||
PROVIDER_NAMES = {
|
PROVIDER_NAMES = {
|
||||||
"sia",
|
"sia", "remote", "s3", "encrypt", "unknown",
|
||||||
"remote",
|
|
||||||
"s3",
|
|
||||||
"encrypt",
|
|
||||||
};
|
};
|
||||||
return PROVIDER_NAMES.at(static_cast<std::size_t>(prov));
|
return PROVIDER_NAMES.at(static_cast<std::size_t>(prov));
|
||||||
}
|
}
|
||||||
@ -1021,7 +1023,7 @@ auto app_config::load() -> bool {
|
|||||||
auto found{true};
|
auto found{true};
|
||||||
auto json_document = json::parse(json_text);
|
auto json_document = json::parse(json_text);
|
||||||
|
|
||||||
get_value(json_document, JSON_API_AUTH, api_auth_, found);
|
get_value(json_document, JSON_API_PASSWORD, api_password_, found);
|
||||||
get_value(json_document, JSON_API_PORT, api_port_, found);
|
get_value(json_document, JSON_API_PORT, api_port_, found);
|
||||||
get_value(json_document, JSON_API_USER, api_user_, found);
|
get_value(json_document, JSON_API_USER, api_user_, found);
|
||||||
get_value(json_document, JSON_DATABASE_TYPE, db_type_, found);
|
get_value(json_document, JSON_DATABASE_TYPE, db_type_, found);
|
||||||
@ -1053,8 +1055,6 @@ auto app_config::load() -> bool {
|
|||||||
med_freq_interval_secs_, found);
|
med_freq_interval_secs_, found);
|
||||||
get_value(json_document, JSON_ONLINE_CHECK_RETRY_SECS,
|
get_value(json_document, JSON_ONLINE_CHECK_RETRY_SECS,
|
||||||
online_check_retry_secs_, found);
|
online_check_retry_secs_, found);
|
||||||
get_value(json_document, JSON_ORPHANED_FILE_RETENTION_DAYS,
|
|
||||||
orphaned_file_retention_days_, found);
|
|
||||||
get_value(json_document, JSON_PREFERRED_DOWNLOAD_TYPE,
|
get_value(json_document, JSON_PREFERRED_DOWNLOAD_TYPE,
|
||||||
preferred_download_type_, found);
|
preferred_download_type_, found);
|
||||||
get_value(json_document, JSON_REMOTE_CONFIG, remote_config_, found);
|
get_value(json_document, JSON_REMOTE_CONFIG, remote_config_, found);
|
||||||
@ -1069,10 +1069,24 @@ auto app_config::load() -> bool {
|
|||||||
std::uint64_t version{};
|
std::uint64_t version{};
|
||||||
get_value(json_document, JSON_VERSION, version, found);
|
get_value(json_document, JSON_VERSION, version, found);
|
||||||
|
|
||||||
// Handle configuration defaults for new config versions
|
|
||||||
if (version != REPERTORY_CONFIG_VERSION) {
|
if (version != REPERTORY_CONFIG_VERSION) {
|
||||||
version_ = REPERTORY_CONFIG_VERSION;
|
version_ = REPERTORY_CONFIG_VERSION;
|
||||||
// TODO upgrade future version
|
if (version_ == 1U) {
|
||||||
|
if (low_freq_interval_secs_ == 0UL) {
|
||||||
|
set_value(low_freq_interval_secs_, default_low_freq_interval_secs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_cache_size_bytes_ == 0UL) {
|
||||||
|
set_value(max_cache_size_bytes_, default_max_cache_size_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version_ == 2U) {
|
||||||
|
if (json_document.contains("ApiAuth")) {
|
||||||
|
api_password_ = json_document.at("ApiAuth").get<std::string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
found = false;
|
found = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1111,8 +1125,8 @@ void app_config::save() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_config::set_api_auth(const std::string &value) {
|
void app_config::set_api_password(const std::string &value) {
|
||||||
set_value(api_auth_, value);
|
set_value(api_password_, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_config::set_api_port(std::uint16_t value) {
|
void app_config::set_api_port(std::uint16_t value) {
|
||||||
@ -1199,10 +1213,6 @@ void app_config::set_online_check_retry_secs(std::uint16_t value) {
|
|||||||
set_value(online_check_retry_secs_, value);
|
set_value(online_check_retry_secs_, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_config::set_orphaned_file_retention_days(std::uint16_t value) {
|
|
||||||
set_value(orphaned_file_retention_days_, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_config::set_preferred_download_type(const download_type &value) {
|
void app_config::set_preferred_download_type(const download_type &value) {
|
||||||
set_value(preferred_download_type_, value);
|
set_value(preferred_download_type_, value);
|
||||||
}
|
}
|
||||||
|
@ -39,33 +39,34 @@ auto directory_iterator::fill_buffer(const remote::file_offset &offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::string item_name;
|
auto next_offset{offset + 1U};
|
||||||
struct stat st{};
|
|
||||||
struct stat *pst = nullptr;
|
|
||||||
switch (offset) {
|
|
||||||
case 0: {
|
|
||||||
item_name = ".";
|
|
||||||
} break;
|
|
||||||
|
|
||||||
|
std::string item_name;
|
||||||
|
struct stat u_stat{};
|
||||||
|
|
||||||
|
switch (offset) {
|
||||||
|
case 0:
|
||||||
case 1: {
|
case 1: {
|
||||||
item_name = "..";
|
item_name = offset == 0U ? "." : "..";
|
||||||
|
u_stat.st_mode = S_IFDIR | 0755;
|
||||||
|
u_stat.st_nlink = 2;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
const auto &item = items_[offset];
|
const auto &item = items_.at(offset);
|
||||||
item_name = utils::path::strip_to_file_name(item.api_path);
|
item_name = utils::path::strip_to_file_name(item.api_path);
|
||||||
populate_stat(item.api_path, item.size, item.meta, item.directory, &st);
|
populate_stat(item.api_path, item.size, item.meta, item.directory,
|
||||||
pst = &st;
|
&u_stat);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
if (filler_function(buffer, item_name.data(), pst,
|
if (filler_function(buffer, item_name.data(), &u_stat,
|
||||||
static_cast<off_t>(offset + 1),
|
static_cast<off_t>(next_offset),
|
||||||
FUSE_FILL_DIR_PLUS) != 0)
|
FUSE_FILL_DIR_PLUS) != 0)
|
||||||
#else // FUSE_USE_VERSION < 30
|
#else // FUSE_USE_VERSION < 30
|
||||||
if (filler_function(buffer, item_name.data(), pst,
|
if (filler_function(buffer, item_name.data(), &u_stat,
|
||||||
static_cast<off_t>(offset + 1)) != 0)
|
static_cast<off_t>(next_offset)) != 0)
|
||||||
#endif // FUSE_USE_VERSION >= 30
|
#endif // FUSE_USE_VERSION >= 30
|
||||||
{
|
{
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
|
@ -374,13 +374,13 @@ auto fuse_base::init_impl(struct fuse_conn_info *conn) -> void * {
|
|||||||
if (not utils::file::change_to_process_directory()) {
|
if (not utils::file::change_to_process_directory()) {
|
||||||
utils::error::raise_error(function_name,
|
utils::error::raise_error(function_name,
|
||||||
"failed to change to process directory");
|
"failed to change to process directory");
|
||||||
event_system::instance().raise<unmount_requested>();
|
event_system::instance().raise<unmount_requested>(function_name);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not console_enabled_ && not repertory::project_initialize()) {
|
if (not console_enabled_ && not repertory::project_initialize()) {
|
||||||
utils::error::raise_error(function_name, "failed to initialize repertory");
|
utils::error::raise_error(function_name, "failed to initialize repertory");
|
||||||
event_system::instance().raise<unmount_requested>();
|
event_system::instance().raise<unmount_requested>(function_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
@ -85,8 +85,8 @@ auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid,
|
|||||||
struct fuse_file_info * /*file_info*/)
|
struct fuse_file_info * /*file_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::chown_impl(std::string api_path, uid_t uid,
|
auto fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
|
||||||
gid_t gid) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
return check_and_perform(
|
return check_and_perform(
|
||||||
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
||||||
@ -464,7 +464,7 @@ auto fuse_drive::get_file_size(const std::string &api_path) const
|
|||||||
|
|
||||||
std::uint64_t file_size{};
|
std::uint64_t file_size{};
|
||||||
auto res = provider_.get_file_size(api_path, file_size);
|
auto res = provider_.get_file_size(api_path, file_size);
|
||||||
if (res == api_error::success) {
|
if (res != api_error::success) {
|
||||||
utils::error::raise_api_path_error(function_name, api_path, res,
|
utils::error::raise_api_path_error(function_name, api_path, res,
|
||||||
"failed to get file size from provider");
|
"failed to get file size from provider");
|
||||||
}
|
}
|
||||||
@ -494,8 +494,8 @@ auto fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st,
|
|||||||
struct fuse_file_info * /*file_info*/)
|
struct fuse_file_info * /*file_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::getattr_impl(std::string api_path,
|
auto fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st)
|
||||||
struct stat *unix_st) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
auto parent = utils::path::get_parent_api_path(api_path);
|
auto parent = utils::path::get_parent_api_path(api_path);
|
||||||
|
|
||||||
@ -561,8 +561,8 @@ auto fuse_drive::getxtimes_impl(std::string api_path, struct timespec *bkuptime,
|
|||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
auto fuse_drive::init_impl(struct fuse_conn_info *conn,
|
auto fuse_drive::init_impl(struct fuse_conn_info *conn, struct fuse_config *cfg)
|
||||||
struct fuse_config *cfg) -> void * {
|
-> void * {
|
||||||
#else
|
#else
|
||||||
void *fuse_drive::init_impl(struct fuse_conn_info *conn) {
|
void *fuse_drive::init_impl(struct fuse_conn_info *conn) {
|
||||||
#endif
|
#endif
|
||||||
@ -804,8 +804,9 @@ auto fuse_drive::release_impl(std::string /*api_path*/,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::releasedir_impl(
|
auto fuse_drive::releasedir_impl(std::string /*api_path*/,
|
||||||
std::string /*api_path*/, struct fuse_file_info *file_info) -> api_error {
|
struct fuse_file_info *file_info)
|
||||||
|
-> api_error {
|
||||||
auto iter = directory_cache_->get_directory(file_info->fh);
|
auto iter = directory_cache_->get_directory(file_info->fh);
|
||||||
if (iter == nullptr) {
|
if (iter == nullptr) {
|
||||||
return api_error::invalid_handle;
|
return api_error::invalid_handle;
|
||||||
@ -823,8 +824,8 @@ auto fuse_drive::rename_directory(const std::string &from_api_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::rename_file(const std::string &from_api_path,
|
auto fuse_drive::rename_file(const std::string &from_api_path,
|
||||||
const std::string &to_api_path,
|
const std::string &to_api_path, bool overwrite)
|
||||||
bool overwrite) -> int {
|
-> int {
|
||||||
auto res = fm_->rename_file(from_api_path, to_api_path, overwrite);
|
auto res = fm_->rename_file(from_api_path, to_api_path, overwrite);
|
||||||
errno = std::abs(utils::from_api_error(res));
|
errno = std::abs(utils::from_api_error(res));
|
||||||
return (res == api_error::success) ? 0 : -1;
|
return (res == api_error::success) ? 0 : -1;
|
||||||
@ -834,8 +835,8 @@ auto fuse_drive::rename_file(const std::string &from_api_path,
|
|||||||
auto fuse_drive::rename_impl(std::string from_api_path, std::string to_api_path,
|
auto fuse_drive::rename_impl(std::string from_api_path, std::string to_api_path,
|
||||||
unsigned int /*flags*/) -> api_error {
|
unsigned int /*flags*/) -> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::rename_impl(std::string from_api_path,
|
auto fuse_drive::rename_impl(std::string from_api_path, std::string to_api_path)
|
||||||
std::string to_api_path) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
auto res = check_parent_access(to_api_path, W_OK | X_OK);
|
auto res = check_parent_access(to_api_path, W_OK | X_OK);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
@ -937,15 +938,15 @@ auto fuse_drive::getxattr_impl(std::string api_path, const char *name,
|
|||||||
}
|
}
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
auto fuse_drive::getxattr_impl(std::string api_path, const char *name,
|
auto fuse_drive::getxattr_impl(std::string api_path, const char *name,
|
||||||
char *value, size_t size,
|
char *value, size_t size, int &attribute_size)
|
||||||
int &attribute_size) -> api_error {
|
-> api_error {
|
||||||
return getxattr_common(api_path, name, value, size, attribute_size, nullptr);
|
return getxattr_common(api_path, name, value, size, attribute_size, nullptr);
|
||||||
}
|
}
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
auto fuse_drive::listxattr_impl(std::string api_path, char *buffer, size_t size,
|
auto fuse_drive::listxattr_impl(std::string api_path, char *buffer, size_t size,
|
||||||
int &required_size,
|
int &required_size, bool &return_size)
|
||||||
bool &return_size) -> api_error {
|
-> api_error {
|
||||||
auto check_size = (size == 0);
|
auto check_size = (size == 0);
|
||||||
|
|
||||||
auto res = check_parent_access(api_path, X_OK);
|
auto res = check_parent_access(api_path, X_OK);
|
||||||
@ -985,8 +986,8 @@ auto fuse_drive::listxattr_impl(std::string api_path, char *buffer, size_t size,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::removexattr_impl(std::string api_path,
|
auto fuse_drive::removexattr_impl(std::string api_path, const char *name)
|
||||||
const char *name) -> api_error {
|
-> api_error {
|
||||||
std::string attribute_name;
|
std::string attribute_name;
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
auto res = parse_xattr_parameters(name, 0, attribute_name, api_path);
|
auto res = parse_xattr_parameters(name, 0, attribute_name, api_path);
|
||||||
@ -1014,8 +1015,8 @@ auto fuse_drive::setxattr_impl(std::string api_path, const char *name,
|
|||||||
uint32_t position) -> api_error {
|
uint32_t position) -> api_error {
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
auto fuse_drive::setxattr_impl(std::string api_path, const char *name,
|
auto fuse_drive::setxattr_impl(std::string api_path, const char *name,
|
||||||
const char *value, size_t size,
|
const char *value, size_t size, int flags)
|
||||||
int flags) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
std::string attribute_name;
|
std::string attribute_name;
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
@ -1086,15 +1087,27 @@ void fuse_drive::set_item_meta(const std::string &api_path,
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
auto res = provider_.set_item_meta(api_path, key, value);
|
auto res = provider_.set_item_meta(api_path, key, value);
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, api_path, res,
|
||||||
|
fmt::format("failed to set item meta|key|{}", key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fuse_drive::set_item_meta(const std::string &api_path,
|
||||||
|
const api_meta_map &meta) {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto res = provider_.set_item_meta(api_path, meta);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
utils::error::raise_api_path_error(function_name, api_path, res,
|
utils::error::raise_api_path_error(function_name, api_path, res,
|
||||||
"key|" + key + "|value|" + value);
|
"failed to set item meta");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
auto fuse_drive::setattr_x_impl(std::string api_path,
|
auto fuse_drive::setattr_x_impl(std::string api_path, struct setattr_x *attr)
|
||||||
struct setattr_x *attr) -> api_error {
|
-> api_error {
|
||||||
bool exists{};
|
bool exists{};
|
||||||
auto res = provider_.is_file(api_path, exists);
|
auto res = provider_.is_file(api_path, exists);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
@ -1148,7 +1161,7 @@ auto fuse_drive::setattr_x_impl(std::string api_path,
|
|||||||
ts[0].tv_sec = attr->acctime.tv_sec;
|
ts[0].tv_sec = attr->acctime.tv_sec;
|
||||||
ts[0].tv_nsec = attr->acctime.tv_nsec;
|
ts[0].tv_nsec = attr->acctime.tv_nsec;
|
||||||
} else {
|
} else {
|
||||||
struct timeval tv {};
|
struct timeval tv{};
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
ts[0].tv_sec = tv.tv_sec;
|
ts[0].tv_sec = tv.tv_sec;
|
||||||
ts[0].tv_nsec = tv.tv_usec * 1000;
|
ts[0].tv_nsec = tv.tv_usec * 1000;
|
||||||
@ -1193,8 +1206,9 @@ auto fuse_drive::setattr_x_impl(std::string api_path,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::setbkuptime_impl(
|
auto fuse_drive::setbkuptime_impl(std::string api_path,
|
||||||
std::string api_path, const struct timespec *bkuptime) -> api_error {
|
const struct timespec *bkuptime)
|
||||||
|
-> api_error {
|
||||||
return check_and_perform(
|
return check_and_perform(
|
||||||
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
api_path, X_OK, [&](api_meta_map &meta) -> api_error {
|
||||||
auto nanos = bkuptime->tv_nsec +
|
auto nanos = bkuptime->tv_nsec +
|
||||||
@ -1230,8 +1244,8 @@ auto fuse_drive::setvolname_impl(const char * /*volname*/) -> api_error {
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fuse_drive::statfs_x_impl(std::string /*api_path*/,
|
auto fuse_drive::statfs_x_impl(std::string /*api_path*/, struct statfs *stbuf)
|
||||||
struct statfs *stbuf) -> api_error {
|
-> api_error {
|
||||||
if (statfs(&config_.get_cache_directory()[0], stbuf) != 0) {
|
if (statfs(&config_.get_cache_directory()[0], stbuf) != 0) {
|
||||||
return api_error::os_error;
|
return api_error::os_error;
|
||||||
}
|
}
|
||||||
@ -1256,8 +1270,8 @@ auto fuse_drive::statfs_x_impl(std::string /*api_path*/,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
auto fuse_drive::statfs_impl(std::string /*api_path*/,
|
auto fuse_drive::statfs_impl(std::string /*api_path*/, struct statvfs *stbuf)
|
||||||
struct statvfs *stbuf) -> api_error {
|
-> api_error {
|
||||||
if (statvfs(config_.get_cache_directory().data(), stbuf) != 0) {
|
if (statvfs(config_.get_cache_directory().data(), stbuf) != 0) {
|
||||||
return api_error::os_error;
|
return api_error::os_error;
|
||||||
}
|
}
|
||||||
@ -1341,8 +1355,8 @@ auto fuse_drive::utimens_impl(std::string api_path, const struct timespec tv[2],
|
|||||||
struct fuse_file_info * /*file_info*/)
|
struct fuse_file_info * /*file_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto fuse_drive::utimens_impl(std::string api_path,
|
auto fuse_drive::utimens_impl(std::string api_path, const struct timespec tv[2])
|
||||||
const struct timespec tv[2]) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
api_meta_map meta;
|
api_meta_map meta;
|
||||||
auto res = provider_.get_item_meta(api_path, meta);
|
auto res = provider_.get_item_meta(api_path, meta);
|
||||||
|
@ -43,8 +43,8 @@
|
|||||||
#include "utils/utils.hpp"
|
#include "utils/utils.hpp"
|
||||||
|
|
||||||
namespace repertory::remote_fuse {
|
namespace repertory::remote_fuse {
|
||||||
auto remote_fuse_drive::access_impl(std::string api_path,
|
auto remote_fuse_drive::access_impl(std::string api_path, int mask)
|
||||||
int mask) -> api_error {
|
-> api_error {
|
||||||
return utils::to_api_error(
|
return utils::to_api_error(
|
||||||
remote_instance_->fuse_access(api_path.c_str(), mask));
|
remote_instance_->fuse_access(api_path.c_str(), mask));
|
||||||
}
|
}
|
||||||
@ -62,8 +62,8 @@ auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode,
|
|||||||
struct fuse_file_info * /*f_info*/)
|
struct fuse_file_info * /*f_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto remote_fuse_drive::chmod_impl(std::string api_path,
|
auto remote_fuse_drive::chmod_impl(std::string api_path, mode_t mode)
|
||||||
mode_t mode) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
return utils::to_api_error(remote_instance_->fuse_chmod(
|
return utils::to_api_error(remote_instance_->fuse_chmod(
|
||||||
api_path.c_str(), static_cast<remote::file_mode>(mode)));
|
api_path.c_str(), static_cast<remote::file_mode>(mode)));
|
||||||
@ -74,8 +74,8 @@ auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid,
|
|||||||
struct fuse_file_info * /*f_info*/)
|
struct fuse_file_info * /*f_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid,
|
auto remote_fuse_drive::chown_impl(std::string api_path, uid_t uid, gid_t gid)
|
||||||
gid_t gid) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
return utils::to_api_error(
|
return utils::to_api_error(
|
||||||
remote_instance_->fuse_chown(api_path.c_str(), uid, gid));
|
remote_instance_->fuse_chown(api_path.c_str(), uid, gid));
|
||||||
@ -94,7 +94,7 @@ void remote_fuse_drive::destroy_impl(void *ptr) {
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
event_system::instance().raise<drive_unmount_pending>(function_name,
|
event_system::instance().raise<drive_unmount_pending>(function_name,
|
||||||
get_mount_location());
|
get_mount_location());
|
||||||
|
|
||||||
if (server_) {
|
if (server_) {
|
||||||
server_->stop();
|
server_->stop();
|
||||||
@ -116,14 +116,15 @@ void remote_fuse_drive::destroy_impl(void *ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
event_system::instance().raise<drive_unmounted>(function_name,
|
event_system::instance().raise<drive_unmounted>(function_name,
|
||||||
get_mount_location());
|
get_mount_location());
|
||||||
|
|
||||||
fuse_base::destroy_impl(ptr);
|
fuse_base::destroy_impl(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_fuse_drive::fgetattr_impl(
|
auto remote_fuse_drive::fgetattr_impl(std::string api_path,
|
||||||
std::string api_path, struct stat *unix_st,
|
struct stat *unix_st,
|
||||||
struct fuse_file_info *f_info) -> api_error {
|
struct fuse_file_info *f_info)
|
||||||
|
-> api_error {
|
||||||
remote::stat r_stat{};
|
remote::stat r_stat{};
|
||||||
auto directory = false;
|
auto directory = false;
|
||||||
|
|
||||||
@ -184,8 +185,8 @@ auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st,
|
|||||||
struct fuse_file_info * /*f_info*/)
|
struct fuse_file_info * /*f_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto remote_fuse_drive::getattr_impl(std::string api_path,
|
auto remote_fuse_drive::getattr_impl(std::string api_path, struct stat *unix_st)
|
||||||
struct stat *unix_st) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
bool directory = false;
|
bool directory = false;
|
||||||
remote::stat r_stat{};
|
remote::stat r_stat{};
|
||||||
@ -258,19 +259,19 @@ auto remote_fuse_drive::init_impl(struct fuse_conn_info *conn) -> void * {
|
|||||||
if (remote_instance_->fuse_init() != 0) {
|
if (remote_instance_->fuse_init() != 0) {
|
||||||
utils::error::raise_error(function_name,
|
utils::error::raise_error(function_name,
|
||||||
"failed to connect to remote server");
|
"failed to connect to remote server");
|
||||||
event_system::instance().raise<unmount_requested>();
|
event_system::instance().raise<unmount_requested>(function_name);
|
||||||
} else {
|
} else {
|
||||||
server_ = std::make_shared<server>(config_);
|
server_ = std::make_shared<server>(config_);
|
||||||
server_->start();
|
server_->start();
|
||||||
event_system::instance().raise<drive_mounted>(function_name,
|
event_system::instance().raise<drive_mounted>(function_name,
|
||||||
get_mount_location());
|
get_mount_location());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_fuse_drive::mkdir_impl(std::string api_path,
|
auto remote_fuse_drive::mkdir_impl(std::string api_path, mode_t mode)
|
||||||
mode_t mode) -> api_error {
|
-> api_error {
|
||||||
return utils::to_api_error(remote_instance_->fuse_mkdir(
|
return utils::to_api_error(remote_instance_->fuse_mkdir(
|
||||||
api_path.c_str(), static_cast<remote::file_mode>(mode)));
|
api_path.c_str(), static_cast<remote::file_mode>(mode)));
|
||||||
}
|
}
|
||||||
@ -295,8 +296,9 @@ auto remote_fuse_drive::open_impl(std::string api_path,
|
|||||||
f_info->fh));
|
f_info->fh));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_fuse_drive::opendir_impl(
|
auto remote_fuse_drive::opendir_impl(std::string api_path,
|
||||||
std::string api_path, struct fuse_file_info *f_info) -> api_error {
|
struct fuse_file_info *f_info)
|
||||||
|
-> api_error {
|
||||||
if ((f_info->flags & O_APPEND) == O_APPEND ||
|
if ((f_info->flags & O_APPEND) == O_APPEND ||
|
||||||
(f_info->flags & O_EXCL) == O_EXCL) {
|
(f_info->flags & O_EXCL) == O_EXCL) {
|
||||||
return api_error::directory_exists;
|
return api_error::directory_exists;
|
||||||
@ -309,12 +311,14 @@ auto remote_fuse_drive::opendir_impl(
|
|||||||
void remote_fuse_drive::populate_stat(const remote::stat &r_stat,
|
void remote_fuse_drive::populate_stat(const remote::stat &r_stat,
|
||||||
bool directory, struct stat &unix_st) {
|
bool directory, struct stat &unix_st) {
|
||||||
std::memset(&unix_st, 0, sizeof(struct stat));
|
std::memset(&unix_st, 0, sizeof(struct stat));
|
||||||
unix_st.st_blksize = r_stat.st_blksize;
|
unix_st.st_blksize =
|
||||||
unix_st.st_blocks = static_cast<blkcnt_t>(r_stat.st_blocks);
|
static_cast<decltype(unix_st.st_blksize)>(r_stat.st_blksize);
|
||||||
|
unix_st.st_blocks =
|
||||||
|
static_cast<decltype(unix_st.st_blocks)>(r_stat.st_blocks);
|
||||||
unix_st.st_gid = r_stat.st_gid;
|
unix_st.st_gid = r_stat.st_gid;
|
||||||
unix_st.st_mode = (directory ? S_IFDIR : S_IFREG) | r_stat.st_mode;
|
unix_st.st_mode = (directory ? S_IFDIR : S_IFREG) | r_stat.st_mode;
|
||||||
unix_st.st_nlink = r_stat.st_nlink;
|
unix_st.st_nlink = r_stat.st_nlink;
|
||||||
unix_st.st_size = static_cast<off_t>(r_stat.st_size);
|
unix_st.st_size = static_cast<decltype(unix_st.st_size)>(r_stat.st_size);
|
||||||
unix_st.st_uid = r_stat.st_uid;
|
unix_st.st_uid = r_stat.st_uid;
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
@ -373,14 +377,18 @@ auto remote_fuse_drive::read_impl(std::string api_path, char *buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
auto remote_fuse_drive::readdir_impl(
|
auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
|
||||||
std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir,
|
fuse_fill_dir_t fuse_fill_dir,
|
||||||
off_t offset, struct fuse_file_info *f_info,
|
off_t offset,
|
||||||
fuse_readdir_flags /*flags*/) -> api_error {
|
struct fuse_file_info *f_info,
|
||||||
|
fuse_readdir_flags /*flags*/)
|
||||||
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto remote_fuse_drive::readdir_impl(
|
auto remote_fuse_drive::readdir_impl(std::string api_path, void *buf,
|
||||||
std::string api_path, void *buf, fuse_fill_dir_t fuse_fill_dir,
|
fuse_fill_dir_t fuse_fill_dir,
|
||||||
off_t offset, struct fuse_file_info *f_info) -> api_error {
|
off_t offset,
|
||||||
|
struct fuse_file_info *f_info)
|
||||||
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
std::string item_path;
|
std::string item_path;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
@ -408,14 +416,16 @@ auto remote_fuse_drive::readdir_impl(
|
|||||||
return utils::to_api_error(res);
|
return utils::to_api_error(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_fuse_drive::release_impl(
|
auto remote_fuse_drive::release_impl(std::string api_path,
|
||||||
std::string api_path, struct fuse_file_info *f_info) -> api_error {
|
struct fuse_file_info *f_info)
|
||||||
|
-> api_error {
|
||||||
return utils::to_api_error(
|
return utils::to_api_error(
|
||||||
remote_instance_->fuse_release(api_path.c_str(), f_info->fh));
|
remote_instance_->fuse_release(api_path.c_str(), f_info->fh));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_fuse_drive::releasedir_impl(
|
auto remote_fuse_drive::releasedir_impl(std::string api_path,
|
||||||
std::string api_path, struct fuse_file_info *f_info) -> api_error {
|
struct fuse_file_info *f_info)
|
||||||
|
-> api_error {
|
||||||
return utils::to_api_error(
|
return utils::to_api_error(
|
||||||
remote_instance_->fuse_releasedir(api_path.c_str(), f_info->fh));
|
remote_instance_->fuse_releasedir(api_path.c_str(), f_info->fh));
|
||||||
}
|
}
|
||||||
@ -512,8 +522,8 @@ api_error remote_fuse_drive::statfs_x_impl(std::string api_path,
|
|||||||
return utils::to_api_error(res);
|
return utils::to_api_error(res);
|
||||||
}
|
}
|
||||||
#else // __APPLE__
|
#else // __APPLE__
|
||||||
auto remote_fuse_drive::statfs_impl(std::string api_path,
|
auto remote_fuse_drive::statfs_impl(std::string api_path, struct statvfs *stbuf)
|
||||||
struct statvfs *stbuf) -> api_error {
|
-> api_error {
|
||||||
auto res = statvfs(config_.get_data_directory().c_str(), stbuf);
|
auto res = statvfs(config_.get_data_directory().c_str(), stbuf);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
remote::statfs r_stat{};
|
remote::statfs r_stat{};
|
||||||
@ -540,8 +550,8 @@ auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size,
|
|||||||
struct fuse_file_info * /*f_info*/)
|
struct fuse_file_info * /*f_info*/)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto remote_fuse_drive::truncate_impl(std::string api_path,
|
auto remote_fuse_drive::truncate_impl(std::string api_path, off_t size)
|
||||||
off_t size) -> api_error {
|
-> api_error {
|
||||||
#endif
|
#endif
|
||||||
return utils::to_api_error(remote_instance_->fuse_truncate(
|
return utils::to_api_error(remote_instance_->fuse_truncate(
|
||||||
api_path.c_str(), static_cast<remote::file_offset>(size)));
|
api_path.c_str(), static_cast<remote::file_offset>(size)));
|
||||||
@ -552,9 +562,10 @@ auto remote_fuse_drive::unlink_impl(std::string api_path) -> api_error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if FUSE_USE_VERSION >= 30
|
#if FUSE_USE_VERSION >= 30
|
||||||
auto remote_fuse_drive::utimens_impl(
|
auto remote_fuse_drive::utimens_impl(std::string api_path,
|
||||||
std::string api_path, const struct timespec tv[2],
|
const struct timespec tv[2],
|
||||||
struct fuse_file_info * /*f_info*/) -> api_error {
|
struct fuse_file_info * /*f_info*/)
|
||||||
|
-> api_error {
|
||||||
#else
|
#else
|
||||||
auto remote_fuse_drive::utimens_impl(std::string api_path,
|
auto remote_fuse_drive::utimens_impl(std::string api_path,
|
||||||
const struct timespec tv[2]) -> api_error {
|
const struct timespec tv[2]) -> api_error {
|
||||||
|
@ -82,18 +82,21 @@ auto remote_server::get_next_handle() -> std::uint64_t {
|
|||||||
auto remote_server::populate_file_info(const std::string &api_path,
|
auto remote_server::populate_file_info(const std::string &api_path,
|
||||||
remote::file_info &file_info)
|
remote::file_info &file_info)
|
||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
std::string meta_attributes;
|
std::string meta_attributes;
|
||||||
auto error = drive_.get_item_meta(api_path, META_ATTRIBUTES, meta_attributes);
|
auto directory = utils::file::directory(construct_path(api_path)).exists();
|
||||||
if (error == api_error::success) {
|
|
||||||
|
auto res = drive_.get_item_meta(api_path, META_ATTRIBUTES, meta_attributes);
|
||||||
|
if (res == api_error::success) {
|
||||||
if (meta_attributes.empty()) {
|
if (meta_attributes.empty()) {
|
||||||
meta_attributes =
|
meta_attributes = directory ? std::to_string(FILE_ATTRIBUTE_DIRECTORY)
|
||||||
utils::file::directory(construct_path(api_path)).exists()
|
: std::to_string(FILE_ATTRIBUTE_ARCHIVE);
|
||||||
? std::to_string(FILE_ATTRIBUTE_DIRECTORY)
|
|
||||||
: std::to_string(FILE_ATTRIBUTE_ARCHIVE);
|
|
||||||
drive_.set_item_meta(api_path, META_ATTRIBUTES, meta_attributes);
|
drive_.set_item_meta(api_path, META_ATTRIBUTES, meta_attributes);
|
||||||
}
|
}
|
||||||
const auto attributes = utils::string::to_uint32(meta_attributes);
|
|
||||||
const auto file_size = drive_.get_file_size(api_path);
|
auto attributes = utils::string::to_uint32(meta_attributes);
|
||||||
|
auto file_size = directory ? 0U : drive_.get_file_size(api_path);
|
||||||
populate_file_info(api_path, file_size, attributes, file_info);
|
populate_file_info(api_path, file_size, attributes, file_info);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -108,7 +111,7 @@ void remote_server::populate_file_info(const std::string &api_path,
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
api_meta_map meta{};
|
api_meta_map meta{};
|
||||||
const auto res = drive_.get_item_meta(api_path, meta);
|
auto res = drive_.get_item_meta(api_path, meta);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
utils::error::raise_api_path_error(function_name, api_path, res,
|
utils::error::raise_api_path_error(function_name, api_path, res,
|
||||||
"get item meta failed");
|
"get item meta failed");
|
||||||
@ -192,10 +195,10 @@ auto remote_server::fuse_access(const char *path, const std::int32_t &mask)
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(path);
|
auto api_path = utils::path::create_api_path(path);
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
const auto res = access(file_path.c_str(), mask);
|
auto res = access(file_path.c_str(), mask);
|
||||||
auto ret = ((res < 0) ? -errno : 0);
|
auto ret = ((res < 0) ? -errno : 0);
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
@ -205,8 +208,8 @@ auto remote_server::fuse_chflags(const char *path, std::uint32_t flags)
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(path);
|
auto api_path = utils::path::create_api_path(path);
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
auto ret = -EACCES;
|
auto ret = -EACCES;
|
||||||
if (drive_.check_parent_access(api_path, X_OK) == api_error::success) {
|
if (drive_.check_parent_access(api_path, X_OK) == api_error::success) {
|
||||||
@ -225,8 +228,8 @@ auto remote_server::fuse_chmod(const char *path, const remote::file_mode &mode)
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
const auto res = chmod(file_path.c_str(), mode);
|
auto res = chmod(file_path.c_str(), mode);
|
||||||
auto ret = ((res < 0) ? -errno : 0);
|
auto ret = ((res < 0) ? -errno : 0);
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
@ -237,8 +240,8 @@ auto remote_server::fuse_chown(const char *path, const remote::user_id &uid,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
const auto res = chown(file_path.c_str(), uid, gid);
|
auto res = chown(file_path.c_str(), uid, gid);
|
||||||
auto ret = ((res < 0) ? -errno : 0);
|
auto ret = ((res < 0) ? -errno : 0);
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
@ -250,10 +253,9 @@ auto remote_server::fuse_create(const char *path, const remote::file_mode &mode,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
const auto res =
|
auto res = open(file_path.c_str(),
|
||||||
open(file_path.c_str(),
|
static_cast<int>(remote::create_os_open_flags(flags)), mode);
|
||||||
static_cast<int>(remote::create_os_open_flags(flags)), mode);
|
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
handle = static_cast<remote::file_handle>(res);
|
handle = static_cast<remote::file_handle>(res);
|
||||||
set_open_info(res, open_info{
|
set_open_info(res, open_info{
|
||||||
@ -322,7 +324,7 @@ auto remote_server::fuse_fgetattr(const char *path, remote::stat &r_stat,
|
|||||||
|
|
||||||
r_stat = {};
|
r_stat = {};
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
auto res = has_open_info(static_cast<native_handle>(handle), EBADF);
|
auto res = has_open_info(static_cast<native_handle>(handle), EBADF);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@ -345,8 +347,8 @@ auto remote_server::fuse_fsetattr_x(const char *path,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(path);
|
auto api_path = utils::path::create_api_path(path);
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
auto res = 0;
|
auto res = 0;
|
||||||
if (SETATTR_WANTS_MODE(&attr)) {
|
if (SETATTR_WANTS_MODE(&attr)) {
|
||||||
@ -440,7 +442,7 @@ auto remote_server::fuse_fsync(const char *path, const std::int32_t &datasync,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
auto res = has_open_info(static_cast<native_handle>(handle), EBADF);
|
auto res = has_open_info(static_cast<native_handle>(handle), EBADF);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@ -464,7 +466,7 @@ auto remote_server::fuse_ftruncate(const char *path,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
auto res = has_open_info(static_cast<native_handle>(handle), EBADF);
|
auto res = has_open_info(static_cast<native_handle>(handle), EBADF);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@ -481,9 +483,9 @@ auto remote_server::fuse_getattr(const char *path, remote::stat &r_stat,
|
|||||||
bool &directory) -> packet::error_type {
|
bool &directory) -> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(path);
|
auto api_path = utils::path::create_api_path(path);
|
||||||
const auto file_path = construct_path(api_path);
|
auto file_path = construct_path(api_path);
|
||||||
const auto parent_api_path = utils::path::get_parent_api_path(api_path);
|
auto parent_api_path = utils::path::get_parent_api_path(api_path);
|
||||||
|
|
||||||
r_stat = {};
|
r_stat = {};
|
||||||
|
|
||||||
@ -560,8 +562,8 @@ auto remote_server::fuse_getxtimes(const char *path,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(path);
|
auto api_path = utils::path::create_api_path(path);
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
auto ret = -EACCES;
|
auto ret = -EACCES;
|
||||||
if (drive_.check_parent_access(api_path, X_OK) == api_error::success) {
|
if (drive_.check_parent_access(api_path, X_OK) == api_error::success) {
|
||||||
@ -608,8 +610,8 @@ auto remote_server::fuse_mkdir(const char *path, const remote::file_mode &mode)
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
const auto res = mkdir(file_path.c_str(), mode);
|
auto res = mkdir(file_path.c_str(), mode);
|
||||||
auto ret = ((res < 0) ? -errno : 0);
|
auto ret = ((res < 0) ? -errno : 0);
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
@ -620,9 +622,9 @@ auto remote_server::fuse_open(const char *path, const remote::open_flags &flags,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
const auto res = open(file_path.c_str(),
|
auto res = open(file_path.c_str(),
|
||||||
static_cast<int>(remote::create_os_open_flags(flags)));
|
static_cast<int>(remote::create_os_open_flags(flags)));
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
handle = static_cast<remote::file_handle>(res);
|
handle = static_cast<remote::file_handle>(res);
|
||||||
set_open_info(res, open_info{
|
set_open_info(res, open_info{
|
||||||
@ -641,7 +643,7 @@ auto remote_server::fuse_opendir(const char *path, remote::file_handle &handle)
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
auto res = -1;
|
auto res = -1;
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
@ -669,7 +671,7 @@ auto remote_server::fuse_read(const char *path, char *buffer,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
auto &data = *reinterpret_cast<data_buffer *>(buffer);
|
auto &data = *reinterpret_cast<data_buffer *>(buffer);
|
||||||
|
|
||||||
ssize_t bytes_read{has_open_info(static_cast<native_handle>(handle), EBADF)};
|
ssize_t bytes_read{has_open_info(static_cast<native_handle>(handle), EBADF)};
|
||||||
@ -691,9 +693,9 @@ auto remote_server::fuse_rename(const char *from, const char *to)
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto from_path = utils::path::combine(mount_location_, {from});
|
auto from_path = utils::path::combine(mount_location_, {from});
|
||||||
const auto to_path = utils::path::combine(mount_location_, {to});
|
auto to_path = utils::path::combine(mount_location_, {to});
|
||||||
const auto res = rename(from_path.c_str(), to_path.c_str());
|
auto res = rename(from_path.c_str(), to_path.c_str());
|
||||||
auto ret = ((res < 0) ? -errno : 0);
|
auto ret = ((res < 0) ? -errno : 0);
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, from + std::string("|") + to,
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, from + std::string("|") + to,
|
||||||
ret);
|
ret);
|
||||||
@ -706,7 +708,7 @@ auto remote_server::fuse_readdir(const char *path,
|
|||||||
std::string &item_path) -> packet::error_type {
|
std::string &item_path) -> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
auto res = 0;
|
auto res = 0;
|
||||||
if (offset > std::numeric_limits<std::size_t>::max()) {
|
if (offset > std::numeric_limits<std::size_t>::max()) {
|
||||||
errno = ERANGE;
|
errno = ERANGE;
|
||||||
@ -733,7 +735,7 @@ auto remote_server::fuse_release(const char *path,
|
|||||||
|
|
||||||
packet::error_type ret = 0;
|
packet::error_type ret = 0;
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
auto res = has_open_info(static_cast<native_handle>(handle), EBADF);
|
auto res = has_open_info(static_cast<native_handle>(handle), EBADF);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
res = close(static_cast<native_handle>(handle));
|
res = close(static_cast<native_handle>(handle));
|
||||||
@ -750,7 +752,7 @@ auto remote_server::fuse_releasedir(const char *path,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
directory_cache_.remove_directory(handle);
|
directory_cache_.remove_directory(handle);
|
||||||
|
|
||||||
@ -771,8 +773,8 @@ removexattr(file_path.c_str(), name); #endif auto ret = ((res < 0) ? -errno :
|
|||||||
auto remote_server::fuse_rmdir(const char *path) -> packet::error_type {
|
auto remote_server::fuse_rmdir(const char *path) -> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
const auto res = rmdir(file_path.c_str());
|
auto res = rmdir(file_path.c_str());
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
directory_cache_.remove_directory(utils::path::create_api_path(path));
|
directory_cache_.remove_directory(utils::path::create_api_path(path));
|
||||||
}
|
}
|
||||||
@ -785,7 +787,7 @@ auto remote_server::fuse_setattr_x(const char *path, remote::setattr_x &attr)
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
auto ret = fuse_fsetattr_x(
|
auto ret = fuse_fsetattr_x(
|
||||||
path, attr, static_cast<remote::file_handle>(REPERTORY_INVALID_HANDLE));
|
path, attr, static_cast<remote::file_handle>(REPERTORY_INVALID_HANDLE));
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
||||||
@ -797,8 +799,8 @@ auto remote_server::fuse_setbkuptime(const char *path,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(path);
|
auto api_path = utils::path::create_api_path(path);
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
auto ret = -EACCES;
|
auto ret = -EACCES;
|
||||||
if (drive_.check_parent_access(api_path, X_OK) == api_error::success) {
|
if (drive_.check_parent_access(api_path, X_OK) == api_error::success) {
|
||||||
@ -818,8 +820,8 @@ auto remote_server::fuse_setchgtime(const char *path,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(path);
|
auto api_path = utils::path::create_api_path(path);
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
auto ret = -EACCES;
|
auto ret = -EACCES;
|
||||||
if (drive_.check_parent_access(api_path, X_OK) == api_error::success) {
|
if (drive_.check_parent_access(api_path, X_OK) == api_error::success) {
|
||||||
@ -839,8 +841,8 @@ auto remote_server::fuse_setcrtime(const char *path,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(path);
|
auto api_path = utils::path::create_api_path(path);
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
auto ret = -EACCES;
|
auto ret = -EACCES;
|
||||||
if (drive_.check_parent_access(api_path, X_OK) == api_error::success) {
|
if (drive_.check_parent_access(api_path, X_OK) == api_error::success) {
|
||||||
@ -886,11 +888,11 @@ auto remote_server::fuse_statfs(const char *path, std::uint64_t frsize,
|
|||||||
remote::statfs &r_stat) -> packet::error_type {
|
remote::statfs &r_stat) -> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
const auto total_bytes = drive_.get_total_drive_space();
|
auto total_bytes = drive_.get_total_drive_space();
|
||||||
const auto total_used = drive_.get_used_drive_space();
|
auto total_used = drive_.get_used_drive_space();
|
||||||
const auto used_blocks = utils::divide_with_ceiling(total_used, frsize);
|
auto used_blocks = utils::divide_with_ceiling(total_used, frsize);
|
||||||
r_stat.f_files = 4294967295;
|
r_stat.f_files = 4294967295;
|
||||||
r_stat.f_blocks = utils::divide_with_ceiling(total_bytes, frsize);
|
r_stat.f_blocks = utils::divide_with_ceiling(total_bytes, frsize);
|
||||||
r_stat.f_bavail = r_stat.f_bfree =
|
r_stat.f_bavail = r_stat.f_bfree =
|
||||||
@ -907,11 +909,11 @@ auto remote_server::fuse_statfs_x(const char *path, std::uint64_t bsize,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
const auto total_bytes = drive_.get_total_drive_space();
|
auto total_bytes = drive_.get_total_drive_space();
|
||||||
const auto total_used = drive_.get_used_drive_space();
|
auto total_used = drive_.get_used_drive_space();
|
||||||
const auto used_blocks = utils::divide_with_ceiling(total_used, bsize);
|
auto used_blocks = utils::divide_with_ceiling(total_used, bsize);
|
||||||
r_stat.f_files = 4294967295;
|
r_stat.f_files = 4294967295;
|
||||||
r_stat.f_blocks = utils::divide_with_ceiling(total_bytes, bsize);
|
r_stat.f_blocks = utils::divide_with_ceiling(total_bytes, bsize);
|
||||||
r_stat.f_bavail = r_stat.f_bfree =
|
r_stat.f_bavail = r_stat.f_bfree =
|
||||||
@ -932,8 +934,8 @@ auto remote_server::fuse_truncate(const char *path,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
const auto res = truncate(file_path.c_str(), static_cast<off_t>(size));
|
auto res = truncate(file_path.c_str(), static_cast<off_t>(size));
|
||||||
auto ret = ((res < 0) ? -errno : 0);
|
auto ret = ((res < 0) ? -errno : 0);
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
@ -942,8 +944,8 @@ auto remote_server::fuse_truncate(const char *path,
|
|||||||
auto remote_server::fuse_unlink(const char *path) -> packet::error_type {
|
auto remote_server::fuse_unlink(const char *path) -> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
const auto res = unlink(file_path.c_str());
|
auto res = unlink(file_path.c_str());
|
||||||
auto ret = ((res < 0) ? -errno : 0);
|
auto ret = ((res < 0) ? -errno : 0);
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
@ -954,7 +956,7 @@ auto remote_server::fuse_utimens(const char *path, const remote::file_time *tv,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
struct timespec tv2[2] = {{0, 0}};
|
struct timespec tv2[2] = {{0, 0}};
|
||||||
const auto process_timespec = [](auto op, const auto &src, auto &dst) {
|
const auto process_timespec = [](auto op, const auto &src, auto &dst) {
|
||||||
@ -971,8 +973,7 @@ auto remote_server::fuse_utimens(const char *path, const remote::file_time *tv,
|
|||||||
process_timespec(op0, tv[0U], tv2[0U]);
|
process_timespec(op0, tv[0U], tv2[0U]);
|
||||||
process_timespec(op1, tv[1U], tv2[1U]);
|
process_timespec(op1, tv[1U], tv2[1U]);
|
||||||
|
|
||||||
const auto res =
|
auto res = utimensat(0, file_path.c_str(), &tv2[0U], AT_SYMLINK_NOFOLLOW);
|
||||||
utimensat(0, file_path.c_str(), &tv2[0U], AT_SYMLINK_NOFOLLOW);
|
|
||||||
auto ret = ((res < 0) ? -errno : 0);
|
auto ret = ((res < 0) ? -errno : 0);
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
@ -985,7 +986,7 @@ auto remote_server::fuse_write(const char *path, const char *buffer,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
|
|
||||||
ssize_t bytes_written{
|
ssize_t bytes_written{
|
||||||
has_open_info(static_cast<native_handle>(handle), EBADF)};
|
has_open_info(static_cast<native_handle>(handle), EBADF)};
|
||||||
@ -1016,8 +1017,8 @@ auto remote_server::winfsp_can_delete(PVOID file_desc, PWSTR file_name)
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto relative_path = utils::string::to_utf8(file_name);
|
auto relative_path = utils::string::to_utf8(file_name);
|
||||||
const auto file_path = construct_path(relative_path);
|
auto file_path = construct_path(relative_path);
|
||||||
auto ret = static_cast<packet::error_type>(
|
auto ret = static_cast<packet::error_type>(
|
||||||
has_open_info(static_cast<native_handle>(
|
has_open_info(static_cast<native_handle>(
|
||||||
reinterpret_cast<remote::file_handle>(file_desc)),
|
reinterpret_cast<remote::file_handle>(file_desc)),
|
||||||
@ -1026,13 +1027,12 @@ auto remote_server::winfsp_can_delete(PVOID file_desc, PWSTR file_name)
|
|||||||
ret = static_cast<packet::error_type>(
|
ret = static_cast<packet::error_type>(
|
||||||
utils::file::directory(file_path).exists()
|
utils::file::directory(file_path).exists()
|
||||||
? drive_.get_directory_item_count(
|
? drive_.get_directory_item_count(
|
||||||
utils::path::create_api_path(relative_path))
|
utils::path::create_api_path(relative_path)) == 0U
|
||||||
? STATUS_DIRECTORY_NOT_EMPTY
|
? STATUS_SUCCESS
|
||||||
: STATUS_SUCCESS
|
: STATUS_DIRECTORY_NOT_EMPTY
|
||||||
|
|
||||||
: STATUS_SUCCESS);
|
: STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1042,22 +1042,25 @@ auto remote_server::winfsp_cleanup(PVOID /*file_desc*/, PWSTR file_name,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto relative_path = utils::string::to_utf8(file_name);
|
auto relative_path = utils::string::to_utf8(file_name);
|
||||||
const auto file_path = construct_path(relative_path);
|
auto file_path = construct_path(relative_path);
|
||||||
was_deleted = 0U;
|
was_deleted = 0U;
|
||||||
|
|
||||||
const auto directory = utils::file::directory(file_path).exists();
|
auto directory = utils::file::directory(file_path).exists();
|
||||||
if (flags & FileSystemBase::FspCleanupDelete) {
|
if (flags & FileSystemBase::FspCleanupDelete) {
|
||||||
remove_all(file_path);
|
remove_all(file_path);
|
||||||
was_deleted = 1U;
|
was_deleted = 1U;
|
||||||
|
|
||||||
if (directory) {
|
if (directory) {
|
||||||
rmdir(file_path.c_str());
|
if (drive_.get_directory_item_count(
|
||||||
|
utils::path::create_api_path(relative_path)) == 0U) {
|
||||||
|
rmdir(file_path.c_str());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unlink(file_path.c_str());
|
unlink(file_path.c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const auto api_path = utils::path::create_api_path(relative_path);
|
auto api_path = utils::path::create_api_path(relative_path);
|
||||||
if ((flags & FileSystemBase::FspCleanupSetArchiveBit) && not directory) {
|
if ((flags & FileSystemBase::FspCleanupSetArchiveBit) && not directory) {
|
||||||
api_meta_map meta;
|
api_meta_map meta;
|
||||||
if (drive_.get_item_meta(api_path, meta) == api_error::success) {
|
if (drive_.get_item_meta(api_path, meta) == api_error::success) {
|
||||||
@ -1071,7 +1074,7 @@ auto remote_server::winfsp_cleanup(PVOID /*file_desc*/, PWSTR file_name,
|
|||||||
if (flags & (FileSystemBase::FspCleanupSetLastAccessTime |
|
if (flags & (FileSystemBase::FspCleanupSetLastAccessTime |
|
||||||
FileSystemBase::FspCleanupSetLastWriteTime |
|
FileSystemBase::FspCleanupSetLastWriteTime |
|
||||||
FileSystemBase::FspCleanupSetChangeTime)) {
|
FileSystemBase::FspCleanupSetChangeTime)) {
|
||||||
const auto file_time_now = utils::time::get_time_now();
|
auto file_time_now = utils::time::get_time_now();
|
||||||
if (flags & FileSystemBase::FspCleanupSetLastAccessTime) {
|
if (flags & FileSystemBase::FspCleanupSetLastAccessTime) {
|
||||||
drive_.set_item_meta(api_path, META_ACCESSED,
|
drive_.set_item_meta(api_path, META_ACCESSED,
|
||||||
std::to_string(file_time_now));
|
std::to_string(file_time_now));
|
||||||
@ -1100,7 +1103,7 @@ auto remote_server::winfsp_close(PVOID file_desc) -> packet::error_type {
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
std::string file_path;
|
std::string file_path;
|
||||||
const auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
||||||
if (has_open_info(static_cast<native_handle>(handle),
|
if (has_open_info(static_cast<native_handle>(handle),
|
||||||
STATUS_INVALID_HANDLE) == STATUS_SUCCESS) {
|
STATUS_INVALID_HANDLE) == STATUS_SUCCESS) {
|
||||||
file_path = get_open_file_path(static_cast<native_handle>(handle));
|
file_path = get_open_file_path(static_cast<native_handle>(handle));
|
||||||
@ -1120,49 +1123,55 @@ auto remote_server::winfsp_create(PWSTR file_name, UINT32 create_options,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto relative_path = utils::string::to_utf8(file_name);
|
auto relative_path = utils::string::to_utf8(file_name);
|
||||||
const auto file_path = construct_path(relative_path);
|
auto file_path = construct_path(relative_path);
|
||||||
exists = utils::file::file(file_path).exists();
|
exists = utils::file::file{file_path}.exists() ||
|
||||||
|
utils::file::directory{file_path}.exists()
|
||||||
if ((create_options & FILE_DIRECTORY_FILE) != 0U) {
|
? 1
|
||||||
attributes |= FILE_ATTRIBUTE_DIRECTORY;
|
: 0;
|
||||||
} else {
|
auto ret{static_cast<packet::error_type>(STATUS_SUCCESS)};
|
||||||
attributes &= static_cast<UINT32>(~FILE_ATTRIBUTE_DIRECTORY);
|
if (exists == 0U) {
|
||||||
attributes |= FILE_ATTRIBUTE_ARCHIVE;
|
if ((create_options & FILE_DIRECTORY_FILE) != 0U) {
|
||||||
}
|
attributes |= FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
} else {
|
||||||
remote::file_mode mode{0U};
|
attributes &= static_cast<UINT32>(~FILE_ATTRIBUTE_DIRECTORY);
|
||||||
std::uint32_t flags{0U};
|
attributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||||
utils::windows_create_to_unix(create_options, granted_access, flags, mode);
|
|
||||||
|
|
||||||
int res = 0;
|
|
||||||
if ((create_options & FILE_DIRECTORY_FILE) != 0U) {
|
|
||||||
res = mkdir(file_path.c_str(), mode);
|
|
||||||
if (res >= 0) {
|
|
||||||
res = open(file_path.c_str(), static_cast<int>(flags));
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
res = open(file_path.c_str(), static_cast<int>(flags), mode);
|
remote::file_mode mode{0U};
|
||||||
|
std::uint32_t flags{0U};
|
||||||
|
utils::windows_create_to_unix(create_options, granted_access, flags, mode);
|
||||||
|
|
||||||
|
auto res{0};
|
||||||
|
if ((create_options & FILE_DIRECTORY_FILE) != 0U) {
|
||||||
|
res = mkdir(file_path.c_str(), mode);
|
||||||
|
if (res >= 0) {
|
||||||
|
res = open(file_path.c_str(), static_cast<int>(flags));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = open(file_path.c_str(), static_cast<int>(flags), mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res >= 0) {
|
||||||
|
*file_desc = reinterpret_cast<PVOID>(res);
|
||||||
|
drive_.set_item_meta(construct_api_path(file_path), META_ATTRIBUTES,
|
||||||
|
std::to_string(attributes));
|
||||||
|
set_open_info(res, open_info{
|
||||||
|
"",
|
||||||
|
nullptr,
|
||||||
|
{},
|
||||||
|
file_path,
|
||||||
|
});
|
||||||
|
|
||||||
|
auto api_path = utils::path::create_api_path(relative_path);
|
||||||
|
normalized_name = utils::string::replace_copy(api_path, '/', '\\');
|
||||||
|
populate_file_info(api_path, 0, attributes, *file_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = static_cast<packet::error_type>(
|
||||||
|
utils::unix_error_to_windows((res < 0) ? errno : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res >= 0) {
|
|
||||||
*file_desc = reinterpret_cast<PVOID>(res);
|
|
||||||
drive_.set_item_meta(construct_api_path(file_path), META_ATTRIBUTES,
|
|
||||||
std::to_string(attributes));
|
|
||||||
set_open_info(res, open_info{
|
|
||||||
"",
|
|
||||||
nullptr,
|
|
||||||
{},
|
|
||||||
file_path,
|
|
||||||
});
|
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(relative_path);
|
|
||||||
normalized_name = utils::string::replace_copy(api_path, '/', '\\');
|
|
||||||
populate_file_info(api_path, 0, attributes, *file_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ret = static_cast<packet::error_type>(
|
|
||||||
utils::unix_error_to_windows((res < 0) ? errno : 0));
|
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1171,7 +1180,7 @@ auto remote_server::winfsp_flush(PVOID file_desc, remote::file_info *file_info)
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
||||||
auto ret = static_cast<packet::error_type>(
|
auto ret = static_cast<packet::error_type>(
|
||||||
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
@ -1194,7 +1203,7 @@ auto remote_server::winfsp_get_file_info(PVOID file_desc,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
||||||
auto ret = static_cast<packet::error_type>(
|
auto ret = static_cast<packet::error_type>(
|
||||||
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
@ -1216,7 +1225,7 @@ auto remote_server::winfsp_get_security_by_name(
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
auto ret = static_cast<packet::error_type>(STATUS_SUCCESS);
|
auto ret = static_cast<packet::error_type>(STATUS_SUCCESS);
|
||||||
const auto file_path = construct_path(file_name);
|
auto file_path = construct_path(file_name);
|
||||||
if (utils::file::file(file_path).exists() ||
|
if (utils::file::file(file_path).exists() ||
|
||||||
(utils::file::directory(file_path).exists())) {
|
(utils::file::directory(file_path).exists())) {
|
||||||
if (attributes) {
|
if (attributes) {
|
||||||
@ -1261,9 +1270,9 @@ auto remote_server::winfsp_open(PWSTR file_name, UINT32 create_options,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto relative_path = utils::string::to_utf8(file_name);
|
auto relative_path = utils::string::to_utf8(file_name);
|
||||||
const auto file_path = construct_path(relative_path);
|
auto file_path = construct_path(relative_path);
|
||||||
const auto directory = utils::file::directory(file_path).exists();
|
auto directory = utils::file::directory(file_path).exists();
|
||||||
if (directory) {
|
if (directory) {
|
||||||
create_options |= FILE_DIRECTORY_FILE;
|
create_options |= FILE_DIRECTORY_FILE;
|
||||||
}
|
}
|
||||||
@ -1283,7 +1292,7 @@ auto remote_server::winfsp_open(PWSTR file_name, UINT32 create_options,
|
|||||||
file_path,
|
file_path,
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(relative_path);
|
auto api_path = utils::path::create_api_path(relative_path);
|
||||||
normalized_name = utils::string::replace_copy(api_path, '/', '\\');
|
normalized_name = utils::string::replace_copy(api_path, '/', '\\');
|
||||||
res = populate_file_info(api_path, *file_info);
|
res = populate_file_info(api_path, *file_info);
|
||||||
if (res != STATUS_SUCCESS) {
|
if (res != STATUS_SUCCESS) {
|
||||||
@ -1306,20 +1315,20 @@ auto remote_server::winfsp_overwrite(PVOID file_desc, UINT32 attributes,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
||||||
auto ret = static_cast<packet::error_type>(
|
auto ret = static_cast<packet::error_type>(
|
||||||
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
const auto api_path = construct_api_path(
|
auto api_path = construct_api_path(
|
||||||
get_open_file_path(static_cast<native_handle>(handle)));
|
get_open_file_path(static_cast<native_handle>(handle)));
|
||||||
const auto res = ftruncate(static_cast<native_handle>(handle), 0);
|
auto res = ftruncate(static_cast<native_handle>(handle), 0);
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
auto set_attributes = false;
|
auto set_attributes = false;
|
||||||
if (replace_attributes) {
|
if (replace_attributes) {
|
||||||
set_attributes = true;
|
set_attributes = true;
|
||||||
} else if (attributes) {
|
} else if (attributes) {
|
||||||
std::string current_attributes;
|
std::string current_attributes;
|
||||||
const auto err =
|
auto err =
|
||||||
drive_.get_item_meta(api_path, META_ATTRIBUTES, current_attributes);
|
drive_.get_item_meta(api_path, META_ATTRIBUTES, current_attributes);
|
||||||
if (err != api_error::success) {
|
if (err != api_error::success) {
|
||||||
utils::error::raise_api_path_error(function_name, api_path, err,
|
utils::error::raise_api_path_error(function_name, api_path, err,
|
||||||
@ -1361,16 +1370,19 @@ auto remote_server::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
*bytes_transferred = 0;
|
*bytes_transferred = 0U;
|
||||||
|
|
||||||
const auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
||||||
auto ret = static_cast<packet::error_type>(
|
auto ret = static_cast<packet::error_type>(
|
||||||
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
const auto res = pread64(static_cast<native_handle>(handle), buffer, length,
|
auto res = pread64(static_cast<native_handle>(handle), buffer, length,
|
||||||
static_cast<off_t>(offset));
|
static_cast<off_t>(offset));
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
*bytes_transferred = static_cast<UINT32>(res);
|
*bytes_transferred = static_cast<UINT32>(res);
|
||||||
|
if (*bytes_transferred == 0U) {
|
||||||
|
ret = static_cast<packet::error_type>(STATUS_END_OF_FILE);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ret =
|
ret =
|
||||||
static_cast<packet::error_type>(utils::unix_error_to_windows(errno));
|
static_cast<packet::error_type>(utils::unix_error_to_windows(errno));
|
||||||
@ -1390,11 +1402,11 @@ auto remote_server::winfsp_read_directory(PVOID file_desc, PWSTR /*pattern*/,
|
|||||||
|
|
||||||
item_list.clear();
|
item_list.clear();
|
||||||
|
|
||||||
const auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
||||||
auto ret = static_cast<packet::error_type>(
|
auto ret = static_cast<packet::error_type>(
|
||||||
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
const auto api_path = construct_api_path(
|
auto api_path = construct_api_path(
|
||||||
get_open_file_path(static_cast<native_handle>(handle)));
|
get_open_file_path(static_cast<native_handle>(handle)));
|
||||||
directory_iterator iterator(drive_.get_directory_items(api_path));
|
directory_iterator iterator(drive_.get_directory_items(api_path));
|
||||||
auto offset = marker == nullptr
|
auto offset = marker == nullptr
|
||||||
@ -1405,7 +1417,7 @@ auto remote_server::winfsp_read_directory(PVOID file_desc, PWSTR /*pattern*/,
|
|||||||
json item;
|
json item;
|
||||||
while (iterator.get_json(offset++, item) == 0) {
|
while (iterator.get_json(offset++, item) == 0) {
|
||||||
try {
|
try {
|
||||||
item_list.emplace_back(update_to_windows_format(item));
|
item_list.emplace_back(update_to_windows_format(api_path, item));
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
utils::error::raise_error(function_name, e, "exception occurred");
|
utils::error::raise_error(function_name, e, "exception occurred");
|
||||||
}
|
}
|
||||||
@ -1425,25 +1437,40 @@ auto remote_server::winfsp_rename(PVOID /*file_desc*/, PWSTR file_name,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto relative_path = utils::string::to_utf8(file_name);
|
auto relative_path = utils::string::to_utf8(file_name);
|
||||||
const auto file_path = construct_path(relative_path);
|
auto file_path = construct_path(relative_path);
|
||||||
const auto new_relative_path = utils::string::to_utf8(new_file_name);
|
auto new_relative_path = utils::string::to_utf8(new_file_name);
|
||||||
const auto new_file_path = construct_path(new_relative_path);
|
auto new_file_path = construct_path(new_relative_path);
|
||||||
|
|
||||||
auto res = -1;
|
packet::error_type ret{};
|
||||||
|
auto res{-1};
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
if (utils::file::file(file_path).exists()) {
|
if (utils::file::file(file_path).exists()) {
|
||||||
res = drive_.rename_file(construct_api_path(file_path),
|
res = drive_.rename_file(construct_api_path(file_path),
|
||||||
construct_api_path(new_file_path),
|
construct_api_path(new_file_path),
|
||||||
replace_if_exists != 0U);
|
replace_if_exists != 0U);
|
||||||
} else if (utils::file::directory(file_path).exists()) {
|
ret = ((res < 0) ? static_cast<packet::error_type>(
|
||||||
res = drive_.rename_directory(construct_api_path(file_path),
|
utils::unix_error_to_windows(errno))
|
||||||
construct_api_path(new_file_path));
|
: 0);
|
||||||
|
} else {
|
||||||
|
auto dir{utils::file::directory(file_path)};
|
||||||
|
if (dir.exists()) {
|
||||||
|
auto count{dir.count(false)};
|
||||||
|
if (count == 0U) {
|
||||||
|
res = drive_.rename_directory(construct_api_path(file_path),
|
||||||
|
construct_api_path(new_file_path));
|
||||||
|
ret = ((res < 0)
|
||||||
|
? errno == EISDIR
|
||||||
|
? static_cast<packet::error_type>(STATUS_ACCESS_DENIED)
|
||||||
|
: static_cast<packet::error_type>(
|
||||||
|
utils::unix_error_to_windows(errno))
|
||||||
|
: 0);
|
||||||
|
} else {
|
||||||
|
ret = static_cast<packet::error_type>(STATUS_ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ret = ((res < 0) ? static_cast<packet::error_type>(
|
|
||||||
utils::unix_error_to_windows(errno))
|
|
||||||
: 0);
|
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path + "|" + new_file_path,
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path + "|" + new_file_path,
|
||||||
ret);
|
ret);
|
||||||
return ret;
|
return ret;
|
||||||
@ -1455,12 +1482,11 @@ auto remote_server::winfsp_set_basic_info(
|
|||||||
remote::file_info *file_info) -> packet::error_type {
|
remote::file_info *file_info) -> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
||||||
auto ret = static_cast<packet::error_type>(
|
auto ret = static_cast<packet::error_type>(
|
||||||
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
const auto file_path =
|
auto file_path = get_open_file_path(static_cast<native_handle>(handle));
|
||||||
get_open_file_path(static_cast<native_handle>(handle));
|
|
||||||
if (attributes == INVALID_FILE_ATTRIBUTES) {
|
if (attributes == INVALID_FILE_ATTRIBUTES) {
|
||||||
attributes = 0;
|
attributes = 0;
|
||||||
} else if (attributes == 0) {
|
} else if (attributes == 0) {
|
||||||
@ -1469,7 +1495,7 @@ auto remote_server::winfsp_set_basic_info(
|
|||||||
: FILE_ATTRIBUTE_ARCHIVE;
|
: FILE_ATTRIBUTE_ARCHIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto api_path = construct_api_path(file_path);
|
auto api_path = construct_api_path(file_path);
|
||||||
api_meta_map meta;
|
api_meta_map meta;
|
||||||
if (attributes != 0U) {
|
if (attributes != 0U) {
|
||||||
attributes &= static_cast<UINT32>(~FILE_ATTRIBUTE_NORMAL);
|
attributes &= static_cast<UINT32>(~FILE_ATTRIBUTE_NORMAL);
|
||||||
@ -1522,14 +1548,14 @@ auto remote_server::winfsp_set_file_size(PVOID file_desc, UINT64 new_size,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
||||||
auto ret = static_cast<packet::error_type>(
|
auto ret = static_cast<packet::error_type>(
|
||||||
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
const auto res = set_allocation_size == 0U
|
auto res = set_allocation_size == 0U
|
||||||
? ftruncate(static_cast<native_handle>(handle),
|
? ftruncate(static_cast<native_handle>(handle),
|
||||||
static_cast<off_t>(new_size))
|
static_cast<off_t>(new_size))
|
||||||
: 0;
|
: 0;
|
||||||
ret = ((res < 0) ? static_cast<packet::error_type>(
|
ret = ((res < 0) ? static_cast<packet::error_type>(
|
||||||
utils::unix_error_to_windows(errno))
|
utils::unix_error_to_windows(errno))
|
||||||
: 0);
|
: 0);
|
||||||
@ -1563,14 +1589,15 @@ auto remote_server::winfsp_write(PVOID file_desc, PVOID buffer, UINT64 offset,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
*bytes_transferred = 0;
|
*bytes_transferred = 0U;
|
||||||
const auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
|
||||||
|
auto handle = reinterpret_cast<remote::file_handle>(file_desc);
|
||||||
auto ret = static_cast<packet::error_type>(
|
auto ret = static_cast<packet::error_type>(
|
||||||
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
has_open_info(static_cast<native_handle>(handle), STATUS_INVALID_HANDLE));
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
const auto api_path = construct_api_path(
|
auto api_path = construct_api_path(
|
||||||
get_open_file_path(static_cast<native_handle>(handle)));
|
get_open_file_path(static_cast<native_handle>(handle)));
|
||||||
const auto file_size = drive_.get_file_size(api_path);
|
auto file_size = drive_.get_file_size(api_path);
|
||||||
if (write_to_end != 0U) {
|
if (write_to_end != 0U) {
|
||||||
offset = file_size;
|
offset = file_size;
|
||||||
}
|
}
|
||||||
@ -1587,8 +1614,8 @@ auto remote_server::winfsp_write(PVOID file_desc, PVOID buffer, UINT64 offset,
|
|||||||
|
|
||||||
if (should_write) {
|
if (should_write) {
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
const auto res = pwrite64(static_cast<native_handle>(handle), buffer,
|
auto res = pwrite64(static_cast<native_handle>(handle), buffer, length,
|
||||||
length, static_cast<off_t>(offset));
|
static_cast<off_t>(offset));
|
||||||
if (res >= 0) {
|
if (res >= 0) {
|
||||||
*bytes_transferred = static_cast<UINT32>(res);
|
*bytes_transferred = static_cast<UINT32>(res);
|
||||||
ret = populate_file_info(construct_api_path(get_open_file_path(
|
ret = populate_file_info(construct_api_path(get_open_file_path(
|
||||||
@ -1613,8 +1640,8 @@ auto remote_server::json_create_directory_snapshot(const std::string &path,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto api_path = utils::path::create_api_path(path);
|
auto api_path = utils::path::create_api_path(path);
|
||||||
const auto file_path = construct_path(api_path);
|
auto file_path = construct_path(api_path);
|
||||||
|
|
||||||
auto res = -1;
|
auto res = -1;
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
@ -1645,7 +1672,7 @@ auto remote_server::json_read_directory_snapshot(
|
|||||||
|
|
||||||
int res{-EBADF};
|
int res{-EBADF};
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
auto iter = directory_cache_.get_directory(handle);
|
auto iter = directory_cache_.get_directory(handle);
|
||||||
if (iter != nullptr) {
|
if (iter != nullptr) {
|
||||||
std::size_t offset{};
|
std::size_t offset{};
|
||||||
@ -1673,39 +1700,83 @@ auto remote_server::json_release_directory_snapshot(
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto file_path = construct_path(path);
|
auto file_path = construct_path(path);
|
||||||
directory_cache_.remove_directory(handle);
|
directory_cache_.remove_directory(handle);
|
||||||
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, 0);
|
RAISE_REMOTE_FUSE_SERVER_EVENT(function_name, file_path, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_server::update_to_windows_format(json &item) -> json & {
|
auto remote_server::update_to_windows_format(const std::string &root_api_path,
|
||||||
const auto api_path = item["path"].get<std::string>();
|
json &item) -> json & {
|
||||||
item["meta"][META_ACCESSED] = std::to_string(
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
utils::string::to_uint64(empty_as_zero(item["meta"][META_ACCESSED])));
|
|
||||||
item["meta"][META_CREATION] = std::to_string(
|
|
||||||
utils::string::to_uint64(empty_as_zero(item["meta"][META_CREATION])));
|
|
||||||
item["meta"][META_MODIFIED] = std::to_string(
|
|
||||||
utils::string::to_uint64(empty_as_zero(item["meta"][META_MODIFIED])));
|
|
||||||
|
|
||||||
if (item["meta"][META_WRITTEN].empty() ||
|
auto api_path = item[JSON_API_PATH].get<std::string>();
|
||||||
(item["meta"][META_WRITTEN].get<std::string>() == "0") ||
|
if (api_path == "." || api_path == "..") {
|
||||||
(item["meta"][META_WRITTEN].get<std::string>() ==
|
auto orig_api_path{api_path};
|
||||||
std::to_string(utils::time::WIN32_TIME_CONVERSION))) {
|
|
||||||
drive_.set_item_meta(api_path, META_WRITTEN,
|
api_path = api_path == "."
|
||||||
item["meta"][META_MODIFIED].get<std::string>());
|
? root_api_path
|
||||||
item["meta"][META_WRITTEN] = item["meta"][META_MODIFIED];
|
: utils::path::get_parent_api_path(root_api_path);
|
||||||
|
|
||||||
|
api_meta_map meta;
|
||||||
|
auto res = drive_.get_item_meta(api_path, meta);
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, api_path, res,
|
||||||
|
fmt::format("failed to get '{}' meta", orig_api_path));
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
item[JSON_DIRECTORY] = true;
|
||||||
|
meta[META_DIRECTORY] = utils::string::from_bool(true);
|
||||||
|
item[JSON_META] = meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item["meta"][META_ATTRIBUTES].empty()) {
|
item[JSON_META][META_ACCESSED] = std::to_string(
|
||||||
item["meta"][META_ATTRIBUTES] =
|
utils::string::to_uint64(empty_as_zero(item[JSON_META][META_ACCESSED])));
|
||||||
item["directory"].get<bool>() ? std::to_string(FILE_ATTRIBUTE_DIRECTORY)
|
item[JSON_META][META_CREATION] = std::to_string(
|
||||||
: std::to_string(FILE_ATTRIBUTE_ARCHIVE);
|
utils::string::to_uint64(empty_as_zero(item[JSON_META][META_CREATION])));
|
||||||
drive_.set_item_meta(api_path, META_ATTRIBUTES,
|
item[JSON_META][META_MODIFIED] = std::to_string(
|
||||||
item["meta"][META_ATTRIBUTES].get<std::string>());
|
utils::string::to_uint64(empty_as_zero(item[JSON_META][META_MODIFIED])));
|
||||||
|
|
||||||
|
auto update_meta{false};
|
||||||
|
if (item[JSON_META][META_WRITTEN].empty() ||
|
||||||
|
(item[JSON_META][META_WRITTEN].get<std::string>() == "0") ||
|
||||||
|
(item[JSON_META][META_WRITTEN].get<std::string>() ==
|
||||||
|
std::to_string(utils::time::WIN32_TIME_CONVERSION))) {
|
||||||
|
item[JSON_META][META_WRITTEN] =
|
||||||
|
item[JSON_META][META_MODIFIED].get<std::string>();
|
||||||
|
update_meta = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item[JSON_META][META_ATTRIBUTES].empty()) {
|
||||||
|
item[JSON_META][META_ATTRIBUTES] = "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto attributes = utils::string::to_uint32(
|
||||||
|
item[JSON_META][META_ATTRIBUTES].get<std::string>());
|
||||||
|
if (item[JSON_DIRECTORY].get<bool>()) {
|
||||||
|
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) {
|
||||||
|
attributes |= FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
attributes &= static_cast<std::uint32_t>(~FILE_ATTRIBUTE_ARCHIVE);
|
||||||
|
item[JSON_META][META_ATTRIBUTES] = std::to_string(attributes);
|
||||||
|
update_meta = true;
|
||||||
|
}
|
||||||
|
} else if ((attributes & FILE_ATTRIBUTE_DIRECTORY) ==
|
||||||
|
FILE_ATTRIBUTE_DIRECTORY ||
|
||||||
|
attributes == 0U) {
|
||||||
|
attributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||||
|
attributes &= static_cast<std::uint32_t>(~FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
item[JSON_META][META_ATTRIBUTES] = std::to_string(attributes);
|
||||||
|
update_meta = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update_meta) {
|
||||||
|
drive_.set_item_meta(api_path, item[JSON_META].get<api_meta_map>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
} // namespace repertory::remote_fuse
|
} // namespace repertory::remote_fuse
|
||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
@ -22,13 +22,11 @@
|
|||||||
#include "drives/winfsp/remotewinfsp/remote_client.hpp"
|
#include "drives/winfsp/remotewinfsp/remote_client.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "drives/winfsp/remotewinfsp/i_remote_instance.hpp"
|
|
||||||
#include "events/event_system.hpp"
|
#include "events/event_system.hpp"
|
||||||
#include "events/types/drive_mounted.hpp"
|
#include "events/types/drive_mounted.hpp"
|
||||||
#include "events/types/drive_unmount_pending.hpp"
|
#include "events/types/drive_unmount_pending.hpp"
|
||||||
#include "events/types/drive_unmounted.hpp"
|
#include "events/types/drive_unmounted.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "utils/string.hpp"
|
||||||
#include "utils/path.hpp"
|
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
|
|
||||||
namespace repertory::remote_winfsp {
|
namespace repertory::remote_winfsp {
|
||||||
@ -44,11 +42,7 @@ auto remote_client::winfsp_can_delete(PVOID file_desc, PWSTR file_name)
|
|||||||
request.encode(file_name);
|
request.encode(file_name);
|
||||||
|
|
||||||
std::uint32_t service_flags{};
|
std::uint32_t service_flags{};
|
||||||
auto ret{
|
return packet_client_.send(function_name, request, service_flags);
|
||||||
packet_client_.send(function_name, request, service_flags),
|
|
||||||
};
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_client::json_create_directory_snapshot(const std::string &path,
|
auto remote_client::json_create_directory_snapshot(const std::string &path,
|
||||||
@ -103,11 +97,7 @@ auto remote_client::json_release_directory_snapshot(
|
|||||||
request.encode(handle);
|
request.encode(handle);
|
||||||
|
|
||||||
std::uint32_t service_flags{};
|
std::uint32_t service_flags{};
|
||||||
auto ret{
|
return packet_client_.send(function_name, request, service_flags);
|
||||||
packet_client_.send(function_name, request, service_flags),
|
|
||||||
};
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_client::winfsp_cleanup(PVOID file_desc, PWSTR file_name,
|
auto remote_client::winfsp_cleanup(PVOID file_desc, PWSTR file_name,
|
||||||
@ -198,7 +188,7 @@ auto remote_client::winfsp_create(PWSTR file_name, UINT32 create_options,
|
|||||||
DECODE_OR_IGNORE(&response, normalized_name);
|
DECODE_OR_IGNORE(&response, normalized_name);
|
||||||
DECODE_OR_IGNORE(&response, exists);
|
DECODE_OR_IGNORE(&response, exists);
|
||||||
|
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (exists == 0U) {
|
||||||
*file_desc = reinterpret_cast<PVOID>(handle);
|
*file_desc = reinterpret_cast<PVOID>(handle);
|
||||||
set_open_info(to_handle(*file_desc),
|
set_open_info(to_handle(*file_desc),
|
||||||
open_info{
|
open_info{
|
||||||
@ -207,11 +197,6 @@ auto remote_client::winfsp_create(PWSTR file_name, UINT32 create_options,
|
|||||||
{},
|
{},
|
||||||
utils::string::to_utf8(file_name),
|
utils::string::to_utf8(file_name),
|
||||||
});
|
});
|
||||||
#if defined(_WIN32)
|
|
||||||
if (exists) {
|
|
||||||
::SetLastError(ERROR_ALREADY_EXISTS);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +227,8 @@ auto remote_client::winfsp_get_dir_buffer([[maybe_unused]] PVOID file_desc,
|
|||||||
if (get_directory_buffer(reinterpret_cast<native_handle>(file_desc), ptr)) {
|
if (get_directory_buffer(reinterpret_cast<native_handle>(file_desc), ptr)) {
|
||||||
return static_cast<packet::error_type>(STATUS_SUCCESS);
|
return static_cast<packet::error_type>(STATUS_SUCCESS);
|
||||||
}
|
}
|
||||||
#endif
|
#endif // defined(_WIN32)
|
||||||
|
|
||||||
return static_cast<packet::error_type>(STATUS_INVALID_HANDLE);
|
return static_cast<packet::error_type>(STATUS_INVALID_HANDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,8 +259,8 @@ auto remote_client::winfsp_get_security_by_name(PWSTR file_name,
|
|||||||
|
|
||||||
packet request;
|
packet request;
|
||||||
request.encode(file_name);
|
request.encode(file_name);
|
||||||
request.encode(static_cast<std::uint64_t>(
|
request.encode(descriptor_size == nullptr ? std::uint64_t(0U)
|
||||||
descriptor_size == nullptr ? 0 : *descriptor_size));
|
: *descriptor_size);
|
||||||
request.encode(static_cast<std::uint8_t>(attributes != nullptr));
|
request.encode(static_cast<std::uint8_t>(attributes != nullptr));
|
||||||
|
|
||||||
packet response;
|
packet response;
|
||||||
@ -402,6 +388,8 @@ auto remote_client::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
*bytes_transferred = 0U;
|
||||||
|
|
||||||
packet request;
|
packet request;
|
||||||
request.encode(file_desc);
|
request.encode(file_desc);
|
||||||
request.encode(offset);
|
request.encode(offset);
|
||||||
@ -413,14 +401,8 @@ auto remote_client::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
|
|||||||
packet_client_.send(function_name, request, response, service_flags),
|
packet_client_.send(function_name, request, response, service_flags),
|
||||||
};
|
};
|
||||||
DECODE_OR_IGNORE(&response, *bytes_transferred);
|
DECODE_OR_IGNORE(&response, *bytes_transferred);
|
||||||
if (ret == STATUS_SUCCESS) {
|
if ((ret == STATUS_SUCCESS) && (*bytes_transferred != 0U)) {
|
||||||
ret = response.decode(buffer, *bytes_transferred);
|
ret = response.decode(buffer, *bytes_transferred);
|
||||||
#if defined(_WIN32)
|
|
||||||
if ((ret == STATUS_SUCCESS) &&
|
|
||||||
(not*bytes_transferred || (*bytes_transferred != length))) {
|
|
||||||
::SetLastError(ERROR_HANDLE_EOF);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -461,11 +443,7 @@ auto remote_client::winfsp_rename(PVOID file_desc, PWSTR file_name,
|
|||||||
request.encode(replace_if_exists);
|
request.encode(replace_if_exists);
|
||||||
|
|
||||||
std::uint32_t service_flags{};
|
std::uint32_t service_flags{};
|
||||||
auto ret{
|
return packet_client_.send(function_name, request, service_flags);
|
||||||
packet_client_.send(function_name, request, service_flags),
|
|
||||||
};
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_client::winfsp_set_basic_info(
|
auto remote_client::winfsp_set_basic_info(
|
||||||
@ -543,6 +521,8 @@ auto remote_client::winfsp_write(PVOID file_desc, PVOID buffer, UINT64 offset,
|
|||||||
-> packet::error_type {
|
-> packet::error_type {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
*bytes_transferred = 0U;
|
||||||
|
|
||||||
packet request;
|
packet request;
|
||||||
request.encode(file_desc);
|
request.encode(file_desc);
|
||||||
request.encode(length);
|
request.encode(length);
|
||||||
|
@ -1061,7 +1061,7 @@ auto remote_server::winfsp_get_security_by_name(PWSTR file_name,
|
|||||||
auto file_path = utils::string::from_utf8(utils::path::combine(
|
auto file_path = utils::string::from_utf8(utils::path::combine(
|
||||||
mount_location_, {utils::string::to_utf8(file_name)}));
|
mount_location_, {utils::string::to_utf8(file_name)}));
|
||||||
|
|
||||||
auto ret = STATUS_BUFFER_OVERFLOW;
|
auto ret{STATUS_BUFFER_OVERFLOW};
|
||||||
if ((descriptor_size == nullptr) ||
|
if ((descriptor_size == nullptr) ||
|
||||||
(*descriptor_size <= std::numeric_limits<SIZE_T>::max())) {
|
(*descriptor_size <= std::numeric_limits<SIZE_T>::max())) {
|
||||||
auto *descriptor = descriptor_size == nullptr
|
auto *descriptor = descriptor_size == nullptr
|
||||||
@ -1221,6 +1221,7 @@ auto remote_server::winfsp_read(PVOID file_desc, PVOID buffer, UINT64 offset,
|
|||||||
? STATUS_SUCCESS
|
? STATUS_SUCCESS
|
||||||
: FspNtStatusFromWin32(::GetLastError());
|
: FspNtStatusFromWin32(::GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != STATUS_SUCCESS) {
|
if (ret != STATUS_SUCCESS) {
|
||||||
RAISE_REMOTE_WINFSP_SERVER_EVENT(function_name,
|
RAISE_REMOTE_WINFSP_SERVER_EVENT(function_name,
|
||||||
get_open_file_path(file_desc), ret);
|
get_open_file_path(file_desc), ret);
|
||||||
|
@ -131,18 +131,21 @@ auto remote_winfsp_drive::Create(PWSTR file_name, UINT32 create_options,
|
|||||||
UINT64 allocation_size, PVOID * /*file_node*/,
|
UINT64 allocation_size, PVOID * /*file_node*/,
|
||||||
PVOID *file_desc, OpenFileInfo *ofi)
|
PVOID *file_desc, OpenFileInfo *ofi)
|
||||||
-> NTSTATUS {
|
-> NTSTATUS {
|
||||||
remote::file_info fi{};
|
remote::file_info f_info{};
|
||||||
std::string normalized_name;
|
std::string normalized_name;
|
||||||
BOOLEAN exists = 0;
|
BOOLEAN exists{0};
|
||||||
auto ret = remote_instance_->winfsp_create(
|
auto ret = remote_instance_->winfsp_create(
|
||||||
file_name, create_options, granted_access, attributes, allocation_size,
|
file_name, create_options, granted_access, attributes, allocation_size,
|
||||||
file_desc, &fi, normalized_name, exists);
|
file_desc, &f_info, normalized_name, exists);
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
set_file_info(ofi->FileInfo, fi);
|
set_file_info(ofi->FileInfo, f_info);
|
||||||
auto file_path = utils::string::from_utf8(normalized_name);
|
auto file_path = utils::string::from_utf8(normalized_name);
|
||||||
wcsncpy(ofi->NormalizedName, file_path.data(), wcslen(file_path.c_str()));
|
wcsncpy(ofi->NormalizedName, file_path.data(), wcslen(file_path.c_str()));
|
||||||
ofi->NormalizedNameSize =
|
ofi->NormalizedNameSize =
|
||||||
static_cast<UINT16>(wcslen(file_path.c_str()) * sizeof(WCHAR));
|
static_cast<UINT16>(wcslen(file_path.c_str()) * sizeof(WCHAR));
|
||||||
|
if (exists != 0U) {
|
||||||
|
ret = STATUS_OBJECT_NAME_COLLISION;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -168,24 +171,32 @@ auto remote_winfsp_drive::GetSecurityByName(PWSTR file_name, PUINT32 attributes,
|
|||||||
PSECURITY_DESCRIPTOR descriptor,
|
PSECURITY_DESCRIPTOR descriptor,
|
||||||
SIZE_T *descriptor_size)
|
SIZE_T *descriptor_size)
|
||||||
-> NTSTATUS {
|
-> NTSTATUS {
|
||||||
|
std::uint64_t sds{
|
||||||
|
(descriptor_size == nullptr) ? 0U : *descriptor_size,
|
||||||
|
};
|
||||||
|
|
||||||
std::wstring string_descriptor;
|
std::wstring string_descriptor;
|
||||||
std::uint64_t sds = (descriptor_size == nullptr) ? 0 : *descriptor_size;
|
auto ret{
|
||||||
auto ret = remote_instance_->winfsp_get_security_by_name(
|
remote_instance_->winfsp_get_security_by_name(
|
||||||
file_name, attributes, descriptor_size ? &sds : nullptr,
|
file_name, attributes, descriptor_size ? &sds : nullptr,
|
||||||
string_descriptor);
|
string_descriptor),
|
||||||
*descriptor_size = static_cast<SIZE_T>(sds);
|
};
|
||||||
if ((ret == STATUS_SUCCESS) && *descriptor_size) {
|
|
||||||
PSECURITY_DESCRIPTOR sd{nullptr};
|
if ((ret == STATUS_SUCCESS) && (descriptor_size != nullptr)) {
|
||||||
ULONG sz2{0U};
|
*descriptor_size = static_cast<SIZE_T>(sds);
|
||||||
|
|
||||||
|
PSECURITY_DESCRIPTOR desc{nullptr};
|
||||||
|
ULONG size{0U};
|
||||||
if (::ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
if (::ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
||||||
string_descriptor.data(), SDDL_REVISION_1, &sd, &sz2)) {
|
string_descriptor.data(), SDDL_REVISION_1, &desc, &size)) {
|
||||||
if (sz2 > *descriptor_size) {
|
if (size > *descriptor_size) {
|
||||||
ret = STATUS_BUFFER_TOO_SMALL;
|
ret = STATUS_BUFFER_TOO_SMALL;
|
||||||
} else {
|
} else {
|
||||||
::CopyMemory(descriptor, sd, sz2);
|
::CopyMemory(descriptor, desc, size);
|
||||||
}
|
}
|
||||||
*descriptor_size = sz2;
|
|
||||||
::LocalFree(sd);
|
*descriptor_size = size;
|
||||||
|
::LocalFree(desc);
|
||||||
} else {
|
} else {
|
||||||
ret = FspNtStatusFromWin32(::GetLastError());
|
ret = FspNtStatusFromWin32(::GetLastError());
|
||||||
}
|
}
|
||||||
@ -338,9 +349,14 @@ void remote_winfsp_drive::populate_file_info(const json &item,
|
|||||||
auto remote_winfsp_drive::Read(PVOID /*file_node*/, PVOID file_desc,
|
auto remote_winfsp_drive::Read(PVOID /*file_node*/, PVOID file_desc,
|
||||||
PVOID buffer, UINT64 offset, ULONG length,
|
PVOID buffer, UINT64 offset, ULONG length,
|
||||||
PULONG bytes_transferred) -> NTSTATUS {
|
PULONG bytes_transferred) -> NTSTATUS {
|
||||||
return remote_instance_->winfsp_read(
|
auto ret = remote_instance_->winfsp_read(
|
||||||
file_desc, buffer, offset, length,
|
file_desc, buffer, offset, length,
|
||||||
reinterpret_cast<PUINT32>(bytes_transferred));
|
reinterpret_cast<PUINT32>(bytes_transferred));
|
||||||
|
if ((ret == STATUS_SUCCESS) && (*bytes_transferred != length)) {
|
||||||
|
::SetLastError(ERROR_HANDLE_EOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc,
|
auto remote_winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc,
|
||||||
@ -361,11 +377,10 @@ auto remote_winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc,
|
|||||||
&ret)) {
|
&ret)) {
|
||||||
auto item_found = false;
|
auto item_found = false;
|
||||||
for (const auto &item : item_list) {
|
for (const auto &item : item_list) {
|
||||||
auto item_path = item["path"].get<std::string>();
|
auto item_path = item[JSON_API_PATH].get<std::string>();
|
||||||
auto display_name = utils::string::from_utf8(
|
auto display_name = utils::string::from_utf8(
|
||||||
utils::path::strip_to_file_name(item_path));
|
utils::path::strip_to_file_name(item_path));
|
||||||
if (not marker || (marker && item_found)) {
|
if (not marker || (marker && item_found)) {
|
||||||
// if (not utils::path::is_ads_file_path(item_path)) {
|
|
||||||
union {
|
union {
|
||||||
UINT8 B[FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) +
|
UINT8 B[FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) +
|
||||||
((repertory::max_path_length + 1U) * sizeof(WCHAR))];
|
((repertory::max_path_length + 1U) * sizeof(WCHAR))];
|
||||||
@ -380,10 +395,8 @@ auto remote_winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc,
|
|||||||
display_name.size()) *
|
display_name.size()) *
|
||||||
sizeof(WCHAR)));
|
sizeof(WCHAR)));
|
||||||
|
|
||||||
if (not item["meta"].empty() ||
|
populate_file_info(item, directory_info->FileInfo);
|
||||||
((item_path != ".") && (item_path != ".."))) {
|
|
||||||
populate_file_info(item, directory_info->FileInfo);
|
|
||||||
}
|
|
||||||
if (ret == STATUS_SUCCESS) {
|
if (ret == STATUS_SUCCESS) {
|
||||||
::wcscpy_s(&directory_info->FileNameBuf[0],
|
::wcscpy_s(&directory_info->FileNameBuf[0],
|
||||||
repertory::max_path_length, &display_name[0]);
|
repertory::max_path_length, &display_name[0]);
|
||||||
@ -394,7 +407,6 @@ auto remote_winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
item_found = display_name == std::wstring(marker);
|
item_found = display_name == std::wstring(marker);
|
||||||
}
|
}
|
||||||
@ -418,8 +430,13 @@ auto remote_winfsp_drive::ReadDirectory(PVOID /*file_node*/, PVOID file_desc,
|
|||||||
auto remote_winfsp_drive::Rename(PVOID /*file_node*/, PVOID file_desc,
|
auto remote_winfsp_drive::Rename(PVOID /*file_node*/, PVOID file_desc,
|
||||||
PWSTR file_name, PWSTR new_file_name,
|
PWSTR file_name, PWSTR new_file_name,
|
||||||
BOOLEAN replace_if_exists) -> NTSTATUS {
|
BOOLEAN replace_if_exists) -> NTSTATUS {
|
||||||
return remote_instance_->winfsp_rename(file_desc, file_name, new_file_name,
|
auto res = remote_instance_->winfsp_rename(file_desc, file_name,
|
||||||
replace_if_exists);
|
new_file_name, replace_if_exists);
|
||||||
|
if (res == STATUS_OBJECT_NAME_EXISTS) {
|
||||||
|
return FspNtStatusFromWin32(ERROR_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_winfsp_drive::SetBasicInfo(PVOID /*file_node*/, PVOID file_desc,
|
auto remote_winfsp_drive::SetBasicInfo(PVOID /*file_node*/, PVOID file_desc,
|
||||||
@ -428,11 +445,11 @@ auto remote_winfsp_drive::SetBasicInfo(PVOID /*file_node*/, PVOID file_desc,
|
|||||||
UINT64 last_write_time,
|
UINT64 last_write_time,
|
||||||
UINT64 change_time, FileInfo *file_info)
|
UINT64 change_time, FileInfo *file_info)
|
||||||
-> NTSTATUS {
|
-> NTSTATUS {
|
||||||
remote::file_info fi{};
|
remote::file_info f_info{};
|
||||||
auto ret = remote_instance_->winfsp_set_basic_info(
|
auto ret = remote_instance_->winfsp_set_basic_info(
|
||||||
file_desc, attributes, creation_time, last_access_time, last_write_time,
|
file_desc, attributes, creation_time, last_access_time, last_write_time,
|
||||||
change_time, &fi);
|
change_time, &f_info);
|
||||||
set_file_info(*file_info, fi);
|
set_file_info(*file_info, f_info);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +490,6 @@ VOID remote_winfsp_drive::Unmounted(PVOID host) {
|
|||||||
}
|
}
|
||||||
remote_instance_->winfsp_unmounted(file_system_host->MountPoint());
|
remote_instance_->winfsp_unmounted(file_system_host->MountPoint());
|
||||||
remote_instance_.reset();
|
remote_instance_.reset();
|
||||||
mount_location_ = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remote_winfsp_drive::Write(PVOID /*file_node*/, PVOID file_desc,
|
auto remote_winfsp_drive::Write(PVOID /*file_node*/, PVOID file_desc,
|
||||||
|
@ -1023,8 +1023,15 @@ auto winfsp_drive::Rename(PVOID /*file_node*/, PVOID /*file_desc*/,
|
|||||||
|
|
||||||
const auto handle_error = [this, &from_api_path,
|
const auto handle_error = [this, &from_api_path,
|
||||||
&to_api_path](api_error error) -> NTSTATUS {
|
&to_api_path](api_error error) -> NTSTATUS {
|
||||||
return this->handle_error(function_name, from_api_path + '|' + to_api_path,
|
auto ret = this->handle_error(
|
||||||
error, nullptr, 0U);
|
function_name, from_api_path + '|' + to_api_path, error, nullptr, 0U);
|
||||||
|
if (ret == FspNtStatusFromWin32(ERROR_FILE_EXISTS)) {
|
||||||
|
ret = FspNtStatusFromWin32(ERROR_ALREADY_EXISTS);
|
||||||
|
} else if (ret == STATUS_OBJECT_NAME_EXISTS) {
|
||||||
|
ret = STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool exists{};
|
bool exists{};
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
#include "events/types/invalid_cache_size.hpp"
|
#include "events/types/invalid_cache_size.hpp"
|
||||||
#include "events/types/max_cache_size_reached.hpp"
|
#include "events/types/max_cache_size_reached.hpp"
|
||||||
#include "types/startup_exception.hpp"
|
#include "types/startup_exception.hpp"
|
||||||
#include "utils/file_utils.hpp"
|
#include "utils/file.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
cache_size_mgr cache_size_mgr::instance_{};
|
cache_size_mgr cache_size_mgr::instance_{};
|
||||||
@ -49,16 +49,15 @@ auto cache_size_mgr::expand(std::uint64_t size) -> api_error {
|
|||||||
auto last_cache_size{cache_size_};
|
auto last_cache_size{cache_size_};
|
||||||
cache_size_ += size;
|
cache_size_ += size;
|
||||||
|
|
||||||
auto max_cache_size{cfg_->get_max_cache_size_bytes()};
|
|
||||||
|
|
||||||
auto cache_dir{
|
auto cache_dir{
|
||||||
utils::file::directory{cfg_->get_cache_directory()},
|
utils::file::directory{cfg_->get_cache_directory()},
|
||||||
};
|
};
|
||||||
while (not get_stop_requested() && cache_size_ > max_cache_size &&
|
while (not get_stop_requested() &&
|
||||||
|
cache_size_ > cfg_->get_max_cache_size_bytes() &&
|
||||||
cache_dir.count() > 1U) {
|
cache_dir.count() > 1U) {
|
||||||
if (last_cache_size != cache_size_) {
|
if (last_cache_size != cache_size_) {
|
||||||
event_system::instance().raise<max_cache_size_reached>(
|
event_system::instance().raise<max_cache_size_reached>(
|
||||||
cache_size_, function_name, max_cache_size);
|
cache_size_, function_name, cfg_->get_max_cache_size_bytes());
|
||||||
last_cache_size = cache_size_;
|
last_cache_size = cache_size_;
|
||||||
}
|
}
|
||||||
notify_.wait_for(lock, cache_wait_secs);
|
notify_.wait_for(lock, cache_wait_secs);
|
||||||
|
@ -466,6 +466,13 @@ auto file_manager::open(const std::string &api_path, bool directory,
|
|||||||
return download_type::default_;
|
return download_type::default_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (utils::file::file{fsi.source_path}.exists()) {
|
||||||
|
auto size = utils::file::file{fsi.source_path}.size();
|
||||||
|
if (size.has_value() && *size == fsi.size) {
|
||||||
|
return download_type::default_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (type == download_type::direct) {
|
if (type == download_type::direct) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
@ -122,8 +122,8 @@ open_file::open_file(std::uint64_t chunk_size, std::uint8_t chunk_timeout,
|
|||||||
|
|
||||||
open_file::~open_file() { close(); }
|
open_file::~open_file() { close(); }
|
||||||
|
|
||||||
auto open_file::adjust_cache_size(std::uint64_t file_size,
|
auto open_file::adjust_cache_size(std::uint64_t file_size, bool shrink)
|
||||||
bool shrink) -> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
if (file_size == get_file_size()) {
|
if (file_size == get_file_size()) {
|
||||||
@ -554,6 +554,7 @@ auto open_file::read(std::size_t read_size, std::uint64_t read_offset,
|
|||||||
read_size =
|
read_size =
|
||||||
utils::calculate_read_size(get_file_size(), read_size, read_offset);
|
utils::calculate_read_size(get_file_size(), read_size, read_offset);
|
||||||
if (read_size == 0U) {
|
if (read_size == 0U) {
|
||||||
|
data.resize(0U);
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,19 +98,23 @@ auto ring_buffer_base::close() -> bool {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ring_buffer_base::download_chunk(std::size_t chunk,
|
auto ring_buffer_base::download_chunk(std::size_t chunk, bool skip_active)
|
||||||
bool skip_active) -> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
unique_mutex_lock chunk_lock(chunk_mtx_);
|
unique_mutex_lock chunk_lock(chunk_mtx_);
|
||||||
const auto unlock_and_notify = [this, &chunk_lock]() {
|
if (not skip_active) {
|
||||||
|
ring_pos_ = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto notify_and_unlock = [this, &chunk_lock]() {
|
||||||
chunk_notify_.notify_all();
|
chunk_notify_.notify_all();
|
||||||
chunk_lock.unlock();
|
chunk_lock.unlock();
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto unlock_and_return =
|
const auto unlock_and_return =
|
||||||
[&unlock_and_notify](api_error res) -> api_error {
|
[¬ify_and_unlock](api_error res) -> api_error {
|
||||||
unlock_and_notify();
|
notify_and_unlock();
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -124,7 +128,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto active_download = get_active_downloads().at(chunk);
|
auto active_download = get_active_downloads().at(chunk);
|
||||||
unlock_and_notify();
|
notify_and_unlock();
|
||||||
|
|
||||||
return active_download->wait();
|
return active_download->wait();
|
||||||
}
|
}
|
||||||
@ -142,7 +146,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk,
|
|||||||
chunk == (total_chunks_ - 1U) ? get_last_chunk_size()
|
chunk == (total_chunks_ - 1U) ? get_last_chunk_size()
|
||||||
: get_chunk_size(),
|
: get_chunk_size(),
|
||||||
};
|
};
|
||||||
unlock_and_notify();
|
notify_and_unlock();
|
||||||
|
|
||||||
auto result{
|
auto result{
|
||||||
get_provider().read_file_bytes(get_api_path(), data_size, data_offset,
|
get_provider().read_file_bytes(get_api_path(), data_size, data_offset,
|
||||||
@ -167,7 +171,7 @@ auto ring_buffer_base::download_chunk(std::size_t chunk,
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_active_downloads().erase(chunk);
|
get_active_downloads().erase(chunk);
|
||||||
unlock_and_notify();
|
notify_and_unlock();
|
||||||
|
|
||||||
active_download->notify(result);
|
active_download->notify(result);
|
||||||
return result;
|
return result;
|
||||||
@ -203,6 +207,7 @@ auto ring_buffer_base::read(std::size_t read_size, std::uint64_t read_offset,
|
|||||||
read_size =
|
read_size =
|
||||||
utils::calculate_read_size(get_file_size(), read_size, read_offset);
|
utils::calculate_read_size(get_file_size(), read_size, read_offset);
|
||||||
if (read_size == 0U) {
|
if (read_size == 0U) {
|
||||||
|
data.resize(0U);
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +231,6 @@ auto ring_buffer_base::read(std::size_t read_size, std::uint64_t read_offset,
|
|||||||
} else if (chunk < ring_pos_) {
|
} else if (chunk < ring_pos_) {
|
||||||
reverse(ring_pos_ - chunk);
|
reverse(ring_pos_ - chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = download_chunk(chunk, false);
|
res = download_chunk(chunk, false);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
if (res == api_error::invalid_ring_buffer_position) {
|
if (res == api_error::invalid_ring_buffer_position) {
|
||||||
@ -264,38 +268,46 @@ void ring_buffer_base::reader_thread() {
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
unique_mutex_lock chunk_lock(chunk_mtx_);
|
unique_mutex_lock chunk_lock(chunk_mtx_);
|
||||||
auto next_chunk{ring_pos_};
|
const auto notify_and_unlock = [this, &chunk_lock]() {
|
||||||
chunk_notify_.notify_all();
|
chunk_notify_.notify_all();
|
||||||
chunk_lock.unlock();
|
chunk_lock.unlock();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto last_pos = ring_pos_;
|
||||||
|
auto next_chunk = ring_pos_;
|
||||||
|
notify_and_unlock();
|
||||||
|
|
||||||
while (not get_stop_requested()) {
|
while (not get_stop_requested()) {
|
||||||
chunk_lock.lock();
|
chunk_lock.lock();
|
||||||
|
|
||||||
next_chunk = next_chunk + 1U > ring_end_ ? ring_begin_ : next_chunk + 1U;
|
if (last_pos == ring_pos_) {
|
||||||
const auto check_and_wait = [this, &chunk_lock, &next_chunk]() {
|
++next_chunk;
|
||||||
|
} else {
|
||||||
|
next_chunk = ring_pos_ + 1U;
|
||||||
|
last_pos = ring_pos_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_chunk > ring_end_) {
|
||||||
|
next_chunk = ring_begin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_state_[next_chunk % read_state_.size()]) {
|
||||||
if (get_stop_requested()) {
|
if (get_stop_requested()) {
|
||||||
chunk_notify_.notify_all();
|
notify_and_unlock();
|
||||||
chunk_lock.unlock();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_read_state().all()) {
|
if (get_read_state().all()) {
|
||||||
chunk_notify_.wait(chunk_lock);
|
chunk_notify_.wait(chunk_lock);
|
||||||
|
last_pos = ring_pos_;
|
||||||
next_chunk = ring_pos_;
|
next_chunk = ring_pos_;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
notify_and_unlock();
|
||||||
chunk_lock.unlock();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (read_state_[next_chunk % read_state_.size()]) {
|
|
||||||
check_and_wait();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
notify_and_unlock();
|
||||||
chunk_lock.unlock();
|
|
||||||
|
|
||||||
download_chunk(next_chunk, true);
|
download_chunk(next_chunk, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,30 +363,31 @@ void ring_buffer_base::update_position(std::size_t count, bool is_forward) {
|
|||||||
if (is_forward ? (ring_pos_ + count) <= ring_end_
|
if (is_forward ? (ring_pos_ + count) <= ring_end_
|
||||||
: (ring_pos_ - count) >= ring_begin_) {
|
: (ring_pos_ - count) >= ring_begin_) {
|
||||||
ring_pos_ += is_forward ? count : -count;
|
ring_pos_ += is_forward ? count : -count;
|
||||||
} else {
|
chunk_notify_.notify_all();
|
||||||
auto delta = is_forward ? count - (ring_end_ - ring_pos_)
|
return;
|
||||||
: count - (ring_pos_ - ring_begin_);
|
|
||||||
|
|
||||||
if (delta >= read_state_.size()) {
|
|
||||||
read_state_.set(0U, read_state_.size(), false);
|
|
||||||
ring_pos_ += is_forward ? count : -count;
|
|
||||||
ring_begin_ += is_forward ? delta : -delta;
|
|
||||||
} else {
|
|
||||||
for (std::size_t idx = 0U; idx < delta; ++idx) {
|
|
||||||
if (is_forward) {
|
|
||||||
read_state_[(ring_begin_ + idx) % read_state_.size()] = false;
|
|
||||||
} else {
|
|
||||||
read_state_[(ring_end_ - idx) % read_state_.size()] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ring_begin_ += is_forward ? delta : -delta;
|
|
||||||
ring_pos_ += is_forward ? count : -count;
|
|
||||||
}
|
|
||||||
|
|
||||||
ring_end_ =
|
|
||||||
std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto delta = is_forward ? count - (ring_end_ - ring_pos_)
|
||||||
|
: count - (ring_pos_ - ring_begin_);
|
||||||
|
if (delta >= read_state_.size()) {
|
||||||
|
read_state_.set(0U, read_state_.size(), false);
|
||||||
|
ring_pos_ += is_forward ? count : -count;
|
||||||
|
ring_begin_ += is_forward ? delta : -delta;
|
||||||
|
} else {
|
||||||
|
for (std::size_t idx = 0U; idx < delta; ++idx) {
|
||||||
|
if (is_forward) {
|
||||||
|
read_state_[(ring_begin_ + idx) % read_state_.size()] = false;
|
||||||
|
} else {
|
||||||
|
read_state_[(ring_end_ - idx) % read_state_.size()] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ring_begin_ += is_forward ? delta : -delta;
|
||||||
|
ring_pos_ += is_forward ? count : -count;
|
||||||
|
}
|
||||||
|
|
||||||
|
ring_end_ =
|
||||||
|
std::min(total_chunks_ - 1U, ring_begin_ + read_state_.size() - 1U);
|
||||||
|
|
||||||
chunk_notify_.notify_all();
|
chunk_notify_.notify_all();
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -50,10 +50,6 @@
|
|||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
auto project_initialize() -> bool {
|
auto project_initialize() -> bool {
|
||||||
spdlog::drop_all();
|
|
||||||
spdlog::flush_every(std::chrono::seconds(10));
|
|
||||||
spdlog::set_pattern("%Y-%m-%d|%T.%e|%^%l%$|%v");
|
|
||||||
|
|
||||||
#if defined(PROJECT_REQUIRE_ALPINE) && !defined(PROJECT_IS_MINGW)
|
#if defined(PROJECT_REQUIRE_ALPINE) && !defined(PROJECT_IS_MINGW)
|
||||||
{
|
{
|
||||||
static constexpr const auto guard_size{4096U};
|
static constexpr const auto guard_size{4096U};
|
||||||
@ -68,6 +64,10 @@ auto project_initialize() -> bool {
|
|||||||
}
|
}
|
||||||
#endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW)
|
#endif // defined(PROJECT_REQUIRE_ALPINE) && !defined (PROJECT_IS_MINGW)
|
||||||
|
|
||||||
|
spdlog::drop_all();
|
||||||
|
spdlog::flush_every(std::chrono::seconds(10));
|
||||||
|
spdlog::set_pattern("%Y-%m-%d|%T.%e|%^%l%$|%v");
|
||||||
|
|
||||||
#if defined(PROJECT_ENABLE_LIBSODIUM)
|
#if defined(PROJECT_ENABLE_LIBSODIUM)
|
||||||
{
|
{
|
||||||
if (sodium_init() == -1) {
|
if (sodium_init() == -1) {
|
||||||
@ -77,7 +77,9 @@ auto project_initialize() -> bool {
|
|||||||
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
|
#endif // defined(PROJECT_ENABLE_LIBSODIUM)
|
||||||
|
|
||||||
#if defined(PROJECT_ENABLE_OPENSSL)
|
#if defined(PROJECT_ENABLE_OPENSSL)
|
||||||
{ SSL_library_init(); }
|
{
|
||||||
|
SSL_library_init();
|
||||||
|
}
|
||||||
#endif // defined(PROJECT_ENABLE_OPENSSL)
|
#endif // defined(PROJECT_ENABLE_OPENSSL)
|
||||||
|
|
||||||
#if defined(PROJECT_ENABLE_CURL)
|
#if defined(PROJECT_ENABLE_CURL)
|
||||||
|
@ -21,9 +21,8 @@
|
|||||||
*/
|
*/
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
|
|
||||||
#include "platform/unix_platform.hpp"
|
#include "platform/platform.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "events/event_system.hpp"
|
#include "events/event_system.hpp"
|
||||||
#include "events/types/filesystem_item_added.hpp"
|
#include "events/types/filesystem_item_added.hpp"
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
@ -36,61 +35,65 @@
|
|||||||
#include "utils/unix.hpp"
|
#include "utils/unix.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
lock_data::lock_data(const provider_type &pt, std::string unique_id /*= ""*/)
|
lock_data::lock_data(provider_type prov, std::string_view unique_id)
|
||||||
: pt_(pt),
|
: mutex_id_(create_lock_id(prov, unique_id)) {
|
||||||
unique_id_(std::move(unique_id)),
|
handle_ = open(get_lock_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
|
||||||
mutex_id_("repertory_" + app_config::get_provider_name(pt) + "_" +
|
|
||||||
unique_id_) {
|
|
||||||
lock_fd_ = open(get_lock_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lock_data::lock_data()
|
lock_data::~lock_data() { release(); }
|
||||||
: pt_(provider_type::sia), unique_id_(""), mutex_id_(""), lock_fd_(-1) {}
|
|
||||||
|
|
||||||
lock_data::~lock_data() {
|
auto lock_data::get_lock_data_file() const -> std::string {
|
||||||
if (lock_fd_ != -1) {
|
auto dir = get_state_directory();
|
||||||
if (lock_status_ == 0) {
|
|
||||||
unlink(get_lock_file().c_str());
|
|
||||||
flock(lock_fd_, LOCK_UN);
|
|
||||||
}
|
|
||||||
|
|
||||||
close(lock_fd_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lock_data::get_lock_data_file() -> std::string {
|
|
||||||
const auto dir = get_state_directory();
|
|
||||||
if (not utils::file::directory(dir).create_directory()) {
|
if (not utils::file::directory(dir).create_directory()) {
|
||||||
throw startup_exception("failed to create directory|sp|" + dir + "|err|" +
|
throw startup_exception("failed to create directory|sp|" + dir + "|err|" +
|
||||||
std::to_string(utils::get_last_error_code()));
|
std::to_string(utils::get_last_error_code()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::path::combine(
|
return utils::path::combine(
|
||||||
dir, {"mountstate_" + std::to_string(getuid()) + ".json"});
|
dir, {
|
||||||
|
fmt::format("{}_{}.json", mutex_id_, getuid()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock_data::get_lock_file() -> std::string {
|
auto lock_data::get_lock_file() const -> std::string {
|
||||||
const auto dir = get_state_directory();
|
auto dir = get_state_directory();
|
||||||
if (not utils::file::directory(dir).create_directory()) {
|
if (not utils::file::directory(dir).create_directory()) {
|
||||||
throw startup_exception("failed to create directory|sp|" + dir + "|err|" +
|
throw startup_exception("failed to create directory|sp|" + dir + "|err|" +
|
||||||
std::to_string(utils::get_last_error_code()));
|
std::to_string(utils::get_last_error_code()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::path::combine(dir,
|
return utils::path::combine(
|
||||||
{mutex_id_ + "_" + std::to_string(getuid())});
|
dir, {
|
||||||
|
fmt::format("{}_{}.lock", mutex_id_, getuid()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock_data::get_mount_state(json &mount_state) -> bool {
|
auto lock_data::get_mount_state(json &mount_state) -> bool {
|
||||||
auto ret = false;
|
auto handle = open(get_lock_data_file().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
|
||||||
auto fd =
|
if (handle == -1) {
|
||||||
open(get_lock_data_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
|
mount_state = {
|
||||||
if (fd != -1) {
|
{"Active", false},
|
||||||
if (wait_for_lock(fd) == 0) {
|
{"Location", ""},
|
||||||
ret = utils::file::read_json_file(get_lock_data_file(), mount_state);
|
{"PID", -1},
|
||||||
flock(fd, LOCK_UN);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
close(fd);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ret{false};
|
||||||
|
if (wait_for_lock(handle) == 0) {
|
||||||
|
ret = utils::file::read_json_file(get_lock_data_file(), mount_state);
|
||||||
|
if (ret && mount_state.empty()) {
|
||||||
|
mount_state = {
|
||||||
|
{"Active", false},
|
||||||
|
{"Location", ""},
|
||||||
|
{"PID", -1},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
flock(handle, LOCK_UN);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(handle);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,25 +101,20 @@ auto lock_data::get_state_directory() -> std::string {
|
|||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
return utils::path::absolute("~/Library/Application Support/" +
|
return utils::path::absolute("~/Library/Application Support/" +
|
||||||
std::string{REPERTORY_DATA_NAME} + "/state");
|
std::string{REPERTORY_DATA_NAME} + "/state");
|
||||||
#else
|
#else // !defined(__APPLE__)
|
||||||
return utils::path::absolute("~/.local/" + std::string{REPERTORY_DATA_NAME} +
|
return utils::path::absolute("~/.local/" + std::string{REPERTORY_DATA_NAME} +
|
||||||
"/state");
|
"/state");
|
||||||
#endif
|
#endif // defined(__APPLE__)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock_data::grab_lock(std::uint8_t retry_count) -> lock_result {
|
auto lock_data::grab_lock(std::uint8_t retry_count) -> lock_result {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
if (handle_ == -1) {
|
||||||
|
|
||||||
if (lock_fd_ == -1) {
|
|
||||||
return lock_result::failure;
|
return lock_result::failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock_status_ = wait_for_lock(lock_fd_, retry_count);
|
lock_status_ = wait_for_lock(handle_, retry_count);
|
||||||
switch (lock_status_) {
|
switch (lock_status_) {
|
||||||
case 0:
|
case 0:
|
||||||
if (not set_mount_state(false, "", -1)) {
|
|
||||||
utils::error::raise_error(function_name, "failed to set mount state");
|
|
||||||
}
|
|
||||||
return lock_result::success;
|
return lock_result::success;
|
||||||
case EWOULDBLOCK:
|
case EWOULDBLOCK:
|
||||||
return lock_result::locked;
|
return lock_result::locked;
|
||||||
@ -125,61 +123,72 @@ auto lock_data::grab_lock(std::uint8_t retry_count) -> lock_result {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock_data::set_mount_state(bool active, const std::string &mount_location,
|
void lock_data::release() {
|
||||||
|
if (handle_ == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lock_status_ == 0) {
|
||||||
|
[[maybe_unused]] auto success{utils::file::file{get_lock_file()}.remove()};
|
||||||
|
flock(handle_, LOCK_UN);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(handle_);
|
||||||
|
handle_ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock_data::set_mount_state(bool active, std::string_view mount_location,
|
||||||
int pid) -> bool {
|
int pid) -> bool {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
auto ret = false;
|
|
||||||
auto handle =
|
auto handle =
|
||||||
open(get_lock_data_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
|
open(get_lock_data_file().c_str(), O_CREAT | O_RDWR, S_IWUSR | S_IRUSR);
|
||||||
if (handle != -1) {
|
if (handle == -1) {
|
||||||
if (wait_for_lock(handle) == 0) {
|
return false;
|
||||||
const auto mount_id =
|
}
|
||||||
app_config::get_provider_display_name(pt_) + unique_id_;
|
|
||||||
json mount_state;
|
|
||||||
if (not utils::file::read_json_file(get_lock_data_file(), mount_state)) {
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"failed to read mount state file|sp|" +
|
|
||||||
get_lock_file());
|
|
||||||
}
|
|
||||||
if ((mount_state.find(mount_id) == mount_state.end()) ||
|
|
||||||
(mount_state[mount_id].find("Active") ==
|
|
||||||
mount_state[mount_id].end()) ||
|
|
||||||
(mount_state[mount_id]["Active"].get<bool>() != active) ||
|
|
||||||
(active && ((mount_state[mount_id].find("Location") ==
|
|
||||||
mount_state[mount_id].end()) ||
|
|
||||||
(mount_state[mount_id]["Location"].get<std::string>() !=
|
|
||||||
mount_location)))) {
|
|
||||||
const auto lines = utils::file::read_file_lines(get_lock_data_file());
|
|
||||||
const auto txt = std::accumulate(
|
|
||||||
lines.begin(), lines.end(), std::string(),
|
|
||||||
[](auto &&val, auto &&line) -> auto { return val + line; });
|
|
||||||
auto json_data = json::parse(txt.empty() ? "{}" : txt);
|
|
||||||
json_data[mount_id] = {
|
|
||||||
{"Active", active},
|
|
||||||
{"Location", active ? mount_location : ""},
|
|
||||||
{"PID", active ? pid : -1},
|
|
||||||
};
|
|
||||||
ret = utils::file::write_json_file(get_lock_data_file(), json_data);
|
|
||||||
} else {
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
flock(handle, LOCK_UN);
|
auto ret{false};
|
||||||
|
if (wait_for_lock(handle) == 0) {
|
||||||
|
json mount_state;
|
||||||
|
if (not utils::file::read_json_file(get_lock_data_file(), mount_state)) {
|
||||||
|
utils::error::raise_error(function_name,
|
||||||
|
"failed to read mount state file|sp|" +
|
||||||
|
get_lock_file());
|
||||||
|
}
|
||||||
|
if ((mount_state.find("Active") == mount_state.end()) ||
|
||||||
|
(mount_state["Active"].get<bool>() != active) ||
|
||||||
|
(active &&
|
||||||
|
((mount_state.find("Location") == mount_state.end()) ||
|
||||||
|
(mount_state["Location"].get<std::string>() != mount_location)))) {
|
||||||
|
if (mount_location.empty() && not active) {
|
||||||
|
ret = utils::file::file{get_lock_data_file()}.remove();
|
||||||
|
} else {
|
||||||
|
ret = utils::file::write_json_file(
|
||||||
|
get_lock_data_file(),
|
||||||
|
{
|
||||||
|
{"Active", active},
|
||||||
|
{"Location", active ? mount_location : ""},
|
||||||
|
{"PID", active ? pid : -1},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(handle);
|
flock(handle, LOCK_UN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close(handle);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock_data::wait_for_lock(int fd, std::uint8_t retry_count) -> int {
|
auto lock_data::wait_for_lock(int handle, std::uint8_t retry_count) -> int {
|
||||||
static constexpr const std::uint32_t max_sleep = 100U;
|
static constexpr const std::uint32_t max_sleep{100U};
|
||||||
|
|
||||||
auto lock_status = EWOULDBLOCK;
|
auto lock_status{EWOULDBLOCK};
|
||||||
auto remain = static_cast<std::uint32_t>(retry_count * max_sleep);
|
auto remain{static_cast<std::uint32_t>(retry_count * max_sleep)};
|
||||||
while ((remain > 0) && (lock_status == EWOULDBLOCK)) {
|
while ((remain > 0) && (lock_status == EWOULDBLOCK)) {
|
||||||
lock_status = flock(fd, LOCK_EX | LOCK_NB);
|
lock_status = flock(handle, LOCK_EX | LOCK_NB);
|
||||||
if (lock_status == -1) {
|
if (lock_status == -1) {
|
||||||
lock_status = errno;
|
lock_status = errno;
|
||||||
if (lock_status == EWOULDBLOCK) {
|
if (lock_status == EWOULDBLOCK) {
|
||||||
@ -228,13 +237,13 @@ auto provider_meta_handler(i_provider &provider, bool directory,
|
|||||||
const api_file &file) -> api_error {
|
const api_file &file) -> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto meta = create_meta_attributes(
|
auto meta = create_meta_attributes(
|
||||||
file.accessed_date,
|
file.accessed_date,
|
||||||
directory ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_ARCHIVE,
|
directory ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_ARCHIVE,
|
||||||
file.changed_date, file.creation_date, directory, getgid(), file.key,
|
file.changed_date, file.creation_date, directory, getgid(), file.key,
|
||||||
directory ? S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR
|
directory ? S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR
|
||||||
: S_IFREG | S_IRUSR | S_IWUSR,
|
: S_IFREG | S_IRUSR | S_IWUSR,
|
||||||
file.modified_date, 0u, 0u, file.file_size, file.source_path, getuid(),
|
file.modified_date, 0U, 0U, file.file_size, file.source_path, getuid(),
|
||||||
file.modified_date);
|
file.modified_date);
|
||||||
auto res = provider.set_item_meta(file.api_path, meta);
|
auto res = provider.set_item_meta(file.api_path, meta);
|
||||||
if (res == api_error::success) {
|
if (res == api_error::success) {
|
||||||
|
@ -21,150 +21,171 @@
|
|||||||
*/
|
*/
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
#include "platform/win32_platform.hpp"
|
#include "platform/platform.hpp"
|
||||||
|
|
||||||
#include "events/event_system.hpp"
|
#include "events/event_system.hpp"
|
||||||
#include "events/types/filesystem_item_added.hpp"
|
#include "events/types/filesystem_item_added.hpp"
|
||||||
#include "providers/i_provider.hpp"
|
#include "providers/i_provider.hpp"
|
||||||
|
#include "utils/config.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
auto lock_data::get_mount_state(const provider_type & /*pt*/, json &mount_state)
|
lock_data::lock_data(provider_type prov, std::string unique_id)
|
||||||
-> bool {
|
: mutex_id_(create_lock_id(prov, unique_id)),
|
||||||
const auto ret = get_mount_state(mount_state);
|
mutex_handle_(::CreateMutex(nullptr, FALSE,
|
||||||
if (ret) {
|
create_lock_id(prov, unique_id).c_str())) {}
|
||||||
const auto mount_id =
|
|
||||||
app_config::get_provider_display_name(pt_) + unique_id_;
|
lock_data::~lock_data() { release(); }
|
||||||
mount_state = mount_state[mount_id].empty()
|
|
||||||
? json({{"Active", false}, {"Location", ""}, {"PID", -1}})
|
auto lock_data::get_current_mount_state(json &mount_state) -> bool {
|
||||||
: mount_state[mount_id];
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
HKEY key{};
|
||||||
|
if (::RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||||
|
fmt::format(R"(SOFTWARE\{}\Mounts\{})",
|
||||||
|
REPERTORY_DATA_NAME, mutex_id_)
|
||||||
|
.c_str(),
|
||||||
|
0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string data;
|
||||||
|
DWORD data_size{};
|
||||||
|
|
||||||
|
DWORD type{REG_SZ};
|
||||||
|
::RegGetValueA(key, nullptr, nullptr, RRF_RT_REG_SZ, &type, nullptr,
|
||||||
|
&data_size);
|
||||||
|
|
||||||
|
data.resize(data_size);
|
||||||
|
auto res = ::RegGetValueA(key, nullptr, nullptr, RRF_RT_REG_SZ, &type,
|
||||||
|
data.data(), &data_size);
|
||||||
|
auto ret = res == ERROR_SUCCESS || res == ERROR_FILE_NOT_FOUND;
|
||||||
|
if (ret && data_size != 0U) {
|
||||||
|
try {
|
||||||
|
mount_state = json::parse(data);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
utils::error::raise_error(function_name, e, "failed to read mount state");
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::RegCloseKey(key);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock_data::get_mount_state(json &mount_state) -> bool {
|
auto lock_data::get_mount_state(json &mount_state) -> bool {
|
||||||
HKEY key;
|
if (not get_current_mount_state(mount_state)) {
|
||||||
auto ret = !::RegCreateKeyEx(
|
return false;
|
||||||
HKEY_CURRENT_USER,
|
|
||||||
("SOFTWARE\\" + std::string{REPERTORY_DATA_NAME} + "\\Mounts").c_str(), 0,
|
|
||||||
nullptr, 0, KEY_ALL_ACCESS, nullptr, &key, nullptr);
|
|
||||||
if (ret) {
|
|
||||||
DWORD i = 0u;
|
|
||||||
DWORD data_size = 0u;
|
|
||||||
std::string name;
|
|
||||||
name.resize(32767u);
|
|
||||||
auto name_size = static_cast<DWORD>(name.size());
|
|
||||||
while (ret &&
|
|
||||||
(::RegEnumValue(key, i, &name[0], &name_size, nullptr, nullptr,
|
|
||||||
nullptr, &data_size) == ERROR_SUCCESS)) {
|
|
||||||
std::string data;
|
|
||||||
data.resize(data_size);
|
|
||||||
name_size++;
|
|
||||||
if ((ret = !::RegEnumValue(key, i++, &name[0], &name_size, nullptr,
|
|
||||||
nullptr, reinterpret_cast<LPBYTE>(&data[0]),
|
|
||||||
&data_size))) {
|
|
||||||
mount_state[name.c_str()] = json::parse(data);
|
|
||||||
name_size = static_cast<DWORD>(name.size());
|
|
||||||
data_size = 0u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
::RegCloseKey(key);
|
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
|
mount_state = mount_state.empty() ? json({
|
||||||
|
{"Active", false},
|
||||||
|
{"Location", ""},
|
||||||
|
{"PID", -1},
|
||||||
|
})
|
||||||
|
: mount_state;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock_data::grab_lock(std::uint8_t retry_count) -> lock_result {
|
auto lock_data::grab_lock(std::uint8_t retry_count) -> lock_result {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
static constexpr const std::uint32_t max_sleep{100U};
|
||||||
|
|
||||||
auto ret = lock_result::success;
|
|
||||||
if (mutex_handle_ == INVALID_HANDLE_VALUE) {
|
if (mutex_handle_ == INVALID_HANDLE_VALUE) {
|
||||||
ret = lock_result::failure;
|
return lock_result::failure;
|
||||||
} else {
|
|
||||||
for (auto i = 0;
|
|
||||||
(i <= retry_count) && ((mutex_state_ = ::WaitForSingleObject(
|
|
||||||
mutex_handle_, 100)) == WAIT_TIMEOUT);
|
|
||||||
i++) {
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (mutex_state_) {
|
|
||||||
case WAIT_OBJECT_0: {
|
|
||||||
ret = lock_result::success;
|
|
||||||
auto should_reset = true;
|
|
||||||
json mount_state;
|
|
||||||
if (get_mount_state(pt_, mount_state)) {
|
|
||||||
if (mount_state["Active"].get<bool>() &&
|
|
||||||
mount_state["Location"] == "elevating") {
|
|
||||||
should_reset = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (should_reset) {
|
|
||||||
if (not set_mount_state(false, "", -1)) {
|
|
||||||
utils::error::raise_error(function_name, "failed to set mount state");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case WAIT_TIMEOUT:
|
|
||||||
ret = lock_result::locked;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ret = lock_result::failure;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
for (std::uint8_t idx = 0U;
|
||||||
|
(idx <= retry_count) &&
|
||||||
|
((mutex_state_ = ::WaitForSingleObject(mutex_handle_, max_sleep)) ==
|
||||||
|
WAIT_TIMEOUT);
|
||||||
|
++idx) {
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mutex_state_) {
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
return lock_result::success;
|
||||||
|
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
return lock_result::locked;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return lock_result::failure;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock_data::release() {
|
void lock_data::release() {
|
||||||
if (mutex_handle_ != INVALID_HANDLE_VALUE) {
|
if (mutex_handle_ == INVALID_HANDLE_VALUE) {
|
||||||
if ((mutex_state_ == WAIT_OBJECT_0) || (mutex_state_ == WAIT_ABANDONED)) {
|
return;
|
||||||
::ReleaseMutex(mutex_handle_);
|
|
||||||
}
|
|
||||||
::CloseHandle(mutex_handle_);
|
|
||||||
mutex_handle_ = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((mutex_state_ == WAIT_OBJECT_0) || (mutex_state_ == WAIT_ABANDONED)) {
|
||||||
|
if (mutex_state_ == WAIT_OBJECT_0) {
|
||||||
|
[[maybe_unused]] auto success{set_mount_state(false, "", -1)};
|
||||||
|
}
|
||||||
|
|
||||||
|
::ReleaseMutex(mutex_handle_);
|
||||||
|
}
|
||||||
|
|
||||||
|
::CloseHandle(mutex_handle_);
|
||||||
|
mutex_handle_ = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock_data::set_mount_state(bool active, const std::string &mount_location,
|
auto lock_data::set_mount_state(bool active, std::string_view mount_location,
|
||||||
const std::int64_t &pid) -> bool {
|
std::int64_t pid) -> bool {
|
||||||
auto ret = false;
|
if (mutex_handle_ == INVALID_HANDLE_VALUE) {
|
||||||
if (mutex_handle_ != INVALID_HANDLE_VALUE) {
|
return false;
|
||||||
const auto mount_id =
|
|
||||||
app_config::get_provider_display_name(pt_) + unique_id_;
|
|
||||||
json mount_state;
|
|
||||||
[[maybe_unused]] auto success = get_mount_state(mount_state);
|
|
||||||
if ((mount_state.find(mount_id) == mount_state.end()) ||
|
|
||||||
(mount_state[mount_id].find("Active") == mount_state[mount_id].end()) ||
|
|
||||||
(mount_state[mount_id]["Active"].get<bool>() != active) ||
|
|
||||||
(active && ((mount_state[mount_id].find("Location") ==
|
|
||||||
mount_state[mount_id].end()) ||
|
|
||||||
(mount_state[mount_id]["Location"].get<std::string>() !=
|
|
||||||
mount_location)))) {
|
|
||||||
HKEY key;
|
|
||||||
if ((ret = !::RegCreateKeyEx(
|
|
||||||
HKEY_CURRENT_USER,
|
|
||||||
("SOFTWARE\\" + std::string{REPERTORY_DATA_NAME} + "\\Mounts")
|
|
||||||
.c_str(),
|
|
||||||
0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &key, nullptr))) {
|
|
||||||
const auto str = json({{"Active", active},
|
|
||||||
{"Location", active ? mount_location : ""},
|
|
||||||
{"PID", active ? pid : -1}})
|
|
||||||
.dump(0);
|
|
||||||
ret = !::RegSetValueEx(key, &mount_id[0], 0, REG_SZ,
|
|
||||||
reinterpret_cast<const BYTE *>(&str[0]),
|
|
||||||
static_cast<DWORD>(str.size()));
|
|
||||||
::RegCloseKey(key);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json mount_state;
|
||||||
|
[[maybe_unused]] auto success{get_mount_state(mount_state)};
|
||||||
|
if (not((mount_state.find("Active") == mount_state.end()) ||
|
||||||
|
(mount_state["Active"].get<bool>() != active) ||
|
||||||
|
(active &&
|
||||||
|
((mount_state.find("Location") == mount_state.end()) ||
|
||||||
|
(mount_state["Location"].get<std::string>() != mount_location))))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
HKEY key{};
|
||||||
|
if (::RegCreateKeyExA(HKEY_CURRENT_USER,
|
||||||
|
fmt::format(R"(SOFTWARE\{}\Mounts\{})",
|
||||||
|
REPERTORY_DATA_NAME, mutex_id_)
|
||||||
|
.c_str(),
|
||||||
|
0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &key,
|
||||||
|
nullptr) != ERROR_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ret{false};
|
||||||
|
if (mount_location.empty() && not active) {
|
||||||
|
::RegCloseKey(key);
|
||||||
|
|
||||||
|
if (::RegCreateKeyExA(
|
||||||
|
HKEY_CURRENT_USER,
|
||||||
|
fmt::format(R"(SOFTWARE\{}\Mounts)", REPERTORY_DATA_NAME).c_str(),
|
||||||
|
0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &key,
|
||||||
|
nullptr) != ERROR_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = (::RegDeleteKeyA(key, mutex_id_.c_str()) == ERROR_SUCCESS);
|
||||||
|
} else {
|
||||||
|
auto data{
|
||||||
|
json({
|
||||||
|
{"Active", active},
|
||||||
|
{"Location", active ? mount_location : ""},
|
||||||
|
{"PID", active ? pid : -1},
|
||||||
|
})
|
||||||
|
.dump(),
|
||||||
|
};
|
||||||
|
ret = (::RegSetValueEx(key, nullptr, 0, REG_SZ,
|
||||||
|
reinterpret_cast<const BYTE *>(data.c_str()),
|
||||||
|
static_cast<DWORD>(data.size())) == ERROR_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
::RegCloseKey(key);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,4 +236,4 @@ auto provider_meta_handler(i_provider &provider, bool directory,
|
|||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif //_WIN32
|
#endif // defined(_WIN32)
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include "events/types/orphaned_file_processing_failed.hpp"
|
#include "events/types/orphaned_file_processing_failed.hpp"
|
||||||
#include "events/types/orphaned_source_file_detected.hpp"
|
#include "events/types/orphaned_source_file_detected.hpp"
|
||||||
#include "events/types/orphaned_source_file_removed.hpp"
|
#include "events/types/orphaned_source_file_removed.hpp"
|
||||||
|
#include "events/types/provider_invalid_version.hpp"
|
||||||
#include "events/types/provider_offline.hpp"
|
#include "events/types/provider_offline.hpp"
|
||||||
#include "events/types/provider_upload_begin.hpp"
|
#include "events/types/provider_upload_begin.hpp"
|
||||||
#include "events/types/provider_upload_end.hpp"
|
#include "events/types/provider_upload_end.hpp"
|
||||||
@ -69,8 +70,8 @@ void base_provider::add_all_items(stop_type &stop_requested) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto base_provider::create_api_file(std::string path, std::string key,
|
auto base_provider::create_api_file(std::string path, std::string key,
|
||||||
std::uint64_t size,
|
std::uint64_t size, std::uint64_t file_time)
|
||||||
std::uint64_t file_time) -> api_file {
|
-> api_file {
|
||||||
api_file file{};
|
api_file file{};
|
||||||
file.api_path = utils::path::create_api_path(path);
|
file.api_path = utils::path::create_api_path(path);
|
||||||
file.api_parent = utils::path::get_parent_api_path(file.api_path);
|
file.api_parent = utils::path::get_parent_api_path(file.api_path);
|
||||||
@ -102,8 +103,8 @@ auto base_provider::create_api_file(std::string path, std::uint64_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto base_provider::create_directory_clone_source_meta(
|
auto base_provider::create_directory_clone_source_meta(
|
||||||
const std::string &source_api_path,
|
const std::string &source_api_path, const std::string &api_path)
|
||||||
const std::string &api_path) -> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
bool exists{};
|
bool exists{};
|
||||||
@ -201,8 +202,8 @@ auto base_provider::create_directory(const std::string &api_path,
|
|||||||
return api_error::error;
|
return api_error::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto base_provider::create_file(const std::string &api_path,
|
auto base_provider::create_file(const std::string &api_path, api_meta_map &meta)
|
||||||
api_meta_map &meta) -> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -259,8 +260,9 @@ auto base_provider::create_file(const std::string &api_path,
|
|||||||
return api_error::error;
|
return api_error::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto base_provider::get_api_path_from_source(
|
auto base_provider::get_api_path_from_source(const std::string &source_path,
|
||||||
const std::string &source_path, std::string &api_path) const -> api_error {
|
std::string &api_path) const
|
||||||
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
if (source_path.empty()) {
|
if (source_path.empty()) {
|
||||||
@ -273,8 +275,9 @@ auto base_provider::get_api_path_from_source(
|
|||||||
return db3_->get_api_path(source_path, api_path);
|
return db3_->get_api_path(source_path, api_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto base_provider::get_directory_items(
|
auto base_provider::get_directory_items(const std::string &api_path,
|
||||||
const std::string &api_path, directory_item_list &list) const -> api_error {
|
directory_item_list &list) const
|
||||||
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -283,8 +286,15 @@ auto base_provider::get_directory_items(
|
|||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not exists) {
|
if (not exists) {
|
||||||
return api_error::directory_not_found;
|
res = is_file(api_path, exists);
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, api_path, res, "failed to determine if file exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists ? api_error::item_exists : api_error::directory_not_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = get_directory_items_impl(api_path, list);
|
res = get_directory_items_impl(api_path, list);
|
||||||
@ -304,20 +314,26 @@ auto base_provider::get_directory_items(
|
|||||||
(item1.api_path.compare(item2.api_path) < 0));
|
(item1.api_path.compare(item2.api_path) < 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
list.insert(list.begin(), directory_item{
|
list.insert(list.begin(),
|
||||||
"..",
|
directory_item{
|
||||||
"",
|
"..",
|
||||||
true,
|
"",
|
||||||
0U,
|
true,
|
||||||
{},
|
0U,
|
||||||
});
|
{
|
||||||
list.insert(list.begin(), directory_item{
|
{META_DIRECTORY, utils::string::from_bool(true)},
|
||||||
".",
|
},
|
||||||
"",
|
});
|
||||||
true,
|
list.insert(list.begin(),
|
||||||
0U,
|
directory_item{
|
||||||
{},
|
".",
|
||||||
});
|
"",
|
||||||
|
true,
|
||||||
|
0U,
|
||||||
|
{
|
||||||
|
{META_DIRECTORY, utils::string::from_bool(true)},
|
||||||
|
},
|
||||||
|
});
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,9 +358,10 @@ auto base_provider::get_file_size(const std::string &api_path,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto base_provider::get_filesystem_item(
|
auto base_provider::get_filesystem_item(const std::string &api_path,
|
||||||
const std::string &api_path, bool directory,
|
bool directory,
|
||||||
filesystem_item &fsi) const -> api_error {
|
filesystem_item &fsi) const
|
||||||
|
-> api_error {
|
||||||
bool exists{};
|
bool exists{};
|
||||||
auto res = is_directory(api_path, exists);
|
auto res = is_directory(api_path, exists);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
@ -377,9 +394,10 @@ auto base_provider::get_filesystem_item(
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto base_provider::get_filesystem_item_and_file(
|
auto base_provider::get_filesystem_item_and_file(const std::string &api_path,
|
||||||
const std::string &api_path, api_file &file,
|
api_file &file,
|
||||||
filesystem_item &fsi) const -> api_error {
|
filesystem_item &fsi) const
|
||||||
|
-> api_error {
|
||||||
auto res = get_file(api_path, file);
|
auto res = get_file(api_path, file);
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
return res;
|
||||||
@ -829,6 +847,14 @@ auto base_provider::start(api_item_added_callback api_item_added,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string returned_version;
|
||||||
|
std::string required_version;
|
||||||
|
if (not check_version(required_version, returned_version)) {
|
||||||
|
event_system::instance().raise<provider_invalid_version>(
|
||||||
|
function_name, required_version, returned_version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
cache_size_mgr::instance().initialize(&config_);
|
cache_size_mgr::instance().initialize(&config_);
|
||||||
|
|
||||||
polling::instance().set_callback({
|
polling::instance().set_callback({
|
||||||
|
@ -224,8 +224,7 @@ auto encrypt_provider::get_directory_items(const std::string &api_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result == api_error::directory_not_found) {
|
if (result == api_error::directory_not_found) {
|
||||||
process_directory_entry(*dir_entry.get(), cfg,
|
process_directory_entry(*dir_entry, cfg, current_api_path);
|
||||||
current_api_path);
|
|
||||||
|
|
||||||
result = db_->get_directory_api_path(dir_entry->get_path(),
|
result = db_->get_directory_api_path(dir_entry->get_path(),
|
||||||
current_api_path);
|
current_api_path);
|
||||||
@ -246,7 +245,7 @@ auto encrypt_provider::get_directory_items(const std::string &api_path,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (result == api_error::item_not_found &&
|
if (result == api_error::item_not_found &&
|
||||||
not process_directory_entry(*dir_entry.get(), cfg,
|
not process_directory_entry(*dir_entry, cfg,
|
||||||
current_api_path)) {
|
current_api_path)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -262,7 +261,6 @@ auto encrypt_provider::get_directory_items(const std::string &api_path,
|
|||||||
dir_item.api_parent = file.api_parent;
|
dir_item.api_parent = file.api_parent;
|
||||||
dir_item.api_path = file.api_path;
|
dir_item.api_path = file.api_path;
|
||||||
dir_item.directory = dir_entry->is_directory_item();
|
dir_item.directory = dir_entry->is_directory_item();
|
||||||
dir_item.resolved = true;
|
|
||||||
dir_item.size = file.file_size;
|
dir_item.size = file.file_size;
|
||||||
create_item_meta(dir_item.meta, dir_item.directory, file);
|
create_item_meta(dir_item.meta, dir_item.directory, file);
|
||||||
|
|
||||||
@ -286,20 +284,26 @@ auto encrypt_provider::get_directory_items(const std::string &api_path,
|
|||||||
(item1.api_path.compare(item2.api_path) < 0));
|
(item1.api_path.compare(item2.api_path) < 0));
|
||||||
});
|
});
|
||||||
|
|
||||||
list.insert(list.begin(), directory_item{
|
list.insert(list.begin(),
|
||||||
"..",
|
directory_item{
|
||||||
"",
|
"..",
|
||||||
true,
|
"",
|
||||||
0U,
|
true,
|
||||||
{},
|
0U,
|
||||||
});
|
{
|
||||||
list.insert(list.begin(), directory_item{
|
{META_DIRECTORY, utils::string::from_bool(true)},
|
||||||
".",
|
},
|
||||||
"",
|
});
|
||||||
true,
|
list.insert(list.begin(),
|
||||||
0U,
|
directory_item{
|
||||||
{},
|
".",
|
||||||
});
|
"",
|
||||||
|
true,
|
||||||
|
0U,
|
||||||
|
{
|
||||||
|
{META_DIRECTORY, utils::string::from_bool(true)},
|
||||||
|
},
|
||||||
|
});
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -342,13 +346,23 @@ auto encrypt_provider::get_file_list(api_file_list &list,
|
|||||||
const auto &cfg{get_encrypt_config()};
|
const auto &cfg{get_encrypt_config()};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const auto &dir_entry : utils::file::directory{cfg.path}.get_items()) {
|
using func = std::function<void(std::string path)>;
|
||||||
std::string api_path{};
|
const func process_directory = [&](std::string path) {
|
||||||
if (process_directory_entry(*dir_entry.get(), cfg, api_path)) {
|
for (const auto &dir_entry : utils::file::directory{path}.get_items()) {
|
||||||
list.emplace_back(create_api_file(
|
std::string api_path{};
|
||||||
api_path, dir_entry->is_directory_item(), dir_entry->get_path()));
|
if (dir_entry->is_directory_item()) {
|
||||||
|
process_directory_entry(*dir_entry, cfg, api_path);
|
||||||
|
process_directory(dir_entry->get_path());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process_directory_entry(*dir_entry, cfg, api_path)) {
|
||||||
|
list.emplace_back(create_api_file(
|
||||||
|
api_path, dir_entry->is_directory_item(), dir_entry->get_path()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
process_directory(cfg.path);
|
||||||
|
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
} catch (const std::exception &ex) {
|
} catch (const std::exception &ex) {
|
||||||
|
@ -43,9 +43,9 @@
|
|||||||
#include "utils/time.hpp"
|
#include "utils/time.hpp"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
[[nodiscard]] auto
|
[[nodiscard]] auto set_request_path(auto &request,
|
||||||
set_request_path(auto &request,
|
const std::string &object_name)
|
||||||
const std::string &object_name) -> repertory::api_error {
|
-> repertory::api_error {
|
||||||
request.path = object_name;
|
request.path = object_name;
|
||||||
if (request.path.substr(1U).size() > repertory::max_s3_object_name_length) {
|
if (request.path.substr(1U).size() > repertory::max_s3_object_name_length) {
|
||||||
return repertory::api_error::name_too_long;
|
return repertory::api_error::name_too_long;
|
||||||
@ -59,8 +59,9 @@ namespace repertory {
|
|||||||
s3_provider::s3_provider(app_config &config, i_http_comm &comm)
|
s3_provider::s3_provider(app_config &config, i_http_comm &comm)
|
||||||
: base_provider(config, comm) {}
|
: base_provider(config, comm) {}
|
||||||
|
|
||||||
auto s3_provider::add_if_not_found(
|
auto s3_provider::add_if_not_found(api_file &file,
|
||||||
api_file &file, const std::string &object_name) const -> api_error {
|
const std::string &object_name) const
|
||||||
|
-> api_error {
|
||||||
api_meta_map meta{};
|
api_meta_map meta{};
|
||||||
auto res{get_item_meta(file.api_path, meta)};
|
auto res{get_item_meta(file.api_path, meta)};
|
||||||
if (res == api_error::item_not_found) {
|
if (res == api_error::item_not_found) {
|
||||||
@ -88,7 +89,7 @@ auto s3_provider::convert_api_date(std::string_view date) -> std::uint64_t {
|
|||||||
1000000UL,
|
1000000UL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tm tm1 {};
|
struct tm tm1{};
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
utils::time::strptime(date_time.c_str(), "%Y-%m-%dT%T", &tm1);
|
utils::time::strptime(date_time.c_str(), "%Y-%m-%dT%T", &tm1);
|
||||||
return nanos + utils::time::windows_time_t_to_unix_time(_mkgmtime(&tm1));
|
return nanos + utils::time::windows_time_t_to_unix_time(_mkgmtime(&tm1));
|
||||||
@ -157,8 +158,9 @@ auto s3_provider::create_directory_impl(const std::string &api_path,
|
|||||||
utils::path::create_api_path(is_encrypted ? meta[META_KEY] : api_path));
|
utils::path::create_api_path(is_encrypted ? meta[META_KEY] : api_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::create_directory_paths(
|
auto s3_provider::create_directory_paths(const std::string &api_path,
|
||||||
const std::string &api_path, const std::string &key) const -> api_error {
|
const std::string &key) const
|
||||||
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
if (api_path == "/") {
|
if (api_path == "/") {
|
||||||
@ -321,8 +323,9 @@ auto s3_provider::get_directory_item_count(const std::string &api_path) const
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::get_directory_items_impl(
|
auto s3_provider::get_directory_items_impl(const std::string &api_path,
|
||||||
const std::string &api_path, directory_item_list &list) const -> api_error {
|
directory_item_list &list) const
|
||||||
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto &cfg{get_s3_config()};
|
const auto &cfg{get_s3_config()};
|
||||||
@ -480,8 +483,8 @@ auto s3_provider::get_directory_items_impl(
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::get_file(const std::string &api_path,
|
auto s3_provider::get_file(const std::string &api_path, api_file &file) const
|
||||||
api_file &file) const -> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -492,7 +495,19 @@ auto s3_provider::get_file(const std::string &api_path,
|
|||||||
get_object_info(false, api_path, is_encrypted, object_name, result),
|
get_object_info(false, api_path, is_encrypted, object_name, result),
|
||||||
};
|
};
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
if (res != api_error::item_not_found) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exists{};
|
||||||
|
res = is_directory(api_path, exists);
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, api_path, res,
|
||||||
|
"failed to determine if directory exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists ? api_error::directory_exists : api_error::item_not_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.api_path = api_path;
|
file.api_path = api_path;
|
||||||
@ -521,8 +536,8 @@ auto s3_provider::get_file(const std::string &api_path,
|
|||||||
return api_error::error;
|
return api_error::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::get_file_list(api_file_list &list,
|
auto s3_provider::get_file_list(api_file_list &list, std::string &marker) const
|
||||||
std::string &marker) const -> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -612,8 +627,9 @@ auto s3_provider::get_file_list(api_file_list &list,
|
|||||||
return api_error::error;
|
return api_error::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::get_last_modified(
|
auto s3_provider::get_last_modified(bool directory,
|
||||||
bool directory, const std::string &api_path) const -> std::uint64_t {
|
const std::string &api_path) const
|
||||||
|
-> std::uint64_t {
|
||||||
bool is_encrypted{};
|
bool is_encrypted{};
|
||||||
std::string object_name;
|
std::string object_name;
|
||||||
head_object_result result{};
|
head_object_result result{};
|
||||||
@ -623,9 +639,10 @@ auto s3_provider::get_last_modified(
|
|||||||
: utils::time::get_time_now();
|
: utils::time::get_time_now();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::get_object_info(
|
auto s3_provider::get_object_info(bool directory, const std::string &api_path,
|
||||||
bool directory, const std::string &api_path, bool &is_encrypted,
|
bool &is_encrypted, std::string &object_name,
|
||||||
std::string &object_name, head_object_result &result) const -> api_error {
|
head_object_result &result) const
|
||||||
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -685,10 +702,12 @@ auto s3_provider::get_object_info(
|
|||||||
return api_error::error;
|
return api_error::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::get_object_list(
|
auto s3_provider::get_object_list(std::string &response_data,
|
||||||
std::string &response_data, long &response_code,
|
long &response_code,
|
||||||
std::optional<std::string> delimiter, std::optional<std::string> prefix,
|
std::optional<std::string> delimiter,
|
||||||
std::optional<std::string> token) const -> bool {
|
std::optional<std::string> prefix,
|
||||||
|
std::optional<std::string> token) const
|
||||||
|
-> bool {
|
||||||
curl::requests::http_get get{};
|
curl::requests::http_get get{};
|
||||||
get.allow_timeout = true;
|
get.allow_timeout = true;
|
||||||
get.aws_service = "aws:amz:" + get_s3_config().region + ":s3";
|
get.aws_service = "aws:amz:" + get_s3_config().region + ":s3";
|
||||||
@ -716,8 +735,8 @@ auto s3_provider::get_total_drive_space() const -> std::uint64_t {
|
|||||||
return std::numeric_limits<std::int64_t>::max() / std::int64_t(2);
|
return std::numeric_limits<std::int64_t>::max() / std::int64_t(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::is_directory(const std::string &api_path,
|
auto s3_provider::is_directory(const std::string &api_path, bool &exists) const
|
||||||
bool &exists) const -> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -745,8 +764,8 @@ auto s3_provider::is_directory(const std::string &api_path,
|
|||||||
return api_error::error;
|
return api_error::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::is_file(const std::string &api_path,
|
auto s3_provider::is_file(const std::string &api_path, bool &exists) const
|
||||||
bool &exists) const -> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1004,8 +1023,8 @@ auto s3_provider::rename_file(const std::string & /* from_api_path */,
|
|||||||
return api_error::not_implemented;
|
return api_error::not_implemented;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto s3_provider::set_meta_key(const std::string &api_path,
|
auto s3_provider::set_meta_key(const std::string &api_path, api_meta_map &meta)
|
||||||
api_meta_map &meta) -> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
const auto &cfg{get_s3_config()};
|
const auto &cfg{get_s3_config()};
|
||||||
|
@ -32,8 +32,8 @@
|
|||||||
#include "providers/base_provider.hpp"
|
#include "providers/base_provider.hpp"
|
||||||
#include "providers/s3/s3_provider.hpp"
|
#include "providers/s3/s3_provider.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
#include "utils/common.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
#include "utils/file_utils.hpp"
|
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
#include "utils/polling.hpp"
|
#include "utils/polling.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
@ -63,6 +63,54 @@ namespace repertory {
|
|||||||
sia_provider::sia_provider(app_config &config, i_http_comm &comm)
|
sia_provider::sia_provider(app_config &config, i_http_comm &comm)
|
||||||
: base_provider(config, comm) {}
|
: base_provider(config, comm) {}
|
||||||
|
|
||||||
|
auto sia_provider::check_version(std::string &required_version,
|
||||||
|
std::string &returned_version) const -> bool {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
required_version = RENTERD_MIN_VERSION;
|
||||||
|
|
||||||
|
try {
|
||||||
|
curl::requests::http_get get{};
|
||||||
|
get.allow_timeout = true;
|
||||||
|
get.path = "/api/bus/state";
|
||||||
|
|
||||||
|
nlohmann::json state_data;
|
||||||
|
std::string error_data;
|
||||||
|
get.response_handler = [&error_data, &state_data](auto &&data,
|
||||||
|
long response_code) {
|
||||||
|
if (response_code == http_error_codes::ok) {
|
||||||
|
state_data = nlohmann::json::parse(data.begin(), data.end());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_data = std::string(data.begin(), data.end());
|
||||||
|
};
|
||||||
|
|
||||||
|
long response_code{};
|
||||||
|
stop_type stop_requested{};
|
||||||
|
if (not get_comm().make_request(get, response_code, stop_requested)) {
|
||||||
|
utils::error::raise_error(function_name, response_code,
|
||||||
|
"failed to check state");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response_code != http_error_codes::ok) {
|
||||||
|
utils::error::raise_error(
|
||||||
|
function_name, response_code,
|
||||||
|
fmt::format("failed to check state|response|{}", error_data));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
returned_version = state_data.at("version").get<std::string>().substr(1U);
|
||||||
|
return utils::compare_version_strings(returned_version, required_version) >=
|
||||||
|
0;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
utils::error::raise_error(function_name, e, "failed to check version");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto sia_provider::create_directory_impl(const std::string &api_path,
|
auto sia_provider::create_directory_impl(const std::string &api_path,
|
||||||
api_meta_map & /* meta */)
|
api_meta_map & /* meta */)
|
||||||
-> api_error {
|
-> api_error {
|
||||||
@ -70,7 +118,7 @@ auto sia_provider::create_directory_impl(const std::string &api_path,
|
|||||||
|
|
||||||
curl::requests::http_put_file put_file{};
|
curl::requests::http_put_file put_file{};
|
||||||
put_file.allow_timeout = true;
|
put_file.allow_timeout = true;
|
||||||
put_file.path = "/api/worker/objects" + api_path + "/";
|
put_file.path = "/api/worker/object" + api_path + "/";
|
||||||
put_file.query["bucket"] = get_bucket(get_sia_config());
|
put_file.query["bucket"] = get_bucket(get_sia_config());
|
||||||
|
|
||||||
std::string error_data;
|
std::string error_data;
|
||||||
@ -101,21 +149,67 @@ auto sia_provider::create_directory_impl(const std::string &api_path,
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto sia_provider::create_directory_key(const std::string &api_path) const
|
||||||
|
-> api_error {
|
||||||
|
auto parent_api_path = utils::path::get_parent_api_path(api_path);
|
||||||
|
|
||||||
|
json object_list;
|
||||||
|
if (not get_object_list(parent_api_path, object_list)) {
|
||||||
|
return api_error::comm_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not object_list.contains("objects")) {
|
||||||
|
return api_error::directory_not_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &list = object_list.at("objects");
|
||||||
|
if (std::ranges::find_if(list, [&api_path](auto &&entry) -> bool {
|
||||||
|
return entry.at("key").template get<std::string>() == api_path + '/';
|
||||||
|
}) == list.end()) {
|
||||||
|
return api_error::directory_not_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
api_meta_map meta;
|
||||||
|
return const_cast<sia_provider *>(this)->create_directory_impl(api_path,
|
||||||
|
meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sia_provider::ensure_directory_exists(const std::string &api_path) const
|
||||||
|
-> api_error {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
bool exists{};
|
||||||
|
auto res{is_directory(api_path, exists)};
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(function_name, api_path, res,
|
||||||
|
"failed detect existing directory");
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not exists) {
|
||||||
|
utils::error::raise_api_path_error(function_name, api_path, res,
|
||||||
|
"directory not found");
|
||||||
|
return api_error::directory_not_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
return api_error::success;
|
||||||
|
}
|
||||||
|
|
||||||
auto sia_provider::get_directory_item_count(const std::string &api_path) const
|
auto sia_provider::get_directory_item_count(const std::string &api_path) const
|
||||||
-> std::uint64_t {
|
-> std::uint64_t {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
json object_list{};
|
json object_list;
|
||||||
if (not get_object_list(api_path, object_list)) {
|
if (not get_object_list(api_path, object_list)) {
|
||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t item_count{};
|
std::uint64_t item_count{};
|
||||||
if (object_list.contains("entries")) {
|
if (object_list.contains("objects")) {
|
||||||
for (const auto &entry : object_list.at("entries")) {
|
for (const auto &entry : object_list.at("objects")) {
|
||||||
try {
|
try {
|
||||||
auto name{entry.at("name").get<std::string>()};
|
auto name{entry.at("key").get<std::string>()};
|
||||||
auto entry_api_path{utils::path::create_api_path(name)};
|
auto entry_api_path{utils::path::create_api_path(name)};
|
||||||
if (utils::string::ends_with(name, "/") &&
|
if (utils::string::ends_with(name, "/") &&
|
||||||
(entry_api_path == api_path)) {
|
(entry_api_path == api_path)) {
|
||||||
@ -144,57 +238,34 @@ auto sia_provider::get_directory_items_impl(const std::string &api_path,
|
|||||||
-> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
json object_list{};
|
json object_list;
|
||||||
if (not get_object_list(api_path, object_list)) {
|
if (not get_object_list(api_path, object_list)) {
|
||||||
return api_error::comm_error;
|
return api_error::comm_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object_list.contains("entries")) {
|
iterate_objects(
|
||||||
for (const auto &entry : object_list.at("entries")) {
|
api_path, object_list,
|
||||||
try {
|
[&](auto &&entry_api_path, auto &&directory, auto &&entry) {
|
||||||
auto name{entry.at("name").get<std::string>()};
|
api_meta_map meta;
|
||||||
auto entry_api_path{utils::path::create_api_path(name)};
|
auto res{get_item_meta(entry_api_path, meta)};
|
||||||
|
if (res != api_error::success) {
|
||||||
auto directory{utils::string::ends_with(name, "/")};
|
utils::error::raise_api_path_error(function_name, entry_api_path, res,
|
||||||
if (directory && (entry_api_path == api_path)) {
|
"failed to get item meta");
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
api_file file{};
|
auto file = create_api_file(
|
||||||
api_meta_map meta{};
|
entry_api_path,
|
||||||
if (get_item_meta(entry_api_path, meta) == api_error::item_not_found) {
|
directory ? 0U : entry["size"].template get<std::uint64_t>(), meta);
|
||||||
file = create_api_file(entry_api_path, "",
|
|
||||||
directory ? 0U
|
|
||||||
: entry["size"].get<std::uint64_t>(),
|
|
||||||
get_last_modified(entry));
|
|
||||||
get_api_item_added()(directory, file);
|
|
||||||
auto res{get_item_meta(entry_api_path, meta)};
|
|
||||||
if (res != api_error::success) {
|
|
||||||
utils::error::raise_api_path_error(function_name, entry_api_path,
|
|
||||||
res, "failed to get item meta");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
file = create_api_file(
|
|
||||||
entry_api_path,
|
|
||||||
directory ? 0U : entry["size"].get<std::uint64_t>(), meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
directory_item dir_item{};
|
directory_item dir_item{};
|
||||||
dir_item.api_parent = file.api_parent;
|
dir_item.api_parent = file.api_parent;
|
||||||
dir_item.api_path = file.api_path;
|
dir_item.api_path = file.api_path;
|
||||||
dir_item.directory = directory;
|
dir_item.directory = directory;
|
||||||
dir_item.meta = meta;
|
dir_item.meta = meta;
|
||||||
dir_item.resolved = true;
|
|
||||||
dir_item.size = file.file_size;
|
dir_item.size = file.file_size;
|
||||||
list.emplace_back(std::move(dir_item));
|
list.emplace_back(std::move(dir_item));
|
||||||
} catch (const std::exception &e) {
|
});
|
||||||
utils::error::raise_api_path_error(function_name, api_path, e,
|
|
||||||
"failed to process entry|" +
|
|
||||||
entry.dump());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
@ -207,22 +278,28 @@ auto sia_provider::get_file(const std::string &api_path, api_file &file) const
|
|||||||
json file_data{};
|
json file_data{};
|
||||||
auto res{get_object_info(api_path, file_data)};
|
auto res{get_object_info(api_path, file_data)};
|
||||||
if (res != api_error::success) {
|
if (res != api_error::success) {
|
||||||
return res;
|
if (res != api_error::item_not_found) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exists{};
|
||||||
|
res = is_directory(api_path, exists);
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, api_path, res,
|
||||||
|
"failed to determine if directory exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists ? api_error::directory_exists : api_error::item_not_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto slabs{file_data["object"]["Slabs"]};
|
|
||||||
auto size{
|
auto size{
|
||||||
std::accumulate(
|
file_data.at("size").get<std::uint64_t>(),
|
||||||
slabs.begin(), slabs.end(), std::uint64_t(0U),
|
|
||||||
[](auto &&total_size, const json &slab) -> std::uint64_t {
|
|
||||||
return total_size + slab["Length"].get<std::uint64_t>();
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
api_meta_map meta{};
|
api_meta_map meta{};
|
||||||
if (get_item_meta(api_path, meta) == api_error::item_not_found) {
|
if (get_item_meta(api_path, meta) == api_error::item_not_found) {
|
||||||
file = create_api_file(api_path, "", size,
|
file = create_api_file(api_path, "", size, get_last_modified(file_data));
|
||||||
get_last_modified(file_data["object"]));
|
|
||||||
get_api_item_added()(false, file);
|
get_api_item_added()(false, file);
|
||||||
} else {
|
} else {
|
||||||
file = create_api_file(api_path, size, meta);
|
file = create_api_file(api_path, size, meta);
|
||||||
@ -237,73 +314,45 @@ auto sia_provider::get_file(const std::string &api_path, api_file &file) const
|
|||||||
return api_error::error;
|
return api_error::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sia_provider::get_file_list(api_file_list &list,
|
auto sia_provider::get_file_list(api_file_list &list, std::string &marker) const
|
||||||
std::string & /* marker */) const
|
|
||||||
-> api_error {
|
-> api_error {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
using dir_func = std::function<api_error(std::string api_path)>;
|
try {
|
||||||
const dir_func get_files_in_dir = [&](std::string api_path) -> api_error {
|
json object_list;
|
||||||
try {
|
if (not get_object_list("", object_list, marker)) {
|
||||||
nlohmann::json object_list{};
|
return api_error::comm_error;
|
||||||
if (not get_object_list(api_path, object_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>()};
|
|
||||||
auto entry_api_path{utils::path::create_api_path(name)};
|
|
||||||
|
|
||||||
if (utils::string::ends_with(name, "/")) {
|
|
||||||
if (entry_api_path == utils::path::create_api_path(api_path)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
api_meta_map meta{};
|
|
||||||
if (get_item_meta(entry_api_path, meta) ==
|
|
||||||
api_error::item_not_found) {
|
|
||||||
auto dir{
|
|
||||||
create_api_file(entry_api_path, "", 0U,
|
|
||||||
get_last_modified(entry)),
|
|
||||||
};
|
|
||||||
get_api_item_added()(true, dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res{get_files_in_dir(entry_api_path)};
|
|
||||||
if (res != api_error::success) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
api_file file{};
|
|
||||||
api_meta_map meta{};
|
|
||||||
if (get_item_meta(entry_api_path, meta) ==
|
|
||||||
api_error::item_not_found) {
|
|
||||||
file = create_api_file(entry_api_path, "",
|
|
||||||
entry["size"].get<std::uint64_t>(),
|
|
||||||
get_last_modified(entry));
|
|
||||||
get_api_item_added()(false, file);
|
|
||||||
} else {
|
|
||||||
file = create_api_file(entry_api_path,
|
|
||||||
entry["size"].get<std::uint64_t>(), meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
list.emplace_back(std::move(file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return api_error::success;
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
utils::error::raise_api_path_error(function_name, api_path, e,
|
|
||||||
"failed to process directory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return api_error::error;
|
iterate_objects("/", object_list,
|
||||||
};
|
[&](auto &&entry_api_path, auto &&directory, auto &&entry) {
|
||||||
|
if (directory) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return get_files_in_dir("");
|
api_meta_map meta;
|
||||||
|
auto res{get_item_meta(entry_api_path, meta)};
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, entry_api_path, res,
|
||||||
|
"failed to get item meta");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.emplace_back(create_api_file(
|
||||||
|
entry_api_path,
|
||||||
|
entry["size"].template get<std::uint64_t>(), meta));
|
||||||
|
});
|
||||||
|
|
||||||
|
marker = object_list.at("nextMarker").get<std::string>();
|
||||||
|
return object_list.at("hasMore").get<bool>() ? api_error::more_data
|
||||||
|
: api_error::success;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
utils::error::raise_api_path_error(function_name, "/", e,
|
||||||
|
"failed to process directory");
|
||||||
|
}
|
||||||
|
|
||||||
|
return api_error::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sia_provider::get_object_info(const std::string &api_path,
|
auto sia_provider::get_object_info(const std::string &api_path,
|
||||||
@ -313,8 +362,9 @@ auto sia_provider::get_object_info(const std::string &api_path,
|
|||||||
try {
|
try {
|
||||||
curl::requests::http_get get{};
|
curl::requests::http_get get{};
|
||||||
get.allow_timeout = true;
|
get.allow_timeout = true;
|
||||||
get.path = "/api/bus/objects" + api_path;
|
get.path = "/api/bus/object" + api_path;
|
||||||
get.query["bucket"] = get_bucket(get_sia_config());
|
get.query["bucket"] = get_bucket(get_sia_config());
|
||||||
|
get.query["onlymetadata"] = "true";
|
||||||
|
|
||||||
std::string error_data;
|
std::string error_data;
|
||||||
get.response_handler = [&error_data, &object_info](auto &&data,
|
get.response_handler = [&error_data, &object_info](auto &&data,
|
||||||
@ -354,7 +404,9 @@ auto sia_provider::get_object_info(const std::string &api_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto sia_provider::get_object_list(const std::string &api_path,
|
auto sia_provider::get_object_list(const std::string &api_path,
|
||||||
nlohmann::json &object_list) const -> bool {
|
nlohmann::json &object_list,
|
||||||
|
std::optional<std::string> marker) const
|
||||||
|
-> bool {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -362,6 +414,12 @@ auto sia_provider::get_object_list(const std::string &api_path,
|
|||||||
get.allow_timeout = true;
|
get.allow_timeout = true;
|
||||||
get.path = "/api/bus/objects" + api_path + "/";
|
get.path = "/api/bus/objects" + api_path + "/";
|
||||||
get.query["bucket"] = get_bucket(get_sia_config());
|
get.query["bucket"] = get_bucket(get_sia_config());
|
||||||
|
if (marker.has_value()) {
|
||||||
|
get.query["limit"] = "1000";
|
||||||
|
get.query["marker"] = marker.value();
|
||||||
|
} else {
|
||||||
|
get.query["delimiter"] = "/";
|
||||||
|
}
|
||||||
|
|
||||||
std::string error_data;
|
std::string error_data;
|
||||||
get.response_handler = [&error_data, &object_list](auto &&data,
|
get.response_handler = [&error_data, &object_list](auto &&data,
|
||||||
@ -405,7 +463,7 @@ auto sia_provider::get_total_drive_space() const -> std::uint64_t {
|
|||||||
try {
|
try {
|
||||||
curl::requests::http_get get{};
|
curl::requests::http_get get{};
|
||||||
get.allow_timeout = true;
|
get.allow_timeout = true;
|
||||||
get.path = "/api/autopilot/config";
|
get.path = "/api/bus/autopilot";
|
||||||
get.query["bucket"] = get_bucket(get_sia_config());
|
get.query["bucket"] = get_bucket(get_sia_config());
|
||||||
|
|
||||||
json config_data;
|
json config_data;
|
||||||
@ -455,17 +513,26 @@ auto sia_provider::is_directory(const std::string &api_path, bool &exists) const
|
|||||||
|
|
||||||
exists = false;
|
exists = false;
|
||||||
|
|
||||||
json object_list{};
|
json file_data{};
|
||||||
if (not get_object_list(utils::path::get_parent_api_path(api_path),
|
auto res{get_object_info(api_path + '/', file_data)};
|
||||||
object_list)) {
|
if (res == api_error::item_not_found) {
|
||||||
return api_error::comm_error;
|
if (create_directory_key(api_path) == api_error::success) {
|
||||||
|
exists = true;
|
||||||
|
return api_error::success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exists = object_list.contains("entries") &&
|
if (res == api_error::directory_not_found ||
|
||||||
std::ranges::find_if(object_list.at("entries"),
|
res == api_error::item_not_found) {
|
||||||
[&api_path](auto &&entry) -> bool {
|
return api_error::success;
|
||||||
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;
|
return api_error::success;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
utils::error::raise_api_path_error(
|
utils::error::raise_api_path_error(
|
||||||
@ -481,6 +548,7 @@ auto sia_provider::is_file(const std::string &api_path, bool &exists) const
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
exists = false;
|
exists = false;
|
||||||
|
|
||||||
if (api_path == "/") {
|
if (api_path == "/") {
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
@ -495,7 +563,8 @@ auto sia_provider::is_file(const std::string &api_path, bool &exists) const
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
exists = not file_data.contains("entries");
|
exists = not utils::string::ends_with(
|
||||||
|
file_data.at("key").get<std::string>(), "/");
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
utils::error::raise_api_path_error(function_name, api_path, e,
|
utils::error::raise_api_path_error(function_name, api_path, e,
|
||||||
@ -551,6 +620,52 @@ auto sia_provider::is_online() const -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sia_provider::iterate_objects(
|
||||||
|
const std::string &api_path, const json &object_list,
|
||||||
|
std::function<void(const std::string &, bool, json)> handle_entry) const {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
if (not object_list.contains("objects")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &entry : object_list.at("objects")) {
|
||||||
|
try {
|
||||||
|
auto name{entry.at("key").get<std::string>()};
|
||||||
|
|
||||||
|
auto directory{utils::string::ends_with(name, "/")};
|
||||||
|
auto entry_api_path{utils::path::create_api_path(name)};
|
||||||
|
|
||||||
|
{
|
||||||
|
api_meta_map meta{};
|
||||||
|
if (get_item_meta(entry_api_path, meta) == api_error::item_not_found) {
|
||||||
|
auto file = create_api_file(
|
||||||
|
entry_api_path, "",
|
||||||
|
directory ? 0U : entry["size"].get<std::uint64_t>(),
|
||||||
|
get_last_modified(entry));
|
||||||
|
if (directory) {
|
||||||
|
auto res{ensure_directory_exists(entry_api_path)};
|
||||||
|
if (res != api_error::success) {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, entry_api_path, res,
|
||||||
|
"failed detect existing directory");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_api_item_added()(directory, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_entry(entry_api_path, directory, entry);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
utils::error::raise_api_path_error(
|
||||||
|
function_name, api_path, e,
|
||||||
|
fmt::format("failed to process entry|{}", entry.dump()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto sia_provider::read_file_bytes(const std::string &api_path,
|
auto sia_provider::read_file_bytes(const std::string &api_path,
|
||||||
std::size_t size, std::uint64_t offset,
|
std::size_t size, std::uint64_t offset,
|
||||||
data_buffer &buffer,
|
data_buffer &buffer,
|
||||||
@ -559,8 +674,9 @@ auto sia_provider::read_file_bytes(const std::string &api_path,
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
curl::requests::http_get get{};
|
curl::requests::http_get get{};
|
||||||
get.path = "/api/worker/objects" + api_path;
|
get.path = "/api/worker/object" + api_path;
|
||||||
get.query["bucket"] = get_bucket(get_sia_config());
|
get.query["bucket"] = get_bucket(get_sia_config());
|
||||||
|
get.headers["accept"] = "application/octet-stream";
|
||||||
get.range = {{
|
get.range = {{
|
||||||
offset,
|
offset,
|
||||||
offset + size - 1U,
|
offset + size - 1U,
|
||||||
@ -622,7 +738,7 @@ auto sia_provider::remove_directory_impl(const std::string &api_path)
|
|||||||
|
|
||||||
curl::requests::http_delete del{};
|
curl::requests::http_delete del{};
|
||||||
del.allow_timeout = true;
|
del.allow_timeout = true;
|
||||||
del.path = "/api/bus/objects" + api_path + "/";
|
del.path = "/api/bus/object" + api_path + "/";
|
||||||
del.query["bucket"] = get_bucket(get_sia_config());
|
del.query["bucket"] = get_bucket(get_sia_config());
|
||||||
|
|
||||||
std::string error_data;
|
std::string error_data;
|
||||||
@ -658,7 +774,7 @@ auto sia_provider::remove_file_impl(const std::string &api_path) -> api_error {
|
|||||||
|
|
||||||
curl::requests::http_delete del{};
|
curl::requests::http_delete del{};
|
||||||
del.allow_timeout = true;
|
del.allow_timeout = true;
|
||||||
del.path = "/api/bus/objects" + api_path;
|
del.path = "/api/bus/object" + api_path;
|
||||||
del.query["bucket"] = get_bucket(get_sia_config());
|
del.query["bucket"] = get_bucket(get_sia_config());
|
||||||
|
|
||||||
std::string error_data;
|
std::string error_data;
|
||||||
@ -697,12 +813,12 @@ auto sia_provider::rename_file(const std::string &from_api_path,
|
|||||||
try {
|
try {
|
||||||
curl::requests::http_post post{};
|
curl::requests::http_post post{};
|
||||||
post.json = nlohmann::json({
|
post.json = nlohmann::json({
|
||||||
|
{"bucket", get_bucket(get_sia_config())},
|
||||||
{"from", from_api_path},
|
{"from", from_api_path},
|
||||||
{"to", to_api_path},
|
{"to", to_api_path},
|
||||||
{"mode", "single"},
|
{"mode", "single"},
|
||||||
});
|
});
|
||||||
post.path = "/api/bus/objects/rename";
|
post.path = "/api/bus/objects/rename";
|
||||||
post.query["bucket"] = get_bucket(get_sia_config());
|
|
||||||
|
|
||||||
std::string error_data;
|
std::string error_data;
|
||||||
post.response_handler = [&error_data](auto &&data, long response_code) {
|
post.response_handler = [&error_data](auto &&data, long response_code) {
|
||||||
@ -770,8 +886,9 @@ auto sia_provider::upload_file_impl(const std::string &api_path,
|
|||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
curl::requests::http_put_file put_file{};
|
curl::requests::http_put_file put_file{};
|
||||||
put_file.path = "/api/worker/objects" + api_path;
|
put_file.path = "/api/worker/object" + api_path;
|
||||||
put_file.query["bucket"] = get_bucket(get_sia_config());
|
put_file.query["bucket"] = get_bucket(get_sia_config());
|
||||||
|
put_file.headers["content-type"] = "application/octet-stream";
|
||||||
put_file.source_path = source_path;
|
put_file.source_path = source_path;
|
||||||
|
|
||||||
std::string error_data;
|
std::string error_data;
|
||||||
|
@ -22,8 +22,6 @@
|
|||||||
#include "rpc/client/client.hpp"
|
#include "rpc/client/client.hpp"
|
||||||
|
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/base64.hpp"
|
|
||||||
#include "utils/utils.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
client::client(rpc_host_info host_info) : host_info_(std::move(host_info)) {}
|
client::client(rpc_host_info host_info) : host_info_(std::move(host_info)) {}
|
||||||
|
@ -1,216 +1,189 @@
|
|||||||
/*
|
/*
|
||||||
Copyright <2018-2025> <scott.e.graves@protonmail.com>
|
Copyright <2018-2025> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in all
|
||||||
copies or substantial portions of the Software.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "rpc/server/server.hpp"
|
#include "rpc/server/server.hpp"
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
#include "events/event_system.hpp"
|
#include "events/event_system.hpp"
|
||||||
#include "events/types/service_start_begin.hpp"
|
#include "events/types/service_start_begin.hpp"
|
||||||
#include "events/types/service_start_end.hpp"
|
#include "events/types/service_start_end.hpp"
|
||||||
#include "events/types/service_stop_begin.hpp"
|
#include "events/types/service_stop_begin.hpp"
|
||||||
#include "events/types/service_stop_end.hpp"
|
#include "events/types/service_stop_end.hpp"
|
||||||
#include "events/types/unmount_requested.hpp"
|
#include "events/types/unmount_requested.hpp"
|
||||||
#include "utils/base64.hpp"
|
#include "rpc/common.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
#include "utils/string.hpp"
|
|
||||||
|
namespace repertory {
|
||||||
namespace repertory {
|
server::server(app_config &config) : config_(config) {}
|
||||||
server::server(app_config &config) : config_(config) {}
|
|
||||||
|
void server::handle_get_config(const httplib::Request & /*req*/,
|
||||||
auto server::check_authorization(const httplib::Request &req) -> bool {
|
httplib::Response &res) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
auto data = config_.get_json();
|
||||||
|
clean_json_config(config_.get_provider_type(), data);
|
||||||
if (config_.get_api_auth().empty() || config_.get_api_user().empty()) {
|
res.set_content(data.dump(), "application/json");
|
||||||
utils::error::raise_error(function_name,
|
res.status = http_error_codes::ok;
|
||||||
"authorization user or password is not set");
|
}
|
||||||
return false;
|
|
||||||
}
|
void server::handle_get_config_value_by_name(const httplib::Request &req,
|
||||||
|
httplib::Response &res) {
|
||||||
auto authorization = req.get_header_value("Authorization");
|
auto name = req.get_param_value("name");
|
||||||
if (authorization.empty()) {
|
auto data = json({{
|
||||||
utils::error::raise_error(function_name, "Authorization header is not set");
|
"value",
|
||||||
return false;
|
clean_json_value(name, config_.get_value_by_name(name)),
|
||||||
}
|
}});
|
||||||
|
res.set_content(data.dump(), "application/json");
|
||||||
auto auth_parts = utils::string::split(authorization, ' ', true);
|
res.status = http_error_codes::ok;
|
||||||
if (auth_parts.empty()) {
|
}
|
||||||
utils::error::raise_error(function_name, "Authorization header is empty");
|
|
||||||
return false;
|
void server::handle_set_config_value_by_name(const httplib::Request &req,
|
||||||
}
|
httplib::Response &res) {
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
auto auth_type = auth_parts[0U];
|
auto value = req.get_param_value("value");
|
||||||
if (auth_type != "Basic") {
|
|
||||||
utils::error::raise_error(function_name, "Authorization is not Basic");
|
json data = {{
|
||||||
return false;
|
"value",
|
||||||
}
|
clean_json_value(name, config_.set_value_by_name(name, value)),
|
||||||
|
}};
|
||||||
auto data = macaron::Base64::Decode(authorization.substr(6U));
|
res.set_content(data.dump(), "application/json");
|
||||||
auto auth_str = std::string(data.begin(), data.end());
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
auto auth = utils::string::split(auth_str, ':', false);
|
|
||||||
if (auth.size() < 2U) {
|
void server::handle_unmount(const httplib::Request & /*req*/,
|
||||||
utils::error::raise_error(function_name, "Authorization is not valid");
|
httplib::Response &res) {
|
||||||
return false;
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
}
|
|
||||||
|
event_system::instance().raise<unmount_requested>(function_name);
|
||||||
auto user = auth.at(0U);
|
res.status = http_error_codes::ok;
|
||||||
auth.erase(auth.begin());
|
}
|
||||||
|
|
||||||
auto pwd = utils::string::join(auth, ':');
|
void server::initialize(httplib::Server &inst) {
|
||||||
if ((user != config_.get_api_user()) || (pwd != config_.get_api_auth())) {
|
inst.Get("/api/v1/" + rpc_method::get_config, [this](auto &&req, auto &&res) {
|
||||||
utils::error::raise_error(function_name, "Authorization failed");
|
handle_get_config(std::forward<decltype(req)>(req),
|
||||||
return false;
|
std::forward<decltype(res)>(res));
|
||||||
}
|
});
|
||||||
|
|
||||||
return true;
|
inst.Get("/api/v1/" + rpc_method::get_config_value_by_name,
|
||||||
}
|
[this](auto &&req, auto &&res) {
|
||||||
|
handle_get_config_value_by_name(std::forward<decltype(req)>(req),
|
||||||
void server::handle_get_config(const httplib::Request & /*req*/,
|
std::forward<decltype(res)>(res));
|
||||||
httplib::Response &res) {
|
});
|
||||||
auto data = config_.get_json();
|
|
||||||
res.set_content(data.dump(), "application/json");
|
inst.Post("/api/v1/" + rpc_method::set_config_value_by_name,
|
||||||
res.status = http_error_codes::ok;
|
[this](auto &&req, auto &&res) {
|
||||||
}
|
handle_set_config_value_by_name(std::forward<decltype(req)>(req),
|
||||||
|
std::forward<decltype(res)>(res));
|
||||||
void server::handle_get_config_value_by_name(const httplib::Request &req,
|
});
|
||||||
httplib::Response &res) {
|
|
||||||
auto name = req.get_param_value("name");
|
inst.Post("/api/v1/" + rpc_method::unmount, [this](auto &&req, auto &&res) {
|
||||||
auto data = json({{"value", config_.get_value_by_name(name)}});
|
handle_unmount(std::forward<decltype(req)>(req),
|
||||||
res.set_content(data.dump(), "application/json");
|
std::forward<decltype(res)>(res));
|
||||||
res.status = http_error_codes::ok;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void server::handle_set_config_value_by_name(const httplib::Request &req,
|
void server::start() {
|
||||||
httplib::Response &res) {
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
auto name = req.get_param_value("name");
|
|
||||||
auto value = req.get_param_value("value");
|
mutex_lock lock(start_stop_mutex_);
|
||||||
|
if (server_thread_) {
|
||||||
json data = {{"value", config_.set_value_by_name(name, value)}};
|
return;
|
||||||
res.set_content(data.dump(), "application/json");
|
}
|
||||||
res.status = http_error_codes::ok;
|
|
||||||
}
|
event_system::instance().raise<service_start_begin>(function_name, "server");
|
||||||
|
|
||||||
void server::handle_unmount(const httplib::Request & /*req*/,
|
server_ = std::make_unique<httplib::Server>();
|
||||||
httplib::Response &res) {
|
|
||||||
event_system::instance().raise<unmount_requested>();
|
server_->set_exception_handler([](const httplib::Request &req,
|
||||||
res.status = http_error_codes::ok;
|
httplib::Response &res,
|
||||||
}
|
std::exception_ptr ptr) {
|
||||||
|
json data = {{"path", req.path}};
|
||||||
void server::initialize(httplib::Server &inst) {
|
|
||||||
inst.Get("/api/v1/" + rpc_method::get_config, [this](auto &&req, auto &&res) {
|
try {
|
||||||
handle_get_config(std::forward<decltype(req)>(req),
|
std::rethrow_exception(ptr);
|
||||||
std::forward<decltype(res)>(res));
|
} catch (std::exception &e) {
|
||||||
});
|
data["error"] = (e.what() == nullptr) ? "unknown error" : e.what();
|
||||||
|
utils::error::raise_error(function_name, e,
|
||||||
inst.Get("/api/v1/" + rpc_method::get_config_value_by_name,
|
"failed request: " + req.path);
|
||||||
[this](auto &&req, auto &&res) {
|
} catch (...) {
|
||||||
handle_get_config_value_by_name(std::forward<decltype(req)>(req),
|
data["error"] = "unknown error";
|
||||||
std::forward<decltype(res)>(res));
|
utils::error::raise_error(function_name, "unknown error",
|
||||||
});
|
"failed request: " + req.path);
|
||||||
|
}
|
||||||
inst.Post("/api/v1/" + rpc_method::set_config_value_by_name,
|
|
||||||
[this](auto &&req, auto &&res) {
|
res.set_content(data.dump(), "application/json");
|
||||||
handle_set_config_value_by_name(std::forward<decltype(req)>(req),
|
res.status = http_error_codes::internal_error;
|
||||||
std::forward<decltype(res)>(res));
|
});
|
||||||
});
|
|
||||||
|
server_->set_pre_routing_handler(
|
||||||
inst.Post("/api/v1/" + rpc_method::unmount, [this](auto &&req, auto &&res) {
|
[this](auto &&req, auto &&res) -> httplib::Server::HandlerResponse {
|
||||||
handle_unmount(std::forward<decltype(req)>(req),
|
if (rpc::check_authorization(config_, req)) {
|
||||||
std::forward<decltype(res)>(res));
|
return httplib::Server::HandlerResponse::Unhandled;
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
res.status = http_error_codes::unauthorized;
|
||||||
void server::start() {
|
return httplib::Server::HandlerResponse::Handled;
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
});
|
||||||
|
|
||||||
mutex_lock lock(start_stop_mutex_);
|
initialize(*server_);
|
||||||
if (server_thread_) {
|
|
||||||
return;
|
server_thread_ = std::make_unique<std::thread>([this]() {
|
||||||
}
|
server_->set_socket_options([](auto &&sock) {
|
||||||
|
#if defined(_WIN32)
|
||||||
event_system::instance().raise<service_start_begin>(function_name, "server");
|
int enable{1};
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
||||||
server_ = std::make_unique<httplib::Server>();
|
reinterpret_cast<const char *>(&enable), sizeof(enable));
|
||||||
|
#else // !defined(_WIN32)
|
||||||
server_->set_exception_handler([](const httplib::Request &req,
|
linger opt{1, 0};
|
||||||
httplib::Response &res,
|
setsockopt(sock, SOL_SOCKET, SO_LINGER,
|
||||||
std::exception_ptr ptr) {
|
reinterpret_cast<const char *>(&opt), sizeof(opt));
|
||||||
json data = {{"path", req.path}};
|
#endif // defined(_WIN32)
|
||||||
|
});
|
||||||
try {
|
|
||||||
std::rethrow_exception(ptr);
|
server_->listen("127.0.0.1", config_.get_api_port());
|
||||||
} catch (std::exception &e) {
|
});
|
||||||
data["error"] = (e.what() == nullptr) ? "unknown error" : e.what();
|
event_system::instance().raise<service_start_end>(function_name, "server");
|
||||||
utils::error::raise_error(function_name, e,
|
}
|
||||||
"failed request: " + req.path);
|
|
||||||
} catch (...) {
|
void server::stop() {
|
||||||
data["error"] = "unknown error";
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
utils::error::raise_error(function_name, "unknown error",
|
|
||||||
"failed request: " + req.path);
|
unique_mutex_lock lock(start_stop_mutex_);
|
||||||
}
|
if (not server_thread_) {
|
||||||
|
return;
|
||||||
res.set_content(data.dump(), "application/json");
|
}
|
||||||
res.status = http_error_codes::internal_error;
|
|
||||||
});
|
event_system::instance().raise<service_stop_begin>(function_name, "server");
|
||||||
|
|
||||||
server_->set_pre_routing_handler(
|
server_->stop();
|
||||||
[this](auto &&req, auto &&res) -> httplib::Server::HandlerResponse {
|
|
||||||
if (check_authorization(req)) {
|
std::unique_ptr<std::thread> thread{nullptr};
|
||||||
return httplib::Server::HandlerResponse::Unhandled;
|
std::swap(thread, server_thread_);
|
||||||
}
|
lock.unlock();
|
||||||
|
|
||||||
res.status = http_error_codes::unauthorized;
|
thread->join();
|
||||||
return httplib::Server::HandlerResponse::Handled;
|
thread.reset();
|
||||||
});
|
|
||||||
|
lock.lock();
|
||||||
initialize(*server_);
|
server_.reset();
|
||||||
|
lock.unlock();
|
||||||
server_thread_ = std::make_unique<std::thread>(
|
|
||||||
[this]() { server_->listen("127.0.0.1", config_.get_api_port()); });
|
event_system::instance().raise<service_stop_end>(function_name, "server");
|
||||||
event_system::instance().raise<service_start_end>(function_name, "server");
|
}
|
||||||
}
|
} // namespace repertory
|
||||||
|
|
||||||
void server::stop() {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
unique_mutex_lock lock(start_stop_mutex_);
|
|
||||||
if (not server_thread_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event_system::instance().raise<service_stop_begin>(function_name, "server");
|
|
||||||
|
|
||||||
server_->stop();
|
|
||||||
|
|
||||||
std::unique_ptr<std::thread> thread{nullptr};
|
|
||||||
std::swap(thread, server_thread_);
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
thread->join();
|
|
||||||
thread.reset();
|
|
||||||
|
|
||||||
lock.lock();
|
|
||||||
server_.reset();
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
event_system::instance().raise<service_stop_end>(function_name, "server");
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
||||||
|
@ -21,10 +21,56 @@
|
|||||||
*/
|
*/
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
|
#include "app_config.hpp"
|
||||||
#include "types/startup_exception.hpp"
|
#include "types/startup_exception.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
|
void clean_json_config(provider_type prov, nlohmann::json &data) {
|
||||||
|
data[JSON_API_PASSWORD] = "";
|
||||||
|
|
||||||
|
switch (prov) {
|
||||||
|
case provider_type::encrypt:
|
||||||
|
data[JSON_ENCRYPT_CONFIG][JSON_ENCRYPTION_TOKEN] = "";
|
||||||
|
data[JSON_REMOTE_MOUNT][JSON_ENCRYPTION_TOKEN] = "";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::remote:
|
||||||
|
data[JSON_REMOTE_CONFIG][JSON_ENCRYPTION_TOKEN] = "";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::s3:
|
||||||
|
data[JSON_REMOTE_MOUNT][JSON_ENCRYPTION_TOKEN] = "";
|
||||||
|
data[JSON_S3_CONFIG][JSON_ENCRYPTION_TOKEN] = "";
|
||||||
|
data[JSON_S3_CONFIG][JSON_SECRET_KEY] = "";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::sia:
|
||||||
|
data[JSON_REMOTE_MOUNT][JSON_ENCRYPTION_TOKEN] = "";
|
||||||
|
data[JSON_HOST_CONFIG][JSON_API_PASSWORD] = "";
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto clean_json_value(std::string_view name, std::string_view data)
|
||||||
|
-> std::string {
|
||||||
|
if (name ==
|
||||||
|
fmt::format("{}.{}", JSON_ENCRYPT_CONFIG, JSON_ENCRYPTION_TOKEN) ||
|
||||||
|
name == fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PASSWORD) ||
|
||||||
|
name == fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_ENCRYPTION_TOKEN) ||
|
||||||
|
name == fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_ENCRYPTION_TOKEN) ||
|
||||||
|
name == fmt::format("{}.{}", JSON_S3_CONFIG, JSON_ENCRYPTION_TOKEN) ||
|
||||||
|
name == fmt::format("{}.{}", JSON_S3_CONFIG, JSON_SECRET_KEY) ||
|
||||||
|
name == JSON_API_PASSWORD) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string{data};
|
||||||
|
}
|
||||||
|
|
||||||
auto database_type_from_string(std::string type, database_type default_type)
|
auto database_type_from_string(std::string type, database_type default_type)
|
||||||
-> database_type {
|
-> database_type {
|
||||||
type = utils::string::to_lower(utils::string::trim(type));
|
type = utils::string::to_lower(utils::string::trim(type));
|
||||||
@ -191,4 +237,34 @@ auto api_error_to_string(const api_error &error) -> const std::string & {
|
|||||||
|
|
||||||
return LOOKUP.at(error);
|
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
|
} // namespace repertory
|
||||||
|
@ -45,7 +45,7 @@ void get_api_authentication_data(std::string &user, std::string &password,
|
|||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
if (user.empty() && password.empty()) {
|
if (user.empty() && password.empty()) {
|
||||||
password = data[JSON_API_AUTH].get<std::string>();
|
password = data[JSON_API_PASSWORD].get<std::string>();
|
||||||
user = data[JSON_API_USER].get<std::string>();
|
user = data[JSON_API_USER].get<std::string>();
|
||||||
}
|
}
|
||||||
port = data[JSON_API_PORT].get<std::uint16_t>();
|
port = data[JSON_API_PORT].get<std::uint16_t>();
|
||||||
|
@ -22,13 +22,23 @@
|
|||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
|
|
||||||
#include "events/event_system.hpp"
|
#include "events/event_system.hpp"
|
||||||
|
#include "events/types/debug_log.hpp"
|
||||||
|
#include "events/types/info_log.hpp"
|
||||||
#include "events/types/repertory_exception.hpp"
|
#include "events/types/repertory_exception.hpp"
|
||||||
|
#include "events/types/trace_log.hpp"
|
||||||
|
#include "events/types/warn_log.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/error.hpp"
|
#include "utils/error.hpp"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct repertory_exception_handler final
|
struct repertory_exception_handler final
|
||||||
: repertory::utils::error::i_exception_handler {
|
: repertory::utils::error::i_exception_handler {
|
||||||
|
void handle_debug(std::string_view function_name,
|
||||||
|
std::string_view msg) const override {
|
||||||
|
repertory::event_system::instance().raise<repertory::debug_log>(
|
||||||
|
function_name, std::string{msg});
|
||||||
|
}
|
||||||
|
|
||||||
void handle_error(std::string_view function_name,
|
void handle_error(std::string_view function_name,
|
||||||
std::string_view msg) const override {
|
std::string_view msg) const override {
|
||||||
repertory::utils::error::raise_error(function_name, msg);
|
repertory::utils::error::raise_error(function_name, msg);
|
||||||
@ -42,13 +52,33 @@ struct repertory_exception_handler final
|
|||||||
const std::exception &ex) const override {
|
const std::exception &ex) const override {
|
||||||
repertory::utils::error::raise_error(function_name, ex);
|
repertory::utils::error::raise_error(function_name, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handle_info(std::string_view function_name,
|
||||||
|
std::string_view msg) const override {
|
||||||
|
repertory::event_system::instance().raise<repertory::info_log>(
|
||||||
|
function_name, std::string{msg});
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_trace(std::string_view function_name,
|
||||||
|
std::string_view msg) const override {
|
||||||
|
repertory::event_system::instance().raise<repertory::trace_log>(
|
||||||
|
function_name, std::string{msg});
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_warn(std::string_view function_name,
|
||||||
|
std::string_view msg) const override {
|
||||||
|
repertory::event_system::instance().raise<repertory::warn_log>(
|
||||||
|
function_name, std::string{msg});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<repertory_exception_handler> handler{([]() -> auto * {
|
const auto repertory_handler{
|
||||||
auto *ptr = new repertory_exception_handler{};
|
([]() -> auto {
|
||||||
repertory::utils::error::set_exception_handler(ptr);
|
auto ptr = std::make_unique<repertory_exception_handler>();
|
||||||
return ptr;
|
repertory::utils::error::set_exception_handler(ptr.get());
|
||||||
})()};
|
return ptr;
|
||||||
|
})(),
|
||||||
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace repertory::utils::error {
|
namespace repertory::utils::error {
|
||||||
|
31
repertory/librepertory/src/utils/platform.cpp
Normal file
31
repertory/librepertory/src/utils/platform.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
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 "platform/platform.hpp"
|
||||||
|
|
||||||
|
#include "app_config.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
auto create_lock_id(provider_type prov, std::string_view unique_id)->std::string {
|
||||||
|
return fmt::format("{}_{}_{}", REPERTORY_DATA_NAME,
|
||||||
|
app_config::get_provider_name(prov), unique_id);
|
||||||
|
}
|
||||||
|
} // namespace repertory
|
@ -38,47 +38,58 @@ void polling::frequency_thread(
|
|||||||
std::function<std::uint32_t()> get_frequency_seconds, frequency freq) {
|
std::function<std::uint32_t()> get_frequency_seconds, frequency freq) {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto last_run = std::chrono::system_clock::time_point::min();
|
||||||
while (not get_stop_requested()) {
|
while (not get_stop_requested()) {
|
||||||
unique_mutex_lock lock(mutex_);
|
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
auto futures = std::accumulate(
|
std::chrono::system_clock::now() - last_run);
|
||||||
items_.begin(), items_.end(), std::deque<tasks::task_ptr>{},
|
auto max_elapsed = std::chrono::seconds(get_frequency_seconds());
|
||||||
[this, &freq](auto &&list, auto &&item) -> auto {
|
|
||||||
if (item.second.freq != freq) {
|
if (last_run == std::chrono::system_clock::time_point::min() ||
|
||||||
|
elapsed >= max_elapsed) {
|
||||||
|
unique_mutex_lock lock(mutex_);
|
||||||
|
auto futures = std::accumulate(
|
||||||
|
items_.begin(), items_.end(), std::deque<tasks::task_ptr>{},
|
||||||
|
[this, &freq](auto &&list, auto &&item) -> auto {
|
||||||
|
if (item.second.freq != freq) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto future = tasks::instance().schedule({
|
||||||
|
[this, &freq, item](auto &&task_stopped) {
|
||||||
|
if (config_->get_event_level() == event_level::trace ||
|
||||||
|
freq != frequency::second) {
|
||||||
|
event_system::instance().raise<polling_item_begin>(
|
||||||
|
function_name, item.first);
|
||||||
|
}
|
||||||
|
item.second.action(task_stopped);
|
||||||
|
if (config_->get_event_level() == event_level::trace ||
|
||||||
|
freq != frequency::second) {
|
||||||
|
event_system::instance().raise<polling_item_end>(
|
||||||
|
function_name, item.first);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
list.emplace_back(future);
|
||||||
return list;
|
return list;
|
||||||
}
|
|
||||||
|
|
||||||
auto future = tasks::instance().schedule({
|
|
||||||
[this, &freq, item](auto &&task_stopped) {
|
|
||||||
if (config_->get_event_level() == event_level::trace ||
|
|
||||||
freq != frequency::second) {
|
|
||||||
event_system::instance().raise<polling_item_begin>(
|
|
||||||
function_name, item.first);
|
|
||||||
}
|
|
||||||
item.second.action(task_stopped);
|
|
||||||
if (config_->get_event_level() == event_level::trace ||
|
|
||||||
freq != frequency::second) {
|
|
||||||
event_system::instance().raise<polling_item_end>(
|
|
||||||
function_name, item.first);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
list.emplace_back(future);
|
while (not futures.empty()) {
|
||||||
return list;
|
futures.front()->wait();
|
||||||
});
|
futures.pop_front();
|
||||||
lock.unlock();
|
}
|
||||||
|
|
||||||
while (not futures.empty()) {
|
last_run = std::chrono::system_clock::now();
|
||||||
futures.front()->wait();
|
elapsed = std::chrono::seconds(0U);
|
||||||
futures.pop_front();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unique_mutex_lock lock(mutex_);
|
||||||
if (get_stop_requested()) {
|
if (get_stop_requested()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.lock();
|
notify_.wait_for(lock, max_elapsed - elapsed);
|
||||||
notify_.wait_for(lock, std::chrono::seconds(get_frequency_seconds()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "cli/pinned_status.hpp"
|
#include "cli/pinned_status.hpp"
|
||||||
#include "cli/set.hpp"
|
#include "cli/set.hpp"
|
||||||
#include "cli/status.hpp"
|
#include "cli/status.hpp"
|
||||||
|
#include "cli/ui.hpp"
|
||||||
#include "cli/unmount.hpp"
|
#include "cli/unmount.hpp"
|
||||||
#include "cli/unpin_file.hpp"
|
#include "cli/unpin_file.hpp"
|
||||||
#include "utils/cli_utils.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},
|
cli::actions::pinned_status},
|
||||||
{utils::cli::options::set_option, cli::actions::set},
|
{utils::cli::options::set_option, cli::actions::set},
|
||||||
{utils::cli::options::status_option, cli::actions::status},
|
{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::unmount_option, cli::actions::unmount},
|
||||||
{utils::cli::options::unpin_file_option, cli::actions::unpin_file},
|
{utils::cli::options::unpin_file_option, cli::actions::unpin_file},
|
||||||
};
|
};
|
||||||
|
@ -23,50 +23,38 @@
|
|||||||
#define REPERTORY_INCLUDE_CLI_CHECK_VERSION_HPP_
|
#define REPERTORY_INCLUDE_CLI_CHECK_VERSION_HPP_
|
||||||
|
|
||||||
#include "app_config.hpp"
|
#include "app_config.hpp"
|
||||||
|
#include "comm/curl/curl_comm.hpp"
|
||||||
|
#include "providers/sia/sia_provider.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
namespace repertory::cli::actions {
|
namespace repertory::cli::actions {
|
||||||
[[nodiscard]] inline auto
|
[[nodiscard]] inline auto check_version(std::vector<const char *> /* args */,
|
||||||
check_version(std::vector<const char *> /* args */,
|
const std::string &data_directory,
|
||||||
const std::string & /* data_directory */,
|
const provider_type &prov,
|
||||||
const provider_type & /* pt */, const std::string & /*unique_id*/,
|
const std::string & /*unique_id*/,
|
||||||
std::string /*user*/, std::string /*password*/) -> exit_code {
|
std::string /*user*/,
|
||||||
auto ret = exit_code::success;
|
std::string /*password*/) -> exit_code {
|
||||||
|
if (prov != provider_type::sia) {
|
||||||
|
fmt::println("Success:\n\tNo specific version is required for {} providers",
|
||||||
|
app_config::get_provider_display_name(prov));
|
||||||
|
return exit_code::success;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO need to updated way to check version
|
app_config config(prov, data_directory);
|
||||||
// if (not((pt == provider_type::remote) || (pt == provider_type::s3))) {
|
curl_comm comm(config.get_host_config());
|
||||||
// app_config config(pt, data_directory);
|
sia_provider provider(config, comm);
|
||||||
// curl_comm comm(config);
|
|
||||||
// json data, err;
|
|
||||||
//
|
|
||||||
// if (comm.get("/daemon/version", data, err) == api_error::success) {
|
|
||||||
// const auto res = utils::compare_version_strings(
|
|
||||||
// data["version"].get<std::string>(),
|
|
||||||
// app_config::get_provider_minimum_version(pt));
|
|
||||||
// if (res < 0) {
|
|
||||||
// ret = exit_code::incompatible_version;
|
|
||||||
// std::cerr << "Failed!" << std::endl;
|
|
||||||
// std::cerr << " Actual: " << data["version"].get<std::string>()
|
|
||||||
// << std::endl;
|
|
||||||
// std::cerr << " Minimum: "
|
|
||||||
// << app_config::get_provider_minimum_version(pt) <<
|
|
||||||
// std::endl;
|
|
||||||
// } else {
|
|
||||||
// std::cout << "Success!" << std::endl;
|
|
||||||
// std::cout << " Actual: " << data["version"].get<std::string>()
|
|
||||||
// << std::endl;
|
|
||||||
// std::cout << " Minimum: "
|
|
||||||
// << app_config::get_provider_minimum_version(pt) <<
|
|
||||||
// std::endl;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// std::cerr << "Failed!" << std::endl;
|
|
||||||
// std::cerr << err.dump(2) << std::endl;
|
|
||||||
// ret = exit_code::communication_error;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
return ret;
|
std::string required_version;
|
||||||
|
std::string returned_version;
|
||||||
|
if (provider.check_version(required_version, returned_version)) {
|
||||||
|
fmt::println("Success:\n\tRequired: {}\n\tActual: {}", required_version,
|
||||||
|
returned_version);
|
||||||
|
return exit_code::success;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::println("Failed:\n\tRequired: {}\n\tActual: {}", required_version,
|
||||||
|
returned_version);
|
||||||
|
return exit_code::incompatible_version;
|
||||||
}
|
}
|
||||||
} // namespace repertory::cli::actions
|
} // namespace repertory::cli::actions
|
||||||
|
|
||||||
|
@ -36,10 +36,9 @@ template <typename drive> inline void help(std::vector<const char *> args) {
|
|||||||
std::cout << " -di,--drive_information Display mounted drive "
|
std::cout << " -di,--drive_information Display mounted drive "
|
||||||
"information"
|
"information"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cout
|
std::cout << " -na,--name Unique configuration "
|
||||||
<< " -na,--name Unique name for S3 or Sia "
|
"name [Required for Encrypt, S3 and Sia]"
|
||||||
"instance [Required]"
|
<< std::endl;
|
||||||
<< std::endl;
|
|
||||||
std::cout << " -s3,--s3 Enables S3 mode"
|
std::cout << " -s3,--s3 Enables S3 mode"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cout
|
std::cout
|
||||||
@ -79,6 +78,12 @@ template <typename drive> inline void help(std::vector<const char *> args) {
|
|||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cout << " -status Display mount status"
|
std::cout << " -status Display mount status"
|
||||||
<< std::endl;
|
<< 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::cout << " -unmount,--unmount Unmount and shutdown"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cout << " -uf,--unpin_file [API path] Unpin a file from cache "
|
std::cout << " -uf,--unpin_file [API path] Unpin a file from cache "
|
||||||
|
@ -28,14 +28,13 @@
|
|||||||
#include "providers/provider.hpp"
|
#include "providers/provider.hpp"
|
||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/cli_utils.hpp"
|
#include "utils/cli_utils.hpp"
|
||||||
#include "utils/com_init_wrapper.hpp"
|
#include "utils/file.hpp"
|
||||||
#include "utils/file_utils.hpp"
|
|
||||||
#include "utils/string.hpp"
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include "drives/winfsp/remotewinfsp/remote_client.hpp"
|
#include "drives/winfsp/remotewinfsp/remote_client.hpp"
|
||||||
#include "drives/winfsp/remotewinfsp/remote_winfsp_drive.hpp"
|
#include "drives/winfsp/remotewinfsp/remote_winfsp_drive.hpp"
|
||||||
#include "drives/winfsp/winfsp_drive.hpp"
|
#include "drives/winfsp/winfsp_drive.hpp"
|
||||||
|
#include "utils/com_init_wrapper.hpp"
|
||||||
|
|
||||||
using repertory_drive = repertory::winfsp_drive;
|
using repertory_drive = repertory::winfsp_drive;
|
||||||
using remote_client = repertory::remote_winfsp::remote_client;
|
using remote_client = repertory::remote_winfsp::remote_client;
|
||||||
@ -57,130 +56,143 @@ namespace repertory::cli::actions {
|
|||||||
mount(std::vector<const char *> args, std::string data_directory,
|
mount(std::vector<const char *> args, std::string data_directory,
|
||||||
int &mount_result, provider_type prov, const std::string &remote_host,
|
int &mount_result, provider_type prov, const std::string &remote_host,
|
||||||
std::uint16_t remote_port, const std::string &unique_id) -> exit_code {
|
std::uint16_t remote_port, const std::string &unique_id) -> exit_code {
|
||||||
auto ret = exit_code::success;
|
lock_data global_lock(provider_type::unknown, "global");
|
||||||
|
{
|
||||||
lock_data lock(prov, unique_id);
|
auto lock_result = global_lock.grab_lock(100U);
|
||||||
const auto res = lock.grab_lock();
|
if (lock_result != lock_result::success) {
|
||||||
if (res == lock_result::locked) {
|
std::cerr << "FATAL: Unable to get global lock" << std::endl;
|
||||||
ret = exit_code::mount_active;
|
return exit_code::lock_failed;
|
||||||
std::cerr << app_config::get_provider_display_name(prov)
|
|
||||||
<< " mount is already active" << std::endl;
|
|
||||||
} else if (res == lock_result::success) {
|
|
||||||
const auto generate_config = utils::cli::has_option(
|
|
||||||
args, utils::cli::options::generate_config_option);
|
|
||||||
if (generate_config) {
|
|
||||||
app_config config(prov, data_directory);
|
|
||||||
if (prov == provider_type::remote) {
|
|
||||||
auto cfg = config.get_remote_config();
|
|
||||||
cfg.host_name_or_ip = remote_host;
|
|
||||||
cfg.api_port = remote_port;
|
|
||||||
config.set_remote_config(cfg);
|
|
||||||
} else if (prov == provider_type::sia &&
|
|
||||||
config.get_sia_config().bucket.empty()) {
|
|
||||||
[[maybe_unused]] auto bucket =
|
|
||||||
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Generated " << app_config::get_provider_display_name(prov)
|
|
||||||
<< " Configuration" << std::endl;
|
|
||||||
std::cout << config.get_config_file_path() << std::endl;
|
|
||||||
ret = utils::file::file(config.get_config_file_path()).exists()
|
|
||||||
? exit_code::success
|
|
||||||
: exit_code::file_creation_failed;
|
|
||||||
} else {
|
|
||||||
#if defined(_WIN32)
|
|
||||||
if (utils::cli::has_option(args, utils::cli::options::hidden_option)) {
|
|
||||||
::ShowWindow(::GetConsoleWindow(), SW_HIDE);
|
|
||||||
}
|
|
||||||
#endif // defined(_WIN32)
|
|
||||||
auto drive_args =
|
|
||||||
utils::cli::parse_drive_options(args, prov, data_directory);
|
|
||||||
app_config config(prov, data_directory);
|
|
||||||
#if defined(_WIN32)
|
|
||||||
if (config.get_enable_mount_manager() &&
|
|
||||||
not utils::is_process_elevated()) {
|
|
||||||
utils::com_init_wrapper cw;
|
|
||||||
if (not lock.set_mount_state(true, "elevating", -1)) {
|
|
||||||
std::cerr << "failed to set mount state" << std::endl;
|
|
||||||
}
|
|
||||||
lock.release();
|
|
||||||
|
|
||||||
mount_result = utils::run_process_elevated(args);
|
|
||||||
lock_data lock2(prov, unique_id);
|
|
||||||
if (lock2.grab_lock() == lock_result::success) {
|
|
||||||
if (not lock2.set_mount_state(false, "", -1)) {
|
|
||||||
std::cerr << "failed to set mount state" << std::endl;
|
|
||||||
}
|
|
||||||
lock2.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
return exit_code::mount_result;
|
|
||||||
}
|
|
||||||
#endif // defined(_WIN32)
|
|
||||||
std::cout << "Initializing "
|
|
||||||
<< app_config::get_provider_display_name(prov)
|
|
||||||
<< (unique_id.empty() ? ""
|
|
||||||
: (prov == provider_type::s3 || prov == provider_type::sia)
|
|
||||||
? " [" + unique_id + ']'
|
|
||||||
: " [" + remote_host + ':' +
|
|
||||||
std::to_string(remote_port) + ']')
|
|
||||||
<< " Drive" << std::endl;
|
|
||||||
if (prov == provider_type::remote) {
|
|
||||||
std::uint16_t port{0U};
|
|
||||||
if (utils::get_next_available_port(config.get_api_port(), port)) {
|
|
||||||
auto cfg = config.get_remote_config();
|
|
||||||
cfg.host_name_or_ip = remote_host;
|
|
||||||
cfg.api_port = remote_port;
|
|
||||||
config.set_remote_config(cfg);
|
|
||||||
config.set_api_port(port);
|
|
||||||
|
|
||||||
try {
|
|
||||||
remote_drive drive(
|
|
||||||
config,
|
|
||||||
[&config]() -> std::unique_ptr<remote_instance> {
|
|
||||||
return std::unique_ptr<remote_instance>(
|
|
||||||
new remote_client(config));
|
|
||||||
},
|
|
||||||
lock);
|
|
||||||
if (not lock.set_mount_state(true, "", -1)) {
|
|
||||||
std::cerr << "failed to set mount state" << std::endl;
|
|
||||||
}
|
|
||||||
mount_result = drive.mount(drive_args);
|
|
||||||
ret = exit_code::mount_result;
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
std::cerr << "FATAL: " << e.what() << std::endl;
|
|
||||||
ret = exit_code::startup_exception;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::cerr << "FATAL: Unable to get available port" << std::endl;
|
|
||||||
ret = exit_code::startup_exception;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (prov == provider_type::sia &&
|
|
||||||
config.get_sia_config().bucket.empty()) {
|
|
||||||
[[maybe_unused]] auto bucket =
|
|
||||||
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
auto provider = create_provider(prov, config);
|
|
||||||
repertory_drive drive(config, lock, *provider);
|
|
||||||
if (not lock.set_mount_state(true, "", -1)) {
|
|
||||||
std::cerr << "failed to set mount state" << std::endl;
|
|
||||||
}
|
|
||||||
mount_result = drive.mount(drive_args);
|
|
||||||
ret = exit_code::mount_result;
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
std::cerr << "FATAL: " << e.what() << std::endl;
|
|
||||||
ret = exit_code::startup_exception;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ret = exit_code::lock_failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
lock_data lock(prov, unique_id);
|
||||||
|
auto lock_result = lock.grab_lock();
|
||||||
|
if (lock_result == lock_result::locked) {
|
||||||
|
std::cerr << app_config::get_provider_display_name(prov)
|
||||||
|
<< " mount is already active" << std::endl;
|
||||||
|
return exit_code::mount_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lock_result != lock_result::success) {
|
||||||
|
std::cerr << "FATAL: Unable to get provider lock" << std::endl;
|
||||||
|
return exit_code::lock_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils::cli::has_option(args,
|
||||||
|
utils::cli::options::generate_config_option)) {
|
||||||
|
app_config config(prov, data_directory);
|
||||||
|
if (prov == provider_type::remote) {
|
||||||
|
auto remote_config = config.get_remote_config();
|
||||||
|
remote_config.host_name_or_ip = remote_host;
|
||||||
|
remote_config.api_port = remote_port;
|
||||||
|
config.set_remote_config(remote_config);
|
||||||
|
} else if (prov == provider_type::sia &&
|
||||||
|
config.get_sia_config().bucket.empty()) {
|
||||||
|
[[maybe_unused]] auto bucket =
|
||||||
|
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Generated " << app_config::get_provider_display_name(prov)
|
||||||
|
<< " Configuration" << std::endl;
|
||||||
|
std::cout << config.get_config_file_path() << std::endl;
|
||||||
|
return utils::file::file(config.get_config_file_path()).exists()
|
||||||
|
? exit_code::success
|
||||||
|
: exit_code::file_creation_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (utils::cli::has_option(args, utils::cli::options::hidden_option)) {
|
||||||
|
::ShowWindow(::GetConsoleWindow(), SW_HIDE);
|
||||||
|
}
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
|
||||||
|
auto drive_args = utils::cli::parse_drive_options(args, prov, data_directory);
|
||||||
|
app_config config(prov, data_directory);
|
||||||
|
{
|
||||||
|
std::uint16_t port{};
|
||||||
|
if (not utils::get_next_available_port(config.get_api_port(), port)) {
|
||||||
|
std::cerr << "FATAL: Unable to get available port" << std::endl;
|
||||||
|
return exit_code::startup_exception;
|
||||||
|
}
|
||||||
|
config.set_api_port(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (config.get_enable_mount_manager() && not utils::is_process_elevated()) {
|
||||||
|
utils::com_init_wrapper wrapper;
|
||||||
|
if (not lock.set_mount_state(true, "elevating", -1)) {
|
||||||
|
std::cerr << "failed to set mount state" << std::endl;
|
||||||
|
}
|
||||||
|
lock.release();
|
||||||
|
global_lock.release();
|
||||||
|
|
||||||
|
mount_result = utils::run_process_elevated(args);
|
||||||
|
lock_data prov_lock(prov, unique_id);
|
||||||
|
if (prov_lock.grab_lock() == lock_result::success) {
|
||||||
|
if (not prov_lock.set_mount_state(false, "", -1)) {
|
||||||
|
std::cerr << "failed to set mount state" << std::endl;
|
||||||
|
}
|
||||||
|
prov_lock.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return exit_code::mount_result;
|
||||||
|
}
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
|
||||||
|
std::cout << "Initializing " << app_config::get_provider_display_name(prov)
|
||||||
|
<< (unique_id.empty() ? ""
|
||||||
|
: (prov == provider_type::remote)
|
||||||
|
? " [" + remote_host + ':' + std::to_string(remote_port) +
|
||||||
|
']'
|
||||||
|
: " [" + unique_id + ']')
|
||||||
|
<< " Drive" << std::endl;
|
||||||
|
if (prov == provider_type::remote) {
|
||||||
|
try {
|
||||||
|
auto remote_cfg = config.get_remote_config();
|
||||||
|
remote_cfg.host_name_or_ip = remote_host;
|
||||||
|
remote_cfg.api_port = remote_port;
|
||||||
|
config.set_remote_config(remote_cfg);
|
||||||
|
|
||||||
|
remote_drive drive(
|
||||||
|
config,
|
||||||
|
[&config]() -> std::unique_ptr<remote_instance> {
|
||||||
|
return std::unique_ptr<remote_instance>(new remote_client(config));
|
||||||
|
},
|
||||||
|
lock);
|
||||||
|
if (not lock.set_mount_state(true, "", -1)) {
|
||||||
|
std::cerr << "failed to set mount state" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
global_lock.release();
|
||||||
|
mount_result = drive.mount(drive_args);
|
||||||
|
return exit_code::mount_result;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
std::cerr << "FATAL: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exit_code::startup_exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (prov == provider_type::sia && config.get_sia_config().bucket.empty()) {
|
||||||
|
[[maybe_unused]] auto bucket =
|
||||||
|
config.set_value_by_name("SiaConfig.Bucket", unique_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto provider = create_provider(prov, config);
|
||||||
|
repertory_drive drive(config, lock, *provider);
|
||||||
|
if (not lock.set_mount_state(true, "", -1)) {
|
||||||
|
std::cerr << "failed to set mount state" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
global_lock.release();
|
||||||
|
mount_result = drive.mount(drive_args);
|
||||||
|
return exit_code::mount_result;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
std::cerr << "FATAL: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exit_code::startup_exception;
|
||||||
}
|
}
|
||||||
} // namespace repertory::cli::actions
|
} // namespace repertory::cli::actions
|
||||||
|
|
||||||
|
61
repertory/repertory/include/cli/ui.hpp
Normal file
61
repertory/repertory/include/cli/ui.hpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
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 "ui/mgmt_app_config.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 {
|
||||||
|
|
||||||
|
ui::mgmt_app_config config{};
|
||||||
|
|
||||||
|
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()) {
|
||||||
|
config.set_api_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::handlers handlers(&config, &server);
|
||||||
|
return exit_code::success;
|
||||||
|
}
|
||||||
|
} // namespace repertory::cli::actions
|
||||||
|
|
||||||
|
#endif // REPERTORY_INCLUDE_CLI_UI_HPP_
|
120
repertory/repertory/include/ui/handlers.hpp
Normal file
120
repertory/repertory/include/ui/handlers.hpp
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
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"
|
||||||
|
#include "utils/common.hpp"
|
||||||
|
|
||||||
|
namespace repertory::ui {
|
||||||
|
class mgmt_app_config;
|
||||||
|
|
||||||
|
class handlers final {
|
||||||
|
private:
|
||||||
|
static constexpr const auto nonce_length{128U};
|
||||||
|
static constexpr const auto nonce_timeout{15U};
|
||||||
|
|
||||||
|
struct nonce_data final {
|
||||||
|
std::chrono::system_clock::time_point creation{
|
||||||
|
std::chrono::system_clock::now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string nonce{
|
||||||
|
utils::generate_random_string(nonce_length),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
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_;
|
||||||
|
std::string repertory_binary_;
|
||||||
|
httplib::Server *server_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
console_consumer console;
|
||||||
|
mutable std::mutex mtx_;
|
||||||
|
mutable std::unordered_map<std::string, std::recursive_mutex> mtx_lookup_;
|
||||||
|
std::mutex nonce_mtx_;
|
||||||
|
std::unordered_map<std::string, nonce_data> nonce_lookup_;
|
||||||
|
std::condition_variable nonce_notify_;
|
||||||
|
std::unique_ptr<std::thread> nonce_thread_;
|
||||||
|
stop_type stop_requested{false};
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] auto data_directory_exists(provider_type prov,
|
||||||
|
std::string_view name) const -> bool;
|
||||||
|
|
||||||
|
static void handle_get_available_locations(httplib::Response &res);
|
||||||
|
|
||||||
|
void handle_get_mount(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const;
|
||||||
|
|
||||||
|
static void handle_get_mount_list(httplib::Response &res);
|
||||||
|
|
||||||
|
void handle_get_mount_location(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const;
|
||||||
|
|
||||||
|
void handle_get_mount_status(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const;
|
||||||
|
|
||||||
|
void handle_get_nonce(httplib::Response &res);
|
||||||
|
|
||||||
|
void handle_get_settings(httplib::Response &res) const;
|
||||||
|
|
||||||
|
void handle_post_add_mount(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const;
|
||||||
|
|
||||||
|
void handle_post_mount(const httplib::Request &req, httplib::Response &res);
|
||||||
|
|
||||||
|
void handle_put_mount_location(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const;
|
||||||
|
|
||||||
|
void handle_put_set_value_by_name(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const;
|
||||||
|
|
||||||
|
void handle_put_settings(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const;
|
||||||
|
|
||||||
|
auto launch_process(provider_type prov, std::string_view name,
|
||||||
|
std::vector<std::string> args,
|
||||||
|
bool background = false) const
|
||||||
|
-> std::vector<std::string>;
|
||||||
|
|
||||||
|
void removed_expired_nonces();
|
||||||
|
|
||||||
|
void set_key_value(provider_type prov, std::string_view name,
|
||||||
|
std::string_view key, std::string_view value) const;
|
||||||
|
};
|
||||||
|
} // namespace repertory::ui
|
||||||
|
|
||||||
|
#endif // REPERTORY_INCLUDE_UI_HANDLERS_HPP_
|
70
repertory/repertory/include/ui/mgmt_app_config.hpp
Normal file
70
repertory/repertory/include/ui/mgmt_app_config.hpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
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_MGMT_APP_CONFIG_HPP_
|
||||||
|
#define REPERTORY_INCLUDE_UI_MGMT_APP_CONFIG_HPP_
|
||||||
|
|
||||||
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
|
namespace repertory::ui {
|
||||||
|
class mgmt_app_config final {
|
||||||
|
public:
|
||||||
|
mgmt_app_config();
|
||||||
|
|
||||||
|
private:
|
||||||
|
atomic<std::string> api_password_{"repertory"};
|
||||||
|
std::atomic<std::uint16_t> api_port_{default_ui_mgmt_port};
|
||||||
|
atomic<std::string> api_user_{"repertory"};
|
||||||
|
std::unordered_map<provider_type,
|
||||||
|
std::unordered_map<std::string, std::string>>
|
||||||
|
locations_;
|
||||||
|
mutable std::recursive_mutex mtx_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void save() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
[[nodiscard]] auto to_json() const -> nlohmann::json;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_api_password() const -> std::string {
|
||||||
|
return api_password_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_api_port() const -> std::uint16_t { return api_port_; }
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_api_user() const -> std::string { return api_user_; }
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_mount_location(provider_type prov,
|
||||||
|
std::string_view name) const
|
||||||
|
-> std::string;
|
||||||
|
|
||||||
|
void set_api_password(std::string_view api_password);
|
||||||
|
|
||||||
|
void set_api_port(std::uint16_t api_port);
|
||||||
|
|
||||||
|
void set_api_user(std::string_view api_user);
|
||||||
|
|
||||||
|
void set_mount_location(provider_type prov, std::string_view name,
|
||||||
|
std::string_view location);
|
||||||
|
};
|
||||||
|
} // namespace repertory::ui
|
||||||
|
|
||||||
|
#endif // REPERTORY_INCLUDE_UI_MGMT_APP_CONFIG_HPP_
|
@ -44,7 +44,7 @@ auto main(int argc, char **argv) -> int {
|
|||||||
std::vector<const char *> args;
|
std::vector<const char *> args;
|
||||||
{
|
{
|
||||||
auto args_span = std::span(argv, static_cast<std::size_t>(argc));
|
auto args_span = std::span(argv, static_cast<std::size_t>(argc));
|
||||||
std::copy(args_span.begin(), args_span.end(), std::back_inserter(args));
|
std::ranges::copy(args_span, std::back_inserter(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
@ -105,7 +105,8 @@ auto main(int argc, char **argv) -> int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ((prov == provider_type::s3) || (prov == provider_type::sia)) {
|
} else if ((prov == provider_type::s3) || (prov == provider_type::sia) ||
|
||||||
|
(prov == provider_type::encrypt)) {
|
||||||
std::string data;
|
std::string data;
|
||||||
res = utils::cli::parse_string_option(
|
res = utils::cli::parse_string_option(
|
||||||
args, utils::cli::options::name_option, data);
|
args, utils::cli::options::name_option, data);
|
||||||
@ -115,9 +116,9 @@ auto main(int argc, char **argv) -> int {
|
|||||||
if (prov == provider_type::sia) {
|
if (prov == provider_type::sia) {
|
||||||
unique_id = "default";
|
unique_id = "default";
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Name of "
|
std::cerr << "Configuration name for '"
|
||||||
<< app_config::get_provider_display_name(prov)
|
<< app_config::get_provider_display_name(prov)
|
||||||
<< " instance not provided" << std::endl;
|
<< "' was not provided" << std::endl;
|
||||||
res = exit_code::invalid_syntax;
|
res = exit_code::invalid_syntax;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,10 +147,17 @@ auto main(int argc, char **argv) -> int {
|
|||||||
(res == exit_code::option_not_found) &&
|
(res == exit_code::option_not_found) &&
|
||||||
(idx < utils::cli::options::option_list.size());
|
(idx < utils::cli::options::option_list.size());
|
||||||
idx++) {
|
idx++) {
|
||||||
res = cli::actions::perform_action(
|
try {
|
||||||
utils::cli::options::option_list[idx], args, data_directory, prov,
|
res = cli::actions::perform_action(
|
||||||
unique_id, user, password);
|
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) {
|
if (res == exit_code::option_not_found) {
|
||||||
res = cli::actions::mount(args, data_directory, mount_result, prov,
|
res = cli::actions::mount(args, data_directory, mount_result, prov,
|
||||||
remote_host, remote_port, unique_id);
|
remote_host, remote_port, unique_id);
|
||||||
|
754
repertory/repertory/src/ui/handlers.cpp
Normal file
754
repertory/repertory/src/ui/handlers.cpp
Normal file
@ -0,0 +1,754 @@
|
|||||||
|
/*
|
||||||
|
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 "types/repertory.hpp"
|
||||||
|
#include "ui/mgmt_app_config.hpp"
|
||||||
|
#include "utils/collection.hpp"
|
||||||
|
#include "utils/common.hpp"
|
||||||
|
#include "utils/config.hpp"
|
||||||
|
#include "utils/error_utils.hpp"
|
||||||
|
#include "utils/file.hpp"
|
||||||
|
#include "utils/hash.hpp"
|
||||||
|
#include "utils/path.hpp"
|
||||||
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
|
#include <boost/process/v1/args.hpp>
|
||||||
|
#include <boost/process/v1/child.hpp>
|
||||||
|
#include <boost/process/v1/io.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
[[nodiscard]] auto decrypt(std::string_view data, std::string_view password)
|
||||||
|
-> std::string {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
if (data.empty()) {
|
||||||
|
return std::string{data};
|
||||||
|
}
|
||||||
|
|
||||||
|
repertory::data_buffer decoded;
|
||||||
|
if (not repertory::utils::collection::from_hex_string(data, decoded)) {
|
||||||
|
throw repertory::utils::error::create_exception(function_name,
|
||||||
|
{"decryption failed"});
|
||||||
|
}
|
||||||
|
repertory::data_buffer buffer(decoded.size());
|
||||||
|
|
||||||
|
auto key = repertory::utils::encryption::create_hash_blake2b_256(password);
|
||||||
|
|
||||||
|
unsigned long long size{};
|
||||||
|
auto res = crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||||
|
reinterpret_cast<unsigned char *>(buffer.data()), &size, nullptr,
|
||||||
|
reinterpret_cast<const unsigned char *>(
|
||||||
|
&decoded.at(crypto_aead_xchacha20poly1305_IETF_NPUBBYTES)),
|
||||||
|
decoded.size() - crypto_aead_xchacha20poly1305_IETF_NPUBBYTES,
|
||||||
|
reinterpret_cast<const unsigned char *>(REPERTORY.data()),
|
||||||
|
REPERTORY.length(),
|
||||||
|
reinterpret_cast<const unsigned char *>(decoded.data()),
|
||||||
|
reinterpret_cast<const unsigned char *>(key.data()));
|
||||||
|
if (res != 0) {
|
||||||
|
throw repertory::utils::error::create_exception(function_name,
|
||||||
|
{"decryption failed"});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
buffer.begin(),
|
||||||
|
std::next(buffer.begin(), static_cast<std::int64_t>(size)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto decrypt_value(const repertory::ui::mgmt_app_config *config,
|
||||||
|
std::string_view key, std::string_view value,
|
||||||
|
bool &skip) -> std::string {
|
||||||
|
auto last_key{key};
|
||||||
|
auto parts = repertory::utils::string::split(key, '.', false);
|
||||||
|
if (parts.size() > 1U) {
|
||||||
|
last_key = parts.at(parts.size() - 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_key == repertory::JSON_API_PASSWORD ||
|
||||||
|
last_key == repertory::JSON_ENCRYPTION_TOKEN ||
|
||||||
|
last_key == repertory::JSON_SECRET_KEY) {
|
||||||
|
auto decrypted = decrypt(value, config->get_api_password());
|
||||||
|
if (decrypted.empty()) {
|
||||||
|
skip = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string{value};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace repertory::ui {
|
||||||
|
handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
||||||
|
: config_(config),
|
||||||
|
#if defined(_WIN32)
|
||||||
|
repertory_binary_(utils::path::combine(".", {"repertory.exe"})),
|
||||||
|
#else // !defined(_WIN32)
|
||||||
|
repertory_binary_(utils::path::combine(".", {"repertory"})),
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
server_(server) {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
server_->set_socket_options([](auto &&sock) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
int enable{1};
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
||||||
|
reinterpret_cast<const char *>(&enable), sizeof(enable));
|
||||||
|
#else // !defined(_WIN32)
|
||||||
|
linger opt{1, 0};
|
||||||
|
setsockopt(sock, SOL_SOCKET, SO_LINGER,
|
||||||
|
reinterpret_cast<const char *>(&opt), sizeof(opt));
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
});
|
||||||
|
|
||||||
|
server_->set_pre_routing_handler(
|
||||||
|
[this](const httplib::Request &req,
|
||||||
|
auto &&res) -> httplib::Server::HandlerResponse {
|
||||||
|
if (req.path == "/api/v1/nonce" || req.path == "/ui" ||
|
||||||
|
req.path.starts_with("/ui/")) {
|
||||||
|
return httplib::Server::HandlerResponse::Unhandled;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto auth =
|
||||||
|
decrypt(req.get_param_value("auth"), config_->get_api_password());
|
||||||
|
if (utils::string::begins_with(
|
||||||
|
auth, fmt::format("{}_", config_->get_api_user()))) {
|
||||||
|
auto nonce = auth.substr(config_->get_api_user().length() + 1U);
|
||||||
|
|
||||||
|
mutex_lock lock(nonce_mtx_);
|
||||||
|
if (nonce_lookup_.contains(nonce)) {
|
||||||
|
nonce_lookup_.erase(nonce);
|
||||||
|
return httplib::Server::HandlerResponse::Unhandled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = http_error_codes::unauthorized;
|
||||||
|
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 = utils::string::ends_with(data["error"].get<std::string>(),
|
||||||
|
"|decryption failed")
|
||||||
|
? http_error_codes::unauthorized
|
||||||
|
: http_error_codes::internal_error;
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Get("/api/v1/locations", [](auto && /* req */, auto &&res) {
|
||||||
|
handle_get_available_locations(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Get("/api/v1/mount",
|
||||||
|
[this](auto &&req, auto &&res) { handle_get_mount(req, res); });
|
||||||
|
|
||||||
|
server->Get("/api/v1/mount_location", [this](auto &&req, auto &&res) {
|
||||||
|
handle_get_mount_location(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Get("/api/v1/mount_list", [](auto && /* req */, auto &&res) {
|
||||||
|
handle_get_mount_list(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Get("/api/v1/mount_status", [this](auto &&req, auto &&res) {
|
||||||
|
handle_get_mount_status(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Get("/api/v1/nonce",
|
||||||
|
[this](auto && /* req */, auto &&res) { handle_get_nonce(res); });
|
||||||
|
|
||||||
|
server->Get("/api/v1/settings", [this](auto && /* req */, auto &&res) {
|
||||||
|
handle_get_settings(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Post("/api/v1/add_mount", [this](auto &&req, auto &&res) {
|
||||||
|
handle_post_add_mount(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Post("/api/v1/mount",
|
||||||
|
[this](auto &&req, auto &&res) { handle_post_mount(req, res); });
|
||||||
|
|
||||||
|
server->Put("/api/v1/mount_location", [this](auto &&req, auto &&res) {
|
||||||
|
handle_put_mount_location(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Put("/api/v1/set_value_by_name", [this](auto &&req, auto &&res) {
|
||||||
|
handle_put_set_value_by_name(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Put("/api/v1/settings", [this](auto &&req, auto &&res) {
|
||||||
|
handle_put_settings(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
system(fmt::format(
|
||||||
|
R"(start "Repertory Management Portal" "http://127.0.0.1:{}/ui")",
|
||||||
|
config_->get_api_port())
|
||||||
|
.c_str());
|
||||||
|
#elif defined(__linux__)
|
||||||
|
system(fmt::format(R"(xdg-open "http://127.0.0.1:{}/ui")",
|
||||||
|
config_->get_api_port())
|
||||||
|
.c_str());
|
||||||
|
#else // error
|
||||||
|
build fails here
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::uint16_t port{};
|
||||||
|
if (not utils::get_next_available_port(config_->get_api_port(), port)) {
|
||||||
|
fmt::println("failed to detect if port is available|{}",
|
||||||
|
config_->get_api_port());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port != config_->get_api_port()) {
|
||||||
|
fmt::println("failed to listen on port|{}|next available|{}",
|
||||||
|
config_->get_api_port(), port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_system::instance().start();
|
||||||
|
|
||||||
|
nonce_thread_ =
|
||||||
|
std::make_unique<std::thread>([this]() { removed_expired_nonces(); });
|
||||||
|
|
||||||
|
server_->listen("127.0.0.1", config_->get_api_port());
|
||||||
|
if (this_server != nullptr) {
|
||||||
|
this_server = nullptr;
|
||||||
|
server_->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers::~handlers() {
|
||||||
|
if (nonce_thread_) {
|
||||||
|
stop_requested = true;
|
||||||
|
|
||||||
|
unique_mutex_lock lock(nonce_mtx_);
|
||||||
|
nonce_notify_.notify_all();
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
nonce_thread_->join();
|
||||||
|
nonce_thread_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
event_system::instance().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto handlers::data_directory_exists(provider_type prov,
|
||||||
|
std::string_view name) const -> bool {
|
||||||
|
auto data_dir = utils::path::combine(app_config::get_root_data_directory(),
|
||||||
|
{
|
||||||
|
app_config::get_provider_name(prov),
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
auto ret = utils::file::directory{data_dir}.exists();
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_mutex_lock lock(mtx_);
|
||||||
|
mtx_lookup_.erase(
|
||||||
|
fmt::format("{}-{}", name, app_config::get_provider_name(prov)));
|
||||||
|
lock.unlock();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_put_mount_location(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
|
auto location = req.get_param_value("location");
|
||||||
|
|
||||||
|
if (not data_directory_exists(prov, name)) {
|
||||||
|
res.status = http_error_codes::not_found;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_->set_mount_location(prov, name, location);
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_get_available_locations(httplib::Response &res) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
constexpr const std::array<std::string_view, 26U> letters{
|
||||||
|
"a:", "b:", "c:", "d:", "e:", "f:", "g:", "h:", "i:",
|
||||||
|
"j:", "k:", "l:", "m:", "n:", "o:", "p:", "q:", "r:",
|
||||||
|
"s:", "t:", "u:", "v:", "w:", "x:", "y:", "z:",
|
||||||
|
};
|
||||||
|
|
||||||
|
auto available = std::accumulate(
|
||||||
|
letters.begin(), letters.end(), std::vector<std::string_view>(),
|
||||||
|
[](auto &&vec, auto &&letter) -> std::vector<std::string_view> {
|
||||||
|
if (utils::file::directory{utils::path::combine(letter, {"\\"})}
|
||||||
|
.exists()) {
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec.emplace_back(letter);
|
||||||
|
return vec;
|
||||||
|
});
|
||||||
|
|
||||||
|
res.set_content(nlohmann::json(available).dump(), "application/json");
|
||||||
|
#else // !defined(_WIN32)
|
||||||
|
res.set_content(nlohmann::json(std::vector<std::string_view>()).dump(),
|
||||||
|
"application/json");
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_get_mount(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
|
|
||||||
|
if (not data_directory_exists(prov, name)) {
|
||||||
|
res.status = http_error_codes::not_found;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lines = launch_process(prov, 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'));
|
||||||
|
clean_json_config(prov, result);
|
||||||
|
|
||||||
|
res.set_content(result.dump(), "application/json");
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_get_mount_list(httplib::Response &res) {
|
||||||
|
auto data_dir = utils::file::directory{app_config::get_root_data_directory()};
|
||||||
|
|
||||||
|
nlohmann::json result;
|
||||||
|
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("encrypt");
|
||||||
|
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_location(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const {
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
|
|
||||||
|
if (not data_directory_exists(prov, name)) {
|
||||||
|
res.status = http_error_codes::not_found;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.set_content(
|
||||||
|
nlohmann::json({
|
||||||
|
{"Location", config_->get_mount_location(prov, name)},
|
||||||
|
})
|
||||||
|
.dump(),
|
||||||
|
"application/json");
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_get_mount_status(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const {
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
|
|
||||||
|
if (not data_directory_exists(prov, name)) {
|
||||||
|
res.status = http_error_codes::not_found;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lines = launch_process(prov, name, {"-status"});
|
||||||
|
|
||||||
|
auto result = nlohmann::json::parse(utils::string::join(lines, '\n'));
|
||||||
|
if (result.at("Location").get<std::string>().empty()) {
|
||||||
|
result.at("Location") = config_->get_mount_location(prov, name);
|
||||||
|
} else if (result.at("Active").get<bool>()) {
|
||||||
|
config_->set_mount_location(prov, name,
|
||||||
|
result.at("Location").get<std::string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
res.set_content(result.dump(), "application/json");
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_get_nonce(httplib::Response &res) {
|
||||||
|
mutex_lock lock(nonce_mtx_);
|
||||||
|
|
||||||
|
nonce_data nonce{};
|
||||||
|
nonce_lookup_[nonce.nonce] = nonce;
|
||||||
|
|
||||||
|
nlohmann::json data({{"nonce", nonce.nonce}});
|
||||||
|
res.set_content(data.dump(), "application/json");
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_get_settings(httplib::Response &res) const {
|
||||||
|
auto settings = config_->to_json();
|
||||||
|
settings[JSON_API_PASSWORD] = "";
|
||||||
|
settings.erase(JSON_MOUNT_LOCATIONS);
|
||||||
|
res.set_content(settings.dump(), "application/json");
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_post_add_mount(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const {
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
|
if (data_directory_exists(prov, name)) {
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cfg = nlohmann::json::parse(req.get_param_value("config"));
|
||||||
|
|
||||||
|
std::map<std::string, std::string> values{};
|
||||||
|
for (const auto &[key, value] : cfg.items()) {
|
||||||
|
if (value.is_object()) {
|
||||||
|
for (const auto &[key2, value2] : value.items()) {
|
||||||
|
auto sub_key = fmt::format("{}.{}", key, key2);
|
||||||
|
auto skip{false};
|
||||||
|
auto decrypted = decrypt_value(
|
||||||
|
config_, sub_key, value2.template get<std::string>(), skip);
|
||||||
|
if (skip) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
values[sub_key] = decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto skip{false};
|
||||||
|
auto decrypted =
|
||||||
|
decrypt_value(config_, key, value.template get<std::string>(), skip);
|
||||||
|
if (skip) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
values[key] = decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
launch_process(prov, name, {"-gc"});
|
||||||
|
for (auto &[key, value] : values) {
|
||||||
|
set_key_value(prov, name, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_post_mount(const httplib::Request &req,
|
||||||
|
httplib::Response &res) {
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
|
|
||||||
|
if (not data_directory_exists(prov, name)) {
|
||||||
|
res.status = http_error_codes::not_found;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto location = utils::path::absolute(req.get_param_value("location"));
|
||||||
|
auto unmount = utils::string::to_bool(req.get_param_value("unmount"));
|
||||||
|
|
||||||
|
if (unmount) {
|
||||||
|
launch_process(prov, name, {"-unmount"});
|
||||||
|
} else {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (utils::file::directory{location}.exists()) {
|
||||||
|
#else // !defined(_WIN32)
|
||||||
|
if (not utils::file::directory{location}.exists()) {
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
config_->set_mount_location(prov, name, "");
|
||||||
|
res.status = http_error_codes::internal_error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_->set_mount_location(prov, name, location);
|
||||||
|
|
||||||
|
static std::mutex mount_mtx;
|
||||||
|
mutex_lock lock(mount_mtx);
|
||||||
|
|
||||||
|
launch_process(prov, name, {location}, true);
|
||||||
|
launch_process(prov, name, {"-status"});
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_put_set_value_by_name(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const {
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
|
|
||||||
|
if (not data_directory_exists(prov, name)) {
|
||||||
|
res.status = http_error_codes::not_found;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto key = req.get_param_value("key");
|
||||||
|
auto value = req.get_param_value("value");
|
||||||
|
|
||||||
|
auto skip{false};
|
||||||
|
value = decrypt_value(config_, key, value, skip);
|
||||||
|
if (not skip) {
|
||||||
|
set_key_value(prov, name, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_put_settings(const httplib::Request &req,
|
||||||
|
httplib::Response &res) const {
|
||||||
|
auto data = nlohmann::json::parse(req.get_param_value("data"));
|
||||||
|
|
||||||
|
if (data.contains(JSON_API_PASSWORD)) {
|
||||||
|
auto password = decrypt(data.at(JSON_API_PASSWORD).get<std::string>(),
|
||||||
|
config_->get_api_password());
|
||||||
|
if (not password.empty()) {
|
||||||
|
config_->set_api_password(password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.contains(JSON_API_PORT)) {
|
||||||
|
config_->set_api_port(
|
||||||
|
utils::string::to_uint16(data.at(JSON_API_PORT).get<std::string>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.contains(JSON_API_USER)) {
|
||||||
|
config_->set_api_user(data.at(JSON_API_USER).get<std::string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto handlers::launch_process(provider_type prov, std::string_view name,
|
||||||
|
std::vector<std::string> args,
|
||||||
|
bool background) const
|
||||||
|
-> std::vector<std::string> {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
switch (prov) {
|
||||||
|
case provider_type::encrypt:
|
||||||
|
args.insert(args.begin(), "-en");
|
||||||
|
args.insert(std::next(args.begin()), "-na");
|
||||||
|
args.insert(std::next(args.begin(), 2U), std::string{name});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::remote: {
|
||||||
|
auto parts = utils::string::split(name, '_', false);
|
||||||
|
args.insert(args.begin(), "-rm");
|
||||||
|
args.insert(std::next(args.begin()),
|
||||||
|
fmt::format("{}:{}", parts.at(0U), parts.at(1U)));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case provider_type::s3:
|
||||||
|
args.insert(args.begin(), "-s3");
|
||||||
|
args.insert(std::next(args.begin()), "-na");
|
||||||
|
args.insert(std::next(args.begin(), 2U), std::string{name});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::sia:
|
||||||
|
args.insert(args.begin(), "-na");
|
||||||
|
args.insert(std::next(args.begin()), std::string{name});
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw utils::error::create_exception(function_name,
|
||||||
|
{
|
||||||
|
"provider is not supported",
|
||||||
|
provider_type_to_string(prov),
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_mutex_lock lock(mtx_);
|
||||||
|
auto &inst_mtx = mtx_lookup_[fmt::format(
|
||||||
|
"{}-{}", name, app_config::get_provider_name(prov))];
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
recur_mutex_lock inst_lock(inst_mtx);
|
||||||
|
if (background) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
std::array<char, MAX_PATH + 1U> path{};
|
||||||
|
::GetSystemDirectoryA(path.data(), path.size());
|
||||||
|
|
||||||
|
args.insert(args.begin(), utils::path::combine(path.data(), {"cmd.exe"}));
|
||||||
|
args.insert(std::next(args.begin()), "/c");
|
||||||
|
args.insert(std::next(args.begin(), 2U), "start");
|
||||||
|
args.insert(std::next(args.begin(), 3U), "");
|
||||||
|
args.insert(std::next(args.begin(), 4U), "/MIN");
|
||||||
|
args.insert(std::next(args.begin(), 5U), repertory_binary_);
|
||||||
|
#else // !defined(_WIN32)
|
||||||
|
args.insert(args.begin(), repertory_binary_);
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
|
||||||
|
std::vector<const char *> exec_args;
|
||||||
|
exec_args.reserve(args.size() + 1U);
|
||||||
|
for (const auto &arg : args) {
|
||||||
|
exec_args.push_back(arg.c_str());
|
||||||
|
}
|
||||||
|
exec_args.push_back(nullptr);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
_spawnv(_P_DETACH, exec_args.at(0U),
|
||||||
|
const_cast<char *const *>(exec_args.data()));
|
||||||
|
#else // !defined(_WIN32)
|
||||||
|
auto pid = fork();
|
||||||
|
if (pid == 0) {
|
||||||
|
setsid();
|
||||||
|
chdir("/");
|
||||||
|
close(STDIN_FILENO);
|
||||||
|
close(STDOUT_FILENO);
|
||||||
|
close(STDERR_FILENO);
|
||||||
|
open("/dev/null", O_RDONLY);
|
||||||
|
open("/dev/null", O_WRONLY);
|
||||||
|
open("/dev/null", O_WRONLY);
|
||||||
|
|
||||||
|
execvp(exec_args.at(0U), const_cast<char *const *>(exec_args.data()));
|
||||||
|
} else {
|
||||||
|
signal(SIGCHLD, SIG_IGN);
|
||||||
|
}
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::process::v1::ipstream out;
|
||||||
|
boost::process::v1::child proc(repertory_binary_,
|
||||||
|
boost::process::v1::args(args),
|
||||||
|
boost::process::v1::std_out > out);
|
||||||
|
|
||||||
|
std::string data;
|
||||||
|
std::string line;
|
||||||
|
while (out && std::getline(out, line)) {
|
||||||
|
data += line + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils::string::split(utils::string::replace(data, "\r", ""), '\n',
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::removed_expired_nonces() {
|
||||||
|
unique_mutex_lock lock(nonce_mtx_);
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
while (not stop_requested) {
|
||||||
|
lock.lock();
|
||||||
|
auto nonces = nonce_lookup_;
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
for (const auto &[key, value] : nonces) {
|
||||||
|
if (std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
|
std::chrono::system_clock::now() - value.creation)
|
||||||
|
.count() >= nonce_timeout) {
|
||||||
|
lock.lock();
|
||||||
|
nonce_lookup_.erase(key);
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stop_requested) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock.lock();
|
||||||
|
if (stop_requested) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
nonce_notify_.wait_for(lock, std::chrono::seconds(1U));
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::set_key_value(provider_type prov, std::string_view name,
|
||||||
|
std::string_view key,
|
||||||
|
std::string_view value) const {
|
||||||
|
std::vector<std::string> args;
|
||||||
|
args.emplace_back("-set");
|
||||||
|
args.emplace_back(key);
|
||||||
|
args.emplace_back(value);
|
||||||
|
launch_process(prov, name, args, false);
|
||||||
|
}
|
||||||
|
} // namespace repertory::ui
|
202
repertory/repertory/src/ui/mgmt_app_config.cpp
Normal file
202
repertory/repertory/src/ui/mgmt_app_config.cpp
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
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/mgmt_app_config.hpp"
|
||||||
|
|
||||||
|
#include "app_config.hpp"
|
||||||
|
#include "utils/error_utils.hpp"
|
||||||
|
#include "utils/file.hpp"
|
||||||
|
#include "utils/path.hpp"
|
||||||
|
#include "utils/unix.hpp"
|
||||||
|
#include "utils/windows.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
[[nodiscard]] auto from_json(const nlohmann::json &json)
|
||||||
|
-> std::unordered_map<repertory::provider_type,
|
||||||
|
std::unordered_map<std::string, std::string>> {
|
||||||
|
std::unordered_map<repertory::provider_type,
|
||||||
|
std::unordered_map<std::string, std::string>>
|
||||||
|
map_of_maps{
|
||||||
|
{repertory::provider_type::encrypt, nlohmann::json::object()},
|
||||||
|
{repertory::provider_type::remote, nlohmann::json::object()},
|
||||||
|
{repertory::provider_type::s3, nlohmann::json::object()},
|
||||||
|
{repertory::provider_type::sia, nlohmann::json::object()},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (json.is_null() || json.empty()) {
|
||||||
|
return map_of_maps;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &[prov, map] : map_of_maps) {
|
||||||
|
auto prov_str = repertory::provider_type_to_string(prov);
|
||||||
|
if (!json.contains(prov_str)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[key, value] : json.at(prov_str).items()) {
|
||||||
|
map[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map_of_maps;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto map_to_json(const auto &map_of_maps) -> nlohmann::json {
|
||||||
|
auto json = nlohmann::json::object();
|
||||||
|
for (const auto &[prov, map] : map_of_maps) {
|
||||||
|
for (const auto &[key, value] : map) {
|
||||||
|
json[repertory::provider_type_to_string(prov)][key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace repertory::ui {
|
||||||
|
mgmt_app_config::mgmt_app_config() {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto config_file =
|
||||||
|
utils::path::combine(app_config::get_root_data_directory(), {"ui.json"});
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (not utils::file::directory{app_config::get_root_data_directory()}
|
||||||
|
.create_directory()) {
|
||||||
|
throw utils::error::create_exception(
|
||||||
|
function_name, {
|
||||||
|
"failed to create directory",
|
||||||
|
app_config::get_root_data_directory(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json data;
|
||||||
|
if (utils::file::read_json_file(config_file, data)) {
|
||||||
|
api_password_ = data.at(JSON_API_PASSWORD).get<std::string>();
|
||||||
|
api_port_ = data.at(JSON_API_PORT).get<std::uint16_t>();
|
||||||
|
api_user_ = data.at(JSON_API_USER).get<std::string>();
|
||||||
|
locations_ = from_json(data.at(JSON_MOUNT_LOCATIONS));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::error::raise_error(
|
||||||
|
function_name, utils::get_last_error_code(),
|
||||||
|
fmt::format("failed to read file|{}", config_file));
|
||||||
|
save();
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
utils::error::raise_error(
|
||||||
|
function_name, ex, fmt::format("failed to read file|{}", config_file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mgmt_app_config::get_mount_location(provider_type prov,
|
||||||
|
std::string_view name) const
|
||||||
|
-> std::string {
|
||||||
|
recur_mutex_lock lock(mtx_);
|
||||||
|
if (locations_.contains(prov) &&
|
||||||
|
locations_.at(prov).contains(std::string{name})) {
|
||||||
|
return locations_.at(prov).at(std::string{name});
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_app_config::save() const {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto config_file =
|
||||||
|
utils::path::combine(app_config::get_root_data_directory(), {"ui.json"});
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (not utils::file::directory{app_config::get_root_data_directory()}
|
||||||
|
.create_directory()) {
|
||||||
|
utils::error::raise_error(
|
||||||
|
function_name, fmt::format("failed to create directory|{}",
|
||||||
|
app_config::get_root_data_directory()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils::file::write_json_file(config_file, to_json())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::error::raise_error(
|
||||||
|
function_name, utils::get_last_error_code(),
|
||||||
|
fmt::format("failed to save file|{}", config_file));
|
||||||
|
} catch (const std::exception &ex) {
|
||||||
|
utils::error::raise_error(
|
||||||
|
function_name, ex, fmt::format("failed to save file|{}", config_file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_app_config::set_api_password(std::string_view api_password) {
|
||||||
|
if (api_password_ == std::string{api_password}) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
api_password_ = std::string{api_password};
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_app_config::set_api_port(std::uint16_t api_port) {
|
||||||
|
if (api_port_ == api_port) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
api_port_ = api_port;
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_app_config::set_api_user(std::string_view api_user) {
|
||||||
|
if (api_user_ == std::string{api_user}) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
api_user_ = std::string{api_user};
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mgmt_app_config::set_mount_location(provider_type prov,
|
||||||
|
std::string_view name,
|
||||||
|
std::string_view location) {
|
||||||
|
if (name.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recur_mutex_lock lock(mtx_);
|
||||||
|
if (locations_[prov][std::string{name}] == std::string{location}) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
locations_[prov][std::string{name}] = std::string{location};
|
||||||
|
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mgmt_app_config::to_json() const -> nlohmann::json {
|
||||||
|
nlohmann::json data;
|
||||||
|
data[JSON_API_PASSWORD] = api_password_;
|
||||||
|
data[JSON_API_PORT] = api_port_;
|
||||||
|
data[JSON_API_USER] = api_user_;
|
||||||
|
data[JSON_MOUNT_LOCATIONS] = map_to_json(locations_);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
} // namespace repertory::ui
|
@ -54,21 +54,31 @@ namespace repertory {
|
|||||||
struct local_s3 final {
|
struct local_s3 final {
|
||||||
static constexpr const provider_type type{provider_type::s3};
|
static constexpr const provider_type type{provider_type::s3};
|
||||||
static constexpr const provider_type type2{provider_type::s3};
|
static constexpr const provider_type type2{provider_type::s3};
|
||||||
|
static constexpr const std::uint16_t port{0U};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct local_sia final {
|
struct local_sia final {
|
||||||
static constexpr const provider_type type{provider_type::sia};
|
static constexpr const provider_type type{provider_type::sia};
|
||||||
static constexpr const provider_type type2{provider_type::sia};
|
static constexpr const provider_type type2{provider_type::sia};
|
||||||
|
static constexpr const std::uint16_t port{0U};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct remote_s3 final {
|
struct remote_s3 final {
|
||||||
static constexpr const provider_type type{provider_type::remote};
|
static constexpr const provider_type type{provider_type::remote};
|
||||||
static constexpr const provider_type type2{provider_type::s3};
|
static constexpr const provider_type type2{provider_type::s3};
|
||||||
|
static constexpr const std::uint16_t port{0U};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct remote_sia final {
|
struct remote_sia final {
|
||||||
static constexpr const provider_type type{provider_type::remote};
|
static constexpr const provider_type type{provider_type::remote};
|
||||||
static constexpr const provider_type type2{provider_type::sia};
|
static constexpr const provider_type type2{provider_type::sia};
|
||||||
|
static constexpr const std::uint16_t port{0U};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct remote_linux_to_winfsp final {
|
||||||
|
static constexpr const provider_type type{provider_type::remote};
|
||||||
|
static constexpr const provider_type type2{provider_type::unknown};
|
||||||
|
static constexpr const std::uint16_t port{40001U};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename provider_t> class fuse_test : public ::testing::Test {
|
template <typename provider_t> class fuse_test : public ::testing::Test {
|
||||||
@ -113,7 +123,7 @@ protected:
|
|||||||
|
|
||||||
auto r_cfg = config->get_remote_mount();
|
auto r_cfg = config->get_remote_mount();
|
||||||
r_cfg.enable = true;
|
r_cfg.enable = true;
|
||||||
r_cfg.api_port = 30000U;
|
r_cfg.api_port = 40000U;
|
||||||
config->set_remote_mount(r_cfg);
|
config->set_remote_mount(r_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +170,7 @@ protected:
|
|||||||
|
|
||||||
auto r_cfg = config->get_remote_mount();
|
auto r_cfg = config->get_remote_mount();
|
||||||
r_cfg.enable = true;
|
r_cfg.enable = true;
|
||||||
r_cfg.api_port = 30000U;
|
r_cfg.api_port = 40000U;
|
||||||
config->set_remote_mount(r_cfg);
|
config->set_remote_mount(r_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +188,7 @@ protected:
|
|||||||
execute_mount(drive_args, mount_location);
|
execute_mount(drive_args, mount_location);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto mount_remote = [&]() {
|
const auto mount_remote = [&](std::uint16_t port = 40000U) {
|
||||||
{
|
{
|
||||||
mount_location2 = mount_location;
|
mount_location2 = mount_location;
|
||||||
|
|
||||||
@ -187,7 +197,8 @@ protected:
|
|||||||
{
|
{
|
||||||
"fuse_test",
|
"fuse_test",
|
||||||
app_config::get_provider_name(provider_t::type) + '_' +
|
app_config::get_provider_name(provider_t::type) + '_' +
|
||||||
app_config::get_provider_name(provider_t::type2),
|
app_config::get_provider_name(provider_t::type2) + '_' +
|
||||||
|
std::to_string(port),
|
||||||
});
|
});
|
||||||
|
|
||||||
mount_location = utils::path::combine(test_directory, {"mount"});
|
mount_location = utils::path::combine(test_directory, {"mount"});
|
||||||
@ -206,7 +217,7 @@ protected:
|
|||||||
"-dd",
|
"-dd",
|
||||||
config2->get_data_directory(),
|
config2->get_data_directory(),
|
||||||
"-rm",
|
"-rm",
|
||||||
"localhost:30000",
|
fmt::format("localhost:{}", port),
|
||||||
mount_location,
|
mount_location,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -233,6 +244,10 @@ protected:
|
|||||||
mount_sia();
|
mount_sia();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case provider_type::unknown:
|
||||||
|
mount_remote(provider_t::port);
|
||||||
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("remote provider type is not implemented");
|
throw std::runtime_error("remote provider type is not implemented");
|
||||||
return;
|
return;
|
||||||
@ -268,8 +283,8 @@ public:
|
|||||||
return file_path;
|
return file_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto create_file_and_test(std::string &file_name,
|
static auto create_file_and_test(std::string &file_name, mode_t perms)
|
||||||
mode_t perms) -> std::string {
|
-> std::string {
|
||||||
file_name += std::to_string(++provider_idx);
|
file_name += std::to_string(++provider_idx);
|
||||||
auto file_path = utils::path::combine(mount_location, {file_name});
|
auto file_path = utils::path::combine(mount_location, {file_name});
|
||||||
|
|
||||||
@ -287,7 +302,7 @@ public:
|
|||||||
EXPECT_TRUE(utils::file::file(file_path).exists());
|
EXPECT_TRUE(utils::file::file(file_path).exists());
|
||||||
EXPECT_FALSE(utils::file::directory(file_path).exists());
|
EXPECT_FALSE(utils::file::directory(file_path).exists());
|
||||||
|
|
||||||
struct stat64 unix_st {};
|
struct stat64 unix_st{};
|
||||||
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
EXPECT_EQ(0, stat64(file_path.c_str(), &unix_st));
|
||||||
EXPECT_EQ(getgid(), unix_st.st_gid);
|
EXPECT_EQ(getgid(), unix_st.st_gid);
|
||||||
EXPECT_EQ(getuid(), unix_st.st_uid);
|
EXPECT_EQ(getuid(), unix_st.st_uid);
|
||||||
@ -299,17 +314,19 @@ public:
|
|||||||
return create_file_and_test(file_name, ACCESSPERMS);
|
return create_file_and_test(file_name, ACCESSPERMS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto create_directory_and_test(std::string &dir_name,
|
static auto create_directory_and_test(std::string &dir_name, mode_t perms)
|
||||||
mode_t perms) -> std::string {
|
-> std::string {
|
||||||
dir_name += std::to_string(++provider_idx);
|
dir_name += std::to_string(++provider_idx);
|
||||||
|
|
||||||
auto dir_path = utils::path::combine(mount_location, {dir_name});
|
auto dir_path = utils::path::combine(mount_location, {dir_name});
|
||||||
mkdir(dir_path.c_str(), perms);
|
mkdir(dir_path.c_str(), perms);
|
||||||
|
|
||||||
EXPECT_TRUE(utils::file::directory(dir_path).exists());
|
EXPECT_TRUE(utils::file::directory(dir_path).exists());
|
||||||
|
EXPECT_EQ(0U, utils::file::directory(dir_path).count(false));
|
||||||
|
EXPECT_EQ(0U, utils::file::directory(dir_path).count(true));
|
||||||
EXPECT_FALSE(utils::file::file(dir_path).exists());
|
EXPECT_FALSE(utils::file::file(dir_path).exists());
|
||||||
|
|
||||||
struct stat64 unix_st {};
|
struct stat64 unix_st{};
|
||||||
EXPECT_EQ(0, stat64(dir_path.c_str(), &unix_st));
|
EXPECT_EQ(0, stat64(dir_path.c_str(), &unix_st));
|
||||||
EXPECT_EQ(getgid(), unix_st.st_gid);
|
EXPECT_EQ(getgid(), unix_st.st_gid);
|
||||||
EXPECT_EQ(getuid(), unix_st.st_uid);
|
EXPECT_EQ(getuid(), unix_st.st_uid);
|
||||||
@ -410,9 +427,15 @@ std::string fuse_test<provider_t>::mount_location;
|
|||||||
template <typename provider_t>
|
template <typename provider_t>
|
||||||
std::string fuse_test<provider_t>::mount_location2;
|
std::string fuse_test<provider_t>::mount_location2;
|
||||||
|
|
||||||
using fuse_provider_types = ::testing::Types<local_s3, remote_s3>;
|
#if defined(__linux__)
|
||||||
|
using fuse_provider_types =
|
||||||
|
::testing::Types<local_s3, remote_s3, local_sia, remote_sia>;
|
||||||
// using fuse_provider_types =
|
// using fuse_provider_types =
|
||||||
// ::testing::Types<local_s3, remote_s3, local_sia, remote_sia>;
|
// ::testing::Types<local_s3, remote_s3, local_sia, remote_sia,
|
||||||
|
// remote_linux_to_winfsp>;
|
||||||
|
#else // !defined(__linux__)
|
||||||
|
build fails here
|
||||||
|
#endif // defined(_WIN32)
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif // !defined(_WIN32)
|
#endif // !defined(_WIN32)
|
||||||
|
@ -45,21 +45,31 @@ namespace repertory {
|
|||||||
struct local_s3 final {
|
struct local_s3 final {
|
||||||
static constexpr const provider_type type{provider_type::s3};
|
static constexpr const provider_type type{provider_type::s3};
|
||||||
static constexpr const provider_type type2{provider_type::s3};
|
static constexpr const provider_type type2{provider_type::s3};
|
||||||
|
static constexpr const std::uint16_t port{0U};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct local_sia final {
|
struct local_sia final {
|
||||||
static constexpr const provider_type type{provider_type::sia};
|
static constexpr const provider_type type{provider_type::sia};
|
||||||
static constexpr const provider_type type2{provider_type::sia};
|
static constexpr const provider_type type2{provider_type::sia};
|
||||||
|
static constexpr const std::uint16_t port{0U};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct remote_s3 final {
|
struct remote_s3 final {
|
||||||
static constexpr const provider_type type{provider_type::remote};
|
static constexpr const provider_type type{provider_type::remote};
|
||||||
static constexpr const provider_type type2{provider_type::s3};
|
static constexpr const provider_type type2{provider_type::s3};
|
||||||
|
static constexpr const std::uint16_t port{0U};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct remote_sia final {
|
struct remote_sia final {
|
||||||
static constexpr const provider_type type{provider_type::remote};
|
static constexpr const provider_type type{provider_type::remote};
|
||||||
static constexpr const provider_type type2{provider_type::sia};
|
static constexpr const provider_type type2{provider_type::sia};
|
||||||
|
static constexpr const std::uint16_t port{0U};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct remote_winfsp_to_linux final {
|
||||||
|
static constexpr const provider_type type{provider_type::remote};
|
||||||
|
static constexpr const provider_type type2{provider_type::unknown};
|
||||||
|
static constexpr const std::uint16_t port{40001U};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename provider_t> class winfsp_test : public ::testing::Test {
|
template <typename provider_t> class winfsp_test : public ::testing::Test {
|
||||||
@ -102,7 +112,7 @@ protected:
|
|||||||
|
|
||||||
auto r_cfg = config->get_remote_mount();
|
auto r_cfg = config->get_remote_mount();
|
||||||
r_cfg.enable = true;
|
r_cfg.enable = true;
|
||||||
r_cfg.api_port = 30000U;
|
r_cfg.api_port = 40000U;
|
||||||
config->set_remote_mount(r_cfg);
|
config->set_remote_mount(r_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +141,7 @@ protected:
|
|||||||
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
ASSERT_TRUE(utils::file::directory(cfg_directory).create_directory());
|
||||||
|
|
||||||
auto config =
|
auto config =
|
||||||
std::make_unique<app_config>(provider_type::s3, cfg_directory);
|
std::make_unique<app_config>(provider_type::sia, cfg_directory);
|
||||||
{
|
{
|
||||||
app_config src_cfg{
|
app_config src_cfg{
|
||||||
provider_type::sia,
|
provider_type::sia,
|
||||||
@ -144,7 +154,7 @@ protected:
|
|||||||
|
|
||||||
auto r_cfg = config->get_remote_mount();
|
auto r_cfg = config->get_remote_mount();
|
||||||
r_cfg.enable = true;
|
r_cfg.enable = true;
|
||||||
r_cfg.api_port = 30000U;
|
r_cfg.api_port = 40000U;
|
||||||
config->set_remote_mount(r_cfg);
|
config->set_remote_mount(r_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,13 +170,15 @@ protected:
|
|||||||
execute_mount(drive_args, mount_location);
|
execute_mount(drive_args, mount_location);
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto mount_remote = [&]() {
|
const auto mount_remote = [&](std::uint16_t port = 40000U) {
|
||||||
{
|
{
|
||||||
auto test_directory = utils::path::combine(
|
auto test_directory = utils::path::combine(
|
||||||
test::get_test_output_dir(),
|
test::get_test_output_dir(),
|
||||||
{
|
{
|
||||||
"winfsp_test",
|
"winfsp_test",
|
||||||
app_config::get_provider_name(provider_type::remote),
|
app_config::get_provider_name(provider_t::type) + '_' +
|
||||||
|
app_config::get_provider_name(provider_t::type2) + '_' +
|
||||||
|
std::to_string(port),
|
||||||
});
|
});
|
||||||
|
|
||||||
mount_location2 = mount_location;
|
mount_location2 = mount_location;
|
||||||
@ -184,7 +196,7 @@ protected:
|
|||||||
"-dd",
|
"-dd",
|
||||||
config->get_data_directory(),
|
config->get_data_directory(),
|
||||||
"-rm",
|
"-rm",
|
||||||
"localhost:30000",
|
fmt::format("localhost:{}", port),
|
||||||
mount_location,
|
mount_location,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -211,6 +223,10 @@ protected:
|
|||||||
mount_sia();
|
mount_sia();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case provider_type::unknown:
|
||||||
|
mount_remote(provider_t::port);
|
||||||
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("remote provider type is not implemented");
|
throw std::runtime_error("remote provider type is not implemented");
|
||||||
return;
|
return;
|
||||||
@ -228,7 +244,9 @@ protected:
|
|||||||
static void TearDownTestCase() {
|
static void TearDownTestCase() {
|
||||||
if (provider_t::type == provider_type::remote) {
|
if (provider_t::type == provider_type::remote) {
|
||||||
execute_unmount(drive_args2, mount_location);
|
execute_unmount(drive_args2, mount_location);
|
||||||
execute_unmount(drive_args, mount_location2);
|
if (provider_t::type2 != provider_type::unknown) {
|
||||||
|
execute_unmount(drive_args, mount_location2);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
execute_unmount(drive_args, mount_location);
|
execute_unmount(drive_args, mount_location);
|
||||||
}
|
}
|
||||||
@ -245,6 +263,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void execute_unmount(auto args, auto location) {
|
static void execute_unmount(auto args, auto location) {
|
||||||
|
std::this_thread::sleep_for(10s);
|
||||||
auto unmounted{false};
|
auto unmounted{false};
|
||||||
|
|
||||||
auto unmount_cmd =
|
auto unmount_cmd =
|
||||||
@ -280,9 +299,9 @@ std::string winfsp_test<provider_t>::mount_location;
|
|||||||
template <typename provider_t>
|
template <typename provider_t>
|
||||||
std::string winfsp_test<provider_t>::mount_location2;
|
std::string winfsp_test<provider_t>::mount_location2;
|
||||||
|
|
||||||
// using winfsp_provider_types = ::testing::Types<local_s3, remote_s3,
|
using winfsp_provider_types =
|
||||||
// local_sia, remote_sia>;
|
::testing::Types<local_s3, remote_s3, local_sia, remote_sia,
|
||||||
using winfsp_provider_types = ::testing::Types<local_s3, remote_s3>;
|
remote_winfsp_to_linux>;
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif // defined(_WIN32)
|
#endif // defined(_WIN32)
|
||||||
|
@ -48,8 +48,8 @@ public:
|
|||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto check_parent_access(const std::string &,
|
auto check_parent_access(const std::string &, int) const
|
||||||
int) const -> api_error override {
|
-> api_error override {
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,8 +84,8 @@ public:
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto get_item_meta(const std::string &api_path,
|
auto get_item_meta(const std::string &api_path, api_meta_map &meta) const
|
||||||
api_meta_map &meta) const -> api_error override {
|
-> api_error override {
|
||||||
meta = const_cast<mock_fuse_drive *>(this)->meta_[api_path];
|
meta = const_cast<mock_fuse_drive *>(this)->meta_[api_path];
|
||||||
return api_error::success;
|
return api_error::success;
|
||||||
}
|
}
|
||||||
@ -124,8 +124,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto rename_file(const std::string &from_api_path,
|
auto rename_file(const std::string &from_api_path,
|
||||||
const std::string &to_api_path,
|
const std::string &to_api_path, bool overwrite)
|
||||||
bool overwrite) -> int override {
|
-> int override {
|
||||||
const auto from_file_path =
|
const auto from_file_path =
|
||||||
utils::path::combine(mount_location_, {from_api_path});
|
utils::path::combine(mount_location_, {from_api_path});
|
||||||
const auto to_file_path =
|
const auto to_file_path =
|
||||||
@ -152,7 +152,13 @@ public:
|
|||||||
const std::string &value) override {
|
const std::string &value) override {
|
||||||
meta_[api_path][key] = value;
|
meta_[api_path][key] = value;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
void set_item_meta(const std::string &api_path,
|
||||||
|
const api_meta_map &meta) override {
|
||||||
|
for (const auto &[key, value] : meta) {
|
||||||
|
meta_[api_path][key] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif // !defined(_WIN32)
|
#endif // !defined(_WIN32)
|
||||||
|
@ -36,6 +36,10 @@ private:
|
|||||||
const bool allow_rename_;
|
const bool allow_rename_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
MOCK_METHOD(bool, check_version,
|
||||||
|
(std::string & required_version, std::string &returned_version),
|
||||||
|
(const, override));
|
||||||
|
|
||||||
MOCK_METHOD(api_error, create_directory,
|
MOCK_METHOD(api_error, create_directory,
|
||||||
(const std::string &api_path, api_meta_map &meta), (override));
|
(const std::string &api_path, api_meta_map &meta), (override));
|
||||||
|
|
||||||
|
763
repertory/repertory_test/src/app_config_test.cpp
Normal file
763
repertory/repertory_test/src/app_config_test.cpp
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2025> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "test_common.hpp"
|
||||||
|
|
||||||
|
#include "app_config.hpp"
|
||||||
|
#include "utils/path.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
class app_config_test : public ::testing::Test {
|
||||||
|
public:
|
||||||
|
static std::atomic<std::uint64_t> idx;
|
||||||
|
|
||||||
|
std::string encrypt_directory;
|
||||||
|
std::string remote_directory;
|
||||||
|
std::string s3_directory;
|
||||||
|
std::string sia_directory;
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
encrypt_directory = utils::path::combine(test::get_test_output_dir(),
|
||||||
|
{
|
||||||
|
"app_config_test",
|
||||||
|
"encrypt",
|
||||||
|
std::to_string(++idx),
|
||||||
|
});
|
||||||
|
|
||||||
|
remote_directory = utils::path::combine(test::get_test_output_dir(),
|
||||||
|
{
|
||||||
|
"app_config_test",
|
||||||
|
"remote",
|
||||||
|
std::to_string(++idx),
|
||||||
|
});
|
||||||
|
|
||||||
|
s3_directory = utils::path::combine(test::get_test_output_dir(),
|
||||||
|
{
|
||||||
|
"app_config_test",
|
||||||
|
"s3",
|
||||||
|
std::to_string(++idx),
|
||||||
|
});
|
||||||
|
|
||||||
|
sia_directory = utils::path::combine(test::get_test_output_dir(),
|
||||||
|
{
|
||||||
|
"app_config_test",
|
||||||
|
"sia",
|
||||||
|
std::to_string(++idx),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void remove_unused_types(auto &data, provider_type prov) {
|
||||||
|
switch (prov) {
|
||||||
|
case provider_type::encrypt:
|
||||||
|
data.erase(JSON_DOWNLOAD_TIMEOUT_SECS);
|
||||||
|
data.erase(JSON_ENABLE_DOWNLOAD_TIMEOUT);
|
||||||
|
data.erase(JSON_EVICTION_DELAY_MINS);
|
||||||
|
data.erase(JSON_EVICTION_USE_ACCESS_TIME);
|
||||||
|
data.erase(JSON_HOST_CONFIG);
|
||||||
|
data.erase(JSON_MAX_CACHE_SIZE_BYTES);
|
||||||
|
data.erase(JSON_MAX_UPLOAD_COUNT);
|
||||||
|
data.erase(JSON_ONLINE_CHECK_RETRY_SECS);
|
||||||
|
data.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
|
||||||
|
data.erase(JSON_REMOTE_CONFIG);
|
||||||
|
data.erase(JSON_RETRY_READ_COUNT);
|
||||||
|
data.erase(JSON_RING_BUFFER_FILE_SIZE);
|
||||||
|
data.erase(JSON_S3_CONFIG);
|
||||||
|
data.erase(JSON_SIA_CONFIG);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::remote:
|
||||||
|
data.erase(JSON_DATABASE_TYPE);
|
||||||
|
data.erase(JSON_DOWNLOAD_TIMEOUT_SECS);
|
||||||
|
data.erase(JSON_ENABLE_DOWNLOAD_TIMEOUT);
|
||||||
|
data.erase(JSON_ENCRYPT_CONFIG);
|
||||||
|
data.erase(JSON_EVICTION_DELAY_MINS);
|
||||||
|
data.erase(JSON_EVICTION_USE_ACCESS_TIME);
|
||||||
|
data.erase(JSON_HIGH_FREQ_INTERVAL_SECS);
|
||||||
|
data.erase(JSON_HOST_CONFIG);
|
||||||
|
data.erase(JSON_LOW_FREQ_INTERVAL_SECS);
|
||||||
|
data.erase(JSON_MAX_CACHE_SIZE_BYTES);
|
||||||
|
data.erase(JSON_MAX_UPLOAD_COUNT);
|
||||||
|
data.erase(JSON_MED_FREQ_INTERVAL_SECS);
|
||||||
|
data.erase(JSON_ONLINE_CHECK_RETRY_SECS);
|
||||||
|
data.erase(JSON_PREFERRED_DOWNLOAD_TYPE);
|
||||||
|
data.erase(JSON_REMOTE_MOUNT);
|
||||||
|
data.erase(JSON_RETRY_READ_COUNT);
|
||||||
|
data.erase(JSON_RING_BUFFER_FILE_SIZE);
|
||||||
|
data.erase(JSON_S3_CONFIG);
|
||||||
|
data.erase(JSON_SIA_CONFIG);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::s3:
|
||||||
|
data.erase(JSON_ENCRYPT_CONFIG);
|
||||||
|
data.erase(JSON_HOST_CONFIG);
|
||||||
|
data.erase(JSON_REMOTE_CONFIG);
|
||||||
|
data.erase(JSON_SIA_CONFIG);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::sia:
|
||||||
|
data.erase(JSON_ENCRYPT_CONFIG);
|
||||||
|
data.erase(JSON_REMOTE_CONFIG);
|
||||||
|
data.erase(JSON_S3_CONFIG);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atomic<std::uint64_t> app_config_test::idx{0U};
|
||||||
|
|
||||||
|
static void defaults_tests(const json &json_data, provider_type prov) {
|
||||||
|
json json_defaults = {
|
||||||
|
{JSON_API_PORT, app_config::default_rpc_port()},
|
||||||
|
{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_PASSWORD);
|
||||||
|
ASSERT_EQ(std::size_t(default_api_password_size),
|
||||||
|
json_data.at(JSON_API_PASSWORD).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_PASSWORD,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_api_password,
|
||||||
|
&app_config::set_api_password, "", "auth",
|
||||||
|
JSON_API_PASSWORD, "auth2");
|
||||||
|
}},
|
||||||
|
{JSON_API_PORT,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_api_port,
|
||||||
|
&app_config::set_api_port, std::uint16_t{0U},
|
||||||
|
std::uint16_t{1024U}, JSON_API_PORT, "1025");
|
||||||
|
}},
|
||||||
|
{JSON_API_USER,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_api_user,
|
||||||
|
&app_config::set_api_user, "", "user",
|
||||||
|
JSON_API_USER, "user2");
|
||||||
|
}},
|
||||||
|
{JSON_DOWNLOAD_TIMEOUT_SECS,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_download_timeout_secs,
|
||||||
|
&app_config::set_download_timeout_secs,
|
||||||
|
std::uint8_t{min_download_timeout_secs + 1U},
|
||||||
|
std::uint8_t{min_download_timeout_secs + 2U},
|
||||||
|
JSON_DOWNLOAD_TIMEOUT_SECS,
|
||||||
|
std::to_string(min_download_timeout_secs + 2U));
|
||||||
|
|
||||||
|
cfg.set_download_timeout_secs(min_download_timeout_secs - 1U);
|
||||||
|
EXPECT_EQ(min_download_timeout_secs, cfg.get_download_timeout_secs());
|
||||||
|
}},
|
||||||
|
{JSON_DATABASE_TYPE,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_database_type,
|
||||||
|
&app_config::set_database_type,
|
||||||
|
database_type::rocksdb, database_type::sqlite,
|
||||||
|
JSON_DATABASE_TYPE, "rocksdb");
|
||||||
|
}},
|
||||||
|
{JSON_ENABLE_DOWNLOAD_TIMEOUT,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_enable_download_timeout,
|
||||||
|
&app_config::set_enable_download_timeout, true,
|
||||||
|
false, JSON_ENABLE_DOWNLOAD_TIMEOUT, "1");
|
||||||
|
}},
|
||||||
|
{JSON_ENABLE_DRIVE_EVENTS,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_enable_drive_events,
|
||||||
|
&app_config::set_enable_drive_events, true, false,
|
||||||
|
JSON_ENABLE_DRIVE_EVENTS, "1");
|
||||||
|
}},
|
||||||
|
#if defined(_WIN32)
|
||||||
|
{JSON_ENABLE_MOUNT_MANAGER,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_enable_mount_manager,
|
||||||
|
&app_config::set_enable_mount_manager, true, false,
|
||||||
|
JSON_ENABLE_MOUNT_MANAGER, "1");
|
||||||
|
}},
|
||||||
|
#endif // defined(_WIN32)
|
||||||
|
{JSON_ENCRYPT_CONFIG,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
encrypt_config cfg1{};
|
||||||
|
cfg1.encryption_token = "1";
|
||||||
|
cfg1.path = "2";
|
||||||
|
|
||||||
|
encrypt_config cfg2{};
|
||||||
|
cfg2.encryption_token = "2";
|
||||||
|
cfg2.path = "1";
|
||||||
|
|
||||||
|
ASSERT_NE(cfg1, cfg2);
|
||||||
|
test_getter_setter(cfg, &app_config::get_encrypt_config,
|
||||||
|
&app_config::set_encrypt_config, cfg1, cfg2, "",
|
||||||
|
"");
|
||||||
|
|
||||||
|
encrypt_config cfg3{};
|
||||||
|
cfg3.encryption_token = "3";
|
||||||
|
cfg3.path = "4";
|
||||||
|
|
||||||
|
auto value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_ENCRYPT_CONFIG, JSON_ENCRYPTION_TOKEN),
|
||||||
|
cfg3.encryption_token);
|
||||||
|
EXPECT_STREQ(cfg3.encryption_token.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_ENCRYPT_CONFIG, JSON_PATH), cfg3.path);
|
||||||
|
EXPECT_STREQ(cfg3.path.c_str(), value.c_str());
|
||||||
|
}},
|
||||||
|
{JSON_EVENT_LEVEL,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_event_level,
|
||||||
|
&app_config::set_event_level, event_level::critical,
|
||||||
|
event_level::debug, JSON_EVENT_LEVEL, "info");
|
||||||
|
}},
|
||||||
|
{JSON_EVICTION_DELAY_MINS,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_eviction_delay_mins,
|
||||||
|
&app_config::set_eviction_delay_mins,
|
||||||
|
std::uint32_t{0U}, std::uint32_t{1U},
|
||||||
|
JSON_EVICTION_DELAY_MINS, "2");
|
||||||
|
}},
|
||||||
|
{JSON_EVICTION_USE_ACCESS_TIME,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_eviction_uses_accessed_time,
|
||||||
|
&app_config::set_eviction_uses_accessed_time, true,
|
||||||
|
false, JSON_EVICTION_USE_ACCESS_TIME, "1");
|
||||||
|
}},
|
||||||
|
{JSON_HIGH_FREQ_INTERVAL_SECS,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(
|
||||||
|
cfg, &app_config::get_high_frequency_interval_secs,
|
||||||
|
&app_config::set_high_frequency_interval_secs,
|
||||||
|
std::uint16_t{default_high_freq_interval_secs + 1U},
|
||||||
|
std::uint16_t{default_high_freq_interval_secs + 2U},
|
||||||
|
JSON_HIGH_FREQ_INTERVAL_SECS,
|
||||||
|
std::to_string(default_high_freq_interval_secs + 3U));
|
||||||
|
|
||||||
|
cfg.set_high_frequency_interval_secs(0U);
|
||||||
|
EXPECT_EQ(1U, cfg.get_high_frequency_interval_secs());
|
||||||
|
}},
|
||||||
|
{JSON_HOST_CONFIG,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
host_config cfg1{};
|
||||||
|
cfg1.agent_string = "1";
|
||||||
|
cfg1.api_password = "2";
|
||||||
|
cfg1.api_user = "3";
|
||||||
|
cfg1.api_port = 4U;
|
||||||
|
cfg1.host_name_or_ip = "5";
|
||||||
|
cfg1.path = "6";
|
||||||
|
cfg1.protocol = "http";
|
||||||
|
cfg1.timeout_ms = 8U;
|
||||||
|
|
||||||
|
host_config cfg2{};
|
||||||
|
cfg2.agent_string = "9";
|
||||||
|
cfg2.api_password = "10";
|
||||||
|
cfg2.api_user = "11";
|
||||||
|
cfg2.api_port = 12U;
|
||||||
|
cfg2.host_name_or_ip = "13";
|
||||||
|
cfg2.path = "14";
|
||||||
|
cfg2.protocol = "https";
|
||||||
|
cfg2.timeout_ms = 16U;
|
||||||
|
|
||||||
|
ASSERT_NE(cfg1, cfg2);
|
||||||
|
|
||||||
|
test_getter_setter(cfg, &app_config::get_host_config,
|
||||||
|
&app_config::set_host_config, cfg1, cfg2, "", "");
|
||||||
|
|
||||||
|
host_config cfg3{};
|
||||||
|
cfg3.agent_string = "17";
|
||||||
|
cfg3.api_password = "18";
|
||||||
|
cfg3.api_user = "19";
|
||||||
|
cfg3.api_port = 20U;
|
||||||
|
cfg3.host_name_or_ip = "21";
|
||||||
|
cfg3.path = "22";
|
||||||
|
cfg3.protocol = "http";
|
||||||
|
cfg3.timeout_ms = 24;
|
||||||
|
|
||||||
|
auto value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_AGENT_STRING),
|
||||||
|
cfg3.agent_string);
|
||||||
|
EXPECT_STREQ(cfg3.agent_string.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PASSWORD),
|
||||||
|
cfg3.api_password);
|
||||||
|
EXPECT_STREQ(cfg3.api_password.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_USER),
|
||||||
|
cfg3.api_user);
|
||||||
|
EXPECT_STREQ(cfg3.api_user.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PORT),
|
||||||
|
std::to_string(cfg3.api_port));
|
||||||
|
EXPECT_STREQ(std::to_string(cfg3.api_port).c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_HOST_NAME_OR_IP),
|
||||||
|
cfg3.host_name_or_ip);
|
||||||
|
EXPECT_STREQ(cfg3.host_name_or_ip.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PATH), cfg3.path);
|
||||||
|
EXPECT_STREQ(cfg3.path.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_PROTOCOL),
|
||||||
|
cfg3.protocol);
|
||||||
|
EXPECT_STREQ(cfg3.protocol.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_TIMEOUT_MS),
|
||||||
|
std::to_string(cfg3.timeout_ms));
|
||||||
|
EXPECT_STREQ(std::to_string(cfg3.timeout_ms).c_str(), value.c_str());
|
||||||
|
}},
|
||||||
|
{JSON_LOW_FREQ_INTERVAL_SECS,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(
|
||||||
|
cfg, &app_config::get_low_frequency_interval_secs,
|
||||||
|
&app_config::set_low_frequency_interval_secs,
|
||||||
|
std::uint16_t{default_low_freq_interval_secs + 1U},
|
||||||
|
std::uint16_t{default_low_freq_interval_secs + 2U},
|
||||||
|
JSON_LOW_FREQ_INTERVAL_SECS,
|
||||||
|
std::to_string(default_low_freq_interval_secs + 3U));
|
||||||
|
|
||||||
|
cfg.set_low_frequency_interval_secs(0U);
|
||||||
|
EXPECT_EQ(1U, cfg.get_low_frequency_interval_secs());
|
||||||
|
}},
|
||||||
|
{JSON_MAX_CACHE_SIZE_BYTES,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(
|
||||||
|
cfg, &app_config::get_max_cache_size_bytes,
|
||||||
|
&app_config::set_max_cache_size_bytes, min_cache_size_bytes + 1U,
|
||||||
|
min_cache_size_bytes + 2U, JSON_MAX_CACHE_SIZE_BYTES,
|
||||||
|
std::to_string(min_cache_size_bytes + 3U));
|
||||||
|
|
||||||
|
cfg.set_max_cache_size_bytes(min_cache_size_bytes - 1U);
|
||||||
|
EXPECT_EQ(min_cache_size_bytes, cfg.get_max_cache_size_bytes());
|
||||||
|
}},
|
||||||
|
{JSON_MAX_UPLOAD_COUNT,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_max_upload_count,
|
||||||
|
&app_config::set_max_upload_count, std::uint8_t{1U},
|
||||||
|
std::uint8_t{2U}, JSON_MAX_UPLOAD_COUNT, "3");
|
||||||
|
|
||||||
|
cfg.set_max_upload_count(0U);
|
||||||
|
EXPECT_EQ(1U, cfg.get_max_upload_count());
|
||||||
|
}},
|
||||||
|
{JSON_MED_FREQ_INTERVAL_SECS,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(
|
||||||
|
cfg, &app_config::get_med_frequency_interval_secs,
|
||||||
|
&app_config::set_med_frequency_interval_secs,
|
||||||
|
std::uint16_t{default_med_freq_interval_secs + 1U},
|
||||||
|
std::uint16_t{default_med_freq_interval_secs + 2U},
|
||||||
|
JSON_MED_FREQ_INTERVAL_SECS,
|
||||||
|
std::to_string(default_med_freq_interval_secs + 3U));
|
||||||
|
|
||||||
|
cfg.set_med_frequency_interval_secs(0U);
|
||||||
|
EXPECT_EQ(1U, cfg.get_med_frequency_interval_secs());
|
||||||
|
}},
|
||||||
|
{JSON_ONLINE_CHECK_RETRY_SECS,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_online_check_retry_secs,
|
||||||
|
&app_config::set_online_check_retry_secs,
|
||||||
|
std::uint16_t{min_online_check_retry_secs + 1U},
|
||||||
|
std::uint16_t{min_online_check_retry_secs + 2U},
|
||||||
|
JSON_ONLINE_CHECK_RETRY_SECS,
|
||||||
|
std::to_string(min_online_check_retry_secs + 3U));
|
||||||
|
|
||||||
|
cfg.set_online_check_retry_secs(min_online_check_retry_secs - 1U);
|
||||||
|
EXPECT_EQ(min_online_check_retry_secs,
|
||||||
|
cfg.get_online_check_retry_secs());
|
||||||
|
}},
|
||||||
|
{JSON_PREFERRED_DOWNLOAD_TYPE,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_preferred_download_type,
|
||||||
|
&app_config::set_preferred_download_type,
|
||||||
|
download_type::direct, download_type::default_,
|
||||||
|
JSON_PREFERRED_DOWNLOAD_TYPE, "ring_buffer");
|
||||||
|
}},
|
||||||
|
{JSON_REMOTE_CONFIG,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
remote::remote_config remote_cfg1{};
|
||||||
|
remote_cfg1.api_port = 1U;
|
||||||
|
remote_cfg1.encryption_token = "2";
|
||||||
|
remote_cfg1.host_name_or_ip = "3";
|
||||||
|
remote_cfg1.max_connections = 4U;
|
||||||
|
remote_cfg1.recv_timeout_ms = 5U;
|
||||||
|
remote_cfg1.send_timeout_ms = 6U;
|
||||||
|
|
||||||
|
remote::remote_config remote_cfg2{};
|
||||||
|
remote_cfg1.api_port = 6U;
|
||||||
|
remote_cfg1.encryption_token = "5";
|
||||||
|
remote_cfg1.host_name_or_ip = "4";
|
||||||
|
remote_cfg1.max_connections = 3U;
|
||||||
|
remote_cfg1.recv_timeout_ms = 2U;
|
||||||
|
remote_cfg1.send_timeout_ms = 1U;
|
||||||
|
|
||||||
|
ASSERT_NE(remote_cfg1, remote_cfg2);
|
||||||
|
|
||||||
|
test_getter_setter(cfg, &app_config::get_remote_config,
|
||||||
|
&app_config::set_remote_config, remote_cfg1,
|
||||||
|
remote_cfg2, "", "");
|
||||||
|
|
||||||
|
remote::remote_config remote_cfg3{};
|
||||||
|
remote_cfg1.api_port = 7U;
|
||||||
|
remote_cfg1.encryption_token = "8";
|
||||||
|
remote_cfg1.host_name_or_ip = "9";
|
||||||
|
remote_cfg1.max_connections = 10U;
|
||||||
|
remote_cfg1.recv_timeout_ms = 11U;
|
||||||
|
remote_cfg1.send_timeout_ms = 12U;
|
||||||
|
|
||||||
|
auto value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_API_PORT),
|
||||||
|
std::to_string(remote_cfg3.api_port));
|
||||||
|
EXPECT_STREQ(std::to_string(remote_cfg3.api_port).c_str(),
|
||||||
|
value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_ENCRYPTION_TOKEN),
|
||||||
|
remote_cfg3.encryption_token);
|
||||||
|
EXPECT_STREQ(remote_cfg3.encryption_token.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_HOST_NAME_OR_IP),
|
||||||
|
remote_cfg3.host_name_or_ip);
|
||||||
|
EXPECT_STREQ(remote_cfg3.host_name_or_ip.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_MAX_CONNECTIONS),
|
||||||
|
std::to_string(remote_cfg3.max_connections));
|
||||||
|
EXPECT_STREQ(std::to_string(remote_cfg3.max_connections).c_str(),
|
||||||
|
value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_RECV_TIMEOUT_MS),
|
||||||
|
std::to_string(remote_cfg3.recv_timeout_ms));
|
||||||
|
EXPECT_STREQ(std::to_string(remote_cfg3.recv_timeout_ms).c_str(),
|
||||||
|
value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_SEND_TIMEOUT_MS),
|
||||||
|
std::to_string(remote_cfg3.send_timeout_ms));
|
||||||
|
EXPECT_STREQ(std::to_string(remote_cfg3.send_timeout_ms).c_str(),
|
||||||
|
value.c_str());
|
||||||
|
}},
|
||||||
|
{JSON_REMOTE_MOUNT,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
remote::remote_mount mnt_cfg1{};
|
||||||
|
mnt_cfg1.api_port = 1U;
|
||||||
|
mnt_cfg1.client_pool_size = 2U;
|
||||||
|
mnt_cfg1.enable = false;
|
||||||
|
mnt_cfg1.encryption_token = "3";
|
||||||
|
|
||||||
|
remote::remote_mount mnt_cfg2{};
|
||||||
|
mnt_cfg2.api_port = 3U;
|
||||||
|
mnt_cfg2.client_pool_size = 4U;
|
||||||
|
mnt_cfg2.enable = true;
|
||||||
|
mnt_cfg2.encryption_token = "5";
|
||||||
|
|
||||||
|
ASSERT_NE(mnt_cfg1, mnt_cfg2);
|
||||||
|
|
||||||
|
test_getter_setter(cfg, &app_config::get_remote_mount,
|
||||||
|
&app_config::set_remote_mount, mnt_cfg1, mnt_cfg2,
|
||||||
|
"", "");
|
||||||
|
|
||||||
|
remote::remote_mount mnt_cfg3{};
|
||||||
|
mnt_cfg3.api_port = 9U;
|
||||||
|
mnt_cfg3.client_pool_size = 10U;
|
||||||
|
mnt_cfg3.enable = false;
|
||||||
|
mnt_cfg3.encryption_token = "11";
|
||||||
|
|
||||||
|
auto value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_API_PORT),
|
||||||
|
std::to_string(mnt_cfg3.api_port));
|
||||||
|
EXPECT_STREQ(std::to_string(mnt_cfg3.api_port).c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_CLIENT_POOL_SIZE),
|
||||||
|
std::to_string(mnt_cfg3.client_pool_size));
|
||||||
|
EXPECT_STREQ(std::to_string(mnt_cfg3.client_pool_size).c_str(),
|
||||||
|
value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_ENABLE_REMOTE_MOUNT),
|
||||||
|
utils::string::from_bool(mnt_cfg3.enable));
|
||||||
|
EXPECT_STREQ(utils::string::from_bool(mnt_cfg3.enable).c_str(),
|
||||||
|
value.c_str());
|
||||||
|
}},
|
||||||
|
{JSON_RETRY_READ_COUNT,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_retry_read_count,
|
||||||
|
&app_config::set_retry_read_count,
|
||||||
|
std::uint16_t{min_retry_read_count + 1U},
|
||||||
|
std::uint16_t{min_retry_read_count + 2U},
|
||||||
|
JSON_RETRY_READ_COUNT,
|
||||||
|
std::to_string(min_retry_read_count + 3U));
|
||||||
|
|
||||||
|
cfg.set_retry_read_count(min_retry_read_count - 1U);
|
||||||
|
EXPECT_EQ(min_retry_read_count, cfg.get_retry_read_count());
|
||||||
|
}},
|
||||||
|
{JSON_RING_BUFFER_FILE_SIZE,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(cfg, &app_config::get_ring_buffer_file_size,
|
||||||
|
&app_config::set_ring_buffer_file_size,
|
||||||
|
std::uint16_t{min_ring_buffer_file_size + 1U},
|
||||||
|
std::uint16_t{min_ring_buffer_file_size + 2U},
|
||||||
|
JSON_RING_BUFFER_FILE_SIZE,
|
||||||
|
std::to_string(min_ring_buffer_file_size + 3U));
|
||||||
|
|
||||||
|
cfg.set_ring_buffer_file_size(min_ring_buffer_file_size - 1U);
|
||||||
|
EXPECT_EQ(min_ring_buffer_file_size, cfg.get_ring_buffer_file_size());
|
||||||
|
|
||||||
|
cfg.set_ring_buffer_file_size(max_ring_buffer_file_size + 1U);
|
||||||
|
EXPECT_EQ(max_ring_buffer_file_size, cfg.get_ring_buffer_file_size());
|
||||||
|
}},
|
||||||
|
{JSON_S3_CONFIG,
|
||||||
|
[](auto &&cfg) {
|
||||||
|
s3_config cfg1{};
|
||||||
|
cfg1.access_key = "1";
|
||||||
|
cfg1.bucket = "2";
|
||||||
|
cfg1.encryption_token = "3";
|
||||||
|
cfg1.region = "4";
|
||||||
|
cfg1.secret_key = "5";
|
||||||
|
cfg1.timeout_ms = 6U;
|
||||||
|
cfg1.url = "7";
|
||||||
|
cfg1.use_path_style = false;
|
||||||
|
cfg1.use_region_in_url = false;
|
||||||
|
|
||||||
|
s3_config cfg2{};
|
||||||
|
cfg2.access_key = "8";
|
||||||
|
cfg2.bucket = "9";
|
||||||
|
cfg2.encryption_token = "10";
|
||||||
|
cfg2.region = "11";
|
||||||
|
cfg2.secret_key = "12";
|
||||||
|
cfg2.timeout_ms = 13U;
|
||||||
|
cfg2.url = "14";
|
||||||
|
cfg2.use_path_style = true;
|
||||||
|
cfg2.use_region_in_url = true;
|
||||||
|
|
||||||
|
ASSERT_NE(cfg1, cfg2);
|
||||||
|
|
||||||
|
test_getter_setter(cfg, &app_config::get_s3_config,
|
||||||
|
&app_config::set_s3_config, cfg1, cfg2, "", "");
|
||||||
|
|
||||||
|
s3_config cfg3{};
|
||||||
|
cfg3.access_key = "8";
|
||||||
|
cfg3.bucket = "9";
|
||||||
|
cfg3.encryption_token = "10";
|
||||||
|
cfg3.region = "11";
|
||||||
|
cfg3.secret_key = "12";
|
||||||
|
cfg3.timeout_ms = 13U;
|
||||||
|
cfg3.url = "14";
|
||||||
|
cfg3.use_path_style = true;
|
||||||
|
cfg3.use_region_in_url = true;
|
||||||
|
|
||||||
|
auto value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_ACCESS_KEY),
|
||||||
|
cfg3.access_key);
|
||||||
|
EXPECT_STREQ(cfg3.access_key.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_BUCKET), cfg3.bucket);
|
||||||
|
EXPECT_STREQ(cfg3.bucket.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_ENCRYPTION_TOKEN),
|
||||||
|
cfg3.encryption_token);
|
||||||
|
EXPECT_STREQ(cfg3.encryption_token.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_REGION), cfg3.region);
|
||||||
|
EXPECT_STREQ(cfg3.region.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_SECRET_KEY),
|
||||||
|
cfg3.secret_key);
|
||||||
|
EXPECT_STREQ(cfg3.secret_key.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_TIMEOUT_MS),
|
||||||
|
std::to_string(cfg3.timeout_ms));
|
||||||
|
EXPECT_STREQ(std::to_string(cfg3.timeout_ms).c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_URL), cfg3.url);
|
||||||
|
EXPECT_STREQ(cfg3.url.c_str(), value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_USE_PATH_STYLE),
|
||||||
|
utils::string::from_bool(cfg3.use_path_style));
|
||||||
|
EXPECT_STREQ(utils::string::from_bool(cfg3.use_path_style).c_str(),
|
||||||
|
value.c_str());
|
||||||
|
|
||||||
|
value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_USE_REGION_IN_URL),
|
||||||
|
utils::string::from_bool(cfg3.use_region_in_url));
|
||||||
|
EXPECT_STREQ(utils::string::from_bool(cfg3.use_region_in_url).c_str(),
|
||||||
|
value.c_str());
|
||||||
|
}},
|
||||||
|
{JSON_SIA_CONFIG,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
sia_config cfg1{};
|
||||||
|
cfg1.bucket = "1";
|
||||||
|
|
||||||
|
sia_config cfg2{};
|
||||||
|
cfg2.bucket = "2";
|
||||||
|
|
||||||
|
ASSERT_NE(cfg1, cfg2);
|
||||||
|
|
||||||
|
test_getter_setter(cfg, &app_config::get_sia_config,
|
||||||
|
&app_config::set_sia_config, cfg1, cfg2, "", "");
|
||||||
|
|
||||||
|
sia_config cfg3{};
|
||||||
|
cfg3.bucket = "3";
|
||||||
|
|
||||||
|
auto value = cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_SIA_CONFIG, JSON_BUCKET), cfg3.bucket);
|
||||||
|
EXPECT_STREQ(cfg3.bucket.c_str(), value.c_str());
|
||||||
|
}},
|
||||||
|
{JSON_TASK_WAIT_MS,
|
||||||
|
[](app_config &cfg) {
|
||||||
|
test_getter_setter(
|
||||||
|
cfg, &app_config::get_task_wait_ms, &app_config::set_task_wait_ms,
|
||||||
|
std::uint16_t{min_task_wait_ms + 1U},
|
||||||
|
std::uint16_t{min_task_wait_ms + 2U}, JSON_TASK_WAIT_MS,
|
||||||
|
std::to_string(min_task_wait_ms + 3U));
|
||||||
|
|
||||||
|
cfg.set_task_wait_ms(min_task_wait_ms - 1U);
|
||||||
|
EXPECT_EQ(min_task_wait_ms, cfg.get_task_wait_ms());
|
||||||
|
}},
|
||||||
|
};
|
||||||
|
|
||||||
|
remove_unused_types(methods, prov);
|
||||||
|
|
||||||
|
for (const auto &[key, test_function] : methods) {
|
||||||
|
fmt::println("testing setting|{}-{}", app_config::get_provider_name(prov),
|
||||||
|
key);
|
||||||
|
test_function(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(app_config_test, encrypt_config) {
|
||||||
|
app_config config(provider_type::encrypt, encrypt_directory);
|
||||||
|
defaults_tests(config.get_json(), provider_type::encrypt);
|
||||||
|
common_tests(config, provider_type::encrypt);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(app_config_test, remote_config) {
|
||||||
|
app_config config(provider_type::remote, remote_directory);
|
||||||
|
defaults_tests(config.get_json(), provider_type::remote);
|
||||||
|
common_tests(config, provider_type::remote);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(app_config_test, s3_config) {
|
||||||
|
app_config config(provider_type::s3, s3_directory);
|
||||||
|
defaults_tests(config.get_json(), provider_type::s3);
|
||||||
|
common_tests(config, provider_type::s3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(app_config_test, sia_config) {
|
||||||
|
app_config config(provider_type::sia, sia_directory);
|
||||||
|
defaults_tests(config.get_json(), provider_type::sia);
|
||||||
|
common_tests(config, provider_type::sia);
|
||||||
|
}
|
||||||
|
} // namespace repertory
|
@ -24,7 +24,7 @@
|
|||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
TEST(atomic, atomic_primitive) {
|
TEST(atomic_test, atomic_primitive) {
|
||||||
atomic<std::uint16_t> value;
|
atomic<std::uint16_t> value;
|
||||||
value = 5U;
|
value = 5U;
|
||||||
EXPECT_EQ(5U, static_cast<std::uint16_t>(value));
|
EXPECT_EQ(5U, static_cast<std::uint16_t>(value));
|
||||||
@ -35,7 +35,7 @@ TEST(atomic, atomic_primitive) {
|
|||||||
EXPECT_EQ(6U, value.load());
|
EXPECT_EQ(6U, value.load());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(atomic, atomic_primitive_equality) {
|
TEST(atomic_test, atomic_primitive_equality) {
|
||||||
atomic<std::uint16_t> value1{5U};
|
atomic<std::uint16_t> value1{5U};
|
||||||
atomic<std::uint16_t> value2{5U};
|
atomic<std::uint16_t> value2{5U};
|
||||||
EXPECT_EQ(value1, value1);
|
EXPECT_EQ(value1, value1);
|
||||||
@ -45,7 +45,7 @@ TEST(atomic, atomic_primitive_equality) {
|
|||||||
EXPECT_EQ(static_cast<std::uint16_t>(value2), 5U);
|
EXPECT_EQ(static_cast<std::uint16_t>(value2), 5U);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(atomic, atomic_primitive_inequality) {
|
TEST(atomic_test, atomic_primitive_inequality) {
|
||||||
atomic<std::uint16_t> value1{5U};
|
atomic<std::uint16_t> value1{5U};
|
||||||
atomic<std::uint16_t> value2{6U};
|
atomic<std::uint16_t> value2{6U};
|
||||||
EXPECT_NE(value1, value2);
|
EXPECT_NE(value1, value2);
|
||||||
@ -53,7 +53,7 @@ TEST(atomic, atomic_primitive_inequality) {
|
|||||||
EXPECT_NE(static_cast<std::uint16_t>(value2), 5U);
|
EXPECT_NE(static_cast<std::uint16_t>(value2), 5U);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(atomic, atomic_struct) {
|
TEST(atomic_test, atomic_struct) {
|
||||||
atomic<encrypt_config> value{
|
atomic<encrypt_config> value{
|
||||||
encrypt_config{
|
encrypt_config{
|
||||||
.encryption_token = "token",
|
.encryption_token = "token",
|
||||||
|
198
repertory/repertory_test/src/clean_json_test.cpp
Normal file
198
repertory/repertory_test/src/clean_json_test.cpp
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
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 "types/repertory.hpp"
|
||||||
|
|
||||||
|
namespace repertory {
|
||||||
|
TEST(clean_json_test, can_clean_values) {
|
||||||
|
auto result = clean_json_value(JSON_API_PASSWORD, "moose");
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
|
||||||
|
result = clean_json_value(
|
||||||
|
fmt::format("{}.{}", JSON_ENCRYPT_CONFIG, JSON_ENCRYPTION_TOKEN),
|
||||||
|
"moose");
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
|
||||||
|
result = clean_json_value(
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PASSWORD), "moose");
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
|
||||||
|
result = clean_json_value(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_ENCRYPTION_TOKEN), "moose");
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
|
||||||
|
result = clean_json_value(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_ENCRYPTION_TOKEN), "moose");
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
|
||||||
|
result = clean_json_value(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_ENCRYPTION_TOKEN), "moose");
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
|
||||||
|
result = clean_json_value(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_SECRET_KEY), "moose");
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(clean_json_test, can_clean_encrypt_config) {
|
||||||
|
auto dir =
|
||||||
|
utils::path::combine(test::get_test_output_dir(), {
|
||||||
|
"clean_json_test",
|
||||||
|
"encrypt",
|
||||||
|
});
|
||||||
|
app_config cfg(provider_type::encrypt, dir);
|
||||||
|
cfg.set_value_by_name(JSON_API_PASSWORD, "moose");
|
||||||
|
cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_ENCRYPT_CONFIG, JSON_ENCRYPTION_TOKEN),
|
||||||
|
"moose");
|
||||||
|
cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_ENCRYPTION_TOKEN), "moose");
|
||||||
|
|
||||||
|
auto data = cfg.get_json();
|
||||||
|
EXPECT_FALSE(data.at(JSON_API_PASSWORD).get<std::string>().empty());
|
||||||
|
EXPECT_FALSE(data.at(JSON_ENCRYPT_CONFIG)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
EXPECT_FALSE(data.at(JSON_REMOTE_MOUNT)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
|
||||||
|
clean_json_config(cfg.get_provider_type(), data);
|
||||||
|
EXPECT_TRUE(data.at(JSON_API_PASSWORD).get<std::string>().empty());
|
||||||
|
EXPECT_TRUE(data.at(JSON_ENCRYPT_CONFIG)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
EXPECT_TRUE(data.at(JSON_REMOTE_MOUNT)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(clean_json_test, can_clean_remote_config) {
|
||||||
|
auto dir =
|
||||||
|
utils::path::combine(test::get_test_output_dir(), {
|
||||||
|
"clean_json_test",
|
||||||
|
"remote",
|
||||||
|
});
|
||||||
|
app_config cfg(provider_type::remote, dir);
|
||||||
|
cfg.set_value_by_name(JSON_API_PASSWORD, "moose");
|
||||||
|
cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_CONFIG, JSON_ENCRYPTION_TOKEN), "moose");
|
||||||
|
|
||||||
|
auto data = cfg.get_json();
|
||||||
|
EXPECT_FALSE(data.at(JSON_API_PASSWORD).get<std::string>().empty());
|
||||||
|
EXPECT_FALSE(data.at(JSON_REMOTE_CONFIG)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
|
||||||
|
clean_json_config(cfg.get_provider_type(), data);
|
||||||
|
EXPECT_TRUE(data.at(JSON_API_PASSWORD).get<std::string>().empty());
|
||||||
|
EXPECT_TRUE(data.at(JSON_REMOTE_CONFIG)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(clean_json_test, can_clean_s3_config) {
|
||||||
|
auto dir =
|
||||||
|
utils::path::combine(test::get_test_output_dir(), {
|
||||||
|
"clean_json_test",
|
||||||
|
"s3",
|
||||||
|
});
|
||||||
|
app_config cfg(provider_type::s3, dir);
|
||||||
|
cfg.set_value_by_name(JSON_API_PASSWORD, "moose");
|
||||||
|
cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_ENCRYPTION_TOKEN), "moose");
|
||||||
|
cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_S3_CONFIG, JSON_ENCRYPTION_TOKEN), "moose");
|
||||||
|
cfg.set_value_by_name(fmt::format("{}.{}", JSON_S3_CONFIG, JSON_SECRET_KEY),
|
||||||
|
"moose");
|
||||||
|
|
||||||
|
auto data = cfg.get_json();
|
||||||
|
EXPECT_FALSE(data.at(JSON_API_PASSWORD).get<std::string>().empty());
|
||||||
|
EXPECT_FALSE(data.at(JSON_REMOTE_MOUNT)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
EXPECT_FALSE(data.at(JSON_S3_CONFIG)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
EXPECT_FALSE(
|
||||||
|
data.at(JSON_S3_CONFIG).at(JSON_SECRET_KEY).get<std::string>().empty());
|
||||||
|
|
||||||
|
clean_json_config(cfg.get_provider_type(), data);
|
||||||
|
EXPECT_TRUE(data.at(JSON_API_PASSWORD).get<std::string>().empty());
|
||||||
|
EXPECT_TRUE(data.at(JSON_REMOTE_MOUNT)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
EXPECT_TRUE(data.at(JSON_S3_CONFIG)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
EXPECT_TRUE(
|
||||||
|
data.at(JSON_S3_CONFIG).at(JSON_SECRET_KEY).get<std::string>().empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(clean_json_test, can_clean_sia_config) {
|
||||||
|
auto dir =
|
||||||
|
utils::path::combine(test::get_test_output_dir(), {
|
||||||
|
"clean_json_test",
|
||||||
|
"sia",
|
||||||
|
});
|
||||||
|
app_config cfg(provider_type::sia, dir);
|
||||||
|
cfg.set_value_by_name(JSON_API_PASSWORD, "moose");
|
||||||
|
cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_HOST_CONFIG, JSON_API_PASSWORD), "moose");
|
||||||
|
cfg.set_value_by_name(
|
||||||
|
fmt::format("{}.{}", JSON_REMOTE_MOUNT, JSON_ENCRYPTION_TOKEN), "moose");
|
||||||
|
|
||||||
|
auto data = cfg.get_json();
|
||||||
|
EXPECT_FALSE(data.at(JSON_API_PASSWORD).get<std::string>().empty());
|
||||||
|
EXPECT_FALSE(data.at(JSON_HOST_CONFIG)
|
||||||
|
.at(JSON_API_PASSWORD)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
EXPECT_FALSE(data.at(JSON_REMOTE_MOUNT)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
|
||||||
|
clean_json_config(cfg.get_provider_type(), data);
|
||||||
|
EXPECT_TRUE(data.at(JSON_API_PASSWORD).get<std::string>().empty());
|
||||||
|
EXPECT_TRUE(data.at(JSON_HOST_CONFIG)
|
||||||
|
.at(JSON_API_PASSWORD)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
EXPECT_TRUE(data.at(JSON_REMOTE_MOUNT)
|
||||||
|
.at(JSON_ENCRYPTION_TOKEN)
|
||||||
|
.get<std::string>()
|
||||||
|
.empty());
|
||||||
|
}
|
||||||
|
} // namespace repertory
|
@ -1,696 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright <2018-2025> <scott.e.graves@protonmail.com>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include "test_common.hpp"
|
|
||||||
|
|
||||||
#include "app_config.hpp"
|
|
||||||
#include "events/event_system.hpp"
|
|
||||||
#include "utils/common.hpp"
|
|
||||||
#include "utils/file_utils.hpp"
|
|
||||||
#include "utils/path.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
|
||||||
class config_test : public ::testing::Test {
|
|
||||||
public:
|
|
||||||
console_consumer cs;
|
|
||||||
|
|
||||||
static std::atomic<std::uint64_t> idx;
|
|
||||||
|
|
||||||
std::string s3_directory;
|
|
||||||
std::string sia_directory;
|
|
||||||
|
|
||||||
void SetUp() override {
|
|
||||||
s3_directory = utils::path::combine(test::get_test_output_dir(),
|
|
||||||
{
|
|
||||||
"config_test",
|
|
||||||
"s3",
|
|
||||||
std::to_string(++idx),
|
|
||||||
});
|
|
||||||
|
|
||||||
sia_directory = utils::path::combine(test::get_test_output_dir(),
|
|
||||||
{
|
|
||||||
"config_test",
|
|
||||||
"sia",
|
|
||||||
std::to_string(++idx),
|
|
||||||
});
|
|
||||||
event_system::instance().start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TearDown() override {
|
|
||||||
event_system::instance().stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::atomic<std::uint64_t> config_test::idx{0U};
|
|
||||||
|
|
||||||
TEST_F(config_test, api_path) {
|
|
||||||
std::string original_value;
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_api_auth();
|
|
||||||
EXPECT_EQ(48U, original_value.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, api_auth) {
|
|
||||||
std::string original_value;
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_api_auth();
|
|
||||||
config.set_api_auth(original_value.substr(0, 20));
|
|
||||||
EXPECT_EQ(original_value.substr(0, 20), config.get_api_auth());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value.substr(0, 20), config.get_api_auth());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, api_port) {
|
|
||||||
std::uint16_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_api_port();
|
|
||||||
config.set_api_port(original_value + 5);
|
|
||||||
EXPECT_EQ(original_value + 5, config.get_api_port());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 5, config.get_api_port());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, api_user) {
|
|
||||||
std::string original_value;
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_api_user();
|
|
||||||
config.set_api_user(original_value.substr(0, 2));
|
|
||||||
EXPECT_EQ(original_value.substr(0, 2), config.get_api_user());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value.substr(0, 2), config.get_api_user());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, download_timeout_secs) {
|
|
||||||
std::uint8_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_download_timeout_secs();
|
|
||||||
config.set_download_timeout_secs(original_value + 5);
|
|
||||||
EXPECT_EQ(original_value + 5, config.get_download_timeout_secs());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 5, config.get_download_timeout_secs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, enable_download_timeout) {
|
|
||||||
bool original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_enable_download_timeout();
|
|
||||||
config.set_enable_download_timeout(not original_value);
|
|
||||||
EXPECT_EQ(not original_value, config.get_enable_download_timeout());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(not original_value, config.get_enable_download_timeout());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, enable_drive_events) {
|
|
||||||
bool original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_enable_drive_events();
|
|
||||||
config.set_enable_drive_events(not original_value);
|
|
||||||
EXPECT_EQ(not original_value, config.get_enable_drive_events());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(not original_value, config.get_enable_drive_events());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
TEST_F(config_test, enable_mount_manager) {
|
|
||||||
bool original_value;
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_enable_mount_manager();
|
|
||||||
config.set_enable_mount_manager(not original_value);
|
|
||||||
EXPECT_EQ(not original_value, config.get_enable_mount_manager());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(not original_value, config.get_enable_mount_manager());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
TEST_F(config_test, event_level) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_event_level(event_level::debug);
|
|
||||||
EXPECT_EQ(event_level::debug, config.get_event_level());
|
|
||||||
config.set_event_level(event_level::warn);
|
|
||||||
EXPECT_EQ(event_level::warn, config.get_event_level());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(event_level::warn, config.get_event_level());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, eviction_delay_mins) {
|
|
||||||
std::uint32_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_eviction_delay_mins();
|
|
||||||
config.set_eviction_delay_mins(original_value + 5);
|
|
||||||
EXPECT_EQ(original_value + 5, config.get_eviction_delay_mins());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 5, config.get_eviction_delay_mins());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, eviction_uses_accessed_time) {
|
|
||||||
bool original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_eviction_uses_accessed_time();
|
|
||||||
config.set_eviction_uses_accessed_time(not original_value);
|
|
||||||
EXPECT_EQ(not original_value, config.get_eviction_uses_accessed_time());
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(not original_value, config.get_eviction_uses_accessed_time());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, high_frequency_interval_secs) {
|
|
||||||
std::uint16_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_high_frequency_interval_secs();
|
|
||||||
config.set_high_frequency_interval_secs(original_value + 5U);
|
|
||||||
EXPECT_EQ(original_value + 5U, config.get_high_frequency_interval_secs());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 5U, config.get_high_frequency_interval_secs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, low_frequency_interval_secs) {
|
|
||||||
std::uint16_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_low_frequency_interval_secs();
|
|
||||||
config.set_low_frequency_interval_secs(original_value + 5U);
|
|
||||||
EXPECT_EQ(original_value + 5U, config.get_low_frequency_interval_secs());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 5U, config.get_low_frequency_interval_secs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, med_frequency_interval_secs) {
|
|
||||||
std::uint16_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_med_frequency_interval_secs();
|
|
||||||
config.set_med_frequency_interval_secs(original_value + 5U);
|
|
||||||
EXPECT_EQ(original_value + 5U, config.get_med_frequency_interval_secs());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 5U, config.get_med_frequency_interval_secs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, max_cache_size_bytes) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_max_cache_size_bytes(100 * 1024 * 1024);
|
|
||||||
EXPECT_EQ(100U * 1024 * 1024, config.get_max_cache_size_bytes());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(100U * 1024 * 1024, config.get_max_cache_size_bytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, max_upload_count) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_max_upload_count(8U);
|
|
||||||
EXPECT_EQ(std::uint8_t(8U), config.get_max_upload_count());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(std::uint8_t(8U), config.get_max_upload_count());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_max_upload_count(0U);
|
|
||||||
EXPECT_EQ(std::uint8_t(1U), config.get_max_upload_count());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, online_check_retry_secs) {
|
|
||||||
std::uint16_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_online_check_retry_secs();
|
|
||||||
config.set_online_check_retry_secs(original_value + 1);
|
|
||||||
EXPECT_EQ(original_value + 1, config.get_online_check_retry_secs());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 1, config.get_online_check_retry_secs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, online_check_retry_secs_minimum_value) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_online_check_retry_secs(14);
|
|
||||||
EXPECT_EQ(15, config.get_online_check_retry_secs());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, orphaned_file_retention_days) {
|
|
||||||
std::uint16_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_orphaned_file_retention_days();
|
|
||||||
config.set_orphaned_file_retention_days(original_value + 1);
|
|
||||||
EXPECT_EQ(original_value + 1, config.get_orphaned_file_retention_days());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 1, config.get_orphaned_file_retention_days());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, orphaned_file_retention_days_minimum_value) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_orphaned_file_retention_days(0);
|
|
||||||
EXPECT_EQ(1, config.get_orphaned_file_retention_days());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, orphaned_file_retention_days_maximum_value) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_orphaned_file_retention_days(32);
|
|
||||||
EXPECT_EQ(31, config.get_orphaned_file_retention_days());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, get_cache_directory) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_STREQ(utils::path::combine(sia_directory, {"cache"}).c_str(),
|
|
||||||
config.get_cache_directory().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, get_config_file_path) {
|
|
||||||
{
|
|
||||||
const auto config_file = utils::path::absolute(
|
|
||||||
utils::path::combine(sia_directory, {"config.json"}));
|
|
||||||
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_STREQ(config_file.c_str(), config.get_config_file_path().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, get_data_directory) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_STREQ(sia_directory.c_str(), config.get_data_directory().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, get_log_directory) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_STREQ(utils::path::combine(sia_directory, {"logs"}).c_str(),
|
|
||||||
config.get_log_directory().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, ring_buffer_file_size) {
|
|
||||||
std::uint16_t original_value;
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_ring_buffer_file_size();
|
|
||||||
config.set_ring_buffer_file_size(original_value + 5u);
|
|
||||||
EXPECT_EQ(original_value + 5u, config.get_ring_buffer_file_size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 5u, config.get_ring_buffer_file_size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, ring_buffer_file_size_minimum_size) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_ring_buffer_file_size(63u);
|
|
||||||
EXPECT_EQ(64u, config.get_ring_buffer_file_size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(64u, config.get_ring_buffer_file_size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, ring_buffer_file_size_maximum_size) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_ring_buffer_file_size(1025u);
|
|
||||||
EXPECT_EQ(1024u, config.get_ring_buffer_file_size());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(1024u, config.get_ring_buffer_file_size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, preferred_download_type) {
|
|
||||||
download_type original_value;
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_preferred_download_type();
|
|
||||||
config.set_preferred_download_type(download_type::ring_buffer);
|
|
||||||
EXPECT_NE(original_value, config.get_preferred_download_type());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_NE(original_value, config.get_preferred_download_type());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, default_agent_name) {
|
|
||||||
EXPECT_STREQ("Sia-Agent",
|
|
||||||
app_config::default_agent_name(provider_type::sia).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, default_api_port) {
|
|
||||||
EXPECT_EQ(9980U, app_config::default_api_port(provider_type::sia));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, default_data_directory) {
|
|
||||||
const std::array<std::string, 1U> data_directory = {
|
|
||||||
app_config::default_data_directory(provider_type::sia),
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
const auto local_app_data = utils::get_environment_variable("localappdata");
|
|
||||||
#endif
|
|
||||||
#if defined(__linux__)
|
|
||||||
const auto local_app_data =
|
|
||||||
utils::path::combine(utils::get_environment_variable("HOME"), {".local"});
|
|
||||||
#endif
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
const auto local_app_data = utils::path::combine(
|
|
||||||
utils::get_environment_variable("HOME"), {"Library/Application Support"});
|
|
||||||
#endif
|
|
||||||
auto expected_directory =
|
|
||||||
utils::path::combine(local_app_data, {"/repertory2/sia"});
|
|
||||||
EXPECT_STREQ(expected_directory.c_str(), data_directory[0].c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, default_rpc_port) {
|
|
||||||
EXPECT_EQ(10000U, app_config::default_rpc_port(provider_type::sia));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, get_provider_display_name) {
|
|
||||||
EXPECT_STREQ(
|
|
||||||
"Sia", app_config::get_provider_display_name(provider_type::sia).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, get_provider_name) {
|
|
||||||
EXPECT_STREQ("sia",
|
|
||||||
app_config::get_provider_name(provider_type::sia).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, get_version) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(REPERTORY_CONFIG_VERSION, config.get_version());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEST_F(config_test, enable_remote_mount) {
|
|
||||||
// bool original_value{};
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// original_value = config.get_enable_remote_mount();
|
|
||||||
// config.set_enable_remote_mount(not original_value);
|
|
||||||
// EXPECT_EQ(not original_value, config.get_enable_remote_mount());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(not original_value, config.get_enable_remote_mount());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, is_remote_mount) {
|
|
||||||
// bool original_value{};
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// original_value = config.get_is_remote_mount();
|
|
||||||
// config.set_is_remote_mount(not original_value);
|
|
||||||
// EXPECT_EQ(not original_value, config.get_is_remote_mount());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(not original_value, config.get_is_remote_mount());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, enable_remote_mount_fails_if_remote_mount_is_true) {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// config.set_is_remote_mount(true);
|
|
||||||
// config.set_enable_remote_mount(true);
|
|
||||||
// EXPECT_FALSE(config.get_enable_remote_mount());
|
|
||||||
// EXPECT_TRUE(config.get_is_remote_mount());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, set_is_remote_mount_fails_if_enable_remote_mount_is_true)
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// config.set_enable_remote_mount(true);
|
|
||||||
// config.set_is_remote_mount(true);
|
|
||||||
// EXPECT_FALSE(config.get_is_remote_mount());
|
|
||||||
// EXPECT_TRUE(config.get_enable_remote_mount());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, remote_host_name_or_ip) {
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// config.set_remote_host_name_or_ip("my.host.name");
|
|
||||||
// EXPECT_STREQ("my.host.name",
|
|
||||||
// config.get_remote_host_name_or_ip().c_str());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_STREQ("my.host.name",
|
|
||||||
// config.get_remote_host_name_or_ip().c_str());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, remote_api_port) {
|
|
||||||
// std::uint16_t original_value{};
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// original_value = config.get_remote_api_port();
|
|
||||||
// config.set_remote_api_port(original_value + 5);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_api_port());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_api_port());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, remote_receive_timeout_secs) {
|
|
||||||
// std::uint16_t original_value{};
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// original_value = config.get_remote_receive_timeout_secs();
|
|
||||||
// config.set_remote_receive_timeout_secs(original_value + 5);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_receive_timeout_secs());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_receive_timeout_secs());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, remote_send_timeout_secs) {
|
|
||||||
// std::uint16_t original_value{};
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// original_value = config.get_remote_send_timeout_secs();
|
|
||||||
// config.set_remote_send_timeout_secs(original_value + 5);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_send_timeout_secs());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, remote_encryption_token) {
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// config.set_remote_encryption_token("myToken");
|
|
||||||
// EXPECT_STREQ("myToken", config.get_remote_encryption_token().c_str());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_STREQ("myToken", config.get_remote_encryption_token().c_str());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// TEST_F(config_test, remote_client_pool_size) {
|
|
||||||
// std::uint8_t original_value{};
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// original_value = config.get_remote_client_pool_size();
|
|
||||||
// config.set_remote_client_pool_size(original_value + 5);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_client_pool_size());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_client_pool_size());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// TEST_F(config_test, remote_client_pool_size_minimum_value) {
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// config.set_remote_client_pool_size(0);
|
|
||||||
// EXPECT_EQ(5, config.get_remote_client_pool_size());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(5, config.get_remote_client_pool_size());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, remote_max_connections) {
|
|
||||||
// std::uint8_t original_value{};
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// original_value = config.get_remote_max_connections();
|
|
||||||
// config.set_remote_max_connections(original_value + 5);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_max_connections());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(original_value + 5, config.get_remote_max_connections());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TEST_F(config_test, remote_max_connections_minimum_value) {
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// config.set_remote_max_connections(0);
|
|
||||||
// EXPECT_EQ(1, config.get_remote_max_connections());
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// app_config config(provider_type::sia, sia_directory);
|
|
||||||
// EXPECT_EQ(1, config.get_remote_max_connections());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
TEST_F(config_test, retry_read_count) {
|
|
||||||
std::uint16_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_retry_read_count();
|
|
||||||
config.set_retry_read_count(original_value + 1);
|
|
||||||
EXPECT_EQ(original_value + 1, config.get_retry_read_count());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 1, config.get_retry_read_count());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, retry_read_count_minimum_value) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_retry_read_count(1);
|
|
||||||
EXPECT_EQ(2, config.get_retry_read_count());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, task_wait_ms) {
|
|
||||||
std::uint16_t original_value{};
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
original_value = config.get_task_wait_ms();
|
|
||||||
config.set_task_wait_ms(original_value + 1U);
|
|
||||||
EXPECT_EQ(original_value + 1U, config.get_task_wait_ms());
|
|
||||||
}
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
EXPECT_EQ(original_value + 1U, config.get_task_wait_ms());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, task_wait_ms_minimum_value) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_task_wait_ms(1U);
|
|
||||||
EXPECT_EQ(50U, config.get_task_wait_ms());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(config_test, can_set_database_type) {
|
|
||||||
{
|
|
||||||
app_config config(provider_type::sia, sia_directory);
|
|
||||||
config.set_database_type(database_type::rocksdb);
|
|
||||||
EXPECT_EQ(database_type::rocksdb, config.get_database_type());
|
|
||||||
|
|
||||||
config.set_database_type(database_type::sqlite);
|
|
||||||
EXPECT_EQ(database_type::sqlite, config.get_database_type());
|
|
||||||
|
|
||||||
config.set_database_type(database_type::rocksdb);
|
|
||||||
EXPECT_EQ(database_type::rocksdb, config.get_database_type());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace repertory
|
|
@ -25,7 +25,7 @@
|
|||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
TEST(curl_comm, can_create_s3_host_config) {
|
TEST(curl_comm_test, can_create_s3_host_config) {
|
||||||
s3_config config{};
|
s3_config config{};
|
||||||
config.bucket = "repertory";
|
config.bucket = "repertory";
|
||||||
config.url = "https://s3.test.com";
|
config.url = "https://s3.test.com";
|
||||||
@ -37,7 +37,7 @@ TEST(curl_comm, can_create_s3_host_config) {
|
|||||||
EXPECT_TRUE(hc.path.empty());
|
EXPECT_TRUE(hc.path.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(curl_comm, can_create_s3_host_config_with_path_style) {
|
TEST(curl_comm_test, can_create_s3_host_config_with_path_style) {
|
||||||
s3_config config{};
|
s3_config config{};
|
||||||
config.bucket = "repertory";
|
config.bucket = "repertory";
|
||||||
config.url = "https://s3.test.com";
|
config.url = "https://s3.test.com";
|
||||||
@ -49,7 +49,7 @@ TEST(curl_comm, can_create_s3_host_config_with_path_style) {
|
|||||||
EXPECT_STREQ("/repertory", hc.path.c_str());
|
EXPECT_STREQ("/repertory", hc.path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(curl_comm, can_create_s3_host_config_with_region) {
|
TEST(curl_comm_test, can_create_s3_host_config_with_region) {
|
||||||
s3_config config{};
|
s3_config config{};
|
||||||
config.bucket = "repertory";
|
config.bucket = "repertory";
|
||||||
config.url = "https://s3.test.com";
|
config.url = "https://s3.test.com";
|
||||||
@ -62,7 +62,7 @@ TEST(curl_comm, can_create_s3_host_config_with_region) {
|
|||||||
EXPECT_TRUE(hc.path.empty());
|
EXPECT_TRUE(hc.path.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(curl_comm, can_create_s3_host_config_with_region_and_path_style) {
|
TEST(curl_comm_test, can_create_s3_host_config_with_region_and_path_style) {
|
||||||
s3_config config{};
|
s3_config config{};
|
||||||
config.bucket = "repertory";
|
config.bucket = "repertory";
|
||||||
config.url = "https://s3.test.com";
|
config.url = "https://s3.test.com";
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
TEST(json_serialize, can_handle_directory_item) {
|
TEST(json_serialize_test, can_handle_directory_item) {
|
||||||
directory_item cfg{
|
directory_item cfg{
|
||||||
"api", "parent", true, 2U, {{META_DIRECTORY, "true"}},
|
"api", "parent", true, 2U, {{META_DIRECTORY, "true"}},
|
||||||
};
|
};
|
||||||
@ -47,7 +47,7 @@ TEST(json_serialize, can_handle_directory_item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_encrypt_config) {
|
TEST(json_serialize_test, can_handle_encrypt_config) {
|
||||||
encrypt_config cfg{
|
encrypt_config cfg{
|
||||||
"token",
|
"token",
|
||||||
"path",
|
"path",
|
||||||
@ -65,7 +65,7 @@ TEST(json_serialize, can_handle_encrypt_config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_host_config) {
|
TEST(json_serialize_test, can_handle_host_config) {
|
||||||
host_config cfg{
|
host_config cfg{
|
||||||
"agent", "pwd", "user", 1024U, "host", "path", "http", 11U,
|
"agent", "pwd", "user", 1024U, "host", "path", "http", 11U,
|
||||||
};
|
};
|
||||||
@ -94,7 +94,7 @@ TEST(json_serialize, can_handle_host_config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_remote_config) {
|
TEST(json_serialize_test, can_handle_remote_config) {
|
||||||
remote::remote_config cfg{
|
remote::remote_config cfg{
|
||||||
1024U, "token", "host", 11U, 20U, 21U,
|
1024U, "token", "host", 11U, 20U, 21U,
|
||||||
};
|
};
|
||||||
@ -120,7 +120,7 @@ TEST(json_serialize, can_handle_remote_config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_remote_mount) {
|
TEST(json_serialize_test, can_handle_remote_mount) {
|
||||||
remote::remote_mount cfg{1024U, 21U, true, "token"};
|
remote::remote_mount cfg{1024U, 21U, true, "token"};
|
||||||
|
|
||||||
json data(cfg);
|
json data(cfg);
|
||||||
@ -139,7 +139,7 @@ TEST(json_serialize, can_handle_remote_mount) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_s3_config) {
|
TEST(json_serialize_test, can_handle_s3_config) {
|
||||||
s3_config cfg{
|
s3_config cfg{
|
||||||
"access", "bucket", "token", "region", "secret", 31U, "url", true, false,
|
"access", "bucket", "token", "region", "secret", 31U, "url", true, false,
|
||||||
};
|
};
|
||||||
@ -170,7 +170,7 @@ TEST(json_serialize, can_handle_s3_config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_sia_config) {
|
TEST(json_serialize_test, can_handle_sia_config) {
|
||||||
sia_config cfg{
|
sia_config cfg{
|
||||||
"bucket",
|
"bucket",
|
||||||
};
|
};
|
||||||
@ -184,7 +184,7 @@ TEST(json_serialize, can_handle_sia_config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_atomic) {
|
TEST(json_serialize_test, can_handle_atomic) {
|
||||||
atomic<sia_config> cfg({
|
atomic<sia_config> cfg({
|
||||||
"bucket",
|
"bucket",
|
||||||
});
|
});
|
||||||
@ -198,7 +198,7 @@ TEST(json_serialize, can_handle_atomic) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_database_type) {
|
TEST(json_serialize_test, can_handle_database_type) {
|
||||||
json data(database_type::rocksdb);
|
json data(database_type::rocksdb);
|
||||||
EXPECT_EQ(database_type::rocksdb, data.get<database_type>());
|
EXPECT_EQ(database_type::rocksdb, data.get<database_type>());
|
||||||
EXPECT_STREQ("rocksdb", data.get<std::string>().c_str());
|
EXPECT_STREQ("rocksdb", data.get<std::string>().c_str());
|
||||||
@ -208,7 +208,7 @@ TEST(json_serialize, can_handle_database_type) {
|
|||||||
EXPECT_STREQ("sqlite", data.get<std::string>().c_str());
|
EXPECT_STREQ("sqlite", data.get<std::string>().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_download_type) {
|
TEST(json_serialize_test, can_handle_download_type) {
|
||||||
json data(download_type::direct);
|
json data(download_type::direct);
|
||||||
EXPECT_EQ(download_type::direct, data.get<download_type>());
|
EXPECT_EQ(download_type::direct, data.get<download_type>());
|
||||||
EXPECT_STREQ("direct", data.get<std::string>().c_str());
|
EXPECT_STREQ("direct", data.get<std::string>().c_str());
|
||||||
@ -222,7 +222,33 @@ TEST(json_serialize, can_handle_download_type) {
|
|||||||
EXPECT_STREQ("ring_buffer", data.get<std::string>().c_str());
|
EXPECT_STREQ("ring_buffer", data.get<std::string>().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_atomic_database_type) {
|
TEST(json_serialize_test, can_handle_event_level) {
|
||||||
|
json data(event_level{event_level::critical});
|
||||||
|
EXPECT_EQ(event_level::critical, data.get<event_level>());
|
||||||
|
EXPECT_STREQ("critical", data.get<std::string>().c_str());
|
||||||
|
|
||||||
|
data = event_level(event_level::error);
|
||||||
|
EXPECT_EQ(event_level::error, data.get<event_level>());
|
||||||
|
EXPECT_STREQ("error", data.get<std::string>().c_str());
|
||||||
|
|
||||||
|
data = event_level(event_level::warn);
|
||||||
|
EXPECT_EQ(event_level::warn, data.get<event_level>());
|
||||||
|
EXPECT_STREQ("warn", data.get<std::string>().c_str());
|
||||||
|
|
||||||
|
data = event_level(event_level::info);
|
||||||
|
EXPECT_EQ(event_level::info, data.get<event_level>());
|
||||||
|
EXPECT_STREQ("info", data.get<std::string>().c_str());
|
||||||
|
|
||||||
|
data = event_level(event_level::debug);
|
||||||
|
EXPECT_EQ(event_level::debug, data.get<event_level>());
|
||||||
|
EXPECT_STREQ("debug", data.get<std::string>().c_str());
|
||||||
|
|
||||||
|
data = event_level(event_level::trace);
|
||||||
|
EXPECT_EQ(event_level::trace, data.get<event_level>());
|
||||||
|
EXPECT_STREQ("trace", data.get<std::string>().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(json_serialize_test, can_handle_atomic_database_type) {
|
||||||
json data(atomic<database_type>{database_type::rocksdb});
|
json data(atomic<database_type>{database_type::rocksdb});
|
||||||
EXPECT_EQ(database_type::rocksdb, data.get<atomic<database_type>>());
|
EXPECT_EQ(database_type::rocksdb, data.get<atomic<database_type>>());
|
||||||
EXPECT_STREQ("rocksdb", data.get<std::string>().c_str());
|
EXPECT_STREQ("rocksdb", data.get<std::string>().c_str());
|
||||||
@ -232,7 +258,7 @@ TEST(json_serialize, can_handle_atomic_database_type) {
|
|||||||
EXPECT_STREQ("sqlite", data.get<std::string>().c_str());
|
EXPECT_STREQ("sqlite", data.get<std::string>().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(json_serialize, can_handle_atomic_download_type) {
|
TEST(json_serialize_test, can_handle_atomic_download_type) {
|
||||||
json data(atomic<download_type>{download_type::direct});
|
json data(atomic<download_type>{download_type::direct});
|
||||||
EXPECT_EQ(download_type::direct, data.get<atomic<download_type>>());
|
EXPECT_EQ(download_type::direct, data.get<atomic<download_type>>());
|
||||||
EXPECT_STREQ("direct", data.get<std::string>().c_str());
|
EXPECT_STREQ("direct", data.get<std::string>().c_str());
|
||||||
@ -245,4 +271,30 @@ TEST(json_serialize, can_handle_atomic_download_type) {
|
|||||||
EXPECT_EQ(download_type::ring_buffer, data.get<atomic<download_type>>());
|
EXPECT_EQ(download_type::ring_buffer, data.get<atomic<download_type>>());
|
||||||
EXPECT_STREQ("ring_buffer", data.get<std::string>().c_str());
|
EXPECT_STREQ("ring_buffer", data.get<std::string>().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(json_serialize_test, can_handle_atomic_event_level) {
|
||||||
|
json data(atomic<event_level>{event_level::critical});
|
||||||
|
EXPECT_EQ(event_level::critical, data.get<atomic<event_level>>());
|
||||||
|
EXPECT_STREQ("critical", data.get<std::string>().c_str());
|
||||||
|
|
||||||
|
data = atomic<event_level>(event_level::error);
|
||||||
|
EXPECT_EQ(event_level::error, data.get<atomic<event_level>>());
|
||||||
|
EXPECT_STREQ("error", data.get<std::string>().c_str());
|
||||||
|
|
||||||
|
data = atomic<event_level>(event_level::warn);
|
||||||
|
EXPECT_EQ(event_level::warn, data.get<atomic<event_level>>());
|
||||||
|
EXPECT_STREQ("warn", data.get<std::string>().c_str());
|
||||||
|
|
||||||
|
data = atomic<event_level>(event_level::info);
|
||||||
|
EXPECT_EQ(event_level::info, data.get<atomic<event_level>>());
|
||||||
|
EXPECT_STREQ("info", data.get<std::string>().c_str());
|
||||||
|
|
||||||
|
data = atomic<event_level>(event_level::debug);
|
||||||
|
EXPECT_EQ(event_level::debug, data.get<atomic<event_level>>());
|
||||||
|
EXPECT_STREQ("debug", data.get<std::string>().c_str());
|
||||||
|
|
||||||
|
data = atomic<event_level>(event_level::trace);
|
||||||
|
EXPECT_EQ(event_level::trace, data.get<atomic<event_level>>());
|
||||||
|
EXPECT_STREQ("trace", data.get<std::string>().c_str());
|
||||||
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
#include "platform/platform.hpp"
|
#include "platform/platform.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
TEST(lock_data, lock_and_unlock) {
|
TEST(lock_data_test, lock_and_unlock) {
|
||||||
{
|
{
|
||||||
lock_data l(provider_type::sia, "1");
|
lock_data l(provider_type::sia, "1");
|
||||||
EXPECT_EQ(lock_result::success, l.grab_lock());
|
EXPECT_EQ(lock_result::success, l.grab_lock());
|
||||||
@ -50,7 +50,7 @@ TEST(lock_data, lock_and_unlock) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
TEST(lock_data, set_and_unset_mount_state) {
|
TEST(lock_data_test, set_and_unset_mount_state) {
|
||||||
lock_data l(provider_type::sia, "1");
|
lock_data l(provider_type::sia, "1");
|
||||||
EXPECT_TRUE(l.set_mount_state(true, "C:", 99));
|
EXPECT_TRUE(l.set_mount_state(true, "C:", 99));
|
||||||
|
|
||||||
@ -62,13 +62,16 @@ TEST(lock_data, set_and_unset_mount_state) {
|
|||||||
|
|
||||||
json mount_state;
|
json mount_state;
|
||||||
EXPECT_TRUE(l.get_mount_state(mount_state));
|
EXPECT_TRUE(l.get_mount_state(mount_state));
|
||||||
|
|
||||||
EXPECT_STREQ(R"({"Active":true,"Location":"C:","PID":99})",
|
EXPECT_STREQ(R"({"Active":true,"Location":"C:","PID":99})",
|
||||||
mount_state["Sia1"].dump().c_str());
|
mount_state.dump().c_str());
|
||||||
|
|
||||||
|
EXPECT_TRUE(l2.get_mount_state(mount_state));
|
||||||
EXPECT_STREQ(R"({"Active":true,"Location":"D:","PID":97})",
|
EXPECT_STREQ(R"({"Active":true,"Location":"D:","PID":97})",
|
||||||
mount_state["Remote1"].dump().c_str());
|
mount_state.dump().c_str());
|
||||||
|
|
||||||
|
EXPECT_TRUE(l3.get_mount_state(mount_state));
|
||||||
EXPECT_STREQ(R"({"Active":true,"Location":"E:","PID":96})",
|
EXPECT_STREQ(R"({"Active":true,"Location":"E:","PID":96})",
|
||||||
mount_state["Remote2"].dump().c_str());
|
mount_state.dump().c_str());
|
||||||
|
|
||||||
EXPECT_TRUE(l.set_mount_state(false, "C:", 99));
|
EXPECT_TRUE(l.set_mount_state(false, "C:", 99));
|
||||||
EXPECT_TRUE(l2.set_mount_state(false, "D:", 98));
|
EXPECT_TRUE(l2.set_mount_state(false, "D:", 98));
|
||||||
@ -76,14 +79,18 @@ TEST(lock_data, set_and_unset_mount_state) {
|
|||||||
|
|
||||||
EXPECT_TRUE(l.get_mount_state(mount_state));
|
EXPECT_TRUE(l.get_mount_state(mount_state));
|
||||||
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
||||||
mount_state["Sia1"].dump().c_str());
|
mount_state.dump().c_str());
|
||||||
|
|
||||||
|
EXPECT_TRUE(l2.get_mount_state(mount_state));
|
||||||
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
||||||
mount_state["Remote1"].dump().c_str());
|
mount_state.dump().c_str());
|
||||||
|
|
||||||
|
EXPECT_TRUE(l3.get_mount_state(mount_state));
|
||||||
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
||||||
mount_state["Remote2"].dump().c_str());
|
mount_state.dump().c_str());
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
TEST(lock_data, set_and_unset_mount_state) {
|
TEST(lock_data_test, set_and_unset_mount_state) {
|
||||||
lock_data l(provider_type::sia, "1");
|
lock_data l(provider_type::sia, "1");
|
||||||
EXPECT_TRUE(l.set_mount_state(true, "/mnt/1", 99));
|
EXPECT_TRUE(l.set_mount_state(true, "/mnt/1", 99));
|
||||||
|
|
||||||
@ -91,14 +98,13 @@ TEST(lock_data, set_and_unset_mount_state) {
|
|||||||
EXPECT_TRUE(l.get_mount_state(mount_state));
|
EXPECT_TRUE(l.get_mount_state(mount_state));
|
||||||
|
|
||||||
EXPECT_STREQ(R"({"Active":true,"Location":"/mnt/1","PID":99})",
|
EXPECT_STREQ(R"({"Active":true,"Location":"/mnt/1","PID":99})",
|
||||||
mount_state["Sia1"].dump().c_str());
|
mount_state.dump().c_str());
|
||||||
|
|
||||||
EXPECT_TRUE(l.set_mount_state(false, "/mnt/1", 99));
|
EXPECT_TRUE(l.set_mount_state(false, "/mnt/1", 99));
|
||||||
|
|
||||||
EXPECT_TRUE(l.get_mount_state(mount_state));
|
EXPECT_TRUE(l.get_mount_state(mount_state));
|
||||||
|
|
||||||
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
EXPECT_STREQ(R"({"Active":false,"Location":"","PID":-1})",
|
||||||
mount_state["Sia1"].dump().c_str());
|
mount_state.dump().c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
#include "comm/packet/packet.hpp"
|
#include "comm/packet/packet.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
TEST(packet, encrypt_and_decrypt) {
|
TEST(packet_test, encrypt_and_decrypt) {
|
||||||
packet test_packet;
|
packet test_packet;
|
||||||
test_packet.encode("test");
|
test_packet.encode("test");
|
||||||
test_packet.encrypt("moose");
|
test_packet.encrypt("moose");
|
||||||
|
@ -19,8 +19,6 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#if 0
|
|
||||||
|
|
||||||
#include "test_common.hpp"
|
#include "test_common.hpp"
|
||||||
|
|
||||||
#include "comm/curl/curl_comm.hpp"
|
#include "comm/curl/curl_comm.hpp"
|
||||||
@ -99,8 +97,6 @@ const auto create_directory = [](repertory::i_provider &provider,
|
|||||||
repertory::utils::string::to_bool(meta2[repertory::META_PINNED]));
|
repertory::utils::string::to_bool(meta2[repertory::META_PINNED]));
|
||||||
EXPECT_EQ(std::uint64_t(0U),
|
EXPECT_EQ(std::uint64_t(0U),
|
||||||
repertory::utils::string::to_uint64(meta2[repertory::META_SIZE]));
|
repertory::utils::string::to_uint64(meta2[repertory::META_SIZE]));
|
||||||
EXPECT_STREQ((api_path + "_src").c_str(),
|
|
||||||
meta2[repertory::META_SOURCE].c_str());
|
|
||||||
EXPECT_EQ(getuid(), static_cast<uid_t>(repertory::utils::string::to_uint32(
|
EXPECT_EQ(getuid(), static_cast<uid_t>(repertory::utils::string::to_uint32(
|
||||||
meta2[repertory::META_UID])));
|
meta2[repertory::META_UID])));
|
||||||
EXPECT_EQ(date + 4U, repertory::utils::string::to_uint64(
|
EXPECT_EQ(date + 4U, repertory::utils::string::to_uint64(
|
||||||
@ -178,6 +174,9 @@ const auto decrypt_parts = [](const repertory::app_config &cfg,
|
|||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
static void can_create_and_remove_directory(i_provider &provider) {
|
static void can_create_and_remove_directory(i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.is_read_only()) {
|
if (provider.is_read_only()) {
|
||||||
api_meta_map meta{};
|
api_meta_map meta{};
|
||||||
EXPECT_EQ(api_error::not_implemented,
|
EXPECT_EQ(api_error::not_implemented,
|
||||||
@ -196,6 +195,9 @@ static void can_create_and_remove_directory(i_provider &provider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void create_directory_fails_if_already_exists(i_provider &provider) {
|
static void create_directory_fails_if_already_exists(i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.is_read_only()) {
|
if (provider.is_read_only()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -210,6 +212,9 @@ static void create_directory_fails_if_already_exists(i_provider &provider) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
create_directory_fails_if_file_already_exists(i_provider &provider) {
|
create_directory_fails_if_file_already_exists(i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.is_read_only()) {
|
if (provider.is_read_only()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -223,6 +228,9 @@ create_directory_fails_if_file_already_exists(i_provider &provider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void create_directory_clone_source_meta(i_provider &provider) {
|
static void create_directory_clone_source_meta(i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.is_read_only()) {
|
if (provider.is_read_only()) {
|
||||||
EXPECT_EQ(api_error::not_implemented,
|
EXPECT_EQ(api_error::not_implemented,
|
||||||
provider.create_directory_clone_source_meta("/moose", "/moose"));
|
provider.create_directory_clone_source_meta("/moose", "/moose"));
|
||||||
@ -257,6 +265,9 @@ static void create_directory_clone_source_meta(i_provider &provider) {
|
|||||||
|
|
||||||
static void create_directory_clone_source_meta_fails_if_already_exists(
|
static void create_directory_clone_source_meta_fails_if_already_exists(
|
||||||
i_provider &provider) {
|
i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.is_read_only()) {
|
if (provider.is_read_only()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -272,6 +283,9 @@ static void create_directory_clone_source_meta_fails_if_already_exists(
|
|||||||
|
|
||||||
static void create_directory_clone_source_meta_fails_if_directory_not_found(
|
static void create_directory_clone_source_meta_fails_if_directory_not_found(
|
||||||
i_provider &provider) {
|
i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.is_read_only()) {
|
if (provider.is_read_only()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -282,6 +296,9 @@ static void create_directory_clone_source_meta_fails_if_directory_not_found(
|
|||||||
|
|
||||||
static void create_directory_clone_source_meta_fails_if_file_already_exists(
|
static void create_directory_clone_source_meta_fails_if_file_already_exists(
|
||||||
i_provider &provider) {
|
i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.is_read_only()) {
|
if (provider.is_read_only()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -297,6 +314,9 @@ static void create_directory_clone_source_meta_fails_if_file_already_exists(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void can_create_and_remove_file(i_provider &provider) {
|
static void can_create_and_remove_file(i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.is_read_only()) {
|
if (provider.is_read_only()) {
|
||||||
api_meta_map meta{};
|
api_meta_map meta{};
|
||||||
EXPECT_EQ(api_error::not_implemented,
|
EXPECT_EQ(api_error::not_implemented,
|
||||||
@ -317,6 +337,9 @@ static void can_create_and_remove_file(i_provider &provider) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void create_file_fails_if_already_exists(i_provider &provider) {
|
static void create_file_fails_if_already_exists(i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.is_read_only()) {
|
if (provider.is_read_only()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -331,6 +354,9 @@ static void create_file_fails_if_already_exists(i_provider &provider) {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
create_file_fails_if_directory_already_exists(i_provider &provider) {
|
create_file_fails_if_directory_already_exists(i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.is_read_only()) {
|
if (provider.is_read_only()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -345,9 +371,12 @@ create_file_fails_if_directory_already_exists(i_provider &provider) {
|
|||||||
|
|
||||||
static void get_api_path_from_source(const app_config &cfg,
|
static void get_api_path_from_source(const app_config &cfg,
|
||||||
i_provider &provider) {
|
i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||||
const auto source_path =
|
auto source_path =
|
||||||
utils::path::combine("./test_date/encrypt", {"test.txt"});
|
utils::path::combine("./test_input/encrypt", {"test.txt"});
|
||||||
|
|
||||||
std::string api_path{};
|
std::string api_path{};
|
||||||
EXPECT_EQ(api_error::success,
|
EXPECT_EQ(api_error::success,
|
||||||
@ -376,6 +405,9 @@ static void get_api_path_from_source(const app_config &cfg,
|
|||||||
static void
|
static void
|
||||||
get_api_path_from_source_fails_if_file_not_found(const app_config &cfg,
|
get_api_path_from_source_fails_if_file_not_found(const app_config &cfg,
|
||||||
i_provider &provider) {
|
i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
std::string source_path{};
|
std::string source_path{};
|
||||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||||
source_path = utils::path::combine(cfg.get_encrypt_config().path,
|
source_path = utils::path::combine(cfg.get_encrypt_config().path,
|
||||||
@ -391,28 +423,50 @@ get_api_path_from_source_fails_if_file_not_found(const app_config &cfg,
|
|||||||
EXPECT_TRUE(api_path.empty());
|
EXPECT_TRUE(api_path.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_directory_item_count(const app_config &cfg,
|
static void get_directory_item_count(const app_config & /* cfg */,
|
||||||
i_provider &provider) {
|
i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||||
EXPECT_EQ(std::size_t(2U), provider.get_directory_item_count("/"));
|
EXPECT_EQ(std::size_t(2U), provider.get_directory_item_count("/"));
|
||||||
EXPECT_EQ(std::size_t(0U), provider.get_directory_item_count("/not_found"));
|
EXPECT_EQ(std::size_t(0U), provider.get_directory_item_count("/not_found"));
|
||||||
|
|
||||||
const auto source_path =
|
auto source_path =
|
||||||
utils::path::combine(test::get_test_input_dir(), {"encrypt", "sub10"});
|
utils::path::combine(test::get_test_input_dir(), {"encrypt", "sub10"});
|
||||||
|
|
||||||
std::string api_path{};
|
std::string api_path{};
|
||||||
EXPECT_EQ(api_error::success,
|
EXPECT_EQ(api_error::success,
|
||||||
provider.get_api_path_from_source(source_path, api_path));
|
provider.get_api_path_from_source(source_path, api_path));
|
||||||
EXPECT_EQ(std::size_t(1U), provider.get_directory_item_count(api_path));
|
EXPECT_EQ(std::size_t(1U), provider.get_directory_item_count(api_path));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void get_directory_items(const app_config &cfg, i_provider &provider) {
|
create_file(provider, "/pt01.txt");
|
||||||
|
create_file(provider, "/pt02.txt");
|
||||||
|
create_directory(provider, "/dir01");
|
||||||
|
create_directory(provider, "/dir02");
|
||||||
|
|
||||||
directory_item_list list{};
|
directory_item_list list{};
|
||||||
EXPECT_EQ(api_error::success, provider.get_directory_items("/", list));
|
EXPECT_EQ(api_error::success, provider.get_directory_items("/", list));
|
||||||
check_forced_dirs(list);
|
check_forced_dirs(list);
|
||||||
|
EXPECT_GE(list.size(), std::size_t(6U));
|
||||||
|
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_file("/pt02.txt"));
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_directory("/dir01"));
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_directory("/dir02"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_directory_items(const app_config &cfg, i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||||
|
directory_item_list list{};
|
||||||
|
EXPECT_EQ(api_error::success, provider.get_directory_items("/", list));
|
||||||
|
check_forced_dirs(list);
|
||||||
|
|
||||||
EXPECT_EQ(std::size_t(4U), list.size());
|
EXPECT_EQ(std::size_t(4U), list.size());
|
||||||
|
|
||||||
directory_item_list list_decrypted{list.begin() + 2U, list.end()};
|
directory_item_list list_decrypted{list.begin() + 2U, list.end()};
|
||||||
@ -443,7 +497,7 @@ static void get_directory_items(const app_config &cfg, i_provider &provider) {
|
|||||||
EXPECT_EQ(std::size_t(46U), file->size);
|
EXPECT_EQ(std::size_t(46U), file->size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const auto source_path =
|
auto source_path =
|
||||||
utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
|
utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
|
||||||
std::string api_path{};
|
std::string api_path{};
|
||||||
EXPECT_EQ(api_error::success,
|
EXPECT_EQ(api_error::success,
|
||||||
@ -472,11 +526,58 @@ static void get_directory_items(const app_config &cfg, i_provider &provider) {
|
|||||||
#else
|
#else
|
||||||
EXPECT_EQ(std::size_t(45U), file2->size);
|
EXPECT_EQ(std::size_t(45U), file2->size);
|
||||||
#endif
|
#endif
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_file(provider, "/pt01.txt");
|
||||||
|
create_file(provider, "/pt02.txt");
|
||||||
|
create_directory(provider, "/dir01");
|
||||||
|
create_directory(provider, "/dir02");
|
||||||
|
|
||||||
|
directory_item_list list{};
|
||||||
|
EXPECT_EQ(api_error::success, provider.get_directory_items("/", list));
|
||||||
|
check_forced_dirs(list);
|
||||||
|
EXPECT_GE(list.size(), std::size_t(6U));
|
||||||
|
|
||||||
|
auto iter = std::ranges::find_if(
|
||||||
|
list, [](auto &&item) -> bool { return item.api_path == "/pt01.txt"; });
|
||||||
|
EXPECT_NE(iter, list.end());
|
||||||
|
EXPECT_STREQ("/", (*iter).api_parent.c_str());
|
||||||
|
EXPECT_FALSE((*iter).directory);
|
||||||
|
EXPECT_EQ(std::uint64_t{0U}, (*iter).size);
|
||||||
|
|
||||||
|
iter = std::ranges::find_if(
|
||||||
|
list, [](auto &&item) -> bool { return item.api_path == "/pt02.txt"; });
|
||||||
|
EXPECT_NE(iter, list.end());
|
||||||
|
EXPECT_STREQ("/", (*iter).api_parent.c_str());
|
||||||
|
EXPECT_FALSE((*iter).directory);
|
||||||
|
EXPECT_EQ(std::uint64_t{0U}, (*iter).size);
|
||||||
|
|
||||||
|
iter = std::ranges::find_if(
|
||||||
|
list, [](auto &&item) -> bool { return item.api_path == "/dir01"; });
|
||||||
|
EXPECT_NE(iter, list.end());
|
||||||
|
EXPECT_STREQ("/", (*iter).api_parent.c_str());
|
||||||
|
EXPECT_TRUE((*iter).directory);
|
||||||
|
EXPECT_EQ(std::uint64_t{0U}, (*iter).size);
|
||||||
|
|
||||||
|
iter = std::ranges::find_if(
|
||||||
|
list, [](auto &&item) -> bool { return item.api_path == "/dir02"; });
|
||||||
|
EXPECT_NE(iter, list.end());
|
||||||
|
EXPECT_STREQ("/", (*iter).api_parent.c_str());
|
||||||
|
EXPECT_TRUE((*iter).directory);
|
||||||
|
EXPECT_EQ(std::uint64_t{0U}, (*iter).size);
|
||||||
|
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_file("/pt02.txt"));
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_directory("/dir01"));
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_directory("/dir02"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_directory_items_fails_if_directory_not_found(i_provider &provider) {
|
get_directory_items_fails_if_directory_not_found(i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
directory_item_list list{};
|
directory_item_list list{};
|
||||||
EXPECT_EQ(api_error::directory_not_found,
|
EXPECT_EQ(api_error::directory_not_found,
|
||||||
provider.get_directory_items("/not_found", list));
|
provider.get_directory_items("/not_found", list));
|
||||||
@ -485,8 +586,11 @@ get_directory_items_fails_if_directory_not_found(i_provider &provider) {
|
|||||||
|
|
||||||
static void get_directory_items_fails_if_item_is_file(const app_config &cfg,
|
static void get_directory_items_fails_if_item_is_file(const app_config &cfg,
|
||||||
i_provider &provider) {
|
i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||||
const auto source_path =
|
auto source_path =
|
||||||
utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
|
utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
|
||||||
|
|
||||||
std::string api_path{};
|
std::string api_path{};
|
||||||
@ -497,12 +601,24 @@ static void get_directory_items_fails_if_item_is_file(const app_config &cfg,
|
|||||||
EXPECT_EQ(api_error::item_exists,
|
EXPECT_EQ(api_error::item_exists,
|
||||||
provider.get_directory_items(api_path, list));
|
provider.get_directory_items(api_path, list));
|
||||||
EXPECT_TRUE(list.empty());
|
EXPECT_TRUE(list.empty());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_file(provider, "/pt01.txt");
|
||||||
|
|
||||||
|
directory_item_list list{};
|
||||||
|
EXPECT_EQ(api_error::item_exists,
|
||||||
|
provider.get_directory_items("/pt01.txt", list));
|
||||||
|
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_file(const app_config &cfg, i_provider &provider) {
|
static void get_file(const app_config &cfg, i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||||
const auto source_path =
|
auto source_path =
|
||||||
utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
|
utils::path::combine(cfg.get_encrypt_config().path, {"test.txt"});
|
||||||
|
|
||||||
std::string api_path{};
|
std::string api_path{};
|
||||||
@ -522,18 +638,43 @@ static void get_file(const app_config &cfg, i_provider &provider) {
|
|||||||
EXPECT_EQ(std::size_t(46U), file.file_size);
|
EXPECT_EQ(std::size_t(46U), file.file_size);
|
||||||
#endif
|
#endif
|
||||||
EXPECT_STREQ(source_path.c_str(), file.source_path.c_str());
|
EXPECT_STREQ(source_path.c_str(), file.source_path.c_str());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_file(provider, "/pt01.txt");
|
||||||
|
|
||||||
|
api_file file{};
|
||||||
|
EXPECT_EQ(api_error::success, provider.get_file("/pt01.txt", file));
|
||||||
|
|
||||||
|
EXPECT_STREQ("/pt01.txt", file.api_path.c_str());
|
||||||
|
EXPECT_STREQ("/", file.api_parent.c_str());
|
||||||
|
EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
|
||||||
|
file.accessed_date);
|
||||||
|
EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
|
||||||
|
file.changed_date);
|
||||||
|
EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
|
||||||
|
file.creation_date);
|
||||||
|
EXPECT_LT(utils::time::get_time_now() - (utils::time::NANOS_PER_SECOND * 5U),
|
||||||
|
file.modified_date);
|
||||||
|
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_file("/pt01.txt"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_file_fails_if_file_not_found(i_provider &provider) {
|
static void get_file_fails_if_file_not_found(i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
api_file file{};
|
api_file file{};
|
||||||
EXPECT_EQ(api_error::item_not_found, provider.get_file("/not_found", file));
|
EXPECT_EQ(api_error::item_not_found, provider.get_file("/not_found", file));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_file_fails_if_item_is_directory(const app_config &cfg,
|
static void get_file_fails_if_item_is_directory(const app_config &cfg,
|
||||||
i_provider &provider) {
|
i_provider &provider) {
|
||||||
|
fmt::println("testing|{}|{}",
|
||||||
|
app_config::get_provider_name(provider.get_provider_type()),
|
||||||
|
__FUNCTION__);
|
||||||
if (provider.get_provider_type() == provider_type::encrypt) {
|
if (provider.get_provider_type() == provider_type::encrypt) {
|
||||||
const auto source_path =
|
auto source_path =
|
||||||
utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
|
utils::path::combine(cfg.get_encrypt_config().path, {"sub10"});
|
||||||
|
|
||||||
std::string api_path{};
|
std::string api_path{};
|
||||||
@ -542,7 +683,15 @@ static void get_file_fails_if_item_is_directory(const app_config &cfg,
|
|||||||
|
|
||||||
api_file file{};
|
api_file file{};
|
||||||
EXPECT_EQ(api_error::directory_exists, provider.get_file(api_path, file));
|
EXPECT_EQ(api_error::directory_exists, provider.get_file(api_path, file));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_directory(provider, "/dir01");
|
||||||
|
|
||||||
|
api_file file{};
|
||||||
|
EXPECT_EQ(api_error::directory_exists, provider.get_file("/dir01", file));
|
||||||
|
|
||||||
|
EXPECT_EQ(api_error::success, provider.remove_directory("/dir01"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_file_list(const app_config &cfg, i_provider &provider) {
|
static void get_file_list(const app_config &cfg, i_provider &provider) {
|
||||||
@ -593,7 +742,6 @@ static void run_tests(const app_config &cfg, i_provider &provider) {
|
|||||||
get_api_path_from_source(cfg, provider);
|
get_api_path_from_source(cfg, provider);
|
||||||
get_api_path_from_source_fails_if_file_not_found(cfg, provider);
|
get_api_path_from_source_fails_if_file_not_found(cfg, provider);
|
||||||
|
|
||||||
// TODO: continue here
|
|
||||||
get_directory_items(cfg, provider);
|
get_directory_items(cfg, provider);
|
||||||
get_directory_items_fails_if_directory_not_found(provider);
|
get_directory_items_fails_if_directory_not_found(provider);
|
||||||
get_directory_items_fails_if_item_is_file(cfg, provider);
|
get_directory_items_fails_if_item_is_file(cfg, provider);
|
||||||
@ -629,17 +777,16 @@ static void run_tests(const app_config &cfg, i_provider &provider) {
|
|||||||
upload_file(provider); */
|
upload_file(provider); */
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(providers, encrypt_provider) {
|
TEST(providers_test, encrypt_provider) {
|
||||||
const auto config_path =
|
auto config_path = utils::path::combine(test::get_test_output_dir(),
|
||||||
utils::path::combine(test::get_test_output_dir(), {"encrypt_provider"});
|
{"provider", "encrypt"});
|
||||||
|
|
||||||
console_consumer consumer{};
|
console_consumer consumer{};
|
||||||
event_system::instance().start();
|
event_system::instance().start();
|
||||||
|
|
||||||
{
|
{
|
||||||
app_config cfg(provider_type::encrypt, config_path);
|
app_config cfg(provider_type::encrypt, config_path);
|
||||||
|
|
||||||
const auto encrypt_path =
|
auto encrypt_path =
|
||||||
utils::path::combine(test::get_test_input_dir(), {"encrypt"});
|
utils::path::combine(test::get_test_input_dir(), {"encrypt"});
|
||||||
|
|
||||||
EXPECT_STREQ(
|
EXPECT_STREQ(
|
||||||
@ -673,9 +820,9 @@ TEST(providers, encrypt_provider) {
|
|||||||
event_system::instance().stop();
|
event_system::instance().stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(providers, s3_provider) {
|
TEST(providers_test, s3_provider) {
|
||||||
const auto config_path =
|
auto config_path =
|
||||||
utils::path::combine(test::get_test_output_dir(), {"s3_provider"});
|
utils::path::combine(test::get_test_output_dir(), {"provider", "s3"});
|
||||||
|
|
||||||
console_consumer consumer{};
|
console_consumer consumer{};
|
||||||
event_system::instance().start();
|
event_system::instance().start();
|
||||||
@ -685,7 +832,7 @@ TEST(providers, s3_provider) {
|
|||||||
{
|
{
|
||||||
app_config src_cfg(
|
app_config src_cfg(
|
||||||
provider_type::s3,
|
provider_type::s3,
|
||||||
utils::path::combine(test::get_test_config_dir(), {"storj"}));
|
utils::path::combine(test::get_test_config_dir(), {"s3"}));
|
||||||
cfg.set_s3_config(src_cfg.get_s3_config());
|
cfg.set_s3_config(src_cfg.get_s3_config());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,9 +860,9 @@ TEST(providers, s3_provider) {
|
|||||||
event_system::instance().stop();
|
event_system::instance().stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(providers, sia_provider) {
|
TEST(providers_test, sia_provider) {
|
||||||
const auto config_path =
|
auto config_path =
|
||||||
utils::path::combine(test::get_test_output_dir(), {"sia_provider"});
|
utils::path::combine(test::get_test_output_dir(), {"sia", "provider"});
|
||||||
|
|
||||||
console_consumer consumer{};
|
console_consumer consumer{};
|
||||||
event_system::instance().start();
|
event_system::instance().start();
|
||||||
@ -753,5 +900,3 @@ TEST(providers, sia_provider) {
|
|||||||
event_system::instance().stop();
|
event_system::instance().stop();
|
||||||
}
|
}
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif // 0
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
namespace repertory {
|
namespace repertory {
|
||||||
static constexpr const std::size_t test_chunk_size{1024U};
|
static constexpr const std::size_t test_chunk_size{1024U};
|
||||||
|
|
||||||
TEST(upload, can_upload_a_valid_file) {
|
TEST(upload_test, can_upload_a_valid_file) {
|
||||||
console_consumer con;
|
console_consumer con;
|
||||||
|
|
||||||
event_system::instance().start();
|
event_system::instance().start();
|
||||||
@ -71,7 +71,7 @@ TEST(upload, can_upload_a_valid_file) {
|
|||||||
event_system::instance().stop();
|
event_system::instance().stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(upload, can_cancel_upload) {
|
TEST(upload_test, can_cancel_upload) {
|
||||||
console_consumer con;
|
console_consumer con;
|
||||||
|
|
||||||
event_system::instance().start();
|
event_system::instance().start();
|
||||||
@ -135,7 +135,7 @@ TEST(upload, can_cancel_upload) {
|
|||||||
event_system::instance().stop();
|
event_system::instance().stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(upload, can_stop_upload) {
|
TEST(upload_test, can_stop_upload) {
|
||||||
console_consumer con;
|
console_consumer con;
|
||||||
|
|
||||||
event_system::instance().start();
|
event_system::instance().start();
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include "utils/file.hpp"
|
#include "utils/file.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
TEST(utils, convert_api_date) {
|
TEST(utils_test, convert_api_date) {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
auto file_time = utils::time::unix_time_to_filetime(
|
auto file_time = utils::time::unix_time_to_filetime(
|
||||||
s3_provider::convert_api_date("2009-10-12T17:50:30.111Z"));
|
s3_provider::convert_api_date("2009-10-12T17:50:30.111Z"));
|
||||||
@ -63,7 +63,7 @@ TEST(utils, convert_api_date) {
|
|||||||
#endif // defined(_WIN32)
|
#endif // defined(_WIN32)
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(utils, generate_sha256) {
|
TEST(utils_test, generate_sha256) {
|
||||||
auto res = utils::file::file{__FILE__}.sha256();
|
auto res = utils::file::file{__FILE__}.sha256();
|
||||||
EXPECT_TRUE(res.has_value());
|
EXPECT_TRUE(res.has_value());
|
||||||
if (res.has_value()) {
|
if (res.has_value()) {
|
||||||
|
@ -334,6 +334,9 @@ static void test_overlapped_file(auto &&mount_location, auto &&file_path,
|
|||||||
EXPECT_EQ(0,
|
EXPECT_EQ(0,
|
||||||
std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
|
std::memcmp(write_buffer.data(), read_buffer.data(), bytes_read));
|
||||||
|
|
||||||
|
LARGE_INTEGER size{};
|
||||||
|
::GetFileSizeEx(handle, &size);
|
||||||
|
|
||||||
read_buffer.clear();
|
read_buffer.clear();
|
||||||
read_buffer.resize(buffer_size);
|
read_buffer.resize(buffer_size);
|
||||||
overlapped.Offset = 3U * bytes_per_sector;
|
overlapped.Offset = 3U * bytes_per_sector;
|
||||||
|
@ -65,13 +65,16 @@ TYPED_TEST(winfsp_test, rename_fails_if_dest_exists_and_replace_is_false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto dir_path{
|
auto dir_path{
|
||||||
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
utils::path::combine(this->mount_location, {"test_dir_5"}),
|
||||||
};
|
};
|
||||||
auto file_path{
|
auto file_path{
|
||||||
utils::path::combine(dir_path, {"test_file_4"}),
|
utils::path::combine(dir_path, {"test_file_5"}),
|
||||||
};
|
};
|
||||||
auto file_path2{
|
auto file_path2{
|
||||||
utils::path::combine(dir_path, {"test_file2_4"}),
|
utils::path::combine(dir_path, {"test_file2_5"}),
|
||||||
|
};
|
||||||
|
auto file_path3{
|
||||||
|
utils::path::combine(dir_path, {"test_file3_5"}),
|
||||||
};
|
};
|
||||||
|
|
||||||
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
@ -84,9 +87,16 @@ TYPED_TEST(winfsp_test, rename_fails_if_dest_exists_and_replace_is_false) {
|
|||||||
|
|
||||||
EXPECT_TRUE(::MoveFileExA(file_path.c_str(), file_path2.c_str(), 0));
|
EXPECT_TRUE(::MoveFileExA(file_path.c_str(), file_path2.c_str(), 0));
|
||||||
|
|
||||||
EXPECT_FALSE(::MoveFileExA(file_path.c_str(), file_path2.c_str(), 0));
|
handle = ::CreateFileA(file_path3.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
|
::CloseHandle(handle);
|
||||||
|
|
||||||
|
EXPECT_FALSE(::MoveFileExA(file_path3.c_str(), file_path2.c_str(), 0));
|
||||||
EXPECT_EQ(ERROR_ALREADY_EXISTS, ::GetLastError());
|
EXPECT_EQ(ERROR_ALREADY_EXISTS, ::GetLastError());
|
||||||
|
|
||||||
|
EXPECT_TRUE(::DeleteFileA(file_path3.c_str()));
|
||||||
EXPECT_TRUE(::DeleteFileA(file_path2.c_str()));
|
EXPECT_TRUE(::DeleteFileA(file_path2.c_str()));
|
||||||
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||||
}
|
}
|
||||||
@ -97,13 +107,16 @@ TYPED_TEST(winfsp_test, rename_succeeds_if_dest_exists_and_replace_is_true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto dir_path{
|
auto dir_path{
|
||||||
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
utils::path::combine(this->mount_location, {"test_dir_6"}),
|
||||||
};
|
};
|
||||||
auto file_path{
|
auto file_path{
|
||||||
utils::path::combine(dir_path, {"test_file_4"}),
|
utils::path::combine(dir_path, {"test_file_6"}),
|
||||||
};
|
};
|
||||||
auto file_path2{
|
auto file_path2{
|
||||||
utils::path::combine(dir_path, {"test_file2_4"}),
|
utils::path::combine(dir_path, {"test_file2_6"}),
|
||||||
|
};
|
||||||
|
auto file_path3{
|
||||||
|
utils::path::combine(dir_path, {"test_file3_6"}),
|
||||||
};
|
};
|
||||||
|
|
||||||
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
@ -116,29 +129,29 @@ TYPED_TEST(winfsp_test, rename_succeeds_if_dest_exists_and_replace_is_true) {
|
|||||||
|
|
||||||
EXPECT_TRUE(::MoveFileExA(file_path.c_str(), file_path2.c_str(), 0));
|
EXPECT_TRUE(::MoveFileExA(file_path.c_str(), file_path2.c_str(), 0));
|
||||||
|
|
||||||
handle = ::CreateFileA(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
|
handle = ::CreateFileA(file_path3.c_str(), GENERIC_READ | GENERIC_WRITE,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
ASSERT_NE(INVALID_HANDLE_VALUE, handle);
|
||||||
::CloseHandle(handle);
|
::CloseHandle(handle);
|
||||||
|
|
||||||
EXPECT_TRUE(::MoveFileExA(file_path.c_str(), file_path2.c_str(),
|
EXPECT_TRUE(::MoveFileExA(file_path3.c_str(), file_path2.c_str(),
|
||||||
MOVEFILE_REPLACE_EXISTING));
|
MOVEFILE_REPLACE_EXISTING));
|
||||||
|
|
||||||
EXPECT_TRUE(::DeleteFileA(file_path2.c_str()));
|
EXPECT_TRUE(::DeleteFileA(file_path2.c_str()));
|
||||||
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
EXPECT_TRUE(::RemoveDirectoryA(dir_path.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(winfsp_test, rename_can_rename_dir_if_dest_does_not_exist) {
|
TYPED_TEST(winfsp_test, rename_dir_succeeds_if_dest_does_not_exist) {
|
||||||
if (this->current_provider == provider_type::s3) {
|
if (this->current_provider == provider_type::s3) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dir_path{
|
auto dir_path{
|
||||||
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
utils::path::combine(this->mount_location, {"test_dir_7"}),
|
||||||
};
|
};
|
||||||
auto dir_path2{
|
auto dir_path2{
|
||||||
utils::path::combine(this->mount_location, {"test_dir2_4"}),
|
utils::path::combine(this->mount_location, {"test_dir2_7"}),
|
||||||
};
|
};
|
||||||
|
|
||||||
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
@ -154,10 +167,10 @@ TYPED_TEST(winfsp_test, rename_dir_fails_if_dest_exists_and_replace_is_false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto dir_path{
|
auto dir_path{
|
||||||
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
utils::path::combine(this->mount_location, {"test_dir_8"}),
|
||||||
};
|
};
|
||||||
auto dir_path2{
|
auto dir_path2{
|
||||||
utils::path::combine(this->mount_location, {"test_dir2_4"}),
|
utils::path::combine(this->mount_location, {"test_dir2_8"}),
|
||||||
};
|
};
|
||||||
|
|
||||||
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
@ -176,10 +189,10 @@ TYPED_TEST(winfsp_test, rename_dir_fails_if_dest_exists_and_replace_is_true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto dir_path{
|
auto dir_path{
|
||||||
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
utils::path::combine(this->mount_location, {"test_dir_9"}),
|
||||||
};
|
};
|
||||||
auto dir_path2{
|
auto dir_path2{
|
||||||
utils::path::combine(this->mount_location, {"test_dir2_4"}),
|
utils::path::combine(this->mount_location, {"test_dir2_9"}),
|
||||||
};
|
};
|
||||||
|
|
||||||
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
@ -200,13 +213,13 @@ TYPED_TEST(winfsp_test,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto dir_path{
|
auto dir_path{
|
||||||
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
utils::path::combine(this->mount_location, {"test_dir_10"}),
|
||||||
};
|
};
|
||||||
auto dir_path2{
|
auto dir_path2{
|
||||||
utils::path::combine(this->mount_location, {"test_dir2_4"}),
|
utils::path::combine(this->mount_location, {"test_dir2_10"}),
|
||||||
};
|
};
|
||||||
auto file_path{
|
auto file_path{
|
||||||
utils::path::combine(dir_path, {"test_file_4"}),
|
utils::path::combine(dir_path, {"test_file_10"}),
|
||||||
};
|
};
|
||||||
|
|
||||||
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
@ -231,13 +244,13 @@ TYPED_TEST(winfsp_test,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto dir_path{
|
auto dir_path{
|
||||||
utils::path::combine(this->mount_location, {"test_dir_4"}),
|
utils::path::combine(this->mount_location, {"test_dir_11"}),
|
||||||
};
|
};
|
||||||
auto dir_path2{
|
auto dir_path2{
|
||||||
utils::path::combine(this->mount_location, {"test_dir2_4"}),
|
utils::path::combine(this->mount_location, {"test_dir2_11"}),
|
||||||
};
|
};
|
||||||
auto file_path{
|
auto file_path{
|
||||||
utils::path::combine(dir_path, {"test_file_4"}),
|
utils::path::combine(dir_path, {"test_file_11"}),
|
||||||
};
|
};
|
||||||
|
|
||||||
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
ASSERT_TRUE(::CreateDirectoryA(dir_path.c_str(), nullptr));
|
||||||
|
@ -50,10 +50,17 @@ TYPED_TEST(winfsp_test, volume_can_get_volume_info) {
|
|||||||
flags);
|
flags);
|
||||||
EXPECT_EQ(255U, max_component_length);
|
EXPECT_EQ(255U, max_component_length);
|
||||||
EXPECT_EQ(0U, serial_num);
|
EXPECT_EQ(0U, serial_num);
|
||||||
EXPECT_STREQ(
|
if (this->current_provider == provider_type::unknown) {
|
||||||
("repertory_" + app_config::get_provider_name(this->current_provider))
|
EXPECT_STREQ(
|
||||||
.c_str(),
|
("repertory_" + app_config::get_provider_name(provider_type::sia))
|
||||||
volume_label.c_str());
|
.c_str(),
|
||||||
|
volume_label.c_str());
|
||||||
|
} else {
|
||||||
|
EXPECT_STREQ(
|
||||||
|
("repertory_" + app_config::get_provider_name(this->current_provider))
|
||||||
|
.c_str(),
|
||||||
|
volume_label.c_str());
|
||||||
|
}
|
||||||
EXPECT_STREQ(this->mount_location.c_str(), fs_name.c_str());
|
EXPECT_STREQ(this->mount_location.c_str(), fs_name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ if [ "${PROJECT_IS_MINGW}" == "1" ] && [ "${PROJECT_STATIC_LINK}" == "OFF" ]; th
|
|||||||
/mingw64/bin/libstdc++-6.dll
|
/mingw64/bin/libstdc++-6.dll
|
||||||
/mingw64/bin/libwinpthread-1.dll
|
/mingw64/bin/libwinpthread-1.dll
|
||||||
/mingw64/bin/libzlib1.dll
|
/mingw64/bin/libzlib1.dll
|
||||||
|
/mingw64/bin/libzstd.dll
|
||||||
/mingw64/bin/zlib1.dll
|
/mingw64/bin/zlib1.dll
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,14 +38,17 @@ BRANCH=$(git branch --show-current)
|
|||||||
RELEASE=$(grep PROJECT_RELEASE_ITER= ./config.sh | sed s/PROJECT_RELEASE_ITER=//g)
|
RELEASE=$(grep PROJECT_RELEASE_ITER= ./config.sh | sed s/PROJECT_RELEASE_ITER=//g)
|
||||||
popd
|
popd
|
||||||
|
|
||||||
if [ "${BRANCH}" == "master" ] || [ "${BRANCH}" == "alpha" ] || [ "${BRANCH}" == "beta" ] || [ "${BRANCH}" == "rc" ]; then
|
if [ "${BRANCH}" == "master" ] || [ "${BRANCH}" == "alpha" ] ||
|
||||||
|
[ "${BRANCH}" == "main" ] || [ "${BRANCH}" == "release" ] ||
|
||||||
|
[ "${BRANCH}" == "beta" ] || [ "${BRANCH}" == "rc" ]; then
|
||||||
DEST_DIR=${DEST_DIR}/${RELEASE}
|
DEST_DIR=${DEST_DIR}/${RELEASE}
|
||||||
else
|
elif [[ ${BRANCH} = *'-alpha-'* ]] || [[ ${BRANCH} = *'-beta-'* ]] ||
|
||||||
|
[[ ${BRANCH} = *'-rc-'* ]] || [[ ${BRANCH} = *'-release-'* ]]; then
|
||||||
DEST_DIR=${DEST_DIR}/nightly
|
DEST_DIR=${DEST_DIR}/nightly
|
||||||
|
else
|
||||||
|
error_exit "skipping ${PROJECT_FILE_PART}" 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ${DEST_DIR}
|
|
||||||
|
|
||||||
pushd "${DIST_DIR}"
|
pushd "${DIST_DIR}"
|
||||||
if [ ! -f "./${PROJECT_OUT_FILE}" ]; then
|
if [ ! -f "./${PROJECT_OUT_FILE}" ]; then
|
||||||
error_exit "failed to find file: ${PROJECT_OUT_FILE}" 1
|
error_exit "failed to find file: ${PROJECT_OUT_FILE}" 1
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user