6 Commits

Author SHA1 Message Date
GW_MC
547d73fab7 temp allow deadcode for AppState struct
All checks were successful
Test / verify-generated-code (pull_request) Successful in 8m32s
Test / test (pull_request) Successful in 1m10s
Test / lint (pull_request) Successful in 1m7s
2025-11-27 19:05:41 +08:00
GW_MC
537737b1cc refactor configs into a crate 2025-11-27 18:59:40 +08:00
GW_MC
bb622df89b Basic route structure 2025-11-27 18:50:11 +08:00
GW_MC
e849b71a40 Implement API setup with configuration management and startup tasks
- Add `Cargo.toml` for API with dependencies.
- Create `config.rs` for managing application settings.
- Implement logging and server settings in `config.rs`.
- Add `main.rs` to initialize the application and handle database connections.
- Introduce `task` module with startup tasks, including database migrations.
- Update `.gitignore` to exclude `config.yaml` and remove `.gitkeep`.
2025-11-26 19:45:37 +08:00
GW_MC
56c1161e97 Change database log level to debug 2025-11-25 21:17:03 +08:00
GW_MC
f9218e0927 Add support for environment file generation in EnvFile struct
- Introduced new methods for writing environment files in YAML and DotEnv formats.
- Updated EnvFile struct to include a buffer for storing key-value pairs.
- Modified write_env_files function to create and write to environment files based on configuration.
- Added tests for environment file writing functionality.
2025-11-25 21:16:21 +08:00
22 changed files with 1080 additions and 29 deletions

3
.gitignore vendored
View File

@@ -23,4 +23,7 @@ target
#.idea/ #.idea/
# generated environment variables file # generated environment variables file
.env
.env.generated .env.generated
generated-config.yaml

466
Cargo.lock generated
View File

@@ -93,6 +93,12 @@ dependencies = [
"windows-sys 0.60.2", "windows-sys 0.60.2",
] ]
[[package]]
name = "arraydeque"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.7.6" version = "0.7.6"
@@ -153,6 +159,70 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "axum"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425"
dependencies = [
"axum-core",
"axum-macros",
"bytes",
"form_urlencoded",
"futures-util",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"serde_core",
"serde_json",
"serde_path_to_error",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "axum-core"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22"
dependencies = [
"bytes",
"futures-core",
"http",
"http-body",
"http-body-util",
"mime",
"pin-project-lite",
"sync_wrapper",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "axum-macros"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.110",
]
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.21.7" version = "0.21.7"
@@ -372,9 +442,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.51" version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@@ -382,9 +452,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.51" version = "4.5.53"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@@ -441,12 +511,52 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "config"
version = "0.15.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b30fa8254caad766fc03cb0ccae691e14bf3bd72bfff27f72802ce729551b3d6"
dependencies = [
"async-trait",
"convert_case",
"json5",
"pathdiff",
"ron",
"rust-ini",
"serde-untagged",
"serde_core",
"serde_json",
"toml",
"winnow",
"yaml-rust2",
]
[[package]] [[package]]
name = "const-oid" name = "const-oid"
version = "0.9.6" version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "const-random"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
[[package]]
name = "const-random-macro"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom 0.2.16",
"once_cell",
"tiny-keccak",
]
[[package]] [[package]]
name = "container-simulate" name = "container-simulate"
version = "0.1.0" version = "0.1.0"
@@ -454,12 +564,22 @@ dependencies = [
"async-trait", "async-trait",
"clap", "clap",
"path-clean", "path-clean",
"serde_json",
"shared", "shared",
"testcontainers", "testcontainers",
"tokio", "tokio",
"url", "url",
] ]
[[package]]
name = "convert_case"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
"unicode-segmentation",
]
[[package]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.9.4" version = "0.9.4"
@@ -525,6 +645,12 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crunchy"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.1.7" version = "0.1.7"
@@ -609,6 +735,7 @@ name = "database"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"log",
"migration", "migration",
"sea-orm", "sea-orm",
"serde", "serde",
@@ -682,6 +809,15 @@ dependencies = [
"syn 2.0.110", "syn 2.0.110",
] ]
[[package]]
name = "dlv-list"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
dependencies = [
"const-random",
]
[[package]] [[package]]
name = "docker_credential" name = "docker_credential"
version = "1.3.2" version = "1.3.2"
@@ -714,12 +850,32 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "encoding_rs"
version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.2" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "erased-serde"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3"
dependencies = [
"serde",
"serde_core",
"typeid",
]
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.14" version = "0.3.14"
@@ -988,6 +1144,12 @@ dependencies = [
"ahash", "ahash",
] ]
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.5" version = "0.15.5"
@@ -1400,6 +1562,17 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "json5"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
dependencies = [
"pest",
"pest_derive",
"serde",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.5.0" version = "1.5.0"
@@ -1479,6 +1652,12 @@ dependencies = [
"regex-automata", "regex-automata",
] ]
[[package]]
name = "matchit"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]] [[package]]
name = "md-5" name = "md-5"
version = "0.10.6" version = "0.10.6"
@@ -1499,11 +1678,18 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
name = "migration" name = "migration"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"log",
"sea-orm-cli", "sea-orm-cli",
"sea-orm-migration", "sea-orm-migration",
"tokio", "tokio",
] ]
[[package]]
name = "mime"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.1.0" version = "1.1.0"
@@ -1532,6 +1718,15 @@ dependencies = [
"tempfile", "tempfile",
] ]
[[package]]
name = "nu-ansi-term"
version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys 0.61.2",
]
[[package]] [[package]]
name = "num-bigint" name = "num-bigint"
version = "0.4.6" version = "0.4.6"
@@ -1659,6 +1854,16 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "ordered-multimap"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79"
dependencies = [
"dlv-list",
"hashbrown 0.14.5",
]
[[package]] [[package]]
name = "ouroboros" name = "ouroboros"
version = "0.18.5" version = "0.18.5"
@@ -1743,6 +1948,12 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef"
[[package]]
name = "pathdiff"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
[[package]] [[package]]
name = "pem-rfc7468" name = "pem-rfc7468"
version = "0.7.0" version = "0.7.0"
@@ -1758,6 +1969,49 @@ version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "pest"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4"
dependencies = [
"memchr",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.110",
]
[[package]]
name = "pest_meta"
version = "2.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a"
dependencies = [
"pest",
"sha2",
]
[[package]] [[package]]
name = "pgvector" name = "pgvector"
version = "0.4.1" version = "0.4.1"
@@ -2093,6 +2347,20 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "ron"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32"
dependencies = [
"bitflags 2.10.0",
"once_cell",
"serde",
"serde_derive",
"typeid",
"unicode-ident",
]
[[package]] [[package]]
name = "rsa" name = "rsa"
version = "0.9.9" version = "0.9.9"
@@ -2113,6 +2381,16 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "rust-ini"
version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7"
dependencies = [
"cfg-if",
"ordered-multimap",
]
[[package]] [[package]]
name = "rust_decimal" name = "rust_decimal"
version = "1.39.0" version = "1.39.0"
@@ -2484,6 +2762,18 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "serde-untagged"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058"
dependencies = [
"erased-serde",
"serde",
"serde_core",
"typeid",
]
[[package]] [[package]]
name = "serde_core" name = "serde_core"
version = "1.0.228" version = "1.0.228"
@@ -2517,6 +2807,17 @@ dependencies = [
"serde_core", "serde_core",
] ]
[[package]]
name = "serde_path_to_error"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
dependencies = [
"itoa",
"serde",
"serde_core",
]
[[package]] [[package]]
name = "serde_repr" name = "serde_repr"
version = "0.1.20" version = "0.1.20"
@@ -2528,6 +2829,15 @@ dependencies = [
"syn 2.0.110", "syn 2.0.110",
] ]
[[package]]
name = "serde_spanned"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392"
dependencies = [
"serde_core",
]
[[package]] [[package]]
name = "serde_urlencoded" name = "serde_urlencoded"
version = "0.7.1" version = "0.7.1"
@@ -2977,6 +3287,12 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
[[package]] [[package]]
name = "synstructure" name = "synstructure"
version = "0.13.2" version = "0.13.2"
@@ -3096,6 +3412,15 @@ dependencies = [
"time-core", "time-core",
] ]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]] [[package]]
name = "tinystr" name = "tinystr"
version = "0.8.2" version = "0.8.2"
@@ -3135,6 +3460,7 @@ dependencies = [
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2",
"tokio-macros", "tokio-macros",
"tracing",
"windows-sys 0.61.2", "windows-sys 0.61.2",
] ]
@@ -3198,6 +3524,19 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "toml"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8"
dependencies = [
"serde_core",
"serde_spanned",
"toml_datetime",
"toml_parser",
"winnow",
]
[[package]] [[package]]
name = "toml_datetime" name = "toml_datetime"
version = "0.7.3" version = "0.7.3"
@@ -3228,6 +3567,42 @@ dependencies = [
"winnow", "winnow",
] ]
[[package]]
name = "tower"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper",
"tokio",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-http"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
dependencies = [
"bitflags 2.10.0",
"bytes",
"http",
"pin-project-lite",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]] [[package]]
name = "tower-service" name = "tower-service"
version = "0.3.3" version = "0.3.3"
@@ -3264,6 +3639,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"log",
"once_cell",
"tracing-core",
]
[[package]]
name = "tracing-serde"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1"
dependencies = [
"serde",
"tracing-core",
] ]
[[package]] [[package]]
@@ -3272,13 +3669,21 @@ version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
dependencies = [ dependencies = [
"chrono",
"matchers", "matchers",
"nu-ansi-term",
"once_cell", "once_cell",
"regex-automata", "regex-automata",
"serde",
"serde_json",
"sharded-slab", "sharded-slab",
"smallvec",
"thread_local", "thread_local",
"time",
"tracing", "tracing",
"tracing-core", "tracing-core",
"tracing-log",
"tracing-serde",
] ]
[[package]] [[package]]
@@ -3287,12 +3692,24 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "typeid"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.19.0" version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
[[package]]
name = "ucd-trie"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.18" version = "0.3.18"
@@ -3320,6 +3737,12 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.6" version = "0.2.6"
@@ -3367,6 +3790,12 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "valuable"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"
@@ -3834,12 +4263,41 @@ dependencies = [
"rustix", "rustix",
] ]
[[package]]
name = "yaml-rust2"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2462ea039c445496d8793d052e13787f2b90e750b833afee748e601c17621ed9"
dependencies = [
"arraydeque",
"encoding_rs",
"hashlink",
]
[[package]] [[package]]
name = "yansi" name = "yansi"
version = "1.0.1" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "yet-another-nginx-proxy-manager"
version = "0.1.0"
dependencies = [
"axum",
"chrono",
"config",
"database",
"migration",
"serde",
"serde_json",
"tokio",
"tower",
"tower-http",
"tracing",
"tracing-subscriber",
]
[[package]] [[package]]
name = "yoke" name = "yoke"
version = "0.8.1" version = "0.8.1"

View File

@@ -1,5 +1,6 @@
[workspace] [workspace]
members = [ members = [
"apps/api",
"apps/container", "apps/container",
"apps/cli", "apps/cli",
"public/shared", "public/shared",

1
apps/api/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
config.yaml

View File

19
apps/api/Cargo.toml Normal file
View File

@@ -0,0 +1,19 @@
[package]
name = "yet-another-nginx-proxy-manager"
version = "0.1.0"
edition = "2024"
[dependencies]
database = { path = "../../public/database" }
migration = { path = "../../public/migration" }
axum = { version = "0.8.7", features = ["form", "http1", "json", "matched-path", "original-uri", "query", "tokio", "tower-log", "tracing", "macros"]}
chrono = { version = "0.4.42", features = ["clock", "std", "oldtime", "wasmbind", "serde"] }
config = { version = "0.15.19", features = ["toml", "json", "yaml", "ini", "ron", "json5", "convert-case", "async"] }
tokio = { version = "1", features = ["fs", "io-util", "io-std", "macros", "net", "parking_lot", "process", "rt", "rt-multi-thread", "signal", "sync", "time", "tracing"] }
tower = { version = "0.5.2", features = ["tokio", "tracing"] }
tower-http = { version = "0.6.6" }
tracing = { version = "0.1.41", features = ["std", "attributes"] }
tracing-subscriber = { version = "0.3.20", features = ["smallvec", "fmt", "ansi", "tracing-log", "std", "chrono", "json", "serde", "serde_json", "time", "tracing"] }
serde_json = { version = "1.0.145", features = ["std"] }
serde = { version = "1.0.228", features = ["std", "derive"] }

76
apps/api/src/configs.rs Normal file
View File

@@ -0,0 +1,76 @@
pub mod database;
pub mod logging;
pub mod server;
mod key;
use config::Config;
use tracing::{debug, error};
pub trait FromConfig: Sized {
fn from_config(config: &Config) -> Result<Self, String>;
fn validate(&self) -> Result<(), String>;
}
#[derive(Debug, Clone)]
pub struct ProgramSettings {
pub logging: logging::LoggingSettings,
pub database: database::DatabaseSettings,
pub server: server::ServerSettings,
}
impl FromConfig for ProgramSettings {
fn from_config(_config: &Config) -> Result<Self, String> {
let config = ProgramSettings {
logging: logging::LoggingSettings::from_config(_config)?,
database: database::DatabaseSettings::from_config(_config)?,
server: server::ServerSettings::from_config(_config)?,
};
config.validate()?;
Ok(config)
}
fn validate(&self) -> Result<(), String> {
self.logging.validate()?;
self.database.validate()?;
self.server.validate()?;
Ok(())
}
}
pub fn get_program_settings() -> ProgramSettings {
debug!("Loading program settings from configuration sources");
let settings = Config::builder()
// dev / generated config has the highest priority (Overwrite by user config files)
.add_source(config::File::with_name("generated-config.yaml").required(false))
// user config files
.add_source(
config::File::with_name("/etc/yet-another-nginx-proxy-manager/config").required(false),
)
.add_source(
config::File::with_name("$HOME/.config/yet-another-nginx-proxy-manager/config")
.required(false),
)
.add_source(config::File::with_name("config.yaml").required(false))
// environment variables have the highest priority (Overwrite all config files)
.add_source(
config::Environment::with_prefix("YANPM")
.separator("__")
.prefix_separator("_"),
)
.build()
.expect("Failed to build configuration");
debug!("Configuration sources loaded successfully");
debug!("Parsing program settings from configuration");
ProgramSettings::from_config(&settings)
.inspect_err(|err| {
error!("Configuration error: {}", err);
debug!("Current configurations: {:#?}", settings);
})
.inspect(|_| {
debug!("Program settings parsed successfully");
})
.expect("Failed to load program settings from configuration")
}

View File

@@ -0,0 +1,53 @@
use config::{Config, ConfigError};
use tracing::warn;
use super::{
FromConfig,
key::{DATABASE_MAX_CONNECTIONS_KEY, DATABASE_MIGRATE_ON_STARTUP_KEY},
};
#[derive(Debug, Clone)]
pub struct DatabaseSettings {
pub url: String,
pub max_connections: u32,
pub migrate_on_startup: bool,
}
impl FromConfig for DatabaseSettings {
fn from_config(_config: &Config) -> Result<Self, String> {
Ok(DatabaseSettings {
url: _config
.get_string(super::key::DATABASE_URL_KEY)
.map_err(|op| match op {
ConfigError::NotFound(_) => "Database URL not found in configuration".into(),
err => {
format!("Failed to read Database URL from configuration {err}")
}
})?,
max_connections: _config
.get_int(DATABASE_MAX_CONNECTIONS_KEY)
.unwrap_or_else(|err| {
const DEFAULT_MAX_CONNECTIONS: i64 = 10;
warn!(
"{} not set or invalid in configuration, defaulting to {}. Error: {}",
DATABASE_MAX_CONNECTIONS_KEY, DEFAULT_MAX_CONNECTIONS, err
);
DEFAULT_MAX_CONNECTIONS
}) as u32,
migrate_on_startup: _config
.get_bool(DATABASE_MIGRATE_ON_STARTUP_KEY)
.unwrap_or_else(|err| {
const DEFAULT_MIGRATE_ON_STARTUP: bool = true;
warn!(
"{} not set or invalid in configuration, defaulting to {}. Error: {}",
DATABASE_MIGRATE_ON_STARTUP_KEY, DEFAULT_MIGRATE_ON_STARTUP, err
);
DEFAULT_MIGRATE_ON_STARTUP
}),
})
}
fn validate(&self) -> Result<(), String> {
Ok(())
}
}

View File

@@ -0,0 +1,9 @@
pub(crate) const LOGGING_LEVEL_KEY: &str = "LOGGING.LEVEL";
pub(crate) const LOGGING_UTC_KEY: &str = "LOGGING.UTC";
//
pub(crate) const SERVER_ADDRESS_KEY: &str = "SERVER.ADDRESS";
pub(crate) const SERVER_PORT_KEY: &str = "SERVER.PORT";
//
pub(crate) const DATABASE_URL_KEY: &str = "DATABASE.URL";
pub(crate) const DATABASE_MAX_CONNECTIONS_KEY: &str = "DATABASE.MAX_CONNECTIONS";
pub(crate) const DATABASE_MIGRATE_ON_STARTUP_KEY: &str = "DATABASE.MIGRATION.MIGRATE_ON_STARTUP";

View File

@@ -0,0 +1,52 @@
use config::{Config, ConfigError};
use tracing::{Level, warn};
use super::{
FromConfig,
key::{LOGGING_LEVEL_KEY, LOGGING_UTC_KEY},
};
#[derive(Debug, Clone)]
pub struct LoggingSettings {
pub level: Level,
pub utc: bool,
}
impl FromConfig for LoggingSettings {
fn from_config(_config: &Config) -> Result<Self, String> {
const DEFAULT_LOGGING_LEVEL: Level = Level::INFO;
Ok(LoggingSettings {
level: _config
.get_string(LOGGING_LEVEL_KEY)
.unwrap_or_else(|err| {
warn!(
"Failed to read {} from configuration, defaulting to {}. Error: {}",
LOGGING_LEVEL_KEY, DEFAULT_LOGGING_LEVEL, err
);
DEFAULT_LOGGING_LEVEL.to_string()
})
.parse()
.unwrap_or_else(|err| {
warn!(
"Invalid logging level in configuration, defaulting to {}. Error: {}",
DEFAULT_LOGGING_LEVEL, err
);
DEFAULT_LOGGING_LEVEL
}),
utc: _config
.get_bool(LOGGING_UTC_KEY)
.unwrap_or_else(|err: ConfigError| {
const DEFAULT_UTC: bool = false;
warn!(
"Invalid UTC setting in configuration, defaulting to {}. Error: {}",
DEFAULT_UTC, err
);
DEFAULT_UTC
}),
})
}
fn validate(&self) -> Result<(), String> {
Ok(())
}
}

View File

@@ -0,0 +1,56 @@
use std::net::IpAddr;
use config::{Config, ConfigError};
use tracing::warn;
use super::{
FromConfig,
key::{SERVER_ADDRESS_KEY, SERVER_PORT_KEY},
};
#[derive(Debug, Clone)]
pub struct ServerSettings {
pub address: IpAddr,
pub port: u16,
}
impl FromConfig for ServerSettings {
fn from_config(_config: &Config) -> Result<Self, String> {
Ok(ServerSettings {
address: _config
.get_string(SERVER_ADDRESS_KEY)
.unwrap_or_else(|err| {
const DEFAULT_ADDRESS: &str = "0.0.0.0";
match err {
ConfigError::NotFound(_) => {}
_ => {
warn!(
"Failed to read {} from configuration, defaulting to {}. Error: {}",
SERVER_ADDRESS_KEY, DEFAULT_ADDRESS, err
);
}
};
DEFAULT_ADDRESS.to_string()
})
.parse()
.map_err(|e| format!("Invalid {} in configuration: {}", SERVER_ADDRESS_KEY, e))?,
port: _config.get_int(SERVER_PORT_KEY).unwrap_or_else(|err| {
const DEFAULT_PORT: i64 = 8080;
warn!(
"{} not set or invalid in configuration, defaulting to {}. Error: {}",
SERVER_PORT_KEY, DEFAULT_PORT, err
);
DEFAULT_PORT
}) as u16,
})
}
fn validate(&self) -> Result<(), String> {
#[allow(clippy::absurd_extreme_comparisons, unused_comparisons)]
if self.port == 0 || self.port > 65535 {
return Err("Server port must be between 1 and 65535".into());
}
Ok(())
}
}

118
apps/api/src/main.rs Normal file
View File

@@ -0,0 +1,118 @@
mod configs;
mod routes;
mod tasks;
use axum::Router;
use database::{ConnectOptions, get_connection};
use tracing::{debug, info};
use tracing_subscriber::fmt::format::{DefaultFields, Format};
use crate::configs::{ProgramSettings, get_program_settings, logging::LoggingSettings};
#[tokio::main]
async fn main() {
// Temporary subscriber for initial logging during configuration reading
let make_temporary_subscriber = || {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.with_target(false)
.with_level(true)
.finish()
};
let settings =
tracing::subscriber::with_default(make_temporary_subscriber(), || -> ProgramSettings {
debug!("Temporary subscriber installed.");
info!("Reading configuration...");
let settings = get_program_settings();
info!("Configuration read successfully.");
debug!("Resetting global subscriber...");
let subscriber = get_global_tracing_subscriber_builder(&settings.logging).finish();
tracing::subscriber::set_global_default(subscriber)
.expect("Failed to set global default subscriber");
debug!(
"Global subscriber set with logging level: {:?}",
settings.logging.level
);
settings
});
tasks::startup::run_startup_tasks(&settings)
.await
.expect("Failed to run startup tasks");
// setup database connection pool
info!("Establishing database connection...");
debug!("Database URL: {}", settings.database.url);
let db_options = |options: &mut ConnectOptions| {
options.max_connections(settings.database.max_connections);
};
let db_connection = get_connection(&settings.database.url, Some(db_options))
.await
.expect("Failed to establish database connection");
info!("Database connection established.");
// build the axum app and run the server...
info!("Starting application...");
let app: Router = routes::get_root_router(routes::AppState {
database_connection: db_connection,
service: std::sync::Arc::new(routes::AppService {}),
});
let address = format!("{}:{}", settings.server.address, settings.server.port);
info!("Starting server at http://{}", address);
let listener = tokio::net::TcpListener::bind(address)
.await
.expect("Failed to bind to address");
axum::serve(listener, app)
.await
.expect("Failed to run the server");
}
fn get_global_tracing_subscriber_builder(
settings: &LoggingSettings,
) -> tracing_subscriber::fmt::SubscriberBuilder<
DefaultFields,
Format<tracing_subscriber::fmt::format::Full, BoxedTimer>,
> {
// After configuration is read, install the global subscriber
let builder = tracing_subscriber::fmt()
.with_max_level(settings.level)
.with_target(false)
.with_level(true);
if settings.utc {
builder.with_timer(BoxedTimer(Box::new(
tracing_subscriber::fmt::time::UtcTime::rfc_3339(),
)))
} else {
builder.with_timer(BoxedTimer(Box::new(
tracing_subscriber::fmt::time::ChronoLocal::rfc_3339(),
)))
}
}
// A small wrapper that holds a boxed `FormatTime` trait object and itself
// implements `FormatTime`, allowing us to use it as a concrete type with
// `builder.with_timer` while still picking the concrete timer implementation
// at runtime.
// wrapper type to hold boxed timers and implement the `FormatTime` trait for
// a concrete type so `with_timer` may be called once outside the conditional.
struct BoxedTimer(Box<dyn tracing_subscriber::fmt::time::FormatTime + Send + Sync + 'static>);
impl tracing_subscriber::fmt::time::FormatTime for BoxedTimer {
fn format_time(
&self,
w: &mut tracing_subscriber::fmt::format::Writer<'_>,
) -> std::result::Result<(), std::fmt::Error> {
self.0.format_time(w)
}
}

37
apps/api/src/routes.rs Normal file
View File

@@ -0,0 +1,37 @@
use std::sync::Arc;
use axum::Router;
use migration::sea_orm::DatabaseConnection;
pub struct AppState {
// TODO: remove dead_code allowances when fields are used
#[allow(dead_code)]
pub database_connection: DatabaseConnection,
// TODO: remove dead_code allowances when fields are used
#[allow(dead_code)]
pub service: Arc<AppService>,
}
pub struct AppService {
//
}
pub fn get_root_router(state: impl Into<Arc<AppState>>) -> Router {
let router = Router::new()
// TODO: Add routes
.with_state(state.into());
#[allow(clippy::let_and_return)]
router
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ensure_state_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<AppState>();
}
}

1
apps/api/src/tasks.rs Normal file
View File

@@ -0,0 +1 @@
pub mod startup;

View File

@@ -0,0 +1,25 @@
use migration::migrate_database;
use tracing::{debug, info};
use crate::configs::ProgramSettings;
pub async fn run_startup_tasks(config: &ProgramSettings) -> Result<(), Box<dyn std::error::Error>> {
// Here you can add any startup tasks you want to run when the application starts.
info!("Running startup tasks...");
if config.database.migrate_on_startup {
run_database_migrations(&config.database.url).await?;
} else {
info!("Database migration on startup is disabled. Skipping migration.");
}
Ok(())
}
async fn run_database_migrations(db_url: &str) -> Result<(), Box<dyn std::error::Error>> {
// Logic to run database migrations
info!("Running database migrations...");
debug!("Database URL: {}", db_url);
migrate_database(db_url).await.map_err(Box::new)?;
info!("Database migrations completed.");
Ok(())
}

View File

@@ -15,3 +15,4 @@ tokio = { version = "1.47.0", features = ["full"] }
url = "2.5.7" url = "2.5.7"
clap = { version = "4.5.48", features = ["derive", "env"] } clap = { version = "4.5.48", features = ["derive", "env"] }
path-clean = "1.0.1" path-clean = "1.0.1"
serde_json = "1.0.145"

View File

@@ -13,24 +13,151 @@ pub struct EnvFile {
pub file_type: EnvFileType, pub file_type: EnvFileType,
pub db_type: DBType, pub db_type: DBType,
pub db_url: String, pub db_url: String,
//
buffer: serde_json::Value,
} }
impl EnvFile { impl EnvFile {
pub fn write(self, path: impl AsRef<std::path::Path>) { pub fn new(file_type: EnvFileType, db_type: DBType, db_url: String) -> Self {
let path_ref = path.as_ref(); let mut env_file = EnvFile {
println!("Config file path: {}", path_ref.display()); file_type,
let mut config_file = db_type,
std::fs::File::create(path_ref).expect("Failed to create config file"); db_url,
// buffer: serde_json::Value::Object(serde_json::Map::new()),
self._write_line(&mut config_file, "DB_TYPE", &self.db_type.to_string()); };
self._write_line(&mut config_file, "DATABASE_URL", &self.db_url.to_string())
env_file._write_line_buffer("DATABASE__TYPE", &env_file.db_type.to_string());
env_file._write_line_buffer("DATABASE__URL", &env_file.db_url.to_string());
env_file
} }
fn _write_line(&self, file: &mut std::fs::File, key: &str, value: &str) { pub fn write(&mut self, stream: &mut dyn Write, with_prefix: bool) {
match self.file_type { self._write_buffer(stream, with_prefix);
EnvFileType::DotEnv => writeln!(file, "{}={}", key, value), }
EnvFileType::Yaml => writeln!(file, "{}: \"{}\"", key, value),
fn key_into_buffer_key(&self, key: &str) -> Vec<String> {
key.split("__").map(String::from).collect()
}
fn _write_line_buffer(&mut self, key: &str, value: &str) {
let buffer_key = self.key_into_buffer_key(key);
let mut current = &mut self.buffer;
for k in &buffer_key[0..(buffer_key.len() - 1)] {
if current.get(k).is_none() {
current[k] = serde_json::Value::Object(serde_json::Map::new());
}
current = &mut current[k];
} }
.expect("Failed to write to config file"); current[buffer_key.last().unwrap()] = serde_json::Value::String(value.to_string());
}
fn _write_buffer(&self, file: &mut dyn Write, with_prefix: bool) {
match self.file_type {
EnvFileType::DotEnv => self._write_buffer_env(file, with_prefix),
EnvFileType::Yaml => self._write_buffer_yaml(file),
}
}
fn _write_buffer_env(&self, file: &mut dyn Write, with_prefix: bool) {
fn _write_buffer_env_layer(
file: &mut dyn Write,
buffer: &serde_json::Value,
prefix: String,
with_root_prefix: bool,
) {
if let serde_json::Value::Object(map) = buffer {
for (key, value) in map {
let current_key = if prefix.is_empty() {
if with_root_prefix {
format!("YANPM__{}", key)
} else {
key.to_string()
}
} else {
format!("{}__{}", prefix, key)
};
match value {
serde_json::Value::Object(_) => {
_write_buffer_env_layer(file, value, current_key, with_root_prefix);
}
_ => {
writeln!(file, "{}={}", current_key, value).unwrap();
}
}
}
}
}
_write_buffer_env_layer(file, &self.buffer, String::new(), with_prefix);
}
fn _write_buffer_yaml(&self, file: &mut dyn Write) {
let mut layer = 0;
fn _write_buffer_yaml_layer(
file: &mut dyn Write,
buffer: &serde_json::Value,
layer: &mut usize,
) {
if let serde_json::Value::Object(map) = buffer {
for (key, value) in map {
let indent = " ".repeat(*layer);
match value {
serde_json::Value::Object(_) => {
writeln!(file, "{}{}:", indent, key).unwrap();
*layer += 1;
_write_buffer_yaml_layer(file, value, layer);
*layer -= 1;
}
_ => {
writeln!(file, "{}{}: {}", indent, key, value).unwrap();
}
}
}
}
}
_write_buffer_yaml_layer(file, &self.buffer, &mut layer);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_env_file_write_yaml() {
let mut env_file_nested = EnvFile::new(
EnvFileType::Yaml,
DBType::SQLite,
"mysql://user:pass@localhost/db".to_string(),
);
let mut output_stream = Vec::new();
env_file_nested.write(&mut output_stream, false);
let output_string = String::from_utf8(output_stream).unwrap();
let expected_output = "\
DATABASE:
TYPE: \"SQLite\"
URL: \"mysql://user:pass@localhost/db\"
";
assert_eq!(output_string, expected_output);
}
#[test]
fn test_env_file_write_env() {
let mut env_file_nested = EnvFile::new(
EnvFileType::DotEnv,
DBType::PostgreSQL,
"postgres://user:pass@localhost/db".to_string(),
);
let mut output_stream = Vec::new();
env_file_nested.write(&mut output_stream, true);
let output_string = String::from_utf8(output_stream).unwrap();
let expected_output = "\
YANPM__DATABASE__TYPE=\"PostgreSQL\"
YANPM__DATABASE__URL=\"postgres://user:pass@localhost/db\"
";
assert_eq!(output_string, expected_output);
} }
} }

View File

@@ -29,17 +29,18 @@ pub fn write_env_files(db_config: &DBConfigInfoType) {
DBConfigInfoType::PreExisting(config) => (config.db_type.clone(), config.url.clone()), DBConfigInfoType::PreExisting(config) => (config.db_type.clone(), config.url.clone()),
}; };
let api_env_file = EnvFile { let mut api_env = EnvFile::new(env::EnvFileType::Yaml, db_type, db_url);
file_type: env::EnvFileType::Yaml, let mut db_env = api_env.clone();
db_type, db_env.file_type = env::EnvFileType::DotEnv;
db_url,
};
let mut db_env_file = api_env_file.clone(); let mut api_file =
db_env_file.file_type = env::EnvFileType::DotEnv; std::fs::File::create(&api_config_path_absolute).expect("Failed to create API config file");
api_env_file.write(&api_config_path_absolute); let mut db_file =
db_env_file.write(&db_config_path_absolute); std::fs::File::create(&db_config_path_absolute).expect("Failed to create DB config file");
api_env.write(&mut api_file, true);
db_env.write(&mut db_file, false);
} }
pub async fn stop_container( pub async fn stop_container(

View File

@@ -14,6 +14,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
tokio = { version = "1.47.0", features = ["full"] } tokio = { version = "1.47.0", features = ["full"] }
sea-orm = { version = "2.0.0-rc", features = [ "sqlx-postgres", "sqlx-mysql", "sqlx-sqlite", "runtime-tokio-rustls", "macros", "mock", "with-chrono", "with-json", "with-uuid", "sqlite-use-returning-for-3_35", "mariadb-use-returning" ] } sea-orm = { version = "2.0.0-rc", features = [ "sqlx-postgres", "sqlx-mysql", "sqlx-sqlite", "runtime-tokio-rustls", "macros", "mock", "with-chrono", "with-json", "with-uuid", "sqlite-use-returning-for-3_35", "mariadb-use-returning" ] }
log = "0.4.28"
[lints] [lints]
workspace = true workspace = true

View File

@@ -1,3 +1,4 @@
use log::LevelFilter;
pub use sea_orm::ConnectOptions; pub use sea_orm::ConnectOptions;
pub mod generated; pub mod generated;
@@ -13,7 +14,8 @@ pub async fn get_connection<T: FnOnce(&mut ConnectOptions)>(
.connect_timeout(std::time::Duration::from_secs(8)) .connect_timeout(std::time::Duration::from_secs(8))
.idle_timeout(std::time::Duration::from_secs(8)) .idle_timeout(std::time::Duration::from_secs(8))
.test_before_acquire(true) .test_before_acquire(true)
.sqlx_logging(true); .sqlx_logging(true)
.sqlx_logging_level(LevelFilter::Debug);
if let Some(option_fn) = option_fn { if let Some(option_fn) = option_fn {
option_fn(&mut opt); option_fn(&mut opt);

View File

@@ -12,6 +12,7 @@ path = "src/lib.rs"
[dependencies] [dependencies]
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] } tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] }
sea-orm-cli = { version = "2.0.0-rc", features = ["sqlx-postgres", "sqlx-mysql", "sqlx-sqlite", "runtime-tokio"] } sea-orm-cli = { version = "2.0.0-rc", features = ["sqlx-postgres", "sqlx-mysql", "sqlx-sqlite", "runtime-tokio"] }
log = "0.4.28"
[dependencies.sea-orm-migration] [dependencies.sea-orm-migration]
version = "2.0.0-rc" version = "2.0.0-rc"

View File

@@ -2,7 +2,7 @@ pub use sea_orm_migration::prelude::*;
mod migrations; mod migrations;
use migrations::*; use migrations::*;
use sea_orm_migration::sea_orm::Database; use sea_orm_migration::sea_orm::{ConnectOptions, Database};
pub struct Migrator; pub struct Migrator;
@@ -17,7 +17,16 @@ impl MigratorTrait for Migrator {
} }
pub async fn migrate_database(db_url: &str) -> Result<(), DbErr> { pub async fn migrate_database(db_url: &str) -> Result<(), DbErr> {
let db = Database::connect(db_url).await?; let mut opt = ConnectOptions::new(db_url);
opt.max_connections(10)
.min_connections(0)
.connect_timeout(std::time::Duration::from_secs(8))
.idle_timeout(std::time::Duration::from_secs(8))
.test_before_acquire(true)
.sqlx_logging(true)
.sqlx_logging_level(log::LevelFilter::Debug);
let db = Database::connect(opt).await?;
Migrator::up(&db, None).await Migrator::up(&db, None).await
} }