From bac76a98bf4e90610d0a7105d2ebe6872dc147d4 Mon Sep 17 00:00:00 2001 From: rtkay123 Date: Mon, 9 Feb 2026 13:25:17 +0200 Subject: feat: svc crate --- Cargo.lock | 891 ++++++++++++++++++++++++++++++++++- Cargo.toml | 11 + lib/auth-service/Cargo.toml | 7 +- lib/auth-service/src/client/mod.rs | 5 +- lib/auth-service/src/lib.rs | 2 + lib/auth-service/src/service/mod.rs | 51 ++ lib/shared-svc/Cargo.toml | 28 ++ lib/shared-svc/src/cache/cluster.rs | 58 +++ lib/shared-svc/src/cache/config.rs | 18 + lib/shared-svc/src/cache/mod.rs | 250 ++++++++++ lib/shared-svc/src/cache/sentinel.rs | 67 +++ lib/shared-svc/src/lib.rs | 16 + sellershut/Cargo.toml | 1 + sellershut/sellershut.toml | 3 + sellershut/src/config/cli/cache.rs | 118 +++++ sellershut/src/config/cli/mod.rs | 4 + sellershut/src/config/mod.rs | 84 +++- sellershut/src/logging/mod.rs | 2 +- sellershut/src/main.rs | 3 + sellershut/src/state/mod.rs | 32 +- 20 files changed, 1629 insertions(+), 22 deletions(-) create mode 100644 lib/auth-service/src/service/mod.rs create mode 100644 lib/shared-svc/Cargo.toml create mode 100644 lib/shared-svc/src/cache/cluster.rs create mode 100644 lib/shared-svc/src/cache/config.rs create mode 100644 lib/shared-svc/src/cache/mod.rs create mode 100644 lib/shared-svc/src/cache/sentinel.rs create mode 100644 lib/shared-svc/src/lib.rs create mode 100644 sellershut/src/config/cli/cache.rs diff --git a/Cargo.lock b/Cargo.lock index 6d62eee..17ebca4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -76,6 +82,83 @@ version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +[[package]] +name = "arc-swap" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ded5f9a03ac8f24d1b8a25101ee812cd32cdc8c50a4c50237de2c4915850e73" +dependencies = [ + "rustversion", +] + +[[package]] +name = "arcstr" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-session" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da4ce523b4e2ebaaf330746761df23a465b951a83d84bbce4233dabedae630" +dependencies = [ + "anyhow", + "async-lock", + "async-trait", + "base64 0.13.1", + "bincode", + "blake3", + "chrono", + "hmac 0.11.0", + "log", + "rand 0.8.5", + "serde", + "serde_json", + "sha2 0.9.9", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -86,9 +169,14 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" name = "auth-service" version = "0.1.0" dependencies = [ + "async-session", + "async-trait", "oauth2", "secrecy", + "shared-svc", + "sqlx", "thiserror 2.0.18", + "time", "tracing", "url", ] @@ -151,18 +239,88 @@ dependencies = [ "tracing", ] +[[package]] +name = "backon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +dependencies = [ + "fastrand", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bb8" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457d7ed3f888dfd2c7af56d4975cade43c622f74bdcddfed6d4352f57acc6310" +dependencies = [ + "futures-util", + "parking_lot", + "portable-atomic", + "tokio", +] + +[[package]] +name = "bb8-redis" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1063effc7f6cf848bcbcc6e31b5962be75215835587d3109607c643d616f66" +dependencies = [ + "bb8", + "redis", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +[[package]] +name = "blake3" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if 0.1.10", + "constant_time_eq", + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -178,6 +336,12 @@ version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.11.1" @@ -194,6 +358,12 @@ dependencies = [ "shlex", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.4" @@ -266,6 +436,35 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -281,6 +480,27 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc16" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338089f42c427b86394a5ee60ff321da23a5c89c9d89514c829687b26359fcff" + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -290,6 +510,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -306,6 +535,26 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "deranged" version = "0.5.5" @@ -315,14 +564,24 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "crypto-common", + "subtle", ] [[package]] @@ -336,6 +595,21 @@ dependencies = [ "syn", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -352,12 +626,52 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if 1.0.4", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -374,6 +688,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -382,6 +697,29 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + [[package]] name = "futures-task" version = "0.3.31" @@ -395,7 +733,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", + "futures-io", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -417,7 +758,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "js-sys", "libc", "wasi", @@ -430,7 +771,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "js-sys", "libc", "r-efi", @@ -438,18 +779,81 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + [[package]] name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "http" version = "1.4.0" @@ -531,7 +935,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 1.0.6", ] [[package]] @@ -540,7 +944,7 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-util", @@ -690,7 +1094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", ] [[package]] @@ -743,12 +1147,32 @@ version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags", + "libc", + "redox_syscall 0.7.0", +] + [[package]] name = "litemap" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.29" @@ -776,6 +1200,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if 1.0.4", + "digest 0.10.7", +] + [[package]] name = "memchr" version = "2.8.0" @@ -808,12 +1242,31 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-conv" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -829,7 +1282,7 @@ version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "getrandom 0.2.17", "http", @@ -838,7 +1291,7 @@ dependencies = [ "serde", "serde_json", "serde_path_to_error", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "url", ] @@ -855,6 +1308,41 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if 1.0.4", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -873,6 +1361,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + [[package]] name = "potential_utf" version = "0.1.4" @@ -1035,6 +1529,54 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "redis" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e969d1d702793536d5fda739a82b88ad7cbe7d04f8386ee8cd16ad3eff4854a5" +dependencies = [ + "arc-swap", + "arcstr", + "backon", + "bytes", + "cfg-if 1.0.4", + "combine", + "crc16", + "futures-channel", + "futures-util", + "itoa", + "log", + "num-bigint", + "percent-encoding", + "pin-project-lite", + "rand 0.9.2", + "ryu", + "sha1_smol", + "socket2", + "tokio", + "tokio-util", + "url", + "xxhash-rust", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +dependencies = [ + "bitflags", +] + [[package]] name = "regex-automata" version = "0.4.14" @@ -1058,7 +1600,7 @@ version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-core", "http", @@ -1087,7 +1629,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 1.0.6", ] [[package]] @@ -1097,7 +1639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.4", "getrandom 0.2.17", "libc", "untrusted", @@ -1157,6 +1699,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "secrecy" version = "0.10.3" @@ -1177,6 +1725,7 @@ dependencies = [ "clap", "secrecy", "serde", + "shared-svc", "tokio", "toml", "tracing", @@ -1260,15 +1809,34 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.4", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + [[package]] name = "sha2" version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -1280,6 +1848,20 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared-svc" +version = "0.1.0" +dependencies = [ + "bb8-redis", + "log", + "redis", + "secrecy", + "thiserror 2.0.18", + "tokio", + "tracing", + "url", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1307,6 +1889,9 @@ name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1318,12 +1903,143 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "sqlx" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-postgres", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64 0.22.1", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener 5.4.1", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.5", + "hashlink", + "indexmap", + "log", + "memchr", + "once_cell", + "percent-encoding", + "rustls", + "serde", + "serde_json", + "sha2 0.10.9", + "smallvec", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tracing", + "url", + "webpki-roots 0.26.11", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "sqlx-core", + "sqlx-postgres", + "syn", + "tokio", + "url", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac 0.12.1", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2 0.10.9", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.18", + "tracing", + "whoami", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "strsim" version = "0.11.1" @@ -1413,7 +2129,7 @@ version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -1481,6 +2197,7 @@ dependencies = [ "bytes", "libc", "mio", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -1509,6 +2226,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.9.11+spec-1.1.0" @@ -1680,12 +2421,33 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + [[package]] name = "untrusted" version = "0.9.0" @@ -1753,13 +2515,19 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "once_cell", "rustversion", "wasm-bindgen-macro", @@ -1772,7 +2540,7 @@ version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "futures-util", "js-sys", "once_cell", @@ -1832,6 +2600,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + [[package]] name = "webpki-roots" version = "1.0.6" @@ -1841,6 +2618,16 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -1900,6 +2687,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -1927,6 +2723,21 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -1960,6 +2771,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -1972,6 +2789,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -1984,6 +2807,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -2008,6 +2837,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -2020,6 +2855,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -2032,6 +2873,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -2044,6 +2891,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -2074,6 +2927,12 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "yoke" version = "0.8.1" diff --git a/Cargo.toml b/Cargo.toml index 315004b..1dab827 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,20 @@ readme = "README.md" documentation = "https://books.kanjala.com/sellershut" [workspace.dependencies] +async-trait = "0.1.89" secrecy = "0.10.3" serde = "1.0.228" +shared-svc = { path = "lib/shared-svc" } thiserror = "2.0.18" +time = "0.3.47" tokio = "1.49.0" tracing = "0.1.44" url = "2.5.8" + +[workspace.dependencies.sqlx] +version = "0.8.6" +default-features = false +features = ["macros", "postgres", "runtime-tokio-rustls"] + +[profile.dev.package.sqlx-macros] +opt-level = 3 diff --git a/lib/auth-service/Cargo.toml b/lib/auth-service/Cargo.toml index 8efdc57..e972312 100644 --- a/lib/auth-service/Cargo.toml +++ b/lib/auth-service/Cargo.toml @@ -7,8 +7,13 @@ readme.workspace = true documentation.workspace = true [dependencies] -secrecy = "0.10.3" +async-session = "3.0.0" +async-trait.workspace = true oauth2 = "5.0.0" +secrecy = "0.10.3" +shared-svc = { workspace = true, features = ["cache"] } +sqlx.workspace = true thiserror.workspace = true +time.workspace = true tracing.workspace = true url = { workspace = true, features = ["serde"] } diff --git a/lib/auth-service/src/client/mod.rs b/lib/auth-service/src/client/mod.rs index af581b0..45e7e4d 100644 --- a/lib/auth-service/src/client/mod.rs +++ b/lib/auth-service/src/client/mod.rs @@ -5,6 +5,7 @@ use url::Url; use crate::AuthServiceError; +#[derive(Debug, Clone)] pub struct OauthClient( oauth2::basic::BasicClient< EndpointSet, @@ -38,10 +39,10 @@ impl ClientConfig { } } -impl TryFrom for OauthClient { +impl TryFrom<&ClientConfig> for OauthClient { type Error = AuthServiceError; - fn try_from(value: ClientConfig) -> Result { + fn try_from(value: &ClientConfig) -> Result { debug!("creating oauth client"); Ok(Self( oauth2::basic::BasicClient::new(ClientId::new(value.client_id.to_string())) diff --git a/lib/auth-service/src/lib.rs b/lib/auth-service/src/lib.rs index f7b9e80..308ce0f 100644 --- a/lib/auth-service/src/lib.rs +++ b/lib/auth-service/src/lib.rs @@ -1,4 +1,6 @@ pub mod client; +mod service; +pub use service::*; use thiserror::Error; diff --git a/lib/auth-service/src/service/mod.rs b/lib/auth-service/src/service/mod.rs new file mode 100644 index 0000000..3d45523 --- /dev/null +++ b/lib/auth-service/src/service/mod.rs @@ -0,0 +1,51 @@ +use async_session::{Result, Session, SessionStore}; +use async_trait::async_trait; +use shared_svc::cache::RedisManager; +use tracing::instrument; + +#[derive(Debug, Clone)] +pub struct AuthService { + cache: RedisManager, +} + +impl AuthService { + pub fn new(cache: &RedisManager) -> Self { + Self { + cache: cache.clone(), + } + } +} + +#[async_trait] +impl SessionStore for AuthService { + #[doc = " Get a session from the storage backend."] + #[doc = ""] + #[doc = " The input is expected to be the value of an identifying"] + #[doc = " cookie. This will then be parsed by the session middleware"] + #[doc = " into a session if possible"] + #[instrument(skip(self))] + async fn load_session(&self, cookie_value: String) -> Result> { + todo!() + } + + #[doc = " Store a session on the storage backend."] + #[doc = ""] + #[doc = " The return value is the value of the cookie to store for the"] + #[doc = " user that represents this session"] + #[instrument(skip(self))] + async fn store_session(&self, session: Session) -> Result> { + todo!() + } + + #[doc = " Remove a session from the session store"] + #[instrument(skip(self))] + async fn destroy_session(&self, session: Session) -> Result { + todo!() + } + + #[doc = " Empties the entire store, destroying all sessions"] + #[instrument(skip(self))] + async fn clear_store(&self) -> Result { + todo!() + } +} diff --git a/lib/shared-svc/Cargo.toml b/lib/shared-svc/Cargo.toml new file mode 100644 index 0000000..d95d3ef --- /dev/null +++ b/lib/shared-svc/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "shared-svc" +version = "0.1.0" +edition = "2024" +license.workspace = true +readme.workspace = true +documentation.workspace = true + +[dependencies] +bb8-redis = { version = "0.26.0", optional = true } +log = "0.4.29" +redis = { version = "1.0.3", optional = true } +secrecy.workspace = true +thiserror.workspace = true +tokio = { workspace = true, optional = true } +tracing.workspace = true +url.workspace = true + +[features] +default = [] +cache = [ + "bb8-redis", + "redis/cluster-async", + "redis/connection-manager", + "redis/sentinel", + "redis/tokio-comp", + "tokio/sync" +] diff --git a/lib/shared-svc/src/cache/cluster.rs b/lib/shared-svc/src/cache/cluster.rs new file mode 100644 index 0000000..ea71954 --- /dev/null +++ b/lib/shared-svc/src/cache/cluster.rs @@ -0,0 +1,58 @@ +use bb8_redis::bb8; +use redis::{ + ErrorKind, FromRedisValue, IntoConnectionInfo, RedisError, + cluster::{ClusterClient, ClusterClientBuilder}, + cluster_routing::{MultipleNodeRoutingInfo, ResponsePolicy, RoutingInfo}, +}; + +/// ConnectionManager that implements `bb8::ManageConnection` and supports +/// asynchronous clustered connections via `redis_cluster_async::Connection` +#[derive(Clone)] +pub struct RedisClusterConnectionManager { + client: ClusterClient, +} + +impl RedisClusterConnectionManager { + pub fn new( + info: T, + ) -> Result { + Ok(RedisClusterConnectionManager { + client: ClusterClientBuilder::new(vec![info]).retries(0).build()?, + }) + } +} + +impl bb8::ManageConnection for RedisClusterConnectionManager { + type Connection = redis::cluster_async::ClusterConnection; + type Error = RedisError; + + async fn connect(&self) -> Result { + self.client.get_async_connection().await + } + + async fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error> { + let cmd = redis::cmd("PING"); + let pong = conn + .route_command( + cmd, + RoutingInfo::MultiNode(( + MultipleNodeRoutingInfo::AllMasters, + Some(ResponsePolicy::OneSucceeded), + )), + ) + .await + .and_then(|v| Ok(String::from_redis_value(v)?))?; + match pong.as_str() { + "PONG" => Ok(()), + _ => Err(( + ErrorKind::Server(redis::ServerErrorKind::ResponseError), + "ping request", + ) + .into()), + } + } + + fn has_broken(&self, _: &mut Self::Connection) -> bool { + false + } +} diff --git a/lib/shared-svc/src/cache/config.rs b/lib/shared-svc/src/cache/config.rs new file mode 100644 index 0000000..79a80d7 --- /dev/null +++ b/lib/shared-svc/src/cache/config.rs @@ -0,0 +1,18 @@ +use url::Url; + +use crate::cache::sentinel::SentinelConfig; + +#[derive(Debug, Clone)] +pub struct CacheConfig { + pub redis_dsn: Url, + pub pooled: bool, + pub kind: RedisVariant, + pub max_connections: u16, +} + +#[derive(Debug, Clone)] +pub enum RedisVariant { + Clustered, + NonClustered, + Sentinel(SentinelConfig), +} diff --git a/lib/shared-svc/src/cache/mod.rs b/lib/shared-svc/src/cache/mod.rs new file mode 100644 index 0000000..cd15463 --- /dev/null +++ b/lib/shared-svc/src/cache/mod.rs @@ -0,0 +1,250 @@ +mod cluster; +mod config; +mod sentinel; +pub use sentinel::SentinelConfig; + +pub use config::*; + +use redis::{ + AsyncConnectionConfig, ProtocolVersion, RedisConnectionInfo, RedisError, TlsMode, + aio::ConnectionManagerConfig, sentinel::SentinelNodeConnectionInfo, +}; +use secrecy::ExposeSecret; +use std::{fmt::Debug, sync::Arc}; +use tracing::debug; + +use bb8_redis::{ + RedisConnectionManager, + bb8::{self, Pool, RunError}, +}; +use tokio::sync::Mutex; + +use crate::{ + ServiceError, + cache::{cluster::RedisClusterConnectionManager, sentinel::RedisSentinelConnectionManager}, +}; + +const REDIS_CONN_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(2); + +#[derive(Clone)] +pub enum RedisManager { + Clustered(Pool), + NonClustered(Pool), + Sentinel(Pool), + ClusteredUnpooled(redis::cluster_async::ClusterConnection), + NonClusteredUnpooled(redis::aio::ConnectionManager), + SentinelUnpooled(Arc>), +} + +impl Debug for RedisManager { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Clustered(arg0) => f.debug_tuple("Clustered").field(arg0).finish(), + Self::NonClustered(arg0) => f.debug_tuple("NonClustered").field(arg0).finish(), + Self::Sentinel(arg0) => f.debug_tuple("Sentinel").field(arg0).finish(), + Self::ClusteredUnpooled(_arg0) => f.debug_tuple("ClusteredUnpooled").finish(), + Self::NonClusteredUnpooled(arg0) => { + f.debug_tuple("NonClusteredUnpooled").field(arg0).finish() + } + Self::SentinelUnpooled(_arg0) => f.debug_tuple("SentinelUnpooled").finish(), + } + } +} + +pub enum RedisConnection<'a> { + Clustered(bb8::PooledConnection<'a, RedisClusterConnectionManager>), + NonClustered(bb8::PooledConnection<'a, RedisConnectionManager>), + SentinelPooled(bb8::PooledConnection<'a, RedisSentinelConnectionManager>), + ClusteredUnpooled(redis::cluster_async::ClusterConnection), + NonClusteredUnpooled(redis::aio::ConnectionManager), + SentinelUnpooled(redis::aio::MultiplexedConnection), +} + +impl redis::aio::ConnectionLike for RedisConnection<'_> { + fn req_packed_command<'a>( + &'a mut self, + cmd: &'a redis::Cmd, + ) -> redis::RedisFuture<'a, redis::Value> { + match self { + RedisConnection::Clustered(conn) => conn.req_packed_command(cmd), + RedisConnection::NonClustered(conn) => conn.req_packed_command(cmd), + RedisConnection::ClusteredUnpooled(conn) => conn.req_packed_command(cmd), + RedisConnection::NonClusteredUnpooled(conn) => conn.req_packed_command(cmd), + RedisConnection::SentinelPooled(conn) => conn.req_packed_command(cmd), + RedisConnection::SentinelUnpooled(conn) => conn.req_packed_command(cmd), + } + } + + fn req_packed_commands<'a>( + &'a mut self, + cmd: &'a redis::Pipeline, + offset: usize, + count: usize, + ) -> redis::RedisFuture<'a, Vec> { + match self { + RedisConnection::Clustered(conn) => conn.req_packed_commands(cmd, offset, count), + RedisConnection::NonClustered(conn) => conn.req_packed_commands(cmd, offset, count), + RedisConnection::ClusteredUnpooled(conn) => { + conn.req_packed_commands(cmd, offset, count) + } + RedisConnection::NonClusteredUnpooled(conn) => { + conn.req_packed_commands(cmd, offset, count) + } + RedisConnection::SentinelPooled(conn) => conn.req_packed_commands(cmd, offset, count), + RedisConnection::SentinelUnpooled(conn) => conn.req_packed_commands(cmd, offset, count), + } + } + + fn get_db(&self) -> i64 { + match self { + RedisConnection::Clustered(conn) => conn.get_db(), + RedisConnection::NonClustered(conn) => conn.get_db(), + RedisConnection::ClusteredUnpooled(conn) => conn.get_db(), + RedisConnection::NonClusteredUnpooled(conn) => conn.get_db(), + RedisConnection::SentinelPooled(conn) => conn.get_db(), + RedisConnection::SentinelUnpooled(conn) => conn.get_db(), + } + } +} + +impl RedisManager { + pub async fn new(config: &CacheConfig) -> Result { + let u = config.redis_dsn.host_str(); + debug!(url = u, "connecting to cache"); + if config.pooled { + Self::new_pooled( + config.redis_dsn.as_ref(), + &config.kind, + config.max_connections, + ) + .await + } else { + Self::new_unpooled(config.redis_dsn.as_ref(), &config.kind).await + } + } + async fn new_pooled( + dsn: &str, + variant: &RedisVariant, + max_conns: u16, + ) -> Result { + debug!(variant = ?variant, "creating pooled cache connection"); + match variant { + RedisVariant::Clustered => { + let mgr = RedisClusterConnectionManager::new(dsn)?; + let pool = bb8::Pool::builder() + .max_size(max_conns.into()) + .build(mgr) + .await?; + Ok(RedisManager::Clustered(pool)) + } + RedisVariant::NonClustered => { + let mgr = RedisConnectionManager::new(dsn)?; + let pool = bb8::Pool::builder() + .max_size(max_conns.into()) + .build(mgr) + .await?; + Ok(RedisManager::NonClustered(pool)) + } + RedisVariant::Sentinel(cfg) => { + let mgr = RedisSentinelConnectionManager::new( + vec![dsn], + cfg.service_name.clone(), + Some(create_config(cfg)), + )?; + let pool = bb8::Pool::builder() + .max_size(max_conns.into()) + .build(mgr) + .await?; + Ok(RedisManager::Sentinel(pool)) + } + } + } + + async fn new_unpooled(dsn: &str, variant: &RedisVariant) -> Result { + match variant { + RedisVariant::Clustered => { + let cli = redis::cluster::ClusterClient::builder(vec![dsn]) + .retries(1) + .connection_timeout(REDIS_CONN_TIMEOUT) + .build()?; + let con = cli.get_async_connection().await?; + Ok(RedisManager::ClusteredUnpooled(con)) + } + RedisVariant::NonClustered => { + let cli = redis::Client::open(dsn)?; + let con = redis::aio::ConnectionManager::new_with_config( + cli, + ConnectionManagerConfig::new() + .set_number_of_retries(1) + .set_connection_timeout(Some(REDIS_CONN_TIMEOUT)), + ) + .await?; + Ok(RedisManager::NonClusteredUnpooled(con)) + } + RedisVariant::Sentinel(cfg) => { + let cli = redis::sentinel::SentinelClient::build( + vec![dsn], + cfg.service_name.clone(), + Some(create_config(cfg)), + redis::sentinel::SentinelServerType::Master, + )?; + + Ok(RedisManager::SentinelUnpooled(Arc::new(Mutex::new(cli)))) + } + } + } + + pub async fn get(&self) -> Result, RunError> { + match self { + Self::Clustered(pool) => Ok(RedisConnection::Clustered(pool.get().await?)), + Self::NonClustered(pool) => Ok(RedisConnection::NonClustered(pool.get().await?)), + Self::Sentinel(pool) => Ok(RedisConnection::SentinelPooled(pool.get().await?)), + Self::ClusteredUnpooled(conn) => Ok(RedisConnection::ClusteredUnpooled(conn.clone())), + Self::NonClusteredUnpooled(conn) => { + Ok(RedisConnection::NonClusteredUnpooled(conn.clone())) + } + Self::SentinelUnpooled(conn) => { + let mut conn = conn.lock().await; + let con = conn + .get_async_connection_with_config( + &AsyncConnectionConfig::new() + .set_response_timeout(Some(REDIS_CONN_TIMEOUT)), + ) + .await?; + Ok(RedisConnection::SentinelUnpooled(con)) + } + } + } +} + +fn create_config(cfg: &SentinelConfig) -> SentinelNodeConnectionInfo { + let tls_mode = cfg.redis_tls_mode_secure.then_some(TlsMode::Secure); + let protocol = if cfg.redis_use_resp3 { + ProtocolVersion::RESP3 + } else { + ProtocolVersion::default() + }; + let info = RedisConnectionInfo::default(); + let info = if let Some(pass) = &cfg.redis_password { + info.set_password(pass.expose_secret()) + } else { + info + }; + + let info = if let Some(user) = &cfg.redis_username { + info.set_username(user.clone()) + } else { + info + } + .set_protocol(protocol) + .set_db(cfg.redis_db.unwrap_or(0)); + + let sent_info = SentinelNodeConnectionInfo::default(); + + if let Some(tls) = tls_mode { + sent_info.set_tls_mode(tls) + } else { + sent_info + } + .set_redis_connection_info(info) +} diff --git a/lib/shared-svc/src/cache/sentinel.rs b/lib/shared-svc/src/cache/sentinel.rs new file mode 100644 index 0000000..9e76423 --- /dev/null +++ b/lib/shared-svc/src/cache/sentinel.rs @@ -0,0 +1,67 @@ +use bb8_redis::bb8; +use redis::{ + ErrorKind, IntoConnectionInfo, RedisError, + sentinel::{SentinelClient, SentinelNodeConnectionInfo, SentinelServerType}, +}; +use secrecy::SecretString; +use tokio::sync::Mutex; + +struct LockedSentinelClient(pub(crate) Mutex); + +/// ConnectionManager that implements `bb8::ManageConnection` and supports +/// asynchronous Sentinel connections via `redis::sentinel::SentinelClient` +pub struct RedisSentinelConnectionManager { + client: LockedSentinelClient, +} + +impl RedisSentinelConnectionManager { + pub fn new( + info: Vec, + service_name: String, + node_connection_info: Option, + ) -> Result { + Ok(RedisSentinelConnectionManager { + client: LockedSentinelClient(Mutex::new(SentinelClient::build( + info, + service_name, + node_connection_info, + SentinelServerType::Master, + )?)), + }) + } +} + +impl bb8::ManageConnection for RedisSentinelConnectionManager { + type Connection = redis::aio::MultiplexedConnection; + type Error = RedisError; + + async fn connect(&self) -> Result { + self.client.0.lock().await.get_async_connection().await + } + + async fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error> { + let pong: String = redis::cmd("PING").query_async(conn).await?; + match pong.as_str() { + "PONG" => Ok(()), + _ => Err(( + ErrorKind::Server(redis::ServerErrorKind::ResponseError), + "ping request", + ) + .into()), + } + } + + fn has_broken(&self, _: &mut Self::Connection) -> bool { + false + } +} + +#[derive(Clone, Debug)] +pub struct SentinelConfig { + pub service_name: String, + pub redis_tls_mode_secure: bool, + pub redis_db: Option, + pub redis_username: Option, + pub redis_password: Option, + pub redis_use_resp3: bool, +} diff --git a/lib/shared-svc/src/lib.rs b/lib/shared-svc/src/lib.rs new file mode 100644 index 0000000..92d9c32 --- /dev/null +++ b/lib/shared-svc/src/lib.rs @@ -0,0 +1,16 @@ +#[cfg(feature = "cache")] +pub mod cache; + +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ServiceError { + #[error("data store disconnected")] + Cache(#[from] redis::RedisError), + #[error("the data for key `{0}` is not available")] + Redaction(String), + #[error("invalid header (expected {expected:?}, found {found:?})")] + InvalidHeader { expected: String, found: String }, + #[error("unknown data store error")] + Unknown, +} diff --git a/sellershut/Cargo.toml b/sellershut/Cargo.toml index 5ad7438..9adb37f 100644 --- a/sellershut/Cargo.toml +++ b/sellershut/Cargo.toml @@ -13,6 +13,7 @@ axum = "0.8.8" clap = { version = "4.5.57", features = ["derive", "env"] } secrecy = { workspace = true, features = ["serde"] } serde = { workspace = true, features = ["derive"] } +shared-svc.workspace = true toml = "0.9.11" tracing.workspace = true tracing-appender = "0.2.4" diff --git a/sellershut/sellershut.toml b/sellershut/sellershut.toml index 32add09..3cdc7ab 100644 --- a/sellershut/sellershut.toml +++ b/sellershut/sellershut.toml @@ -7,6 +7,9 @@ log-level = "trace" url = "http://localhost:5432" pool-size = 10 +[cache] +url = "redis://localhost:6379" + [oauth] redirect-url = "http://localhost:2210" diff --git a/sellershut/src/config/cli/cache.rs b/sellershut/src/config/cli/cache.rs new file mode 100644 index 0000000..f20b7f4 --- /dev/null +++ b/sellershut/src/config/cli/cache.rs @@ -0,0 +1,118 @@ +use clap::{Parser, ValueEnum}; +use secrecy::SecretString; +use serde::Deserialize; +use url::Url; + +#[derive(Parser, Deserialize, Debug)] +#[serde(rename_all = "kebab-case")] +/// Distributed cache options +pub struct Cache { + /// Cache url + #[arg(long, value_name = "CACHE_URL", env = "CACHE_URL")] + #[serde(rename = "url")] + pub cache_url: Option, + /// Pooled distributed cache + #[arg(long, value_name = "CACHE_POOLED", env = "CACHE_POOLED")] + pub cache_pooled: Option, + /// Distributed cache type + #[serde(rename = "type")] + #[arg(long, value_name = "CACHE_TYPE", env = "CACHE_TYPE")] + pub cache_kind: Option, + /// Database pool size + #[arg( + long, + value_name = "CACHE_MAX_CONNECTIONS", + env = "CACHE_MAX_CONNECTIONS" + )] + pub cache_max_connections: Option, + #[command(flatten)] + pub sentinel: Option, +} + +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize, Clone, Copy, Default, ValueEnum)] +#[serde(rename_all = "kebab-case")] +pub enum RedisVariant { + Clustered, + #[default] + NonClustered, + Sentinel, +} + +pub fn create_cache_variant( + variant: RedisVariant, + sent: Option, +) -> shared_svc::cache::RedisVariant { + match (variant, sent) { + (RedisVariant::Clustered, None) | (RedisVariant::Clustered, Some(_)) => { + shared_svc::cache::RedisVariant::Clustered + } + (RedisVariant::NonClustered, None) | (RedisVariant::NonClustered, Some(_)) => { + shared_svc::cache::RedisVariant::NonClustered + } + (RedisVariant::Sentinel, None) => { + unreachable!("should have bailed here") + } + (RedisVariant::Sentinel, Some(v)) => shared_svc::cache::RedisVariant::Sentinel(v.into()), + } +} + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Parser)] +pub struct SentinelConfig { + /// Cache sentinel service name + #[arg( + long, + value_name = "CACHE_SENTINEL_SERVICE", + env = "CACHE_SENTINEL_SERVICE" + )] + #[serde(rename = "service-name")] + pub cache_sentinel_service: Option, + #[serde(default)] + /// Cache sentinel TLS mode secure + #[arg( + long, + value_name = "CACHE_SENTINEL_TLS_SECURE", + env = "CACHE_SENTINEL_TLS_SECURE" + )] + #[serde(rename = "tls-mode-secure")] + pub cache_sentinel_tls_secure: bool, + /// Cache sentinel database number + #[arg(long, value_name = "CACHE_SENTINEL_DB", env = "CACHE_SENTINEL_DB")] + pub cache_sentinel_db: Option, + /// Cache sentinel username + #[arg( + long, + value_name = "CACHE_SENTINEL_USERNAME", + env = "CACHE_SENTINEL_USERNAME" + )] + pub cache_sentinel_username: Option, + /// Cache sentinel password + #[arg( + long, + value_name = "CACHE_SENTINEL_PASSWORD", + env = "CACHE_SENTINEL_PASSWORD" + )] + pub cache_sentinel_password: Option, + /// Cache sentinel use resp3 + #[arg( + long, + value_name = "CACHE_SENTINEL_RESP3", + env = "CACHE_SENTINEL_RESP3" + )] + #[serde(default)] + pub cache_sentinel_use_resp3: Option, +} + +impl From for shared_svc::cache::SentinelConfig { + fn from(value: SentinelConfig) -> Self { + Self { + service_name: value.cache_sentinel_service.unwrap(), + redis_tls_mode_secure: value.cache_sentinel_tls_secure, + redis_db: value.cache_sentinel_db, + redis_username: value.cache_sentinel_username, + redis_password: value + .cache_sentinel_password + .map(|v| SecretString::new(v.into())), + redis_use_resp3: value.cache_sentinel_use_resp3.unwrap(), + } + } +} diff --git a/sellershut/src/config/cli/mod.rs b/sellershut/src/config/cli/mod.rs index 8227407..784114e 100644 --- a/sellershut/src/config/cli/mod.rs +++ b/sellershut/src/config/cli/mod.rs @@ -1,3 +1,4 @@ +pub mod cache; pub mod database; pub mod oauth; use std::path::PathBuf; @@ -6,6 +7,7 @@ use clap::Parser; use clap::ValueEnum; use serde::Deserialize; +use crate::config::cli::cache::Cache; use crate::config::cli::{database::Database, oauth::Oauth}; use crate::config::log_level::LogLevel; @@ -24,6 +26,8 @@ pub struct Cli { pub oauth: Option, #[command(flatten)] pub database: Option, + #[command(flatten)] + pub cache: Option, } #[derive(Parser, Deserialize, Default, Debug)] diff --git a/sellershut/src/config/mod.rs b/sellershut/src/config/mod.rs index b013765..42d4d5d 100644 --- a/sellershut/src/config/mod.rs +++ b/sellershut/src/config/mod.rs @@ -4,10 +4,14 @@ pub mod log_level; use auth_service::client::ClientConfig; use clap::ValueEnum; use serde::Deserialize; +use shared_svc::cache::CacheConfig; use tracing::Level; use url::Url; -use crate::config::cli::{Cli, CliEnvironment}; +use crate::config::cli::{ + Cli, CliEnvironment, + cache::{RedisVariant, SentinelConfig, create_cache_variant}, +}; #[derive(Deserialize, ValueEnum, Clone, Copy)] #[serde(rename_all = "lowercase")] @@ -29,6 +33,7 @@ pub struct Configuration { pub server: Server, pub oauth: Oauth, pub database: Database, + pub cache: CacheConfig, } pub struct Oauth { @@ -134,6 +139,77 @@ impl Configuration { .or(file_db.and_then(|v| v.database_pool_size)) .unwrap_or(10); // sensible default + let cli_cache = cli.cache.as_ref(); + let file_cache = file.cache.as_ref(); + + let cache_url = cli_cache + .and_then(|v| v.cache_url.clone()) + .or(file_cache.and_then(|v| v.cache_url.clone())); + + if cache_url.is_none() { + missing.push("cache.url"); + } + let cache_pooled = cli_cache + .and_then(|v| v.cache_pooled) + .or(file_cache.and_then(|v| v.cache_pooled)) + .unwrap_or(true); + + let cache_kind = cli_cache + .and_then(|v| v.cache_kind) + .or(file_cache.and_then(|v| v.cache_kind)) + .unwrap_or_default(); + + let cache_max_connections = cli_cache + .and_then(|v| v.cache_max_connections) + .or(file_cache.and_then(|v| v.cache_max_connections)) + .unwrap_or(10); + + // --- sentinel (only if kind == Sentinel) --- + let cli_sentinel = cli_cache.and_then(|v| v.sentinel.as_ref()); + let file_sentinel = file_cache.and_then(|v| v.sentinel.as_ref()); + + let sentinel = if cache_kind == RedisVariant::Sentinel { + let service_name = cli_sentinel + .map(|v| v.cache_sentinel_service.clone()) + .or(file_sentinel.map(|v| v.cache_sentinel_service.clone())); + + if service_name.is_none() { + missing.push("cache.sentinel.service-name"); + } + + let redis_tls_mode_secure = cli_sentinel + .map(|v| v.cache_sentinel_tls_secure) + .or(file_sentinel.map(|v| v.cache_sentinel_tls_secure)) + .unwrap_or(true); + + let redis_db = cli_sentinel + .and_then(|v| v.cache_sentinel_db) + .or(file_sentinel.and_then(|v| v.cache_sentinel_db)); + + let redis_username = cli_sentinel + .and_then(|v| v.cache_sentinel_username.clone()) + .or(file_sentinel.and_then(|v| v.cache_sentinel_username.clone())); + + let redis_password = cli_sentinel + .and_then(|v| v.cache_sentinel_password.clone()) + .or(file_sentinel.and_then(|v| v.cache_sentinel_password.clone())); + + let redis_use_resp3 = cli_sentinel + .and_then(|v| v.cache_sentinel_use_resp3) + .or(file_sentinel.and_then(|v| v.cache_sentinel_use_resp3)); + + Some(SentinelConfig { + cache_sentinel_service: service_name.unwrap(), + cache_sentinel_tls_secure: redis_tls_mode_secure, + cache_sentinel_db: redis_db, + cache_sentinel_username: redis_username, + cache_sentinel_password: redis_password, + cache_sentinel_use_resp3: redis_use_resp3, + }) + } else { + None + }; + if !missing.is_empty() { anyhow::bail!( "Missing required configuration values:\n{}", @@ -166,6 +242,12 @@ impl Configuration { url: database_url.unwrap(), pool_size, }, + cache: CacheConfig { + redis_dsn: cache_url.unwrap(), + pooled: cache_pooled, + kind: create_cache_variant(cache_kind, sentinel), + max_connections: cache_max_connections, + }, }) } } diff --git a/sellershut/src/logging/mod.rs b/sellershut/src/logging/mod.rs index c4b00c9..29c0ca1 100644 --- a/sellershut/src/logging/mod.rs +++ b/sellershut/src/logging/mod.rs @@ -7,7 +7,7 @@ pub fn initialise_logging(config: &Configuration) { .with( tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| { format!( - "{}={},tower_http=debug,axum=trace", + "{}={},tower_http=debug,axum=trace,info", env!("CARGO_CRATE_NAME"), config.server.log_level ) diff --git a/sellershut/src/main.rs b/sellershut/src/main.rs index 86db34d..f267071 100644 --- a/sellershut/src/main.rs +++ b/sellershut/src/main.rs @@ -15,6 +15,7 @@ use tracing::info; use crate::config::Configuration; use crate::config::cli::Cli; use crate::logging::initialise_logging; +use crate::state::AppState; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -30,6 +31,8 @@ async fn main() -> anyhow::Result<()> { let config = Configuration::merge(&cli, &config)?; initialise_logging(&config); + let state = AppState::new(&config).await?; + // Create a regular axum app. let app = Router::new() .route("/slow", get(|| sleep(Duration::from_secs(5)))) diff --git a/sellershut/src/state/mod.rs b/sellershut/src/state/mod.rs index cf659c5..1a28381 100644 --- a/sellershut/src/state/mod.rs +++ b/sellershut/src/state/mod.rs @@ -1,5 +1,35 @@ -use auth_service::client::OauthClient; +use auth_service::{AuthService, client::OauthClient}; +use shared_svc::cache::RedisManager; +use tracing::{debug, error}; +use crate::config::Configuration; + +#[derive(Debug, Clone)] pub struct AppState { discord_client: OauthClient, + cache: RedisManager, + auth_service: AuthService, +} + +impl AppState { + pub async fn new(config: &Configuration) -> anyhow::Result { + let discord_client = OauthClient::try_from(&config.oauth.discord)? + .with_redirect_url(&config.oauth.redirect_url); + + let cache = { + let c = RedisManager::new(&config.cache).await?; + debug!("testing cache connection"); + // test connection + c.get().await.inspect_err(|e| error!("{e}"))?; + c + }; + + let auth_service = AuthService::new(&cache); + + Ok(Self { + discord_client, + cache, + auth_service, + }) + } } -- cgit v1.2.3