Compare commits
111 Commits
v2.0.4-rc
...
cc4991e211
Author | SHA1 | Date | |
---|---|---|---|
cc4991e211 | |||
5a19ada15d | |||
f165919ed4 | |||
c4b456b9e3 | |||
ad4856739e | |||
fb6a97b97b | |||
8e400db321 | |||
c6c6c5e743 | |||
a8d18fe476 | |||
b57b680344 | |||
8287a1bce8 | |||
892d13ec99 | |||
c817d432c0 | |||
b5aa5136e9 | |||
68c82f76a9 | |||
b4025cf084 | |||
d6b30e11b2 | |||
ba884245b8 | |||
5f713b1f9c | |||
b017aeec12 | |||
462ea165f7 | |||
3ff0cb3f31 | |||
f7fc726452 | |||
e3d9487c74 | |||
b6ded4d026 | |||
e19e606a96 | |||
734f2d3ffe | |||
a957126d90 | |||
b428e996f0 | |||
6c5c592471 | |||
fbaa51f634 | |||
974eeafaf7 | |||
239854194f | |||
e886940999 | |||
a2a1f3e905 | |||
7d1574d042 | |||
43280b2913 | |||
788aefdf86 | |||
3453bd0b50 | |||
96df3168fc | |||
45381c3d0c | |||
4c82b87b07 | |||
c29072d84d | |||
311a2688cb | |||
968633a5b9 | |||
bcda2abfd2 | |||
7d5c252e89 | |||
0aeb69a050 | |||
7d441964e9 | |||
1d78ee88b8 | |||
d54ba8203a | |||
52f0d755ba | |||
343c324050 | |||
e446757f7e | |||
513bc09944 | |||
a79e696315 | |||
26dbda290e | |||
d06b965dc1 | |||
6aee374725 | |||
a7d570d5a0 | |||
c93e6bedcc | |||
93b4237e4f | |||
4013ed692e | |||
99914382f4 | |||
3a468d72ce | |||
0611f0c9dd | |||
5567e665cc | |||
13ebd7b8b0 | |||
c2e9960ad5 | |||
86918595b3 | |||
9f90494efb | |||
b3ee609e09 | |||
7dc2ce8702 | |||
ed5f1f04ad | |||
863e0b2165 | |||
122b4998d6 | |||
722357388c | |||
0e21d93bb3 | |||
e8118bac89 | |||
c4af929d7a | |||
3826afd3bf | |||
4a15e2f827 | |||
48b6012f97 | |||
d37c6598c4 | |||
c95242e016 | |||
6ed4db0737 | |||
1560804df8 | |||
cc3c0febc3 | |||
0458f12e17 | |||
ae43cedb45 | |||
191eb1620b | |||
9c648583fb | |||
14d78d0b65 | |||
54efde0497 | |||
5f593ab86d | |||
feb09746f5 | |||
faad98c11e | |||
12f04c6064 | |||
ca307c3bf2 | |||
ac6f4bcade | |||
9d48cd97e3 | |||
6c6fb0554f | |||
a134f01436 | |||
44c33652fa | |||
131c36415d | |||
9456c8b1d2 | |||
b8c62612d8 | |||
521874a56f | |||
f41ad47262 | |||
8bb2eeb88c | |||
b1aca46034 |
@ -154,6 +154,7 @@ mtune
|
|||||||
musl-libc
|
musl-libc
|
||||||
nana
|
nana
|
||||||
ncrypt
|
ncrypt
|
||||||
|
nlohmann
|
||||||
nlohmann_json
|
nlohmann_json
|
||||||
nmakeprg
|
nmakeprg
|
||||||
nominmax
|
nominmax
|
||||||
|
13
CHANGELOG.md
13
CHANGELOG.md
@ -1,11 +1,24 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v2.0.5-rc
|
||||||
|
|
||||||
|
### Issues
|
||||||
|
|
||||||
|
* ~~\#12 [Unit Test] Complete all providers unit tests~~
|
||||||
|
* ~~\#21 [Unit Test] Complete WinFSP unit tests~~
|
||||||
|
* ~~\#22 [Unit Test] Complete FUSE unit tests~~
|
||||||
|
|
||||||
|
### Changes from v2.0.4-rc
|
||||||
|
|
||||||
|
* Continue documentation updates
|
||||||
|
|
||||||
## v2.0.4-rc
|
## 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
|
||||||
|
469
README.md
469
README.md
@ -3,11 +3,41 @@
|
|||||||
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. [Usage](#usage)
|
||||||
|
1. [Important Options](#important-options)
|
||||||
|
2. [Sia](#sia)
|
||||||
|
* [Sia Initial Configuration](#sia-initial-configuration)
|
||||||
|
* [Sia Mounting](#sia-mounting)
|
||||||
|
* [Sia Configuration File](#sia-configuration-file)
|
||||||
|
3. [S3](#s3)
|
||||||
|
* [S3 Initial Configuration](#s3-initial-configuration)
|
||||||
|
* [S3 Mounting](#s3-mounting)
|
||||||
|
* [S3 Configuration File](#s3-configuration-file)
|
||||||
|
4. [Data Directories](#data-directories)
|
||||||
|
1. [Linux Directories](#linux-directories)
|
||||||
|
2. [Windows Directories](#windows-directories)
|
||||||
|
5. [Remote Mounting](#remote-mounting)
|
||||||
|
1. [Server Setup](#server-setup)
|
||||||
|
* [Remote Mount Configuration File Section](#remote-mount-configuration-file-section)
|
||||||
|
2. [Client Setup](#client-setup)
|
||||||
|
* [Client Remote Mounting](#client-remote-mounting)
|
||||||
|
* [Remote Mount Configuration File](#remote-mount-configuration-file)
|
||||||
|
6. [Compiling](#compiling)
|
||||||
|
1. [Linux Compilation](#linux-compilation)
|
||||||
|
2. [Windows Setup](#windows-compilation)
|
||||||
|
7. [Credits](#credits)
|
||||||
|
8. [Developer Public Key](#developer-public-key)
|
||||||
|
9. [Consult the Wiki for additional information](https://git.fifthgrid.com/BlockStorage/repertory/wiki)
|
||||||
|
|
||||||
## Details and Features
|
## 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,12 +45,13 @@ 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`
|
||||||
@ -28,124 +59,356 @@ on Windows.
|
|||||||
|
|
||||||
## 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
|
||||||
|
{
|
||||||
|
"ApiAuth": "<random generated rpc password>",
|
||||||
|
"ApiPort": 10000,
|
||||||
|
"ApiUser": "repertory",
|
||||||
|
"DatabaseType": "rocksdb",
|
||||||
|
"DownloadTimeoutSeconds": 30,
|
||||||
|
"EnableDownloadTimeout": true,
|
||||||
|
"EnableDriveEvents": false,
|
||||||
|
"EventLevel": "info",
|
||||||
|
"EvictionDelayMinutes": 1,
|
||||||
|
"EvictionUseAccessedTime": false,
|
||||||
|
"HighFreqIntervalSeconds": 30,
|
||||||
|
"HostConfig": {
|
||||||
|
"AgentString": "Sia-Agent",
|
||||||
|
"ApiPassword": "<renterd api password>",
|
||||||
|
"ApiPort": 9980,
|
||||||
|
"ApiUser": "",
|
||||||
|
"HostNameOrIp": "localhost",
|
||||||
|
"Path": "",
|
||||||
|
"Protocol": "http",
|
||||||
|
"TimeoutMs": 60000
|
||||||
|
},
|
||||||
|
"LowFreqIntervalSeconds": 3600,
|
||||||
|
"MaxCacheSizeBytes": 21474836480,
|
||||||
|
"MaxUploadCount": 5,
|
||||||
|
"MedFreqIntervalSeconds": 120,
|
||||||
|
"OnlineCheckRetrySeconds": 60,
|
||||||
|
"PreferredDownloadType": "default",
|
||||||
|
"RemoteMount": {
|
||||||
|
"ApiPort": 20000,
|
||||||
|
"ClientPoolSize": 20,
|
||||||
|
"Enable": false,
|
||||||
|
"EncryptionToken": ""
|
||||||
|
},
|
||||||
|
"RetryReadCount": 6,
|
||||||
|
"RingBufferFileSize": 512,
|
||||||
|
"SiaConfig": {
|
||||||
|
"Bucket": "default"
|
||||||
|
},
|
||||||
|
"TaskWaitMs": 100,
|
||||||
|
"Version": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### S3
|
||||||
|
|
||||||
|
#### S3 Initial Configuration
|
||||||
|
|
||||||
|
* Required steps:
|
||||||
|
* Set the appropriate base URL:
|
||||||
|
* `repertory -s3 --name '<my config name>' -set S3Config.URL '<my url>'`
|
||||||
|
* Example:
|
||||||
|
* `repertory -s3 --name minio -set S3Config.URL 'http://localhost:9000'`
|
||||||
|
* Set the appropriate bucket name:
|
||||||
|
* `repertory -s3 --name '<my config name>' -set S3Config.Bucket '<my bucket name>'`
|
||||||
|
* Set the appropriate access key:
|
||||||
|
* `repertory -s3 --name '<my config name>' -set S3Config.AccessKey '<my access key>'`
|
||||||
|
* Set the appropriate secret key:
|
||||||
|
* `repertory -s3 --name '<my config name>' -set S3Config.SecretKey '<my secret key>'`
|
||||||
|
* For Sia and most local S3 gateway instances, enable path style URL's:
|
||||||
|
* `repertory -s3 --name '<my config name>' -set S3Config.UsePathStyle true`
|
||||||
|
|
||||||
|
* Optional steps:
|
||||||
|
* Set an appropriate region. Default is set to `any`:
|
||||||
|
* `repertory -s3 --name '<my config name>' -set S3Config.Region '<my region>'`
|
||||||
|
* Enable encrypted file names and file data. Set a strong, random encryption token and be sure to store it in a secure backup location:
|
||||||
|
* `repertory -s3 --name '<my config name>' -set S3Config.EncryptionToken '<my strong password>'`
|
||||||
|
|
||||||
|
* To verify/view all configuration options:
|
||||||
|
* `repertory -s3 --name '<my config name>' -dc`
|
||||||
|
* Example:
|
||||||
|
* `repertory -s3 --name minio -dc`
|
||||||
|
|
||||||
|
#### S3 Mounting
|
||||||
|
|
||||||
|
* Linux:
|
||||||
|
* `repertory -s3 --name '<my config name>' /mnt/location`
|
||||||
|
* Example:
|
||||||
|
* `repertory -s3 --name minio /mnt/location`
|
||||||
|
|
||||||
|
* Windows:
|
||||||
|
* `repertory -s3 --name '<my config name>' t:`
|
||||||
|
* Example:
|
||||||
|
* `repertory -s3 --name minio t:`
|
||||||
|
|
||||||
|
#### S3 Configuration File
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ApiAuth": "<random generated rpc password>",
|
||||||
|
"ApiPort": 10100,
|
||||||
|
"ApiUser": "repertory",
|
||||||
|
"DatabaseType": "rocksdb",
|
||||||
|
"DownloadTimeoutSeconds": 30,
|
||||||
|
"EnableDownloadTimeout": true,
|
||||||
|
"EnableDriveEvents": false,
|
||||||
|
"EventLevel": "info",
|
||||||
|
"EvictionDelayMinutes": 1,
|
||||||
|
"EvictionUseAccessedTime": false,
|
||||||
|
"HighFreqIntervalSeconds": 30,
|
||||||
|
"LowFreqIntervalSeconds": 3600,
|
||||||
|
"MaxCacheSizeBytes": 21474836480,
|
||||||
|
"MaxUploadCount": 5,
|
||||||
|
"MedFreqIntervalSeconds": 120,
|
||||||
|
"OnlineCheckRetrySeconds": 60,
|
||||||
|
"PreferredDownloadType": "default",
|
||||||
|
"RemoteMount": {
|
||||||
|
"ApiPort": 20100,
|
||||||
|
"ClientPoolSize": 20,
|
||||||
|
"Enable": false,
|
||||||
|
"EncryptionToken": ""
|
||||||
|
},
|
||||||
|
"RetryReadCount": 6,
|
||||||
|
"RingBufferFileSize": 512,
|
||||||
|
"S3Config": {
|
||||||
|
"AccessKey": "<my access key>",
|
||||||
|
"Bucket": "<my bucket name>",
|
||||||
|
"EncryptionToken": "",
|
||||||
|
"Region": "any",
|
||||||
|
"SecretKey": "<my secret key>",
|
||||||
|
"TimeoutMs": 60000,
|
||||||
|
"URL": "http://localhost:9000",
|
||||||
|
"UsePathStyle": true,
|
||||||
|
"UseRegionInURL": false
|
||||||
|
},
|
||||||
|
"TaskWaitMs": 100,
|
||||||
|
"Version": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Data Directories
|
### 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
|
||||||
|
{
|
||||||
|
"ApiAuth": "<random generated rpc password>",
|
||||||
|
"ApiPort": 10010,
|
||||||
|
"ApiUser": "repertory",
|
||||||
|
"EnableDriveEvents": false,
|
||||||
|
"EventLevel": "info",
|
||||||
|
"RemoteConfig": {
|
||||||
|
"ApiPort": 20000,
|
||||||
|
"EncryptionToken": "<my secure password>",
|
||||||
|
"HostNameOrIp": "192.168.1.10",
|
||||||
|
"MaxConnections": 20,
|
||||||
|
"ReceiveTimeoutMs": 120000,
|
||||||
|
"SendTimeoutMs": 30000
|
||||||
|
},
|
||||||
|
"TaskWaitMs": 100,
|
||||||
|
"Version": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Compiling
|
## 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(BOOST_HASH f55c340aa49763b1925ccf02b2e83f35fdcf634c9d5164a2acb87540173c741d)
|
set(BOOST_HASH f55c340aa49763b1925ccf02b2e83f35fdcf634c9d5164a2acb87540173c741d)
|
||||||
set(CPP_HTTPLIB_HASH 405abd8170f2a446fc8612ac635d0db5947c0d2e156e32603403a4496255ff00)
|
set(BOOST2_HASH 7bd7ddceec1a1dfdcbdb3e609b60d01739c38390a5f956385a12f3122049f0ca)
|
||||||
set(CURL_HASH 5a231145114589491fc52da118f9c7ef8abee885d1cb1ced99c7290e9a352f07)
|
set(CPP_HTTPLIB_HASH c9b9e0524666e1cd088f0874c57c1ce7c0eaa8552f9f4e15c755d5201fc8c608)
|
||||||
|
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
|
||||||
|
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
|
@ -679,6 +679,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 +715,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} \
|
||||||
|
@ -52,6 +52,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;
|
||||||
|
|
||||||
|
@ -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_auth().empty() || cfg.get_api_user().empty()) {
|
||||||
|
utils::error::raise_error(function_name,
|
||||||
|
"authorization user or password is not set");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto authorization = req.get_header_value("Authorization");
|
||||||
|
if (authorization.empty()) {
|
||||||
|
utils::error::raise_error(function_name,
|
||||||
|
"'Authorization' header is not set");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto auth_parts = utils::string::split(authorization, ' ', true);
|
||||||
|
if (auth_parts.empty()) {
|
||||||
|
utils::error::raise_error(function_name, "'Authorization' header is empty");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto auth_type = auth_parts[0U];
|
||||||
|
if (auth_type != "Basic") {
|
||||||
|
utils::error::raise_error(function_name,
|
||||||
|
"authorization type is not 'Basic'");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data = macaron::Base64::Decode(authorization.substr(6U));
|
||||||
|
auto auth_str = std::string(data.begin(), data.end());
|
||||||
|
|
||||||
|
auto auth = utils::string::split(auth_str, ':', false);
|
||||||
|
if (auth.size() < 2U) {
|
||||||
|
utils::error::raise_error(function_name, "authorization data is not valid");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto user = auth.at(0U);
|
||||||
|
auth.erase(auth.begin());
|
||||||
|
|
||||||
|
auto pwd = utils::string::join(auth, ':');
|
||||||
|
if ((user != cfg.get_api_user()) || (pwd != cfg.get_api_auth())) {
|
||||||
|
utils::error::raise_error(function_name, "authorization failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace repertory::rpc
|
||||||
|
|
||||||
|
#endif // REPERTORY_INCLUDE_RPC_COMMON_HPP_
|
@ -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,
|
||||||
|
@ -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,13 @@ 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;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
struct open_file_data final {
|
struct open_file_data final {
|
||||||
PVOID directory_buffer{nullptr};
|
PVOID directory_buffer{nullptr};
|
||||||
|
@ -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_
|
||||||
|
@ -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,6 +742,7 @@ auto app_config::default_remote_api_port(const provider_type &prov)
|
|||||||
};
|
};
|
||||||
return PROVIDER_REMOTE_PORTS.at(static_cast<std::size_t>(prov));
|
return PROVIDER_REMOTE_PORTS.at(static_cast<std::size_t>(prov));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto app_config::default_rpc_port(const provider_type &prov) -> std::uint16_t {
|
auto app_config::default_rpc_port(const provider_type &prov) -> std::uint16_t {
|
||||||
static const std::array<std::uint16_t,
|
static const std::array<std::uint16_t,
|
||||||
static_cast<std::size_t>(provider_type::unknown)>
|
static_cast<std::size_t>(provider_type::unknown)>
|
||||||
|
@ -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,6 +28,7 @@
|
|||||||
#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 "rpc/common.hpp"
|
||||||
#include "utils/base64.hpp"
|
#include "utils/base64.hpp"
|
||||||
#include "utils/error_utils.hpp"
|
#include "utils/error_utils.hpp"
|
||||||
#include "utils/string.hpp"
|
#include "utils/string.hpp"
|
||||||
@ -35,54 +36,6 @@
|
|||||||
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();
|
||||||
@ -173,7 +126,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
#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"
|
||||||
|
|
||||||
@ -191,4 +192,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
|
||||||
|
@ -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 {
|
||||||
|
@ -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},
|
||||||
};
|
};
|
||||||
|
@ -79,6 +79,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 "
|
||||||
|
65
repertory/repertory/include/cli/ui.hpp
Normal file
65
repertory/repertory/include/cli/ui.hpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2025> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef REPERTORY_INCLUDE_CLI_UI_HPP_
|
||||||
|
#define REPERTORY_INCLUDE_CLI_UI_HPP_
|
||||||
|
|
||||||
|
#include "types/repertory.hpp"
|
||||||
|
#include "ui/handlers.hpp"
|
||||||
|
#include "utils/cli_utils.hpp"
|
||||||
|
#include "utils/file.hpp"
|
||||||
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
|
namespace repertory::cli::actions {
|
||||||
|
[[nodiscard]] inline auto
|
||||||
|
ui(std::vector<const char *> args, const std::string & /*data_directory*/,
|
||||||
|
const provider_type & /* prov */, const std::string & /* unique_id */,
|
||||||
|
std::string /* user */, std::string /* password */) -> exit_code {
|
||||||
|
auto ui_port{default_ui_mgmt_port};
|
||||||
|
|
||||||
|
std::string data;
|
||||||
|
auto res = utils::cli::parse_string_option(
|
||||||
|
args, utils::cli::options::ui_port_option, data);
|
||||||
|
if (res == exit_code::success && not data.empty()) {
|
||||||
|
ui_port = utils::string::to_uint16(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not utils::file::change_to_process_directory()) {
|
||||||
|
return exit_code::ui_mount_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
httplib::Server server;
|
||||||
|
if (not server.set_mount_point("/ui", "./web")) {
|
||||||
|
return exit_code::ui_mount_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui::mgmt_app_config config{
|
||||||
|
.api_auth_ = "test",
|
||||||
|
.api_port_ = ui_port,
|
||||||
|
.api_user_ = "test",
|
||||||
|
};
|
||||||
|
ui::handlers handlers(&config, &server);
|
||||||
|
|
||||||
|
return exit_code::success;
|
||||||
|
}
|
||||||
|
} // namespace repertory::cli::actions
|
||||||
|
|
||||||
|
#endif // REPERTORY_INCLUDE_CLI_UI_HPP_
|
77
repertory/repertory/include/ui/handlers.hpp
Normal file
77
repertory/repertory/include/ui/handlers.hpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2025> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef REPERTORY_INCLUDE_UI_HANDLERS_HPP_
|
||||||
|
#define REPERTORY_INCLUDE_UI_HANDLERS_HPP_
|
||||||
|
|
||||||
|
#include "events/consumers/console_consumer.hpp"
|
||||||
|
|
||||||
|
namespace repertory::ui {
|
||||||
|
struct mgmt_app_config final {
|
||||||
|
std::string api_auth_{"test"};
|
||||||
|
std::uint16_t api_port_{default_ui_mgmt_port};
|
||||||
|
std::string api_user_{"test"};
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_api_auth() const -> std::string { return api_auth_; }
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_api_port() const -> std::uint16_t { return api_port_; }
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_api_user() const -> std::string { return api_user_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class handlers final {
|
||||||
|
public:
|
||||||
|
handlers(mgmt_app_config *config, httplib::Server *server);
|
||||||
|
|
||||||
|
handlers() = delete;
|
||||||
|
handlers(const handlers &) = delete;
|
||||||
|
handlers(handlers &&) = delete;
|
||||||
|
|
||||||
|
~handlers();
|
||||||
|
|
||||||
|
auto operator=(const handlers &) -> handlers & = delete;
|
||||||
|
auto operator=(handlers &&) -> handlers & = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
mgmt_app_config *config_;
|
||||||
|
httplib::Server *server_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
console_consumer console;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handle_get_mount(auto &&req, auto &&res) const;
|
||||||
|
|
||||||
|
void handle_get_mount_list(auto &&res) const;
|
||||||
|
|
||||||
|
void handle_get_mount_status(auto &&req, auto &&res) const;
|
||||||
|
|
||||||
|
void handle_post_mount(auto &&req, auto &&res) const;
|
||||||
|
|
||||||
|
void handle_put_set_value_by_name(auto &&req, auto &&res);
|
||||||
|
|
||||||
|
static auto read_process(provider_type prov, std::string_view name,
|
||||||
|
std::string_view command)
|
||||||
|
-> std::vector<std::string>;
|
||||||
|
};
|
||||||
|
} // namespace repertory::ui
|
||||||
|
|
||||||
|
#endif // REPERTORY_INCLUDE_UI_HANDLERS_HPP_
|
@ -146,10 +146,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);
|
||||||
|
284
repertory/repertory/src/ui/handlers.cpp
Normal file
284
repertory/repertory/src/ui/handlers.cpp
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
/*
|
||||||
|
Copyright <2018-2025> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "ui/handlers.hpp"
|
||||||
|
|
||||||
|
#include "app_config.hpp"
|
||||||
|
#include "events/event_system.hpp"
|
||||||
|
#include "rpc/common.hpp"
|
||||||
|
#include "types/repertory.hpp"
|
||||||
|
#include "utils/error_utils.hpp"
|
||||||
|
#include "utils/file.hpp"
|
||||||
|
#include "utils/path.hpp"
|
||||||
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
|
namespace repertory::ui {
|
||||||
|
handlers::handlers(mgmt_app_config *config, httplib::Server *server)
|
||||||
|
: config_(config), server_(server) {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
server_->set_pre_routing_handler(
|
||||||
|
[this](auto &&req, auto &&res) -> httplib::Server::HandlerResponse {
|
||||||
|
if (rpc::check_authorization(*config_, req)) {
|
||||||
|
return httplib::Server::HandlerResponse::Unhandled;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status = http_error_codes::unauthorized;
|
||||||
|
res.set_header(
|
||||||
|
"WWW-Authenticate",
|
||||||
|
R"(Basic realm="Repertory Management Portal", charset="UTF-8")");
|
||||||
|
return httplib::Server::HandlerResponse::Handled;
|
||||||
|
});
|
||||||
|
|
||||||
|
server_->set_exception_handler([](const httplib::Request &req,
|
||||||
|
httplib::Response &res,
|
||||||
|
std::exception_ptr ptr) {
|
||||||
|
json data{
|
||||||
|
{"path", req.path},
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::rethrow_exception(ptr);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
data["error"] = (e.what() == nullptr) ? "unknown error" : e.what();
|
||||||
|
utils::error::raise_error(function_name, e,
|
||||||
|
"failed request: " + req.path);
|
||||||
|
} catch (...) {
|
||||||
|
data["error"] = "unknown error";
|
||||||
|
utils::error::raise_error(function_name, "unknown error",
|
||||||
|
"failed request: " + req.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.set_content(data.dump(), "application/json");
|
||||||
|
res.status = http_error_codes::internal_error;
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Get("/api/v1/mount",
|
||||||
|
[this](auto &&req, auto &&res) { handle_get_mount(req, res); });
|
||||||
|
|
||||||
|
server->Get("/api/v1/mount_list", [this](auto && /* req */, auto &&res) {
|
||||||
|
handle_get_mount_list(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Get("/api/v1/mount_status",
|
||||||
|
[this](const httplib::Request &req, auto &&res) {
|
||||||
|
handle_get_mount_status(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
server->Post("/api/v1/mount",
|
||||||
|
[this](auto &&req, auto &&res) { handle_post_mount(req, res); });
|
||||||
|
|
||||||
|
server->Put("/api/v1/set_value_by_name", [this](auto &&req, auto &&res) {
|
||||||
|
handle_put_set_value_by_name(req, res);
|
||||||
|
});
|
||||||
|
|
||||||
|
event_system::instance().start();
|
||||||
|
|
||||||
|
static std::atomic<httplib::Server *> this_server{server_};
|
||||||
|
static const auto quit_handler = [](int /* sig */) {
|
||||||
|
auto *ptr = this_server.load();
|
||||||
|
if (ptr == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this_server = nullptr;
|
||||||
|
ptr->stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
std::signal(SIGINT, quit_handler);
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
std::signal(SIGQUIT, quit_handler);
|
||||||
|
#endif // !defined(_WIN32)
|
||||||
|
std::signal(SIGTERM, quit_handler);
|
||||||
|
|
||||||
|
server_->listen("127.0.0.1", config_->get_api_port());
|
||||||
|
this_server = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers::~handlers() { event_system::instance().stop(); }
|
||||||
|
|
||||||
|
void handlers::handle_get_mount(auto &&req, auto &&res) const {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto prov = provider_type_from_string(req.get_param_value("type"));
|
||||||
|
|
||||||
|
auto lines = handlers::read_process(prov, req.get_param_value("name"), "-dc");
|
||||||
|
|
||||||
|
if (lines.at(0U) != "0") {
|
||||||
|
throw utils::error::create_exception(function_name, {
|
||||||
|
"command failed",
|
||||||
|
lines.at(0U),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.erase(lines.begin());
|
||||||
|
|
||||||
|
auto result = nlohmann::json::parse(utils::string::join(lines, '\n'));
|
||||||
|
res.set_content(result.dump(), "application/json");
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_get_mount_list(auto &&res) const {
|
||||||
|
auto data_dir = utils::file::directory{app_config::get_root_data_directory()};
|
||||||
|
|
||||||
|
nlohmann::json result;
|
||||||
|
|
||||||
|
auto encrypt_dir = data_dir.get_directory("encrypt");
|
||||||
|
if (encrypt_dir && encrypt_dir->get_file("config.json")) {
|
||||||
|
result["encrypt"].emplace_back("encrypt");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto process_dir = [&data_dir, &result](std::string_view name) {
|
||||||
|
auto name_dir = data_dir.get_directory(name);
|
||||||
|
if (not name_dir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &dir : name_dir->get_directories()) {
|
||||||
|
if (not dir->get_file("config.json")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result[name].emplace_back(
|
||||||
|
utils::path::strip_to_file_name(dir->get_path()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
process_dir("remote");
|
||||||
|
process_dir("s3");
|
||||||
|
process_dir("sia");
|
||||||
|
|
||||||
|
res.set_content(result.dump(), "application/json");
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_get_mount_status(auto &&req, auto &&res) const {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
auto type = req.get_param_value("type");
|
||||||
|
auto prov = provider_type_from_string(type);
|
||||||
|
auto status_name = app_config::get_provider_display_name(prov);
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
|
|
||||||
|
switch (prov) {
|
||||||
|
case provider_type::encrypt:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::remote: {
|
||||||
|
auto parts = utils::string::split(name, '_', false);
|
||||||
|
status_name = fmt::format("{}{}:{}", status_name, parts[0U], parts[1U]);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case provider_type::sia:
|
||||||
|
case provider_type::s3:
|
||||||
|
status_name = fmt::format("{}{}", status_name, name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw utils::error::create_exception(
|
||||||
|
function_name, {
|
||||||
|
fmt::format("`{}` is not supported", name),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lines = handlers::read_process(prov, name, "-status");
|
||||||
|
|
||||||
|
auto result =
|
||||||
|
nlohmann::json::parse(utils::string::join(lines, '\n')).at(status_name);
|
||||||
|
res.set_content(result.dump(), "application/json");
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_post_mount(auto &&req, auto &&res) const {
|
||||||
|
auto type = req.get_param_value("type");
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
|
auto unmount = utils::string::to_bool(req.get_param_value("unmount"));
|
||||||
|
auto prov = provider_type_from_string(type);
|
||||||
|
|
||||||
|
if (unmount) {
|
||||||
|
read_process(prov, name, "-unmount");
|
||||||
|
}
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlers::handle_put_set_value_by_name(auto &&req, auto &&res) {
|
||||||
|
auto type = req.get_param_value("type");
|
||||||
|
auto name = req.get_param_value("name");
|
||||||
|
auto prov = provider_type_from_string(type);
|
||||||
|
|
||||||
|
auto key = req.get_param_value("key");
|
||||||
|
auto value = req.get_param_value("value");
|
||||||
|
|
||||||
|
read_process(prov, name, fmt::format("-set {} \'{}\'", key, value));
|
||||||
|
res.status = http_error_codes::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto handlers::read_process(provider_type prov, std::string_view name,
|
||||||
|
std::string_view command)
|
||||||
|
-> std::vector<std::string> {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
std::string str_type;
|
||||||
|
switch (prov) {
|
||||||
|
case provider_type::encrypt:
|
||||||
|
str_type = "-en";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::remote: {
|
||||||
|
auto parts = utils::string::split(name, '_', false);
|
||||||
|
str_type = fmt::format("-rm {}:{}", parts[0U], parts[1U]);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case provider_type::s3:
|
||||||
|
str_type = fmt::format("-s3 -na {}", name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case provider_type::sia:
|
||||||
|
str_type = fmt::format("-na {}", name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw utils::error::create_exception(
|
||||||
|
function_name, {
|
||||||
|
fmt::format("`{}` is not supported", name),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cmd_line = fmt::format("repertory {} {}", str_type, command);
|
||||||
|
|
||||||
|
auto *pipe = popen(cmd_line.c_str(), "r");
|
||||||
|
if (pipe == nullptr) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string data;
|
||||||
|
std::array<char, 1024U> buffer{};
|
||||||
|
while (feof(pipe) == 0) {
|
||||||
|
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
|
||||||
|
data += buffer.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pclose(pipe);
|
||||||
|
|
||||||
|
return utils::string::split(utils::string::replace(data, "\r", ""), '\n',
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
} // namespace repertory::ui
|
@ -38,14 +38,16 @@ 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}" == "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/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
vendored
Normal file
BIN
support/3rd_party/cpp-httplib-0.19.0.tar.gz
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
vendored
Normal file
BIN
support/3rd_party/curl-8.12.1.tar.gz
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.16.0.tar.gz
vendored
Normal file
BIN
support/3rd_party/googletest-1.16.0.tar.gz
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
|
@ -1 +0,0 @@
|
|||||||
e15dda82fe2fe8139dc2ac21a36d4ca01d5313c75f99f46c4e8a27709b7294bf *openssl-3.4.0.tar.gz
|
|
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
vendored
Normal file
BIN
support/3rd_party/pugixml-1.15.tar.gz
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
|
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
|
@ -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
vendored
Normal file
BIN
support/3rd_party/spdlog-1.15.1.tar.gz
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
vendored
Normal file
BIN
support/3rd_party/sqlite-amalgamation-3490100.zip
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
|
@ -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_
|
||||||
|
@ -47,82 +47,4 @@ auto create_exception(std::string_view function_name,
|
|||||||
return std::runtime_error(create_error_message(function_name, items));
|
return std::runtime_error(create_error_message(function_name, items));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
|
||||||
void handle_debug(std::string_view function_name, std::string_view msg) {
|
|
||||||
const i_exception_handler *handler{exception_handler};
|
|
||||||
if (handler != nullptr) {
|
|
||||||
handler->handle_debug(function_name, msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default_exception_handler.handle_debug(function_name, msg);
|
|
||||||
}
|
|
||||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
|
||||||
|
|
||||||
void handle_error(std::string_view function_name, std::string_view msg) {
|
|
||||||
const i_exception_handler *handler{exception_handler};
|
|
||||||
if (handler != nullptr) {
|
|
||||||
handler->handle_error(function_name, msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default_exception_handler.handle_error(function_name, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_exception(std::string_view function_name) {
|
|
||||||
const i_exception_handler *handler{exception_handler};
|
|
||||||
if (handler != nullptr) {
|
|
||||||
handler->handle_exception(function_name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default_exception_handler.handle_exception(function_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_exception(std::string_view function_name,
|
|
||||||
const std::exception &ex) {
|
|
||||||
const i_exception_handler *handler{exception_handler};
|
|
||||||
if (handler != nullptr) {
|
|
||||||
handler->handle_exception(function_name, ex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default_exception_handler.handle_exception(function_name, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
|
||||||
void handle_info(std::string_view function_name, std::string_view msg) {
|
|
||||||
const i_exception_handler *handler{exception_handler};
|
|
||||||
if (handler != nullptr) {
|
|
||||||
handler->handle_info(function_name, msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default_exception_handler.handle_info(function_name, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_trace(std::string_view function_name, std::string_view msg) {
|
|
||||||
const i_exception_handler *handler{exception_handler};
|
|
||||||
if (handler != nullptr) {
|
|
||||||
handler->handle_trace(function_name, msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default_exception_handler.handle_trace(function_name, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_warn(std::string_view function_name, std::string_view msg) {
|
|
||||||
const i_exception_handler *handler{exception_handler};
|
|
||||||
if (handler != nullptr) {
|
|
||||||
handler->handle_warn(function_name, msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default_exception_handler.handle_warn(function_name, msg);
|
|
||||||
}
|
|
||||||
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
|
||||||
|
|
||||||
void set_exception_handler(const i_exception_handler *handler) {
|
|
||||||
exception_handler = handler;
|
|
||||||
}
|
|
||||||
} // namespace repertory::utils::error
|
} // namespace repertory::utils::error
|
||||||
|
@ -19,12 +19,15 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include "utils/config.hpp"
|
|
||||||
#include "utils/error.hpp"
|
#include "utils/error.hpp"
|
||||||
|
|
||||||
|
#include "utils/config.hpp"
|
||||||
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
namespace repertory::utils::error {
|
namespace repertory::utils::error {
|
||||||
std::atomic<const i_exception_handler *> exception_handler{
|
std::atomic<const i_exception_handler *> exception_handler{
|
||||||
&default_exception_handler};
|
&default_exception_handler,
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||||
void iostream_exception_handler::handle_debug(std::string_view function_name,
|
void iostream_exception_handler::handle_debug(std::string_view function_name,
|
||||||
@ -238,4 +241,83 @@ void spdlog_exception_handler::handle_warn(std::string_view function_name,
|
|||||||
file->warn(utils::error::create_error_message(function_name, {msg}));
|
file->warn(utils::error::create_error_message(function_name, {msg}));
|
||||||
}
|
}
|
||||||
#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
#endif // defined(PROJECT_ENABLE_SPDLOG) && defined(PROJECT_ENABLE_V2_ERRORS)
|
||||||
|
|
||||||
|
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||||
|
void handle_debug(std::string_view function_name, std::string_view msg) {
|
||||||
|
const i_exception_handler *handler{exception_handler};
|
||||||
|
if (handler != nullptr) {
|
||||||
|
handler->handle_debug(function_name, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default_exception_handler.handle_debug(function_name, msg);
|
||||||
|
}
|
||||||
|
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||||
|
|
||||||
|
void handle_error(std::string_view function_name, std::string_view msg) {
|
||||||
|
const i_exception_handler *handler{exception_handler};
|
||||||
|
if (handler != nullptr) {
|
||||||
|
handler->handle_error(function_name, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default_exception_handler.handle_error(function_name, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_exception(std::string_view function_name) {
|
||||||
|
const i_exception_handler *handler{exception_handler};
|
||||||
|
if (handler != nullptr) {
|
||||||
|
handler->handle_exception(function_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default_exception_handler.handle_exception(function_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_exception(std::string_view function_name,
|
||||||
|
const std::exception &ex) {
|
||||||
|
const i_exception_handler *handler{exception_handler};
|
||||||
|
if (handler != nullptr) {
|
||||||
|
handler->handle_exception(function_name, ex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default_exception_handler.handle_exception(function_name, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(PROJECT_ENABLE_V2_ERRORS)
|
||||||
|
void handle_info(std::string_view function_name, std::string_view msg) {
|
||||||
|
const i_exception_handler *handler{exception_handler};
|
||||||
|
if (handler != nullptr) {
|
||||||
|
handler->handle_info(function_name, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default_exception_handler.handle_info(function_name, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_trace(std::string_view function_name, std::string_view msg) {
|
||||||
|
const i_exception_handler *handler{exception_handler};
|
||||||
|
if (handler != nullptr) {
|
||||||
|
handler->handle_trace(function_name, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default_exception_handler.handle_trace(function_name, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_warn(std::string_view function_name, std::string_view msg) {
|
||||||
|
const i_exception_handler *handler{exception_handler};
|
||||||
|
if (handler != nullptr) {
|
||||||
|
handler->handle_warn(function_name, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default_exception_handler.handle_warn(function_name, msg);
|
||||||
|
}
|
||||||
|
#endif // defined(PROJECT_ENABLE_V2_ERRORS)
|
||||||
|
|
||||||
|
void set_exception_handler(const i_exception_handler *handler) {
|
||||||
|
exception_handler = handler;
|
||||||
|
}
|
||||||
} // namespace repertory::utils::error
|
} // namespace repertory::utils::error
|
||||||
|
3
web/repertory/.cspell/words.txt
Normal file
3
web/repertory/.cspell/words.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
cupertino
|
||||||
|
cupertinoicons
|
||||||
|
onetwothree
|
47
web/repertory/.gitignore
vendored
Normal file
47
web/repertory/.gitignore
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.build/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
.swiftpm/
|
||||||
|
migrate_working_dir/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# Symbolication related
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Obfuscation related
|
||||||
|
app.*.map.json
|
||||||
|
|
||||||
|
# Android Studio will place build artifacts here
|
||||||
|
/android/app/debug
|
||||||
|
/android/app/profile
|
||||||
|
/android/app/release
|
||||||
|
.flutter-companion
|
||||||
|
pubspec.lock
|
30
web/repertory/.metadata
Normal file
30
web/repertory/.metadata
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# This file tracks properties of this Flutter project.
|
||||||
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
|
#
|
||||||
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
|
version:
|
||||||
|
revision: "35c388afb57ef061d06a39b537336c87e0e3d1b1"
|
||||||
|
channel: "stable"
|
||||||
|
|
||||||
|
project_type: app
|
||||||
|
|
||||||
|
# Tracks metadata for the flutter migrate command
|
||||||
|
migration:
|
||||||
|
platforms:
|
||||||
|
- platform: root
|
||||||
|
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
|
||||||
|
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
|
||||||
|
- platform: web
|
||||||
|
create_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
|
||||||
|
base_revision: 35c388afb57ef061d06a39b537336c87e0e3d1b1
|
||||||
|
|
||||||
|
# User provided section
|
||||||
|
|
||||||
|
# List of Local paths (relative to this file) that should be
|
||||||
|
# ignored by the migrate tool.
|
||||||
|
#
|
||||||
|
# Files that are not part of the templates will be ignored by default.
|
||||||
|
unmanaged_files:
|
||||||
|
- 'lib/main.dart'
|
||||||
|
- 'ios/Runner.xcodeproj/project.pbxproj'
|
16
web/repertory/README.md
Normal file
16
web/repertory/README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# repertory
|
||||||
|
|
||||||
|
A new Flutter project.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This project is a starting point for a Flutter application.
|
||||||
|
|
||||||
|
A few resources to get you started if this is your first Flutter project:
|
||||||
|
|
||||||
|
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||||
|
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||||
|
|
||||||
|
For help getting started with Flutter development, view the
|
||||||
|
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||||
|
samples, guidance on mobile development, and a full API reference.
|
28
web/repertory/analysis_options.yaml
Normal file
28
web/repertory/analysis_options.yaml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# This file configures the analyzer, which statically analyzes Dart code to
|
||||||
|
# check for errors, warnings, and lints.
|
||||||
|
#
|
||||||
|
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||||
|
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||||
|
# invoked from the command line by running `flutter analyze`.
|
||||||
|
|
||||||
|
# The following line activates a set of recommended lints for Flutter apps,
|
||||||
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
linter:
|
||||||
|
# The lint rules applied to this project can be customized in the
|
||||||
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
|
# included above or to enable additional rules. A list of all available lints
|
||||||
|
# and their documentation is published at https://dart.dev/lints.
|
||||||
|
#
|
||||||
|
# Instead of disabling a lint rule for the entire project in the
|
||||||
|
# section below, it can also be suppressed for a single line of code
|
||||||
|
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||||
|
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||||
|
# producing the lint.
|
||||||
|
rules:
|
||||||
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
|
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
1
web/repertory/lib/constants.dart
Normal file
1
web/repertory/lib/constants.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
const String appTitle = "Repertory Management Portal";
|
6
web/repertory/lib/errors/duplicate_mount_exception.dart
Normal file
6
web/repertory/lib/errors/duplicate_mount_exception.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class DuplicateMountException implements Exception {
|
||||||
|
final String _name;
|
||||||
|
const DuplicateMountException({required name}) : _name = name, super();
|
||||||
|
|
||||||
|
String get name => _name;
|
||||||
|
}
|
18
web/repertory/lib/helpers.dart
Normal file
18
web/repertory/lib/helpers.dart
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
String formatMountName(String type, String name) {
|
||||||
|
if (type == "remote") {
|
||||||
|
return name.replaceAll("_", ":");
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
String initialCaps(String txt) {
|
||||||
|
if (txt.isEmpty) {
|
||||||
|
return txt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (txt.length == 1) {
|
||||||
|
return txt[0].toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
return txt[0].toUpperCase() + txt.substring(1).toLowerCase();
|
||||||
|
}
|
90
web/repertory/lib/main.dart
Normal file
90
web/repertory/lib/main.dart
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:repertory/constants.dart' as constants;
|
||||||
|
import 'package:repertory/helpers.dart';
|
||||||
|
import 'package:repertory/models/mount.dart';
|
||||||
|
import 'package:repertory/models/mount_list.dart';
|
||||||
|
import 'package:repertory/widgets/mount_list_widget.dart';
|
||||||
|
import 'package:repertory/widgets/mount_settings.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
runApp(const MyApp());
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyApp extends StatelessWidget {
|
||||||
|
const MyApp({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
title: constants.appTitle,
|
||||||
|
theme: ThemeData(
|
||||||
|
brightness: Brightness.light,
|
||||||
|
colorScheme: ColorScheme.fromSeed(
|
||||||
|
seedColor: Colors.deepOrange,
|
||||||
|
brightness: Brightness.light,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
themeMode: ThemeMode.dark,
|
||||||
|
darkTheme: ThemeData(
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
colorScheme: ColorScheme.fromSeed(
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
seedColor: Colors.deepOrange,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
initialRoute: '/',
|
||||||
|
routes: {'/': (context) => const MyHomePage(title: constants.appTitle)},
|
||||||
|
onGenerateRoute: (settings) {
|
||||||
|
if (settings.name != '/settings') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final mount = settings.arguments as Mount;
|
||||||
|
return MaterialPageRoute(
|
||||||
|
builder: (context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||||
|
title: Text(
|
||||||
|
'${initialCaps(mount.type)} [${formatMountName(mount.type, mount.name)}] Settings',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: MountSettingsWidget(mount: mount),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyHomePage extends StatefulWidget {
|
||||||
|
final String title;
|
||||||
|
const MyHomePage({super.key, required this.title});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MyHomePage> createState() => _MyHomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||||
|
leading: const Icon(Icons.storage),
|
||||||
|
title: Text(widget.title),
|
||||||
|
),
|
||||||
|
body: ChangeNotifierProvider(
|
||||||
|
create: (context) => MountList(),
|
||||||
|
child: MountListWidget(),
|
||||||
|
),
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
onPressed: () {},
|
||||||
|
tooltip: 'Add',
|
||||||
|
child: const Icon(Icons.add),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
79
web/repertory/lib/models/mount.dart
Normal file
79
web/repertory/lib/models/mount.dart
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:repertory/types/mount_config.dart';
|
||||||
|
|
||||||
|
class Mount with ChangeNotifier {
|
||||||
|
final MountConfig mountConfig;
|
||||||
|
Mount(this.mountConfig) {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
String get name => mountConfig.name;
|
||||||
|
String get path => mountConfig.path;
|
||||||
|
IconData get state => mountConfig.state;
|
||||||
|
String get type => mountConfig.type;
|
||||||
|
|
||||||
|
Future<void> _fetch() async {
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse(
|
||||||
|
Uri.encodeFull('${Uri.base.origin}/api/v1/mount?name=$name&type=$type'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mountConfig.updateSettings(jsonDecode(response.body));
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _fetchStatus() async {
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse(
|
||||||
|
Uri.encodeFull(
|
||||||
|
'${Uri.base.origin}/api/v1/mount_status?name=$name&type=$type',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mountConfig.updateStatus(jsonDecode(response.body));
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> mount(bool unmount) async {
|
||||||
|
await http.post(
|
||||||
|
Uri.parse(
|
||||||
|
Uri.encodeFull(
|
||||||
|
'${Uri.base.origin}/api/v1/mount?unmount=$unmount&name=$name&type=$type',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> refresh() async {
|
||||||
|
await _fetch();
|
||||||
|
return _fetchStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setValue(String key, String value) async {
|
||||||
|
await http.put(
|
||||||
|
Uri.parse(
|
||||||
|
Uri.encodeFull(
|
||||||
|
'${Uri.base.origin}/api/v1/set_value_by_name?name=$name&type=$type&key=$key&value=$value',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return refresh();
|
||||||
|
}
|
||||||
|
}
|
67
web/repertory/lib/models/mount_list.dart
Normal file
67
web/repertory/lib/models/mount_list.dart
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:repertory/errors/duplicate_mount_exception.dart';
|
||||||
|
import 'package:repertory/types/mount_config.dart';
|
||||||
|
|
||||||
|
class MountList with ChangeNotifier {
|
||||||
|
MountList() {
|
||||||
|
_fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MountConfig> _mountList = [];
|
||||||
|
|
||||||
|
UnmodifiableListView get items => UnmodifiableListView(_mountList);
|
||||||
|
|
||||||
|
Future<void> _fetch() async {
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse('${Uri.base.origin}/api/v1/mount_list'),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
List<MountConfig> nextList = [];
|
||||||
|
|
||||||
|
jsonDecode(response.body).forEach((key, value) {
|
||||||
|
nextList.addAll(
|
||||||
|
value.map((name) => MountConfig.fromJson(key, name)).toList(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
_sort(nextList);
|
||||||
|
_mountList = nextList;
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _sort(list) {
|
||||||
|
list.sort((a, b) {
|
||||||
|
final res = a.type.compareTo(b.type);
|
||||||
|
if (res != 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.name.compareTo(b.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(MountConfig config) {
|
||||||
|
var item = _mountList.firstWhereOrNull((cfg) => cfg.name == config.name);
|
||||||
|
if (item != null) {
|
||||||
|
throw DuplicateMountException(name: config.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
_mountList.add(config);
|
||||||
|
_sort(_mountList);
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(String name) {
|
||||||
|
_mountList.removeWhere((item) => item.name == name);
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
31
web/repertory/lib/types/mount_config.dart
Normal file
31
web/repertory/lib/types/mount_config.dart
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class MountConfig {
|
||||||
|
final String _name;
|
||||||
|
String _path = "";
|
||||||
|
Map<String, dynamic> _settings = {};
|
||||||
|
IconData _state = Icons.toggle_off;
|
||||||
|
final String _type;
|
||||||
|
MountConfig({required name, required type}) : _name = name, _type = type;
|
||||||
|
|
||||||
|
String get name => _name;
|
||||||
|
String get path => _path;
|
||||||
|
UnmodifiableMapView<String, dynamic> get settings =>
|
||||||
|
UnmodifiableMapView<String, dynamic>(_settings);
|
||||||
|
IconData get state => _state;
|
||||||
|
String get type => _type;
|
||||||
|
|
||||||
|
factory MountConfig.fromJson(String type, String name) {
|
||||||
|
return MountConfig(name: name, type: type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateSettings(Map<String, dynamic> settings) {
|
||||||
|
_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateStatus(Map<String, dynamic> status) {
|
||||||
|
_path = status["Location"] as String;
|
||||||
|
_state = status["Active"] as bool ? Icons.toggle_on : Icons.toggle_off;
|
||||||
|
}
|
||||||
|
}
|
31
web/repertory/lib/widgets/mount_list_widget.dart
Normal file
31
web/repertory/lib/widgets/mount_list_widget.dart
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:repertory/models/mount.dart';
|
||||||
|
import 'package:repertory/models/mount_list.dart';
|
||||||
|
import 'package:repertory/widgets/mount_widget.dart';
|
||||||
|
|
||||||
|
class MountListWidget extends StatefulWidget {
|
||||||
|
const MountListWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MountListWidget> createState() => _MountListWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MountListWidgetState extends State<MountListWidget> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Consumer<MountList>(
|
||||||
|
builder: (context, mountList, widget) {
|
||||||
|
return ListView.builder(
|
||||||
|
itemBuilder: (context, idx) {
|
||||||
|
return ChangeNotifierProvider(
|
||||||
|
create: (context) => Mount(mountList.items[idx]),
|
||||||
|
child: const MountWidget(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: mountList.items.length,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
568
web/repertory/lib/widgets/mount_settings.dart
Normal file
568
web/repertory/lib/widgets/mount_settings.dart
Normal file
@ -0,0 +1,568 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:repertory/models/mount.dart';
|
||||||
|
import 'package:settings_ui/settings_ui.dart';
|
||||||
|
|
||||||
|
class MountSettingsWidget extends StatefulWidget {
|
||||||
|
final Mount mount;
|
||||||
|
const MountSettingsWidget({super.key, required this.mount});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MountSettingsWidget> createState() => _MountSettingsWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MountSettingsWidgetState extends State<MountSettingsWidget> {
|
||||||
|
Map<String, dynamic> _settings = {};
|
||||||
|
|
||||||
|
void _addBooleanSetting(list, root, key, value) {
|
||||||
|
list.add(
|
||||||
|
SettingsTile.switchTile(
|
||||||
|
leading: Icon(Icons.quiz),
|
||||||
|
title: Text(key),
|
||||||
|
initialValue: (value as bool),
|
||||||
|
onPressed: (_) {
|
||||||
|
setState(() {
|
||||||
|
root[key] = !value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onToggle: (bool nextValue) {
|
||||||
|
setState(() {
|
||||||
|
root[key] = nextValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addIntSetting(list, root, key, value) {
|
||||||
|
list.add(
|
||||||
|
SettingsTile.navigation(
|
||||||
|
leading: Icon(Icons.onetwothree),
|
||||||
|
title: Text(key),
|
||||||
|
value: Text(value.toString()),
|
||||||
|
onPressed: (_) {
|
||||||
|
String updatedValue = value.toString();
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
child: Text('Cancel'),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: Text('OK'),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
root[key] = int.parse(updatedValue);
|
||||||
|
});
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
content: TextField(
|
||||||
|
autofocus: true,
|
||||||
|
controller: TextEditingController(text: updatedValue),
|
||||||
|
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
onChanged: (nextValue) {
|
||||||
|
updatedValue = nextValue;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
title: Text(key),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addIntListSetting(
|
||||||
|
list,
|
||||||
|
root,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
List<String> valueList,
|
||||||
|
defaultValue,
|
||||||
|
icon,
|
||||||
|
) {
|
||||||
|
list.add(
|
||||||
|
SettingsTile.navigation(
|
||||||
|
title: Text(key),
|
||||||
|
leading: Icon(icon),
|
||||||
|
value: DropdownButton<String>(
|
||||||
|
value: value.toString(),
|
||||||
|
onChanged: (newValue) {
|
||||||
|
setState(() {
|
||||||
|
root[key] = int.parse(newValue ?? defaultValue.toString());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
items:
|
||||||
|
valueList.map<DropdownMenuItem<String>>((item) {
|
||||||
|
return DropdownMenuItem<String>(value: item, child: Text(item));
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addListSetting(list, root, key, value, List<String> valueList, icon) {
|
||||||
|
list.add(
|
||||||
|
SettingsTile.navigation(
|
||||||
|
title: Text(key),
|
||||||
|
leading: Icon(icon),
|
||||||
|
value: DropdownButton<String>(
|
||||||
|
value: value,
|
||||||
|
onChanged: (newValue) {
|
||||||
|
setState(() {
|
||||||
|
root[key] = newValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
items:
|
||||||
|
valueList.map<DropdownMenuItem<String>>((item) {
|
||||||
|
return DropdownMenuItem<String>(value: item, child: Text(item));
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addPasswordSetting(list, root, key, value) {
|
||||||
|
list.add(
|
||||||
|
SettingsTile.navigation(
|
||||||
|
leading: Icon(Icons.password),
|
||||||
|
title: Text(key),
|
||||||
|
value: Text('*' * (value as String).length),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addStringSetting(list, root, key, value, icon) {
|
||||||
|
list.add(
|
||||||
|
SettingsTile.navigation(
|
||||||
|
leading: Icon(icon),
|
||||||
|
title: Text(key),
|
||||||
|
value: Text(value),
|
||||||
|
onPressed: (_) {
|
||||||
|
String updatedValue = value;
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
child: Text('Cancel'),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: Text('OK'),
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
root[key] = updatedValue;
|
||||||
|
});
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
content: TextField(
|
||||||
|
autofocus: true,
|
||||||
|
controller: TextEditingController(text: updatedValue),
|
||||||
|
onChanged: (value) {
|
||||||
|
updatedValue = value;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
title: Text(key),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<SettingsTile> commonSettings = [];
|
||||||
|
List<SettingsTile> encryptConfigSettings = [];
|
||||||
|
List<SettingsTile> hostConfigSettings = [];
|
||||||
|
List<SettingsTile> remoteConfigSettings = [];
|
||||||
|
List<SettingsTile> remoteMountSettings = [];
|
||||||
|
List<SettingsTile> s3ConfigSettings = [];
|
||||||
|
List<SettingsTile> siaConfigSettings = [];
|
||||||
|
|
||||||
|
_settings.forEach((key, value) {
|
||||||
|
if (key == "ApiAuth") {
|
||||||
|
_addPasswordSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "ApiPort") {
|
||||||
|
_addIntSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "ApiUser") {
|
||||||
|
_addStringSetting(commonSettings, _settings, key, value, Icons.person);
|
||||||
|
} else if (key == "DatabaseType") {
|
||||||
|
_addListSetting(commonSettings, _settings, key, value, [
|
||||||
|
"rocksdb",
|
||||||
|
"sqlite",
|
||||||
|
], Icons.dataset);
|
||||||
|
} else if (key == "DownloadTimeoutSeconds") {
|
||||||
|
_addIntSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "EnableDownloadTimeout") {
|
||||||
|
_addBooleanSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "EnableDriveEvents") {
|
||||||
|
_addBooleanSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "EventLevel") {
|
||||||
|
_addListSetting(commonSettings, _settings, key, value, [
|
||||||
|
"critical",
|
||||||
|
"error",
|
||||||
|
"warn",
|
||||||
|
"info",
|
||||||
|
"debug",
|
||||||
|
"trace",
|
||||||
|
], Icons.event);
|
||||||
|
} else if (key == "EvictionDelayMinutes") {
|
||||||
|
_addIntSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "EvictionUseAccessedTime") {
|
||||||
|
_addBooleanSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "MaxCacheSizeBytes") {
|
||||||
|
_addIntSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "MaxUploadCount") {
|
||||||
|
_addIntSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "OnlineCheckRetrySeconds") {
|
||||||
|
_addIntSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "PreferredDownloadType") {
|
||||||
|
_addListSetting(commonSettings, _settings, key, value, [
|
||||||
|
"default",
|
||||||
|
"direct",
|
||||||
|
"ring_buffer",
|
||||||
|
], Icons.download);
|
||||||
|
} else if (key == "RetryReadCount") {
|
||||||
|
_addIntSetting(commonSettings, _settings, key, value);
|
||||||
|
} else if (key == "RingBufferFileSize") {
|
||||||
|
_addIntListSetting(
|
||||||
|
commonSettings,
|
||||||
|
_settings,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
["128", "256", "512", "1024", "2048"],
|
||||||
|
512,
|
||||||
|
Icons.animation,
|
||||||
|
);
|
||||||
|
} else if (key == "EncryptConfig") {
|
||||||
|
value.forEach((subKey, subValue) {
|
||||||
|
if (subKey == "EncryptionToken") {
|
||||||
|
_addPasswordSetting(
|
||||||
|
encryptConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "Path") {
|
||||||
|
_addStringSetting(
|
||||||
|
encryptConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
Icons.folder,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (key == "HostConfig") {
|
||||||
|
value.forEach((subKey, subValue) {
|
||||||
|
if (subKey == "AgentString") {
|
||||||
|
_addStringSetting(
|
||||||
|
hostConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
Icons.support_agent,
|
||||||
|
);
|
||||||
|
} else if (subKey == "ApiPassword") {
|
||||||
|
_addPasswordSetting(
|
||||||
|
hostConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "ApiPort") {
|
||||||
|
_addIntSetting(
|
||||||
|
hostConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "ApiUser") {
|
||||||
|
_addStringSetting(
|
||||||
|
hostConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
Icons.person,
|
||||||
|
);
|
||||||
|
} else if (subKey == "HostNameOrIp") {
|
||||||
|
_addStringSetting(
|
||||||
|
hostConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
Icons.computer,
|
||||||
|
);
|
||||||
|
} else if (subKey == "Path") {
|
||||||
|
_addStringSetting(
|
||||||
|
hostConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
Icons.route,
|
||||||
|
);
|
||||||
|
} else if (subKey == "Protocol") {
|
||||||
|
_addListSetting(
|
||||||
|
hostConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
["http", "https"],
|
||||||
|
Icons.http,
|
||||||
|
);
|
||||||
|
} else if (subKey == "TimeoutMs") {
|
||||||
|
_addIntSetting(
|
||||||
|
hostConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (key == "RemoteConfig") {
|
||||||
|
value.forEach((subKey, subValue) {
|
||||||
|
if (subKey == "ApiPort") {
|
||||||
|
_addIntSetting(
|
||||||
|
remoteConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "EncryptionToken") {
|
||||||
|
_addPasswordSetting(
|
||||||
|
remoteConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "HostNameOrIp") {
|
||||||
|
_addStringSetting(
|
||||||
|
remoteConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
Icons.computer,
|
||||||
|
);
|
||||||
|
} else if (subKey == "MaxConnections") {
|
||||||
|
_addIntSetting(
|
||||||
|
remoteConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "ReceiveTimeoutMs") {
|
||||||
|
_addIntSetting(
|
||||||
|
remoteConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "SendTimeoutMs") {
|
||||||
|
_addIntSetting(
|
||||||
|
remoteConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (key == "RemoteMount") {
|
||||||
|
value.forEach((subKey, subValue) {
|
||||||
|
if (subKey == "Enable") {
|
||||||
|
List<SettingsTile> tempSettings = [];
|
||||||
|
_addBooleanSetting(tempSettings, _settings[key], subKey, subValue);
|
||||||
|
remoteMountSettings.insertAll(0, tempSettings);
|
||||||
|
} else if (subKey == "ApiPort") {
|
||||||
|
_addIntSetting(
|
||||||
|
remoteMountSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "ClientPoolSize") {
|
||||||
|
_addIntSetting(
|
||||||
|
remoteMountSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "EncryptionToken") {
|
||||||
|
_addPasswordSetting(
|
||||||
|
remoteMountSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (key == "S3Config") {
|
||||||
|
value.forEach((subKey, subValue) {
|
||||||
|
if (subKey == "AccessKey") {
|
||||||
|
_addPasswordSetting(
|
||||||
|
s3ConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "Bucket") {
|
||||||
|
_addStringSetting(
|
||||||
|
s3ConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
Icons.folder,
|
||||||
|
);
|
||||||
|
} else if (subKey == "EncryptionToken") {
|
||||||
|
_addPasswordSetting(
|
||||||
|
s3ConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "Region") {
|
||||||
|
_addStringSetting(
|
||||||
|
s3ConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
Icons.map,
|
||||||
|
);
|
||||||
|
} else if (subKey == "SecretKey") {
|
||||||
|
_addPasswordSetting(
|
||||||
|
s3ConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "TimeoutMs") {
|
||||||
|
_addIntSetting(s3ConfigSettings, _settings[key], subKey, subValue);
|
||||||
|
} else if (subKey == "URL") {
|
||||||
|
_addStringSetting(
|
||||||
|
s3ConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
Icons.http,
|
||||||
|
);
|
||||||
|
} else if (subKey == "UsePathStyle") {
|
||||||
|
_addBooleanSetting(
|
||||||
|
s3ConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
} else if (subKey == "UseRegionInURL") {
|
||||||
|
_addBooleanSetting(
|
||||||
|
s3ConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (key == "SiaConfig") {
|
||||||
|
value.forEach((subKey, subValue) {
|
||||||
|
if (subKey == "Bucket") {
|
||||||
|
_addStringSetting(
|
||||||
|
siaConfigSettings,
|
||||||
|
_settings[key],
|
||||||
|
subKey,
|
||||||
|
subValue,
|
||||||
|
Icons.folder,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return SettingsList(
|
||||||
|
shrinkWrap: false,
|
||||||
|
sections: [
|
||||||
|
if (encryptConfigSettings.isNotEmpty)
|
||||||
|
SettingsSection(
|
||||||
|
title: const Text('Encrypt Config'),
|
||||||
|
tiles: encryptConfigSettings,
|
||||||
|
),
|
||||||
|
if (hostConfigSettings.isNotEmpty)
|
||||||
|
SettingsSection(
|
||||||
|
title: const Text('Host Config'),
|
||||||
|
tiles: hostConfigSettings,
|
||||||
|
),
|
||||||
|
if (remoteConfigSettings.isNotEmpty)
|
||||||
|
SettingsSection(
|
||||||
|
title: const Text('Remote Config'),
|
||||||
|
tiles: remoteConfigSettings,
|
||||||
|
),
|
||||||
|
if (s3ConfigSettings.isNotEmpty)
|
||||||
|
SettingsSection(
|
||||||
|
title: const Text('S3 Config'),
|
||||||
|
tiles: s3ConfigSettings,
|
||||||
|
),
|
||||||
|
if (siaConfigSettings.isNotEmpty)
|
||||||
|
SettingsSection(
|
||||||
|
title: const Text('Sia Config'),
|
||||||
|
tiles: siaConfigSettings,
|
||||||
|
),
|
||||||
|
if (remoteMountSettings.isNotEmpty)
|
||||||
|
SettingsSection(
|
||||||
|
title: const Text('Remote Mount'),
|
||||||
|
tiles:
|
||||||
|
_settings["RemoteMount"]["Enable"] as bool
|
||||||
|
? remoteMountSettings
|
||||||
|
: [remoteMountSettings[0]],
|
||||||
|
),
|
||||||
|
SettingsSection(title: const Text('Settings'), tiles: commonSettings),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
var settings = widget.mount.mountConfig.settings;
|
||||||
|
if (!DeepCollectionEquality().equals(_settings, settings)) {
|
||||||
|
_settings.forEach((key, value) {
|
||||||
|
if (!DeepCollectionEquality().equals(settings[key], value)) {
|
||||||
|
if (value is Map<String, dynamic>) {
|
||||||
|
value.forEach((subKey, subValue) {
|
||||||
|
if (!DeepCollectionEquality().equals(
|
||||||
|
settings[key][subKey],
|
||||||
|
subValue,
|
||||||
|
)) {
|
||||||
|
widget.mount.setValue('$key.$subKey', subValue.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
widget.mount.setValue(key, value.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_settings = jsonDecode(jsonEncode(widget.mount.mountConfig.settings));
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
}
|
115
web/repertory/lib/widgets/mount_widget.dart
Normal file
115
web/repertory/lib/widgets/mount_widget.dart
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:repertory/helpers.dart';
|
||||||
|
import 'package:repertory/models/mount.dart';
|
||||||
|
|
||||||
|
class MountWidget extends StatefulWidget {
|
||||||
|
const MountWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MountWidget> createState() => _MountWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MountWidgetState extends State<MountWidget> {
|
||||||
|
Timer? _timer;
|
||||||
|
bool _enabled = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
child: Consumer<Mount>(
|
||||||
|
builder: (context, mount, widget) {
|
||||||
|
final textColor = Theme.of(context).colorScheme.onSurface;
|
||||||
|
final subTextColor =
|
||||||
|
Theme.of(context).brightness == Brightness.dark
|
||||||
|
? Colors.white70
|
||||||
|
: Colors.black87;
|
||||||
|
|
||||||
|
final isActive = mount.state == Icons.toggle_on;
|
||||||
|
final nameText = SelectableText(
|
||||||
|
formatMountName(mount.type, mount.name),
|
||||||
|
style: TextStyle(color: subTextColor),
|
||||||
|
);
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
isThreeLine: isActive,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: Icon(Icons.settings, color: subTextColor),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pushNamed(context, '/settings', arguments: mount);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
subtitle:
|
||||||
|
isActive
|
||||||
|
? Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
nameText,
|
||||||
|
SelectableText(
|
||||||
|
mount.path,
|
||||||
|
style: TextStyle(color: subTextColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: nameText,
|
||||||
|
title: SelectableText(
|
||||||
|
initialCaps(mount.type),
|
||||||
|
style: TextStyle(color: textColor, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
trailing: IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
mount.state,
|
||||||
|
color: isActive ? textColor : subTextColor,
|
||||||
|
),
|
||||||
|
onPressed:
|
||||||
|
_enabled
|
||||||
|
? () {
|
||||||
|
setState(() {
|
||||||
|
_enabled = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isActive) {
|
||||||
|
mount
|
||||||
|
.mount(isActive)
|
||||||
|
.then((_) {
|
||||||
|
setState(() {
|
||||||
|
_enabled = true;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catchError((_) {
|
||||||
|
setState(() {
|
||||||
|
_enabled = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_enabled = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_timer?.cancel();
|
||||||
|
_timer = null;
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_timer = Timer.periodic(const Duration(seconds: 5), (_) {
|
||||||
|
Provider.of<Mount>(context, listen: false).refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
93
web/repertory/pubspec.yaml
Normal file
93
web/repertory/pubspec.yaml
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
name: repertory
|
||||||
|
description: "Repertory Management Portal"
|
||||||
|
# The following line prevents the package from being accidentally published to
|
||||||
|
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||||
|
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
|
# The following defines the version and build number for your application.
|
||||||
|
# A version number is three numbers separated by dots, like 1.2.43
|
||||||
|
# followed by an optional build number separated by a +.
|
||||||
|
# Both the version and the builder number may be overridden in flutter
|
||||||
|
# build by specifying --build-name and --build-number, respectively.
|
||||||
|
# In Android, build-name is used as versionName while build-number used as versionCode.
|
||||||
|
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
|
||||||
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
|
||||||
|
# Read more about iOS versioning at
|
||||||
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
|
version: 1.0.0+1
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ^3.7.0
|
||||||
|
|
||||||
|
# Dependencies specify other packages that your package needs in order to work.
|
||||||
|
# To automatically upgrade your package dependencies to the latest versions
|
||||||
|
# consider running `flutter pub upgrade --major-versions`. Alternatively,
|
||||||
|
# dependencies can be manually updated by changing the version numbers below to
|
||||||
|
# the latest version available on pub.dev. To see which dependencies have newer
|
||||||
|
# versions available, run `flutter pub outdated`.
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
# The following adds the Cupertino Icons font to your application.
|
||||||
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
|
cupertino_icons: ^1.0.8
|
||||||
|
collection: ^1.19.1
|
||||||
|
http: ^1.3.0
|
||||||
|
provider: ^6.1.2
|
||||||
|
settings_ui: ^2.0.2
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
# The "flutter_lints" package below contains a set of recommended lints to
|
||||||
|
# encourage good coding practices. The lint set provided by the package is
|
||||||
|
# activated in the `analysis_options.yaml` file located at the root of your
|
||||||
|
# package. See that file for information about deactivating specific lint
|
||||||
|
# rules and activating additional ones.
|
||||||
|
flutter_lints: ^5.0.0
|
||||||
|
|
||||||
|
# For information on the generic Dart part of this file, see the
|
||||||
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
||||||
|
# The following section is specific to Flutter packages.
|
||||||
|
flutter:
|
||||||
|
|
||||||
|
# The following line ensures that the Material Icons font is
|
||||||
|
# included with your application, so that you can use the icons in
|
||||||
|
# the material Icons class.
|
||||||
|
uses-material-design: true
|
||||||
|
|
||||||
|
# To add assets to your application, add an assets section, like this:
|
||||||
|
# assets:
|
||||||
|
# - images/a_dot_burr.jpeg
|
||||||
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
# https://flutter.dev/to/resolution-aware-images
|
||||||
|
|
||||||
|
# For details regarding adding assets from package dependencies, see
|
||||||
|
# https://flutter.dev/to/asset-from-package
|
||||||
|
|
||||||
|
# To add custom fonts to your application, add a fonts section here,
|
||||||
|
# in this "flutter" section. Each entry in this list should have a
|
||||||
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
|
# list giving the asset and other descriptors for the font. For
|
||||||
|
# example:
|
||||||
|
# fonts:
|
||||||
|
# - family: Schyler
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/Schyler-Regular.ttf
|
||||||
|
# - asset: fonts/Schyler-Italic.ttf
|
||||||
|
# style: italic
|
||||||
|
# - family: Trajan Pro
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/TrajanPro.ttf
|
||||||
|
# - asset: fonts/TrajanPro_Bold.ttf
|
||||||
|
# weight: 700
|
||||||
|
#
|
||||||
|
# For details regarding fonts from package dependencies,
|
||||||
|
# see https://flutter.dev/to/font-from-package
|
30
web/repertory/test/widget_test.dart
Normal file
30
web/repertory/test/widget_test.dart
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// This is a basic Flutter widget test.
|
||||||
|
//
|
||||||
|
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||||
|
// utility in the flutter_test package. For example, you can send tap and scroll
|
||||||
|
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||||
|
// tree, read text, and verify that the values of widget properties are correct.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'package:repertory/main.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||||
|
// Build our app and trigger a frame.
|
||||||
|
await tester.pumpWidget(const MyApp());
|
||||||
|
|
||||||
|
// Verify that our counter starts at 0.
|
||||||
|
expect(find.text('0'), findsOneWidget);
|
||||||
|
expect(find.text('1'), findsNothing);
|
||||||
|
|
||||||
|
// Tap the '+' icon and trigger a frame.
|
||||||
|
await tester.tap(find.byIcon(Icons.add));
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// Verify that our counter has incremented.
|
||||||
|
expect(find.text('0'), findsNothing);
|
||||||
|
expect(find.text('1'), findsOneWidget);
|
||||||
|
});
|
||||||
|
}
|
BIN
web/repertory/web/favicon.png
Normal file
BIN
web/repertory/web/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 917 B |
BIN
web/repertory/web/icons/Icon-192.png
Normal file
BIN
web/repertory/web/icons/Icon-192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
web/repertory/web/icons/Icon-512.png
Normal file
BIN
web/repertory/web/icons/Icon-512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.1 KiB |
BIN
web/repertory/web/icons/Icon-maskable-192.png
Normal file
BIN
web/repertory/web/icons/Icon-maskable-192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
web/repertory/web/icons/Icon-maskable-512.png
Normal file
BIN
web/repertory/web/icons/Icon-maskable-512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
38
web/repertory/web/index.html
Normal file
38
web/repertory/web/index.html
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!--
|
||||||
|
If you are serving your web app in a path other than the root, change the
|
||||||
|
href value below to reflect the base path you are serving from.
|
||||||
|
|
||||||
|
The path provided below has to start and end with a slash "/" in order for
|
||||||
|
it to work correctly.
|
||||||
|
|
||||||
|
For more details:
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||||
|
|
||||||
|
This is a placeholder for base href that will be replaced by the value of
|
||||||
|
the `--base-href` argument provided to `flutter build`.
|
||||||
|
-->
|
||||||
|
<base href="$FLUTTER_BASE_HREF">
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||||
|
<meta name="description" content="A new Flutter project.">
|
||||||
|
|
||||||
|
<!-- iOS meta tags & icons -->
|
||||||
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
|
<meta name="apple-mobile-web-app-title" content="repertory">
|
||||||
|
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||||
|
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||||
|
|
||||||
|
<title>repertory</title>
|
||||||
|
<link rel="manifest" href="manifest.json">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="flutter_bootstrap.js" async></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
35
web/repertory/web/manifest.json
Normal file
35
web/repertory/web/manifest.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "repertory",
|
||||||
|
"short_name": "repertory",
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#0175C2",
|
||||||
|
"theme_color": "#0175C2",
|
||||||
|
"description": "A new Flutter project.",
|
||||||
|
"orientation": "portrait-primary",
|
||||||
|
"prefer_related_applications": false,
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-maskable-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-maskable-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Reference in New Issue
Block a user