diff --git a/Cargo.lock b/Cargo.lock index 5621d8e..281fb6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -148,6 +154,435 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-config" +version = "1.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c478f5b10ce55c9a33f87ca3404ca92768b144fc1bfdede7c0121214a8283a25" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-sdk-sso", + "aws-sdk-ssooidc", + "aws-sdk-sts", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "hex", + "http 1.3.1", + "ring", + "time", + "tokio", + "tracing", + "url", + "zeroize", +] + +[[package]] +name = "aws-credential-types" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1541072f81945fa1251f8795ef6c92c4282d74d59f88498ae7d4bf00f0ebdad9" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", +] + +[[package]] +name = "aws-lc-rs" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "aws-runtime" +version = "1.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c034a1bc1d70e16e7f4e4caf7e9f7693e4c9c24cd91cf17c2a0b21abaebc7c8b" +dependencies = [ + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "http 0.2.12", + "http-body 0.4.6", + "percent-encoding", + "pin-project-lite", + "tracing", + "uuid", +] + +[[package]] +name = "aws-sdk-s3" +version = "1.103.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af040a86ae4378b7ed2f62c83b36be1848709bbbf5757ec850d0e08596a26be9" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-checksums", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "bytes", + "fastrand", + "hex", + "hmac", + "http 0.2.12", + "http 1.3.1", + "http-body 0.4.6", + "lru", + "percent-encoding", + "regex-lite", + "sha2", + "tracing", + "url", +] + +[[package]] +name = "aws-sdk-sso" +version = "1.81.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79ede098271e3471036c46957cba2ba30888f53bda2515bf04b560614a30a36e" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "http 0.2.12", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-ssooidc" +version = "1.82.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43326f724ba2cc957e6f3deac0ca1621a3e5d4146f5970c24c8a108dac33070f" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "http 0.2.12", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-sts" +version = "1.83.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5468593c47efc31fdbe6c902d1a5fde8d9c82f78a3f8ccfe907b1e9434748cb" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-query", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "fastrand", + "http 0.2.12", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sigv4" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084c34162187d39e3740cb635acd73c4e3a551a36146ad6fe8883c929c9f876c" +dependencies = [ + "aws-credential-types", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "crypto-bigint 0.5.5", + "form_urlencoded", + "hex", + "hmac", + "http 0.2.12", + "http 1.3.1", + "p256", + "percent-encoding", + "ring", + "sha2", + "subtle", + "time", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-async" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e190749ea56f8c42bf15dd76c65e14f8f765233e6df9b0506d9d934ebef867c" +dependencies = [ + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "aws-smithy-checksums" +version = "0.63.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dbef71cd3cf607deb5c407df52f7e589e6849b296874ee448977efbb6d0832b" +dependencies = [ + "aws-smithy-http", + "aws-smithy-types", + "bytes", + "crc-fast", + "hex", + "http 0.2.12", + "http-body 0.4.6", + "md-5", + "pin-project-lite", + "sha1", + "sha2", + "tracing", +] + +[[package]] +name = "aws-smithy-eventstream" +version = "0.60.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604c7aec361252b8f1c871a7641d5e0ba3a7f5a586e51b66bc9510a5519594d9" +dependencies = [ + "aws-smithy-types", + "bytes", + "crc32fast", +] + +[[package]] +name = "aws-smithy-http" +version = "0.62.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c4dacf2d38996cf729f55e7a762b30918229917eca115de45dfa8dfb97796c9" +dependencies = [ + "aws-smithy-eventstream", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http 1.3.1", + "http-body 0.4.6", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + +[[package]] +name = "aws-smithy-http-client" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f108f1ca850f3feef3009bdcc977be201bca9a91058864d9de0684e64514bee0" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "h2 0.3.27", + "h2 0.4.11", + "http 0.2.12", + "http 1.3.1", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper 1.6.0", + "hyper-rustls 0.24.2", + "hyper-rustls 0.27.7", + "hyper-util", + "pin-project-lite", + "rustls 0.21.12", + "rustls 0.23.31", + "rustls-native-certs 0.8.1", + "rustls-pki-types", + "tokio", + "tower", + "tracing", +] + +[[package]] +name = "aws-smithy-json" +version = "0.61.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a16e040799d29c17412943bdbf488fd75db04112d0c0d4b9290bacf5ae0014b9" +dependencies = [ + "aws-smithy-types", +] + +[[package]] +name = "aws-smithy-observability" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9364d5989ac4dd918e5cc4c4bdcc61c9be17dcd2586ea7f69e348fc7c6cab393" +dependencies = [ + "aws-smithy-runtime-api", +] + +[[package]] +name = "aws-smithy-query" +version = "0.60.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fbd61ceb3fe8a1cb7352e42689cec5335833cd9f94103a61e98f9bb61c64bb" +dependencies = [ + "aws-smithy-types", + "urlencoding", +] + +[[package]] +name = "aws-smithy-runtime" +version = "1.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e107ce0783019dbff59b3a244aa0c114e4a8c9d93498af9162608cd5474e796" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-http-client", + "aws-smithy-observability", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "fastrand", + "http 0.2.12", + "http 1.3.1", + "http-body 0.4.6", + "http-body 1.0.1", + "pin-project-lite", + "pin-utils", + "tokio", + "tracing", +] + +[[package]] +name = "aws-smithy-runtime-api" +version = "1.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75d52251ed4b9776a3e8487b2a01ac915f73b2da3af8fc1e77e0fce697a550d4" +dependencies = [ + "aws-smithy-async", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.3.1", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-types" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d498595448e43de7f4296b7b7a18a8a02c61ec9349128c80a368f7c3b4ab11a8" +dependencies = [ + "base64-simd", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http 1.3.1", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "itoa", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", + "serde", + "time", + "tokio", + "tokio-util", +] + +[[package]] +name = "aws-smithy-xml" +version = "0.60.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db87b96cb1b16c024980f133968d52882ca0daaee3a086c6decc500f6c99728" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "aws-types" +version = "1.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b069d19bf01e46298eaedd7c6f283fe565a59263e53eebec945f3e6398f42390" +dependencies = [ + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "rustc_version", + "tracing", +] + [[package]] name = "axum" version = "0.8.4" @@ -158,10 +593,10 @@ dependencies = [ "bytes", "form_urlencoded", "futures-util", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-util", "itoa", "matchit", @@ -190,8 +625,8 @@ checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" dependencies = [ "bytes", "futures-core", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", @@ -217,6 +652,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + [[package]] name = "base64" version = "0.21.7" @@ -229,6 +670,45 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags 2.9.1", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -265,9 +745,9 @@ dependencies = [ "futures-core", "futures-util", "hex", - "http", + "http 1.3.1", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-named-pipe", "hyper-util", "hyperlocal", @@ -316,15 +796,36 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "bytes-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +dependencies = [ + "bytes", + "either", +] + [[package]] name = "cc" version = "1.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" dependencies = [ + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -346,6 +847,17 @@ dependencies = [ "windows-link", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.43" @@ -386,6 +898,15 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + [[package]] name = "colorchoice" version = "1.0.4" @@ -411,6 +932,12 @@ dependencies = [ "yaml-rust2", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const-random" version = "0.1.18" @@ -450,6 +977,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -465,6 +1002,34 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc-fast" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bf62af4cc77d8fe1c22dde4e721d87f2f54056139d8c412e1366b740305f56f" +dependencies = [ + "crc", + "digest", + "libc", + "rand", + "regex", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -504,6 +1069,28 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -514,6 +1101,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "deranged" version = "0.4.0" @@ -532,6 +1129,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -554,12 +1152,56 @@ dependencies = [ "const-random", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "dyn-clone" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint 0.4.9", + "der", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -591,6 +1233,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "fnv" version = "1.0.7" @@ -637,6 +1289,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures" version = "0.3.31" @@ -774,6 +1432,42 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.10.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.11" @@ -785,7 +1479,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http", + "http 1.3.1", "indexmap 2.10.0", "slab", "tokio", @@ -811,6 +1505,8 @@ version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ + "allocator-api2", + "equivalent", "foldhash", ] @@ -835,6 +1531,35 @@ 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 = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.3.1" @@ -846,6 +1571,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.1" @@ -853,7 +1589,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.3.1", ] [[package]] @@ -864,8 +1600,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "pin-project-lite", ] @@ -881,6 +1617,30 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.6.0" @@ -890,9 +1650,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.11", + "http 1.3.1", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -909,7 +1669,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" dependencies = [ "hex", - "hyper", + "hyper 1.6.0", "hyper-util", "pin-project-lite", "tokio", @@ -917,19 +1677,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "log", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http", - "hyper", + "http 1.3.1", + "hyper 1.6.0", "hyper-util", - "rustls", + "rustls 0.23.31", + "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.2", "tower-service", ] @@ -941,7 +1718,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-util", "native-tls", "tokio", @@ -960,14 +1737,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "http", - "http-body", - "hyper", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.6.0", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.0", "system-configuration", "tokio", "tower-service", @@ -983,7 +1760,7 @@ checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" dependencies = [ "hex", "http-body-util", - "hyper", + "hyper 1.6.0", "hyper-util", "pin-project-lite", "tokio", @@ -1185,12 +1962,31 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -1218,12 +2014,34 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.53.3", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -1252,6 +2070,15 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.4", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1267,6 +2094,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.5" @@ -1279,6 +2116,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1311,11 +2154,21 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1343,6 +2196,15 @@ dependencies = [ "syn", ] +[[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" @@ -1427,12 +2289,29 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "p256" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" +dependencies = [ + "ecdsa", + "elliptic-curve", + "sha2", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -1549,6 +2428,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.32" @@ -1570,6 +2459,25 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -1594,6 +2502,44 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1664,6 +2610,12 @@ dependencies = [ "regex-syntax 0.8.5", ] +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + [[package]] name = "regex-syntax" version = "0.6.29" @@ -1686,12 +2638,12 @@ dependencies = [ "bytes", "encoding_rs", "futures-core", - "h2", - "http", - "http-body", + "h2 0.4.11", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", - "hyper", - "hyper-rustls", + "hyper 1.6.0", + "hyper-rustls 0.27.7", "hyper-tls", "hyper-util", "js-sys", @@ -1716,6 +2668,17 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac", + "zeroize", +] + [[package]] name = "ring" version = "0.17.14" @@ -1758,6 +2721,34 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + [[package]] name = "rustix" version = "1.0.8" @@ -1767,23 +2758,69 @@ dependencies = [ "bitflags 2.9.1", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.9.4", "windows-sys 0.60.2", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ + "aws-lc-rs", "once_cell", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.4", "subtle", "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.3.0", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -1793,12 +2830,23 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -1855,6 +2903,30 @@ 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 = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "2.11.1" @@ -1862,7 +2934,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.9.1", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -1878,6 +2963,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + [[package]] name = "serde" version = "1.0.219" @@ -1971,6 +3062,17 @@ dependencies = [ "time", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.9" @@ -2006,24 +3108,38 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "silserv" -version = "0.1.1" +version = "0.1.2" dependencies = [ "anyhow", "async-trait", + "aws-config", + "aws-sdk-s3", "axum", + "base64 0.22.1", "bollard", "chrono", "clap", "config", "futures", - "hyper", + "hyper 1.6.0", "ipnet", "regex", "reqwest", "serde", "serde_json", + "sha2", "sled", "thiserror", "tokio", @@ -2064,6 +3180,16 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket2" version = "0.6.0" @@ -2074,6 +3200,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -2130,7 +3266,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.9.1", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -2153,7 +3289,7 @@ dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix", + "rustix 1.0.8", "windows-sys 0.59.0", ] @@ -2251,7 +3387,7 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "slab", - "socket2", + "socket2 0.6.0", "tokio-macros", "windows-sys 0.59.0", ] @@ -2292,13 +3428,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls", + "rustls 0.23.31", "tokio", ] @@ -2395,8 +3541,8 @@ dependencies = [ "bitflags 2.9.1", "bytes", "futures-util", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "iri-string", "pin-project-lite", "tower", @@ -2526,6 +3672,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -2568,6 +3720,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "want" version = "0.3.1" @@ -2673,6 +3831,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2945,6 +4115,12 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + [[package]] name = "yaml-rust2" version = "0.10.3" @@ -2980,6 +4156,26 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zerofrom" version = "0.1.6" diff --git a/Cargo.toml b/Cargo.toml index 3d15077..dbb0b68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "silserv" -version = "0.1.1" +version = "0.1.2" edition = "2024" authors = ["pakin"] description = "Container manager service for testing" @@ -8,7 +8,10 @@ description = "Container manager service for testing" [dependencies] anyhow = "1.0.98" async-trait = "0.1.88" +aws-config = { version = "1.8.5", features = ["behavior-version-latest"] } +aws-sdk-s3 = "1.103.0" axum = "0.8.4" +base64 = "0.22.1" bollard = "0.19.2" chrono = { version = "0.4.41", features = ["serde"] } clap = { version = "4.5.43", features = ["derive"] } @@ -20,6 +23,7 @@ regex = "1.11.1" reqwest = { version = "0.12.22", features = ["json"] } serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.142" +sha2 = "0.10.9" sled = "0.34.7" thiserror = "2.0.12" tokio = { version = "1.47.1", features = ["full"] } diff --git a/src/api.rs b/src/api.rs index 2f11cdb..c664d96 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,12 +1,14 @@ +use aws_sdk_s3::operation::list_objects_v2::ListObjectsV2Output; use axum::{ Router, + body::Body, extract::{Path, Query, State}, http::StatusCode, response::{IntoResponse, Json, Response}, - routing::{get, post}, + routing::{delete, get, post, put}, }; use serde::{Deserialize, Serialize}; -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; use tokio::sync::Mutex; use tower::ServiceBuilder; use tower_http::{ @@ -30,6 +32,8 @@ pub struct ApiServer { discovery: Arc, storage: Arc, log_manager: Arc, + s3_client: aws_sdk_s3::Client, + garage_endpoint: String, } #[derive(Clone)] @@ -38,6 +42,10 @@ pub struct AppState { pub discovery: Arc, pub storage: Arc, pub log_manager: Arc, + + // garage + pub s3_client: aws_sdk_s3::Client, + pub garage_endpoint: String, } impl ApiServer { @@ -47,6 +55,8 @@ impl ApiServer { discovery: Arc, storage: Arc, log_manager: Arc, + s3_client: aws_sdk_s3::Client, + garage_endpoint: String, ) -> Self { Self { port, @@ -54,6 +64,8 @@ impl ApiServer { discovery, storage, log_manager, + s3_client, + garage_endpoint, } } @@ -63,6 +75,8 @@ impl ApiServer { discovery: self.discovery, storage: self.storage, log_manager: self.log_manager.clone(), + s3_client: self.s3_client, + garage_endpoint: self.garage_endpoint, }; let app = Router::new() @@ -74,6 +88,7 @@ impl ApiServer { .route("/api/containers/{id}", get(get_container)) .route("/api/containers/{id}/update", post(trigger_update)) .route("/api/containers/{id}/force-update", post(force_update)) + .route("/api/containers/{id}/rollback", post(force_rollback)) // Discovery endpoints .route("/api/discovery/scan", post(force_discovery)) .route("/api/discovery/containers", get(get_discovered_containers)) @@ -84,6 +99,14 @@ impl ApiServer { .route("/api/logs/dates", get(get_log_dates)) // Bulk operations .route("/api/bulk/update-check", post(bulk_update_check)) + // TODO: communicate with garage s3 + // .route("/api/s3/{bucket}", get(handler)) + // .route("/api/s3/{bucket}", put(handler)) + // .route("/api/s3/{bucket}", delete(handler)) + // .route("/api/s3/{bucket}/{key}", get(handler)) + // .route("/api/s3/{bucket}/{key}", put(handler)) + // .route("/api/s3/{bucket}/{key}", delete(handler)) + // TODO: Online installations .with_state(state) .layer( ServiceBuilder::new() @@ -214,8 +237,8 @@ async fn system_status(State(state): State) -> Json, + State(state): State, +) -> Result>, ApiError> { + // find images with format of -backup- + { + let mgr = state.update_manager.lock().await; + let container = mgr.get_container(&id).await; + + match container { + Ok(mut c) => { + mgr.attempt_rollback(&mut c).await?; + } + Err(err) => { + error!("Failed to get container: {}", err); + return Ok(Json(ApiResponse::error(err.to_string()))); + } + } + } + + let success = RollbackResponse { + message: "Rollback completed successfully".to_string(), + }; + + Ok(Json(ApiResponse::success(success))) +} + async fn get_discovered_containers( State(state): State, ) -> Result>>, ApiError> { @@ -459,6 +509,55 @@ async fn bulk_update_check( Ok(Json(ApiResponse::success(response))) } +// get object list +async fn list_objects( + State(state): State, + Path(bucket): Path, + Query(params): Query>, +) -> Result>, ApiError> { + let mut list_request = state.s3_client.list_objects_v2().bucket(&bucket); + + if let Some(prefix) = params.get("prefix") { + list_request = list_request.prefix(prefix); + } + + let response: ListObjectsV2Output = list_request.send().await?; + + if response.contents.is_some() { + let mapped = response + .contents() + .iter() + .map(|obj| { + let mut hashmap = HashMap::new(); + hashmap.insert("Key".to_string(), obj.key().unwrap().to_string()); + hashmap.insert("Size".to_string(), obj.size().unwrap().to_string()); + hashmap.insert( + "LastModified".to_string(), + obj.last_modified().unwrap().to_string(), + ); + hashmap.insert("ETag".to_string(), obj.e_tag().unwrap().to_string()); + hashmap.insert( + "StorageClass".to_string(), + obj.storage_class().unwrap().to_string(), + ); + hashmap.insert( + "Owner".to_string(), + obj.owner().unwrap().id().unwrap().to_string(), + ); + hashmap + }) + .collect::>>(); + + // let mut response = Response::builder() + // .status(StatusCode::OK) + // .body(Body::new(mapped)) + // .unwrap(); + Ok(Json(ApiResponse::success(serde_json::json!(mapped)))) + } else { + Ok(Json(ApiResponse::success(serde_json::json!({})))) + } +} + // Request/Response types #[derive(Debug, Deserialize)] @@ -546,6 +645,11 @@ struct BulkUpdateResult { error: Option, } +#[derive(Debug, Serialize)] +struct RollbackResponse { + message: String, +} + // Error handling #[derive(Debug)] diff --git a/src/config.rs b/src/config.rs index 3cb390b..e321bae 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,6 +12,7 @@ pub struct Config { pub registry: RegistryConfig, pub storage: StorageConfig, bearer: String, + s3: S3Config, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -47,6 +48,14 @@ pub struct StorageConfig { pub path: String, } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct S3Config { + pub access_key_id: String, + pub secret_access_key: String, + pub region: String, + pub endpoint: String, +} + impl Default for Config { fn default() -> Self { Self { @@ -74,6 +83,12 @@ impl Default for Config { path: "./data/silserv.db".to_string(), }, bearer: "".to_string(), + s3: S3Config { + access_key_id: "".to_string(), + secret_access_key: "".to_string(), + region: "".to_string(), + endpoint: "".to_string(), + }, } } } @@ -103,4 +118,12 @@ impl Config { pub fn bearer(&self) -> &str { &self.bearer } + + pub fn get_s3_access_key_id(&self) -> &str { + &self.s3.access_key_id + } + + pub fn get_s3_secret_access_key(&self) -> &str { + &self.s3.secret_access_key + } } diff --git a/src/main.rs b/src/main.rs index 07808ad..b7c06c2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use anyhow::Result; use clap::Parser; -use std::sync::Arc; -use tracing::{info, warn}; +use std::{path::PathBuf, sync::Arc}; +use tracing::{error, info, warn}; mod api; mod config; @@ -12,10 +12,17 @@ mod registry; mod storage; mod types; mod updater; +// mod zmq; +mod nproc; use crate::{ - api::ApiServer, config::Config, discovery::ContainerDiscovery, logging::LogManager, - storage::Storage, updater::UpdateManager, + api::ApiServer, + config::Config, + discovery::ContainerDiscovery, + logging::LogManager, + storage::Storage, + updater::UpdateManager, + // zmq::{SocketConfig, ZmqBackend}, }; #[derive(Parser, Debug)] @@ -114,6 +121,75 @@ async fn main() -> Result<()> { }) }; + // s3 garage + let config = aws_sdk_s3::Config::builder() + .endpoint_url("http://localhost:3900") + .region(aws_sdk_s3::config::Region::new("garage")) + .credentials_provider( + aws_sdk_s3::config::Credentials::builder() + .provider_name("garage") + .access_key_id(config.clone().get_s3_access_key_id()) + .secret_access_key(config.clone().get_s3_secret_access_key()) + .build(), + ) + .behavior_version_latest() + .build(); + let s3client = aws_sdk_s3::Client::from_conf(config); + + // ZMQ + // let download_dir = PathBuf::from("./downloads"); + // let mut zmq_manager = Arc::new(ZmqBackend::new( + // 36540, + // Some("127.0.0.1".to_string()), + // Some(download_dir), + // )); + + // // publisher + // let publisher_endpoint = zmq_manager + // .add_socket( + // "publisher".to_string(), + // SocketConfig::publish(None, vec![]).with_bind(true), + // ) + // .await?; + + // info!("zmq.publisher: {}", publisher_endpoint); + + // let subscriber_endpoint = zmq_manager + // .add_socket( + // "subscriber".to_string(), + // SocketConfig::subscribe(None, vec!["files".to_string(), "news".to_string()]), + // ) + // .await?; + + // info!("zmq.subscriber: {}", subscriber_endpoint); + + // zmq_manager + // .add_socket( + // "file_server".to_string(), + // SocketConfig::pull(None).with_bind(true), + // ) + // .await?; + + // zmq_manager + // .add_socket("file_client".to_string(), SocketConfig::push(None)) + // .await?; + + // let _ = zmq_manager.start_receivers().await; + + // nproc + // let nproc_listener = tokio::net::TcpListener::bind(&"0.0.0.0:36540").await?; + // let nproc_state = nproc::ServerState::new(); + let reply_key = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + + let pubsub_nproc = { + let addr = "0.0.0.0:36540".to_string(); + tokio::spawn(async move { + if let Err(e) = nproc::run_server(&addr, *reply_key).await { + error!("pubsub server exited: {e}"); + } + }) + }; + // Start API server let api_server = ApiServer::new( args.port, @@ -121,6 +197,8 @@ async fn main() -> Result<()> { discovery.clone(), storage.clone(), log_manager.clone(), + s3client.clone(), + "http://localhost:3900".to_string(), ); info!("🌐 Starting API server on port {}", args.port); @@ -137,6 +215,9 @@ async fn main() -> Result<()> { result = update_handle => { tracing::error!("Update scheduler stopped: {:?}", result); } + result = pubsub_nproc => { + tracing::error!("Nproc stopped: {:?}", result); + } _ = tokio::signal::ctrl_c() => { info!("🛑 Received shutdown signal"); } diff --git a/src/nproc.rs b/src/nproc.rs new file mode 100644 index 0000000..3657c2a --- /dev/null +++ b/src/nproc.rs @@ -0,0 +1,290 @@ +use std::{ + collections::{HashMap, HashSet}, + net::SocketAddr, + sync::{Arc, atomic::AtomicUsize}, +}; + +use tokio::{ + io::{AsyncReadExt, AsyncWriteExt}, + net::TcpStream, + sync::{Mutex, RwLock, mpsc}, +}; + +pub const API_KEY_LEN: usize = 32; +const MAX_FRAME: usize = 1 << 22; +const MAX_TOPIC: usize = 256; +const N_SHARDS: usize = 32; +const WRITER_QUEUE_CAP: usize = 256; + +#[derive(Clone)] +pub struct ConnectionHandle { + tx: tokio::sync::mpsc::Sender>>, +} + +type TopicSubs = HashMap>; + +pub struct ServerState { + shards: Vec>, + conns: RwLock>, + next_id: AtomicUsize, +} + +impl ServerState { + pub fn new() -> Self { + let mut shards = Vec::with_capacity(N_SHARDS); + for _ in 0..N_SHARDS { + shards.push(Mutex::new(HashMap::new())); + } + Self { + shards, + conns: RwLock::new(HashMap::new()), + next_id: AtomicUsize::new(1), + } + } + + pub fn shard_idx(topic: &str) -> usize { + let mut h: u64 = 1469598103934665603; + for b in topic.as_bytes() { + h ^= *b as u64; + h = h.wrapping_mul(1099511628211); + } + (h as usize) % N_SHARDS + } +} + +#[inline] +fn be_u32(b: &[u8]) -> u32 { + u32::from_be_bytes([b[0], b[1], b[2], b[3]]) +} + +#[inline] +fn put_be_u32(buf: &mut Vec, v: u32) { + buf.extend_from_slice(&v.to_be_bytes()); +} + +fn build_frame_arc(t: u8, topic: &[u8], body: &[u8], key: &[u8; API_KEY_LEN]) -> Arc> { + let payload = 1 + 2 + 4 + topic.len() + body.len(); + let total = payload + API_KEY_LEN; + let mut buf = Vec::with_capacity(4 + total); + put_be_u32(&mut buf, total as u32); + buf.push(t); + buf.extend_from_slice(&(topic.len() as u16).to_be_bytes()); + buf.extend_from_slice(&(body.len() as u32).to_be_bytes()); + buf.extend_from_slice(topic); + buf.extend_from_slice(body); + buf.extend_from_slice(key); + Arc::new(buf) +} + +fn parse_one(buf: &[u8]) -> Option<(u8, Vec, Vec, [u8; API_KEY_LEN], usize)> { + if buf.len() < 4 { + return None; + } + let total = be_u32(&buf[0..4]) as usize; + if buf.len() < 4 + total { + return None; + } + let err_value = Some((0, vec![], vec![], [0; API_KEY_LEN], 4 + total)); + let pl = &buf[4..4 + total]; + if total < API_KEY_LEN + 1 + 2 + 4 { + return err_value; + } + let key_off = pl.len() - API_KEY_LEN; + let (hdr, keyb) = pl.split_at(key_off); + let mut key = [0u8; API_KEY_LEN]; + key.copy_from_slice(keyb); + let t = hdr[0]; + let tl = usize::from(u16::from_be_bytes([hdr[1], hdr[2]])); + let bl = usize::from(u32::from_be_bytes([hdr[3], hdr[4], hdr[5], hdr[6]]) as usize); + if tl > MAX_TOPIC { + return err_value; + } + let need = 1 + 2 + 4 + tl + bl; + if hdr.len() != need { + return err_value; + } + let mut off = 7; + let topic = hdr[off..off + tl].to_vec(); + off += tl; + let body = hdr[off..off + bl].to_vec(); + Some((t, topic, body, key, 4 + total)) +} + +pub async fn handle_connection( + st: Arc, + sock: TcpStream, + _peer: SocketAddr, + reply_key: [u8; API_KEY_LEN], +) -> std::io::Result<()> { + let (mut rd, mut wr) = sock.into_split(); + let (tx, mut rx) = mpsc::channel::>>(WRITER_QUEUE_CAP); + let writer = tokio::spawn(async move { + while let Some(b) = rx.recv().await { + if wr.write_all(&b).await.is_err() { + break; + } + } + }); + let id = st + .next_id + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + { + st.conns + .write() + .await + .insert(id, ConnectionHandle { tx: tx.clone() }); + } + + let my = Arc::new(Mutex::new(HashSet::::new())); + let mut acc = Vec::::with_capacity(8192); + let mut tmp = vec![0u8; 8192]; + + 'read: loop { + while let Some((t, topic, body, _key, end)) = parse_one(&acc) { + acc.drain(..end); + match t { + 1 => { + let ts = String::from_utf8_lossy(&topic).to_string(); + let idx = ServerState::shard_idx(&ts); + { + st.shards[idx] + .lock() + .await + .entry(ts.clone()) + .or_default() + .insert(id); + } + { + my.lock().await.insert(ts); + } + let _ = tx.send(build_frame_arc( + 1, + b"", + br#"{"subscribed": true}"#, + &reply_key, + )); + } + 2 => { + let ts = String::from_utf8_lossy(&topic).to_string(); + let idx = ServerState::shard_idx(&ts); + { + if let Some(s) = st.shards[idx].lock().await.get_mut(&ts) { + s.remove(&id); + } + } + { + my.lock().await.remove(&ts); + } + let _ = tx.try_send(build_frame_arc( + 2, + b"", + br#"{"unsubscribed":true}"#, + &reply_key, + )); + } + 3 => { + // PUBLISH + let topic_str = String::from_utf8_lossy(&topic).to_string(); + let idx = ServerState::shard_idx(&topic_str); + + // Build the fanout frame **once** (zero/low-copy) + let fanout = build_frame_arc(3, &topic, &body, &reply_key); + + // Snapshot targets under shard lock + let targets: Vec>>> = { + let shard = st.shards[idx].lock().await; + let conns = st.conns.read().await; + shard + .get(&topic_str) + .map(|ids| { + ids.iter() + .filter_map(|id| conns.get(id).map(|h| h.tx.clone())) + .collect() + }) + .unwrap_or_default() + }; + + for t in targets { + // If a subscriber is slow and its queue is full, drop it by closing channel + if t.try_send(fanout.clone()).is_err() { + // let the writer task break naturally; optional: proactively close + // (we skip here for simplicity) + } + } + + // ACK publisher + let ack = build_frame_arc( + 3, + topic_str.as_bytes(), + br#"{"published":true}"#, + &reply_key, + ); + + // handle internal topic; log, ... + + let _ = tx.try_send(ack); + } + 4 => { + // PING -> PONG + let _ = tx.send(build_frame_arc(4, b"", b"", &reply_key)); + } + _ => { + let _ = tx.send(build_frame_arc( + 0, + b"", + br#"{"error": "bad type"}"#, + &reply_key, + )); + } + } + } + let n = rd.read(&mut tmp).await?; + if n == 0 { + break 'read; + } + acc.extend_from_slice(&tmp[..n]); + if acc.len() > MAX_FRAME * 2 { + break 'read; + } + } + + // clean + { + let mut conns = st.conns.write().await; + conns.remove(&id); + } + + let topics: Vec = { + let guard = my.lock().await; + guard.iter().cloned().collect() + }; + + for t in topics { + let idx = ServerState::shard_idx(&t); + let mut shard = st.shards[idx].lock().await; + if let Some(set) = shard.get_mut(&t) { + set.remove(&id); + } + } + + drop(tx); + let _ = writer.await; + + Ok(()) +} + +pub async fn run_server(addr: &str, reply_key: [u8; API_KEY_LEN]) -> std::io::Result<()> { + let nproc_listener = tokio::net::TcpListener::bind(addr).await?; + let nproc_state = Arc::new(ServerState::new()); + loop { + let (socket, peer) = nproc_listener.accept().await?; + + let state_cloned = nproc_state.clone(); + + tokio::spawn(async move { + if let Err(e) = handle_connection(state_cloned, socket, peer, reply_key).await { + eprintln!("conn error: {e}"); + } + }); + } +} diff --git a/src/types.rs b/src/types.rs index d385855..8723df9 100644 --- a/src/types.rs +++ b/src/types.rs @@ -232,4 +232,12 @@ impl ManagedContainer { self.update_history.remove(0); } } + + pub fn get_semver(&self) -> Vec { + self.current_version + .replace("v", "") + .split(".") + .map(|v| v.parse::().unwrap()) + .collect() + } } diff --git a/src/updater.rs b/src/updater.rs index c4212cf..bed222c 100644 --- a/src/updater.rs +++ b/src/updater.rs @@ -5,13 +5,15 @@ use bollard::{ CreateContainerOptions, RemoveContainerOptions, StartContainerOptions, StopContainerOptions, }, image::{CommitContainerOptions, CreateImageOptions}, + query_parameters::ListImagesOptionsBuilder, + secret::ImageSummary, }; use chrono::Utc; -use std::ops::Deref; use std::{ collections::{HashMap, VecDeque}, marker::PhantomData, }; +use std::{ops::Deref, string::ParseError}; use std::{ops::DerefMut, sync::Arc}; use tokio::{ sync::Mutex, @@ -30,6 +32,84 @@ use crate::{ types::{ContainerStatus, ManagedContainer, UpdateJob, UpdateRecord, UpdateStatus}, }; +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Semver { + major: i64, + minor: i64, + patch: i64, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum SemverError { + InvalidFormat, + InvalidNumber, +} + +impl Semver { + pub fn parse(version: &str) -> Result { + let parts: Vec<&str> = version.split('.').collect(); + if parts.len() != 3 { + return Err(SemverError::InvalidFormat); + } + let major = parts[0].parse().map_err(|_| SemverError::InvalidNumber)?; + let minor = parts[1].parse().map_err(|_| SemverError::InvalidNumber)?; + let patch = parts[2].parse().map_err(|_| SemverError::InvalidNumber)?; + Ok(Semver { + major, + minor, + patch, + }) + } + + pub fn to_string(&self) -> String { + format!("{}.{}.{}", self.major, self.minor, self.patch) + } +} + +impl PartialOrd for Semver { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(&other)) + } +} + +impl Ord for Semver { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + use std::cmp::Ordering; + + match self.major.cmp(&other.major) { + Ordering::Equal => {} + other => return other, + } + + match self.minor.cmp(&other.minor) { + Ordering::Equal => {} + other => return other, + } + + self.patch.cmp(&other.patch) + } +} + +impl std::fmt::Display for Semver { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?; + + Ok(()) + } +} + +fn find_previous_latest_version(versions: &[Semver], target: &Semver) -> Option { + versions + .iter() + .filter(|&v| v < target) + .map(|s| s.clone()) + .max() +} + +fn parse_versions(versions: &[String]) -> Result, SemverError> { + versions.iter().map(|s| Semver::parse(s.as_str())).collect() +} + pub struct UpdateManager { docker: Docker, config: Config, @@ -407,7 +487,7 @@ impl UpdateManager { } async fn perform_update(mself: Arc>, mut job: UpdateJob) -> Result<()> { - let container = { + let mut container = { let mut mgr = mself.lock().await; mgr.storage.get_container(&job.container_id).await? }; @@ -452,7 +532,7 @@ impl UpdateManager { // Perform the update steps let update_result = Self::execute_update_steps( mself.clone(), - &container, + &mut container, &job.target_version, &mut update_record, ) @@ -520,7 +600,7 @@ impl UpdateManager { { let mgr = mself.lock().await; - if let Err(rollback_error) = mgr.attempt_rollback(&container).await { + if let Err(rollback_error) = mgr.attempt_rollback(&mut container).await { error!("Rollback also failed: {}", rollback_error); { let mgr = mself.lock().await; @@ -553,7 +633,7 @@ impl UpdateManager { async fn execute_update_steps( mself: Arc>, - container: &ManagedContainer, + container: &mut ManagedContainer, target_version: &str, update_record: &mut UpdateRecord, ) -> Result<()> { @@ -902,7 +982,7 @@ impl UpdateManager { Ok(()) } - async fn verify_update_health(&self, container: &ManagedContainer) -> Result<()> { + async fn verify_update_health(&self, container: &mut ManagedContainer) -> Result<()> { if let Some(health_url) = &container.health_check_url { info!("🏥 Performing health check: {}", health_url); @@ -946,6 +1026,22 @@ impl UpdateManager { } } + // do rollback + let rollback_result = self.attempt_rollback(container).await; + + match rollback_result { + Ok(_) => { + info!("Rollback successful"); + } + Err(e) => { + log_warn!( + self.log_manager, + "updater", + format!("⚠️ Rollback failed: {}", e) + ); + } + } + Err(anyhow::anyhow!( "Health check failed after {} attempts", self.config.max_retries @@ -956,11 +1052,112 @@ impl UpdateManager { } } - async fn attempt_rollback(&self, container: &ManagedContainer) -> Result<()> { - warn!("🔄 Attempting rollback for container: {}", container.name); + /// List all images on the Docker host. + async fn list_images(&self) -> Result> { + let list_image_options = ListImagesOptionsBuilder::new().all(true).build(); + let result = self.docker.list_images(Some(list_image_options)).await?; + Ok(result) + } + + pub async fn attempt_rollback(&self, container: &mut ManagedContainer) -> Result<()> { + warn!("🔄 Attempting rollback for container: {}", container.name); warn!("Cleaning up ... "); + let images = self.list_images().await?; + let expected_prefix = container.image_name.clone(); + + let mut filtered_expected_backup: Vec = images + .iter() + .filter(|img| { + !img.repo_tags.is_empty() + && img + .repo_tags + .iter() + .filter(|tag| tag.contains(&expected_prefix.clone())) + .count() + > 0 + }) + .map(|img| img.clone()) + .collect(); + + filtered_expected_backup.sort_by_key(|k| k.created); + + let version_lists = filtered_expected_backup + .iter() + .map(|x| { + x.repo_tags + .first() + .unwrap() + .split(":") + .last() + .unwrap() + .replace("v", "") + }) + .collect::>(); + + let versions = parse_versions(&version_lists); + let current_version = Semver::parse(&container.container_id).unwrap(); + + let previous_latest_version = + find_previous_latest_version(&versions.unwrap(), ¤t_version); + + if let Some(prev) = previous_latest_version { + // find image name + let prev_image = filtered_expected_backup + .iter() + .filter(|fe| fe.repo_tags.first().unwrap().ends_with(&prev.to_string())) + .map(|fe| fe.clone()) + .collect::>(); + + if prev_image.len() == 1 { + let img_name = prev_image + .first() + .unwrap() + .repo_tags + .first() + .unwrap() + .clone(); + + let _ = self.storage.delete_container(&container.container_id); + + container.image_name = img_name; + // container.current_version = prev.to_string(); + + self.start_updated_container(container, &prev.to_string()) + .await?; + } + } else { + let _ = self.storage.delete_container(&container.container_id); + } + + // find latest previous version available + + // // get latetst backup by timestamp + // // let current_timestamp = Utc::now().timestamp(); + // let mut diff_timestamp = filtered_expected_backup.get(0).unwrap().created; + // let mut latest_backup = None; + // for backup_image in filtered_expected_backup.iter() { + // let backup_timestamp = backup_image.created; + // if backup_timestamp > diff_timestamp { + // diff_timestamp = backup_timestamp; + // latest_backup = Some(backup_image.clone()); + // } + // } + + // if let Some(latest_backup) = latest_backup { + // // + // let _ = self.storage.delete_container(&container.container_id); + + // // Perform actions with the latest backup + // container.image_name = latest_backup.repo_digests.get(0).unwrap().clone(); + // container.registry_url = "default.backup".to_string(); + + // info!("Starting backup container ..."); + + // self.start_updated_container(container, "latest").await?; + // } + // let _ = self.storage.delete_container(&container.container_id); // Implementation for rollback would go here