Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
62555e6125 |
@ -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
|
||||||
|
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
|
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,11 +1,28 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v2.0.5-rc
|
||||||
|
|
||||||
|
### 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
|
## v2.0.4-rc
|
||||||
|
|
||||||
### BREAKING CHANGES
|
### BREAKING CHANGES
|
||||||
|
|
||||||
* `renterd` v2.0.0+ is now required. Prior versions will fail to mount.
|
* `renterd` v2.0.0+ is now required. Prior versions will fail to mount.
|
||||||
|
|
||||||
|
<!-- markdownlint-disable-next-line -->
|
||||||
### Issues
|
### Issues
|
||||||
|
|
||||||
* \#35 [bug] Low frequency check is set to '0' instead of 1 hour by default
|
* \#35 [bug] Low frequency check is set to '0' instead of 1 hour by default
|
||||||
|
488
README.md
488
README.md
@ -3,11 +3,42 @@
|
|||||||
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
|
||||||
@ -15,137 +46,388 @@ on Windows.
|
|||||||
## Minimum Requirements
|
## Minimum Requirements
|
||||||
|
|
||||||
* [Sia renterd](https://github.com/SiaFoundation/renterd/releases) v2.0.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 b53606f443ac8f01d1d5fc9c39497f2af322d99e14cea5c0b4b124d630379365)
|
||||||
set(BOOST2_HASH 7bd7ddceec1a1dfdcbdb3e609b60d01739c38390a5f956385a12f3122049f0ca)
|
set(BOOST2_HASH 7bd7ddceec1a1dfdcbdb3e609b60d01739c38390a5f956385a12f3122049f0ca)
|
||||||
set(BOOST_HASH f55c340aa49763b1925ccf02b2e83f35fdcf634c9d5164a2acb87540173c741d)
|
set(BOOST_HASH f55c340aa49763b1925ccf02b2e83f35fdcf634c9d5164a2acb87540173c741d)
|
||||||
set(CPP_HTTPLIB_HASH 405abd8170f2a446fc8612ac635d0db5947c0d2e156e32603403a4496255ff00)
|
set(CPP_HTTPLIB_HASH c9b9e0524666e1cd088f0874c57c1ce7c0eaa8552f9f4e15c755d5201fc8c608)
|
||||||
set(CURL_HASH 5a231145114589491fc52da118f9c7ef8abee885d1cb1ced99c7290e9a352f07)
|
set(CURL_HASH 6edc063d1ebaf9cf3b3b46e9fef2f3cd8932694989ecd43d005d6e828426d09f)
|
||||||
set(EXPAT_HASH 372b18f6527d162fa9658f1c74d22a37429b82d822f5a1e1fc7e00f6045a06a2)
|
set(EXPAT_HASH 372b18f6527d162fa9658f1c74d22a37429b82d822f5a1e1fc7e00f6045a06a2)
|
||||||
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 0d8ef5af7f9794e3263480193c491549b2ba6cc74bb018906202ada498a79406)
|
||||||
set(LIBSODIUM_HASH 8e5aeca07a723a27bbecc3beef14b0068d37e7fc0e97f51b3f1c82d2a58005c1)
|
set(LIBSODIUM_HASH 8e5aeca07a723a27bbecc3beef14b0068d37e7fc0e97f51b3f1c82d2a58005c1)
|
||||||
set(MINGW_HASH 30e5aad2c48dd318150f79cff47661232c4175876d6b4d6b270961cf2b49a48b)
|
set(MINGW_HASH cc41898aac4b6e8dd5cffd7331b9d9515b912df4420a3a612b5ea2955bbeed2f)
|
||||||
set(OPENSSL_HASH e15dda82fe2fe8139dc2ac21a36d4ca01d5313c75f99f46c4e8a27709b7294bf)
|
set(OPENSSL_HASH 002a2d6b30b58bf4bea46c43bdd96365aaf8daa6c428782aa4feee06da197df3)
|
||||||
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 fdccab16133c9d927a183c2648bcea8d956fb41eb1df2aacaa73eb0b95e43724)
|
||||||
set(SPDLOG_HASH 9962648c9b4f1a7bbc76fd8d9172555bad1871fdb14ff4f842ef87949682caa5)
|
set(SPDLOG_HASH 25c843860f039a1600f232c6eb9e01e6627f7d030a2ae5e232bdd3c9205d26cc)
|
||||||
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()
|
||||||
|
@ -5,24 +5,24 @@ set(BOOST2_PATCH_VERSION 0)
|
|||||||
set(BOOST_MAJOR_VERSION 1)
|
set(BOOST_MAJOR_VERSION 1)
|
||||||
set(BOOST_MINOR_VERSION 87)
|
set(BOOST_MINOR_VERSION 87)
|
||||||
set(BOOST_PATCH_VERSION 0)
|
set(BOOST_PATCH_VERSION 0)
|
||||||
set(CPP_HTTPLIB_VERSION 0.18.1)
|
set(CPP_HTTPLIB_VERSION 0.19.0)
|
||||||
set(CURL2_VERSION 8_11_0)
|
set(CURL2_VERSION 8_12_1)
|
||||||
set(CURL_VERSION 8.11.0)
|
set(CURL_VERSION 8.12.1)
|
||||||
set(EXPAT2_VERSION 2_6_4)
|
set(EXPAT2_VERSION 2_6_4)
|
||||||
set(EXPAT_VERSION 2.6.4)
|
set(EXPAT_VERSION 2.6.4)
|
||||||
set(GCC_VERSION 14.2.0)
|
set(GCC_VERSION 14.2.0)
|
||||||
set(GTEST_VERSION 1.15.2)
|
set(GTEST_VERSION 1.16.0)
|
||||||
set(ICU_VERSION 76-1)
|
set(ICU_VERSION 76-1)
|
||||||
set(JSON_VERSION 3.11.3)
|
set(JSON_VERSION 3.11.3)
|
||||||
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.4.1)
|
||||||
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 9.10.0)
|
||||||
set(SPDLOG_VERSION 1.15.0)
|
set(SPDLOG_VERSION 1.15.1)
|
||||||
set(SQLITE2_VERSION 3.46.1)
|
set(SQLITE2_VERSION 3.49.1)
|
||||||
set(SQLITE_VERSION 3460100)
|
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=4
|
PROJECT_REVISION_VERSION=5
|
||||||
PROJECT_RELEASE_NUM=0
|
PROJECT_RELEASE_NUM=0
|
||||||
PROJECT_RELEASE_ITER=rc
|
PROJECT_RELEASE_ITER=rc
|
||||||
|
|
||||||
@ -19,6 +19,8 @@ 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_WIN32_LONG_PATH_NAMES=OFF
|
PROJECT_ENABLE_WIN32_LONG_PATH_NAMES=OFF
|
||||||
|
|
||||||
PROJECT_ENABLE_BACKWARD_CPP=OFF
|
PROJECT_ENABLE_BACKWARD_CPP=OFF
|
||||||
|
@ -31,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 \
|
||||||
|
@ -31,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
|
@ -18,6 +18,7 @@ RUN apk add \
|
|||||||
gcc \
|
gcc \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
git-lfs \
|
||||||
gmp \
|
gmp \
|
||||||
gmp-dev \
|
gmp-dev \
|
||||||
gperf \
|
gperf \
|
||||||
@ -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} \
|
||||||
|
@ -43,8 +43,7 @@ public:
|
|||||||
[[nodiscard]] static auto default_remote_api_port(const provider_type &prov)
|
[[nodiscard]] static auto default_remote_api_port(const provider_type &prov)
|
||||||
-> std::uint16_t;
|
-> std::uint16_t;
|
||||||
|
|
||||||
[[nodiscard]] static auto default_rpc_port(const provider_type &prov)
|
[[nodiscard]] static auto default_rpc_port() -> std::uint16_t;
|
||||||
-> std::uint16_t;
|
|
||||||
|
|
||||||
[[nodiscard]] static auto get_provider_display_name(const provider_type &prov)
|
[[nodiscard]] static auto get_provider_display_name(const provider_type &prov)
|
||||||
-> std::string;
|
-> std::string;
|
||||||
@ -52,6 +51,8 @@ public:
|
|||||||
[[nodiscard]] static auto get_provider_name(const provider_type &prov)
|
[[nodiscard]] static auto 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_;
|
||||||
@ -121,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;
|
||||||
|
|
||||||
@ -199,7 +200,7 @@ public:
|
|||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ using json = nlohmann::json;
|
|||||||
inline constexpr const std::string_view REPERTORY = "repertory";
|
inline constexpr const std::string_view REPERTORY = "repertory";
|
||||||
inline constexpr const std::wstring_view REPERTORY_W = L"repertory";
|
inline constexpr const std::wstring_view REPERTORY_W = L"repertory";
|
||||||
|
|
||||||
inline constexpr const std::uint64_t REPERTORY_CONFIG_VERSION = 1ULL;
|
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_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";
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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,7 +23,7 @@
|
|||||||
#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_secs{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{std::uint16_t{30U}};
|
constexpr const auto default_high_freq_interval_secs{std::uint16_t{30U}};
|
||||||
@ -38,6 +38,7 @@ 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 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{
|
||||||
@ -280,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 {
|
||||||
@ -304,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};
|
||||||
@ -452,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"};
|
||||||
@ -487,6 +501,7 @@ 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_PATH{"Path"};
|
inline constexpr const auto JSON_PATH{"Path"};
|
||||||
|
@ -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,8 +66,8 @@ 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_secs),
|
download_timeout_secs_(default_download_timeout_secs),
|
||||||
@ -124,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,
|
||||||
@ -253,10 +253,10 @@ app_config::app_config(const provider_type &prov,
|
|||||||
|
|
||||||
value_set_lookup_ = {
|
value_set_lookup_ = {
|
||||||
{
|
{
|
||||||
JSON_API_AUTH,
|
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();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -699,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,
|
||||||
@ -741,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_; }
|
||||||
|
|
||||||
@ -814,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_},
|
||||||
@ -939,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));
|
||||||
}
|
}
|
||||||
@ -1035,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);
|
||||||
@ -1092,6 +1080,13 @@ auto app_config::load() -> bool {
|
|||||||
set_value(max_cache_size_bytes_, default_max_cache_size_bytes);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1130,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) {
|
||||||
|
@ -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)
|
||||||
|
@ -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)) {}
|
||||||
|
@ -28,64 +28,16 @@
|
|||||||
#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) {}
|
||||||
|
|
||||||
auto server::check_authorization(const httplib::Request &req) -> bool {
|
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
|
||||||
|
|
||||||
if (config_.get_api_auth().empty() || config_.get_api_user().empty()) {
|
|
||||||
utils::error::raise_error(function_name,
|
|
||||||
"authorization user or password is not set");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto authorization = req.get_header_value("Authorization");
|
|
||||||
if (authorization.empty()) {
|
|
||||||
utils::error::raise_error(function_name, "Authorization header is not set");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto auth_parts = utils::string::split(authorization, ' ', true);
|
|
||||||
if (auth_parts.empty()) {
|
|
||||||
utils::error::raise_error(function_name, "Authorization header is empty");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto auth_type = auth_parts[0U];
|
|
||||||
if (auth_type != "Basic") {
|
|
||||||
utils::error::raise_error(function_name, "Authorization is not Basic");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto data = macaron::Base64::Decode(authorization.substr(6U));
|
|
||||||
auto auth_str = std::string(data.begin(), data.end());
|
|
||||||
|
|
||||||
auto auth = utils::string::split(auth_str, ':', false);
|
|
||||||
if (auth.size() < 2U) {
|
|
||||||
utils::error::raise_error(function_name, "Authorization is not valid");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto user = auth.at(0U);
|
|
||||||
auth.erase(auth.begin());
|
|
||||||
|
|
||||||
auto pwd = utils::string::join(auth, ':');
|
|
||||||
if ((user != config_.get_api_user()) || (pwd != config_.get_api_auth())) {
|
|
||||||
utils::error::raise_error(function_name, "Authorization failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void server::handle_get_config(const httplib::Request & /*req*/,
|
void server::handle_get_config(const httplib::Request & /*req*/,
|
||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
auto data = config_.get_json();
|
auto data = config_.get_json();
|
||||||
|
clean_json_config(config_.get_provider_type(), data);
|
||||||
res.set_content(data.dump(), "application/json");
|
res.set_content(data.dump(), "application/json");
|
||||||
res.status = http_error_codes::ok;
|
res.status = http_error_codes::ok;
|
||||||
}
|
}
|
||||||
@ -93,7 +45,10 @@ void server::handle_get_config(const httplib::Request & /*req*/,
|
|||||||
void server::handle_get_config_value_by_name(const httplib::Request &req,
|
void server::handle_get_config_value_by_name(const httplib::Request &req,
|
||||||
httplib::Response &res) {
|
httplib::Response &res) {
|
||||||
auto name = req.get_param_value("name");
|
auto name = req.get_param_value("name");
|
||||||
auto data = json({{"value", config_.get_value_by_name(name)}});
|
auto data = json({{
|
||||||
|
"value",
|
||||||
|
clean_json_value(name, config_.get_value_by_name(name)),
|
||||||
|
}});
|
||||||
res.set_content(data.dump(), "application/json");
|
res.set_content(data.dump(), "application/json");
|
||||||
res.status = http_error_codes::ok;
|
res.status = http_error_codes::ok;
|
||||||
}
|
}
|
||||||
@ -103,7 +58,10 @@ void server::handle_set_config_value_by_name(const httplib::Request &req,
|
|||||||
auto name = req.get_param_value("name");
|
auto name = req.get_param_value("name");
|
||||||
auto value = req.get_param_value("value");
|
auto value = req.get_param_value("value");
|
||||||
|
|
||||||
json data = {{"value", config_.set_value_by_name(name, value)}};
|
json data = {{
|
||||||
|
"value",
|
||||||
|
clean_json_value(name, config_.set_value_by_name(name, value)),
|
||||||
|
}};
|
||||||
res.set_content(data.dump(), "application/json");
|
res.set_content(data.dump(), "application/json");
|
||||||
res.status = http_error_codes::ok;
|
res.status = http_error_codes::ok;
|
||||||
}
|
}
|
||||||
@ -173,7 +131,7 @@ void server::start() {
|
|||||||
|
|
||||||
server_->set_pre_routing_handler(
|
server_->set_pre_routing_handler(
|
||||||
[this](auto &&req, auto &&res) -> httplib::Server::HandlerResponse {
|
[this](auto &&req, auto &&res) -> httplib::Server::HandlerResponse {
|
||||||
if (check_authorization(req)) {
|
if (rpc::check_authorization(config_, req)) {
|
||||||
return httplib::Server::HandlerResponse::Unhandled;
|
return httplib::Server::HandlerResponse::Unhandled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,8 +141,21 @@ void server::start() {
|
|||||||
|
|
||||||
initialize(*server_);
|
initialize(*server_);
|
||||||
|
|
||||||
server_thread_ = std::make_unique<std::thread>(
|
server_thread_ = std::make_unique<std::thread>([this]() {
|
||||||
[this]() { server_->listen("127.0.0.1", config_.get_api_port()); });
|
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_->listen("127.0.0.1", config_.get_api_port());
|
||||||
|
});
|
||||||
event_system::instance().raise<service_start_end>(function_name, "server");
|
event_system::instance().raise<service_start_end>(function_name, "server");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>();
|
||||||
|
@ -44,11 +44,13 @@ struct repertory_exception_handler final
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
@ -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},
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
void handle_get_mount_list(httplib::Response &res) const;
|
||||||
|
|
||||||
|
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_
|
@ -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);
|
||||||
|
751
repertory/repertory/src/ui/handlers.cpp
Normal file
751
repertory/repertory/src/ui/handlers.cpp
Normal file
@ -0,0 +1,751 @@
|
|||||||
|
/*
|
||||||
|
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.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", [this](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) const {
|
||||||
|
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::ipstream out;
|
||||||
|
boost::process::child proc(repertory_binary_, boost::process::args(args),
|
||||||
|
boost::process::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
|
@ -128,7 +128,7 @@ std::atomic<std::uint64_t> app_config_test::idx{0U};
|
|||||||
|
|
||||||
static void defaults_tests(const json &json_data, provider_type prov) {
|
static void defaults_tests(const json &json_data, provider_type prov) {
|
||||||
json json_defaults = {
|
json json_defaults = {
|
||||||
{JSON_API_PORT, app_config::default_rpc_port(prov)},
|
{JSON_API_PORT, app_config::default_rpc_port()},
|
||||||
{JSON_API_USER, std::string{REPERTORY}},
|
{JSON_API_USER, std::string{REPERTORY}},
|
||||||
{JSON_DOWNLOAD_TIMEOUT_SECS, default_download_timeout_secs},
|
{JSON_DOWNLOAD_TIMEOUT_SECS, default_download_timeout_secs},
|
||||||
{JSON_DATABASE_TYPE, database_type::rocksdb},
|
{JSON_DATABASE_TYPE, database_type::rocksdb},
|
||||||
@ -185,9 +185,9 @@ static void defaults_tests(const json &json_data, provider_type prov) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt::println("testing default|{}-{}", app_config::get_provider_name(prov),
|
fmt::println("testing default|{}-{}", app_config::get_provider_name(prov),
|
||||||
JSON_API_AUTH);
|
JSON_API_PASSWORD);
|
||||||
ASSERT_EQ(std::size_t(default_api_auth_size),
|
ASSERT_EQ(std::size_t(default_api_password_size),
|
||||||
json_data.at(JSON_API_AUTH).get<std::string>().size());
|
json_data.at(JSON_API_PASSWORD).get<std::string>().size());
|
||||||
for (const auto &[key, value] : json_defaults.items()) {
|
for (const auto &[key, value] : json_defaults.items()) {
|
||||||
fmt::println("testing default|{}-{}", app_config::get_provider_name(prov),
|
fmt::println("testing default|{}-{}", app_config::get_provider_name(prov),
|
||||||
key);
|
key);
|
||||||
@ -216,11 +216,11 @@ static void common_tests(app_config &config, provider_type prov) {
|
|||||||
ASSERT_EQ(config.get_provider_type(), prov);
|
ASSERT_EQ(config.get_provider_type(), prov);
|
||||||
|
|
||||||
std::map<std::string_view, std::function<void(app_config &)>> methods{
|
std::map<std::string_view, std::function<void(app_config &)>> methods{
|
||||||
{JSON_API_AUTH,
|
{JSON_API_PASSWORD,
|
||||||
[](app_config &cfg) {
|
[](app_config &cfg) {
|
||||||
test_getter_setter(cfg, &app_config::get_api_auth,
|
test_getter_setter(cfg, &app_config::get_api_password,
|
||||||
&app_config::set_api_auth, "", "auth",
|
&app_config::set_api_password, "", "auth",
|
||||||
JSON_API_AUTH, "auth2");
|
JSON_API_PASSWORD, "auth2");
|
||||||
}},
|
}},
|
||||||
{JSON_API_PORT,
|
{JSON_API_PORT,
|
||||||
[](app_config &cfg) {
|
[](app_config &cfg) {
|
||||||
|
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
|
@ -62,13 +62,16 @@ TEST(lock_data_test, 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,11 +79,15 @@ TEST(lock_data_test, 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_test, set_and_unset_mount_state) {
|
TEST(lock_data_test, set_and_unset_mount_state) {
|
||||||
@ -91,14 +98,13 @@ TEST(lock_data_test, 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
|
||||||
|
@ -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
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
if [ "${PROJECT_BUILD_ARCH}" == "aarch64" ]; then
|
if [ "${PROJECT_BUILD_ARCH}" == "aarch64" ] &&
|
||||||
|
[ "${PROJECT_ENABLE_MULTIARCH_DOCKER}" == "1" ]; then
|
||||||
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -7,6 +7,12 @@ PROJECT_IS_MINGW=$4
|
|||||||
PROJECT_IS_MINGW_UNIX=$5
|
PROJECT_IS_MINGW_UNIX=$5
|
||||||
DISABLE_CREATE_DIRS=$6
|
DISABLE_CREATE_DIRS=$6
|
||||||
|
|
||||||
|
PROJECT_FLUTTER_BASE_HREF="/"
|
||||||
|
|
||||||
|
if [ "${PROJECT_IS_MINGW}" != "1" ]; then
|
||||||
|
PROJECT_IS_MINGW_UNIX=0
|
||||||
|
fi
|
||||||
|
|
||||||
PROJECT_SOURCE_DIR=${PROJECT_SCRIPTS_DIR}/..
|
PROJECT_SOURCE_DIR=${PROJECT_SCRIPTS_DIR}/..
|
||||||
PROJECT_SOURCE_DIR=$(realpath "${PROJECT_SOURCE_DIR}")
|
PROJECT_SOURCE_DIR=$(realpath "${PROJECT_SOURCE_DIR}")
|
||||||
|
|
||||||
@ -306,9 +312,10 @@ export PROJECT_COMPANY_NAME
|
|||||||
export PROJECT_COPYRIGHT
|
export PROJECT_COPYRIGHT
|
||||||
export PROJECT_DESC
|
export PROJECT_DESC
|
||||||
export PROJECT_DIST_DIR
|
export PROJECT_DIST_DIR
|
||||||
export PROJECT_ENABLE_WIN32_LONG_PATH_NAMES
|
|
||||||
export PROJECT_ENABLE_V2_ERRORS
|
export PROJECT_ENABLE_V2_ERRORS
|
||||||
|
export PROJECT_ENABLE_WIN32_LONG_PATH_NAMES
|
||||||
export PROJECT_FILE_PART
|
export PROJECT_FILE_PART
|
||||||
|
export PROJECT_FLUTTER_BASE_HREF
|
||||||
export PROJECT_GIT_REV
|
export PROJECT_GIT_REV
|
||||||
export PROJECT_IS_ALPINE
|
export PROJECT_IS_ALPINE
|
||||||
export PROJECT_IS_ARM64
|
export PROJECT_IS_ARM64
|
||||||
@ -361,6 +368,7 @@ echo " Dist dir: ${PROJECT_DIST_DIR}"
|
|||||||
echo " Enable v2 errors: ${PROJECT_ENABLE_V2_ERRORS}"
|
echo " Enable v2 errors: ${PROJECT_ENABLE_V2_ERRORS}"
|
||||||
echo " External build root: ${PROJECT_EXTERNAL_BUILD_ROOT}"
|
echo " External build root: ${PROJECT_EXTERNAL_BUILD_ROOT}"
|
||||||
echo " File part: ${PROJECT_FILE_PART}"
|
echo " File part: ${PROJECT_FILE_PART}"
|
||||||
|
echo " Flutter base href: ${PROJECT_FLUTTER_BASE_HREF}"
|
||||||
echo " Is ARM64: ${PROJECT_IS_ARM64}"
|
echo " Is ARM64: ${PROJECT_IS_ARM64}"
|
||||||
echo " Is Alpine: ${PROJECT_IS_ALPINE}"
|
echo " Is Alpine: ${PROJECT_IS_ALPINE}"
|
||||||
echo " Is MINGW on Unix: ${PROJECT_IS_MINGW_UNIX}"
|
echo " Is MINGW on Unix: ${PROJECT_IS_MINGW_UNIX}"
|
||||||
|
@ -59,7 +59,7 @@ PROJECT_DOWNLOADS[PKG_CONFIG]="https://pkgconfig.freedesktop.org/releases/pkg-co
|
|||||||
PROJECT_DOWNLOADS[PUGIXML]="https://github.com/zeux/pugixml/releases/download/v${PROJECT_VERSIONS[PUGIXML]}/pugixml-${PROJECT_VERSIONS[PUGIXML]}.tar.gz;pugixml-${PROJECT_VERSIONS[PUGIXML]}.tar.gz;3rd_party"
|
PROJECT_DOWNLOADS[PUGIXML]="https://github.com/zeux/pugixml/releases/download/v${PROJECT_VERSIONS[PUGIXML]}/pugixml-${PROJECT_VERSIONS[PUGIXML]}.tar.gz;pugixml-${PROJECT_VERSIONS[PUGIXML]}.tar.gz;3rd_party"
|
||||||
PROJECT_DOWNLOADS[ROCKSDB]="https://github.com/facebook/rocksdb/archive/refs/tags/v${PROJECT_VERSIONS[ROCKSDB]}.tar.gz;rocksdb-${PROJECT_VERSIONS[ROCKSDB]}.tar.gz;3rd_party"
|
PROJECT_DOWNLOADS[ROCKSDB]="https://github.com/facebook/rocksdb/archive/refs/tags/v${PROJECT_VERSIONS[ROCKSDB]}.tar.gz;rocksdb-${PROJECT_VERSIONS[ROCKSDB]}.tar.gz;3rd_party"
|
||||||
PROJECT_DOWNLOADS[SPDLOG]="https://github.com/gabime/spdlog/archive/refs/tags/v${PROJECT_VERSIONS[SPDLOG]}.tar.gz;spdlog-${PROJECT_VERSIONS[SPDLOG]}.tar.gz;3rd_party"
|
PROJECT_DOWNLOADS[SPDLOG]="https://github.com/gabime/spdlog/archive/refs/tags/v${PROJECT_VERSIONS[SPDLOG]}.tar.gz;spdlog-${PROJECT_VERSIONS[SPDLOG]}.tar.gz;3rd_party"
|
||||||
PROJECT_DOWNLOADS[SQLITE]="https://www.sqlite.org/2024/sqlite-amalgamation-${PROJECT_VERSIONS[SQLITE]}.zip;sqlite-amalgamation-${PROJECT_VERSIONS[SQLITE]}.zip;3rd_party"
|
PROJECT_DOWNLOADS[SQLITE]="https://www.sqlite.org/2025/sqlite-amalgamation-${PROJECT_VERSIONS[SQLITE]}.zip;sqlite-amalgamation-${PROJECT_VERSIONS[SQLITE]}.zip;3rd_party"
|
||||||
PROJECT_DOWNLOADS[STDUUID]="https://github.com/mariusbancila/stduuid/archive/refs/tags/v${PROJECT_VERSIONS[STDUUID]}.tar.gz;stduuid-${PROJECT_VERSIONS[STDUUID]}.tar.gz;3rd_party"
|
PROJECT_DOWNLOADS[STDUUID]="https://github.com/mariusbancila/stduuid/archive/refs/tags/v${PROJECT_VERSIONS[STDUUID]}.tar.gz;stduuid-${PROJECT_VERSIONS[STDUUID]}.tar.gz;3rd_party"
|
||||||
PROJECT_DOWNLOADS[ZLIB]="https://github.com/madler/zlib/archive/refs/tags/v${PROJECT_VERSIONS[ZLIB]}.tar.gz;zlib-${PROJECT_VERSIONS[ZLIB]}.tar.gz;3rd_party/mingw64"
|
PROJECT_DOWNLOADS[ZLIB]="https://github.com/madler/zlib/archive/refs/tags/v${PROJECT_VERSIONS[ZLIB]}.tar.gz;zlib-${PROJECT_VERSIONS[ZLIB]}.tar.gz;3rd_party/mingw64"
|
||||||
export PROJECT_DOWNLOADS
|
export PROJECT_DOWNLOADS
|
||||||
|
@ -18,6 +18,8 @@ fi
|
|||||||
ln -sf "${PROJECT_BUILD_DIR}/build/compile_commands.json" "${PROJECT_SOURCE_DIR}/compile_commands.json"
|
ln -sf "${PROJECT_BUILD_DIR}/build/compile_commands.json" "${PROJECT_SOURCE_DIR}/compile_commands.json"
|
||||||
|
|
||||||
pushd "${PROJECT_BUILD_DIR}"
|
pushd "${PROJECT_BUILD_DIR}"
|
||||||
|
export CMAKE_BUILD_PARALLEL_LEVEL=${NUM_JOBS}
|
||||||
|
|
||||||
cmake "${PROJECT_SOURCE_DIR}" \
|
cmake "${PROJECT_SOURCE_DIR}" \
|
||||||
-G"Unix Makefiles" \
|
-G"Unix Makefiles" \
|
||||||
-DPROJECT_COMPANY_NAME="${PROJECT_COMPANY_NAME}" \
|
-DPROJECT_COMPANY_NAME="${PROJECT_COMPANY_NAME}" \
|
||||||
@ -34,10 +36,10 @@ if [ "${PROJECT_BUILD_CLEAN}" == "clean" ]; then
|
|||||||
popd
|
popd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
make -j${NUM_JOBS} || exit 1
|
make || exit 1
|
||||||
|
|
||||||
pushd build
|
pushd build
|
||||||
make -j${NUM_JOBS} || exit 1
|
make -j${CMAKE_BUILD_PARALLEL_LEVEL} || exit 1
|
||||||
popd
|
popd
|
||||||
popd
|
popd
|
||||||
|
|
||||||
@ -79,6 +81,11 @@ EOF
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [ -f "${PROJECT_SOURCE_DIR}/web/${PROJECT_NAME}/pubspec.yaml" ]; then
|
||||||
|
rsync -av --progress "${PROJECT_SOURCE_DIR}/web/${PROJECT_NAME}/build/web/" \
|
||||||
|
"${PROJECT_DIST_DIR}/web/"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "${PROJECT_IS_MINGW}" == "1" ]; then
|
if [ "${PROJECT_IS_MINGW}" == "1" ]; then
|
||||||
. "${PROJECT_SCRIPTS_DIR}/copy_mingw64_deps.sh" "$1" "$2" "$3" "$4" "$5"
|
. "${PROJECT_SCRIPTS_DIR}/copy_mingw64_deps.sh" "$1" "$2" "$3" "$4" "$5"
|
||||||
fi
|
fi
|
||||||
|
43
scripts/make_flutter.sh
Executable file
43
scripts/make_flutter.sh
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PROJECT_SCRIPTS_DIR=$(realpath "$0")
|
||||||
|
PROJECT_SCRIPTS_DIR=$(dirname "${PROJECT_SCRIPTS_DIR}")
|
||||||
|
. "${PROJECT_SCRIPTS_DIR}/env.sh" "$1" "$2" "$3" "$4" "$5"
|
||||||
|
|
||||||
|
if [ -f "${PROJECT_SOURCE_DIR}/web/${PROJECT_NAME}/pubspec.yaml" ]; then
|
||||||
|
if [ "${PROJECT_IS_MINGW}" == "0" ] || [ "${PROJECT_IS_MINGW_UNIX}" == "1" ]; then
|
||||||
|
FLUTTER_CONTAINER_NAME="${PROJECT_NAME}_flutter"
|
||||||
|
FLUTTER_TAG_NAME="${PROJECT_NAME}:flutter"
|
||||||
|
|
||||||
|
docker stop ${FLUTTER_CONTAINER_NAME}
|
||||||
|
docker rm ${FLUTTER_CONTAINER_NAME}
|
||||||
|
|
||||||
|
docker build "${PROJECT_SOURCE_DIR}/docker/x86_64/" \
|
||||||
|
--build-arg UID=$(id -u) \
|
||||||
|
--build-arg GID=$(id -g) \
|
||||||
|
-t ${FLUTTER_TAG_NAME} \
|
||||||
|
-f "${PROJECT_SOURCE_DIR}/docker/x86_64/flutter" || exit 1
|
||||||
|
|
||||||
|
docker run -td \
|
||||||
|
--name ${FLUTTER_CONTAINER_NAME} \
|
||||||
|
-u $(id -u):$(id -g) \
|
||||||
|
-v ${PROJECT_SOURCE_DIR}:${PROJECT_SOURCE_DIR}:rw,z \
|
||||||
|
-w ${PROJECT_SOURCE_DIR}/web/${PROJECT_NAME} \
|
||||||
|
${FLUTTER_TAG_NAME} || exit 1
|
||||||
|
|
||||||
|
docker exec \
|
||||||
|
${FLUTTER_CONTAINER_NAME} \
|
||||||
|
/bin/bash -c \
|
||||||
|
"flutter clean;flutter build web --base-href=${PROJECT_FLUTTER_BASE_HREF}" || exit 1
|
||||||
|
|
||||||
|
docker stop ${FLUTTER_CONTAINER_NAME}
|
||||||
|
docker rm ${FLUTTER_CONTAINER_NAME}
|
||||||
|
else
|
||||||
|
pushd "${PROJECT_SOURCE_DIR}/web/${PROJECT_NAME}"
|
||||||
|
export MSYS_NO_PATHCONV=1
|
||||||
|
flutter clean
|
||||||
|
flutter build web --base-href=${PROJECT_FLUTTER_BASE_HREF} || exit 1
|
||||||
|
export MSYS_NO_PATHCONV=0
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
fi
|
@ -9,6 +9,8 @@ if [ -f "${PROJECT_SCRIPTS_DIR}/cleanup.sh" ]; then
|
|||||||
rm ${PROJECT_SCRIPTS_DIR}/cleanup.*
|
rm ${PROJECT_SCRIPTS_DIR}/cleanup.*
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
"${PROJECT_SOURCE_DIR}/scripts/make_flutter.sh" "${PROJECT_BUILD_ARCH}" "${PROJECT_CMAKE_BUILD_TYPE}" "${PROJECT_BUILD_CLEAN}" 0 0 || exit 1
|
||||||
|
|
||||||
if [ "${PROJECT_REQUIRE_ALPINE}" == "ON" ] || [ "${PROJECT_IS_ARM64}" == "1" ]; then
|
if [ "${PROJECT_REQUIRE_ALPINE}" == "ON" ] || [ "${PROJECT_IS_ARM64}" == "1" ]; then
|
||||||
DOCKER_NAME=alpine
|
DOCKER_NAME=alpine
|
||||||
DOCKER_CONTAINER=${PROJECT_NAME}_${DOCKER_NAME}_${PROJECT_BUILD_ARCH}
|
DOCKER_CONTAINER=${PROJECT_NAME}_${DOCKER_NAME}_${PROJECT_BUILD_ARCH}
|
||||||
|
@ -12,5 +12,7 @@ pushd "%~dp0%"
|
|||||||
call cleanup.cmd "%ARG1%" "%ARG2%" "%ARG3%" 1 0
|
call cleanup.cmd "%ARG1%" "%ARG2%" "%ARG3%" 1 0
|
||||||
del cleanup.*
|
del cleanup.*
|
||||||
)
|
)
|
||||||
|
|
||||||
|
call mingw64 -no-start ./make_flutter.sh "%ARG1%" "%ARG2%" "%ARG3%" 1 0 || exit 1
|
||||||
call mingw64 -no-start ./make_common.sh "%ARG1%" "%ARG2%" "%ARG3%" 1 0 || exit 1
|
call mingw64 -no-start ./make_common.sh "%ARG1%" "%ARG2%" "%ARG3%" 1 0 || exit 1
|
||||||
popd
|
popd
|
||||||
|
@ -8,25 +8,25 @@ PROJECT_VERSIONS[BOOST2_PATCH]="0"
|
|||||||
PROJECT_VERSIONS[BOOST_MAJOR]="1"
|
PROJECT_VERSIONS[BOOST_MAJOR]="1"
|
||||||
PROJECT_VERSIONS[BOOST_MINOR]="87"
|
PROJECT_VERSIONS[BOOST_MINOR]="87"
|
||||||
PROJECT_VERSIONS[BOOST_PATCH]="0"
|
PROJECT_VERSIONS[BOOST_PATCH]="0"
|
||||||
PROJECT_VERSIONS[CPP_HTTPLIB]="0.18.1"
|
PROJECT_VERSIONS[CPP_HTTPLIB]="0.19.0"
|
||||||
PROJECT_VERSIONS[CURL]="8.11.0"
|
PROJECT_VERSIONS[CURL]="8.12.1"
|
||||||
PROJECT_VERSIONS[CURL2]="8_11_0"
|
PROJECT_VERSIONS[CURL2]="8_12_1"
|
||||||
PROJECT_VERSIONS[EXPAT]="2.6.4"
|
PROJECT_VERSIONS[EXPAT]="2.6.4"
|
||||||
PROJECT_VERSIONS[EXPAT2]="2_6_4"
|
PROJECT_VERSIONS[EXPAT2]="2_6_4"
|
||||||
PROJECT_VERSIONS[GCC]="14.2.0"
|
PROJECT_VERSIONS[GCC]="14.2.0"
|
||||||
PROJECT_VERSIONS[GTEST]="1.15.2"
|
PROJECT_VERSIONS[GTEST]="1.16.0"
|
||||||
PROJECT_VERSIONS[ICU]="76-1"
|
PROJECT_VERSIONS[ICU]="76-1"
|
||||||
PROJECT_VERSIONS[JSON]="3.11.3"
|
PROJECT_VERSIONS[JSON]="3.11.3"
|
||||||
PROJECT_VERSIONS[LIBSODIUM]="1.0.20"
|
PROJECT_VERSIONS[LIBSODIUM]="1.0.20"
|
||||||
PROJECT_VERSIONS[MESA]="23.3.3"
|
PROJECT_VERSIONS[MESA]="23.3.3"
|
||||||
PROJECT_VERSIONS[MINGW]="12.0.0"
|
PROJECT_VERSIONS[MINGW]="12.0.0"
|
||||||
PROJECT_VERSIONS[OPENSSL]="3.4.0"
|
PROJECT_VERSIONS[OPENSSL]="3.4.1"
|
||||||
PROJECT_VERSIONS[PKG_CONFIG]="0.29.2"
|
PROJECT_VERSIONS[PKG_CONFIG]="0.29.2"
|
||||||
PROJECT_VERSIONS[PUGIXML]="1.14"
|
PROJECT_VERSIONS[PUGIXML]="1.15"
|
||||||
PROJECT_VERSIONS[ROCKSDB]="9.7.4"
|
PROJECT_VERSIONS[ROCKSDB]="9.10.0"
|
||||||
PROJECT_VERSIONS[SPDLOG]="1.15.0"
|
PROJECT_VERSIONS[SPDLOG]="1.15.1"
|
||||||
PROJECT_VERSIONS[SQLITE]="3460100"
|
PROJECT_VERSIONS[SQLITE]="3490100"
|
||||||
PROJECT_VERSIONS[SQLITE2]="3.46.1"
|
PROJECT_VERSIONS[SQLITE2]="3.49.1"
|
||||||
PROJECT_VERSIONS[STDUUID]="1.2.3"
|
PROJECT_VERSIONS[STDUUID]="1.2.3"
|
||||||
PROJECT_VERSIONS[ZLIB]="1.3.1"
|
PROJECT_VERSIONS[ZLIB]="1.3.1"
|
||||||
export PROJECT_VERSIONS
|
export PROJECT_VERSIONS
|
||||||
|
BIN
support/3rd_party/boost_1_87_0.tar.gz
vendored
BIN
support/3rd_party/boost_1_87_0.tar.gz
vendored
Binary file not shown.
BIN
support/3rd_party/cpp-httplib-0.18.1.tar.gz
vendored
BIN
support/3rd_party/cpp-httplib-0.18.1.tar.gz
vendored
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
405abd8170f2a446fc8612ac635d0db5947c0d2e156e32603403a4496255ff00 *cpp-httplib-0.18.1.tar.gz
|
|
BIN
support/3rd_party/cpp-httplib-0.19.0.tar.gz
(Stored with Git LFS)
vendored
Normal file
BIN
support/3rd_party/cpp-httplib-0.19.0.tar.gz
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
1
support/3rd_party/cpp-httplib-0.19.0.tar.gz.sha256
vendored
Normal file
1
support/3rd_party/cpp-httplib-0.19.0.tar.gz.sha256
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
c9b9e0524666e1cd088f0874c57c1ce7c0eaa8552f9f4e15c755d5201fc8c608 *cpp-httplib-0.19.0.tar.gz
|
BIN
support/3rd_party/curl-8.11.0.tar.gz
vendored
BIN
support/3rd_party/curl-8.11.0.tar.gz
vendored
Binary file not shown.
1
support/3rd_party/curl-8.11.0.tar.gz.sha256
vendored
1
support/3rd_party/curl-8.11.0.tar.gz.sha256
vendored
@ -1 +0,0 @@
|
|||||||
5a231145114589491fc52da118f9c7ef8abee885d1cb1ced99c7290e9a352f07 *curl-8.11.0.tar.gz
|
|
BIN
support/3rd_party/curl-8.12.1.tar.gz
(Stored with Git LFS)
vendored
Normal file
BIN
support/3rd_party/curl-8.12.1.tar.gz
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
1
support/3rd_party/curl-8.12.1.tar.gz.sha256
vendored
Normal file
1
support/3rd_party/curl-8.12.1.tar.gz.sha256
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
6edc063d1ebaf9cf3b3b46e9fef2f3cd8932694989ecd43d005d6e828426d09f *curl-8.12.1.tar.gz
|
BIN
support/3rd_party/googletest-1.15.2.tar.gz
vendored
BIN
support/3rd_party/googletest-1.15.2.tar.gz
vendored
Binary file not shown.
BIN
support/3rd_party/googletest-1.16.0.tar.gz
(Stored with Git LFS)
vendored
Normal file
BIN
support/3rd_party/googletest-1.16.0.tar.gz
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
1
support/3rd_party/googletest-1.16.0.tar.gz.sha256
vendored
Normal file
1
support/3rd_party/googletest-1.16.0.tar.gz.sha256
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
78c676fc63881529bf97bf9d45948d905a66833fbfa5318ea2cd7478cb98f399 *googletest-1.16.0.tar.gz
|
BIN
support/3rd_party/json-3.11.3.tar.gz
vendored
BIN
support/3rd_party/json-3.11.3.tar.gz
vendored
Binary file not shown.
BIN
support/3rd_party/libsodium-1.0.20.tar.gz
vendored
BIN
support/3rd_party/libsodium-1.0.20.tar.gz
vendored
Binary file not shown.
BIN
support/3rd_party/mingw64/binutils-2.43.tar.xz
vendored
BIN
support/3rd_party/mingw64/binutils-2.43.tar.xz
vendored
Binary file not shown.
BIN
support/3rd_party/mingw64/expat-2.6.4.tar.gz
vendored
BIN
support/3rd_party/mingw64/expat-2.6.4.tar.gz
vendored
Binary file not shown.
BIN
support/3rd_party/mingw64/gcc-14.2.0.tar.gz
vendored
BIN
support/3rd_party/mingw64/gcc-14.2.0.tar.gz
vendored
Binary file not shown.
BIN
support/3rd_party/mingw64/icu-release-76-1.tar.gz
vendored
BIN
support/3rd_party/mingw64/icu-release-76-1.tar.gz
vendored
Binary file not shown.
BIN
support/3rd_party/mingw64/pkg-config-0.29.2.tar.gz
vendored
BIN
support/3rd_party/mingw64/pkg-config-0.29.2.tar.gz
vendored
Binary file not shown.
BIN
support/3rd_party/mingw64/zlib-1.3.1.tar.gz
vendored
BIN
support/3rd_party/mingw64/zlib-1.3.1.tar.gz
vendored
Binary file not shown.
BIN
support/3rd_party/openssl-3.4.0.tar.gz
vendored
BIN
support/3rd_party/openssl-3.4.0.tar.gz
vendored
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
e15dda82fe2fe8139dc2ac21a36d4ca01d5313c75f99f46c4e8a27709b7294bf *openssl-3.4.0.tar.gz
|
|
BIN
support/3rd_party/openssl-3.4.1.tar.gz
(Stored with Git LFS)
vendored
Normal file
BIN
support/3rd_party/openssl-3.4.1.tar.gz
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
1
support/3rd_party/openssl-3.4.1.tar.gz.sha256
vendored
Normal file
1
support/3rd_party/openssl-3.4.1.tar.gz.sha256
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
002a2d6b30b58bf4bea46c43bdd96365aaf8daa6c428782aa4feee06da197df3 *openssl-3.4.1.tar.gz
|
BIN
support/3rd_party/pugixml-1.14.tar.gz
vendored
BIN
support/3rd_party/pugixml-1.14.tar.gz
vendored
Binary file not shown.
1
support/3rd_party/pugixml-1.14.tar.gz.sha256
vendored
1
support/3rd_party/pugixml-1.14.tar.gz.sha256
vendored
@ -1 +0,0 @@
|
|||||||
2f10e276870c64b1db6809050a75e11a897a8d7456c4be5c6b2e35a11168a015 pugixml-1.14.tar.gz
|
|
BIN
support/3rd_party/pugixml-1.15.tar.gz
(Stored with Git LFS)
vendored
Normal file
BIN
support/3rd_party/pugixml-1.15.tar.gz
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
1
support/3rd_party/pugixml-1.15.tar.gz.sha256
vendored
Normal file
1
support/3rd_party/pugixml-1.15.tar.gz.sha256
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
655ade57fa703fb421c2eb9a0113b5064bddb145d415dd1f88c79353d90d511a *pugixml-1.15.tar.gz
|
BIN
support/3rd_party/rocksdb-9.10.0.tar.gz
(Stored with Git LFS)
vendored
Normal file
BIN
support/3rd_party/rocksdb-9.10.0.tar.gz
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
1
support/3rd_party/rocksdb-9.10.0.tar.gz.sha256
vendored
Normal file
1
support/3rd_party/rocksdb-9.10.0.tar.gz.sha256
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
fdccab16133c9d927a183c2648bcea8d956fb41eb1df2aacaa73eb0b95e43724 *rocksdb-9.10.0.tar.gz
|
BIN
support/3rd_party/rocksdb-9.7.4.tar.gz
vendored
BIN
support/3rd_party/rocksdb-9.7.4.tar.gz
vendored
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
9b810c81731835fda0d4bbdb51d3199d901fa4395733ab63752d297da84c5a47 *rocksdb-9.7.4.tar.gz
|
|
BIN
support/3rd_party/spdlog-1.15.0.tar.gz
vendored
BIN
support/3rd_party/spdlog-1.15.0.tar.gz
vendored
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
9962648c9b4f1a7bbc76fd8d9172555bad1871fdb14ff4f842ef87949682caa5 *spdlog-1.15.0.tar.gz
|
|
BIN
support/3rd_party/spdlog-1.15.1.tar.gz
(Stored with Git LFS)
vendored
Normal file
BIN
support/3rd_party/spdlog-1.15.1.tar.gz
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
1
support/3rd_party/spdlog-1.15.1.tar.gz.sha256
vendored
Normal file
1
support/3rd_party/spdlog-1.15.1.tar.gz.sha256
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
25c843860f039a1600f232c6eb9e01e6627f7d030a2ae5e232bdd3c9205d26cc *spdlog-1.15.1.tar.gz
|
BIN
support/3rd_party/sqlite-amalgamation-3460100.zip
vendored
BIN
support/3rd_party/sqlite-amalgamation-3460100.zip
vendored
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
77823cb110929c2bcb0f5d48e4833b5c59a8a6e40cdea3936b99e199dbbe5784 sqlite-amalgamation-3460100.zip
|
|
BIN
support/3rd_party/sqlite-amalgamation-3490100.zip
(Stored with Git LFS)
vendored
Normal file
BIN
support/3rd_party/sqlite-amalgamation-3490100.zip
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
1
support/3rd_party/sqlite-amalgamation-3490100.zip.sha256
vendored
Normal file
1
support/3rd_party/sqlite-amalgamation-3490100.zip.sha256
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
6cebd1d8403fc58c30e93939b246f3e6e58d0765a5cd50546f16c00fd805d2c3 *sqlite-amalgamation-3490100.zip
|
BIN
support/3rd_party/stduuid-1.2.3.tar.gz
vendored
BIN
support/3rd_party/stduuid-1.2.3.tar.gz
vendored
Binary file not shown.
@ -399,6 +399,13 @@ using vlc_string_t = std::unique_ptr<char, vlc_string_deleter>;
|
|||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#endif // defined(PROJECT_ENABLE_SPDLOG)
|
#endif // defined(PROJECT_ENABLE_SPDLOG)
|
||||||
|
|
||||||
|
#if defined(PROJECT_ENABLE_FMT)
|
||||||
|
#include "fmt/chrono.h"
|
||||||
|
#include "fmt/core.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
#include "fmt/ranges.h"
|
||||||
|
#endif // defined(PROJECT_ENABLE_FMT)
|
||||||
|
|
||||||
#if defined(PROJECT_ENABLE_STDUUID)
|
#if defined(PROJECT_ENABLE_STDUUID)
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
#endif // defined(PROJECT_ENABLE_STDUUID)
|
#endif // defined(PROJECT_ENABLE_STDUUID)
|
||||||
|
@ -131,15 +131,6 @@ inline const spdlog_exception_handler default_exception_handler{};
|
|||||||
inline const iostream_exception_handler default_exception_handler{};
|
inline const iostream_exception_handler default_exception_handler{};
|
||||||
#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
||||||
|
|
||||||
#if defined(PROJECT_ENABLE_TESTING)
|
|
||||||
extern std::atomic<const i_exception_handler *> exception_handler;
|
|
||||||
|
|
||||||
[[nodiscard]] inline auto get_exception_handler()
|
|
||||||
-> const i_exception_handler * {
|
|
||||||
return exception_handler;
|
|
||||||
}
|
|
||||||
#endif // defined(PROJECT_ENABLE_TESTING)
|
|
||||||
|
|
||||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||||
void handle_debug(std::string_view function_name, std::string_view msg);
|
void handle_debug(std::string_view function_name, std::string_view msg);
|
||||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||||
@ -159,6 +150,15 @@ void handle_warn(std::string_view function_name, std::string_view msg);
|
|||||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||||
|
|
||||||
void set_exception_handler(const i_exception_handler *handler);
|
void set_exception_handler(const i_exception_handler *handler);
|
||||||
|
|
||||||
|
#if defined(PROJECT_ENABLE_TESTING)
|
||||||
|
extern std::atomic<const i_exception_handler *> exception_handler;
|
||||||
|
|
||||||
|
[[nodiscard]] inline auto get_exception_handler()
|
||||||
|
-> const i_exception_handler * {
|
||||||
|
return exception_handler;
|
||||||
|
}
|
||||||
|
#endif // defined(PROJECT_ENABLE_TESTING)
|
||||||
} // namespace repertory::utils::error
|
} // namespace repertory::utils::error
|
||||||
|
|
||||||
#endif // REPERTORY_INCLUDE_UTILS_ERROR_HPP_
|
#endif // REPERTORY_INCLUDE_UTILS_ERROR_HPP_
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user