diff options
| author | rtkay123 <dev@kanjala.com> | 2026-04-03 14:43:54 +0200 |
|---|---|---|
| committer | rtkay123 <dev@kanjala.com> | 2026-04-03 14:43:54 +0200 |
| commit | 41d90f42c37df06dabfd717d19f3dc72b5ba2d11 (patch) | |
| tree | 2da259062cbdb459a2958d0be46eed20642b355a | |
| parent | 898a2966975c7397e35d8df6b72df42147bf18bd (diff) | |
| download | sellershut-41d90f42c37df06dabfd717d19f3dc72b5ba2d11.tar.bz2 sellershut-41d90f42c37df06dabfd717d19f3dc72b5ba2d11.zip | |
feat: openapi
| -rw-r--r-- | Cargo.lock | 820 | ||||
| -rw-r--r-- | Cargo.toml | 4 | ||||
| -rw-r--r-- | crates/api-base/Cargo.toml | 17 | ||||
| -rw-r--r-- | crates/api-base/src/health/apidoc.rs | 12 | ||||
| -rw-r--r-- | crates/api-base/src/health/mod.rs | 27 | ||||
| -rw-r--r-- | crates/api-base/src/lib.rs | 3 | ||||
| -rw-r--r-- | crates/api-base/src/version.rs | 45 | ||||
| -rw-r--r-- | crates/sellershut/Cargo.toml | 16 | ||||
| -rw-r--r-- | crates/sellershut/src/config/mod.rs | 2 | ||||
| -rw-r--r-- | crates/sellershut/src/config/server.rs | 10 | ||||
| -rw-r--r-- | crates/sellershut/src/main.rs | 48 | ||||
| -rw-r--r-- | crates/sellershut/src/server/api/mod.rs | 55 | ||||
| -rw-r--r-- | crates/sellershut/src/server/api/routes/logs/mod.rs | 54 | ||||
| -rw-r--r-- | crates/sellershut/src/server/api/routes/mod.rs | 38 | ||||
| -rw-r--r-- | crates/sellershut/src/server/logs.rs | 36 | ||||
| -rw-r--r-- | crates/sellershut/src/server/mod.rs | 2 | ||||
| -rw-r--r-- | crates/sellershut/src/state/mod.rs | 12 |
17 files changed, 1184 insertions, 17 deletions
@@ -3,6 +3,12 @@ version = 4 [[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] name = "aho-corasick" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -68,6 +74,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] +name = "api-base" +version = "0.0.0" +dependencies = [ + "axum", + "serde", + "utoipa", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -138,6 +162,52 @@ dependencies = [ ] [[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bon" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47dbe92550676ee653353c310dfb9cf6ba17ee70396e1f7cf0a2020ad49b2fe" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" +dependencies = [ + "darling", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] name = "bytes" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -196,12 +266,140 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "miniz_oxide", + "zlib-rs", +] + +[[package]] name = "form_urlencoded" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -244,6 +442,16 @@ dependencies = [ ] [[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -336,6 +544,115 @@ dependencies = [ ] [[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] name = "indexmap" version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -343,6 +660,8 @@ checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" dependencies = [ "equivalent", "hashbrown", + "serde", + "serde_core", ] [[package]] @@ -370,6 +689,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] name = "log" version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -403,6 +728,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] name = "mio" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -423,6 +768,12 @@ dependencies = [ ] [[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + +[[package]] name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -435,6 +786,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -447,6 +804,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] name = "proc-macro2" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -465,6 +847,18 @@ dependencies = [ ] [[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] name = "regex-automata" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -482,23 +876,81 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] +name = "rust-embed" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" +dependencies = [ + "sha2", + "walkdir", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] name = "ryu" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] name = "sellershut" version = "0.1.0" dependencies = [ "anyhow", + "api-base", "axum", + "bon", "clap", "serde", "tokio", "toml", "tracing", + "tracing-appender", "tracing-subscriber", + "utoipa", + "utoipa-axum", + "utoipa-rapidoc", + "utoipa-redoc", + "utoipa-scalar", + "utoipa-swagger-ui", ] [[package]] @@ -577,6 +1029,17 @@ dependencies = [ ] [[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] name = "sharded-slab" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -586,6 +1049,12 @@ dependencies = [ ] [[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] name = "slab" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -608,6 +1077,12 @@ dependencies = [ ] [[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -631,6 +1106,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "thread_local" version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -640,6 +1146,47 @@ dependencies = [ ] [[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] name = "tokio" version = "1.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -744,6 +1291,18 @@ dependencies = [ ] [[package]] +name = "tracing-appender" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + +[[package]] name = "tracing-attributes" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -794,30 +1353,176 @@ dependencies = [ ] [[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] +name = "utoipa" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" +dependencies = [ + "indexmap", + "serde", + "serde_json", + "utoipa-gen", +] + +[[package]] +name = "utoipa-axum" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c25bae5bccc842449ec0c5ddc5cbb6a3a1eaeac4503895dc105a1138f8234a0" +dependencies = [ + "axum", + "paste", + "tower-layer", + "tower-service", + "utoipa", +] + +[[package]] +name = "utoipa-gen" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "utoipa-rapidoc" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5f8f5abd341cce16bb4f09a8bafc087d4884a004f25fb980e538d51d6501dab" +dependencies = [ + "axum", + "serde", + "serde_json", + "utoipa", +] + +[[package]] +name = "utoipa-redoc" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6427547f6db7ec006cbbef95f7565952a16f362e298b416d2d497d9706fef72d" +dependencies = [ + "axum", + "serde", + "serde_json", + "utoipa", +] + +[[package]] +name = "utoipa-scalar" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59559e1509172f6b26c1cdbc7247c4ddd1ac6560fe94b584f81ee489b141f719" +dependencies = [ + "axum", + "serde", + "serde_json", + "utoipa", +] + +[[package]] +name = "utoipa-swagger-ui" +version = "9.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d047458f1b5b65237c2f6dc6db136945667f40a7668627b3490b9513a3d43a55" +dependencies = [ + "axum", + "base64", + "mime_guess", + "regex", + "rust-embed", + "serde", + "serde_json", + "url", + "utoipa", + "zip", +] + +[[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -839,7 +1544,122 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" [[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zip" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308" +dependencies = [ + "arbitrary", + "crc32fast", + "flate2", + "indexmap", + "memchr", + "zopfli", +] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + +[[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] @@ -9,6 +9,10 @@ documentation = "https://books.kanjala.com/sellershut" homepage = "https://git.kanjala.com/sellershut" [workspace.dependencies] +api-base = { path = "./crates/api-base", version = "0.0.0" } +async-trait = "0.1.89" +axum = "0.8.8" serde = "1.0.228" thiserror = "2.0.18" tracing = "0.1.44" +utoipa = "5.4.0" diff --git a/crates/api-base/Cargo.toml b/crates/api-base/Cargo.toml new file mode 100644 index 0000000..e15c19b --- /dev/null +++ b/crates/api-base/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "api-base" +version = "0.0.0" +edition = "2024" +license.workspace = true +readme.workspace = true +documentation.workspace = true +homepage.workspace = true + +[dependencies] +axum = { workspace = true, optional = true } +serde.workspace = true +utoipa = { workspace = true, optional = true } + +[features] +axum = ["dep:axum"] +utoipa = ["dep:utoipa", "serde/derive", "axum"] diff --git a/crates/api-base/src/health/apidoc.rs b/crates/api-base/src/health/apidoc.rs new file mode 100644 index 0000000..45b8754 --- /dev/null +++ b/crates/api-base/src/health/apidoc.rs @@ -0,0 +1,12 @@ +use utoipa::OpenApi; + +use crate::Version; + +#[derive(OpenApi)] +#[openapi( + tags( + (name = "sellershut", description = "API health check"), + ), + components(schemas(Version)) +)] +pub struct ApiDocBase; diff --git a/crates/api-base/src/health/mod.rs b/crates/api-base/src/health/mod.rs new file mode 100644 index 0000000..a84dc85 --- /dev/null +++ b/crates/api-base/src/health/mod.rs @@ -0,0 +1,27 @@ +#[cfg(feature = "utoipa")] +mod apidoc; + +#[cfg(feature = "utoipa")] +pub use apidoc::*; + +#[derive(Default)] +pub struct BaseService; + +impl HealthDriver for BaseService {} + +pub trait HealthDriver: Send + Sync { + fn health(&self, app: &str, version: &str) -> String { + format!("{app} v{version} is live") + } +} + +#[cfg(test)] +mod tests { + use crate::health::{BaseService, HealthDriver}; + + #[test] + fn health() { + let app = BaseService.health(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); + assert!(app.contains("is live")); + } +} diff --git a/crates/api-base/src/lib.rs b/crates/api-base/src/lib.rs new file mode 100644 index 0000000..9c632e0 --- /dev/null +++ b/crates/api-base/src/lib.rs @@ -0,0 +1,3 @@ +pub mod health; +mod version; +pub use version::*; diff --git a/crates/api-base/src/version.rs b/crates/api-base/src/version.rs new file mode 100644 index 0000000..0652c6e --- /dev/null +++ b/crates/api-base/src/version.rs @@ -0,0 +1,45 @@ +#[derive(Debug)] +#[cfg_attr( + feature = "utoipa", + derive(utoipa::ToSchema, serde::Deserialize, serde::Serialize), + schema(example = "v0"), + serde(rename_all = "lowercase") +)] +pub enum Version { + V0, +} + +#[cfg(feature = "axum")] +mod request { + use super::*; + use axum::RequestPartsExt; + use axum::extract::{FromRequestParts, Path}; + use axum::http::StatusCode; + use axum::http::request::Parts; + use axum::response::{IntoResponse, Response}; + use std::collections::HashMap; + + impl<S> FromRequestParts<S> for Version + where + S: Send + Sync, + { + type Rejection = Response; + + async fn from_request_parts( + parts: &mut Parts, + _state: &S, + ) -> Result<Self, Self::Rejection> { + let params: Path<HashMap<String, String>> = + parts.extract().await.map_err(IntoResponse::into_response)?; + + let version = params + .get("apiVersion") + .ok_or_else(|| (StatusCode::NOT_FOUND, "version param missing").into_response())?; + + match version.as_str() { + "v0" => Ok(Version::V0), + _ => Err((StatusCode::NOT_FOUND, "unknown version").into_response()), + } + } + } +} diff --git a/crates/sellershut/Cargo.toml b/crates/sellershut/Cargo.toml index 9ded17b..f7cd15a 100644 --- a/crates/sellershut/Cargo.toml +++ b/crates/sellershut/Cargo.toml @@ -6,13 +6,29 @@ license.workspace = true readme.workspace = true documentation.workspace = true homepage.workspace = true +description = "A federated marketplace platform" [dependencies] anyhow = "1.0.102" +api-base = { workspace = true, features = ["utoipa"] } axum = { version = "0.8.8", features = ["macros"] } +bon = "3.9.1" clap = { version = "4.6.0", features = ["derive", "env"] } serde = { workspace = true, features = ["derive"] } tokio = { version = "1.51.0", features = ["macros", "rt", "rt-multi-thread"] } toml = "1.1.2" tracing.workspace = true +tracing-appender = "0.2.4" tracing-subscriber = { version = "0.3.23", features = ["env-filter"] } +utoipa = { workspace = true, features = ["axum_extras"] } +utoipa-axum = "0.2.0" +utoipa-rapidoc = { version = "6.0.0", features = ["axum"], optional = true } +utoipa-redoc = { version = "6.0.0", features = ["axum"], optional = true } +utoipa-scalar = { version = "0.3.0", features = ["axum"], optional = true } +utoipa-swagger-ui = { version = "9.0.2", features = ["axum"], optional = true } + +[features] +swagger = ["dep:utoipa-swagger-ui"] +redoc = ["dep:utoipa-redoc"] +rapidoc = ["dep:utoipa-rapidoc"] +scalar = ["dep:utoipa-scalar"] diff --git a/crates/sellershut/src/config/mod.rs b/crates/sellershut/src/config/mod.rs index b7a6ba3..d35ba1e 100644 --- a/crates/sellershut/src/config/mod.rs +++ b/crates/sellershut/src/config/mod.rs @@ -16,7 +16,7 @@ pub struct Config { config: Option<PathBuf>, /// Server configuration. #[command(flatten)] - server: server::ServerConfig, + pub server: server::ServerConfig, } impl Config { pub fn load(cli: Self) -> Result<Self> { diff --git a/crates/sellershut/src/config/server.rs b/crates/sellershut/src/config/server.rs index 08b7828..3680c16 100644 --- a/crates/sellershut/src/config/server.rs +++ b/crates/sellershut/src/config/server.rs @@ -8,18 +8,18 @@ use serde::{Deserialize, Serialize}; pub struct ServerConfig { /// Port the application server listens on. #[arg(short, long, env = "HUT_SERVER_PORT")] - port: Option<u16>, + pub port: Option<u16>, /// Request timeout duration #[arg(long, env = "HUT_SERVER_TIMEOUT_SECS")] - timeout_duration: Option<u64>, + pub timeout_duration: Option<u64>, /// Log level for the application server. - #[arg(long, env = "HUT_SERVER_LOG_LEVEL")] - log_level: Option<String>, + #[arg(long, env = "HUT_LOG")] + pub log_level: Option<String>, /// Directory where log files should be written. #[arg(long, env = "HUT_SERVER_LOG_FILE_DIRECTORY")] - log_directory: Option<PathBuf>, + pub log_directory: Option<PathBuf>, } impl ServerConfig { diff --git a/crates/sellershut/src/main.rs b/crates/sellershut/src/main.rs index 900d554..cb7be07 100644 --- a/crates/sellershut/src/main.rs +++ b/crates/sellershut/src/main.rs @@ -1,24 +1,50 @@ mod config; +mod server; +mod state; -use anyhow::Result; +use std::{ + net::{Ipv6Addr, SocketAddr}, + sync::Arc, +}; + +use anyhow::{Context, Result}; +use api_base::health::BaseService; use clap::Parser; +use tokio::net::TcpListener; +use tracing::info; -use crate::config::cli; +use crate::{config::cli, state::AppState}; #[tokio::main] async fn main() -> Result<()> { let cli = cli::Cli::parse(); - match cli.command { - Some(cli::Commands::GenerateConfig { dir, file_name }) => { - let path = config::generate_config_file(&dir, &file_name)?; - println!("Wrote {}", path.display()); - } - None => { - let cfg = config::Config::load(cli.config)?; - println!("{cfg:#?}"); - } + if let Some(cli::Commands::GenerateConfig { dir, file_name }) = cli.command { + let path = config::generate_config_file(&dir, &file_name)?; + println!("Wrote {}", path.display()); + return Ok(()); } + let cfg = config::Config::load(cli.config)?; + let (log_handle, _log_guard) = server::logs::initialise_logging( + cfg.server.log_level.as_deref(), + cfg.server.log_directory.as_ref(), + )?; + + let state = AppState::builder() + .log_handle(log_handle) + .base_service(Arc::new(BaseService)) + .build(); + let addr = SocketAddr::from(( + Ipv6Addr::UNSPECIFIED, + cfg.server.port.context("missing port")?, + )); + + let app = server::api::router(state, cfg).await; + + let listener = TcpListener::bind(addr).await?; + info!(addr = ?listener.local_addr().unwrap(), "starting server"); + + axum::serve(listener, app).await?; Ok(()) } diff --git a/crates/sellershut/src/server/api/mod.rs b/crates/sellershut/src/server/api/mod.rs new file mode 100644 index 0000000..0fd48c6 --- /dev/null +++ b/crates/sellershut/src/server/api/mod.rs @@ -0,0 +1,55 @@ +use api_base::health::ApiDocBase; +use axum::Router; +use utoipa::OpenApi; +use utoipa_axum::router::OpenApiRouter; + +use crate::{config::Config, server::api::routes::ServerConfigDoc, state::AppState}; + +pub mod routes; + +#[derive(OpenApi)] +#[openapi( + tags( + (name = "sellershut", description = env!("CARGO_PKG_DESCRIPTION")), + ), +)] +pub struct ApiDoc; + +pub async fn router(state: AppState, config: Config) -> Router<()> { + let mut doc = ApiDoc::openapi(); + + doc.merge(ApiDocBase::openapi()); + doc.merge(ServerConfigDoc::openapi()); + + let stubs = OpenApiRouter::with_openapi(doc) + .routes(utoipa_axum::routes!(routes::health)) + .nest("/api", routes::router(state.clone())) + .with_state(state); + + let (router, _api) = stubs.split_for_parts(); + + #[cfg(feature = "swagger")] + let router = router.merge( + utoipa_swagger_ui::SwaggerUi::new("/swagger-ui") + .url("/api-docs/swaggerdoc.json", _api.clone()), + ); + + #[cfg(feature = "redoc")] + let router = { + use utoipa_redoc::Servable as _; + router.merge(utoipa_redoc::Redoc::with_url("/redoc", _api.clone())) + }; + + #[cfg(feature = "scalar")] + let router = { + use utoipa_scalar::Servable as _; + router.merge(utoipa_scalar::Scalar::with_url("/scalar", _api.clone())) + }; + + #[cfg(feature = "rapidoc")] + let router = router.merge( + utoipa_rapidoc::RapiDoc::with_openapi("/api-docs/rapidoc.json", _api).path("/rapidoc"), + ); + + router +} diff --git a/crates/sellershut/src/server/api/routes/logs/mod.rs b/crates/sellershut/src/server/api/routes/logs/mod.rs new file mode 100644 index 0000000..8718d86 --- /dev/null +++ b/crates/sellershut/src/server/api/routes/logs/mod.rs @@ -0,0 +1,54 @@ +use axum::{Json, extract::State, http::StatusCode}; +use serde::Deserialize; +use tracing::warn; +use utoipa::ToSchema; + +use crate::state::AppState; + +#[derive(Deserialize, Debug, Clone, ToSchema)] +/// Log level +#[serde(rename_all = "camelCase")] +pub struct LogLevel { + #[schema(examples("info", "trace", "warden=debug,tower_http=debug,axum::rejection=trace"))] + log_level: String, +} + +/// Update log level +#[utoipa::path( + patch, + responses( + ( + status = 200, + description = "Server's log level has been updated", + headers( + ("x-request-id", description = "Request identifier") + ) + ), + ( + status = 400, + description = "Invalid log level", + headers( + ("x-request-id", description = "Request identifier") + ) + ), + ), + operation_id = "log_update", // https://github.com/juhaku/utoipa/issues/1170 + path = "/logging", + tag = super::CONFIG, + request_body( + content = LogLevel + ) +)] +pub async fn reload(State(state): State<AppState>, Json(body): Json<LogLevel>) -> StatusCode { + if let Ok(value) = body.log_level.parse::<tracing_subscriber::EnvFilter>() { + match state.log_handle.reload(value) { + Ok(_) => StatusCode::OK, + Err(e) => { + warn!("{e:?}"); + StatusCode::INTERNAL_SERVER_ERROR + } + } + } else { + StatusCode::BAD_REQUEST + } +} diff --git a/crates/sellershut/src/server/api/routes/mod.rs b/crates/sellershut/src/server/api/routes/mod.rs new file mode 100644 index 0000000..f343742 --- /dev/null +++ b/crates/sellershut/src/server/api/routes/mod.rs @@ -0,0 +1,38 @@ +mod logs; + +use axum::{extract::State, response::IntoResponse}; + +use crate::state::AppState; + +use utoipa::OpenApi; +use utoipa_axum::router::OpenApiRouter; + +const CONFIG: &str = "Server configuration"; + +#[derive(OpenApi)] +#[openapi(tags((name = CONFIG, description = "Configuration endpoints")))] +pub struct ServerConfigDoc; + +pub fn router(state: AppState) -> OpenApiRouter<AppState> { + OpenApiRouter::new() + .routes(utoipa_axum::routes!(logs::reload)) + .with_state(state) +} + +/// Health +#[utoipa::path( + method(get, head), + path = "/api/health", + responses( + ( + status = OK, description = "API is live", + body = Option<str>, content_type = "text/plain", + ) + ), + tag = "sellershut" +)] +pub async fn health(State(state): State<AppState>) -> impl IntoResponse { + state + .base_service + .health(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")) +} diff --git a/crates/sellershut/src/server/logs.rs b/crates/sellershut/src/server/logs.rs new file mode 100644 index 0000000..edb698b --- /dev/null +++ b/crates/sellershut/src/server/logs.rs @@ -0,0 +1,36 @@ +use anyhow::{Context, Result}; +use std::{env, path::PathBuf}; +use tracing_appender::rolling::{RollingFileAppender, Rotation}; +use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt}; + +pub type LogHandle = tracing_subscriber::reload::Handle<EnvFilter, tracing_subscriber::Registry>; + +pub fn initialise_logging( + level: Option<&str>, + log_dir: Option<&PathBuf>, +) -> Result<(LogHandle, tracing_appender::non_blocking::WorkerGuard)> { + let level = level.context("missing log level")?; + let log_dir = log_dir.context("missing log dir")?; + + let file_appender = RollingFileAppender::new(Rotation::DAILY, log_dir, env!("CARGO_PKG_NAME")); + + let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); + + let env_filter = + tracing_subscriber::EnvFilter::try_from_env("HUT_LOG").unwrap_or_else(|_| level.into()); + + let (filter_layer, reload_handle) = tracing_subscriber::reload::Layer::new(env_filter); + + let file_layer = tracing_subscriber::fmt::layer() + .with_writer(non_blocking) + .with_ansi(false) + .with_target(true); + + tracing_subscriber::registry() + .with(filter_layer) + .with(tracing_subscriber::fmt::layer()) + .with(file_layer) + .init(); + + Ok((reload_handle, guard)) +} diff --git a/crates/sellershut/src/server/mod.rs b/crates/sellershut/src/server/mod.rs new file mode 100644 index 0000000..f669af9 --- /dev/null +++ b/crates/sellershut/src/server/mod.rs @@ -0,0 +1,2 @@ +pub mod api; +pub mod logs; diff --git a/crates/sellershut/src/state/mod.rs b/crates/sellershut/src/state/mod.rs new file mode 100644 index 0000000..067cc62 --- /dev/null +++ b/crates/sellershut/src/state/mod.rs @@ -0,0 +1,12 @@ +use std::sync::Arc; + +use api_base::health::HealthDriver; +use bon::Builder; + +use crate::server::logs::LogHandle; + +#[derive(Clone, Builder)] +pub struct AppState { + pub base_service: Arc<dyn HealthDriver>, + pub log_handle: LogHandle, +} |
