From 2ae4ed93c19598de547bad0a5dcc6758c0b92e17 Mon Sep 17 00:00:00 2001 From: Patrick Meade Date: Thu, 8 Aug 2024 00:40:32 -0500 Subject: [PATCH 1/6] First pass at migration to Axum + Mongo --- .github/workflows/ci.yml | 2 + Cargo.lock | 1225 +++++++++++++++++++++++++++++++++++- Cargo.toml | 13 +- bin/run-app | 12 + bin/run-app-docker | 15 + bin/run-docker | 10 - bin/run-mongo-docker | 13 + bin/run-mongo-shell-docker | 10 + src/context.rs | 55 ++ src/database.rs | 43 ++ src/error.rs | 46 ++ src/main.rs | 116 ++-- src/old_main.rs | 62 ++ 13 files changed, 1527 insertions(+), 95 deletions(-) create mode 100755 bin/run-app create mode 100755 bin/run-app-docker delete mode 100755 bin/run-docker create mode 100755 bin/run-mongo-docker create mode 100755 bin/run-mongo-shell-docker create mode 100644 src/context.rs create mode 100644 src/database.rs create mode 100644 src/error.rs create mode 100644 src/old_main.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa7a701..83c7b7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,8 @@ jobs: - run: rustup update stable && rustup default stable - run: cargo fmt --check - run: cargo clippy --locked + - run: cargo install cargo-outdated + - run: cargo outdated --root-deps-only --exit-code 1 test: name: Test diff --git a/Cargo.lock b/Cargo.lock index 18fc3df..e361460 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,19 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -26,6 +39,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.14" @@ -81,12 +109,78 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backtrace" version = "0.3.73" @@ -108,6 +202,18 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -123,12 +229,66 @@ dependencies = [ "serde", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[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 = "borrow-bag" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b654fee34da149f35fa96ba970ca2d342490f7461fbaa99b6588b63595c7fccf" +[[package]] +name = "bson" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a88e82b9106923b5c4d6edfca9e7db958d4e98a478ec115022e81b9b38e2c8" +dependencies = [ + "ahash", + "base64 0.13.1", + "bitvec", + "hex", + "indexmap", + "js-sys", + "once_cell", + "rand", + "serde", + "serde_bytes", + "serde_json", + "time 0.3.36", + "uuid", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -153,6 +313,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.5", +] + [[package]] name = "colorchoice" version = "1.0.1" @@ -165,6 +337,12 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "cookie" version = "0.15.2" @@ -175,6 +353,72 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "deranged" version = "0.3.11" @@ -184,6 +428,41 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 2.0.66", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "discard" version = "1.0.4" @@ -196,6 +475,18 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +[[package]] +name = "enum-as-inner" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "env_filter" version = "0.1.0" @@ -208,9 +499,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ "anstream", "anstyle", @@ -231,6 +522,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures-channel" version = "0.3.30" @@ -246,6 +552,23 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + [[package]] name = "futures-macro" version = "0.3.30" @@ -276,13 +599,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", + "futures-io", "futures-macro", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", ] +[[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 = "getrandom" version = "0.2.15" @@ -307,7 +642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c0e1892f0ec4bb9a4f5441c1d56af1d13d9bbb2a8f44ac58a670862eff3f8a6" dependencies = [ "anyhow", - "base64", + "base64 0.22.1", "bincode", "borrow-bag", "bytes", @@ -315,7 +650,7 @@ dependencies = [ "futures-util", "gotham_derive", "httpdate", - "hyper", + "hyper 0.14.29", "linked-hash-map", "log", "mime", @@ -385,7 +720,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap", "slab", "tokio", @@ -399,12 +734,44 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.12" @@ -416,6 +783,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -423,7 +801,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -456,8 +857,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -469,6 +870,90 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -479,6 +964,24 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "is_terminal_polyfill" version = "1.70.0" @@ -491,6 +994,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy-regex" version = "3.1.0" @@ -514,6 +1026,12 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.155" @@ -526,11 +1044,58 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] [[package]] name = "memchr" @@ -565,13 +1130,73 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "mongodb" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60f61f1556ee1d65e0b256e5bbc6d61e10022d1e3df86c23526d469bd832fa24" +dependencies = [ + "async-trait", + "base64 0.13.1", + "bitflags 1.3.2", + "bson", + "chrono", + "derivative", + "derive_more", + "futures-core", + "futures-executor", + "futures-io", + "futures-util", + "hex", + "hmac", + "md-5", + "mongodb-internal-macros", + "once_cell", + "pbkdf2", + "percent-encoding", + "rand", + "rustc_version_runtime", + "rustls", + "rustls-pemfile", + "serde", + "serde_bytes", + "serde_with", + "sha-1", + "sha2", + "socket2", + "stringprep", + "strsim", + "take_mut", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "trust-dns-proto", + "trust-dns-resolver", + "typed-builder", + "uuid", + "webpki-roots", +] + +[[package]] +name = "mongodb-internal-macros" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934305ae9c66ef6a3aa728c66dec8fa2424de4dfcd043c7acaffacae2bf99442" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", ] [[package]] @@ -580,6 +1205,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -605,12 +1239,44 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.5", +] + [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -676,6 +1342,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.36" @@ -685,6 +1357,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -715,6 +1393,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "regex" version = "1.10.5" @@ -745,26 +1432,123 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] -name = "rustc-demangle" -version = "0.1.24" +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rustc_version_runtime" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f" +dependencies = [ + "rustc_version 0.2.3", + "semver 0.9.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] [[package]] -name = "rustc_version" -version = "0.2.3" +name = "rustls-webpki" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "semver", + "ring", + "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "semver" version = "0.9.0" @@ -774,6 +1558,12 @@ dependencies = [ "semver-parser", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "semver-parser" version = "0.7.0" @@ -782,18 +1572,27 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", @@ -802,15 +1601,72 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.122" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +dependencies = [ + "indexmap", + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ + "form_urlencoded", "itoa", "ryu", "serde", ] +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha1" version = "0.6.1" @@ -826,6 +1682,26 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.9" @@ -835,6 +1711,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "socket2" version = "0.5.7" @@ -845,6 +1727,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "standback" version = "0.2.17" @@ -861,7 +1749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" dependencies = [ "discard", - "rustc_version", + "rustc_version 0.2.3", "stdweb-derive", "stdweb-internal-macros", "stdweb-internal-runtime", @@ -903,6 +1791,29 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[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.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "1.0.109" @@ -925,6 +1836,30 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "thiserror" version = "1.0.61" @@ -1014,20 +1949,58 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" -version = "1.38.0" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", - "windows-sys 0.48.0", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", ] [[package]] @@ -1038,11 +2011,34 @@ checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -1055,6 +2051,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-core", ] @@ -1068,12 +2065,74 @@ dependencies = [ "once_cell", ] +[[package]] +name = "trust-dns-proto" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.2.3", + "ipnet", + "lazy_static", + "log", + "rand", + "smallvec", + "thiserror", + "tinyvec", + "tokio", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +dependencies = [ + "cfg-if", + "futures-util", + "ipconfig", + "lazy_static", + "log", + "lru-cache", + "parking_lot", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "trust-dns-proto", +] + [[package]] name = "try-lock" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typed-builder" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicase" version = "2.7.0" @@ -1083,18 +2142,56 @@ dependencies = [ "version_check", ] +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" + [[package]] name = "unindent" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna 0.5.0", + "percent-encoding", +] + [[package]] name = "utf8parse" version = "0.2.2" @@ -1108,6 +2205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", + "serde", ] [[package]] @@ -1185,6 +2283,18 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -1207,6 +2317,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -1346,14 +2465,56 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wipac-disk-tracking" -version = "0.2.2" +version = "0.3.0" dependencies = [ + "axum", "env_logger", "gotham", "gotham_restful", "log", + "mongodb", "serde", "serde_json", + "tokio", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", ] diff --git a/Cargo.toml b/Cargo.toml index f60bf59..37bdbf3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,16 @@ [package] name = "wipac-disk-tracking" -version = "0.2.2" +version = "0.3.0" edition = "2021" publish = false [dependencies] -env_logger = "0.11.3" +axum = "0.7.5" +env_logger = "0.11.5" gotham = "0.7.4" gotham_restful = "0.9.0" -log = "0.4.21" -serde = "1.0.203" -serde_json = "1.0.117" +log = "0.4.22" +mongodb = "3.0.1" +serde = "1.0.204" +serde_json = "1.0.122" +tokio = { version = "1.39.2", features = [ "full" ] } diff --git a/bin/run-app b/bin/run-app new file mode 100755 index 0000000..dafafd8 --- /dev/null +++ b/bin/run-app @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# run-app + +export MONGODB_DATABASE=${MONGODB_DATABASE:="disk_tracking"} +export MONGODB_HOSTNAME=${MONGODB_HOSTNAME:="localhost"} +export MONGODB_PASSWORD=${MONGODB_PASSWORD:="hunter2"} +export MONGODB_PORT=${MONGODB_PORT:="27017"} +# export MONGODB_USERNAME=${MONGODB_USERNAME:="disk_tracking"} +export MONGODB_USERNAME=${MONGODB_USERNAME:="root"} +export RUST_LOG=${RUST_LOG:="debug"} + +cargo run --bin wipac-disk-tracking diff --git a/bin/run-app-docker b/bin/run-app-docker new file mode 100755 index 0000000..bd1efff --- /dev/null +++ b/bin/run-app-docker @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# run-app-docker + +docker run \ + --detach \ + --env=MONGODB_HOSTNAME=disk_tracking_mongo \ + --env=MONGODB_PASSWORD=hunter2 \ + --env=MONGODB_PORT=27017 \ + --env=MONGODB_USERNAME=disk_tracking \ + --env=RUST_LOG=debug \ + --link disk_tracking_mongo:disk_tracking_mongo \ + --name=disk_tracking \ + --publish 8080:8080 \ + --rm \ + wipac-disk-tracking:latest-SNAPSHOT diff --git a/bin/run-docker b/bin/run-docker deleted file mode 100755 index 8d21959..0000000 --- a/bin/run-docker +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -# run-docker - -docker run \ - --detach \ - --env=RUST_LOG=debug \ - --name=wipac_disk_tracking \ - --publish 8080:8080 \ - --rm \ - wipac-disk-tracking:latest-SNAPSHOT diff --git a/bin/run-mongo-docker b/bin/run-mongo-docker new file mode 100755 index 0000000..6c0a011 --- /dev/null +++ b/bin/run-mongo-docker @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# run-mongo-docker + + # --detach \ + # --rm \ +docker run \ + --env=MONGODB_DATABASE=disk_tracking \ + --env=MONGODB_PASSWORD=hunter2 \ + --env=MONGODB_ROOT_PASSWORD=hunter2 \ + --env=MONGODB_USERNAME=disk_tracking \ + --name=disk_tracking_mongo \ + --publish 27017:27017 \ + bitnami/mongodb:latest diff --git a/bin/run-mongo-shell-docker b/bin/run-mongo-shell-docker new file mode 100755 index 0000000..330e505 --- /dev/null +++ b/bin/run-mongo-shell-docker @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# run-mongo-shell-docker + +docker run \ + --interactive \ + --network="host" \ + --rm \ + --tty \ + mongo:latest \ + mongosh --host localhost:27017 -u "root" -p "hunter2" --authenticationDatabase "admin" diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..2d44cfa --- /dev/null +++ b/src/context.rs @@ -0,0 +1,55 @@ +// context.rs + +use std::env; + +use crate::error::{ApplicationError::ContextError, Result}; + +#[derive(Debug)] +pub struct ApplicationContext { + pub mongo_database: String, + pub mongo_host: String, + pub mongo_password: String, + pub mongo_port: String, + pub mongo_user: String, +} + +impl ApplicationContext { + pub fn get_mongo_url(&self) -> String { + format!("mongodb://{}:{}@{}:{}/", self.mongo_user, self.mongo_password, self.mongo_host, self.mongo_port) + } +} + +pub fn build_context() -> Result { + // read database parameters from the environment + let mongo_host = env::var("MONGODB_HOSTNAME").unwrap_or_else(|_| "localhost".into()); + let mongo_port = env::var("MONGODB_PORT").unwrap_or_else(|_| "27017".into()); + let mongo_user = env::var("MONGODB_USERNAME").unwrap_or_else(|_| "disk_tracking".into()); + let mongo_database = env::var("MONGO_DB_NAME").unwrap_or_else(|_| "disk_tracking".into()); + let mongo_password = match env::var("MONGODB_PASSWORD") { + Err(_) => return Err(ContextError("environment variable MONGODB_PASSWORD not defined".to_string())), + Ok(x) => x, + }; + + // return the application context to the caller + Ok(ApplicationContext { + mongo_database, + mongo_host, + mongo_password, + mongo_port, + mongo_user, + }) +} + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + // use super::*; + + #[test] + fn test_always_succeed() { + assert!(true); + } +} diff --git a/src/database.rs b/src/database.rs new file mode 100644 index 0000000..a635b7c --- /dev/null +++ b/src/database.rs @@ -0,0 +1,43 @@ +// database.rs + +use mongodb::{bson::document::Document, Client, options::ClientOptions}; + +use crate::context::ApplicationContext; +use crate::error::Result; + +const DISK_EVENT_COLLECTION: &str = "disk_event"; + +struct DiskEvent; + +pub async fn setup_mongo(context: &ApplicationContext) -> Result { + let conn_str = context.get_mongo_url(); + let client_options = ClientOptions::parse(conn_str).await?; + let client = Client::with_options(client_options)?; + Ok(client) +} + +pub async fn count_disk_events(context: &ApplicationContext, client: &Client) -> Result { + let database = client.database(&context.mongo_database); + let collection = database.collection::(DISK_EVENT_COLLECTION); + let count = collection.count_documents(Document::new()).await?; + Ok(count) + +// match collection.count_documents(None, None).await { +// Ok(count) => { +// let body = json!({ +// "status": "ok", +// "count": count, +// }); +// (StatusCode::OK, body.to_string()) +// }, +// Err(_) => { +// let body = json!({ +// "status": "error", +// "message": "Failed to connect to the database", +// }); +// (StatusCode::INTERNAL_SERVER_ERROR, body.to_string()) +// }, +// } + +} + diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..3e15333 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,46 @@ +// error.rs + +#[derive(Debug)] +pub enum ApplicationError { + ContextError(String), + MongoError(String), +} + +impl From for ApplicationError { + fn from(error: std::env::VarError) -> Self { + ApplicationError::ContextError(error.to_string()) + } +} + +impl From for ApplicationError { + fn from(error: mongodb::error::Error) -> Self { + ApplicationError::MongoError(error.to_string()) + } +} + +pub type Result = std::result::Result; + +pub fn get_error_message(e: ApplicationError) -> String { + match e { + ApplicationError::ContextError(x) => { + format!("disk-tracking: Unable to build application context: {x}") + }, + ApplicationError::MongoError(x) => { + format!("disk-tracking: Database error: {x}") + }, + } +} + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + // use super::*; + + #[test] + fn test_always_succeed() { + assert!(true); + } +} diff --git a/src/main.rs b/src/main.rs index e006e56..14fd4e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,62 +1,82 @@ // main.rs -pub mod routes; +pub mod context; +pub mod database; +pub mod error; -use gotham::{ - router::{build_simple_router, builder::DrawRoutes, Router}, - state::State, -}; -use log::info; +// use axum::{ +// routing::get, +// Router, +// response::IntoResponse, +// http::StatusCode, +// }; +use mongodb::{Client, options::ClientOptions}; +// use serde_json::json; +// use std::net::SocketAddr; -const HELLO_WORLD: &str = "Hello World!\n"; +use context::{build_context, ApplicationContext}; +use database::{count_disk_events, setup_mongo}; +use error::{get_error_message, Result}; -pub fn say_hello(state: State) -> (State, &'static str) { - (state, HELLO_WORLD) -} - -fn build_router() -> Router { - build_simple_router(|route| { - route.delegate("/api/v1").to_router(routes::v1::router()); - }) -} - -pub fn main() { +#[tokio::main] +async fn main() { // initialize logging, configured by environment env_logger::init(); - // start the service - let addr = "0.0.0.0:8080"; - info!("Listening for requests at http://{}", addr); - // gotham::start(addr, || Ok(say_hello)).unwrap(); - let _ = gotham::start(addr, build_router()); + + match do_main().await { + Err(e) => eprintln!("Error: {}", get_error_message(e)), + Ok(_) => {}, + } } -// -------------------------------------------------------------------------------------------------------------------- -// -------------------------------------------------------------------------------------------------------------------- -// -------------------------------------------------------------------------------------------------------------------- +async fn do_main() -> Result<()> { + let context = build_context().expect("Unable to build application context"); -#[cfg(test)] -mod tests { - use super::*; - use gotham::hyper::StatusCode; - use gotham::test::TestServer; + println!("{:?}", context); + println!("{}", context.get_mongo_url()); - #[test] - fn test_always_succeed() { - assert_eq!(true, true) - } + let client = setup_mongo(&context).await.expect("Unable to initialize MongoDB client"); + let count = count_disk_events(&context, &client).await?; + println!("{}", count); - #[test] - fn test_say_hello() { - let test_server = TestServer::new(|| Ok(say_hello)).unwrap(); - let response = test_server - .client() - .get("http://localhost") - .perform() - .unwrap(); + Ok(()) +} - assert_eq!(response.status(), StatusCode::OK); +// // Create a MongoDB client +// let mongo_client = setup_mongo().await.expect("Failed to initialize MongoDB client"); - let body = response.read_utf8_body().unwrap(); - assert_eq!(body, HELLO_WORLD); - } -} +// // Build our application with a route +// let app = Router::new() +// .route("/health", get(health_handler)) +// .with_state(mongo_client); + +// // Run the server +// let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); +// println!("Listening on {}", addr); +// axum::Server::bind(&addr) +// .serve(app.into_make_service()) +// .await +// .unwrap(); +// } + +// async fn health_handler(client: axum::extract::State) -> impl IntoResponse { +// let database = client.database("your_database_name"); +// let collection = database.collection("disk_event"); + +// match collection.count_documents(None, None).await { +// Ok(count) => { +// let body = json!({ +// "status": "ok", +// "count": count, +// }); +// (StatusCode::OK, body.to_string()) +// }, +// Err(_) => { +// let body = json!({ +// "status": "error", +// "message": "Failed to connect to the database", +// }); +// (StatusCode::INTERNAL_SERVER_ERROR, body.to_string()) +// }, +// } +// } diff --git a/src/old_main.rs b/src/old_main.rs new file mode 100644 index 0000000..f1b738c --- /dev/null +++ b/src/old_main.rs @@ -0,0 +1,62 @@ +// main.rs + +pub mod routes; + +use gotham::{ + router::{build_simple_router, builder::DrawRoutes, Router}, + state::State, +}; +use log::info; + +const HELLO_WORLD: &str = "Hello World!\n"; + +pub fn say_hello(state: State) -> (State, &'static str) { + (state, HELLO_WORLD) +} + +fn build_router() -> Router { + build_simple_router(|route| { + route.delegate("/api/v1").to_router(routes::v1::router()); + }) +} + +// pub fn main() { +// // initialize logging, configured by environment +// env_logger::init(); +// // start the service +// let addr = "0.0.0.0:8080"; +// info!("Listening for requests at http://{}", addr); +// // gotham::start(addr, || Ok(say_hello)).unwrap(); +// let _ = gotham::start(addr, build_router()); +// } + +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use gotham::hyper::StatusCode; + use gotham::test::TestServer; + + #[test] + fn test_always_succeed() { + assert_eq!(true, true) + } + + #[test] + fn test_say_hello() { + let test_server = TestServer::new(|| Ok(say_hello)).unwrap(); + let response = test_server + .client() + .get("http://localhost") + .perform() + .unwrap(); + + assert_eq!(response.status(), StatusCode::OK); + + let body = response.read_utf8_body().unwrap(); + assert_eq!(body, HELLO_WORLD); + } +} From 4f9bd23495a3a2fa5ad3d3cad1b2b8f1af16ccb0 Mon Sep 17 00:00:00 2001 From: Patrick Meade Date: Thu, 8 Aug 2024 17:59:48 -0500 Subject: [PATCH 2/6] Now authenticating with the correct database --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- bin/build-docker | 8 +++++++- bin/run-app | 10 +++++++--- bin/run-app-docker | 29 ++++++++++++++++++++++------- bin/run-mongo-docker | 26 +++++++++++++++++++------- bin/run-mongo-shell-docker | 13 ++++++++++++- src/context.rs | 17 ++++++++++++++--- src/database.rs | 38 ++++++++++++++++++-------------------- src/error.rs | 4 ++-- src/main.rs | 11 ++++++----- 11 files changed, 112 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e361460..fd7c0e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1572,9 +1572,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" dependencies = [ "serde_derive", ] @@ -1590,9 +1590,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.205" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 37bdbf3..8ce2916 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,6 @@ gotham = "0.7.4" gotham_restful = "0.9.0" log = "0.4.22" mongodb = "3.0.1" -serde = "1.0.204" +serde = "1.0.205" serde_json = "1.0.122" tokio = { version = "1.39.2", features = [ "full" ] } diff --git a/bin/build-docker b/bin/build-docker index 00f227d..4e663ea 100755 --- a/bin/build-docker +++ b/bin/build-docker @@ -1,7 +1,13 @@ #!/usr/bin/env bash # build-docker +# use `docker buildx build` to create a Docker image of the application +# by default the image is `wipac-disk-tracking:latest-SNAPSHOT` unless +# you set the BUILD_TAG environment variable before calling the script + +: ${BUILD_TAG:="latest-SNAPSHOT"} + docker buildx build \ --file Dockerfile \ - --tag wipac-disk-tracking:latest-SNAPSHOT \ + --tag wipac-disk-tracking:${BUILD_TAG} \ . diff --git a/bin/run-app b/bin/run-app index dafafd8..f63a497 100755 --- a/bin/run-app +++ b/bin/run-app @@ -1,12 +1,16 @@ #!/usr/bin/env bash # run-app +# use `cargo run` to run an instance of the application locally +# when starting this script, you can provide one of the environment +# variables listed below to override the defaults + export MONGODB_DATABASE=${MONGODB_DATABASE:="disk_tracking"} export MONGODB_HOSTNAME=${MONGODB_HOSTNAME:="localhost"} export MONGODB_PASSWORD=${MONGODB_PASSWORD:="hunter2"} -export MONGODB_PORT=${MONGODB_PORT:="27017"} -# export MONGODB_USERNAME=${MONGODB_USERNAME:="disk_tracking"} -export MONGODB_USERNAME=${MONGODB_USERNAME:="root"} +export MONGODB_PORT_NUMBER=${MONGODB_PORT_NUMBER:="27017"} +export MONGODB_USERNAME=${MONGODB_USERNAME:="disk_tracking"} +export PORT=${PORT:="8080"} export RUST_LOG=${RUST_LOG:="debug"} cargo run --bin wipac-disk-tracking diff --git a/bin/run-app-docker b/bin/run-app-docker index bd1efff..f481e8a 100755 --- a/bin/run-app-docker +++ b/bin/run-app-docker @@ -1,15 +1,30 @@ #!/usr/bin/env bash # run-app-docker +# use `docker run` to run an instance of the application in a Docker +# container. when starting this script, you can provide one of the +# environment variables listed below to override the defaults + +: ${DOCKER_CONTAINER_NAME:="disk_tracking"} +: ${DOCKER_MONGO_CONTAINER_NAME:="disk_tracking_mongo"} +: ${MONGODB_DATABASE:="disk_tracking"} +: ${MONGODB_HOSTNAME:="localhost"} +: ${MONGODB_PASSWORD:="hunter2"} +: ${MONGODB_USERNAME:="disk_tracking"} +: ${MONGODB_PORT_NUMBER:="27017"} +: ${PORT:="8080"} + docker run \ --detach \ - --env=MONGODB_HOSTNAME=disk_tracking_mongo \ - --env=MONGODB_PASSWORD=hunter2 \ - --env=MONGODB_PORT=27017 \ - --env=MONGODB_USERNAME=disk_tracking \ + --env=MONGODB_DATABASE=${MONGODB_DATABASE} \ + --env=MONGODB_HOSTNAME=${DOCKER_MONGO_CONTAINER_NAME} \ + --env=MONGODB_PASSWORD=${MONGODB_PASSWORD} \ + --env=MONGODB_PORT_NUMBER=${MONGODB_PORT_NUMBER} \ + --env=MONGODB_USERNAME=${MONGODB_USERNAME} \ + --env=PORT=${PORT} \ --env=RUST_LOG=debug \ - --link disk_tracking_mongo:disk_tracking_mongo \ - --name=disk_tracking \ - --publish 8080:8080 \ + --link ${DOCKER_MONGO_CONTAINER_NAME}:${DOCKER_MONGO_CONTAINER_NAME} \ + --name=${DOCKER_CONTAINER_NAME} \ + --publish ${PORT}:${PORT} \ --rm \ wipac-disk-tracking:latest-SNAPSHOT diff --git a/bin/run-mongo-docker b/bin/run-mongo-docker index 6c0a011..13cb75f 100755 --- a/bin/run-mongo-docker +++ b/bin/run-mongo-docker @@ -1,13 +1,25 @@ #!/usr/bin/env bash # run-mongo-docker - # --detach \ - # --rm \ +# use `docker run` to create a TEMPORARY instance of MongoDB in a +# Docker container for development/testing purposes. when starting +# this script, you can provide one of the environment variables listed +# below to override the defaults + +: ${DOCKER_CONTAINER_NAME:="disk_tracking_mongo"} +: ${MONGODB_DATABASE:="disk_tracking"} +: ${MONGODB_PASSWORD:="hunter2"} +: ${MONGODB_USERNAME:="disk_tracking"} +: ${MONGODB_PORT_NUMBER:="27017"} + docker run \ - --env=MONGODB_DATABASE=disk_tracking \ - --env=MONGODB_PASSWORD=hunter2 \ + --detach \ + --env=MONGODB_DATABASE=${MONGODB_DATABASE} \ + --env=MONGODB_PASSWORD=${MONGODB_PASSWORD} \ --env=MONGODB_ROOT_PASSWORD=hunter2 \ - --env=MONGODB_USERNAME=disk_tracking \ - --name=disk_tracking_mongo \ - --publish 27017:27017 \ + --env=MONGODB_USERNAME=${MONGODB_USERNAME} \ + --env=MONGODB_PORT_NUMBER=${MONGODB_PORT_NUMBER} \ + --name=${DOCKER_CONTAINER_NAME} \ + --publish ${MONGODB_PORT_NUMBER}:${MONGODB_PORT_NUMBER} \ + --rm \ bitnami/mongodb:latest diff --git a/bin/run-mongo-shell-docker b/bin/run-mongo-shell-docker index 330e505..4609ae3 100755 --- a/bin/run-mongo-shell-docker +++ b/bin/run-mongo-shell-docker @@ -1,10 +1,21 @@ #!/usr/bin/env bash # run-mongo-shell-docker +# use `docker run` to create an interactive mongoshell that connects to +# the TEMPORARY instance of MongoDB for development/testing purposes. +# when starting this script, you can provide one of the environment +# variables listed below to override the defaults + +: ${MONGODB_DATABASE:="disk_tracking"} +: ${MONGODB_HOSTNAME:="localhost"} +: ${MONGODB_PASSWORD:="hunter2"} +: ${MONGODB_USERNAME:="disk_tracking"} +: ${MONGODB_PORT_NUMBER:="27017"} + docker run \ --interactive \ --network="host" \ --rm \ --tty \ mongo:latest \ - mongosh --host localhost:27017 -u "root" -p "hunter2" --authenticationDatabase "admin" + mongosh --host ${MONGODB_HOSTNAME}:${MONGODB_PORT_NUMBER} -u "${MONGODB_USERNAME}" -p "${MONGODB_PASSWORD}" --authenticationDatabase "${MONGODB_DATABASE}" diff --git a/src/context.rs b/src/context.rs index 2d44cfa..c718944 100644 --- a/src/context.rs +++ b/src/context.rs @@ -15,18 +15,29 @@ pub struct ApplicationContext { impl ApplicationContext { pub fn get_mongo_url(&self) -> String { - format!("mongodb://{}:{}@{}:{}/", self.mongo_user, self.mongo_password, self.mongo_host, self.mongo_port) + format!( + "mongodb://{}:{}@{}:{}/{}", + self.mongo_user, + self.mongo_password, + self.mongo_host, + self.mongo_port, + self.mongo_database + ) } } pub fn build_context() -> Result { // read database parameters from the environment let mongo_host = env::var("MONGODB_HOSTNAME").unwrap_or_else(|_| "localhost".into()); - let mongo_port = env::var("MONGODB_PORT").unwrap_or_else(|_| "27017".into()); + let mongo_port = env::var("MONGODB_PORT_NUMBER").unwrap_or_else(|_| "27017".into()); let mongo_user = env::var("MONGODB_USERNAME").unwrap_or_else(|_| "disk_tracking".into()); let mongo_database = env::var("MONGO_DB_NAME").unwrap_or_else(|_| "disk_tracking".into()); let mongo_password = match env::var("MONGODB_PASSWORD") { - Err(_) => return Err(ContextError("environment variable MONGODB_PASSWORD not defined".to_string())), + Err(_) => { + return Err(ContextError( + "environment variable MONGODB_PASSWORD not defined".to_string(), + )) + } Ok(x) => x, }; diff --git a/src/database.rs b/src/database.rs index a635b7c..087d0b5 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,6 +1,6 @@ // database.rs -use mongodb::{bson::document::Document, Client, options::ClientOptions}; +use mongodb::{bson::document::Document, options::ClientOptions, Client}; use crate::context::ApplicationContext; use crate::error::Result; @@ -19,25 +19,23 @@ pub async fn setup_mongo(context: &ApplicationContext) -> Result { pub async fn count_disk_events(context: &ApplicationContext, client: &Client) -> Result { let database = client.database(&context.mongo_database); let collection = database.collection::(DISK_EVENT_COLLECTION); - let count = collection.count_documents(Document::new()).await?; + let count = collection.count_documents(Document::new()).await?; Ok(count) -// match collection.count_documents(None, None).await { -// Ok(count) => { -// let body = json!({ -// "status": "ok", -// "count": count, -// }); -// (StatusCode::OK, body.to_string()) -// }, -// Err(_) => { -// let body = json!({ -// "status": "error", -// "message": "Failed to connect to the database", -// }); -// (StatusCode::INTERNAL_SERVER_ERROR, body.to_string()) -// }, -// } - + // match collection.count_documents(None, None).await { + // Ok(count) => { + // let body = json!({ + // "status": "ok", + // "count": count, + // }); + // (StatusCode::OK, body.to_string()) + // }, + // Err(_) => { + // let body = json!({ + // "status": "error", + // "message": "Failed to connect to the database", + // }); + // (StatusCode::INTERNAL_SERVER_ERROR, body.to_string()) + // }, + // } } - diff --git a/src/error.rs b/src/error.rs index 3e15333..bb70aa9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -24,10 +24,10 @@ pub fn get_error_message(e: ApplicationError) -> String { match e { ApplicationError::ContextError(x) => { format!("disk-tracking: Unable to build application context: {x}") - }, + } ApplicationError::MongoError(x) => { format!("disk-tracking: Database error: {x}") - }, + } } } diff --git a/src/main.rs b/src/main.rs index 14fd4e3..edaa7b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,11 +10,10 @@ pub mod error; // response::IntoResponse, // http::StatusCode, // }; -use mongodb::{Client, options::ClientOptions}; // use serde_json::json; // use std::net::SocketAddr; -use context::{build_context, ApplicationContext}; +use context::build_context; use database::{count_disk_events, setup_mongo}; use error::{get_error_message, Result}; @@ -22,10 +21,10 @@ use error::{get_error_message, Result}; async fn main() { // initialize logging, configured by environment env_logger::init(); - + // run the application match do_main().await { Err(e) => eprintln!("Error: {}", get_error_message(e)), - Ok(_) => {}, + Ok(_) => {} } } @@ -35,7 +34,9 @@ async fn do_main() -> Result<()> { println!("{:?}", context); println!("{}", context.get_mongo_url()); - let client = setup_mongo(&context).await.expect("Unable to initialize MongoDB client"); + let client = setup_mongo(&context) + .await + .expect("Unable to initialize MongoDB client"); let count = count_disk_events(&context, &client).await?; println!("{}", count); From 1755c83205fb1dd04b65806e4e3ff93fff3dd5c1 Mon Sep 17 00:00:00 2001 From: Patrick Meade Date: Thu, 22 Aug 2024 05:35:33 -0500 Subject: [PATCH 3/6] /events and /health routes --- Cargo.lock | 49 ++- Cargo.toml | 14 +- README.md | 38 +- bin/run-app | 1 + bin/run-app-docker | 2 + src/context.rs | 65 +++- src/database.rs | 102 ++++-- src/event.rs | 99 +++++ src/lib.rs | 7 + src/main.rs | 86 ++--- src/middleware.rs | 29 ++ src/old_main.rs | 62 ---- src/routes.rs | 26 ++ src/routes/v1.rs | 29 +- src/routes/v1/disks.rs | 82 +---- src/routes/v1/events.rs | 190 ++++++++-- src/routes/v1/health.rs | 38 ++ src/smartctl.rs | 113 ++++++ tests/data/smartctl001.json | 679 +++++++++++++++++++++++++++++++++++ tests/mongodb_test.rs | 90 +++++ tests/smartctl_serde_test.rs | 19 + 21 files changed, 1504 insertions(+), 316 deletions(-) create mode 100644 src/event.rs create mode 100644 src/lib.rs create mode 100644 src/middleware.rs delete mode 100644 src/old_main.rs create mode 100644 src/routes/v1/health.rs create mode 100644 src/smartctl.rs create mode 100644 tests/data/smartctl001.json create mode 100644 tests/mongodb_test.rs create mode 100644 tests/smartctl_serde_test.rs diff --git a/Cargo.lock b/Cargo.lock index fd7c0e3..48a10b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -181,6 +181,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-extra" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733" +dependencies = [ + "axum", + "axum-core", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "serde", + "serde_json", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backtrace" version = "0.3.73" @@ -321,7 +344,9 @@ checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", + "wasm-bindgen", "windows-targets 0.52.5", ] @@ -1572,9 +1597,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.205" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] @@ -1590,9 +1615,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.205" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", @@ -1601,9 +1626,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" dependencies = [ "indexmap", "itoa", @@ -1966,9 +1991,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "bytes", @@ -2200,9 +2225,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", "serde", @@ -2480,7 +2505,10 @@ name = "wipac-disk-tracking" version = "0.3.0" dependencies = [ "axum", + "axum-extra", + "chrono", "env_logger", + "futures-util", "gotham", "gotham_restful", "log", @@ -2488,6 +2516,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "uuid", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8ce2916..0a0d554 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,11 +6,19 @@ publish = false [dependencies] axum = "0.7.5" +axum-extra = { version = "0.9.3", features = [ "erased-json" ] } +chrono = "0.4.38" env_logger = "0.11.5" +futures-util = "0.3.30" gotham = "0.7.4" gotham_restful = "0.9.0" log = "0.4.22" mongodb = "3.0.1" -serde = "1.0.205" -serde_json = "1.0.122" -tokio = { version = "1.39.2", features = [ "full" ] } +serde = "1.0.208" +serde_json = "1.0.125" +tokio = { version = "1.39.3", features = [ "full" ] } +uuid = { version = "1.10.0", features = [ "serde", "v4" ] } + +[lib] +name = "wipac_disk_tracking" +path = "src/lib.rs" diff --git a/README.md b/README.md index 7403179..faf09c3 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,12 @@ The REST API for the wipac-disk-tracking service is documented below. The API is rooted at: - /api/v# - -Where # is the version number of the API under use. + /api/v1 ### Disks -Disks represent a unique archival disk. -While the disk entity does carry some immutable identifying information, it -is mostly a container for archival disk events. +Disks represent a collection of unique archival disks. While the disk +entity does carry some immutable identifying information, it is mostly +a container for archival disk events. #### Routes These routes are implemented to work with disks: @@ -24,7 +22,7 @@ These routes are implemented to work with disks: GET /disks/:disk_id/search?query Find a disk based on a key-value query ### Events -Events represent a record of an event involving an archival disk. +Events represent a record of an event involving an archival disk. There are four distinct events that are tracked by the system. sighted This disk was observed to be loaded in a host that processes archival disks @@ -37,6 +35,28 @@ The format for each of these events is specified with a JSON Schema file. #### Routes These routes are implemented to work with events: - POST /events Create a new event + POST /events/closed Create a new 'closed' event + POST /events/formatted Create a new 'formatted' event + POST /events/opened Create a new 'opened' event + POST /events/sighted Create a new 'sighted' event GET /events/:event_id Get the data for a given event - GET /events/search?query Find an event based on key-value query + +## Development +As typical in a Rust project, you can run the unit and integration tests with: + + cargo test -- --show-output + +### MongoDB Tests +The MongoDB integration test will look for the temporary MongoDB container +running locally. If you'd rather run the test against a different MongoDB, +you can supply the URL through this environment variable: + + DESTRUCTIVE_TEST_MONGODB_URL + +Note that the integration test is destructive. It may wipe out your collections, +indexes, or databases! DON'T point this at any data that you want to keep! + +If MongoDB is not available, locally or through the provided URL, then a +message will appear in the output of the tests: + + "MongoDB is not available. Skipping test." diff --git a/bin/run-app b/bin/run-app index f63a497..2c676e8 100755 --- a/bin/run-app +++ b/bin/run-app @@ -9,6 +9,7 @@ export MONGODB_DATABASE=${MONGODB_DATABASE:="disk_tracking"} export MONGODB_HOSTNAME=${MONGODB_HOSTNAME:="localhost"} export MONGODB_PASSWORD=${MONGODB_PASSWORD:="hunter2"} export MONGODB_PORT_NUMBER=${MONGODB_PORT_NUMBER:="27017"} +export MONGODB_TIMEOUT_SECS=${MONGODB_TIMEOUT_SECS:="5"} export MONGODB_USERNAME=${MONGODB_USERNAME:="disk_tracking"} export PORT=${PORT:="8080"} export RUST_LOG=${RUST_LOG:="debug"} diff --git a/bin/run-app-docker b/bin/run-app-docker index f481e8a..f931366 100755 --- a/bin/run-app-docker +++ b/bin/run-app-docker @@ -10,6 +10,7 @@ : ${MONGODB_DATABASE:="disk_tracking"} : ${MONGODB_HOSTNAME:="localhost"} : ${MONGODB_PASSWORD:="hunter2"} +: ${MONGODB_TIMEOUT_SECS:="5"} : ${MONGODB_USERNAME:="disk_tracking"} : ${MONGODB_PORT_NUMBER:="27017"} : ${PORT:="8080"} @@ -20,6 +21,7 @@ docker run \ --env=MONGODB_HOSTNAME=${DOCKER_MONGO_CONTAINER_NAME} \ --env=MONGODB_PASSWORD=${MONGODB_PASSWORD} \ --env=MONGODB_PORT_NUMBER=${MONGODB_PORT_NUMBER} \ + --env=MONGODB_TIMEOUT_SECS=${MONGODB_TIMEOUT_SECS} \ --env=MONGODB_USERNAME=${MONGODB_USERNAME} \ --env=PORT=${PORT} \ --env=RUST_LOG=debug \ diff --git a/src/context.rs b/src/context.rs index c718944..8bf9803 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,37 +1,25 @@ // context.rs +use mongodb::{options::ClientOptions, Client}; use std::env; +use std::time::Duration; use crate::error::{ApplicationError::ContextError, Result}; -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct ApplicationContext { + pub mongo_client: Client, pub mongo_database: String, pub mongo_host: String, pub mongo_password: String, pub mongo_port: String, pub mongo_user: String, + pub port: u16, } -impl ApplicationContext { - pub fn get_mongo_url(&self) -> String { - format!( - "mongodb://{}:{}@{}:{}/{}", - self.mongo_user, - self.mongo_password, - self.mongo_host, - self.mongo_port, - self.mongo_database - ) - } -} - -pub fn build_context() -> Result { - // read database parameters from the environment - let mongo_host = env::var("MONGODB_HOSTNAME").unwrap_or_else(|_| "localhost".into()); - let mongo_port = env::var("MONGODB_PORT_NUMBER").unwrap_or_else(|_| "27017".into()); +pub async fn build_context() -> Result { + // read database connection parameters from the environment let mongo_user = env::var("MONGODB_USERNAME").unwrap_or_else(|_| "disk_tracking".into()); - let mongo_database = env::var("MONGO_DB_NAME").unwrap_or_else(|_| "disk_tracking".into()); let mongo_password = match env::var("MONGODB_PASSWORD") { Err(_) => { return Err(ContextError( @@ -40,14 +28,53 @@ pub fn build_context() -> Result { } Ok(x) => x, }; + let mongo_host = env::var("MONGODB_HOSTNAME").unwrap_or_else(|_| "localhost".into()); + let mongo_port = env::var("MONGODB_PORT_NUMBER").unwrap_or_else(|_| "27017".into()); + let mongo_database = env::var("MONGODB_DATABASE").unwrap_or_else(|_| "disk_tracking".into()); + + // read application port from the environment + let port_str = env::var("PORT").unwrap_or_else(|_| "8080".into()); + let port = match port_str.parse::() { + Err(_) => { + return Err(ContextError(format!( + "environment variable PORT contains invalid value: {}", + port_str + ))) + } + Ok(x) => x, + }; + + // read database connection timeout from the environment + let mongodb_timeout_secs_str = env::var("MONGODB_TIMEOUT_SECS").unwrap_or_else(|_| "30".into()); + let mongodb_timeout_secs = match mongodb_timeout_secs_str.parse::() { + Err(_) => { + return Err(ContextError(format!( + "environment variable MONGODB_TIMEOUT_SECS contains invalid value: {}", + mongodb_timeout_secs_str + ))) + } + Ok(x) => x, + }; + + // build the database client + let conn_str = format!( + "mongodb://{}:{}@{}:{}/{}", + mongo_user, mongo_password, mongo_host, mongo_port, mongo_database + ); + let mut client_options = ClientOptions::parse(conn_str).await?; + client_options.connect_timeout = Some(Duration::from_secs(mongodb_timeout_secs)); + client_options.server_selection_timeout = Some(Duration::from_secs(mongodb_timeout_secs)); + let mongo_client = Client::with_options(client_options)?; // return the application context to the caller Ok(ApplicationContext { + mongo_client, mongo_database, mongo_host, mongo_password, mongo_port, mongo_user, + port, }) } diff --git a/src/database.rs b/src/database.rs index 087d0b5..0be3fb4 100644 --- a/src/database.rs +++ b/src/database.rs @@ -1,41 +1,87 @@ // database.rs -use mongodb::{bson::document::Document, options::ClientOptions, Client}; +use futures_util::stream::TryStreamExt; +use mongodb::{ + bson::{doc, document::Document}, + results::InsertOneResult, +}; +use uuid::Uuid; use crate::context::ApplicationContext; use crate::error::Result; +use crate::event::DiskEvent; -const DISK_EVENT_COLLECTION: &str = "disk_event"; +pub const DISK_EVENTS_COLLECTION: &str = "disk_events"; -struct DiskEvent; +pub async fn count_disk_events(context: &ApplicationContext) -> Result { + let client = &context.mongo_client; + let database = client.database(&context.mongo_database); + let collection = database.collection::(DISK_EVENTS_COLLECTION); + + let count = collection.count_documents(Document::new()).await?; -pub async fn setup_mongo(context: &ApplicationContext) -> Result { - let conn_str = context.get_mongo_url(); - let client_options = ClientOptions::parse(conn_str).await?; - let client = Client::with_options(client_options)?; - Ok(client) + Ok(count) } -pub async fn count_disk_events(context: &ApplicationContext, client: &Client) -> Result { +pub async fn find_disk_events_uuid( + context: &ApplicationContext, + uuid: Uuid, +) -> Result> { + let client = &context.mongo_client; let database = client.database(&context.mongo_database); - let collection = database.collection::(DISK_EVENT_COLLECTION); - let count = collection.count_documents(Document::new()).await?; - Ok(count) + let collection = database.collection::(DISK_EVENTS_COLLECTION); + let filter = doc! { "uuid": uuid.to_string() }; + + let mut cursor = collection.find(filter).await?; + let mut result = Vec::new(); + while let Some(doc) = cursor.try_next().await? { + result.push(doc); + } + + Ok(result) +} + +pub async fn find_disk_events_serial_number( + context: &ApplicationContext, + serial_number: String, +) -> Result> { + let client = &context.mongo_client; + let database = client.database(&context.mongo_database); + let collection = database.collection::(DISK_EVENTS_COLLECTION); + let filter = doc! { "serial_number": serial_number }; + + let mut cursor = collection.find(filter).await?; + let mut result = Vec::new(); + while let Some(doc) = cursor.try_next().await? { + result.push(doc); + } + + Ok(result) +} + +pub async fn save_disk_event( + context: &ApplicationContext, + disk_event: DiskEvent, +) -> Result { + let client = &context.mongo_client; + let database = client.database(&context.mongo_database); + let collection = database.collection::(DISK_EVENTS_COLLECTION); + + let result = collection.insert_one(disk_event).await?; + + Ok(result) +} + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + // use super::*; - // match collection.count_documents(None, None).await { - // Ok(count) => { - // let body = json!({ - // "status": "ok", - // "count": count, - // }); - // (StatusCode::OK, body.to_string()) - // }, - // Err(_) => { - // let body = json!({ - // "status": "error", - // "message": "Failed to connect to the database", - // }); - // (StatusCode::INTERNAL_SERVER_ERROR, body.to_string()) - // }, - // } + #[test] + fn test_always_succeed() { + assert!(true); + } } diff --git a/src/event.rs b/src/event.rs new file mode 100644 index 0000000..d221cb3 --- /dev/null +++ b/src/event.rs @@ -0,0 +1,99 @@ +// event.rs + +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::smartctl::SmartCtl; + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum Event { + /// this disk was determined to full/finished and archival activity stopped + CLOSED, + /// this disk was given a file system to make it ready for archival purposes + FORMATTED, + /// this disk was given a label and was designated for active archival activity + OPENED, + /// this disk was observed to be loaded in a host that processes archival disks + SIGHTED, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct DiskEvent { + /// unique identifier for this DiskEvent + #[serde(serialize_with = "uuid_to_string", deserialize_with = "string_to_uuid")] + pub uuid: Uuid, + /// iso-8601 timestamp when this DiskEvent was created + pub date_created: String, + /// hardware serial number of the disk this DiskEvent is about + pub serial_number: String, + /// the type of event this DiskEvent describes + pub event: Event, + /// the output from the `smartctl` command for this DiskEvent + pub smartctl: SmartCtl, +} + +fn uuid_to_string(uuid: &Uuid, serializer: S) -> Result +where + S: serde::Serializer, +{ + serializer.serialize_str(&uuid.to_string()) +} + +fn string_to_uuid<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + Uuid::parse_str(&s).map_err(serde::de::Error::custom) +} + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn test_always_succeed() { + assert!(true); + } + + #[test] + fn test_serialization() { + // create a uuid + let test_uuid = Uuid::new_v4(); + + // create a disk event + let disk_event = DiskEvent { + uuid: test_uuid, + date_created: "2024-08-14T17:36:31Z".to_string(), + serial_number: "ZRS1NWBL".to_string(), + event: Event::FORMATTED, + smartctl: SmartCtl(json!({ + "serial_number": "ZRS1NWBL" + })), + }; + + // serialize it to JSON + let serialized = serde_json::to_string(&disk_event).unwrap(); + + // expected JSON representation + let expected_json = json!({ + "uuid": test_uuid.to_string(), + "date_created": "2024-08-14T17:36:31Z", + "serial_number": "ZRS1NWBL", + "event": "formatted", + "smartctl": { + "serial_number": "ZRS1NWBL" + } + }) + .to_string(); + + // assert that the serialized JSON matches the expected JSON + assert_eq!(serialized, expected_json); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..b581add --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,7 @@ +// lib.rs + +pub mod context; +pub mod database; +pub mod error; +pub mod event; +pub mod smartctl; diff --git a/src/main.rs b/src/main.rs index edaa7b5..5de5013 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,81 +3,43 @@ pub mod context; pub mod database; pub mod error; +pub mod event; +pub mod middleware; +pub mod routes; +pub mod smartctl; -// use axum::{ -// routing::get, -// Router, -// response::IntoResponse, -// http::StatusCode, -// }; -// use serde_json::json; -// use std::net::SocketAddr; +use log::{error, info}; +use std::net::SocketAddr; +use tokio::net::TcpListener; use context::build_context; -use database::{count_disk_events, setup_mongo}; use error::{get_error_message, Result}; +use routes::build_router; #[tokio::main] async fn main() { // initialize logging, configured by environment env_logger::init(); - // run the application - match do_main().await { - Err(e) => eprintln!("Error: {}", get_error_message(e)), - Ok(_) => {} + // run the application, report any errors + if let Err(e) = do_main().await { + error!("Error: {}", get_error_message(e)) } } async fn do_main() -> Result<()> { - let context = build_context().expect("Unable to build application context"); - - println!("{:?}", context); - println!("{}", context.get_mongo_url()); - - let client = setup_mongo(&context) + // set up the context of the application + let context = build_context() .await - .expect("Unable to initialize MongoDB client"); - let count = count_disk_events(&context, &client).await?; - println!("{}", count); - + .expect("Unable to build application context"); + // establish our listening port + let listener = TcpListener::bind(format!("0.0.0.0:{}", context.port)) + .await + .unwrap_or_else(|_| panic!("Unable to listen on port {}", context.port)); + // build the application router + let app = build_router(context).into_make_service_with_connect_info::(); + // start the disk tracking service + info!("listening on {}", listener.local_addr().unwrap()); + axum::serve(listener, app).await.unwrap(); + // tell the caller that there were no errors Ok(()) } - -// // Create a MongoDB client -// let mongo_client = setup_mongo().await.expect("Failed to initialize MongoDB client"); - -// // Build our application with a route -// let app = Router::new() -// .route("/health", get(health_handler)) -// .with_state(mongo_client); - -// // Run the server -// let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); -// println!("Listening on {}", addr); -// axum::Server::bind(&addr) -// .serve(app.into_make_service()) -// .await -// .unwrap(); -// } - -// async fn health_handler(client: axum::extract::State) -> impl IntoResponse { -// let database = client.database("your_database_name"); -// let collection = database.collection("disk_event"); - -// match collection.count_documents(None, None).await { -// Ok(count) => { -// let body = json!({ -// "status": "ok", -// "count": count, -// }); -// (StatusCode::OK, body.to_string()) -// }, -// Err(_) => { -// let body = json!({ -// "status": "error", -// "message": "Failed to connect to the database", -// }); -// (StatusCode::INTERNAL_SERVER_ERROR, body.to_string()) -// }, -// } -// } diff --git a/src/middleware.rs b/src/middleware.rs new file mode 100644 index 0000000..ecbb5c8 --- /dev/null +++ b/src/middleware.rs @@ -0,0 +1,29 @@ +// middleware.rs + +use axum::{ + extract::ConnectInfo, extract::Request, http::StatusCode, middleware::Next, response::Response, +}; +use core::net::SocketAddr; +use log::info; + +pub async fn log_request( + ConnectInfo(addr): ConnectInfo, + req: Request, + next: Next, +) -> Result { + // if we can't figure out the IP address, then we don't know it + let mut client_ip = addr.ip().to_string(); + + // try to get the IP address from the request headers + if let Some(header) = req.headers().get("x-forwarded-for") { + if let Ok(ip) = header.to_str() { + client_ip = ip.to_string(); + } + } + + // log about it + info!("{} {} {}", client_ip, req.method(), req.uri()); + + // call the next middleware in the chain + Ok(next.run(req).await) +} diff --git a/src/old_main.rs b/src/old_main.rs deleted file mode 100644 index f1b738c..0000000 --- a/src/old_main.rs +++ /dev/null @@ -1,62 +0,0 @@ -// main.rs - -pub mod routes; - -use gotham::{ - router::{build_simple_router, builder::DrawRoutes, Router}, - state::State, -}; -use log::info; - -const HELLO_WORLD: &str = "Hello World!\n"; - -pub fn say_hello(state: State) -> (State, &'static str) { - (state, HELLO_WORLD) -} - -fn build_router() -> Router { - build_simple_router(|route| { - route.delegate("/api/v1").to_router(routes::v1::router()); - }) -} - -// pub fn main() { -// // initialize logging, configured by environment -// env_logger::init(); -// // start the service -// let addr = "0.0.0.0:8080"; -// info!("Listening for requests at http://{}", addr); -// // gotham::start(addr, || Ok(say_hello)).unwrap(); -// let _ = gotham::start(addr, build_router()); -// } - -// -------------------------------------------------------------------------------------------------------------------- -// -------------------------------------------------------------------------------------------------------------------- -// -------------------------------------------------------------------------------------------------------------------- - -#[cfg(test)] -mod tests { - use super::*; - use gotham::hyper::StatusCode; - use gotham::test::TestServer; - - #[test] - fn test_always_succeed() { - assert_eq!(true, true) - } - - #[test] - fn test_say_hello() { - let test_server = TestServer::new(|| Ok(say_hello)).unwrap(); - let response = test_server - .client() - .get("http://localhost") - .perform() - .unwrap(); - - assert_eq!(response.status(), StatusCode::OK); - - let body = response.read_utf8_body().unwrap(); - assert_eq!(body, HELLO_WORLD); - } -} diff --git a/src/routes.rs b/src/routes.rs index c7d5b3b..5f272bf 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1,3 +1,29 @@ // routes.rs pub mod v1; + +use axum::{middleware, Router}; + +use crate::context::ApplicationContext; +use crate::middleware::log_request; + +pub fn build_router(context: ApplicationContext) -> Router { + Router::new() + .with_state(context.clone()) + .nest("/api/v1", v1::build_router(context.clone())) + .layer(middleware::from_fn(log_request)) +} + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + // use super::*; + + #[test] + fn test_always_succeed() { + assert!(true); + } +} diff --git a/src/routes/v1.rs b/src/routes/v1.rs index 6dd23ce..376b5aa 100644 --- a/src/routes/v1.rs +++ b/src/routes/v1.rs @@ -2,16 +2,27 @@ pub mod disks; pub mod events; +pub mod health; -pub use disks::{DiskResource, DiskResources}; -pub use events::{EventResource, EventResources}; +use axum::{ + routing::{get, post}, + Router, +}; -use gotham::router::{build_simple_router, Router}; -use gotham_restful::DrawResources; +use crate::context::ApplicationContext; +use crate::routes::v1::events::{ + get_events, post_closed, post_formatted, post_opened, post_sighted, +}; +use crate::routes::v1::health::get_health; -pub fn router() -> Router { - build_simple_router(|route| { - route.resource::("disks"); - route.resource::("events"); - }) +pub fn build_router(context: ApplicationContext) -> Router { + // build the routes under /api/v1 + Router::new() + .route("/health", get(get_health)) + .route("/events/closed", post(post_closed)) + .route("/events/formatted", post(post_formatted)) + .route("/events/opened", post(post_opened)) + .route("/events/sighted", post(post_sighted)) + .route("/events/:id", get(get_events)) + .with_state(context) } diff --git a/src/routes/v1/disks.rs b/src/routes/v1/disks.rs index 403f03b..8a81e73 100644 --- a/src/routes/v1/disks.rs +++ b/src/routes/v1/disks.rs @@ -1,83 +1,3 @@ // disks.rs -use gotham::{router::response::StaticResponseExtender, state::StateData}; -use gotham_restful::{endpoint, gotham::hyper::Method, read, search, Resource, Success}; -use log::info; -use serde::{Deserialize, Serialize}; - -use crate::routes::v1::{EventResource, EventResources}; - -#[derive(Resource, Serialize)] -#[resource(get_disk_by_id)] -#[resource(get_event_by_disk_id_and_event_id)] -#[resource(get_events_by_disk_id)] -#[resource(find_disk_by_query)] -pub struct DiskResource { - pub id: u64, -} - -#[derive(Serialize)] -pub struct DiskResources { - pub disks: Vec, -} - -// -------------------------------------------------------------------------------------------------------------------- - -#[derive(Clone, Deserialize, StateData, StaticResponseExtender)] -struct DiskSearchQuery { - _serial_number: String, -} - -#[search] -fn find_disk_by_query(_query: DiskSearchQuery) -> Success { - info!("find_disk_by_query()"); - DiskResources { disks: Vec::new() }.into() -} - -// -------------------------------------------------------------------------------------------------------------------- - -#[read] -fn get_disk_by_id(disk_id: u64) -> Success { - info!("get_disk_by_id()"); - DiskResource { id: disk_id }.into() -} - -// -------------------------------------------------------------------------------------------------------------------- - -#[derive(Clone, Deserialize, StateData, StaticResponseExtender)] -struct DiskAndEvent { - _disk_id: u64, - event_id: u64, -} - -#[endpoint( - uri = ":disk_id/events/:event_id", - method = "Method::GET", - params = false, - body = false -)] -fn get_event_by_disk_id_and_event_id(disk_and_event: DiskAndEvent) -> Success { - info!("get_event_by_disk_id_and_event_id()"); - EventResource { - id: disk_and_event.event_id, - } - .into() -} - -// -------------------------------------------------------------------------------------------------------------------- - -#[derive(Clone, Deserialize, StateData, StaticResponseExtender)] -struct Disk { - _disk_id: u64, -} - -#[endpoint( - uri = ":disk_id/events", - method = "Method::GET", - params = false, - body = false -)] -fn get_events_by_disk_id(_disk: Disk) -> Success { - info!("get_events_by_disk_id()"); - EventResources { events: Vec::new() }.into() -} +// TODO: Implement more stuff here diff --git a/src/routes/v1/events.rs b/src/routes/v1/events.rs index 82602b0..4923209 100644 --- a/src/routes/v1/events.rs +++ b/src/routes/v1/events.rs @@ -1,53 +1,177 @@ // events.rs -use gotham::{router::response::StaticResponseExtender, state::StateData}; -use gotham_restful::{create, read, search, Resource, Success}; -use log::info; -use serde::{Deserialize, Serialize}; +use axum::{ + extract::{Path, State}, + http::StatusCode, + response::IntoResponse, + Json, +}; +use axum_extra::response::ErasedJson; +use chrono::Utc; +use serde::Serialize; +use uuid::Uuid; -#[derive(Resource, Serialize)] -#[resource(create_event)] -#[resource(find_event_by_query)] -#[resource(get_event_by_id)] -pub struct EventResource { - pub id: u64, +use crate::context::ApplicationContext; +use crate::database::{find_disk_events_serial_number, find_disk_events_uuid, save_disk_event}; +use crate::event::{DiskEvent, Event}; +use crate::smartctl::SmartCtl; + +#[derive(Serialize)] +struct DiskEventCreatedResponse { + pub status: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, } #[derive(Serialize)] -pub struct EventResources { - pub events: Vec, +struct DiskEventFindResponse { + pub events: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, } -// -------------------------------------------------------------------------------------------------------------------- +pub async fn get_events( + State(context): State, + Path(id): Path, +) -> impl IntoResponse { + // if we can parse the provided id as a UUID + if let Ok(uuid) = Uuid::parse_str(&id) { + // search the database by UUID + let (status, response) = find_events_by_uuid(context, uuid).await; + return (status, ErasedJson::pretty(response)); + } -#[derive(Clone, Deserialize, StateData, StaticResponseExtender)] -struct EventBody { - _serial_number: String, + // look the events up by serial_number + let (status, response) = find_events_by_serial_number(context, id).await; + (status, ErasedJson::pretty(response)) } -#[create] -fn create_event(_body: EventBody) -> Success { - info!("create_event()"); - EventResource { id: 0 }.into() +pub async fn post_closed( + State(context): State, + Json(smartctl): Json, +) -> impl IntoResponse { + let (status, response) = create_event(context, smartctl, Event::CLOSED).await; + (status, ErasedJson::pretty(response)) } -// -------------------------------------------------------------------------------------------------------------------- +pub async fn post_formatted( + State(context): State, + Json(smartctl): Json, +) -> impl IntoResponse { + let (status, response) = create_event(context, smartctl, Event::FORMATTED).await; + (status, ErasedJson::pretty(response)) +} -#[derive(Clone, Deserialize, StateData, StaticResponseExtender)] -struct EventSearchQuery { - _serial_number: String, +pub async fn post_opened( + State(context): State, + Json(smartctl): Json, +) -> impl IntoResponse { + let (status, response) = create_event(context, smartctl, Event::OPENED).await; + (status, ErasedJson::pretty(response)) } -#[search] -fn find_event_by_query(_query: EventSearchQuery) -> Success { - info!("find_event_by_query()"); - EventResources { events: Vec::new() }.into() +pub async fn post_sighted( + State(context): State, + Json(smartctl): Json, +) -> impl IntoResponse { + let (status, response) = create_event(context, smartctl, Event::SIGHTED).await; + (status, ErasedJson::pretty(response)) } -// -------------------------------------------------------------------------------------------------------------------- +async fn create_event( + context: ApplicationContext, + smartctl: SmartCtl, + event: Event, +) -> (StatusCode, DiskEventCreatedResponse) { + // ensure we can extract a serial number + let serial_number = if let Some(serial) = smartctl.get_serial() { + serial + } else { + return ( + StatusCode::UNPROCESSABLE_ENTITY, + DiskEventCreatedResponse { + status: "error".to_string(), + message: Some("provided smartctl data is missing key 'serial_number'".to_string()), + }, + ); + }; + + // extract a creation date, or just use the current one + let date_created = if let Some(date) = smartctl.get_date_created() { + date + } else { + // the user provided smartctl data without a date, so we'll use the current one + Utc::now().to_rfc3339().replace("+00:00", "Z") + }; + + // create the disk event + let disk_event = DiskEvent { + uuid: Uuid::new_v4(), + date_created, + serial_number, + event, + smartctl, + }; + + // store the disk event in the database + match save_disk_event(&context, disk_event).await { + Ok(_) => ( + StatusCode::CREATED, + DiskEventCreatedResponse { + status: "ok".to_string(), + message: None, + }, + ), + Err(e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + DiskEventCreatedResponse { + status: "error".to_string(), + message: Some(format!("{:?}", e)), + }, + ), + } +} + +async fn find_events_by_uuid( + context: ApplicationContext, + uuid: Uuid, +) -> (StatusCode, DiskEventFindResponse) { + match find_disk_events_uuid(&context, uuid).await { + Ok(events) => ( + StatusCode::OK, + DiskEventFindResponse { + events, + message: None, + }, + ), + Err(e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + DiskEventFindResponse { + events: Vec::new(), + message: Some(format!("{:?}", e)), + }, + ), + } +} -#[read] -fn get_event_by_id(id: u64) -> Success { - info!("get_event_by_id()"); - EventResource { id }.into() +async fn find_events_by_serial_number( + context: ApplicationContext, + serial_number: String, +) -> (StatusCode, DiskEventFindResponse) { + match find_disk_events_serial_number(&context, serial_number).await { + Ok(events) => ( + StatusCode::OK, + DiskEventFindResponse { + events, + message: None, + }, + ), + Err(e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + DiskEventFindResponse { + events: Vec::new(), + message: Some(format!("{:?}", e)), + }, + ), + } } diff --git a/src/routes/v1/health.rs b/src/routes/v1/health.rs new file mode 100644 index 0000000..f986dcc --- /dev/null +++ b/src/routes/v1/health.rs @@ -0,0 +1,38 @@ +// health.rs + +use axum::{extract::State, http::StatusCode, response::IntoResponse}; +use axum_extra::response::ErasedJson; +use serde::Serialize; + +use crate::context::ApplicationContext; +use crate::database::count_disk_events; + +#[derive(Serialize)] +struct HealthResponse { + pub status: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub count: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, +} + +pub async fn get_health(context: State) -> impl IntoResponse { + match count_disk_events(&context).await { + Ok(count) => ( + StatusCode::OK, + ErasedJson::pretty(HealthResponse { + status: "ok".to_string(), + count: Some(count), + message: None, + }), + ), + Err(e) => ( + StatusCode::INTERNAL_SERVER_ERROR, + ErasedJson::pretty(HealthResponse { + status: "error".to_string(), + count: None, + message: Some(format!("Failed to connect to the database: {:?}", e)), + }), + ), + } +} diff --git a/src/smartctl.rs b/src/smartctl.rs new file mode 100644 index 0000000..bb69abd --- /dev/null +++ b/src/smartctl.rs @@ -0,0 +1,113 @@ +// smartctl.rs + +use chrono::DateTime; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +/// the output of a `smartctl --all --json` command; a `serde_json::Value` +/// wrapped up to provide a convenience method for extraction of the +/// `serial_number` field found in smartctl output +#[derive(Debug, Deserialize, Serialize)] +pub struct SmartCtl(pub Value); + +impl SmartCtl { + pub fn get_date_created(&self) -> Option { + // from the wrapped JSON Value + self.0 + // find the `local_time` field + .get("local_time") + // find the `time_t` field + .and_then(|local_time| local_time.get("time_t")) + // convert the integer there to an i64 + .and_then(|time_t| time_t.as_i64()) + // convert that into an ISO8601 date + .and_then(|timestamp| { + // convert the integer into a DateTime + let datetime = DateTime::from_timestamp(timestamp, 0)?; + // format the DateTime as an ISO8601 date + Some(datetime.to_rfc3339().replace("+00:00", "Z")) + }) + } + + pub fn get_serial(&self) -> Option { + // from the wrapped JSON Value + self.0 + // find the `serial_number` field + .get("serial_number") + // and attempt to extract it as an owned String + .and_then(|serial_number| serial_number.as_str().map(String::from)) + } +} + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn test_always_succeed() { + assert!(true); + } + + #[test] + fn test_get_serial() { + // test that get_serial can extract a serial number from the JSON Value + // hey wait a minute, those funky integers aren't valid JSON! + // See: https://github.com/serde-rs/json/issues/974 + let smartctl_json = json!({ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 1 + ], + "svn_revision": "5080", + "platform_info": "x86_64-linux-4.18.0-305.17.1.el8_4.x86_64", + "build_info": "(local build)", + "argv": [ + "smartctl", + "--all", + "--json", + "/dev/slot1" + ], + "exit_status": 0 + }, + "device": { + "name": "/dev/slot1", + "info_name": "/dev/slot1 [SAT]", + "type": "sat", + "protocol": "ATA" + }, + "model_name": "ST16000NM000J-2TW103", + "serial_number": "ZRS1NWBL", + "wwn": { + "naa": 5, + "oui": 3152, + "id": 3906377770_i64 + }, + "firmware_version": "SN04", + "user_capacity": { + "blocks": 31251759104_i64, + "bytes": 16000900661248_i64 + }, + "logical_block_size": 512, + "physical_block_size": 4096 + }); + let smartctl = SmartCtl(smartctl_json); + assert_eq!(smartctl.get_serial(), Some("ZRS1NWBL".to_string())); + } + + #[test] + fn test_get_serial_none() { + // test that get_serial returns None when serial number is missing from the JSON Value + let smartctl_no_serial = SmartCtl(json!({})); + assert_eq!(smartctl_no_serial.get_serial(), None); + } +} diff --git a/tests/data/smartctl001.json b/tests/data/smartctl001.json new file mode 100644 index 0000000..a37b80a --- /dev/null +++ b/tests/data/smartctl001.json @@ -0,0 +1,679 @@ +{ + "json_format_version": [ + 1, + 0 + ], + "smartctl": { + "version": [ + 7, + 1 + ], + "svn_revision": "5080", + "platform_info": "x86_64-linux-4.18.0-305.17.1.el8_4.x86_64", + "build_info": "(local build)", + "argv": [ + "smartctl", + "--all", + "--json", + "/dev/slot1" + ], + "exit_status": 0 + }, + "device": { + "name": "/dev/slot1", + "info_name": "/dev/slot1 [SAT]", + "type": "sat", + "protocol": "ATA" + }, + "model_name": "ST16000NM000J-2TW103", + "serial_number": "ZRS1NWBL", + "wwn": { + "naa": 5, + "oui": 3152, + "id": 3906377770 + }, + "firmware_version": "SN04", + "user_capacity": { + "blocks": 31251759104, + "bytes": 16000900661248 + }, + "logical_block_size": 512, + "physical_block_size": 4096, + "rotation_rate": 7200, + "form_factor": { + "ata_value": 2, + "name": "3.5 inches" + }, + "in_smartctl_database": false, + "ata_version": { + "string": "ACS-4 (minor revision not indicated)", + "major_value": 4064, + "minor_value": 65535 + }, + "sata_version": { + "string": "SATA 3.3", + "value": 511 + }, + "interface_speed": { + "max": { + "sata_value": 14, + "string": "6.0 Gb/s", + "units_per_second": 60, + "bits_per_unit": 100000000 + }, + "current": { + "sata_value": 3, + "string": "6.0 Gb/s", + "units_per_second": 60, + "bits_per_unit": 100000000 + } + }, + "local_time": { + "time_t": 1722274912, + "asctime": "Mon Jul 29 17:41:52 2024 GMT" + }, + "smart_status": { + "passed": true + }, + "ata_smart_data": { + "offline_data_collection": { + "status": { + "value": 130, + "string": "was completed without error", + "passed": true + }, + "completion_seconds": 567 + }, + "self_test": { + "status": { + "value": 0, + "string": "completed without error", + "passed": true + }, + "polling_minutes": { + "short": 1, + "extended": 1402, + "conveyance": 2 + } + }, + "capabilities": { + "values": [ + 123, + 3 + ], + "exec_offline_immediate_supported": true, + "offline_is_aborted_upon_new_cmd": false, + "offline_surface_scan_supported": true, + "self_tests_supported": true, + "conveyance_self_test_supported": true, + "selective_self_test_supported": true, + "attribute_autosave_enabled": true, + "error_logging_supported": true, + "gp_logging_supported": true + } + }, + "ata_sct_capabilities": { + "value": 28861, + "error_recovery_control_supported": true, + "feature_control_supported": true, + "data_table_supported": true + }, + "ata_smart_attributes": { + "revision": 10, + "table": [ + { + "id": 1, + "name": "Raw_Read_Error_Rate", + "value": 64, + "worst": 64, + "thresh": 44, + "when_failed": "", + "flags": { + "value": 15, + "string": "POSR-- ", + "prefailure": true, + "updated_online": true, + "performance": true, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 2540008, + "string": "2540008" + } + }, + { + "id": 3, + "name": "Spin_Up_Time", + "value": 98, + "worst": 98, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 3, + "string": "PO---- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 4, + "name": "Start_Stop_Count", + "value": 100, + "worst": 100, + "thresh": 20, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 2, + "string": "2" + } + }, + { + "id": 5, + "name": "Reallocated_Sector_Ct", + "value": 100, + "worst": 100, + "thresh": 10, + "when_failed": "", + "flags": { + "value": 51, + "string": "PO--CK ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 7, + "name": "Seek_Error_Rate", + "value": 100, + "worst": 253, + "thresh": 45, + "when_failed": "", + "flags": { + "value": 15, + "string": "POSR-- ", + "prefailure": true, + "updated_online": true, + "performance": true, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 11411, + "string": "11411" + } + }, + { + "id": 9, + "name": "Power_On_Hours", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 10, + "name": "Spin_Retry_Count", + "value": 100, + "worst": 100, + "thresh": 97, + "when_failed": "", + "flags": { + "value": 19, + "string": "PO--C- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 12, + "name": "Power_Cycle_Count", + "value": 100, + "worst": 100, + "thresh": 20, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 2, + "string": "2" + } + }, + { + "id": 18, + "name": "Unknown_Attribute", + "value": 100, + "worst": 100, + "thresh": 50, + "when_failed": "", + "flags": { + "value": 11, + "string": "PO-R-- ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": true, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 187, + "name": "Reported_Uncorrect", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 188, + "name": "Command_Timeout", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 190, + "name": "Airflow_Temperature_Cel", + "value": 78, + "worst": 78, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 34, + "string": "-O---K ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": true + }, + "raw": { + "value": 370540566, + "string": "22 (Min/Max 22/22)" + } + }, + { + "id": 192, + "name": "Power-Off_Retract_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 1, + "string": "1" + } + }, + { + "id": 193, + "name": "Load_Cycle_Count", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 50, + "string": "-O--CK ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 5, + "string": "5" + } + }, + { + "id": 194, + "name": "Temperature_Celsius", + "value": 22, + "worst": 40, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 34, + "string": "-O---K ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": true + }, + "raw": { + "value": 81604378646, + "string": "22 (0 19 0 0 0)" + } + }, + { + "id": 197, + "name": "Current_Pending_Sector", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 18, + "string": "-O--C- ", + "prefailure": false, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 198, + "name": "Offline_Uncorrectable", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 16, + "string": "----C- ", + "prefailure": false, + "updated_online": false, + "performance": false, + "error_rate": false, + "event_count": true, + "auto_keep": false + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 199, + "name": "UDMA_CRC_Error_Count", + "value": 200, + "worst": 200, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 62, + "string": "-OSRCK ", + "prefailure": false, + "updated_online": true, + "performance": true, + "error_rate": true, + "event_count": true, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 200, + "name": "Multi_Zone_Error_Rate", + "value": 100, + "worst": 100, + "thresh": 1, + "when_failed": "", + "flags": { + "value": 35, + "string": "PO---K ", + "prefailure": true, + "updated_online": true, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": true + }, + "raw": { + "value": 0, + "string": "0" + } + }, + { + "id": 240, + "name": "Head_Flying_Hours", + "value": 100, + "worst": 100, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 0, + "string": "------ ", + "prefailure": false, + "updated_online": false, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 153210073382912, + "string": "0 (139 88 0)" + } + }, + { + "id": 241, + "name": "Total_LBAs_Written", + "value": 100, + "worst": 253, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 0, + "string": "------ ", + "prefailure": false, + "updated_online": false, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 2531344, + "string": "2531344" + } + }, + { + "id": 242, + "name": "Total_LBAs_Read", + "value": 100, + "worst": 253, + "thresh": 0, + "when_failed": "", + "flags": { + "value": 0, + "string": "------ ", + "prefailure": false, + "updated_online": false, + "performance": false, + "error_rate": false, + "event_count": false, + "auto_keep": false + }, + "raw": { + "value": 8664, + "string": "8664" + } + } + ] + }, + "power_on_time": { + "hours": 0 + }, + "power_cycle_count": 2, + "temperature": { + "current": 22 + }, + "ata_smart_error_log": { + "summary": { + "revision": 1, + "count": 0 + } + }, + "ata_smart_self_test_log": { + "standard": { + "revision": 1, + "count": 0 + } + }, + "ata_smart_selective_self_test_log": { + "revision": 1, + "table": [ + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + }, + { + "lba_min": 0, + "lba_max": 0, + "status": { + "value": 0, + "string": "Not_testing" + } + } + ], + "flags": { + "value": 0, + "remainder_scan_enabled": false + }, + "power_up_scan_resume_minutes": 0 + } +} diff --git a/tests/mongodb_test.rs b/tests/mongodb_test.rs new file mode 100644 index 0000000..5c3ff75 --- /dev/null +++ b/tests/mongodb_test.rs @@ -0,0 +1,90 @@ +// mongodb_test.rs + +use mongodb::{bson::doc, options::ClientOptions, Client, Collection}; +use serde_json::Value; +use std::fs::read_to_string; +use std::time::Duration; +use uuid::Uuid; +use wipac_disk_tracking::database::DISK_EVENTS_COLLECTION; +use wipac_disk_tracking::event::{DiskEvent, Event}; +use wipac_disk_tracking::smartctl::SmartCtl; + +async fn get_mongodb_collection() -> Option> { + // determine which database to use for integration testing + // this will be a destructive test, so hopefully you didn't provide credentials to production! + let mongo_url = std::env::var("DESTRUCTIVE_TEST_MONGODB_URL").unwrap_or_else(|_| { + "mongodb://disk_tracking:hunter2@localhost:27017/disk_tracking".to_string() + }); + + // create a client options object and attempt to connect to MongoDB + let mut client_options = ClientOptions::parse(&mongo_url).await.ok()?; + client_options.connect_timeout = Some(Duration::from_secs(1)); + client_options.server_selection_timeout = Some(Duration::from_secs(1)); + let client = Client::with_options(client_options).ok()?; + + // check connection by pinging the database + let database = client.database("admin"); + let ping_result = database.run_command(doc! {"ping": 1}).await.map(|_| ()); + if ping_result.is_err() { + // if we couldn't ping the DB, we don't really have a connection + return None; + } + + // return the disk events collection to the caller + let database = client.database("disk_tracking"); + let collection = database.collection::(DISK_EVENTS_COLLECTION); + Some(collection) +} + +#[tokio::test] +async fn test_mongodb_crud_operations() { + // check if the disk_events collection is available + let collection = match get_mongodb_collection().await { + Some(coll) => coll, + None => { + dbg!("MongoDB is not available. Skipping test."); + return; + } + }; + + // create a random UUID + let test_uuid = Uuid::new_v4(); + + // create a SmartCtl from the test data + let json_str = read_to_string("tests/data/smartctl001.json").expect("Unable to read file"); + let smartctl_json: Value = serde_json::from_str(&json_str).expect("Unable to deserialize JSON"); + let test_smartctl = SmartCtl(smartctl_json); + + // create a disk event + let new_event = DiskEvent { + uuid: test_uuid, + date_created: "2024-08-14T17:36:31Z".to_string(), + serial_number: "ZRS1NWBL".to_string(), + event: Event::FORMATTED, + smartctl: test_smartctl, + }; + + // insert the disk event + let insert_result = collection.insert_one(&new_event).await; + assert!(insert_result.is_ok()); + + // read the disk event + let filter = doc! { "serial_number": "ZRS1NWBL" }; + let found_event = collection + .find_one(filter.clone()) + .await + .expect("Error finding document"); + assert!(found_event.is_some()); + assert_eq!(found_event.unwrap().serial_number, "ZRS1NWBL"); + + // update the disk event + let update = doc! { "$set": { "event": "closed" } }; // we would never actually do this, but what the heck + let update_result = collection.update_one(filter.clone(), update).await; + assert!(update_result.is_ok()); + assert_eq!(update_result.unwrap().modified_count, 1); + + // delete the disk event + let delete_result = collection.delete_one(filter.clone()).await; + assert!(delete_result.is_ok()); + assert_eq!(delete_result.unwrap().deleted_count, 1); +} diff --git a/tests/smartctl_serde_test.rs b/tests/smartctl_serde_test.rs new file mode 100644 index 0000000..366a8ea --- /dev/null +++ b/tests/smartctl_serde_test.rs @@ -0,0 +1,19 @@ +// smartctl_serde_test.rs + +use serde_json::Value; +use std::fs::read_to_string; +use wipac_disk_tracking::smartctl::SmartCtl; + +#[test] +fn test_deserialize_smartctl() { + // read JSON data + let json_str = read_to_string("tests/data/smartctl001.json").expect("Unable to read file"); + // deserialize JSON data + let smartctl_json: Value = serde_json::from_str(&json_str).expect("Unable to deserialize JSON"); + // wrap in a SmartCtl struct + let smartctl = SmartCtl(smartctl_json); + // obtain the serial number of the disk + let serial = smartctl.get_serial(); + // ensure we got the correct serial number from the test data + assert_eq!(serial, Some("ZRS1NWBL".to_string())); +} From 0ef1b8df11f29390cb96ef49cca3febea420b832 Mon Sep 17 00:00:00 2001 From: Patrick Meade Date: Wed, 16 Oct 2024 03:24:01 -0500 Subject: [PATCH 4/6] Keycloak Auth integration, /token route --- .gitignore | 6 + Cargo.lock | 1425 +++++++++++++++++++++++++-------- Cargo.toml | 20 +- bin/run-app | 3 + bin/run-app-docker | 5 + client/README.md | 31 + client/client.py | 57 ++ client/client.sh | 10 + client/requirements.txt | 1 + client/smartctl.json | 679 ++++++++++++++++ smartctl.json | 679 ++++++++++++++++ src/context.rs | 12 + src/error.rs | 4 + src/main.rs | 11 +- src/middleware.rs | 22 +- src/routes.rs | 52 +- src/routes/{v1 => }/health.rs | 9 +- src/routes/token.rs | 92 +++ src/routes/v1.rs | 22 +- 19 files changed, 2804 insertions(+), 336 deletions(-) create mode 100644 client/README.md create mode 100644 client/client.py create mode 100755 client/client.sh create mode 100644 client/requirements.txt create mode 100644 client/smartctl.json create mode 100644 smartctl.json rename src/routes/{v1 => }/health.rs (83%) create mode 100644 src/routes/token.rs diff --git a/.gitignore b/.gitignore index 8b0e667..9280096 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,9 @@ # Added by cargo /target + +# don't check in our precious secrets +keycloak-client-secret + +# don't check in Python virtual environments +env diff --git a/Cargo.lock b/Cargo.lock index 48a10b8..75c9f58 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -71,33 +71,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -105,32 +105,48 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", +] + +[[package]] +name = "atomic-time" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9622f5c6fb50377516c70f65159e70b25465409760c6bd6d4e581318bf704e83" +dependencies = [ + "once_cell", + "portable-atomic", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -139,7 +155,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "itoa", "matchit", @@ -162,9 +178,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -175,7 +191,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", "tracing", @@ -183,9 +199,9 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be6ea09c9b96cb5076af0de2e383bd2bc0c18f827cf1967bdd353e0b910d733" +checksum = "73c3220b188aea709cf1b6c5f9b01c3bd936bb08bd2b5184a12b35ac8131b1f9" dependencies = [ "axum", "axum-core", @@ -204,19 +220,48 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-keycloak-auth" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be9f06871201a9be2a42da89f98ad7b588681d7ac6c6b18193e010732f90b8d3" +dependencies = [ + "atomic-time", + "axum", + "educe", + "futures", + "http 1.1.0", + "jsonwebtoken", + "nonempty", + "reqwest", + "serde", + "serde-querystring", + "serde_json", + "serde_with", + "snafu", + "time 0.3.36", + "tokio", + "tower", + "tracing", + "try-again", + "typed-builder 0.20.0", + "url", + "uuid", +] + [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -293,15 +338,15 @@ checksum = "b654fee34da149f35fa96ba970ca2d342490f7461fbaa99b6588b63595c7fccf" [[package]] name = "bson" -version = "2.11.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a88e82b9106923b5c4d6edfca9e7db958d4e98a478ec115022e81b9b38e2c8" +checksum = "068208f2b6fcfa27a7f1ee37488d2bb8ba2640f68f5475d08e1d9130696aba59" dependencies = [ "ahash", "base64 0.13.1", "bitvec", "hex", - "indexmap", + "indexmap 2.6.0", "js-sys", "once_cell", "rand", @@ -318,17 +363,26 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "cc" -version = "1.0.99" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -346,15 +400,16 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "const_fn" @@ -378,17 +433,27 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -405,9 +470,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.13.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -415,27 +480,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 1.0.109", + "syn 2.0.79", ] [[package]] name = "darling_macro" -version = "0.13.4" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 1.0.109", + "syn 2.0.79", ] [[package]] @@ -451,6 +516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", + "serde", ] [[package]] @@ -473,8 +539,8 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 2.0.66", + "rustc_version 0.4.1", + "syn 2.0.79", ] [[package]] @@ -494,29 +560,70 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] [[package]] name = "enum-as-inner" -version = "0.4.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ "heck", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.79", +] + +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", ] [[package]] name = "env_filter" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ "log", "regex", @@ -541,12 +648,43 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -562,26 +700,42 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -590,42 +744,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", "futures-io", "futures-macro", + "futures-sink", "futures-task", "memchr", "pin-project-lite", @@ -650,15 +806,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "gotham" @@ -675,7 +833,7 @@ dependencies = [ "futures-util", "gotham_derive", "httpdate", - "hyper 0.14.29", + "hyper 0.14.31", "linked-hash-map", "log", "mime", @@ -700,7 +858,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39260b1324f4cf40bf4d86e4aa3a7574fabf6b25fe1b07345b776698d2a0459" dependencies = [ "quote", - "syn 2.0.66", + "syn 2.0.79", ] [[package]] @@ -730,7 +888,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", "unindent", ] @@ -746,7 +904,26 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -755,15 +932,21 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -777,6 +960,51 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "hmac" version = "0.12.1" @@ -855,9 +1083,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -873,15 +1101,15 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.29" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "httparse", @@ -897,13 +1125,14 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", "futures-util", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -912,28 +1141,66 @@ dependencies = [ "pin-project-lite", "smallvec", "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.5.0", + "hyper-util", + "rustls 0.23.14", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.5.0", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", ] [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", + "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.0", "pin-project-lite", + "socket2", "tokio", + "tower-service", + "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -960,11 +1227,10 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.2.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] @@ -981,12 +1247,24 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.0", + "serde", ] [[package]] @@ -1003,15 +1281,15 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" @@ -1021,18 +1299,33 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "lazy-regex" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c" +checksum = "8d8e41c97e6bc7ecb552016274b99fbb5d035e8de288c582d9b933af6677bfda" dependencies = [ "lazy-regex-proc_macros", "once_cell", @@ -1041,37 +1334,110 @@ dependencies = [ [[package]] name = "lazy-regex-proc_macros" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b" +checksum = "76e1d8b05d672c53cb9c7b920bbba8783845ae4f0b076e02a3db1d02c81b4163" dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.66", + "syn 2.0.79", ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "lexical" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "c7aefb36fd43fef7003334742cbf77b243fcd36418a1d1bdd480d613a67968f6" +dependencies = [ + "lexical-core", +] [[package]] -name = "libc" -version = "0.2.155" +name = "lexical-core" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] [[package]] -name = "linked-hash-map" -version = "0.5.6" +name = "lexical-parse-float" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] [[package]] -name = "lock_api" -version = "0.4.12" +name = "lexical-parse-integer" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ @@ -1100,12 +1466,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "matchit" version = "0.7.3" @@ -1136,9 +1496,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ "mime", "unicase", @@ -1146,18 +1506,18 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi", "libc", @@ -1167,9 +1527,9 @@ dependencies = [ [[package]] name = "mongodb" -version = "3.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f61f1556ee1d65e0b256e5bbc6d61e10022d1e3df86c23526d469bd832fa24" +checksum = "c857d71f918b38221baf2fdff7207fec9984b4504901544772b1edf0302d669f" dependencies = [ "async-trait", "base64 0.13.1", @@ -1183,6 +1543,8 @@ dependencies = [ "futures-io", "futures-util", "hex", + "hickory-proto", + "hickory-resolver", "hmac", "md-5", "mongodb-internal-macros", @@ -1191,8 +1553,8 @@ dependencies = [ "percent-encoding", "rand", "rustc_version_runtime", - "rustls", - "rustls-pemfile", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", "serde", "serde_bytes", "serde_with", @@ -1204,24 +1566,55 @@ dependencies = [ "take_mut", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tokio-util", - "trust-dns-proto", - "trust-dns-resolver", - "typed-builder", + "typed-builder 0.10.0", "uuid", "webpki-roots", ] [[package]] name = "mongodb-internal-macros" -version = "3.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934305ae9c66ef6a3aa728c66dec8fa2424de4dfcd043c7acaffacae2bf99442" +checksum = "3a6dbc533e93429a71c44a14c04547ac783b56d3f22e6c4f12b1b994cf93844e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nonempty" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "303e8749c804ccd6ca3b428de7fe0d86cb86bc7606bc15291f100fd487960bb8" + +[[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]] @@ -1230,6 +1623,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[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" @@ -1251,18 +1653,62 @@ dependencies = [ [[package]] name = "object" -version = "0.36.0" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "openssl" +version = "0.10.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b8cefcf97f41316955f9294cd61f639bdcfa9f2f230faac6cb896aa8ab64704" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] [[package]] name = "parking_lot" @@ -1284,7 +1730,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -1302,6 +1748,16 @@ dependencies = [ "digest", ] +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1310,22 +1766,22 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", ] [[package]] @@ -1340,6 +1796,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + [[package]] name = "powerfmt" version = "0.2.0" @@ -1348,9 +1816,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro-hack" @@ -1360,9 +1831,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -1375,9 +1846,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1420,18 +1891,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", @@ -1441,9 +1912,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", @@ -1452,9 +1923,52 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.0", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] [[package]] name = "resolv-conf" @@ -1498,21 +2012,34 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.23", ] [[package]] name = "rustc_version_runtime" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" dependencies = [ - "rustc_version 0.2.3", - "semver 0.9.0", + "rustc_version 0.4.1", + "semver 1.0.23", +] + +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1523,10 +2050,23 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -1536,6 +2076,21 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + [[package]] name = "rustls-webpki" version = "0.101.7" @@ -1546,11 +2101,22 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -1558,6 +2124,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "schannel" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -1574,6 +2149,29 @@ dependencies = [ "untrusted", ] +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.9.0" @@ -1597,13 +2195,23 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] +[[package]] +name = "serde-querystring" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce88f8e75d0920545b35b78775e0927137337401f65b01326ce299734885fd21" +dependencies = [ + "lexical", + "serde", +] + [[package]] name = "serde_bytes" version = "0.11.15" @@ -1615,22 +2223,22 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", ] [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ - "indexmap", + "indexmap 2.6.0", "itoa", "memchr", "ryu", @@ -1661,24 +2269,32 @@ dependencies = [ [[package]] name = "serde_with" -version = "1.14.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.6.0", "serde", + "serde_derive", + "serde_json", "serde_with_macros", + "time 0.3.36", ] [[package]] name = "serde_with_macros" -version = "1.5.2" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.79", ] [[package]] @@ -1703,9 +2319,9 @@ dependencies = [ [[package]] name = "sha1_smol" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" [[package]] name = "sha2" @@ -1718,6 +2334,12 @@ dependencies = [ "digest", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1727,6 +2349,18 @@ dependencies = [ "libc", ] +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time 0.3.36", +] + [[package]] name = "slab" version = "0.4.9" @@ -1742,6 +2376,27 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "snafu" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "socket2" version = "0.5.7" @@ -1767,6 +2422,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stdweb" version = "0.4.20" @@ -1829,9 +2490,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" @@ -1852,9 +2513,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -1872,6 +2533,30 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] name = "take_mut" @@ -1885,24 +2570,37 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", ] [[package]] @@ -1991,9 +2689,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -2015,7 +2713,17 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", ] [[package]] @@ -2024,15 +2732,26 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.14", + "rustls-pki-types", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -2044,14 +2763,14 @@ dependencies = [ [[package]] name = "tower" -version = "0.4.13" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite", + "sync_wrapper 0.1.2", "tokio", "tower-layer", "tower-service", @@ -2060,15 +2779,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -2078,61 +2797,38 @@ checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] [[package]] -name = "tracing-core" -version = "0.1.32" +name = "tracing-attributes" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "once_cell", + "proc-macro2", + "quote", + "syn 2.0.79", ] [[package]] -name = "trust-dns-proto" -version = "0.21.2" +name = "tracing-core" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.2.3", - "ipnet", - "lazy_static", - "log", - "rand", - "smallvec", - "thiserror", - "tinyvec", - "tokio", - "url", + "once_cell", ] [[package]] -name = "trust-dns-resolver" -version = "0.21.2" +name = "try-again" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +checksum = "1006cfd66eadaaa9ec7a3d011336e40b98cd6c4d8f7b1e331080f6145ac00671" dependencies = [ - "cfg-if", - "futures-util", - "ipconfig", - "lazy_static", - "log", - "lru-cache", - "parking_lot", - "resolv-conf", - "smallvec", - "thiserror", "tokio", - "trust-dns-proto", + "tracing", ] [[package]] @@ -2152,6 +2848,26 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "typed-builder" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e14ed59dc8b7b26cacb2a92bad2e8b1f098806063898ab42a3bd121d7d45e75" +dependencies = [ + "typed-builder-macro", +] + +[[package]] +name = "typed-builder-macro" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560b82d656506509d43abe30e0ba64c56b1953ab3d4fe7ba5902747a7a3cedd5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.79", +] + [[package]] name = "typenum" version = "1.17.0" @@ -2169,30 +2885,30 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unindent" @@ -2225,19 +2941,25 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", "serde", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "want" @@ -2256,34 +2978,47 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2291,22 +3026,32 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "web-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "webpki-roots" @@ -2348,7 +3093,37 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", ] [[package]] @@ -2366,7 +3141,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -2386,18 +3170,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -2408,9 +3192,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -2420,9 +3204,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -2432,15 +3216,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -2450,9 +3234,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -2462,9 +3246,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -2474,9 +3258,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -2486,9 +3270,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winreg" @@ -2502,10 +3286,11 @@ dependencies = [ [[package]] name = "wipac-disk-tracking" -version = "0.3.0" +version = "0.4.0" dependencies = [ "axum", "axum-extra", + "axum-keycloak-auth", "chrono", "env_logger", "futures-util", @@ -2515,6 +3300,7 @@ dependencies = [ "mongodb", "serde", "serde_json", + "time 0.3.36", "tokio", "uuid", ] @@ -2534,6 +3320,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -2545,5 +3332,11 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.79", ] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index 0a0d554..be81ee3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,23 +1,25 @@ [package] name = "wipac-disk-tracking" -version = "0.3.0" +version = "0.4.0" edition = "2021" publish = false [dependencies] -axum = "0.7.5" -axum-extra = { version = "0.9.3", features = [ "erased-json" ] } +axum = "0.7.7" +axum-extra = { version = "0.9.4", features = [ "erased-json" ] } +axum-keycloak-auth = "0.6.0" chrono = "0.4.38" env_logger = "0.11.5" -futures-util = "0.3.30" +futures-util = "0.3.31" gotham = "0.7.4" gotham_restful = "0.9.0" log = "0.4.22" -mongodb = "3.0.1" -serde = "1.0.208" -serde_json = "1.0.125" -tokio = { version = "1.39.3", features = [ "full" ] } -uuid = { version = "1.10.0", features = [ "serde", "v4" ] } +mongodb = "3.1.0" +serde = "1.0.210" +serde_json = "1.0.128" +time = "0.3.36" +tokio = { version = "1.40.0", features = [ "full" ] } +uuid = { version = "1.11.0", features = [ "serde", "v4" ] } [lib] name = "wipac_disk_tracking" diff --git a/bin/run-app b/bin/run-app index 2c676e8..9722884 100755 --- a/bin/run-app +++ b/bin/run-app @@ -11,6 +11,9 @@ export MONGODB_PASSWORD=${MONGODB_PASSWORD:="hunter2"} export MONGODB_PORT_NUMBER=${MONGODB_PORT_NUMBER:="27017"} export MONGODB_TIMEOUT_SECS=${MONGODB_TIMEOUT_SECS:="5"} export MONGODB_USERNAME=${MONGODB_USERNAME:="disk_tracking"} +export OAUTH_AUDIENCE=${OAUTH_AUDIENCE:="long-term-archive"} # TODO: CHANGE THIS TO disk-tracking !!! +export OAUTH_REALM=${OAUTH_REALM:="IceCube"} +export OAUTH_URL=${OAUTH_URL:="https://keycloak.icecube.wisc.edu/auth"} export PORT=${PORT:="8080"} export RUST_LOG=${RUST_LOG:="debug"} diff --git a/bin/run-app-docker b/bin/run-app-docker index f931366..16eb0f1 100755 --- a/bin/run-app-docker +++ b/bin/run-app-docker @@ -13,6 +13,9 @@ : ${MONGODB_TIMEOUT_SECS:="5"} : ${MONGODB_USERNAME:="disk_tracking"} : ${MONGODB_PORT_NUMBER:="27017"} +: ${OAUTH_AUDIENCE:="disk-tracking"} +: ${OAUTH_REALM:="IceCube"} +: ${OAUTH_URL:="https://keycloak.icecube.wisc.edu/auth"} : ${PORT:="8080"} docker run \ @@ -23,6 +26,8 @@ docker run \ --env=MONGODB_PORT_NUMBER=${MONGODB_PORT_NUMBER} \ --env=MONGODB_TIMEOUT_SECS=${MONGODB_TIMEOUT_SECS} \ --env=MONGODB_USERNAME=${MONGODB_USERNAME} \ + --env=OAUTH_AUDIENCE=${OAUTH_AUDIENCE} \ + --env=OAUTH_URL=${OAUTH_URL} \ --env=PORT=${PORT} \ --env=RUST_LOG=debug \ --link ${DOCKER_MONGO_CONTAINER_NAME}:${DOCKER_MONGO_CONTAINER_NAME} \ diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..e7b9841 --- /dev/null +++ b/client/README.md @@ -0,0 +1,31 @@ +# README.md +wipac-disk-tracking example client (auf Python) + +## Installation +You should first create a Python virtual environment: + + python3 -m venv env + +Then you should activate the Python virtual environment: + + source env/bin/activate + +Then you should install the libraries required by the client: + + pip3 install -r requirements.txt + +Finally, you'll need to create the file `keycloak-client-secret` with the client secret. + + +## Usage +When run, the client will: + +- display information about the keycloak token +- get the /health route to check if the service is healthy +- post an example event to the wipac-disk-tracking service +- get the /health route to check if the service is healthy +- get and display the example event posted to the service + +You can run the client with a helper script: + + client.sh diff --git a/client/client.py b/client/client.py new file mode 100644 index 0000000..6f4e46f --- /dev/null +++ b/client/client.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# client.py + +import asyncio +import json +import logging +import os +from typing import cast, Dict + +from rest_tools.client import ClientCredentialsAuth, RestClient + + +async def main() -> None: + config: Dict[str, str] = { + "BASE_URL": os.getenv("BASE_URL", None), + "CLIENT_ID": os.getenv("CLIENT_ID", None), + "CLIENT_SECRET": os.getenv("CLIENT_SECRET", None), + "OAUTH_URL": os.getenv("OAUTH_URL", None), + "REST_URL": os.getenv("REST_URL", None), + } + + with open('smartctl.json', 'r') as file: + data = json.load(file) + + # http://localhost:8080/ + base_rc: RestClient = RestClient(config["BASE_URL"]) + + # http://localhost:8080/ + Keycloak Credentials + token_rc: RestClient = ClientCredentialsAuth(address=cast(str, config["BASE_URL"]), + token_url=cast(str, config["OAUTH_URL"]), + client_id=cast(str, config["CLIENT_ID"]), + client_secret=cast(str, config["CLIENT_SECRET"])) + + # http://localhost:8080/api/v1 + Keycloak Credentials + rest_rc: RestClient = ClientCredentialsAuth(address=cast(str, config["REST_URL"]), + token_url=cast(str, config["OAUTH_URL"]), + client_id=cast(str, config["CLIENT_ID"]), + client_secret=cast(str, config["CLIENT_SECRET"])) + + response = await token_rc.request("GET", "/token") + print(response, end="\n\n") + + response = await base_rc.request("GET", "/health") + print(response, end="\n\n") + + response = await rest_rc.request("POST", "/events/sighted", data) + print(response, end="\n\n") + + response = await base_rc.request("GET", "/health") + print(response, end="\n\n") + + response = await rest_rc.request("GET", "/events/ZRS1NWBL") + print(response, end="\n\n") + +if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG) + asyncio.run(main()) diff --git a/client/client.sh b/client/client.sh new file mode 100755 index 0000000..e157af7 --- /dev/null +++ b/client/client.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# run the testing client + +export BASE_URL=${HEALTH_URL:="http://localhost:8080"} +export CLIENT_ID=${CLIENT_ID:="long-term-archive"} # TODO: CHANGE THIS TO disk-tracking !!! +export CLIENT_SECRET=${CLIENT_SECRET:="$( Result { let mongo_port = env::var("MONGODB_PORT_NUMBER").unwrap_or_else(|_| "27017".into()); let mongo_database = env::var("MONGODB_DATABASE").unwrap_or_else(|_| "disk_tracking".into()); + // read oauth configuration from the environment + let oauth_audience = env::var("OAUTH_AUDIENCE").unwrap_or_else(|_| "disk-tracking".into()); + let oauth_realm = env::var("OAUTH_REALM").unwrap_or_else(|_| "IceCube".into()); + let oauth_url = + env::var("OAUTH_URL").unwrap_or_else(|_| "https://keycloak.icecube.wisc.edu/auth".into()); + // read application port from the environment let port_str = env::var("PORT").unwrap_or_else(|_| "8080".into()); let port = match port_str.parse::() { @@ -74,6 +83,9 @@ pub async fn build_context() -> Result { mongo_password, mongo_port, mongo_user, + oauth_audience, + oauth_realm, + oauth_url, port, }) } diff --git a/src/error.rs b/src/error.rs index bb70aa9..ae275d2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,6 +2,7 @@ #[derive(Debug)] pub enum ApplicationError { + AuthError(String), ContextError(String), MongoError(String), } @@ -22,6 +23,9 @@ pub type Result = std::result::Result; pub fn get_error_message(e: ApplicationError) -> String { match e { + ApplicationError::AuthError(x) => { + format!("disk-tracking: OAuth Error: {x}") + } ApplicationError::ContextError(x) => { format!("disk-tracking: Unable to build application context: {x}") } diff --git a/src/main.rs b/src/main.rs index 5de5013..57192da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ pub mod middleware; pub mod routes; pub mod smartctl; +use axum_keycloak_auth::{instance::KeycloakAuthInstance, instance::KeycloakConfig, Url}; use log::{error, info}; use std::net::SocketAddr; use tokio::net::TcpListener; @@ -31,12 +32,20 @@ async fn do_main() -> Result<()> { let context = build_context() .await .expect("Unable to build application context"); + // set up keycloak instance for authentication + let keycloak_auth_instance = KeycloakAuthInstance::new( + KeycloakConfig::builder() + .server(Url::parse(&context.oauth_url).unwrap()) + .realm(String::from(&context.oauth_realm)) + .build(), + ); // establish our listening port let listener = TcpListener::bind(format!("0.0.0.0:{}", context.port)) .await .unwrap_or_else(|_| panic!("Unable to listen on port {}", context.port)); // build the application router - let app = build_router(context).into_make_service_with_connect_info::(); + let app = build_router(context, keycloak_auth_instance.into()) + .into_make_service_with_connect_info::(); // start the disk tracking service info!("listening on {}", listener.local_addr().unwrap()); axum::serve(listener, app).await.unwrap(); diff --git a/src/middleware.rs b/src/middleware.rs index ecbb5c8..3df106f 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -4,7 +4,11 @@ use axum::{ extract::ConnectInfo, extract::Request, http::StatusCode, middleware::Next, response::Response, }; use core::net::SocketAddr; -use log::info; +use log::{debug, info}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct EmptyExtra; pub async fn log_request( ConnectInfo(addr): ConnectInfo, @@ -27,3 +31,19 @@ pub async fn log_request( // call the next middleware in the chain Ok(next.run(req).await) } + +pub async fn log_token(req: Request, next: Next) -> Result { + // if we've got an 'Authorization' header in the request + if let Some(header) = req.headers().get("Authorization") { + // and we can obtain the value of that header as a string slice + if let Ok(token) = header.to_str() { + // log about it, and continue in the request processing stack + debug!("Authorization: {}", token); + return Ok(next.run(req).await); + } + } + + // log about the fact that no token was found + debug!("Authorization: None"); + Ok(next.run(req).await) +} diff --git a/src/routes.rs b/src/routes.rs index 5f272bf..d1b9426 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1,19 +1,63 @@ // routes.rs +pub mod health; +pub mod token; pub mod v1; -use axum::{middleware, Router}; +use axum::{http::StatusCode, middleware, response::IntoResponse, Router}; +use axum_keycloak_auth::instance::KeycloakAuthInstance; +use log::error; +use std::sync::Arc; use crate::context::ApplicationContext; -use crate::middleware::log_request; +use crate::middleware::{log_request, log_token}; -pub fn build_router(context: ApplicationContext) -> Router { +pub async fn handle_error(err: E) -> impl IntoResponse +where + E: std::fmt::Display, +{ + eprintln!("Error occurred: {}", err); + error!("Error occurred: {}", err); + ( + StatusCode::INTERNAL_SERVER_ERROR, + "An internal error occurred.", + ) +} + +pub async fn handle_error2() -> impl IntoResponse { + ( + StatusCode::INTERNAL_SERVER_ERROR, + "An internal error occurred", + ) +} + +pub fn build_router(context: ApplicationContext, instance: Arc) -> Router { Router::new() .with_state(context.clone()) - .nest("/api/v1", v1::build_router(context.clone())) + .merge(crate::routes::health::build_router(context.clone())) + .merge(crate::routes::token::build_router( + context.clone(), + instance.clone(), + )) + .nest( + "/api/v1", + crate::routes::v1::build_router(context.clone(), instance.clone()), + ) + .layer(middleware::from_fn(log_token)) .layer(middleware::from_fn(log_request)) } +// async fn get_log_error() -> impl IntoResponse { +// let simulated_error = Some("Database on fire!"); + +// if let Some(err_message) = simulated_error { +// error!("An error occurred: {}", err_message); +// return (StatusCode::INTERNAL_SERVER_ERROR, err_message).into_response(); +// } + +// (StatusCode::OK, "Database only smoking; this is fine, everything is fine.").into_response() +// } + //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- diff --git a/src/routes/v1/health.rs b/src/routes/health.rs similarity index 83% rename from src/routes/v1/health.rs rename to src/routes/health.rs index f986dcc..14535b7 100644 --- a/src/routes/v1/health.rs +++ b/src/routes/health.rs @@ -1,6 +1,6 @@ // health.rs -use axum::{extract::State, http::StatusCode, response::IntoResponse}; +use axum::{extract::State, http::StatusCode, response::IntoResponse, routing::get, Router}; use axum_extra::response::ErasedJson; use serde::Serialize; @@ -16,6 +16,13 @@ struct HealthResponse { pub message: Option, } +pub fn build_router(context: ApplicationContext) -> Router { + // build the routes under /health + Router::new() + .route("/health", get(get_health)) + .with_state(context) +} + pub async fn get_health(context: State) -> impl IntoResponse { match count_disk_events(&context).await { Ok(count) => ( diff --git a/src/routes/token.rs b/src/routes/token.rs new file mode 100644 index 0000000..c39124d --- /dev/null +++ b/src/routes/token.rs @@ -0,0 +1,92 @@ +// token.rs + +use axum::{http::StatusCode, response::IntoResponse, routing::get, Extension, Router}; +use axum_extra::response::ErasedJson; +use axum_keycloak_auth::{ + decode::KeycloakToken, instance::KeycloakAuthInstance, layer::KeycloakAuthLayer, + role::KeycloakRole, PassthroughMode, +}; +use serde::Serialize; +use std::sync::Arc; +use time::OffsetDateTime; + +use crate::context::ApplicationContext; +use crate::middleware::EmptyExtra; + +// function to serialize `OffsetDateTime` as a Unix timestamp +fn serialize_offset_date_time_as_unix_timestamp( + datetime: &OffsetDateTime, + serializer: S, +) -> Result +where + S: serde::Serializer, +{ + let unix_timestamp = datetime.unix_timestamp(); + serializer.serialize_i64(unix_timestamp) +} + +#[derive(Serialize)] +pub struct SerializableToken { + /// Expiration time (UTC). + #[serde(serialize_with = "serialize_offset_date_time_as_unix_timestamp")] + pub expires_at: OffsetDateTime, + /// Issued at time (UTC). + #[serde(serialize_with = "serialize_offset_date_time_as_unix_timestamp")] + pub issued_at: OffsetDateTime, + /// JWT ID (unique identifier for this token). + pub jwt_id: String, + /// Issuer (who created and signed this token). + pub issuer: String, + /// Audience (who or what the token is intended for). + pub audience: Vec, + /// Subject (whom the token refers to). This is the UUID which uniquely identifies this user inside Keycloak. + pub subject: String, + /// Authorized party (the party to which this token was issued). + pub authorized_party: String, + // Keycloak: Roles of the user. + pub roles: Vec>, + // addtional fields (actually, no additional fields) + pub extra: EmptyExtra, +} + +impl From> for SerializableToken { + fn from(token: KeycloakToken) -> Self { + SerializableToken { + expires_at: token.expires_at, + issued_at: token.issued_at, + jwt_id: token.jwt_id, + issuer: token.issuer, + audience: token.audience, + subject: token.subject, + authorized_party: token.authorized_party, + roles: token.roles, + extra: EmptyExtra, + } + } +} + +pub fn build_router(context: ApplicationContext, instance: Arc) -> Router { + // save the audience + let oauth_audience = context.oauth_audience.clone(); + + // build the routes under /token + Router::new() + .route("/token", get(get_token)) + .with_state(context) + .layer( + KeycloakAuthLayer::::builder() + .instance(instance) + .passthrough_mode(PassthroughMode::Block) + .persist_raw_claims(false) + .expected_audiences(vec![oauth_audience]) + .required_roles(vec![String::from("system")]) + .build(), + ) +} + +pub async fn get_token( + Extension(token): Extension>, +) -> impl IntoResponse { + let output_token: SerializableToken = token.into(); + (StatusCode::OK, ErasedJson::pretty(output_token)) +} diff --git a/src/routes/v1.rs b/src/routes/v1.rs index 376b5aa..6a63e98 100644 --- a/src/routes/v1.rs +++ b/src/routes/v1.rs @@ -2,27 +2,41 @@ pub mod disks; pub mod events; -pub mod health; use axum::{ routing::{get, post}, Router, }; +use axum_keycloak_auth::{ + instance::KeycloakAuthInstance, layer::KeycloakAuthLayer, PassthroughMode, +}; +use std::sync::Arc; use crate::context::ApplicationContext; +use crate::middleware::EmptyExtra; use crate::routes::v1::events::{ get_events, post_closed, post_formatted, post_opened, post_sighted, }; -use crate::routes::v1::health::get_health; -pub fn build_router(context: ApplicationContext) -> Router { +pub fn build_router(context: ApplicationContext, instance: Arc) -> Router { + // save the audience + let oauth_audience = context.oauth_audience.clone(); + // build the routes under /api/v1 Router::new() - .route("/health", get(get_health)) .route("/events/closed", post(post_closed)) .route("/events/formatted", post(post_formatted)) .route("/events/opened", post(post_opened)) .route("/events/sighted", post(post_sighted)) .route("/events/:id", get(get_events)) .with_state(context) + .layer( + KeycloakAuthLayer::::builder() + .instance(instance) + .passthrough_mode(PassthroughMode::Block) + .persist_raw_claims(false) + .expected_audiences(vec![oauth_audience]) + .required_roles(vec![String::from("system")]) + .build(), + ) } From 1127c07cee65216f46d2e4930955e104e057ff3d Mon Sep 17 00:00:00 2001 From: Patrick Meade Date: Wed, 16 Oct 2024 03:38:48 -0500 Subject: [PATCH 5/6] Install OpenSSL for Docker image build --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 0f016f8..27ddb29 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,8 @@ #---------------------------------------------------------------------------- FROM rust:slim-bookworm AS build +RUN apt-get update && apt-get install -y libssl-dev pkg-config build-essential + COPY Cargo.lock Cargo.toml /build/ COPY src /build/src From 6246546333c77190f46117db68b37c9c89386bd5 Mon Sep 17 00:00:00 2001 From: Patrick Meade Date: Mon, 21 Oct 2024 20:10:10 -0500 Subject: [PATCH 6/6] Final clean up for merging --- .github/workflows/ci.yml | 8 +-- Cargo.lock | 95 +++++++++++++++++------------------ Cargo.toml | 2 +- README.md | 106 ++++++++++++++++++++++++++++----------- bin/run-app | 2 +- client/client.sh | 4 +- 6 files changed, 132 insertions(+), 85 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83c7b7e..21508ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,10 +18,12 @@ jobs: steps: - uses: actions/checkout@v4 - run: rustup update stable && rustup default stable - - run: cargo fmt --check - - run: cargo clippy --locked - - run: cargo install cargo-outdated - run: cargo outdated --root-deps-only --exit-code 1 + - run: cargo fmt --all -- --check + - run: cargo generate-lockfile --locked + - run: cargo check --locked + - run: cargo clippy --locked + - run: cargo verify-project --locked test: name: Test diff --git a/Cargo.lock b/Cargo.lock index 75c9f58..940e1fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,9 +105,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95" [[package]] name = "async-trait" @@ -117,7 +117,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -371,15 +371,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "cc" -version = "1.1.30" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "shlex", ] @@ -489,7 +489,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -500,7 +500,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -540,7 +540,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -569,7 +569,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -596,7 +596,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -616,7 +616,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -756,7 +756,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -858,7 +858,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39260b1324f4cf40bf4d86e4aa3a7574fabf6b25fe1b07345b776698d2a0459" dependencies = [ "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -888,7 +888,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "unindent", ] @@ -1154,7 +1154,7 @@ dependencies = [ "http 1.1.0", "hyper 1.5.0", "hyper-util", - "rustls 0.23.14", + "rustls 0.23.15", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -1341,7 +1341,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1419,9 +1419,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "linked-hash-map" @@ -1581,7 +1581,7 @@ checksum = "3a6dbc533e93429a71c44a14c04547ac783b56d3f22e6c4f12b1b994cf93844e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1668,9 +1668,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" -version = "0.10.67" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8cefcf97f41316955f9294cd61f639bdcfa9f2f230faac6cb896aa8ab64704" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -1689,7 +1689,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1781,7 +1781,7 @@ checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -1831,9 +1831,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -2056,9 +2056,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.14" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "once_cell", "rustls-pki-types", @@ -2229,14 +2229,14 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "indexmap 2.6.0", "itoa", @@ -2294,7 +2294,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2394,7 +2394,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2513,9 +2513,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", @@ -2600,7 +2600,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2713,7 +2713,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2742,7 +2742,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.14", + "rustls 0.23.15", "rustls-pki-types", "tokio", ] @@ -2809,7 +2809,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2865,7 +2865,7 @@ checksum = "560b82d656506509d43abe30e0ba64c56b1953ab3d4fe7ba5902747a7a3cedd5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] @@ -2876,12 +2876,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" @@ -2998,7 +2995,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "wasm-bindgen-shared", ] @@ -3032,7 +3029,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3332,7 +3329,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.82", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index be81ee3..c3d90cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ gotham_restful = "0.9.0" log = "0.4.22" mongodb = "3.1.0" serde = "1.0.210" -serde_json = "1.0.128" +serde_json = "1.0.132" time = "0.3.36" tokio = { version = "1.40.0", features = [ "full" ] } uuid = { version = "1.11.0", features = [ "serde", "v4" ] } diff --git a/README.md b/README.md index faf09c3..f96e7d7 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,93 @@ # wipac-disk-tracking Archival media tracking service for WIPAC -## API -The REST API for the wipac-disk-tracking service is documented below. +## Routes +The following routes are supported in the wipac-disk-tracking service: -The API is rooted at: +### API / +These routes live at the root of the service. - /api/v1 +#### GET /health +This route allows a client to query the health of the service. Mostly, +this is just a check if the service can access the database that stores +the disk events. This route requires no authentication, and can be +checked with a simple `curl` command: -### Disks -Disks represent a collection of unique archival disks. While the disk -entity does carry some immutable identifying information, it is mostly -a container for archival disk events. + curl -v http://localhost:8080/health && echo "" -#### Routes -These routes are implemented to work with disks: +A healthy response is 200, along with some JSON indicating the status +of the service. Here `count` is a simple count of disk events stored +in the backing database: - GET /disks/:disk_id Get the data for a given disk - GET /disks/:disk_id/events Get all of the events for a given disk - GET /disks/:disk_id/events/:event_id Get the data for a given event for a given disk - GET /disks/:disk_id/search?query Find a disk based on a key-value query + { + "status": "ok", + "count": 0 + } -### Events -Events represent a record of an event involving an archival disk. -There are four distinct events that are tracked by the system. +An unhealthy response is 500, along with some JSON indicating the error +the service is experiencing connecting to the database: - sighted This disk was observed to be loaded in a host that processes archival disks - formatted This disk was given a file system to make it ready for archival purposes - opened This disk was given a label and was designated for active archival activity - closed This disk was determined to full/finished and archival activity stopped + { + "status": "error", + "message": "Failed to connect to the database: MongoError(\"Kind: Server selection timeout: No available servers. Topology: { Type: Single, Servers: [ { Address: localhost:27017, Type: Unknown, Error: Kind: I/O error: Connection refused (os error 111), labels: {} } ] }, labels: {}\")" + } -The format for each of these events is specified with a JSON Schema file. +#### GET /token +This route allows a client to query the service's view of its token +issued by Keycloak for authorization. This route exists for debugging +purposes. -#### Routes -These routes are implemented to work with events: +The client can also inspect its token in a service like [jwt.io](https://jwt.io). - POST /events/closed Create a new 'closed' event - POST /events/formatted Create a new 'formatted' event - POST /events/opened Create a new 'opened' event - POST /events/sighted Create a new 'sighted' event - GET /events/:event_id Get the data for a given event +This route offers a view of 'how did the service parse my token' or +'how does the service see my authorization grants'? + +### API /api/v1 +These routes live under /api/v1. + +#### GET /events/:event_id +Get the data for a given event. This route is actually multi-purpose. + +If you specify the UUID assigned to an event, you can find the record +for a specific event: + + GET /api/v1/events/0badfdd0-963a-4b25-9af6-1acc52c5d334 + +If you specify the serial number of a disk, you can find the records of +every event referencing that serial number: + + GET /api/v1/events/ZRS1NWBL + +In both cases, a successful query will return with the structure like +this one: + + { + "events": [ + { + smartctl-event-here + }, + ... + { + smartctl-event-here + } + ] + } + +#### POST /events/closed +Create a new 'closed' event. This disk was determined to full/finished +and archival activity stopped. + +#### POST /events/formatted +Create a new 'formatted' event. This disk was given a file system to +make it ready for archival purposes. + +#### POST /events/opened +Create a new 'opened' event. This disk was given a label and was +designated for active archival activity. + +#### POST /events/sighted +Create a new 'sighted' event. This disk was observed to be loaded in a +host that processes archival disks. ## Development As typical in a Rust project, you can run the unit and integration tests with: diff --git a/bin/run-app b/bin/run-app index 9722884..b601e94 100755 --- a/bin/run-app +++ b/bin/run-app @@ -11,7 +11,7 @@ export MONGODB_PASSWORD=${MONGODB_PASSWORD:="hunter2"} export MONGODB_PORT_NUMBER=${MONGODB_PORT_NUMBER:="27017"} export MONGODB_TIMEOUT_SECS=${MONGODB_TIMEOUT_SECS:="5"} export MONGODB_USERNAME=${MONGODB_USERNAME:="disk_tracking"} -export OAUTH_AUDIENCE=${OAUTH_AUDIENCE:="long-term-archive"} # TODO: CHANGE THIS TO disk-tracking !!! +export OAUTH_AUDIENCE=${OAUTH_AUDIENCE:="disk-tracking"} export OAUTH_REALM=${OAUTH_REALM:="IceCube"} export OAUTH_URL=${OAUTH_URL:="https://keycloak.icecube.wisc.edu/auth"} export PORT=${PORT:="8080"} diff --git a/client/client.sh b/client/client.sh index e157af7..58b3700 100755 --- a/client/client.sh +++ b/client/client.sh @@ -2,8 +2,8 @@ # run the testing client export BASE_URL=${HEALTH_URL:="http://localhost:8080"} -export CLIENT_ID=${CLIENT_ID:="long-term-archive"} # TODO: CHANGE THIS TO disk-tracking !!! -export CLIENT_SECRET=${CLIENT_SECRET:="$(