From 06b0ebef88c7e8658dbb0ce895e89cf2f5e2ba99 Mon Sep 17 00:00:00 2001 From: Biswa Panda Date: Thu, 13 Nov 2025 09:54:54 -0800 Subject: [PATCH] feat: transport agnostic request plane for dynamo - natless (#4246) --- Cargo.lock | 1393 ++++++++------- Cargo.toml | 1 + .../vllm/launch/agg_request_planes.sh | 47 + lib/async-openai/Cargo.toml | 2 +- lib/bindings/python/Cargo.lock | 1522 +++++++++-------- lib/bindings/python/rust/http.rs | 2 +- lib/llm/Cargo.toml | 3 + lib/llm/src/common/checked_file.rs | 4 - lib/runtime/Cargo.toml | 13 +- lib/runtime/benches/tcp_codec_perf.rs | 126 ++ lib/runtime/src/component.rs | 35 +- lib/runtime/src/component/endpoint.rs | 168 +- lib/runtime/src/component/service.rs | 5 +- lib/runtime/src/config.rs | 128 ++ lib/runtime/src/discovery/kv_store.rs | 10 +- lib/runtime/src/discovery/metadata.rs | 6 +- lib/runtime/src/discovery/mock.rs | 2 +- lib/runtime/src/distributed.rs | 70 +- lib/runtime/src/health_check.rs | 6 +- lib/runtime/src/lib.rs | 20 + lib/runtime/src/logging.rs | 24 + lib/runtime/src/pipeline/network.rs | 8 +- lib/runtime/src/pipeline/network/codec.rs | 736 +++++++- lib/runtime/src/pipeline/network/egress.rs | 6 + .../network/egress/addressed_router.rs | 61 +- .../pipeline/network/egress/http_router.rs | 694 ++++++++ .../pipeline/network/egress/nats_client.rs | 87 + .../pipeline/network/egress/push_router.rs | 62 +- .../src/pipeline/network/egress/queue.rs | 2 - .../src/pipeline/network/egress/tcp_client.rs | 918 ++++++++++ .../pipeline/network/egress/unified_client.rs | 193 +++ lib/runtime/src/pipeline/network/ingress.rs | 4 + .../pipeline/network/ingress/http_endpoint.rs | 355 ++++ .../pipeline/network/ingress/nats_server.rs | 216 +++ .../network/ingress/shared_tcp_endpoint.rs | 365 ++++ .../network/ingress/unified_server.rs | 119 ++ lib/runtime/src/pipeline/network/manager.rs | 327 ++++ lib/runtime/src/runtime.rs | 11 +- lib/runtime/src/system_status_server.rs | 4 +- lib/runtime/src/transports/nats.rs | 6 - lib/runtime/src/utils.rs | 2 + lib/runtime/src/utils/ip_resolver.rs | 157 ++ tests/serve/test_vllm.py | 24 + 43 files changed, 6345 insertions(+), 1599 deletions(-) create mode 100755 examples/backends/vllm/launch/agg_request_planes.sh create mode 100644 lib/runtime/benches/tcp_codec_perf.rs create mode 100644 lib/runtime/src/pipeline/network/egress/http_router.rs create mode 100644 lib/runtime/src/pipeline/network/egress/nats_client.rs delete mode 100644 lib/runtime/src/pipeline/network/egress/queue.rs create mode 100644 lib/runtime/src/pipeline/network/egress/tcp_client.rs create mode 100644 lib/runtime/src/pipeline/network/egress/unified_client.rs create mode 100644 lib/runtime/src/pipeline/network/ingress/http_endpoint.rs create mode 100644 lib/runtime/src/pipeline/network/ingress/nats_server.rs create mode 100644 lib/runtime/src/pipeline/network/ingress/shared_tcp_endpoint.rs create mode 100644 lib/runtime/src/pipeline/network/ingress/unified_server.rs create mode 100644 lib/runtime/src/pipeline/network/manager.rs create mode 100644 lib/runtime/src/utils/ip_resolver.rs diff --git a/Cargo.lock b/Cargo.lock index ee12166db..32fd26794 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -33,8 +33,8 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ - "cfg-if 1.0.3", - "getrandom 0.3.3", + "cfg-if 1.0.4", + "getrandom 0.3.4", "once_cell", "serde", "version_check", @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -88,9 +88,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -103,9 +103,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -183,7 +183,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -300,7 +300,7 @@ checksum = "0289cba6d5143bfe8251d57b4a8cac036adf158525a76533a7082ba65ec76398" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -322,7 +322,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -333,7 +333,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -397,14 +397,14 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "av1-grain" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" dependencies = [ "anyhow", "arrayvec", "log", - "nom 7.1.3", + "nom 8.0.0", "num-rational", "v_frame", ] @@ -420,9 +420,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786" +checksum = "5932a7d9d28b0d2ea34c6b3779d35e3dd6f6345317c34e73438c4f1f29144151" dependencies = [ "aws-lc-sys", "zeroize", @@ -430,9 +430,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.31.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd" +checksum = "1826f2e4cfc2cd19ee53c42fbf68e2f81ec21108e0b7ecf6a71cf062137360fc" dependencies = [ "bindgen 0.72.1", "cc", @@ -474,7 +474,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" dependencies = [ - "axum-core 0.5.2", + "axum-core 0.5.5", "axum-macros", "bytes", "form_urlencoded", @@ -525,9 +525,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ "bytes", "futures-core", @@ -536,7 +536,6 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper 1.0.2", "tower-layer", "tower-service", @@ -551,7 +550,7 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -603,17 +602,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libc", "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -675,7 +674,7 @@ version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cexpr", "clang-sys", "itertools 0.13.0", @@ -686,7 +685,7 @@ dependencies = [ "regex", "rustc-hash 2.1.1", "shlex", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -695,7 +694,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cexpr", "clang-sys", "itertools 0.13.0", @@ -706,7 +705,7 @@ dependencies = [ "regex", "rustc-hash 2.1.1", "shlex", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -774,11 +773,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -796,7 +795,7 @@ dependencies = [ "arrayref", "arrayvec", "cc", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "constant_time_eq", "memmap2", "rayon-core", @@ -844,9 +843,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", @@ -873,22 +872,22 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -923,7 +922,7 @@ dependencies = [ "cached_proc_macro_types", "hashbrown 0.15.5", "once_cell", - "thiserror 2.0.16", + "thiserror 2.0.17", "web-time", ] @@ -936,7 +935,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -953,7 +952,7 @@ checksum = "a9f51e2ecf6efe9737af8f993433c839f956d2b6ed4fd2dd4a7c6d8b0fa667ff" dependencies = [ "byteorder", "gemm 0.17.1", - "half 2.6.0", + "half 2.7.1", "memmap2", "num-traits", "num_cpus", @@ -975,10 +974,10 @@ dependencies = [ "byteorder", "candle-kernels", "candle-metal-kernels", - "cudarc 0.17.3", + "cudarc 0.17.8", "float8", "gemm 0.17.1", - "half 2.6.0", + "half 2.7.1", "memmap2", "metal 0.27.0", "num-traits", @@ -1008,7 +1007,7 @@ name = "candle-metal-kernels" version = "0.9.1" source = "git+https://github.com/EricLBuehler/candle.git?rev=7511e510#7511e510054973ea4e2043f6d2da14409c195baf" dependencies = [ - "half 2.6.0", + "half 2.7.1", "metal 0.27.0", "once_cell", "thiserror 1.0.69", @@ -1022,7 +1021,7 @@ source = "git+https://github.com/EricLBuehler/candle.git?rev=7511e510#7511e51005 dependencies = [ "candle-core 0.9.1 (git+https://github.com/EricLBuehler/candle.git?rev=7511e510)", "candle-metal-kernels", - "half 2.6.0", + "half 2.7.1", "metal 0.27.0", "num-traits", "rayon", @@ -1052,24 +1051,24 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb" dependencies = [ - "clap 4.5.48", + "clap 4.5.51", "heck 0.4.1", - "indexmap 2.11.4", + "indexmap 2.12.0", "log", "proc-macro2", "quote", "serde", "serde_json", - "syn 2.0.106", + "syn 2.0.110", "tempfile", "toml 0.8.23", ] [[package]] name = "cc" -version = "1.2.38" +version = "1.2.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe" dependencies = [ "find-msvc-tools", "jobserver", @@ -1104,9 +1103,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -1120,7 +1119,7 @@ version = "0.13.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe45e18904af7af10e4312df7c97251e98af98c70f42f1f2587aecfcbee56bf" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "lazy_static", "num-traits", "regex", @@ -1139,7 +1138,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -1166,7 +1165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", - "half 2.6.0", + "half 2.7.1", ] [[package]] @@ -1193,9 +1192,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.48" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -1203,9 +1202,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.48" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -1216,21 +1215,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.47" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cmake" @@ -1269,7 +1268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" dependencies = [ "castaway", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "itoa", "rustversion", "ryu", @@ -1288,9 +1287,9 @@ dependencies = [ [[package]] name = "config" -version = "0.15.17" +version = "0.15.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680d3ac2fe066c43300ec831c978871e50113a708d58ab13d231bd92deca5adb" +checksum = "b30fa8254caad766fc03cb0ccae691e14bf3bd72bfff27f72802ce729551b3d6" dependencies = [ "async-trait", "convert_case", @@ -1301,7 +1300,7 @@ dependencies = [ "serde-untagged", "serde_core", "serde_json", - "toml 0.9.7", + "toml 0.9.8", "winnow", "yaml-rust2", ] @@ -1315,7 +1314,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.1", + "unicode-width 0.2.2", "windows-sys 0.59.0", ] @@ -1451,7 +1450,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", ] [[package]] @@ -1489,7 +1488,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.48", + "clap 4.5.51", "criterion-plot 0.5.0", "futures", "is-terminal", @@ -1617,9 +1616,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -1645,26 +1644,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "csv" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" dependencies = [ "csv-core", "itoa", "ryu", - "serde", + "serde_core", ] [[package]] name = "csv-core" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" dependencies = [ "memchr", ] @@ -1675,17 +1674,17 @@ version = "0.16.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17200eb07e7d85a243aa1bf4569a7aa998385ba98d14833973a817a63cc86e92" dependencies = [ - "half 2.6.0", + "half 2.7.1", "libloading", ] [[package]] name = "cudarc" -version = "0.17.3" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ba848ae5c6f3cb36e71eab5f268763e3fabcabe3f7bc683e16f7fa3d46281e" +checksum = "0bf99ab37ee7072d64d906aa2dada9a3422f1d975cdf8c8055a573bc84897ed8" dependencies = [ - "half 2.6.0", + "half 2.7.1", "libloading", ] @@ -1695,7 +1694,7 @@ version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "cpufeatures", "curve25519-dalek-derive", "digest", @@ -1712,7 +1711,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1770,7 +1769,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1784,7 +1783,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1806,7 +1805,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1817,7 +1816,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1835,7 +1834,7 @@ version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "hashbrown 0.14.5", "lock_api", "once_cell", @@ -1848,7 +1847,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "crossbeam-utils", "hashbrown 0.14.5", "lock_api", @@ -1881,9 +1880,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", "serde_core", @@ -1897,7 +1896,7 @@ checksum = "74ef43543e701c01ad77d3a5922755c6a1d71b22d942cb8042be4994b380caff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1908,7 +1907,7 @@ checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1919,7 +1918,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1940,7 +1939,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1950,7 +1949,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1961,7 +1960,7 @@ checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1990,7 +1989,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "unicode-xid", ] @@ -2002,7 +2001,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -2076,7 +2075,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.0", + "windows-sys 0.59.0", ] [[package]] @@ -2087,7 +2086,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -2096,7 +2095,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc178fc3bf4ce54c26ccffcf271ff574954ac4b940f15121be3d69f277194537" dependencies = [ - "half 2.6.0", + "half 2.7.1", "pyo3", ] @@ -2154,13 +2153,20 @@ dependencies = [ [[package]] name = "dyn-stack" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490bd48eb68fffcfed519b4edbfd82c69cbe741d175b84f0e0cbe8c57cbe0bdd" +checksum = "1c4713e43e2886ba72b8271aa66c93d722116acf7a75555cce11dcde84388fe8" dependencies = [ "bytemuck", + "dyn-stack-macros", ] +[[package]] +name = "dyn-stack-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9" + [[package]] name = "dynamo-async-openai" version = "0.7.0" @@ -2173,12 +2179,12 @@ dependencies = [ "eventsource-stream", "futures", "rand 0.9.2", - "reqwest 0.12.23", + "reqwest 0.12.24", "reqwest-eventsource", "secrecy", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", "tokio-test", @@ -2196,7 +2202,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -2217,7 +2223,7 @@ dependencies = [ "dynamo-llm", "dynamo-runtime", "either", - "indexmap 2.11.4", + "indexmap 2.12.0", "mistralrs", "serde_json", "tokio", @@ -2243,7 +2249,7 @@ dependencies = [ "axum-server", "base64 0.22.1", "bincode 2.0.1", - "bitflags 2.9.4", + "bitflags 2.10.0", "blake3", "bs62", "bytemuck", @@ -2251,7 +2257,7 @@ dependencies = [ "candle-core 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "chrono", "criterion 0.3.6", - "cudarc 0.17.3", + "cudarc 0.17.8", "dashmap 5.5.3", "derive-getters", "derive_builder", @@ -2267,6 +2273,8 @@ dependencies = [ "galil-seiferas", "hf-hub", "humantime", + "hyper 1.7.0", + "hyper-util", "image", "insta", "itertools 0.14.0", @@ -2289,7 +2297,7 @@ dependencies = [ "rand 0.9.2", "rayon", "regex", - "reqwest 0.12.23", + "reqwest 0.12.24", "rmp-serde", "rstest 0.18.2", "rstest_reuse", @@ -2300,17 +2308,18 @@ dependencies = [ "strum", "temp-env", "tempfile", - "thiserror 2.0.16", + "thiserror 2.0.17", "tmq", "tokenizers", "tokio", "tokio-rayon", "tokio-stream", "tokio-util", - "toktrie 1.2.0", - "toktrie_hf_tokenizers 1.2.0", + "toktrie 1.3.0", + "toktrie_hf_tokenizers 1.3.0", "tonic 0.13.1", "tonic-build", + "tower 0.5.2", "tower-http", "tracing", "unicode-segmentation", @@ -2328,7 +2337,7 @@ name = "dynamo-memory" version = "0.7.0" dependencies = [ "anyhow", - "cudarc 0.17.3", + "cudarc 0.17.8", "dynamo-config", "libc", "nix 0.30.1", @@ -2336,7 +2345,7 @@ dependencies = [ "offset-allocator", "serde", "tempfile", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -2365,7 +2374,7 @@ dependencies = [ "anyhow", "async-stream", "async-trait", - "clap 4.5.48", + "clap 4.5.51", "dynamo-async-openai", "dynamo-engine-mistralrs", "dynamo-llm", @@ -2405,6 +2414,7 @@ dependencies = [ "chrono", "console-subscriber", "criterion 0.5.1", + "dashmap 6.1.0", "derive-getters", "derive_builder", "educe", @@ -2414,9 +2424,13 @@ dependencies = [ "figment", "futures", "humantime", + "hyper 1.7.0", + "hyper-util", + "inotify 0.11.0", "jsonschema", "k8s-openapi", "kube", + "libc", "local-ip-address", "log", "nid", @@ -2432,7 +2446,8 @@ dependencies = [ "rand 0.9.2", "rayon", "regex", - "reqwest 0.12.23", + "reqwest 0.12.24", + "rmp-serde", "rstest 0.23.0", "serde", "serde_json", @@ -2440,11 +2455,12 @@ dependencies = [ "stdio-override", "temp-env", "tempfile", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-rayon", "tokio-stream", "tokio-util", + "tower 0.5.2", "tower-http", "tracing", "tracing-opentelemetry", @@ -2463,7 +2479,7 @@ dependencies = [ "dashmap 6.1.0", "derive-getters", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "xxhash-rust", ] @@ -2498,7 +2514,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -2528,7 +2544,7 @@ version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", ] [[package]] @@ -2546,34 +2562,34 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "enum-ordinalize" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ "enum-ordinalize-derive", ] [[package]] name = "enum-ordinalize-derive" -version = "4.3.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "env_filter" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" dependencies = [ "log", "regex", @@ -2609,7 +2625,7 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -2620,9 +2636,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "259d404d09818dec19332e31d94558aeb442fea04c817006456c24b5460bbd4b" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" dependencies = [ "serde", "serde_core", @@ -2636,7 +2652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.59.0", ] [[package]] @@ -2698,12 +2714,12 @@ dependencies = [ [[package]] name = "exr" -version = "1.73.0" +version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" dependencies = [ "bit_field", - "half 2.6.0", + "half 2.7.1", "lebe", "miniz_oxide", "rayon-core", @@ -2772,7 +2788,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -2813,7 +2829,7 @@ version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libc", "libredox", "windows-sys 0.60.2", @@ -2821,9 +2837,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "fixedbitset" @@ -2833,9 +2849,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "libz-rs-sys", @@ -2848,8 +2864,8 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4203231de188ebbdfb85c11f3c20ca2b063945710de04e7b59268731e728b462" dependencies = [ - "cudarc 0.17.3", - "half 2.6.0", + "cudarc 0.17.8", + "half 2.7.1", "num-traits", ] @@ -2892,7 +2908,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -2928,9 +2944,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "3.1.2" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f150ffc8782f35521cec2b23727707cb4045706ba3c854e86bef66b3a8cdbd" +checksum = "6ad492b2cf1d89d568a43508ab24f98501fe03f2f31c01e1d0fe7366a71745d2" dependencies = [ "autocfg", "tokio", @@ -3033,7 +3049,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -3117,7 +3133,7 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-c32 0.18.2", "gemm-c64 0.18.2", "gemm-common 0.18.2", @@ -3152,7 +3168,7 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-common 0.18.2", "num-complex", "num-traits", @@ -3182,7 +3198,7 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-common 0.18.2", "num-complex", "num-traits", @@ -3199,7 +3215,7 @@ checksum = "a2e7ea062c987abcd8db95db917b4ffb4ecdfd0668471d8dc54734fdff2354e8" dependencies = [ "bytemuck", "dyn-stack 0.10.0", - "half 2.6.0", + "half 2.7.1", "num-complex", "num-traits", "once_cell", @@ -3218,8 +3234,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3" dependencies = [ "bytemuck", - "dyn-stack 0.13.0", - "half 2.6.0", + "dyn-stack 0.13.2", + "half 2.7.1", "libm", "num-complex", "num-traits", @@ -3241,7 +3257,7 @@ dependencies = [ "dyn-stack 0.10.0", "gemm-common 0.17.1", "gemm-f32 0.17.1", - "half 2.6.0", + "half 2.7.1", "num-complex", "num-traits", "paste", @@ -3256,10 +3272,10 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff95ae3259432f3c3410eaa919033cd03791d81cebd18018393dc147952e109" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-common 0.18.2", "gemm-f32 0.18.2", - "half 2.6.0", + "half 2.7.1", "num-complex", "num-traits", "paste", @@ -3289,7 +3305,7 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-common 0.18.2", "num-complex", "num-traits", @@ -3319,7 +3335,7 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-common 0.18.2", "num-complex", "num-traits", @@ -3344,7 +3360,7 @@ version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ - "unicode-width 0.2.1", + "unicode-width 0.2.2", ] [[package]] @@ -3353,24 +3369,24 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "js-sys", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] @@ -3386,9 +3402,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" @@ -3398,9 +3414,9 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "globset" -version = "0.4.16" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" dependencies = [ "aho-corasick", "bstr", @@ -3433,7 +3449,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.11.4", + "indexmap 2.12.0", "slab", "tokio", "tokio-util", @@ -3452,7 +3468,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.3.1", - "indexmap 2.11.4", + "indexmap 2.12.0", "slab", "tokio", "tokio-util", @@ -3467,16 +3483,17 @@ checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "bytemuck", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "crunchy", "num-traits", "rand 0.9.2", "rand_distr 0.5.1", + "zerocopy", ] [[package]] @@ -3580,10 +3597,10 @@ dependencies = [ "log", "num_cpus", "rand 0.9.2", - "reqwest 0.12.23", + "reqwest 0.12.24", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "ureq", "windows-sys 0.60.2", @@ -3595,7 +3612,7 @@ version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -3604,7 +3621,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libc", "windows-link 0.1.3", ] @@ -3623,8 +3640,8 @@ checksum = "c1637acec3b965bab873352189d887b12c87b4f8d7571f4d185e796be5654ad8" dependencies = [ "html5ever 0.31.0", "tendril", - "thiserror 2.0.16", - "unicode-width 0.2.1", + "thiserror 2.0.17", + "unicode-width 0.2.2", ] [[package]] @@ -3783,12 +3800,12 @@ dependencies = [ "hyper-util", "log", "rustls", - "rustls-native-certs 0.8.1", + "rustls-native-certs 0.8.2", "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.2", + "webpki-roots 1.0.4", ] [[package]] @@ -3838,7 +3855,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.6.1", "system-configuration 0.6.1", "tokio", "tower-service", @@ -3858,7 +3875,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.0", + "windows-core 0.62.2", ] [[package]] @@ -3872,22 +3889,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", - "yoke 0.8.0", + "yoke 0.8.1", "zerofrom", "zerovec", ] [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -3898,11 +3915,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -3913,44 +3929,40 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", - "yoke 0.8.0", + "yoke 0.8.1", "zerofrom", "zerotrie", "zerovec", @@ -4036,9 +4048,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -4056,15 +4068,18 @@ dependencies = [ "number_prefix", "portable-atomic", "rayon", - "unicode-width 0.2.1", + "unicode-width 0.2.2", "web-time", ] [[package]] name = "indoc" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] [[package]] name = "inlinable_string" @@ -4083,6 +4098,19 @@ dependencies = [ "libc", ] +[[package]] +name = "inotify" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" +dependencies = [ + "bitflags 2.10.0", + "futures-core", + "inotify-sys", + "libc", + "tokio", +] + [[package]] name = "inotify-sys" version = "0.1.5" @@ -4115,7 +4143,7 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", ] [[package]] @@ -4126,7 +4154,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4151,17 +4179,6 @@ dependencies = [ "rustversion", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.4", - "cfg-if 1.0.3", - "libc", -] - [[package]] name = "iovec" version = "0.1.4" @@ -4179,9 +4196,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -4196,14 +4213,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "is-terminal" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi 0.5.2", "libc", @@ -4212,9 +4229,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "iso8601" @@ -4278,28 +4295,28 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" dependencies = [ "jiff-static", "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", - "serde", + "serde_core", "windows-sys 0.59.0", ] [[package]] name = "jiff-static" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4323,15 +4340,15 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -4380,7 +4397,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4403,7 +4420,7 @@ dependencies = [ "anyhow", "base64 0.21.7", "bytecount", - "clap 4.5.48", + "clap 4.5.51", "fancy-regex 0.11.0", "fraction", "getrandom 0.2.16", @@ -4516,7 +4533,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-util", "tower 0.5.2", @@ -4536,11 +4553,11 @@ dependencies = [ "http 1.3.1", "json-patch", "k8s-openapi", - "schemars 1.0.4", + "schemars 1.1.0", "serde", "serde-value", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4554,7 +4571,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4578,7 +4595,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-util", "tracing", @@ -4608,8 +4625,8 @@ dependencies = [ "rstest 0.25.0", "serde", "serde_json", - "socket2 0.6.0", - "thiserror 2.0.16", + "socket2 0.6.1", + "thiserror 2.0.17", "tokio", "tokio-stream", "tokio-util", @@ -4638,9 +4655,9 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" -version = "0.2.176" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libdynamo_llm" @@ -4679,8 +4696,8 @@ version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ - "cfg-if 1.0.3", - "windows-link 0.2.0", + "cfg-if 1.0.4", + "windows-link 0.2.1", ] [[package]] @@ -4695,7 +4712,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", "redox_syscall", ] @@ -4717,9 +4734,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "llguidance" @@ -4728,7 +4745,7 @@ source = "git+https://github.com/guidance-ai/llguidance.git?rev=c432092#c432092d dependencies = [ "anyhow", "derivre", - "indexmap 2.11.4", + "indexmap 2.12.0", "regex-syntax", "serde", "serde_json", @@ -4743,7 +4760,7 @@ checksum = "656b3b27f8893f7bbf9485148ff9a65f019e3f33bd5cdc87c83cab16b3fd9ec8" dependencies = [ "libc", "neli", - "thiserror 2.0.16", + "thiserror 2.0.17", "windows-sys 0.59.0", ] @@ -4912,7 +4929,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4952,7 +4969,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "rayon", ] @@ -4964,9 +4981,9 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" dependencies = [ "libc", "stable_deref_trait", @@ -5002,7 +5019,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block", "core-graphics-types", "foreign-types 0.5.0", @@ -5017,7 +5034,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "block", "core-graphics-types", "foreign-types 0.5.0", @@ -5107,19 +5124,19 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -5142,14 +5159,14 @@ dependencies = [ "anyhow", "candle-core 0.9.1 (git+https://github.com/EricLBuehler/candle.git?rev=7511e510)", "candle-nn", - "clap 4.5.48", + "clap 4.5.51", "either", "futures", "image", - "indexmap 2.11.4", + "indexmap 2.12.0", "mistralrs-core", "rand 0.9.2", - "reqwest 0.12.23", + "reqwest 0.12.24", "serde", "serde_json", "tokio", @@ -5187,7 +5204,7 @@ dependencies = [ "candle-nn", "cfgrammar", "chrono", - "clap 4.5.48", + "clap 4.5.51", "csv", "derive-new", "derive_more 2.0.1", @@ -5196,14 +5213,14 @@ dependencies = [ "float8", "futures", "galil-seiferas", - "half 2.6.0", + "half 2.7.1", "hashbrown 0.15.5", "hf-hub", "hound", "html2text", "http 1.3.1", "image", - "indexmap 2.11.4", + "indexmap 2.12.0", "indicatif", "interprocess", "itertools 0.14.0", @@ -5230,7 +5247,7 @@ dependencies = [ "rayon", "regex", "regex-automata", - "reqwest 0.12.23", + "reqwest 0.12.24", "rubato", "rust-mcp-schema", "rustc-hash 2.1.1", @@ -5247,7 +5264,7 @@ dependencies = [ "strum", "symphonia", "sysinfo", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokenizers", "tokio", "tokio-rayon", @@ -5272,7 +5289,7 @@ dependencies = [ "async-trait", "futures-util", "http 1.3.1", - "reqwest 0.12.23", + "reqwest 0.12.24", "rust-mcp-schema", "serde", "serde_json", @@ -5292,10 +5309,10 @@ dependencies = [ "bindgen_cuda 0.1.7", "candle-core 0.9.1 (git+https://github.com/EricLBuehler/candle.git?rev=7511e510)", "float8", - "half 2.6.0", + "half 2.7.1", "metal 0.27.0", "once_cell", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -5308,7 +5325,7 @@ dependencies = [ "candle-core 0.9.1 (git+https://github.com/EricLBuehler/candle.git?rev=7511e510)", "candle-nn", "float8", - "half 2.6.0", + "half 2.7.1", "hf-hub", "lazy_static", "memmap2", @@ -5320,7 +5337,7 @@ dependencies = [ "safetensors 0.6.2", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "yoke 0.7.5", @@ -5367,14 +5384,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9462ec6cd8b3d6beaa262ad0907a8ba297c7e3a220c11e4159742d8c275588eb" dependencies = [ "anyhow", - "clap 4.5.48", + "clap 4.5.51", "colored", "futures", "modelexpress-common", "prost 0.13.5", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tonic 0.13.1", "tracing", @@ -5391,7 +5408,7 @@ dependencies = [ "anyhow", "async-trait", "chrono", - "clap 4.5.48", + "clap 4.5.51", "config", "hf-hub", "jiff", @@ -5399,7 +5416,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tonic 0.13.1", "tonic-build", @@ -5408,9 +5425,9 @@ dependencies = [ [[package]] name = "monostate" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a2901b7478a273256ce419c446289eb3c883a790d0bf5ed2f363c0cc3988012" +checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67" dependencies = [ "monostate-impl", "serde", @@ -5419,20 +5436,20 @@ dependencies = [ [[package]] name = "monostate-impl" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "328f7435b7f54322b33832f1e981ff192781f0d12473f12d062705a55015de8d" +checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "moxcms" -version = "0.7.5" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08" +checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6" dependencies = [ "num-traits", "pxfm", @@ -5562,7 +5579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libc", "memoffset 0.7.1", "pin-utils", @@ -5574,8 +5591,8 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.9.4", - "cfg-if 1.0.3", + "bitflags 2.10.0", + "cfg-if 1.0.4", "cfg_aliases", "libc", ] @@ -5586,8 +5603,8 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.4", - "cfg-if 1.0.3", + "bitflags 2.10.0", + "cfg-if 1.0.4", "cfg_aliases", "libc", ] @@ -5604,7 +5621,7 @@ dependencies = [ "os_info", "pkg-config", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -5660,10 +5677,10 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "filetime", "fsevent-sys", - "inotify", + "inotify 0.9.6", "kqueue", "libc", "log", @@ -5683,11 +5700,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.50.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5753,7 +5770,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -5809,9 +5826,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -5819,14 +5836,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -5865,9 +5882,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -5890,9 +5907,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "oneshot" @@ -5906,7 +5923,7 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "libc", "once_cell", "onig_sys", @@ -5937,29 +5954,29 @@ dependencies = [ "anyhow", "base64 0.22.1", "bstr", - "clap 4.5.48", + "clap 4.5.51", "fancy-regex 0.13.0", "futures", "image", "regex", - "reqwest 0.12.23", + "reqwest 0.12.24", "rustc-hash 1.1.0", "serde", "serde_json", "serde_with", "sha1", "sha2", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] name = "openssl" -version = "0.10.73" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.9.4", - "cfg-if 1.0.3", + "bitflags 2.10.0", + "cfg-if 1.0.4", "foreign-types 0.3.2", "libc", "once_cell", @@ -5975,7 +5992,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -5986,18 +6003,18 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.5.2+3.5.2" +version = "300.5.4+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" +checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.109" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -6016,7 +6033,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -6030,7 +6047,7 @@ dependencies = [ "bytes", "http 1.3.1", "opentelemetry", - "reqwest 0.12.23", + "reqwest 0.12.24", ] [[package]] @@ -6045,8 +6062,8 @@ dependencies = [ "opentelemetry-proto", "opentelemetry_sdk", "prost 0.14.1", - "reqwest 0.12.23", - "thiserror 2.0.16", + "reqwest 0.12.24", + "thiserror 2.0.17", "tokio", "tonic 0.14.2", "tracing", @@ -6077,7 +6094,7 @@ dependencies = [ "opentelemetry", "percent-encoding", "rand 0.9.2", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", ] @@ -6160,11 +6177,11 @@ version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libc", "redox_syscall", "smallvec", - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -6199,7 +6216,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6229,20 +6246,19 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" +checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" dependencies = [ "memchr", - "thiserror 2.0.16", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663" +checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" dependencies = [ "pest", "pest_generator", @@ -6250,22 +6266,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f" +checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "pest_meta" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420" +checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" dependencies = [ "pest", "sha2", @@ -6278,7 +6294,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset", - "indexmap 2.11.4", + "indexmap 2.12.0", ] [[package]] @@ -6321,7 +6337,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6350,7 +6366,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6388,7 +6404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ "base64 0.22.1", - "indexmap 2.11.4", + "indexmap 2.12.0", "quick-xml", "serde", "time", @@ -6428,7 +6444,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "crc32fast", "fdeflate", "flate2", @@ -6452,9 +6468,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -6487,7 +6503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6505,7 +6521,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.23.6", + "toml_edit 0.23.7", ] [[package]] @@ -6527,14 +6543,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -6547,7 +6563,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "version_check", "yansi", ] @@ -6568,7 +6584,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6577,25 +6593,24 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "fnv", "lazy_static", "memchr", "parking_lot", "protobuf", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] name = "proptest" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set 0.8.0", "bit-vec 0.8.0", - "bitflags 2.9.4", - "lazy_static", + "bitflags 2.10.0", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -6642,7 +6657,7 @@ dependencies = [ "prost 0.13.5", "prost-types", "regex", - "syn 2.0.106", + "syn 2.0.110", "tempfile", ] @@ -6656,7 +6671,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6669,7 +6684,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6720,7 +6735,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907" dependencies = [ "bytemuck", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libm", "num-complex", "reborrow", @@ -6729,9 +6744,9 @@ dependencies = [ [[package]] name = "pxfm" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f9b339b02259ada5c0f4a389b7fb472f933aa17ce176fd2ad98f28bb401fde" +checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84" dependencies = [ "num-traits", ] @@ -6742,7 +6757,7 @@ version = "0.23.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "indoc", "libc", "memoffset 0.9.1", @@ -6761,7 +6776,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "977dc837525cfd22919ba6a831413854beb7c99a256c03bf8624ad707e45810e" dependencies = [ "async-channel", - "clap 4.5.48", + "clap 4.5.51", "futures", "inventory", "once_cell", @@ -6779,7 +6794,7 @@ checksum = "b2df2884957d2476731f987673befac5d521dff10abb0a7cbe12015bc7702fe9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6811,7 +6826,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6824,7 +6839,7 @@ dependencies = [ "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6860,9 +6875,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.38.3" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" dependencies = [ "memchr", ] @@ -6880,8 +6895,8 @@ dependencies = [ "quinn-udp", "rustc-hash 2.1.1", "rustls", - "socket2 0.6.0", - "thiserror 2.0.16", + "socket2 0.6.1", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -6894,7 +6909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "getrandom 0.3.3", + "getrandom 0.3.4", "lru-slab", "rand 0.9.2", "ring", @@ -6902,7 +6917,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.16", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -6917,16 +6932,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.0", + "socket2 0.6.1", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -7003,7 +7018,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -7056,7 +7071,7 @@ dependencies = [ "av1-grain", "bitstream-io", "built", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "interpolate_name", "itertools 0.12.1", "libc", @@ -7109,7 +7124,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -7172,11 +7187,11 @@ checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -7187,34 +7202,34 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "regex" -version = "1.11.3" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -7224,9 +7239,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -7235,9 +7250,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "relative-path" @@ -7283,9 +7298,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.23" +version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ "base64 0.22.1", "bytes", @@ -7310,7 +7325,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-native-certs 0.8.1", + "rustls-native-certs 0.8.2", "rustls-pki-types", "serde", "serde_json", @@ -7328,7 +7343,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.2", + "webpki-roots 1.0.4", ] [[package]] @@ -7343,7 +7358,7 @@ dependencies = [ "mime", "nom 7.1.3", "pin-project-lite", - "reqwest 0.12.23", + "reqwest 0.12.24", "thiserror 1.0.69", ] @@ -7360,7 +7375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "getrandom 0.2.16", "libc", "untrusted", @@ -7391,14 +7406,16 @@ dependencies = [ [[package]] name = "ron" -version = "0.8.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32" dependencies = [ - "base64 0.21.7", - "bitflags 2.9.4", + "bitflags 2.10.0", + "once_cell", "serde", "serde_derive", + "typeid", + "unicode-ident", ] [[package]] @@ -7443,14 +7460,14 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "glob", "proc-macro2", "quote", "regex", "relative-path", "rustc_version", - "syn 2.0.106", + "syn 2.0.110", "unicode-ident", ] @@ -7460,7 +7477,7 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "glob", "proc-macro-crate", "proc-macro2", @@ -7468,7 +7485,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.106", + "syn 2.0.110", "unicode-ident", ] @@ -7478,7 +7495,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f168d99749d307be9de54d23fd226628d99768225ef08f6ffb52e0182a27746" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "glob", "proc-macro-crate", "proc-macro2", @@ -7486,7 +7503,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.106", + "syn 2.0.110", "unicode-ident", ] @@ -7498,7 +7515,7 @@ checksum = "b3a8fb4672e840a587a66fc577a5491375df51ddb88f2a2c2a792598c326fe14" dependencies = [ "quote", "rand 0.8.5", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -7515,9 +7532,9 @@ dependencies = [ [[package]] name = "rust-embed" -version = "8.7.2" +version = "8.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025908b8682a26ba8d12f6f2d66b987584a4a87bc024abc5bbc12553a8cd178a" +checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -7526,22 +7543,22 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "8.7.2" +version = "8.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6065f1a4392b71819ec1ea1df1120673418bf386f50de1d6f54204d836d4349c" +checksum = "5fa2c8c9e8711e10f9c4fd2d64317ef13feaab820a4c51541f1a8c8e2e851ab2" dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.106", + "syn 2.0.110", "walkdir", ] [[package]] name = "rust-embed-utils" -version = "8.7.2" +version = "8.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6cc0c81648b20b70c491ff8cce00c1c3b223bb8ed2b5d41f0e54c6c4c0a3594" +checksum = "60b161f275cb337fe0a44d924a5f4df0ed69c2c39519858f931ce61c779d3475" dependencies = [ "sha2", "walkdir", @@ -7553,7 +7570,7 @@ version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "ordered-multimap", ] @@ -7624,25 +7641,25 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.32" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.6", + "rustls-webpki 0.103.8", "subtle", "zeroize", ] @@ -7662,14 +7679,14 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.5.0", + "security-framework 3.5.1", ] [[package]] @@ -7683,9 +7700,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "web-time", "zeroize", @@ -7703,9 +7720,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.6" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "aws-lc-rs", "ring", @@ -7778,9 +7795,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rusty-fork" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", "quick-error 1.2.3", @@ -7847,7 +7864,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -7876,13 +7893,13 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" dependencies = [ "dyn-clone", "ref-cast", - "schemars_derive 1.0.4", + "schemars_derive 1.1.0", "serde", "serde_json", ] @@ -7896,19 +7913,19 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "schemars_derive" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80" +checksum = "301858a4023d78debd2353c7426dc486001bddc91ae31a76fb1f55132f7e2633" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -7954,7 +7971,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -7963,11 +7980,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.5.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc198e42d9b7510827939c9a15f5062a0c913f3371d765977e586d2fe6c16f4a" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -7990,7 +8007,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "cssparser", "derive_more 0.99.20", "fxhash", @@ -8005,9 +8022,9 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" +checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33" [[package]] name = "semver" @@ -8023,9 +8040,9 @@ checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" [[package]] name = "serde" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -8074,22 +8091,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -8100,7 +8117,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -8109,7 +8126,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "itoa", "memchr", "ryu", @@ -8154,7 +8171,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -8168,9 +8185,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ "serde_core", ] @@ -8189,19 +8206,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.1" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" +checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.4", + "indexmap 2.12.0", "schemars 0.9.0", - "schemars 1.0.4", - "serde", - "serde_derive", + "schemars 1.1.0", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -8209,14 +8225,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.1" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" +checksum = "b91a903660542fced4e99881aa481bdbaec1634568ee02e0b8bd57c64cb38955" dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -8225,7 +8241,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "itoa", "ryu", "serde", @@ -8254,14 +8270,14 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "servo_arc" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "204ea332803bd95a0b60388590d59cf6468ec9becf626e2451f1d26a1d972de4" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" dependencies = [ "stable_deref_trait", ] @@ -8272,7 +8288,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "cpufeatures", "digest", ] @@ -8283,7 +8299,7 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "cpufeatures", "digest", ] @@ -8321,9 +8337,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" dependencies = [ "libc", "mio 0.8.11", @@ -8425,12 +8441,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -8480,9 +8496,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -8582,7 +8598,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -8739,9 +8755,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" dependencies = [ "proc-macro2", "quote", @@ -8771,7 +8787,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -8780,7 +8796,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "byteorder", "enum-as-inner", "libc", @@ -8794,7 +8810,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "byteorder", "enum-as-inner", "libc", @@ -8808,7 +8824,7 @@ version = "0.30.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "core-foundation-sys", "libc", "ntapi", @@ -8834,7 +8850,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation 0.9.4", "system-configuration-sys 0.6.0", ] @@ -8895,10 +8911,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.61.0", + "windows-sys 0.59.0", ] [[package]] @@ -8942,11 +8958,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -8957,18 +8973,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -8977,7 +8993,7 @@ version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", ] [[package]] @@ -8988,7 +9004,7 @@ checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" dependencies = [ "fax", "flate2", - "half 2.6.0", + "half 2.7.1", "quick-error 2.0.1", "weezl", "zune-jpeg", @@ -9038,9 +9054,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -9097,7 +9113,7 @@ dependencies = [ "derive_builder", "esaxx-rs", "fancy-regex 0.14.0", - "getrandom 0.3.3", + "getrandom 0.3.4", "hf-hub", "itertools 0.14.0", "log", @@ -9113,7 +9129,7 @@ dependencies = [ "serde", "serde_json", "spm_precompiled", - "thiserror 2.0.16", + "thiserror 2.0.17", "unicode-normalization-alignments", "unicode-segmentation", "unicode_categories", @@ -9121,34 +9137,31 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", - "mio 1.0.4", + "mio 1.1.0", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2 0.6.1", "tokio-macros", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -9173,9 +9186,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -9231,9 +9244,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -9280,9 +9293,9 @@ dependencies = [ [[package]] name = "toktrie" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804459e7818d5cc8920f80d555526454353117a4f2fcda38e4b38666639d7e81" +checksum = "55c5e672ee5e0311bbb37ac0f9f60ed7db38463365e6cf4f71240c7b15bb374d" dependencies = [ "anyhow", "bytemuck", @@ -9306,16 +9319,16 @@ dependencies = [ [[package]] name = "toktrie_hf_tokenizers" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fc302ed2c53b1d7fcbe3d760a2dc6567def0eb2da7ca09cb21a16b9a9aa4f13" +checksum = "baec7fb81a716f85ae1e07ce951f9e9bc1b745635edd48cbebb6a033c6491dca" dependencies = [ "anyhow", "log", "serde", "serde_json", "tokenizers", - "toktrie 1.2.0", + "toktrie 1.3.0", ] [[package]] @@ -9332,13 +9345,13 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "serde_core", - "serde_spanned 1.0.2", - "toml_datetime 0.7.2", + "serde_spanned 1.0.3", + "toml_datetime 0.7.3", "toml_parser", "winnow", ] @@ -9354,9 +9367,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] @@ -9367,7 +9380,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", @@ -9377,21 +9390,21 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.23.6" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ - "indexmap 2.11.4", - "toml_datetime 0.7.2", + "indexmap 2.12.0", + "toml_datetime 0.7.3", "toml_parser", "winnow", ] [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] @@ -9499,7 +9512,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -9541,7 +9554,7 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "indexmap 2.11.4", + "indexmap 2.12.0", "pin-project-lite", "slab", "sync_wrapper 1.0.2", @@ -9559,7 +9572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ "base64 0.22.1", - "bitflags 2.9.4", + "bitflags 2.10.0", "bytes", "futures-util", "http 1.3.1", @@ -9616,7 +9629,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -9651,7 +9664,7 @@ dependencies = [ "opentelemetry_sdk", "rustversion", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "tracing-core", "tracing-log", @@ -9744,7 +9757,7 @@ dependencies = [ "bytes", "log", "rand 0.9.2", - "thiserror 2.0.16", + "thiserror 2.0.17", "utf-8", ] @@ -9756,9 +9769,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -9773,7 +9786,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90b70b37e9074642bc5f60bb23247fd072a84314ca9e71cdf8527593406a0dd3" dependencies = [ "gemm 0.18.2", - "half 2.6.0", + "half 2.7.1", "libloading", "memmap2", "num", @@ -9794,7 +9807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14053653d0b7fa7b21015aa9a62edc8af2f60aa6f9c54e66386ecce55f22ed29" dependencies = [ "cudarc 0.16.6", - "half 2.6.0", + "half 2.7.1", "serde", "thiserror 1.0.69", "ug", @@ -9806,7 +9819,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76daec3c7a32a1b4a0e3307b6b057fa067aa64e750713987410a2c402e5cd731" dependencies = [ - "half 2.6.0", + "half 2.7.1", "metal 0.29.0", "objc", "serde", @@ -9901,9 +9914,9 @@ checksum = "0b993bddc193ae5bd0d623b49ec06ac3e9312875fdae725a975c51db1cc1677f" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization-alignments" @@ -9928,9 +9941,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -10051,7 +10064,7 @@ version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" dependencies = [ - "indexmap 2.11.4", + "indexmap 2.12.0", "serde", "serde_json", "utoipa-gen", @@ -10066,7 +10079,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -10102,7 +10115,7 @@ version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", "serde", "wasm-bindgen", @@ -10146,7 +10159,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -10214,9 +10227,9 @@ dependencies = [ [[package]] name = "version-compare" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "version_check" @@ -10274,15 +10287,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -10294,38 +10298,24 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "once_cell", "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "js-sys", "once_cell", "wasm-bindgen", @@ -10334,9 +10324,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10344,22 +10334,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.110", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -10379,9 +10369,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -10415,23 +10405,23 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.2", + "webpki-roots 1.0.4", ] [[package]] name = "webpki-roots" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] [[package]] name = "weezl" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "wide" @@ -10483,7 +10473,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.48.0", ] [[package]] @@ -10513,37 +10503,37 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.62.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.0", - "windows-result 0.4.0", - "windows-strings 0.5.0", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -10554,9 +10544,9 @@ checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-registry" @@ -10580,11 +10570,11 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -10598,11 +10588,11 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -10638,16 +10628,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link 0.2.1", ] [[package]] @@ -10683,19 +10673,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -10712,9 +10702,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -10730,9 +10720,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -10748,9 +10738,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -10760,9 +10750,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -10778,9 +10768,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -10796,9 +10786,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -10814,9 +10804,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -10832,9 +10822,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" @@ -10851,7 +10841,7 @@ version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "windows-sys 0.48.0", ] @@ -10863,9 +10853,9 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "ws2_32-sys" @@ -10914,13 +10904,12 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", - "yoke-derive 0.8.0", + "yoke-derive 0.8.1", "zerofrom", ] @@ -10932,19 +10921,19 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "synstructure", ] [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "synstructure", ] @@ -10965,7 +10954,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -10985,15 +10974,15 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zeromq" @@ -11034,35 +11023,35 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", - "yoke 0.8.0", + "yoke 0.8.1", "zerofrom", ] [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ - "yoke 0.8.0", + "yoke 0.8.1", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -11075,7 +11064,7 @@ dependencies = [ "crc32fast", "crossbeam-utils", "displaydoc", - "indexmap 2.11.4", + "indexmap 2.12.0", "num_enum", "thiserror 1.0.69", ] @@ -11089,7 +11078,7 @@ dependencies = [ "arbitrary", "crc32fast", "flate2", - "indexmap 2.11.4", + "indexmap 2.12.0", "memchr", "zopfli", ] @@ -11124,9 +11113,9 @@ dependencies = [ [[package]] name = "zopfli" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" dependencies = [ "bumpalo", "crc32fast", diff --git a/Cargo.toml b/Cargo.toml index 87e426dad..722729735 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,6 +97,7 @@ reqwest = { version = "0.12.22", default-features = false, features = [ "stream", "rustls-tls", ] } +rmp-serde = { version = "1" } serde = { version = "1", features = ["derive"] } serde_json = { version = "1" } strum = { version = "0.27", features = ["derive"] } diff --git a/examples/backends/vllm/launch/agg_request_planes.sh b/examples/backends/vllm/launch/agg_request_planes.sh new file mode 100755 index 000000000..6e55b8495 --- /dev/null +++ b/examples/backends/vllm/launch/agg_request_planes.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +set -e +trap 'echo Cleaning up...; kill 0' EXIT + +# Parse command-line arguments for request plane mode +REQUEST_PLANE="tcp" # Default to TCP + +while [[ $# -gt 0 ]]; do + case $1 in + --tcp) + REQUEST_PLANE="tcp" + shift + ;; + --http) + REQUEST_PLANE="http" + shift + ;; + --nats) + REQUEST_PLANE="nats" + shift + ;; + -h|--help) + echo "Usage: $0 [--tcp|--http|--nats]" + echo " --tcp Use TCP request plane (default)" + echo " --http Use HTTP/2 request plane" + echo " --nats Use NATS request plane" + exit 0 + ;; + *) + echo "Unknown option: $1" + echo "Use --help for usage information" + exit 1 + ;; + esac +done + +# Set the request plane mode +export DYN_REQUEST_PLANE=$REQUEST_PLANE +echo "Using request plane mode: $REQUEST_PLANE" + +# Frontend +python -m dynamo.frontend --http-port=8000 & + +DYN_SYSTEM_PORT=8081 \ + python -m dynamo.vllm --model Qwen/Qwen3-0.6B --enforce-eager --connector none diff --git a/lib/async-openai/Cargo.toml b/lib/async-openai/Cargo.toml index 2799d8e11..9835241a1 100644 --- a/lib/async-openai/Cargo.toml +++ b/lib/async-openai/Cargo.toml @@ -39,7 +39,7 @@ backoff = { version = "0.4.0", features = ["tokio"] } base64 = "0.22.1" futures = "0.3.31" rand = "0.9.0" -reqwest = { version = "0.12.12", features = [ +reqwest = { version = "0.12.24", features = [ "json", "stream", "multipart", diff --git a/lib/bindings/python/Cargo.lock b/lib/bindings/python/Cargo.lock index 34345b2ae..5eeaa775f 100644 --- a/lib/bindings/python/Cargo.lock +++ b/lib/bindings/python/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -23,8 +23,8 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ - "cfg-if 1.0.3", - "getrandom 0.3.3", + "cfg-if 1.0.4", + "getrandom 0.3.4", "once_cell", "serde", "version_check", @@ -33,9 +33,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -61,12 +61,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[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" @@ -78,9 +72,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -93,9 +87,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -128,9 +122,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" dependencies = [ "backtrace", ] @@ -158,7 +152,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -253,7 +247,7 @@ checksum = "0289cba6d5143bfe8251d57b4a8cac036adf158525a76533a7082ba65ec76398" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -275,7 +269,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -286,7 +280,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -339,14 +333,14 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "av1-grain" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" dependencies = [ "anyhow", "arrayvec", "log", - "nom", + "nom 8.0.0", "num-rational", "v_frame", ] @@ -362,9 +356,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.13.3" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +checksum = "5932a7d9d28b0d2ea34c6b3779d35e3dd6f6345317c34e73438c4f1f29144151" dependencies = [ "aws-lc-sys", "zeroize", @@ -372,9 +366,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.30.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +checksum = "1826f2e4cfc2cd19ee53c42fbf68e2f81ec21108e0b7ecf6a71cf062137360fc" dependencies = [ "bindgen", "cc", @@ -420,9 +414,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" dependencies = [ "bytes", "futures-core", @@ -431,7 +425,6 @@ dependencies = [ "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", @@ -446,7 +439,7 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -498,17 +491,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libc", "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link 0.2.1", ] [[package]] @@ -517,12 +510,6 @@ 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" @@ -566,25 +553,22 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.5" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "cexpr", "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", "shlex", - "syn 2.0.106", - "which", + "syn 2.0.110", ] [[package]] @@ -631,11 +615,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.3" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -653,7 +637,7 @@ dependencies = [ "arrayref", "arrayvec", "cc", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "constant_time_eq", "memmap2", "rayon-core", @@ -681,12 +665,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", - "regex-automata 0.4.10", + "regex-automata", "serde", ] @@ -704,22 +688,22 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f154e572231cb6ba2bd1176980827e3d5dc04cc183a75dea38109fbdd672d29" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -776,10 +760,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.34" +version = "1.2.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" +checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -791,7 +776,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom", + "nom 7.1.3", ] [[package]] @@ -812,9 +797,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -824,17 +809,16 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link 0.1.3", + "windows-link 0.2.1", ] [[package]] @@ -850,9 +834,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.46" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -860,9 +844,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.46" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -872,21 +856,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.45" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "clap_lex" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" [[package]] name = "cmake" @@ -925,7 +909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" dependencies = [ "castaway", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "itoa", "rustversion", "ryu", @@ -944,9 +928,9 @@ dependencies = [ [[package]] name = "config" -version = "0.15.15" +version = "0.15.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0faa974509d38b33ff89282db9c3295707ccf031727c0de9772038ec526852ba" +checksum = "b30fa8254caad766fc03cb0ccae691e14bf3bd72bfff27f72802ce729551b3d6" dependencies = [ "async-trait", "convert_case", @@ -954,10 +938,10 @@ dependencies = [ "pathdiff", "ron", "rust-ini", - "serde", "serde-untagged", + "serde_core", "serde_json", - "toml 0.9.5", + "toml 0.9.8", "winnow", "yaml-rust2", ] @@ -1057,7 +1041,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", ] [[package]] @@ -1124,9 +1108,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -1134,9 +1118,9 @@ dependencies = [ [[package]] name = "cudarc" -version = "0.17.2" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8147ca46109d41cc513fd629b52bbea9bd09b972034c2f32954ce84a92895a91" +checksum = "0bf99ab37ee7072d64d906aa2dada9a3422f1d975cdf8c8055a573bc84897ed8" dependencies = [ "libloading", ] @@ -1147,7 +1131,7 @@ version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "cpufeatures", "curve25519-dalek-derive", "digest", @@ -1164,7 +1148,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1198,7 +1182,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1212,7 +1196,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1223,7 +1207,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1234,14 +1218,14 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "dary_heap" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d2cd9c18b9f454ed67da600630b021a8a80bf33f8c95896ab33aaf1c26b728" +checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04" dependencies = [ "serde", ] @@ -1252,7 +1236,21 @@ version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if 1.0.4", + "crossbeam-utils", "hashbrown 0.14.5", "lock_api", "once_cell", @@ -1284,12 +1282,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -1300,7 +1298,7 @@ checksum = "74ef43543e701c01ad77d3a5922755c6a1d71b22d942cb8042be4994b380caff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1311,7 +1309,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1332,7 +1330,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1342,7 +1340,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1371,7 +1369,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "unicode-xid", ] @@ -1383,7 +1381,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1437,7 +1435,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -1448,7 +1446,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1494,13 +1492,20 @@ dependencies = [ [[package]] name = "dyn-stack" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490bd48eb68fffcfed519b4edbfd82c69cbe741d175b84f0e0cbe8c57cbe0bdd" +checksum = "1c4713e43e2886ba72b8271aa66c93d722116acf7a75555cce11dcde84388fe8" dependencies = [ "bytemuck", + "dyn-stack-macros", ] +[[package]] +name = "dyn-stack-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9" + [[package]] name = "dynamo-async-openai" version = "0.7.0" @@ -1518,7 +1523,7 @@ dependencies = [ "secrecy", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", "tokio-util", @@ -1543,14 +1548,14 @@ dependencies = [ "axum-server", "base64 0.22.1", "bincode 2.0.1", - "bitflags 2.9.3", + "bitflags 2.10.0", "blake3", "bs62", "bytemuck", "bytes", "candle-core", "chrono", - "dashmap", + "dashmap 5.5.3", "derive-getters", "derive_builder", "dialoguer", @@ -1565,6 +1570,8 @@ dependencies = [ "galil-seiferas", "hf-hub", "humantime", + "hyper", + "hyper-util", "image", "itertools 0.14.0", "json-five", @@ -1588,7 +1595,7 @@ dependencies = [ "serde_json", "strum", "tempfile", - "thiserror 2.0.16", + "thiserror 2.0.17", "tmq", "tokenizers", "tokio", @@ -1599,6 +1606,7 @@ dependencies = [ "toktrie_hf_tokenizers", "tonic 0.13.1", "tonic-build", + "tower", "tower-http", "tracing", "unicode-segmentation", @@ -1654,7 +1662,7 @@ dependencies = [ "rstest", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", "tokio-util", @@ -1679,6 +1687,7 @@ dependencies = [ "blake3", "bytes", "chrono", + "dashmap 6.1.0", "derive-getters", "derive_builder", "educe", @@ -1687,8 +1696,12 @@ dependencies = [ "figment", "futures", "humantime", + "hyper", + "hyper-util", + "inotify 0.11.0", "k8s-openapi", "kube", + "libc", "local-ip-address", "log", "nid", @@ -1705,14 +1718,16 @@ dependencies = [ "rayon", "regex", "reqwest", + "rmp-serde", "serde", "serde_json", "socket2 0.5.10", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-rayon", "tokio-stream", "tokio-util", + "tower", "tower-http", "tracing", "tracing-opentelemetry", @@ -1754,7 +1769,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1778,7 +1793,7 @@ version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", ] [[package]] @@ -1790,27 +1805,27 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "enum-ordinalize" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ "enum-ordinalize-derive", ] [[package]] name = "enum-ordinalize-derive" -version = "4.3.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1830,7 +1845,7 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -1841,22 +1856,23 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" dependencies = [ "serde", + "serde_core", "typeid", ] [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -1912,15 +1928,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab" dependencies = [ "futures-core", - "nom", + "nom 7.1.3", "pin-project-lite", ] [[package]] name = "exr" -version = "1.73.0" +version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" dependencies = [ "bit_field", "half", @@ -1938,8 +1954,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" dependencies = [ "bit-set 0.5.3", - "regex-automata 0.4.10", - "regex-syntax 0.8.6", + "regex-automata", + "regex-syntax", ] [[package]] @@ -1949,8 +1965,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298" dependencies = [ "bit-set 0.8.0", - "regex-automata 0.4.10", - "regex-syntax 0.8.6", + "regex-automata", + "regex-syntax", ] [[package]] @@ -1959,6 +1975,26 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + [[package]] name = "fdeflate" version = "0.3.7" @@ -1997,12 +2033,18 @@ version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libc", "libredox", "windows-sys 0.60.2", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "fixedbitset" version = "0.5.7" @@ -2011,9 +2053,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ "crc32fast", "libz-rs-sys", @@ -2043,9 +2085,9 @@ dependencies = [ [[package]] name = "fs-err" -version = "3.1.1" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d7be93788013f265201256d58f04936a8079ad5dc898743aa20525f503b683" +checksum = "6ad492b2cf1d89d568a43508ab24f98501fe03f2f31c01e1d0fe7366a71745d2" dependencies = [ "autocfg", "tokio", @@ -2138,7 +2180,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -2213,7 +2255,7 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab96b703d31950f1aeddded248bc95543c9efc7ac9c4a21fda8703a83ee35451" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-c32 0.18.2", "gemm-c64 0.18.2", "gemm-common 0.18.2", @@ -2223,7 +2265,7 @@ dependencies = [ "num-complex", "num-traits", "paste", - "raw-cpuid 11.5.0", + "raw-cpuid 11.6.0", "seq-macro", ] @@ -2248,12 +2290,12 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6db9fd9f40421d00eea9dd0770045a5603b8d684654816637732463f4073847" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-common 0.18.2", "num-complex", "num-traits", "paste", - "raw-cpuid 11.5.0", + "raw-cpuid 11.6.0", "seq-macro", ] @@ -2278,12 +2320,12 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfcad8a3d35a43758330b635d02edad980c1e143dc2f21e6fd25f9e4eada8edf" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-common 0.18.2", "num-complex", "num-traits", "paste", - "raw-cpuid 11.5.0", + "raw-cpuid 11.6.0", "seq-macro", ] @@ -2314,7 +2356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a352d4a69cbe938b9e2a9cb7a3a63b7e72f9349174a2752a558a8a563510d0f3" dependencies = [ "bytemuck", - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "half", "libm", "num-complex", @@ -2322,7 +2364,7 @@ dependencies = [ "once_cell", "paste", "pulp 0.21.5", - "raw-cpuid 11.5.0", + "raw-cpuid 11.6.0", "rayon", "seq-macro", "sysctl 0.6.0", @@ -2352,14 +2394,14 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cff95ae3259432f3c3410eaa919033cd03791d81cebd18018393dc147952e109" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-common 0.18.2", "gemm-f32 0.18.2", "half", "num-complex", "num-traits", "paste", - "raw-cpuid 11.5.0", + "raw-cpuid 11.6.0", "rayon", "seq-macro", ] @@ -2385,12 +2427,12 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc8d3d4385393304f407392f754cd2dc4b315d05063f62cf09f47b58de276864" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-common 0.18.2", "num-complex", "num-traits", "paste", - "raw-cpuid 11.5.0", + "raw-cpuid 11.6.0", "seq-macro", ] @@ -2415,12 +2457,12 @@ version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35b2a4f76ce4b8b16eadc11ccf2e083252d8237c1b589558a49b0183545015bd" dependencies = [ - "dyn-stack 0.13.0", + "dyn-stack 0.13.2", "gemm-common 0.18.2", "num-complex", "num-traits", "paste", - "raw-cpuid 11.5.0", + "raw-cpuid 11.6.0", "seq-macro", ] @@ -2449,24 +2491,24 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "js-sys", "libc", "r-efi", - "wasi 0.14.3+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] @@ -2482,9 +2524,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" @@ -2516,7 +2558,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.11.0", + "indexmap 2.12.0", "slab", "tokio", "tokio-util", @@ -2525,16 +2567,17 @@ dependencies = [ [[package]] name = "half" -version = "2.6.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "bytemuck", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "crunchy", "num-traits", "rand 0.9.2", "rand_distr", + "zerocopy", ] [[package]] @@ -2563,6 +2606,12 @@ dependencies = [ "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "hashlink" version = "0.10.0" @@ -2607,7 +2656,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "ureq", "windows-sys 0.60.2", @@ -2615,11 +2664,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2628,7 +2677,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libc", "windows-link 0.1.3", ] @@ -2681,9 +2730,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" @@ -2719,12 +2768,12 @@ dependencies = [ "hyper-util", "log", "rustls", - "rustls-native-certs 0.8.1", + "rustls-native-certs 0.8.2", "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.2", + "webpki-roots 1.0.4", ] [[package]] @@ -2742,9 +2791,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64 0.22.1", "bytes", @@ -2758,7 +2807,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.5.10", "system-configuration", "tokio", "tower-service", @@ -2768,9 +2817,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2792,22 +2841,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", - "yoke 0.8.0", + "yoke 0.8.1", "zerofrom", "zerovec", ] [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -2818,11 +2867,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -2833,44 +2881,40 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", - "yoke 0.8.0", + "yoke 0.8.1", "zerofrom", "zerotrie", "zerovec", @@ -2905,9 +2949,9 @@ dependencies = [ [[package]] name = "image" -version = "0.25.6" +version = "0.25.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" dependencies = [ "bytemuck", "byteorder-lite", @@ -2915,6 +2959,7 @@ dependencies = [ "exr", "gif", "image-webp", + "moxcms", "num-traits", "png", "qoi", @@ -2938,9 +2983,9 @@ dependencies = [ [[package]] name = "imgref" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" [[package]] name = "indexmap" @@ -2955,13 +3000,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "serde", + "serde_core", ] [[package]] @@ -2979,9 +3025,12 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] [[package]] name = "inlinable_string" @@ -3000,6 +3049,19 @@ dependencies = [ "libc", ] +[[package]] +name = "inotify" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" +dependencies = [ + "bitflags 2.10.0", + "futures-core", + "inotify-sys", + "libc", + "tokio", +] + [[package]] name = "inotify-sys" version = "0.1.5" @@ -3015,7 +3077,7 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", ] [[package]] @@ -3026,7 +3088,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -3038,17 +3100,6 @@ dependencies = [ "rustversion", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.3", - "cfg-if 1.0.3", - "libc", -] - [[package]] name = "iovec" version = "0.1.4" @@ -3066,9 +3117,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -3083,14 +3134,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -3110,6 +3161,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -3127,28 +3187,28 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" dependencies = [ "jiff-static", "jiff-tzdb-platform", "log", "portable-atomic", "portable-atomic-util", - "serde", - "windows-sys 0.59.0", + "serde_core", + "windows-sys 0.52.0", ] [[package]] name = "jiff-static" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -3172,21 +3232,15 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" - [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -3235,7 +3289,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3341,7 +3395,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-util", "tower", @@ -3361,11 +3415,11 @@ dependencies = [ "http", "json-patch", "k8s-openapi", - "schemars 1.0.4", + "schemars 1.1.0", "serde", "serde-value", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3379,7 +3433,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -3403,7 +3457,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-util", "tracing", @@ -3421,23 +3475,17 @@ 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 = "lebe" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" -version = "0.2.175" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libfuzzer-sys" @@ -3451,12 +3499,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ - "cfg-if 1.0.3", - "windows-targets 0.53.3", + "cfg-if 1.0.4", + "windows-link 0.2.1", ] [[package]] @@ -3467,11 +3515,11 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "libc", "redox_syscall", ] @@ -3487,21 +3535,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "local-ip-address" @@ -3511,7 +3553,7 @@ checksum = "656b3b27f8893f7bbf9485148ff9a65f019e3f33bd5cdc87c83cab16b3fd9ec8" dependencies = [ "libc", "neli", - "thiserror 2.0.16", + "thiserror 2.0.17", "windows-sys 0.59.0", ] @@ -3526,9 +3568,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "loop9" @@ -3621,11 +3663,11 @@ dependencies = [ [[package]] name = "matchers" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "regex-automata 0.1.10", + "regex-automata", ] [[package]] @@ -3650,21 +3692,21 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "rayon", ] [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" dependencies = [ "libc", "stable_deref_trait", @@ -3765,19 +3807,19 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.48.0", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -3806,7 +3848,7 @@ dependencies = [ "prost 0.13.5", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tonic 0.13.1", "tracing", @@ -3831,7 +3873,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tonic 0.13.1", "tonic-build", @@ -3840,23 +3882,34 @@ dependencies = [ [[package]] name = "monostate" -version = "0.1.14" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafe1be9d0c75642e3e50fedc7ecadf1ef1cbce6eb66462153fc44245343fbee" +checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67" dependencies = [ "monostate-impl", "serde", + "serde_core", ] [[package]] name = "monostate-impl" -version = "0.1.14" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c402a4092d5e204f32c9e155431046831fa712637043c58cb73bc6bc6c9663b5" +checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", +] + +[[package]] +name = "moxcms" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6" +dependencies = [ + "num-traits", + "pxfm", ] [[package]] @@ -3939,8 +3992,8 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.9.3", - "cfg-if 1.0.3", + "bitflags 2.10.0", + "cfg-if 1.0.4", "cfg_aliases", "libc", ] @@ -3970,6 +4023,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + [[package]] name = "nonmax" version = "0.5.5" @@ -3988,10 +4050,10 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "filetime", "fsevent-sys", - "inotify", + "inotify 0.9.6", "kqueue", "libc", "log", @@ -4002,12 +4064,11 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "overload", - "winapi 0.3.9", + "windows-sys 0.59.0", ] [[package]] @@ -4067,7 +4128,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4123,9 +4184,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -4133,14 +4194,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4160,9 +4221,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -4185,9 +4246,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "oneshot" @@ -4201,7 +4262,7 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "libc", "once_cell", "onig_sys", @@ -4238,7 +4299,7 @@ dependencies = [ "serde_with", "sha1", "sha2", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4257,7 +4318,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -4287,7 +4348,7 @@ dependencies = [ "opentelemetry_sdk", "prost 0.14.1", "reqwest", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tonic 0.14.2", "tracing", @@ -4318,7 +4379,7 @@ dependencies = [ "opentelemetry", "percent-encoding", "rand 0.9.2", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", ] @@ -4348,12 +4409,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "parking" version = "2.2.1" @@ -4376,7 +4431,7 @@ version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libc", "redox_syscall", "smallvec", @@ -4415,7 +4470,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4445,20 +4500,19 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" +checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" dependencies = [ "memchr", - "thiserror 2.0.16", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663" +checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" dependencies = [ "pest", "pest_generator", @@ -4466,22 +4520,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f" +checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "pest_meta" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420" +checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" dependencies = [ "pest", "sha2", @@ -4494,7 +4548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset", - "indexmap 2.11.0", + "indexmap 2.12.0", ] [[package]] @@ -4552,7 +4606,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4585,11 +4639,11 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "png" -version = "0.17.16" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.10.0", "crc32fast", "fdeflate", "flate2", @@ -4613,9 +4667,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -4642,16 +4696,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.7", ] [[package]] @@ -4673,14 +4727,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -4693,7 +4747,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "version_check", "yansi", ] @@ -4714,7 +4768,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4723,13 +4777,13 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ca5326d8d0b950a9acd87e6a3f94745394f62e4dae1b1ee22b2bc0c394af43a" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "fnv", "lazy_static", "memchr", "parking_lot", "protobuf", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4768,7 +4822,7 @@ dependencies = [ "prost 0.13.5", "prost-types", "regex", - "syn 2.0.106", + "syn 2.0.110", "tempfile", ] @@ -4782,7 +4836,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4795,7 +4849,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4846,20 +4900,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96b86df24f0a7ddd5e4b95c94fc9ed8a98f1ca94d3b01bdce2824097e7835907" dependencies = [ "bytemuck", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "libm", "num-complex", "reborrow", "version_check", ] +[[package]] +name = "pxfm" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84" +dependencies = [ + "num-traits", +] + [[package]] name = "pyo3" version = "0.23.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7778bffd85cf38175ac1f545509665d0b9b92a198ca7941f131f85f7a4f9a872" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "indoc", "libc", "memoffset", @@ -4896,7 +4959,7 @@ checksum = "b2df2884957d2476731f987673befac5d521dff10abb0a7cbe12015bc7702fe9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4928,7 +4991,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4941,7 +5004,7 @@ dependencies = [ "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -4982,8 +5045,8 @@ dependencies = [ "quinn-udp", "rustc-hash 2.1.1", "rustls", - "socket2 0.6.0", - "thiserror 2.0.16", + "socket2 0.5.10", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -4996,7 +5059,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "getrandom 0.3.3", + "getrandom 0.3.4", "lru-slab", "rand 0.9.2", "ring", @@ -5004,7 +5067,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.16", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -5019,16 +5082,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.0", + "socket2 0.5.10", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -5095,7 +5158,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -5120,7 +5183,7 @@ dependencies = [ "av1-grain", "bitstream-io", "built", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "interpolate_name", "itertools 0.12.1", "libc", @@ -5169,11 +5232,11 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.5.0" +version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", ] [[package]] @@ -5221,11 +5284,11 @@ checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", ] [[package]] @@ -5236,72 +5299,57 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "regex" -version = "1.11.2" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.10", - "regex-syntax 0.8.6", + "regex-automata", + "regex-syntax", ] [[package]] name = "regex-automata" -version = "0.1.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.6", + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "relative-path" @@ -5311,9 +5359,9 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "reqwest" -version = "0.12.23" +version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ "base64 0.22.1", "bytes", @@ -5336,7 +5384,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", - "rustls-native-certs 0.8.1", + "rustls-native-certs 0.8.2", "rustls-pki-types", "serde", "serde_json", @@ -5353,7 +5401,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.2", + "webpki-roots 1.0.4", ] [[package]] @@ -5366,7 +5414,7 @@ dependencies = [ "futures-core", "futures-timer", "mime", - "nom", + "nom 7.1.3", "pin-project-lite", "reqwest", "thiserror 1.0.69", @@ -5385,7 +5433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", - "cfg-if 1.0.3", + "cfg-if 1.0.4", "getrandom 0.2.16", "libc", "untrusted", @@ -5416,14 +5464,16 @@ dependencies = [ [[package]] name = "ron" -version = "0.8.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32" dependencies = [ - "base64 0.21.7", - "bitflags 2.9.3", + "bitflags 2.10.0", + "once_cell", "serde", "serde_derive", + "typeid", + "unicode-ident", ] [[package]] @@ -5444,7 +5494,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f168d99749d307be9de54d23fd226628d99768225ef08f6ffb52e0182a27746" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "glob", "proc-macro-crate", "proc-macro2", @@ -5452,15 +5502,15 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.106", + "syn 2.0.110", "unicode-ident", ] [[package]] name = "rust-embed" -version = "8.7.2" +version = "8.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025908b8682a26ba8d12f6f2d66b987584a4a87bc024abc5bbc12553a8cd178a" +checksum = "947d7f3fad52b283d261c4c99a084937e2fe492248cb9a68a8435a861b8798ca" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -5469,22 +5519,22 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "8.7.2" +version = "8.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6065f1a4392b71819ec1ea1df1120673418bf386f50de1d6f54204d836d4349c" +checksum = "5fa2c8c9e8711e10f9c4fd2d64317ef13feaab820a4c51541f1a8c8e2e851ab2" dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.106", + "syn 2.0.110", "walkdir", ] [[package]] name = "rust-embed-utils" -version = "8.7.2" +version = "8.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6cc0c81648b20b70c491ff8cce00c1c3b223bb8ed2b5d41f0e54c6c4c0a3594" +checksum = "60b161f275cb337fe0a44d924a5f4df0ed69c2c39519858f931ce61c779d3475" dependencies = [ "sha2", "walkdir", @@ -5496,7 +5546,7 @@ version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "ordered-multimap", ] @@ -5529,42 +5579,29 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.44" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "errno", "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" -dependencies = [ - "bitflags 2.9.3", - "errno", - "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", + "linux-raw-sys", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.4", + "rustls-webpki 0.103.8", "subtle", "zeroize", ] @@ -5584,14 +5621,14 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.3.0", + "security-framework 3.5.1", ] [[package]] @@ -5605,9 +5642,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "web-time", "zeroize", @@ -5625,9 +5662,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "aws-lc-rs", "ring", @@ -5725,11 +5762,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5746,9 +5783,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" dependencies = [ "dyn-clone", "ref-cast", @@ -5759,14 +5796,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80" +checksum = "301858a4023d78debd2353c7426dc486001bddc91ae31a76fb1f55132f7e2633" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -5791,7 +5828,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -5800,11 +5837,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.3.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -5813,9 +5850,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -5823,15 +5860,15 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" +checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33" [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "seq-macro" @@ -5851,12 +5888,13 @@ dependencies = [ [[package]] name = "serde-untagged" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34836a629bcbc6f1afdf0907a744870039b1e14c0561cb26094fa683b158eff3" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" dependencies = [ "erased-serde", "serde", + "serde_core", "typeid", ] @@ -5887,7 +5925,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -5898,20 +5936,21 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.12.0", "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -5925,12 +5964,13 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] @@ -5941,7 +5981,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -5955,11 +5995,11 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -5976,19 +6016,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.0" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" +checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.11.0", + "indexmap 2.12.0", "schemars 0.9.0", - "schemars 1.0.4", - "serde", - "serde_derive", + "schemars 1.1.0", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -5996,14 +6035,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.0" +version = "3.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" +checksum = "b91a903660542fced4e99881aa481bdbaec1634568ee02e0b8bd57c64cb38955" dependencies = [ - "darling 0.20.11", + "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6012,7 +6051,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.12.0", "itoa", "ryu", "serde", @@ -6025,7 +6064,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "cpufeatures", "digest", ] @@ -6036,7 +6075,7 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "cpufeatures", "digest", ] @@ -6138,12 +6177,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -6174,16 +6213,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5851699c4033c63636f7ea4cf7b7c1f1bf06d0cc03cfb42e711de5a5c46cf326" dependencies = [ "base64 0.13.1", - "nom", + "nom 7.1.3", "serde", "unicode-segmentation", ] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -6215,7 +6254,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6237,9 +6276,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" dependencies = [ "proc-macro2", "quote", @@ -6263,7 +6302,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6272,7 +6311,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec7dddc5f0fee506baf8b9fdb989e242f17e4b11c61dfbb0635b705217199eea" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "byteorder", "enum-as-inner", "libc", @@ -6286,7 +6325,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01198a2debb237c62b6826ec7081082d951f46dbb64b0e8c7649a452230d1dfc" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "byteorder", "enum-as-inner", "libc", @@ -6300,7 +6339,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.3", + "bitflags 2.10.0", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -6336,15 +6375,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.21.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", - "rustix 1.0.8", - "windows-sys 0.60.2", + "rustix", + "windows-sys 0.52.0", ] [[package]] @@ -6358,11 +6397,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -6373,18 +6412,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6393,25 +6432,28 @@ version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", ] [[package]] name = "tiff" -version = "0.9.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" dependencies = [ + "fax", "flate2", - "jpeg-decoder", + "half", + "quick-error", "weezl", + "zune-jpeg", ] [[package]] name = "time" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", @@ -6426,15 +6468,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -6451,9 +6493,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -6500,7 +6542,7 @@ dependencies = [ "derive_builder", "esaxx-rs", "fancy-regex 0.14.0", - "getrandom 0.3.3", + "getrandom 0.3.4", "hf-hub", "itertools 0.14.0", "log", @@ -6512,11 +6554,11 @@ dependencies = [ "rayon", "rayon-cond", "regex", - "regex-syntax 0.8.6", + "regex-syntax", "serde", "serde_json", "spm_precompiled", - "thiserror 2.0.16", + "thiserror 2.0.17", "unicode-normalization-alignments", "unicode-segmentation", "unicode_categories", @@ -6524,33 +6566,30 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", - "mio 1.0.4", + "mio 1.1.0", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2 0.6.1", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6565,9 +6604,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", @@ -6586,9 +6625,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -6623,9 +6662,9 @@ dependencies = [ [[package]] name = "toktrie" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804459e7818d5cc8920f80d555526454353117a4f2fcda38e4b38666639d7e81" +checksum = "55c5e672ee5e0311bbb37ac0f9f60ed7db38463365e6cf4f71240c7b15bb374d" dependencies = [ "anyhow", "bytemuck", @@ -6636,9 +6675,9 @@ dependencies = [ [[package]] name = "toktrie_hf_tokenizers" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fc302ed2c53b1d7fcbe3d760a2dc6567def0eb2da7ca09cb21a16b9a9aa4f13" +checksum = "baec7fb81a716f85ae1e07ce951f9e9bc1b745635edd48cbebb6a033c6491dca" dependencies = [ "anyhow", "log", @@ -6657,18 +6696,18 @@ dependencies = [ "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", - "toml_edit", + "toml_edit 0.22.27", ] [[package]] name = "toml" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ - "serde", - "serde_spanned 1.0.0", - "toml_datetime 0.7.0", + "serde_core", + "serde_spanned 1.0.3", + "toml_datetime 0.7.3", "toml_parser", "winnow", ] @@ -6684,11 +6723,11 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -6697,7 +6736,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.12.0", "serde", "serde_spanned 0.6.9", "toml_datetime 0.6.11", @@ -6706,10 +6745,22 @@ dependencies = [ ] [[package]] -name = "toml_parser" -version = "1.0.3" +name = "toml_edit" +version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +dependencies = [ + "indexmap 2.12.0", + "toml_datetime 0.7.3", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] @@ -6787,7 +6838,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6809,7 +6860,7 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "indexmap 2.11.0", + "indexmap 2.12.0", "pin-project-lite", "slab", "sync_wrapper", @@ -6827,7 +6878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ "base64 0.22.1", - "bitflags 2.9.3", + "bitflags 2.10.0", "bytes", "futures-util", "http", @@ -6873,7 +6924,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -6908,7 +6959,7 @@ dependencies = [ "opentelemetry_sdk", "rustversion", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "tracing-core", "tracing-log", @@ -6928,14 +6979,14 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" dependencies = [ "matchers", "nu-ansi-term", "once_cell", - "regex", + "regex-automata", "serde", "serde_json", "sharded-slab", @@ -6972,9 +7023,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -7084,9 +7135,9 @@ checksum = "0b993bddc193ae5bd0d623b49ec06ac3e9312875fdae725a975c51db1cc1677f" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization-alignments" @@ -7105,9 +7156,9 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" @@ -7216,7 +7267,7 @@ version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fcc29c80c21c31608227e0912b2d7fddba57ad76b606890627ba8ee7964e993" dependencies = [ - "indexmap 2.11.0", + "indexmap 2.12.0", "serde", "serde_json", "utoipa-gen", @@ -7231,7 +7282,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -7254,11 +7305,11 @@ dependencies = [ [[package]] name = "uuid" -version = "1.18.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", "serde", "wasm-bindgen", @@ -7302,7 +7353,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -7313,9 +7364,9 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "version-compare" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "version_check" @@ -7355,47 +7406,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.3+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.106", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ - "cfg-if 1.0.3", + "cfg-if 1.0.4", "js-sys", "once_cell", "wasm-bindgen", @@ -7404,9 +7442,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7414,22 +7452,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", - "wasm-bindgen-backend", + "syn 2.0.110", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -7449,9 +7487,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -7473,35 +7511,23 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.2", + "webpki-roots 1.0.4", ] [[package]] name = "webpki-roots" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] [[package]] name = "weezl" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" - -[[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", -] +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "winapi" @@ -7533,11 +7559,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.48.0", ] [[package]] @@ -7548,37 +7574,37 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.1.3", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -7600,8 +7626,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ "windows-link 0.1.3", - "windows-result", - "windows-strings", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -7613,6 +7639,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -7622,6 +7657,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -7655,7 +7699,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", ] [[package]] @@ -7691,19 +7744,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -7720,9 +7773,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -7738,9 +7791,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -7756,9 +7809,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -7768,9 +7821,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -7786,9 +7839,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -7804,9 +7857,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -7822,9 +7875,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -7840,9 +7893,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" @@ -7855,15 +7908,15 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.45.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "ws2_32-sys" @@ -7912,13 +7965,12 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", - "yoke-derive 0.8.0", + "yoke-derive 0.8.1", "zerofrom", ] @@ -7930,40 +7982,40 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "synstructure", ] [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -7983,15 +8035,15 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zeromq" @@ -8003,7 +8055,7 @@ dependencies = [ "asynchronous-codec", "bytes", "crossbeam-queue", - "dashmap", + "dashmap 5.5.3", "futures-channel", "futures-io", "futures-task", @@ -8032,35 +8084,35 @@ dependencies = [ [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", - "yoke 0.8.0", + "yoke 0.8.1", "zerofrom", ] [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ - "yoke 0.8.0", + "yoke 0.8.1", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.110", ] [[package]] @@ -8073,7 +8125,7 @@ dependencies = [ "crc32fast", "crossbeam-utils", "displaydoc", - "indexmap 2.11.0", + "indexmap 2.12.0", "num_enum", "thiserror 1.0.69", ] @@ -8087,7 +8139,7 @@ dependencies = [ "arbitrary", "crc32fast", "flate2", - "indexmap 2.11.0", + "indexmap 2.12.0", "memchr", "zopfli", ] @@ -8122,9 +8174,9 @@ dependencies = [ [[package]] name = "zopfli" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" dependencies = [ "bumpalo", "crc32fast", @@ -8149,9 +8201,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1f7e205ce79eb2da3cd71c5f55f3589785cb7c79f6a03d1c8d1491bda5d089" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ "zune-core", ] diff --git a/lib/bindings/python/rust/http.rs b/lib/bindings/python/rust/http.rs index 1cf01322b..ff75d9dcd 100644 --- a/lib/bindings/python/rust/http.rs +++ b/lib/bindings/python/rust/http.rs @@ -169,7 +169,7 @@ where let message = message.replace(['\r', '\n'], ""); return Err(http_error::HttpError { code, message })?; } - Err(error!("Python Error: {}", py_err.to_string())) + Err(error!("Python Error: {}", py_err)) }) } else { Err(e) diff --git a/lib/llm/Cargo.toml b/lib/llm/Cargo.toml index ecc4a20d8..87fece25c 100644 --- a/lib/llm/Cargo.toml +++ b/lib/llm/Cargo.toml @@ -106,8 +106,11 @@ unicode-segmentation = "1.12" # http-service axum = { workspace = true } axum-server = { version = "0.7", features = ["tls-rustls"] } +hyper = { version = "1.5", features = ["http2", "server"] } +hyper-util = { version = "0.1", features = ["tokio", "server", "server-auto"] } tower-http = { workspace = true } rustls = { version = "0.23" } +tower = { version = "0.5", features = ["util", "make"] } utoipa = { version = "5.3", features = ["axum_extras"] } utoipa-swagger-ui = { version = "9.0", features = ["axum"] } diff --git a/lib/llm/src/common/checked_file.rs b/lib/llm/src/common/checked_file.rs index 76dcdef22..68c014f1c 100644 --- a/lib/llm/src/common/checked_file.rs +++ b/lib/llm/src/common/checked_file.rs @@ -82,10 +82,6 @@ impl CheckedFile { } } - pub fn is_nats_url(&self) -> bool { - matches!(self.path.as_ref(), Either::Right(u) if u.scheme() == "nats") - } - pub fn checksum(&self) -> &Checksum { &self.checksum } diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index b98cd8550..730a7805a 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -18,6 +18,7 @@ integration = [] testing-etcd = [] # Tests that require an active ETCD server tokio-console = ["dep:console-subscriber", "tokio/tracing"] compute-validation = [] # Enable validation and timing for compute macros +tcp-low-latency = [] # Enable Linux-specific TCP optimizations (TCP_QUICKACK, SO_BUSY_POLL) [dependencies] # Use workspace dependencies where available @@ -30,6 +31,7 @@ axum = { workspace = true } blake3 = { workspace = true } bytes = { workspace = true } chrono = { workspace = true } +dashmap = { workspace = true } derive_builder = { workspace = true } derive-getters = { workspace = true } either = { workspace = true } @@ -40,13 +42,17 @@ parking_lot = { workspace = true } prometheus = { workspace = true } rand = { workspace = true } reqwest = { workspace = true } +rmp-serde = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true } tokio-stream = { workspace = true } tokio-util = { workspace = true } +tower = { version = "0.5" } tower-http = { workspace = true } tracing = { workspace = true } +hyper = { version = "1.5", features = ["http2", "server"] } +hyper-util = { version = "0.1", features = ["tokio", "server", "server-auto"] } tracing-subscriber = { workspace = true } tracing-opentelemetry = { workspace = true } opentelemetry = { workspace = true } @@ -65,6 +71,8 @@ console-subscriber = { version = "0.4", optional = true } educe = { version = "0.6.0" } figment = { version = "0.10.19", features = ["env", "json", "toml", "test"] } notify = { version = "6.1", default-features = false, features = ["macos_fsevent"] } +inotify = { version = "0.11" } +libc = { version = "0.2" } local-ip-address = { version = "0.6.3" } log = { version = "0.4" } nid = { version = "3.0.0", features = ["serde"] } @@ -84,7 +92,6 @@ k8s-openapi = { version = "0.26.0", features = ["v1_32"] } assert_matches = { version = "1.5.0" } criterion = { version = "0.5", features = ["async_tokio"] } env_logger = { version = "0.11" } -reqwest = { workspace = true } rstest = { version = "0.23.0" } temp-env = { version = "0.3.6" , features=["async_closure"] } stdio-override = {version= "0.2.0"} @@ -94,3 +101,7 @@ tempfile = { workspace = true } [[bench]] name = "compute_pool_overhead" harness = false + +[[bench]] +name = "tcp_codec_perf" +harness = false diff --git a/lib/runtime/benches/tcp_codec_perf.rs b/lib/runtime/benches/tcp_codec_perf.rs new file mode 100644 index 000000000..91a869c9a --- /dev/null +++ b/lib/runtime/benches/tcp_codec_perf.rs @@ -0,0 +1,126 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Micro-benchmarks for TCP codec performance +//! +//! Run with: cargo bench --bench tcp_codec_perf + +use bytes::Bytes; +use criterion::{BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main}; +use dynamo_runtime::pipeline::network::codec::{TcpRequestMessage, TcpResponseMessage}; + +/// Benchmark request encoding (hot path operation) +fn bench_request_encoding(c: &mut Criterion) { + let mut group = c.benchmark_group("tcp_request_encoding"); + + // Test different payload sizes + for size in [102_400, 1_024_000, 31_000_000].iter() { + let payload = Bytes::from(vec![0u8; *size]); + let endpoint = "api.endpoint.test".to_string(); + + group.throughput(Throughput::Bytes(*size as u64)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, _| { + b.iter(|| { + let msg = TcpRequestMessage::new(endpoint.clone(), payload.clone()); + let encoded = msg.encode().unwrap(); + black_box(encoded); + }); + }); + } + + group.finish(); +} + +/// Benchmark response encoding +fn bench_response_encoding(c: &mut Criterion) { + let mut group = c.benchmark_group("tcp_response_encoding"); + + for size in [100, 1024, 10_240, 102_400].iter() { + let data = Bytes::from(vec![0u8; *size]); + + group.throughput(Throughput::Bytes(*size as u64)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, _| { + b.iter(|| { + let msg = TcpResponseMessage::new(data.clone()); + let encoded = msg.encode().unwrap(); + black_box(encoded); + }); + }); + } + + group.finish(); +} + +/// Benchmark request decoding +fn bench_request_decoding(c: &mut Criterion) { + let mut group = c.benchmark_group("tcp_request_decoding"); + + for size in [100, 1024, 10_240, 102_400].iter() { + let payload = Bytes::from(vec![0u8; *size]); + let msg = TcpRequestMessage::new("api.endpoint.test".to_string(), payload); + let encoded = msg.encode().unwrap(); + + group.throughput(Throughput::Bytes(*size as u64)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, _| { + b.iter(|| { + let decoded = TcpRequestMessage::decode(&encoded).unwrap(); + black_box(decoded); + }); + }); + } + + group.finish(); +} + +/// Benchmark response decoding +fn bench_response_decoding(c: &mut Criterion) { + let mut group = c.benchmark_group("tcp_response_decoding"); + + for size in [100, 1024, 10_240, 102_400].iter() { + let data = Bytes::from(vec![0u8; *size]); + let msg = TcpResponseMessage::new(data); + let encoded = msg.encode().unwrap(); + + group.throughput(Throughput::Bytes(*size as u64)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, _| { + b.iter(|| { + let decoded = TcpResponseMessage::decode(&encoded).unwrap(); + black_box(decoded); + }); + }); + } + + group.finish(); +} + +/// Benchmark full encode-decode cycle for requests +fn bench_request_roundtrip(c: &mut Criterion) { + let mut group = c.benchmark_group("tcp_request_roundtrip"); + + for size in [100, 1024, 10_240].iter() { + let payload = Bytes::from(vec![0u8; *size]); + let endpoint = "api.endpoint.test".to_string(); + + group.throughput(Throughput::Bytes(*size as u64)); + group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, _| { + b.iter(|| { + let msg = TcpRequestMessage::new(endpoint.clone(), payload.clone()); + let encoded = msg.encode().unwrap(); + let decoded = TcpRequestMessage::decode(&encoded).unwrap(); + black_box(decoded); + }); + }); + } + + group.finish(); +} + +criterion_group!( + benches, + bench_request_encoding, + bench_response_encoding, + bench_request_decoding, + bench_response_decoding, + bench_request_roundtrip, +); +criterion_main!(benches); diff --git a/lib/runtime/src/component.rs b/lib/runtime/src/component.rs index f560eb058..43c7683ff 100644 --- a/lib/runtime/src/component.rs +++ b/lib/runtime/src/component.rs @@ -32,7 +32,7 @@ use std::fmt; use crate::{ - config::HealthStatus, + config::{HealthStatus, RequestPlaneMode}, metrics::{MetricsHierarchy, MetricsRegistry, prometheus_names}, service::ServiceSet, transports::etcd::{ETCD_ROOT_PATH, EtcdPath}, @@ -78,18 +78,22 @@ pub const INSTANCE_ROOT_PATH: &str = "v1/instances"; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)] #[serde(rename_all = "snake_case")] pub enum TransportType { - NatsTcp(String), + #[serde(rename = "nats_tcp")] + Nats(String), + Http(String), + Tcp(String), } #[derive(Default)] pub struct RegistryInner { - services: HashMap, - stats_handlers: HashMap>>>, + pub(crate) services: HashMap, + pub(crate) stats_handlers: + HashMap>>>, } #[derive(Clone)] pub struct Registry { - inner: Arc>, + pub(crate) inner: Arc>, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] @@ -407,8 +411,25 @@ impl Component { } // Register metrics callback. CRITICAL: Never fail service creation for metrics issues. - if let Err(err) = self.start_scraping_nats_service_component_metrics() { - tracing::debug!(service_name, error = %err, "Metrics registration failed"); + // Only enable NATS service metrics collection when using NATS request plane mode + let request_plane_mode = RequestPlaneMode::get(); + match request_plane_mode { + RequestPlaneMode::Nats => { + if let Err(err) = self.start_scraping_nats_service_component_metrics() { + tracing::debug!( + "Metrics registration failed for '{}': {}", + self.service_name(), + err + ); + } + } + _ => { + tracing::info!( + "Skipping NATS service metrics collection for '{}' - request plane mode is '{}'", + self.service_name(), + request_plane_mode + ); + } } Ok(()) } diff --git a/lib/runtime/src/component/endpoint.rs b/lib/runtime/src/component/endpoint.rs index 6139a9852..ef659f6f2 100644 --- a/lib/runtime/src/component/endpoint.rs +++ b/lib/runtime/src/component/endpoint.rs @@ -12,6 +12,7 @@ use tokio_util::sync::CancellationToken; use crate::{ component::{Endpoint, Instance, TransportType, service::EndpointStatsHandler}, + config::RequestPlaneMode, pipeline::network::{PushWorkHandler, ingress::push_endpoint::PushEndpoint}, storage::key_value_store, traits::DistributedRuntimeProvider, @@ -87,8 +88,9 @@ impl EndpointConfigBuilder { let registry = endpoint.drt().component_registry().inner.lock().await; - // get the group - let group = registry + // Note: NATS service group is no longer needed here as the NetworkManager + // handles all transport-specific initialization internally + let _group = registry .services .get(&service_name) .map(|service| service.group(endpoint.component.service_name())) @@ -110,11 +112,12 @@ impl EndpointConfigBuilder { .insert(endpoint.subject_to(connection_id), stats_handler); } - // creates an endpoint for the service - let service_endpoint = group - .endpoint(&endpoint.name_with_id(connection_id)) - .await - .map_err(|e| anyhow::anyhow!("Failed to start endpoint: {e}"))?; + // Determine request plane mode + let request_plane_mode = RequestPlaneMode::get(); + tracing::info!( + "Endpoint starting with request plane mode: {:?}", + request_plane_mode + ); // This creates a child token of the runtime's endpoint_shutdown_token. That token is // cancelled first as part of graceful shutdown. See Runtime::shutdown. @@ -129,12 +132,20 @@ impl EndpointConfigBuilder { // Register health check target in SystemHealth if provided if let Some(health_check_payload) = &health_check_payload { + // Build transport based on request plane mode + let transport = build_transport_type( + request_plane_mode, + &endpoint_name, + &subject, + TransportContext::HealthCheck, + ); + let instance = Instance { component: component_name.clone(), endpoint: endpoint_name.clone(), namespace: namespace_name.clone(), instance_id: connection_id, - transport: TransportType::NatsTcp(subject.clone()), + transport, }; tracing::debug!(endpoint_name = %endpoint_name, "Registering endpoint health check target"); let guard = system_health.lock(); @@ -160,13 +171,7 @@ impl EndpointConfigBuilder { tracing::debug!("Endpoint '{}' has graceful_shutdown=false", endpoint.name); } - let push_endpoint = PushEndpoint::builder() - .service_handler(handler) - .cancellation_token(endpoint_shutdown_token.clone()) - .graceful_shutdown(graceful_shutdown) - .build() - .map_err(|e| anyhow::anyhow!("Failed to build push endpoint: {e}"))?; - + // Launch endpoint based on request plane mode let tracker_clone = if graceful_shutdown { Some(endpoint.drt().graceful_shutdown_tracker()) } else { @@ -178,25 +183,59 @@ impl EndpointConfigBuilder { let component_name_for_task = component_name.clone(); let endpoint_name_for_task = endpoint_name.clone(); - let task = tokio::spawn(async move { - let result = push_endpoint - .start( - service_endpoint, - namespace_name_for_task, - component_name_for_task, - endpoint_name_for_task, - connection_id, - system_health, - ) - .await; + // Get the unified request plane server (works for all transport types) + let server = endpoint.drt().request_plane_server().await?; + + tracing::info!( + endpoint = %endpoint_name_for_task, + transport = server.transport_name(), + "Registering endpoint with request plane server" + ); + + // Register endpoint with the server (unified interface) + server + .register_endpoint( + endpoint_name_for_task.clone(), + handler, + connection_id, + namespace_name_for_task.clone(), + component_name_for_task.clone(), + system_health.clone(), + ) + .await?; + + // Create cleanup task that unregisters on cancellation + let endpoint_name_for_cleanup = endpoint_name_for_task.clone(); + let server_for_cleanup = server.clone(); + let cancel_token_for_cleanup = endpoint_shutdown_token.clone(); + + let task: tokio::task::JoinHandle> = tokio::spawn(async move { + cancel_token_for_cleanup.cancelled().await; + + tracing::debug!( + endpoint = %endpoint_name_for_cleanup, + "Unregistering endpoint from request plane server" + ); + + // Unregister from server + if let Err(e) = server_for_cleanup + .unregister_endpoint(&endpoint_name_for_cleanup) + .await + { + tracing::warn!( + endpoint = %endpoint_name_for_cleanup, + error = %e, + "Failed to unregister endpoint" + ); + } // Unregister from graceful shutdown tracker if let Some(tracker) = tracker_clone { - tracing::debug!("Unregistering endpoint from graceful shutdown tracker"); + tracing::debug!("Unregister endpoint from graceful shutdown tracker"); tracker.unregister_endpoint(); } - result + anyhow::Ok(()) }); // Register this endpoint instance in the discovery plane @@ -204,11 +243,19 @@ impl EndpointConfigBuilder { // consistent registration/discovery across the system. let discovery = endpoint.drt().discovery(); + // Build transport for discovery service based on request plane mode + let transport = build_transport_type( + request_plane_mode, + &endpoint_name, + &subject, + TransportContext::Discovery, + ); + let discovery_spec = crate::discovery::DiscoverySpec::Endpoint { namespace: namespace_name.clone(), component: component_name.clone(), endpoint: endpoint_name.clone(), - transport: TransportType::NatsTcp(subject.clone()), + transport, }; if let Err(e) = discovery.register(discovery_spec).await { @@ -229,3 +276,66 @@ impl EndpointConfigBuilder { Ok(()) } } + +/// Context for building transport type - determines port and formatting differences +enum TransportContext { + /// For health check targets + HealthCheck, + /// For discovery service registration + Discovery, +} + +/// Build transport type based on request plane mode and context +/// +/// This unified function handles both health check and discovery transport building, +/// with context-specific differences: +/// - HTTP: Both use the same port (default 8888, configurable via DYN_HTTP_RPC_PORT) +/// - TCP: Health check omits endpoint suffix, discovery includes it for routing +/// - NATS: Identical for both contexts +fn build_transport_type( + mode: RequestPlaneMode, + endpoint_name: &str, + subject: &str, + context: TransportContext, +) -> TransportType { + match mode { + RequestPlaneMode::Http => { + let http_host = crate::utils::get_http_rpc_host_from_env(); + // Both health check and discovery use the same port (8888) where the HTTP server binds + let http_port = std::env::var("DYN_HTTP_RPC_PORT") + .ok() + .and_then(|p| p.parse::().ok()) + .unwrap_or(8888); + let rpc_root = + std::env::var("DYN_HTTP_RPC_ROOT_PATH").unwrap_or_else(|_| "/v1/rpc".to_string()); + + let http_endpoint = format!( + "http://{}:{}{}/{}", + http_host, http_port, rpc_root, endpoint_name + ); + + TransportType::Http(http_endpoint) + } + RequestPlaneMode::Tcp => { + let tcp_host = crate::utils::get_tcp_rpc_host_from_env(); + let tcp_port = std::env::var("DYN_TCP_RPC_PORT") + .ok() + .and_then(|p| p.parse::().ok()) + .unwrap_or(9999); + + let tcp_endpoint = match context { + TransportContext::HealthCheck => { + // Health check uses simple host:port format + format!("{}:{}", tcp_host, tcp_port) + } + TransportContext::Discovery => { + // Discovery includes endpoint name for routing + format!("{}:{}/{}", tcp_host, tcp_port, endpoint_name) + } + }; + + TransportType::Tcp(tcp_endpoint) + } + RequestPlaneMode::Nats => TransportType::Nats(subject.to_string()), + } +} diff --git a/lib/runtime/src/component/service.rs b/lib/runtime/src/component/service.rs index b12e0d866..ddfc0f0cf 100644 --- a/lib/runtime/src/component/service.rs +++ b/lib/runtime/src/component/service.rs @@ -1,6 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 +use super::*; +use crate::component::Component; +use crate::config::RequestPlaneMode; use async_nats::service::Service as NatsService; use async_nats::service::ServiceExt as _; use derive_builder::Builder; @@ -9,8 +12,6 @@ use parking_lot::Mutex; use std::collections::HashMap; use std::sync::Arc; -use crate::component::Component; - pub use super::endpoint::EndpointStats; type StatsHandlerRegistry = Arc>>; diff --git a/lib/runtime/src/config.rs b/lib/runtime/src/config.rs index bd4058a04..72ede9fa6 100644 --- a/lib/runtime/src/config.rs +++ b/lib/runtime/src/config.rs @@ -9,6 +9,7 @@ use figment::{ }; use serde::{Deserialize, Serialize}; use std::fmt; +use std::sync::OnceLock; use validator::Validate; /// Default system host for health and metrics endpoints @@ -468,6 +469,75 @@ pub fn use_local_timezone() -> bool { env_is_truthy("DYN_LOG_USE_LOCAL_TZ") } +/// Request plane transport mode configuration +/// +/// This determines how requests are distributed from routers to workers: +/// - `Nats`: Use NATS for request distribution (default, legacy) +/// - `Http`: Use HTTP/2 for request distribution +/// - `Tcp`: Use raw TCP for request distribution with msgpack support +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum RequestPlaneMode { + /// Use NATS for request plane (default for backward compatibility) + Nats, + /// Use HTTP/2 for request plane + Http, + /// Use raw TCP for request plane with msgpack support + Tcp, +} + +impl Default for RequestPlaneMode { + fn default() -> Self { + Self::Nats + } +} + +impl fmt::Display for RequestPlaneMode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Nats => write!(f, "nats"), + Self::Http => write!(f, "http"), + Self::Tcp => write!(f, "tcp"), + } + } +} + +impl std::str::FromStr for RequestPlaneMode { + type Err = anyhow::Error; + + fn from_str(s: &str) -> std::result::Result { + match s.to_lowercase().as_str() { + "nats" => Ok(Self::Nats), + "http" => Ok(Self::Http), + "tcp" => Ok(Self::Tcp), + _ => Err(anyhow::anyhow!( + "Invalid request plane mode: '{}'. Valid options are: 'nats', 'http', 'tcp'", + s + )), + } + } +} + +/// Global cached request plane mode +static REQUEST_PLANE_MODE: OnceLock = OnceLock::new(); + +impl RequestPlaneMode { + /// The cached request plane mode, initialized from `DYN_REQUEST_PLANE` environment variable + /// or defaulting to NATS if not set or invalid. + pub fn get() -> Self { + *REQUEST_PLANE_MODE.get_or_init(Self::from_env) + } + + /// Get the request plane mode from environment variable (uncached) + /// Reads from `DYN_REQUEST_PLANE` environment variable. + pub fn from_env() -> Self { + std::env::var("DYN_REQUEST_PLANE") + .ok() + .and_then(|s| s.parse().ok()) + .unwrap_or_default() + } +} + #[cfg(test)] mod tests { use super::*; @@ -671,4 +741,62 @@ mod tests { assert!(!env_is_falsey("TEST_MISSING")); }); } + + #[test] + fn test_request_plane_mode_from_str() { + assert_eq!( + "nats".parse::().unwrap(), + RequestPlaneMode::Nats + ); + assert_eq!( + "http".parse::().unwrap(), + RequestPlaneMode::Http + ); + assert_eq!( + "tcp".parse::().unwrap(), + RequestPlaneMode::Tcp + ); + assert_eq!( + "NATS".parse::().unwrap(), + RequestPlaneMode::Nats + ); + assert_eq!( + "HTTP".parse::().unwrap(), + RequestPlaneMode::Http + ); + assert_eq!( + "TCP".parse::().unwrap(), + RequestPlaneMode::Tcp + ); + assert!("invalid".parse::().is_err()); + } + + #[test] + fn test_request_plane_mode_display() { + assert_eq!(RequestPlaneMode::Nats.to_string(), "nats"); + assert_eq!(RequestPlaneMode::Http.to_string(), "http"); + assert_eq!(RequestPlaneMode::Tcp.to_string(), "tcp"); + } + + #[test] + fn test_request_plane_mode_default() { + assert_eq!(RequestPlaneMode::default(), RequestPlaneMode::Nats); + } + + #[test] + fn test_request_plane_mode_get_cached() { + // Test that get() returns a consistent value + let mode1 = RequestPlaneMode::get(); + let mode2 = RequestPlaneMode::get(); + assert_eq!(mode1, mode2, "Cached mode should be consistent"); + + // Verify it's one of the valid modes + assert!( + matches!( + mode1, + RequestPlaneMode::Nats | RequestPlaneMode::Http | RequestPlaneMode::Tcp + ), + "Mode should be a valid variant" + ); + } } diff --git a/lib/runtime/src/discovery/kv_store.rs b/lib/runtime/src/discovery/kv_store.rs index b599b211b..f62a8f0b6 100644 --- a/lib/runtime/src/discovery/kv_store.rs +++ b/lib/runtime/src/discovery/kv_store.rs @@ -403,7 +403,7 @@ mod tests { namespace: "test".to_string(), component: "comp1".to_string(), endpoint: "ep1".to_string(), - transport: TransportType::NatsTcp("nats://localhost:4222".to_string()), + transport: TransportType::Nats("nats://localhost:4222".to_string()), }; let instance = client.register(spec).await.unwrap(); @@ -429,7 +429,7 @@ mod tests { namespace: "ns1".to_string(), component: "comp1".to_string(), endpoint: "ep1".to_string(), - transport: TransportType::NatsTcp("nats://localhost:4222".to_string()), + transport: TransportType::Nats("nats://localhost:4222".to_string()), }; client.register(spec1).await.unwrap(); @@ -437,7 +437,7 @@ mod tests { namespace: "ns1".to_string(), component: "comp1".to_string(), endpoint: "ep2".to_string(), - transport: TransportType::NatsTcp("nats://localhost:4222".to_string()), + transport: TransportType::Nats("nats://localhost:4222".to_string()), }; client.register(spec2).await.unwrap(); @@ -445,7 +445,7 @@ mod tests { namespace: "ns2".to_string(), component: "comp2".to_string(), endpoint: "ep1".to_string(), - transport: TransportType::NatsTcp("nats://localhost:4222".to_string()), + transport: TransportType::Nats("nats://localhost:4222".to_string()), }; client.register(spec3).await.unwrap(); @@ -493,7 +493,7 @@ mod tests { namespace: "test".to_string(), component: "comp1".to_string(), endpoint: "ep1".to_string(), - transport: TransportType::NatsTcp("nats://localhost:4222".to_string()), + transport: TransportType::Nats("nats://localhost:4222".to_string()), }; client_clone.register(spec).await.unwrap(); }); diff --git a/lib/runtime/src/discovery/metadata.rs b/lib/runtime/src/discovery/metadata.rs index 86437383f..356efe5aa 100644 --- a/lib/runtime/src/discovery/metadata.rs +++ b/lib/runtime/src/discovery/metadata.rs @@ -234,7 +234,7 @@ mod tests { component: "comp1".to_string(), endpoint: "ep1".to_string(), instance_id: 123, - transport: TransportType::NatsTcp("nats://localhost:4222".to_string()), + transport: TransportType::Nats("nats://localhost:4222".to_string()), }); metadata.register_endpoint(instance).unwrap(); @@ -266,7 +266,7 @@ mod tests { component: "comp1".to_string(), endpoint: format!("ep{}", i), instance_id: i, - transport: TransportType::NatsTcp("nats://localhost:4222".to_string()), + transport: TransportType::Nats("nats://localhost:4222".to_string()), }); meta.register_endpoint(instance).unwrap(); }) @@ -294,7 +294,7 @@ mod tests { component: "comp1".to_string(), endpoint: format!("ep{}", i), instance_id: i, - transport: TransportType::NatsTcp("nats://localhost:4222".to_string()), + transport: TransportType::Nats("nats://localhost:4222".to_string()), }); metadata.register_endpoint(instance).unwrap(); } diff --git a/lib/runtime/src/discovery/mock.rs b/lib/runtime/src/discovery/mock.rs index 73719823d..588f260e6 100644 --- a/lib/runtime/src/discovery/mock.rs +++ b/lib/runtime/src/discovery/mock.rs @@ -218,7 +218,7 @@ mod tests { namespace: "test-ns".to_string(), component: "test-comp".to_string(), endpoint: "test-ep".to_string(), - transport: crate::component::TransportType::NatsTcp("test-subject".to_string()), + transport: crate::component::TransportType::Nats("test-subject".to_string()), }; let query = DiscoveryQuery::Endpoint { diff --git a/lib/runtime/src/distributed.rs b/lib/runtime/src/distributed.rs index 053601060..7f9ec72cd 100644 --- a/lib/runtime/src/distributed.rs +++ b/lib/runtime/src/distributed.rs @@ -42,11 +42,12 @@ pub struct DistributedRuntime { // local runtime runtime: Runtime, - // we might consider a unifed transport manager here + // Unified transport manager etcd_client: Option, nats_client: Option, store: KeyValueStoreManager, tcp_server: Arc>>, + network_manager: Arc>>, system_status_server: Arc>>, // Service discovery client @@ -174,6 +175,7 @@ impl DistributedRuntime { store, nats_client, tcp_server: Arc::new(OnceCell::new()), + network_manager: Arc::new(OnceCell::new()), system_status_server: Arc::new(OnceLock::new()), discovery_client, discovery_metadata, @@ -337,6 +339,72 @@ impl DistributedRuntime { .clone()) } + /// Get the network manager (lazy initialization) + /// + /// The network manager consolidates all network configuration and provides + /// unified access to request plane servers and clients. + pub async fn network_manager( + &self, + ) -> Result> { + use crate::pipeline::network::manager::NetworkManager; + + let manager = self + .network_manager + .get_or_try_init(async { + // Get NATS client if available + let nats_client = self.nats_client().map(|c| c.client().clone()); + + // NetworkManager handles all config reading and mode selection + anyhow::Ok(NetworkManager::new( + self.child_token(), + nats_client, + self.component_registry.clone(), + )) + }) + .await?; + + Ok(manager.clone()) + } + + /// Get the request plane server (convenience method) + /// + /// This is a shortcut for `network_manager().await?.server().await`. + pub async fn request_plane_server( + &self, + ) -> Result> + { + let manager = self.network_manager().await?; + manager.server().await + } + + /// DEPRECATED: Use network_manager().server() instead + #[deprecated(note = "Use request_plane_server() or network_manager().server() instead")] + pub async fn http_server( + &self, + ) -> Result> { + // For backward compatibility, try to downcast + let _server = self.request_plane_server().await?; + // This will only work if we're actually in HTTP mode + // For now, just return an error suggesting the new API + anyhow::bail!( + "http_server() is deprecated. Use request_plane_server() instead, which returns a trait object that works with all transport types." + ) + } + + /// DEPRECATED: Use network_manager().server() instead + #[deprecated(note = "Use request_plane_server() or network_manager().server() instead")] + pub async fn shared_tcp_server( + &self, + ) -> Result> { + // For backward compatibility, try to downcast + let _server = self.request_plane_server().await?; + // This will only work if we're actually in TCP mode + // For now, just return an error suggesting the new API + anyhow::bail!( + "shared_tcp_server() is deprecated. Use request_plane_server() instead, which returns a trait object that works with all transport types." + ) + } + pub fn nats_client(&self) -> Option<&nats::Client> { self.nats_client.as_ref() } diff --git a/lib/runtime/src/health_check.rs b/lib/runtime/src/health_check.rs index 6312dc3d2..18a1b671d 100644 --- a/lib/runtime/src/health_check.rs +++ b/lib/runtime/src/health_check.rs @@ -442,7 +442,7 @@ mod integration_tests { endpoint: "test_endpoint".to_string(), namespace: "test_namespace".to_string(), instance_id: 12345, - transport: crate::component::TransportType::NatsTcp(endpoint.to_string()), + transport: crate::component::TransportType::Nats(endpoint.to_string()), }, payload.clone(), ); @@ -477,7 +477,7 @@ mod integration_tests { endpoint: format!("test_endpoint_{}", i), namespace: "test_namespace".to_string(), instance_id: i, - transport: crate::component::TransportType::NatsTcp(endpoint.clone()), + transport: crate::component::TransportType::Nats(endpoint.clone()), }, payload, ); @@ -520,7 +520,7 @@ mod integration_tests { endpoint: "test_endpoint_notifier".to_string(), namespace: "test_namespace".to_string(), instance_id: 999, - transport: crate::component::TransportType::NatsTcp(endpoint.to_string()), + transport: crate::component::TransportType::Nats(endpoint.to_string()), }, payload.clone(), ); diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index f9bd82a84..415bc734a 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -6,6 +6,17 @@ #![allow(dead_code)] #![allow(unused_imports)] +use std::{ + collections::HashMap, + sync::{Arc, OnceLock, Weak}, +}; + +pub use anyhow::{ + Context as ErrorContext, Error, Ok as OK, Result, anyhow as error, bail as raise, +}; + +use async_once_cell::OnceCell; + pub mod config; pub use config::RuntimeConfig; @@ -41,3 +52,12 @@ pub use runtime::Runtime; pub use system_health::{HealthCheckTarget, SystemHealth}; pub use tokio_util::sync::CancellationToken; pub use worker::Worker; + +use crate::{ + metrics::prometheus_names::distributed_runtime, storage::key_value_store::KeyValueStore, +}; + +use component::Endpoint; +use utils::GracefulShutdownTracker; + +use config::HealthStatus; diff --git a/lib/runtime/src/logging.rs b/lib/runtime/src/logging.rs index a46b043eb..d779f0172 100644 --- a/lib/runtime/src/logging.rs +++ b/lib/runtime/src/logging.rs @@ -414,6 +414,30 @@ pub fn inject_current_trace_into_nats_headers(headers: &mut async_nats::HeaderMa inject_otel_context_into_nats_headers(headers, None); } +// Inject trace headers into a generic HashMap for HTTP/TCP transports +pub fn inject_trace_headers_into_map(headers: &mut std::collections::HashMap) { + if let Some(trace_context) = get_distributed_tracing_context() { + // Inject W3C traceparent header + headers.insert( + "traceparent".to_string(), + trace_context.create_traceparent(), + ); + + // Inject optional tracestate + if let Some(tracestate) = trace_context.tracestate { + headers.insert("tracestate".to_string(), tracestate); + } + + // Inject custom request IDs + if let Some(x_request_id) = trace_context.x_request_id { + headers.insert("x-request-id".to_string(), x_request_id); + } + if let Some(x_dynamo_request_id) = trace_context.x_dynamo_request_id { + headers.insert("x-dynamo-request-id".to_string(), x_dynamo_request_id); + } + } +} + /// Create a client_request span linked to the parent trace context pub fn make_client_request_span( operation: &str, diff --git a/lib/runtime/src/pipeline/network.rs b/lib/runtime/src/pipeline/network.rs index 2e8fd63be..d1f0bcb2b 100644 --- a/lib/runtime/src/pipeline/network.rs +++ b/lib/runtime/src/pipeline/network.rs @@ -1,11 +1,17 @@ // SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! TODO - we need to reconcile what is in this crate with distributed::transports +//! Network layer for distributed communication +//! +//! Provides request distribution across multiple transport protocols: +//! - HTTP/2 for standard deployments +//! - TCP with length-prefixed protocol for high-performance scenarios +//! - NATS for legacy/messaging-based deployments pub mod codec; pub mod egress; pub mod ingress; +pub mod manager; pub mod tcp; use crate::SystemHealth; diff --git a/lib/runtime/src/pipeline/network/codec.rs b/lib/runtime/src/pipeline/network/codec.rs index 34e2115b6..bded78f41 100644 --- a/lib/runtime/src/pipeline/network/codec.rs +++ b/lib/runtime/src/pipeline/network/codec.rs @@ -8,6 +8,7 @@ //! In this module, we define three primary codec used to issue single, two-part or multi-part messages, //! on a byte stream. +use bytes::Bytes; use tokio_util::{ bytes::{Buf, BufMut, BytesMut}, codec::{Decoder, Encoder}, @@ -17,50 +18,709 @@ mod two_part; pub use two_part::{TwoPartCodec, TwoPartMessage, TwoPartMessageType}; -// // Custom codec that reads a u64 length header and the message of that length -// #[derive(Default)] -// pub struct LengthPrefixedCodec; +/// TCP request plane protocol message with endpoint routing +/// +/// Wire format: +/// - endpoint_path_len: u16 (big-endian) +/// - endpoint_path: UTF-8 string +/// - payload_len: u32 (big-endian) +/// - payload: bytes +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TcpRequestMessage { + pub endpoint_path: String, + pub payload: Bytes, +} -// impl LengthPrefixedCodec { -// pub fn new() -> Self { -// LengthPrefixedCodec {} -// } -// } +impl TcpRequestMessage { + pub fn new(endpoint_path: String, payload: Bytes) -> Self { + Self { + endpoint_path, + payload, + } + } -// impl Decoder for LengthPrefixedCodec { -// type Item = Vec; -// type Error = tokio::io::Error; + /// Encode message to bytes + pub fn encode(&self) -> Result { + let endpoint_bytes = self.endpoint_path.as_bytes(); + let endpoint_len = endpoint_bytes.len(); -// fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { -// // Check if enough bytes are available to read the length (u64 = 8 bytes) -// if src.len() < 8 { -// return Ok(None); // Not enough data to read the length -// } + if endpoint_len > u16::MAX as usize { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!("Endpoint path too long: {} bytes", endpoint_len), + )); + } -// // Read the u64 length header -// let len = src.get_u64() as usize; + if self.payload.len() > u32::MAX as usize { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!("Payload too large: {} bytes", self.payload.len()), + )); + } -// // Check if enough bytes are available to read the full message -// if src.len() < len { -// src.reserve(len - src.len()); // Reserve space for the remaining bytes -// return Ok(None); -// } + // Use BytesMut for efficient buffer building + let mut buf = BytesMut::with_capacity(2 + endpoint_len + 4 + self.payload.len()); -// // Read the actual message bytes of the specified length -// let data = src.split_to(len).to_vec(); -// Ok(Some(data)) -// } -// } + // Write endpoint path length (2 bytes) + buf.put_u16(endpoint_len as u16); -// impl Encoder> for LengthPrefixedCodec { -// type Error = tokio::io::Error; + // Write endpoint path + buf.put_slice(endpoint_bytes); -// fn encode(&mut self, item: Vec, dst: &mut BytesMut) -> Result<(), Self::Error> { -// // Write the length of the message as a u64 header -// dst.put_u64(item.len() as u64); + // Write payload length (4 bytes) + buf.put_u32(self.payload.len() as u32); -// // Write the actual message bytes -// dst.put_slice(&item); -// Ok(()) -// } -// } + // Write payload + buf.put_slice(&self.payload); + + // Zero-copy conversion to Bytes + Ok(buf.freeze()) + } + + /// Decode message from bytes (for backward compatibility, zero-copy when possible) + pub fn decode(bytes: &Bytes) -> Result { + if bytes.len() < 2 { + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Not enough bytes for endpoint path length", + )); + } + + // Read endpoint path length (2 bytes) + let endpoint_len = u16::from_be_bytes([bytes[0], bytes[1]]) as usize; + let mut offset = 2; + + if bytes.len() < offset + endpoint_len { + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Not enough bytes for endpoint path", + )); + } + + // Read endpoint path (requires copy for UTF-8 validation) + let endpoint_path = String::from_utf8(bytes[offset..offset + endpoint_len].to_vec()) + .map_err(|e| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Invalid UTF-8: {}", e), + ) + })?; + offset += endpoint_len; + + if bytes.len() < offset + 4 { + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Not enough bytes for payload length", + )); + } + + // Read payload length (4 bytes) + let payload_len = u32::from_be_bytes([ + bytes[offset], + bytes[offset + 1], + bytes[offset + 2], + bytes[offset + 3], + ]) as usize; + offset += 4; + + if bytes.len() < offset + payload_len { + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + format!( + "Not enough bytes for payload: expected {}, got {}", + payload_len, + bytes.len() - offset + ), + )); + } + + // Read payload (zero-copy slice) + let payload = bytes.slice(offset..offset + payload_len); + + Ok(Self { + endpoint_path, + payload, + }) + } +} + +/// Codec for encoding/decoding TcpRequestMessage +/// Supports max_message_size enforcement +#[derive(Clone, Default)] +pub struct TcpRequestCodec { + max_message_size: Option, +} + +impl TcpRequestCodec { + pub fn new(max_message_size: Option) -> Self { + Self { max_message_size } + } +} + +impl Decoder for TcpRequestCodec { + type Item = TcpRequestMessage; + type Error = std::io::Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + // Need at least 2 bytes for endpoint_path_len + if src.len() < 2 { + return Ok(None); + } + + // Peek at endpoint path length without consuming + let endpoint_len = u16::from_be_bytes([src[0], src[1]]) as usize; + let header_size = 2 + endpoint_len + 4; // path_len + path + payload_len + + if src.len() < header_size { + return Ok(None); + } + + // Peek at payload length + let payload_len_offset = 2 + endpoint_len; + let payload_len = u32::from_be_bytes([ + src[payload_len_offset], + src[payload_len_offset + 1], + src[payload_len_offset + 2], + src[payload_len_offset + 3], + ]) as usize; + + let total_len = header_size + payload_len; + + // Check max message size + if let Some(max_size) = self.max_message_size + && total_len > max_size + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!( + "Request too large: {} bytes (max: {} bytes)", + total_len, max_size + ), + )); + } + + // Check if we have the full message + if src.len() < total_len { + return Ok(None); + } + + // We have a complete message, advance past length prefix + src.advance(2); + + // Read endpoint path + let endpoint_bytes = src.split_to(endpoint_len); + let endpoint_path = String::from_utf8(endpoint_bytes.to_vec()).map_err(|e| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Invalid UTF-8 in endpoint path: {}", e), + ) + })?; + + // Advance past payload length + src.advance(4); + + // Read payload + let payload = src.split_to(payload_len).freeze(); + + Ok(Some(TcpRequestMessage { + endpoint_path, + payload, + })) + } +} + +impl Encoder for TcpRequestCodec { + type Error = std::io::Error; + + fn encode(&mut self, item: TcpRequestMessage, dst: &mut BytesMut) -> Result<(), Self::Error> { + let endpoint_bytes = item.endpoint_path.as_bytes(); + let endpoint_len = endpoint_bytes.len(); + + if endpoint_len > u16::MAX as usize { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!("Endpoint path too long: {} bytes", endpoint_len), + )); + } + + if item.payload.len() > u32::MAX as usize { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!("Payload too large: {} bytes", item.payload.len()), + )); + } + + let total_len = 2 + endpoint_len + 4 + item.payload.len(); + + // Check max message size + if let Some(max_size) = self.max_message_size + && total_len > max_size + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!( + "Request too large: {} bytes (max: {} bytes)", + total_len, max_size + ), + )); + } + + // Reserve space + dst.reserve(total_len); + + // Write endpoint path length + dst.put_u16(endpoint_len as u16); + + // Write endpoint path + dst.put_slice(endpoint_bytes); + + // Write payload length + dst.put_u32(item.payload.len() as u32); + + // Write payload + dst.put_slice(&item.payload); + + Ok(()) + } +} + +/// TCP response message (acknowledgment or error) +/// +/// Wire format: +/// - length: u32 (big-endian) +/// - data: bytes +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TcpResponseMessage { + pub data: Bytes, +} + +impl TcpResponseMessage { + pub fn new(data: Bytes) -> Self { + Self { data } + } + + pub fn empty() -> Self { + Self { data: Bytes::new() } + } + + /// Encode response to bytes (for backward compatibility) + pub fn encode(&self) -> Result { + if self.data.len() > u32::MAX as usize { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!("Response too large: {} bytes", self.data.len()), + )); + } + + // Use BytesMut for efficient buffer building + let mut buf = BytesMut::with_capacity(4 + self.data.len()); + + // Write length (4 bytes) + buf.put_u32(self.data.len() as u32); + + // Write data + buf.put_slice(&self.data); + + // Zero-copy conversion to Bytes + Ok(buf.freeze()) + } + + /// Decode response from bytes (for backward compatibility, zero-copy when possible) + pub fn decode(bytes: &Bytes) -> Result { + if bytes.len() < 4 { + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Not enough bytes for response length", + )); + } + + // Read length (4 bytes) + let len = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize; + + if bytes.len() < 4 + len { + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + format!( + "Not enough bytes for response: expected {}, got {}", + len, + bytes.len() - 4 + ), + )); + } + + // Read data (zero-copy slice) + let data = bytes.slice(4..4 + len); + + Ok(Self { data }) + } +} + +/// Codec for encoding/decoding TcpResponseMessage +/// Supports max_message_size enforcement +#[derive(Clone, Default)] +pub struct TcpResponseCodec { + max_message_size: Option, +} + +impl TcpResponseCodec { + pub fn new(max_message_size: Option) -> Self { + Self { max_message_size } + } +} + +impl Decoder for TcpResponseCodec { + type Item = TcpResponseMessage; + type Error = std::io::Error; + + fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { + // Need at least 4 bytes for length + if src.len() < 4 { + return Ok(None); + } + + // Peek at message length without consuming + let data_len = u32::from_be_bytes([src[0], src[1], src[2], src[3]]) as usize; + let total_len = 4 + data_len; + + // Check max message size + if let Some(max_size) = self.max_message_size + && total_len > max_size + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!( + "Response too large: {} bytes (max: {} bytes)", + total_len, max_size + ), + )); + } + + // Check if we have the full message + if src.len() < total_len { + return Ok(None); + } + + // Advance past the length prefix + src.advance(4); + + // Read data + let data = src.split_to(data_len).freeze(); + + Ok(Some(TcpResponseMessage { data })) + } +} + +impl Encoder for TcpResponseCodec { + type Error = std::io::Error; + + fn encode(&mut self, item: TcpResponseMessage, dst: &mut BytesMut) -> Result<(), Self::Error> { + if item.data.len() > u32::MAX as usize { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!("Response too large: {} bytes", item.data.len()), + )); + } + + let total_len = 4 + item.data.len(); + + // Check max message size + if let Some(max_size) = self.max_message_size + && total_len > max_size + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + format!( + "Response too large: {} bytes (max: {} bytes)", + total_len, max_size + ), + )); + } + + // Reserve space + dst.reserve(total_len); + + // Write length + dst.put_u32(item.data.len() as u32); + + // Write data + dst.put_slice(&item.data); + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_tcp_request_encode_decode() { + let msg = TcpRequestMessage::new( + "test.endpoint".to_string(), + Bytes::from(vec![1, 2, 3, 4, 5]), + ); + + let encoded = msg.encode().unwrap(); + let decoded = TcpRequestMessage::decode(&encoded).unwrap(); + + assert_eq!(decoded, msg); + } + + #[test] + fn test_tcp_request_empty_payload() { + let msg = TcpRequestMessage::new("test".to_string(), Bytes::new()); + + let encoded = msg.encode().unwrap(); + let decoded = TcpRequestMessage::decode(&encoded).unwrap(); + + assert_eq!(decoded, msg); + } + + #[test] + fn test_tcp_request_large_payload() { + let payload = Bytes::from(vec![42u8; 1024 * 1024]); // 1MB + let msg = TcpRequestMessage::new("large".to_string(), payload); + + let encoded = msg.encode().unwrap(); + let decoded = TcpRequestMessage::decode(&encoded).unwrap(); + + assert_eq!(decoded, msg); + } + + #[test] + fn test_tcp_request_decode_truncated() { + let msg = TcpRequestMessage::new("test".to_string(), Bytes::from(vec![1, 2, 3, 4, 5])); + let encoded = msg.encode().unwrap(); + + // Truncate the encoded message + let truncated = encoded.slice(..encoded.len() - 2); + let result = TcpRequestMessage::decode(&truncated); + + assert!(result.is_err()); + } + + #[test] + fn test_tcp_response_encode_decode() { + let msg = TcpResponseMessage::new(Bytes::from(vec![1, 2, 3, 4, 5])); + + let encoded = msg.encode().unwrap(); + let decoded = TcpResponseMessage::decode(&encoded).unwrap(); + + assert_eq!(decoded, msg); + } + + #[test] + fn test_tcp_response_empty() { + let msg = TcpResponseMessage::empty(); + + let encoded = msg.encode().unwrap(); + let decoded = TcpResponseMessage::decode(&encoded).unwrap(); + + assert_eq!(decoded, msg); + assert_eq!(decoded.data.len(), 0); + } + + #[test] + fn test_tcp_response_decode_truncated() { + let msg = TcpResponseMessage::new(Bytes::from(vec![1, 2, 3, 4, 5])); + let encoded = msg.encode().unwrap(); + + // Truncate the encoded message + let truncated = encoded.slice(..3); + let result = TcpResponseMessage::decode(&truncated); + + assert!(result.is_err()); + } + + #[test] + fn test_tcp_request_unicode_endpoint() { + let msg = TcpRequestMessage::new("тест.端点".to_string(), Bytes::from(vec![1, 2, 3])); + + let encoded = msg.encode().unwrap(); + let decoded = TcpRequestMessage::decode(&encoded).unwrap(); + + assert_eq!(decoded, msg); + } + + #[test] + fn test_tcp_request_codec() { + use tokio_util::codec::{Decoder, Encoder}; + + let msg = TcpRequestMessage::new( + "test.endpoint".to_string(), + Bytes::from(vec![1, 2, 3, 4, 5]), + ); + + let mut codec = TcpRequestCodec::new(None); + let mut buf = BytesMut::new(); + + // Encode + codec.encode(msg.clone(), &mut buf).unwrap(); + + // Decode + let decoded = codec.decode(&mut buf).unwrap().unwrap(); + assert_eq!(decoded, msg); + } + + #[test] + fn test_tcp_request_codec_partial() { + use tokio_util::codec::Decoder; + + let msg = TcpRequestMessage::new( + "test.endpoint".to_string(), + Bytes::from(vec![1, 2, 3, 4, 5]), + ); + + let encoded = msg.encode().unwrap(); + let mut codec = TcpRequestCodec::new(None); + + // Feed partial data + let mut buf = BytesMut::from(&encoded[..5]); + assert!(codec.decode(&mut buf).unwrap().is_none()); + + // Feed rest of data + buf.extend_from_slice(&encoded[5..]); + let decoded = codec.decode(&mut buf).unwrap().unwrap(); + assert_eq!(decoded, msg); + } + + #[test] + fn test_tcp_request_codec_max_size() { + use tokio_util::codec::Encoder; + + let msg = TcpRequestMessage::new("test".to_string(), Bytes::from(vec![1, 2, 3, 4, 5])); + + let mut codec = TcpRequestCodec::new(Some(10)); // Too small + let mut buf = BytesMut::new(); + + let result = codec.encode(msg, &mut buf); + assert!(result.is_err()); + } + + #[test] + fn test_tcp_response_codec() { + use tokio_util::codec::{Decoder, Encoder}; + + let msg = TcpResponseMessage::new(Bytes::from(vec![1, 2, 3, 4, 5])); + + let mut codec = TcpResponseCodec::new(None); + let mut buf = BytesMut::new(); + + // Encode + codec.encode(msg.clone(), &mut buf).unwrap(); + + // Decode + let decoded = codec.decode(&mut buf).unwrap().unwrap(); + assert_eq!(decoded, msg); + } + + #[test] + fn test_tcp_response_codec_partial() { + use tokio_util::codec::Decoder; + + let msg = TcpResponseMessage::new(Bytes::from(vec![1, 2, 3, 4, 5])); + + let encoded = msg.encode().unwrap(); + let mut codec = TcpResponseCodec::new(None); + + // Feed partial data + let mut buf = BytesMut::from(&encoded[..3]); + assert!(codec.decode(&mut buf).unwrap().is_none()); + + // Feed rest of data + buf.extend_from_slice(&encoded[3..]); + let decoded = codec.decode(&mut buf).unwrap().unwrap(); + assert_eq!(decoded, msg); + } + + #[test] + fn test_tcp_response_codec_max_size() { + use tokio_util::codec::Encoder; + + let msg = TcpResponseMessage::new(Bytes::from(vec![1, 2, 3, 4, 5])); + + let mut codec = TcpResponseCodec::new(Some(5)); // Too small + let mut buf = BytesMut::new(); + + let result = codec.encode(msg, &mut buf); + assert!(result.is_err()); + } + + /// Demonstrates how framed codec enables testability without actual TCP connections + #[tokio::test] + async fn test_framed_codec_integration() { + use futures::{SinkExt, StreamExt}; + use std::io::Cursor; + use tokio_util::codec::{FramedRead, FramedWrite}; + + // Simulate a duplex connection using in-memory buffer + let mut buffer = Vec::new(); + + // Writer side: encode requests + { + let cursor = Cursor::new(&mut buffer); + let mut writer = FramedWrite::new(cursor, TcpRequestCodec::new(None)); + + let msg1 = TcpRequestMessage::new("endpoint1".to_string(), Bytes::from("data1")); + let msg2 = TcpRequestMessage::new("endpoint2".to_string(), Bytes::from("data2")); + + writer.send(msg1).await.unwrap(); + writer.send(msg2).await.unwrap(); + } + + // Reader side: decode requests + { + let cursor = Cursor::new(&buffer[..]); + let mut reader = FramedRead::new(cursor, TcpRequestCodec::new(None)); + + let decoded1 = reader.next().await.unwrap().unwrap(); + assert_eq!(decoded1.endpoint_path, "endpoint1"); + assert_eq!(decoded1.payload, Bytes::from("data1")); + + let decoded2 = reader.next().await.unwrap().unwrap(); + assert_eq!(decoded2.endpoint_path, "endpoint2"); + assert_eq!(decoded2.payload, Bytes::from("data2")); + } + } + + /// Demonstrates testing partial message handling + #[tokio::test] + async fn test_framed_codec_partial_messages() { + use futures::StreamExt; + use std::io::Cursor; + use tokio_util::codec::FramedRead; + + // Create a message and encode it + let msg = TcpRequestMessage::new("test".to_string(), Bytes::from("hello")); + let encoded = msg.encode().unwrap(); + + // Split the encoded message into chunks + let chunk1 = &encoded[..5]; + let chunk2 = &encoded[5..]; + + // Create a buffer that simulates receiving data in chunks + let mut full_buffer = Vec::new(); + full_buffer.extend_from_slice(chunk1); + + // Reader can't decode yet (partial data) + { + let cursor = Cursor::new(&full_buffer[..]); + let _reader = FramedRead::new(cursor, TcpRequestCodec::new(None)); + // In real async, this would return Ok(None) and wait for more data + // For Cursor, it returns None at EOF + } + + // Add the rest of the data + full_buffer.extend_from_slice(chunk2); + + // Now decoding succeeds + { + let cursor = Cursor::new(&full_buffer[..]); + let mut reader = FramedRead::new(cursor, TcpRequestCodec::new(None)); + + let decoded = reader.next().await.unwrap().unwrap(); + assert_eq!(decoded.endpoint_path, "test"); + assert_eq!(decoded.payload, Bytes::from("hello")); + } + } +} diff --git a/lib/runtime/src/pipeline/network/egress.rs b/lib/runtime/src/pipeline/network/egress.rs index fccb91d0f..42e078ff3 100644 --- a/lib/runtime/src/pipeline/network/egress.rs +++ b/lib/runtime/src/pipeline/network/egress.rs @@ -2,6 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 pub mod addressed_router; +pub mod http_router; +pub mod nats_client; pub mod push_router; +// Unified request plane interface and implementations +pub mod tcp_client; +pub mod unified_client; + use super::*; diff --git a/lib/runtime/src/pipeline/network/egress/addressed_router.rs b/lib/runtime/src/pipeline/network/egress/addressed_router.rs index e5fa67ad6..08d145603 100644 --- a/lib/runtime/src/pipeline/network/egress/addressed_router.rs +++ b/lib/runtime/src/pipeline/network/egress/addressed_router.rs @@ -3,14 +3,13 @@ use std::sync::Arc; +use super::unified_client::RequestPlaneClient; +use super::*; use crate::engine::{AsyncEngine, AsyncEngineContextProvider, Data}; -use crate::logging::DistributedTraceContext; -use crate::logging::get_distributed_tracing_context; -use crate::logging::inject_otel_context_into_nats_headers; +use crate::logging::inject_trace_headers_into_map; use crate::pipeline::network::ConnectionInfo; use crate::pipeline::network::NetworkStreamWrapper; use crate::pipeline::network::PendingConnections; -use crate::pipeline::network::ResponseService; use crate::pipeline::network::STREAM_ERR_MSG; use crate::pipeline::network::StreamOptions; use crate::pipeline::network::TwoPartCodec; @@ -20,8 +19,6 @@ use crate::pipeline::{ManyOut, PipelineError, ResponseStream, SingleIn}; use crate::protocols::maybe_error::MaybeError; use anyhow::{Error, Result}; -use async_nats::client::Client; -use async_nats::{HeaderMap, HeaderValue}; use serde::Deserialize; use serde::Serialize; use tokio_stream::{StreamExt, StreamNotifyClose, wrappers::ReceiverStream}; @@ -59,26 +56,30 @@ impl AddressedRequest { Self { request, address } } - fn into_parts(self) -> (T, String) { + pub(crate) fn into_parts(self) -> (T, String) { (self.request, self.address) } } pub struct AddressedPushRouter { - // todo: generalize with a generic - req_transport: Client, + // Request transport (unified trait object - works with all transports) + req_client: Arc, - // todo: generalize with a generic + // Response transport (TCP streaming - unchanged) resp_transport: Arc, } impl AddressedPushRouter { + /// Create a new router with a request plane client + /// + /// This is the unified constructor that works with any transport type. + /// The client is provided as a trait object, hiding the specific implementation. pub fn new( - req_transport: Client, + req_client: Arc, resp_transport: Arc, ) -> Result> { Ok(Arc::new(Self { - req_transport, + req_client, resp_transport, })) } @@ -154,32 +155,22 @@ where // TRANSPORT ABSTRACT REQUIRED - END HERE - tracing::trace!(request_id, "enqueueing two-part message to nats"); + // Send request using unified client interface + tracing::trace!( + request_id, + transport = self.req_client.transport_name(), + address = %address, + "Sending request via request plane client" + ); - // Insert Trace Context into Headers - // Enables span to be created in push_endpoint before - // payload is parsed + // Prepare trace headers using shared helper + let mut headers = std::collections::HashMap::new(); + inject_trace_headers_into_map(&mut headers); - // Prepare trace headers using the OpenTelemetry injector pattern - // This handles traceparent and tracestate headers according to W3C Trace Context standard - let mut headers = HeaderMap::new(); - inject_otel_context_into_nats_headers(&mut headers, None); - - // Add additional custom headers that aren't handled by the OpenTelemetry propagator - if let Some(trace_context) = get_distributed_tracing_context() { - if let Some(x_request_id) = trace_context.x_request_id { - headers.insert("x-request-id", x_request_id); - } - if let Some(x_dynamo_request_id) = trace_context.x_dynamo_request_id { - headers.insert("x-dynamo-request-id", x_dynamo_request_id); - } - } - - // we might need to add a timeout on this if there is no subscriber to the subject; however, I think nats - // will handle this for us + // Send request (works for all transport types) let _response = self - .req_transport - .request_with_headers(address.to_string(), headers, buffer) + .req_client + .send_request(address, buffer, headers) .await?; tracing::trace!(request_id, "awaiting transport handshake"); diff --git a/lib/runtime/src/pipeline/network/egress/http_router.rs b/lib/runtime/src/pipeline/network/egress/http_router.rs new file mode 100644 index 000000000..b7e4d390a --- /dev/null +++ b/lib/runtime/src/pipeline/network/egress/http_router.rs @@ -0,0 +1,694 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! HTTP/2 client for request plane + +use super::unified_client::{Headers, RequestPlaneClient}; +use crate::Result; +use async_trait::async_trait; +use bytes::Bytes; +use std::sync::Arc; +use std::time::Duration; + +/// Default timeout for HTTP requests (ack only, not full response) +const DEFAULT_HTTP_REQUEST_TIMEOUT_SECS: u64 = 5; + +/// HTTP/2 Performance Configuration Constants +const DEFAULT_MAX_FRAME_SIZE: u32 = 1024 * 1024; // 1MB frame size for better throughput +const DEFAULT_MAX_CONCURRENT_STREAMS: u32 = 1000; // Allow more concurrent streams +const DEFAULT_POOL_MAX_IDLE_PER_HOST: usize = 100; // Increased connection pool +const DEFAULT_POOL_IDLE_TIMEOUT_SECS: u64 = 90; // Keep connections alive longer +const DEFAULT_HTTP2_KEEP_ALIVE_INTERVAL_SECS: u64 = 30; // Send pings every 30s +const DEFAULT_HTTP2_KEEP_ALIVE_TIMEOUT_SECS: u64 = 10; // Timeout for ping responses +const DEFAULT_HTTP2_ADAPTIVE_WINDOW: bool = true; // Enable adaptive flow control + +/// HTTP/2 Performance Configuration +#[derive(Debug, Clone)] +pub struct Http2Config { + pub max_frame_size: u32, + pub max_concurrent_streams: u32, + pub pool_max_idle_per_host: usize, + pub pool_idle_timeout: Duration, + pub keep_alive_interval: Duration, + pub keep_alive_timeout: Duration, + pub adaptive_window: bool, + pub request_timeout: Duration, +} + +impl Default for Http2Config { + fn default() -> Self { + Self { + max_frame_size: DEFAULT_MAX_FRAME_SIZE, + max_concurrent_streams: DEFAULT_MAX_CONCURRENT_STREAMS, + pool_max_idle_per_host: DEFAULT_POOL_MAX_IDLE_PER_HOST, + pool_idle_timeout: Duration::from_secs(DEFAULT_POOL_IDLE_TIMEOUT_SECS), + keep_alive_interval: Duration::from_secs(DEFAULT_HTTP2_KEEP_ALIVE_INTERVAL_SECS), + keep_alive_timeout: Duration::from_secs(DEFAULT_HTTP2_KEEP_ALIVE_TIMEOUT_SECS), + adaptive_window: DEFAULT_HTTP2_ADAPTIVE_WINDOW, + request_timeout: Duration::from_secs(DEFAULT_HTTP_REQUEST_TIMEOUT_SECS), + } + } +} + +impl Http2Config { + /// Create configuration from environment variables + pub fn from_env() -> Self { + let mut config = Self::default(); + + if let Ok(val) = std::env::var("DYN_HTTP2_MAX_FRAME_SIZE") + && let Ok(size) = val.parse::() + { + config.max_frame_size = size; + } + + if let Ok(val) = std::env::var("DYN_HTTP2_MAX_CONCURRENT_STREAMS") + && let Ok(streams) = val.parse::() + { + config.max_concurrent_streams = streams; + } + + if let Ok(val) = std::env::var("DYN_HTTP2_POOL_MAX_IDLE_PER_HOST") + && let Ok(pool_size) = val.parse::() + { + config.pool_max_idle_per_host = pool_size; + } + + if let Ok(val) = std::env::var("DYN_HTTP2_POOL_IDLE_TIMEOUT_SECS") + && let Ok(timeout) = val.parse::() + { + config.pool_idle_timeout = Duration::from_secs(timeout); + } + + if let Ok(val) = std::env::var("DYN_HTTP2_KEEP_ALIVE_INTERVAL_SECS") + && let Ok(interval) = val.parse::() + { + config.keep_alive_interval = Duration::from_secs(interval); + } + + if let Ok(val) = std::env::var("DYN_HTTP2_KEEP_ALIVE_TIMEOUT_SECS") + && let Ok(timeout) = val.parse::() + { + config.keep_alive_timeout = Duration::from_secs(timeout); + } + + if let Ok(val) = std::env::var("DYN_HTTP2_ADAPTIVE_WINDOW") { + config.adaptive_window = val.parse().unwrap_or(DEFAULT_HTTP2_ADAPTIVE_WINDOW); + } + + if let Ok(val) = std::env::var("DYN_HTTP_REQUEST_TIMEOUT") + && let Ok(timeout) = val.parse::() + { + config.request_timeout = Duration::from_secs(timeout); + } + + config + } +} + +/// HTTP/2 request plane client +pub struct HttpRequestClient { + client: reqwest::Client, + config: Http2Config, +} + +impl HttpRequestClient { + /// Create a new HTTP request client with HTTP/2 and default configuration + pub fn new() -> Result { + Self::with_config(Http2Config::default()) + } + + /// Create a new HTTP request client with custom timeout (legacy method) + /// Uses HTTP/2 with prior knowledge to avoid ALPN negotiation overhead + pub fn with_timeout(timeout: Duration) -> Result { + let config = Http2Config { + request_timeout: timeout, + ..Http2Config::default() + }; + Self::with_config(config) + } + + /// Create a new HTTP request client with basic configuration + /// + /// Note: Advanced HTTP/2 configuration methods may not be available in all versions of reqwest. + /// This implementation uses only the stable, widely-supported configuration options. + pub fn with_config(config: Http2Config) -> Result { + let builder = reqwest::Client::builder() + .pool_max_idle_per_host(config.pool_max_idle_per_host) + .pool_idle_timeout(config.pool_idle_timeout) + .timeout(config.request_timeout); + // HTTP/2 is automatically negotiated by reqwest when available + + let client = builder.build()?; + + Ok(Self { client, config }) + } + + /// Create from environment configuration + pub fn from_env() -> Result { + Self::with_config(Http2Config::from_env()) + } + + /// Get the current HTTP/2 configuration + pub fn config(&self) -> &Http2Config { + &self.config + } +} + +impl Default for HttpRequestClient { + fn default() -> Self { + Self::new().expect("Failed to create HTTP request client") + } +} + +#[async_trait] +impl RequestPlaneClient for HttpRequestClient { + async fn send_request( + &self, + address: String, + payload: Bytes, + headers: Headers, + ) -> Result { + let mut req = self + .client + .post(&address) + .header("Content-Type", "application/octet-stream") + .body(payload); + + // Add custom headers + for (key, value) in headers { + req = req.header(key, value); + } + + let response = req.send().await?; + + if !response.status().is_success() { + anyhow::bail!( + "HTTP request failed with status {}: {}", + response.status(), + response.text().await.unwrap_or_default() + ); + } + + let body = response.bytes().await?; + Ok(body) + } + + fn transport_name(&self) -> &'static str { + "http2" + } + + fn is_healthy(&self) -> bool { + // HTTP client is stateless and always healthy if created successfully + true + } +} + +#[cfg(test)] +mod tests { + use super::*; + use axum::{Router, body::Bytes as AxumBytes, extract::State as AxumState, routing::post}; + use std::sync::Arc; + use tokio::sync::Mutex as TokioMutex; + + #[test] + fn test_http_client_creation() { + let client = HttpRequestClient::new(); + assert!(client.is_ok()); + } + + #[test] + fn test_http_client_with_custom_timeout() { + let client = HttpRequestClient::with_timeout(Duration::from_secs(10)); + assert!(client.is_ok()); + assert_eq!( + client.unwrap().config.request_timeout, + Duration::from_secs(10) + ); + } + + #[test] + fn test_http2_config_from_env() { + // Set environment variables + unsafe { + std::env::set_var("DYN_HTTP2_MAX_FRAME_SIZE", "2097152"); // 2MB + std::env::set_var("DYN_HTTP2_MAX_CONCURRENT_STREAMS", "2000"); + std::env::set_var("DYN_HTTP2_POOL_MAX_IDLE_PER_HOST", "200"); + std::env::set_var("DYN_HTTP2_KEEP_ALIVE_INTERVAL_SECS", "60"); + std::env::set_var("DYN_HTTP2_ADAPTIVE_WINDOW", "false"); + } + + let config = Http2Config::from_env(); + + assert_eq!(config.max_frame_size, 2097152); + assert_eq!(config.max_concurrent_streams, 2000); + assert_eq!(config.pool_max_idle_per_host, 200); + assert_eq!(config.keep_alive_interval, Duration::from_secs(60)); + assert!(!config.adaptive_window); + + // Clean up + unsafe { + std::env::remove_var("DYN_HTTP2_MAX_FRAME_SIZE"); + std::env::remove_var("DYN_HTTP2_MAX_CONCURRENT_STREAMS"); + std::env::remove_var("DYN_HTTP2_POOL_MAX_IDLE_PER_HOST"); + std::env::remove_var("DYN_HTTP2_KEEP_ALIVE_INTERVAL_SECS"); + std::env::remove_var("DYN_HTTP2_ADAPTIVE_WINDOW"); + } + } + + #[test] + fn test_http_client_with_custom_config() { + let config = Http2Config { + max_frame_size: 512 * 1024, // 512KB + max_concurrent_streams: 500, + pool_max_idle_per_host: 75, + pool_idle_timeout: Duration::from_secs(60), + keep_alive_interval: Duration::from_secs(45), + keep_alive_timeout: Duration::from_secs(15), + adaptive_window: false, + request_timeout: Duration::from_secs(8), + }; + + let client = HttpRequestClient::with_config(config.clone()); + assert!(client.is_ok()); + + let client = client.unwrap(); + assert_eq!(client.config.max_frame_size, 512 * 1024); + assert_eq!(client.config.max_concurrent_streams, 500); + assert_eq!(client.config.pool_max_idle_per_host, 75); + assert_eq!(client.config.request_timeout, Duration::from_secs(8)); + } + + #[tokio::test] + async fn test_http_client_send_request_invalid_url() { + let client = HttpRequestClient::new().unwrap(); + let result = client + .send_request( + "http://invalid-host-that-does-not-exist:9999/test".to_string(), + Bytes::from("test"), + std::collections::HashMap::new(), + ) + .await; + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_http2_client_server_integration() { + use hyper_util::rt::{TokioExecutor, TokioIo}; + use hyper_util::server::conn::auto::Builder as ConnBuilder; + use hyper_util::service::TowerToHyperService; + + // Create a test server that accepts HTTP/2 + #[derive(Clone)] + struct TestState { + received: Arc>>, + protocol_version: Arc>>, + } + + async fn test_handler( + AxumState(state): AxumState, + body: AxumBytes, + ) -> &'static str { + state.received.lock().await.push(body); + "OK" + } + + let state = TestState { + received: Arc::new(TokioMutex::new(Vec::new())), + protocol_version: Arc::new(TokioMutex::new(None)), + }; + + let app = Router::new() + .route("/test", post(test_handler)) + .with_state(state.clone()); + + // Bind to a random port + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + + // Start HTTP/2 server + let server_handle = tokio::spawn(async move { + loop { + let Ok((stream, _)) = listener.accept().await else { + break; + }; + + let app = app.clone(); + tokio::spawn(async move { + let conn_builder = ConnBuilder::new(TokioExecutor::new()); + let io = TokioIo::new(stream); + let tower_service = app.into_service(); + let hyper_service = TowerToHyperService::new(tower_service); + + let _ = conn_builder.serve_connection(io, hyper_service).await; + }); + } + }); + + // Give server time to start + tokio::time::sleep(Duration::from_millis(100)).await; + + // Create HTTP/2 client with prior knowledge + let client = HttpRequestClient::new().unwrap(); + + // Send request + let test_data = Bytes::from("test_payload"); + let result = client + .send_request( + format!("http://{}/test", addr), + test_data.clone(), + std::collections::HashMap::new(), + ) + .await; + + // Verify request succeeded + assert!(result.is_ok(), "Request failed: {:?}", result.err()); + + // Verify server received the data + tokio::time::sleep(Duration::from_millis(100)).await; + let received = state.received.lock().await; + assert_eq!(received.len(), 1); + assert_eq!(received[0], test_data); + + // Cleanup + server_handle.abort(); + } + + #[tokio::test] + async fn test_http2_headers_propagation() { + use hyper_util::rt::{TokioExecutor, TokioIo}; + use hyper_util::server::conn::auto::Builder as ConnBuilder; + use hyper_util::service::TowerToHyperService; + + // Create a test server that captures headers + #[derive(Clone)] + struct HeaderState { + headers: Arc>>, + } + + async fn header_handler( + AxumState(state): AxumState, + headers: axum::http::HeaderMap, + ) -> &'static str { + let mut captured = state.headers.lock().await; + for (name, value) in headers.iter() { + if let Ok(val_str) = value.to_str() { + captured.push((name.to_string(), val_str.to_string())); + } + } + "OK" + } + + let state = HeaderState { + headers: Arc::new(TokioMutex::new(Vec::new())), + }; + + let app = Router::new() + .route("/test", post(header_handler)) + .with_state(state.clone()); + + // Bind to a random port + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + + // Start HTTP/2 server + let server_handle = tokio::spawn(async move { + loop { + let Ok((stream, _)) = listener.accept().await else { + break; + }; + + let app = app.clone(); + tokio::spawn(async move { + let conn_builder = ConnBuilder::new(TokioExecutor::new()); + let io = TokioIo::new(stream); + let tower_service = app.into_service(); + let hyper_service = TowerToHyperService::new(tower_service); + + let _ = conn_builder.serve_connection(io, hyper_service).await; + }); + } + }); + + // Give server time to start + tokio::time::sleep(Duration::from_millis(100)).await; + + // Create HTTP/2 client + let client = HttpRequestClient::new().unwrap(); + + // Send request with custom headers + let mut headers = std::collections::HashMap::new(); + headers.insert("x-test-header".to_string(), "test-value".to_string()); + headers.insert("x-request-id".to_string(), "req-123".to_string()); + + let result = client + .send_request( + format!("http://{}/test", addr), + Bytes::from("test"), + headers, + ) + .await; + + // Verify request succeeded + assert!(result.is_ok()); + + // Verify headers were received + tokio::time::sleep(Duration::from_millis(100)).await; + let received_headers = state.headers.lock().await; + + let header_map: std::collections::HashMap<_, _> = received_headers + .iter() + .map(|(k, v)| (k.as_str(), v.as_str())) + .collect(); + + assert!(header_map.contains_key("x-test-header")); + assert_eq!(header_map.get("x-test-header"), Some(&"test-value")); + assert!(header_map.contains_key("x-request-id")); + assert_eq!(header_map.get("x-request-id"), Some(&"req-123")); + + // Cleanup + server_handle.abort(); + } + + #[tokio::test] + async fn test_http2_concurrent_requests() { + use hyper_util::rt::{TokioExecutor, TokioIo}; + use hyper_util::server::conn::auto::Builder as ConnBuilder; + use hyper_util::service::TowerToHyperService; + use std::sync::atomic::{AtomicU64, Ordering}; + + // Create a test server that counts requests + #[derive(Clone)] + struct CounterState { + count: Arc, + } + + async fn counter_handler(AxumState(state): AxumState) -> String { + let count = state.count.fetch_add(1, Ordering::SeqCst); + format!("{}", count) + } + + let state = CounterState { + count: Arc::new(AtomicU64::new(0)), + }; + + let app = Router::new() + .route("/test", post(counter_handler)) + .with_state(state.clone()); + + // Bind to a random port + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + + // Start HTTP/2 server + let server_handle = tokio::spawn(async move { + loop { + let Ok((stream, _)) = listener.accept().await else { + break; + }; + + let app = app.clone(); + tokio::spawn(async move { + let conn_builder = ConnBuilder::new(TokioExecutor::new()); + let io = TokioIo::new(stream); + let tower_service = app.into_service(); + let hyper_service = TowerToHyperService::new(tower_service); + + let _ = conn_builder.serve_connection(io, hyper_service).await; + }); + } + }); + + // Give server time to start + tokio::time::sleep(Duration::from_millis(100)).await; + + // Create HTTP/2 client + let client = Arc::new(HttpRequestClient::new().unwrap()); + + // Send multiple concurrent requests (HTTP/2 multiplexing) + let mut handles = vec![]; + for _ in 0..10 { + let client = client.clone(); + let handle = tokio::spawn(async move { + client + .send_request( + format!("http://{}/test", addr), + Bytes::from("test"), + std::collections::HashMap::new(), + ) + .await + }); + handles.push(handle); + } + + // Wait for all requests to complete + let mut success_count = 0; + for handle in handles { + if let Ok(Ok(_)) = handle.await { + success_count += 1; + } + } + + // Verify all requests succeeded + assert_eq!(success_count, 10); + + // Verify server received all requests + assert_eq!(state.count.load(Ordering::SeqCst), 10); + + // Cleanup + server_handle.abort(); + } + + #[tokio::test] + async fn test_http2_performance_benchmark() { + use hyper_util::rt::{TokioExecutor, TokioIo}; + use hyper_util::server::conn::auto::Builder as ConnBuilder; + use hyper_util::service::TowerToHyperService; + use std::sync::atomic::{AtomicU64, Ordering}; + use std::time::Instant; + + // Create a test server that measures performance + #[derive(Clone)] + struct PerfState { + request_count: Arc, + total_bytes: Arc, + } + + async fn perf_handler( + AxumState(state): AxumState, + body: AxumBytes, + ) -> &'static str { + state.request_count.fetch_add(1, Ordering::Relaxed); + state + .total_bytes + .fetch_add(body.len() as u64, Ordering::Relaxed); + "OK" + } + + let state = PerfState { + request_count: Arc::new(AtomicU64::new(0)), + total_bytes: Arc::new(AtomicU64::new(0)), + }; + + let app = Router::new() + .route("/perf", post(perf_handler)) + .with_state(state.clone()); + + // Bind to a random port + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + + // Start HTTP/2 server + let server_handle = tokio::spawn(async move { + loop { + let Ok((stream, _)) = listener.accept().await else { + break; + }; + + let app = app.clone(); + tokio::spawn(async move { + let conn_builder = ConnBuilder::new(TokioExecutor::new()); + let io = TokioIo::new(stream); + let tower_service = app.into_service(); + let hyper_service = TowerToHyperService::new(tower_service); + + let _ = conn_builder.serve_connection(io, hyper_service).await; + }); + } + }); + + // Give server time to start + tokio::time::sleep(Duration::from_millis(100)).await; + + // Create optimized HTTP/2 client + let optimized_config = Http2Config { + max_frame_size: 1024 * 1024, // 1MB frames + max_concurrent_streams: 1000, + pool_max_idle_per_host: 100, + pool_idle_timeout: Duration::from_secs(90), + keep_alive_interval: Duration::from_secs(30), + keep_alive_timeout: Duration::from_secs(10), + adaptive_window: true, + request_timeout: Duration::from_secs(30), + }; + + let client = Arc::new(HttpRequestClient::with_config(optimized_config).unwrap()); + + // Performance test: Send many concurrent requests + let num_requests = 100; + let payload_size = 64 * 1024; // 64KB payload + let payload = Bytes::from(vec![0u8; payload_size]); + + let start_time = Instant::now(); + let mut handles = vec![]; + + for _ in 0..num_requests { + let client = client.clone(); + let payload = payload.clone(); + + let handle = tokio::spawn(async move { + let headers = std::collections::HashMap::new(); + client + .send_request(format!("http://{}/perf", addr), payload, headers) + .await + }); + handles.push(handle); + } + + // Wait for all requests to complete + let mut successful_requests = 0; + for handle in handles { + if handle.await.unwrap().is_ok() { + successful_requests += 1; + } + } + + let elapsed = start_time.elapsed(); + let requests_per_sec = successful_requests as f64 / elapsed.as_secs_f64(); + let throughput_mbps = + (successful_requests * payload_size) as f64 / elapsed.as_secs_f64() / (1024.0 * 1024.0); + + println!("Performance Results:"); + println!( + " Successful requests: {}/{}", + successful_requests, num_requests + ); + println!(" Total time: {:?}", elapsed); + println!(" Requests/sec: {:.2}", requests_per_sec); + println!(" Throughput: {:.2} MB/s", throughput_mbps); + + // Verify server received all requests + let server_count = state.request_count.load(Ordering::Relaxed); + let server_bytes = state.total_bytes.load(Ordering::Relaxed); + + assert_eq!(server_count, successful_requests as u64); + assert_eq!(server_bytes, (successful_requests * payload_size) as u64); + + // Performance assertions (adjust based on your requirements) + assert!(successful_requests >= num_requests * 95 / 100); // At least 95% success rate + assert!(requests_per_sec > 50.0); // At least 50 requests per second + assert!(throughput_mbps > 10.0); // At least 10 MB/s throughput + + // Cleanup + server_handle.abort(); + } +} diff --git a/lib/runtime/src/pipeline/network/egress/nats_client.rs b/lib/runtime/src/pipeline/network/egress/nats_client.rs new file mode 100644 index 000000000..a1a708ee5 --- /dev/null +++ b/lib/runtime/src/pipeline/network/egress/nats_client.rs @@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! NATS Request Plane Client +//! +//! Wraps the NATS client to implement the unified RequestPlaneClient trait, +//! providing a consistent interface across all transport types. + +use super::unified_client::{ClientStats, Headers, RequestPlaneClient}; +use anyhow::Result; +use async_trait::async_trait; +use bytes::Bytes; + +/// NATS implementation of RequestPlaneClient +/// +/// This client wraps the async_nats::Client and adapts it to the +/// unified RequestPlaneClient interface. +pub struct NatsRequestClient { + client: async_nats::Client, +} + +impl NatsRequestClient { + /// Create a new NATS request client + /// + /// # Arguments + /// + /// * `client` - The underlying NATS client + pub fn new(client: async_nats::Client) -> Self { + Self { client } + } +} + +#[async_trait] +impl RequestPlaneClient for NatsRequestClient { + async fn send_request( + &self, + address: String, + payload: Bytes, + headers: Headers, + ) -> Result { + // Convert generic headers to NATS headers + let mut nats_headers = async_nats::HeaderMap::new(); + for (key, value) in headers { + nats_headers.insert(key.as_str(), value.as_str()); + } + + // Send request with headers + let response = self + .client + .request_with_headers(address, nats_headers, payload) + .await + .map_err(|e| anyhow::anyhow!("NATS request failed: {}", e))?; + + Ok(response.payload) + } + + fn transport_name(&self) -> &'static str { + "nats" + } + + fn is_healthy(&self) -> bool { + // Check if NATS client is connected + // NATS client doesn't expose connection state directly, assume healthy + true + } + + fn stats(&self) -> ClientStats { + // NATS client doesn't expose detailed stats + // Return basic health indicator + ClientStats { + requests_sent: 0, + responses_received: 0, + errors: 0, + bytes_sent: 0, + bytes_received: 0, + active_connections: if self.is_healthy() { 1 } else { 0 }, + idle_connections: 0, + avg_latency_us: 0, + } + } + + async fn close(&self) -> Result<()> { + // NATS client doesn't have an explicit close method + // Connection is managed by the client lifecycle + Ok(()) + } +} diff --git a/lib/runtime/src/pipeline/network/egress/push_router.rs b/lib/runtime/src/pipeline/network/egress/push_router.rs index 55ab51d4b..a8cf32654 100644 --- a/lib/runtime/src/pipeline/network/egress/push_router.rs +++ b/lib/runtime/src/pipeline/network/egress/push_router.rs @@ -89,13 +89,17 @@ impl RouterMode { } async fn addressed_router(endpoint: &Endpoint) -> anyhow::Result> { - let Some(nats_client) = endpoint.drt().nats_client() else { - anyhow::bail!("Missing NATS. Please ensure it is running and accessible."); - }; - AddressedPushRouter::new( - nats_client.client().clone(), - endpoint.drt().tcp_server().await?, - ) + // Get network manager and create client (no mode checks!) + let manager = endpoint.drt().network_manager().await?; + let req_client = manager.create_client()?; + let resp_transport = endpoint.drt().tcp_server().await?; + + tracing::debug!( + transport = req_client.transport_name(), + "Creating AddressedPushRouter with request plane client" + ); + + AddressedPushRouter::new(req_client, resp_transport) } impl PushRouter @@ -224,8 +228,48 @@ where } } - let subject = self.client.endpoint.subject_to(instance_id); - let request = request.map(|req| AddressedRequest::new(req, subject)); + // Get the address based on discovered transport type + let address = { + use crate::component::TransportType; + + // Get the instance and use its actual transport type + let instances = self.client.instances(); + let instance = instances + .iter() + .find(|i| i.instance_id == instance_id) + .ok_or_else(|| { + anyhow::anyhow!("Instance {} not found in available instances", instance_id) + })?; + + match &instance.transport { + TransportType::Http(http_endpoint) => { + tracing::debug!( + instance_id = instance_id, + http_endpoint = %http_endpoint, + "Using HTTP transport for instance" + ); + http_endpoint.clone() + } + TransportType::Tcp(tcp_endpoint) => { + tracing::debug!( + instance_id = instance_id, + tcp_endpoint = %tcp_endpoint, + "Using TCP transport for instance" + ); + tcp_endpoint.clone() + } + TransportType::Nats(subject) => { + tracing::debug!( + instance_id = instance_id, + subject = %subject, + "Using NATS transport for instance" + ); + subject.clone() + } + } + }; + + let request = request.map(|req| AddressedRequest::new(req, address)); let stream: anyhow::Result> = self.addressed.generate(request).await; match stream { diff --git a/lib/runtime/src/pipeline/network/egress/queue.rs b/lib/runtime/src/pipeline/network/egress/queue.rs deleted file mode 100644 index 1fa0b8c65..000000000 --- a/lib/runtime/src/pipeline/network/egress/queue.rs +++ /dev/null @@ -1,2 +0,0 @@ -// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 diff --git a/lib/runtime/src/pipeline/network/egress/tcp_client.rs b/lib/runtime/src/pipeline/network/egress/tcp_client.rs new file mode 100644 index 000000000..d84f8cbb6 --- /dev/null +++ b/lib/runtime/src/pipeline/network/egress/tcp_client.rs @@ -0,0 +1,918 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! TCP Request Plane Client +//! + +use super::unified_client::{ClientStats, Headers, RequestPlaneClient}; +use anyhow::Result; +use async_trait::async_trait; +use bytes::Bytes; +use dashmap::DashMap; +use futures::StreamExt; +use std::io::IoSlice; +use std::net::SocketAddr; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::time::Duration; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::TcpStream; +use tokio::sync::{Mutex, mpsc, oneshot}; +use tokio::task::JoinHandle; +use tokio_util::codec::FramedRead; + +/// Default timeout for TCP request acknowledgment +const DEFAULT_TCP_REQUEST_TIMEOUT_SECS: u64 = 5; + +/// Default connection pool size per host +const DEFAULT_POOL_SIZE: usize = 100; + +/// Buffer size for request channel per connection (backpressure control) +const REQUEST_CHANNEL_BUFFER: usize = 50; + +/// Pre-allocated read buffer size (64KB typical message size) +const READ_BUFFER_SIZE: usize = 65536; + +/// Default maximum message size for TCP client (32 MB) +/// This is the limit for a SINGLE message. For larger data, split into multiple messages. +const DEFAULT_MAX_MESSAGE_SIZE: usize = 32 * 1024 * 1024; + +/// Get maximum message size from environment or use default +fn get_max_message_size() -> usize { + std::env::var("DYN_TCP_MAX_MESSAGE_SIZE") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(DEFAULT_MAX_MESSAGE_SIZE) +} + +/// TCP request plane configuration +#[derive(Debug, Clone)] +pub struct TcpRequestConfig { + /// Request timeout + pub request_timeout: Duration, + /// Maximum connections per host + pub pool_size: usize, + /// Connect timeout + pub connect_timeout: Duration, + /// Request channel buffer size + pub channel_buffer: usize, +} + +impl Default for TcpRequestConfig { + fn default() -> Self { + Self { + request_timeout: Duration::from_secs(DEFAULT_TCP_REQUEST_TIMEOUT_SECS), + pool_size: DEFAULT_POOL_SIZE, + connect_timeout: Duration::from_secs(5), + channel_buffer: REQUEST_CHANNEL_BUFFER, + } + } +} + +impl TcpRequestConfig { + /// Create configuration from environment variables + pub fn from_env() -> Self { + let mut config = Self::default(); + + if let Ok(val) = std::env::var("DYN_TCP_REQUEST_TIMEOUT") + && let Ok(timeout) = val.parse::() + { + config.request_timeout = Duration::from_secs(timeout); + } + + if let Ok(val) = std::env::var("DYN_TCP_POOL_SIZE") + && let Ok(size) = val.parse::() + { + config.pool_size = size; + } + + if let Ok(val) = std::env::var("DYN_TCP_CONNECT_TIMEOUT") + && let Ok(timeout) = val.parse::() + { + config.connect_timeout = Duration::from_secs(timeout); + } + + if let Ok(val) = std::env::var("DYN_TCP_CHANNEL_BUFFER") + && let Ok(size) = val.parse::() + { + config.channel_buffer = size; + } + + config + } +} + +/// Request to be sent over TCP +/// Pre-encoded on caller's thread for optimal write performance (hot path optimization) +struct TcpRequest { + /// Pre-encoded request data ready to send (zero-copy Bytes) + /// Encoding happens on caller thread to parallelize across multiple request handlers + encoded_data: Bytes, + /// Oneshot channel to send response back to caller + response_tx: oneshot::Sender>, +} + +/// TCP connection with split read/write tasks +/// +/// Design: One writer task + one reader task per connection +/// - Writer task receives pre-encoded requests and writes directly (hot path optimized) +/// - Reader task uses framed codec for robust protocol handling +/// - FIFO ordering ensures request/response correlation without explicit IDs +/// +/// Performance: Hybrid approach optimizes each path independently: +/// - Write path: Pre-encode on caller thread → direct write (minimal overhead, parallel encoding) +/// - Read path: Framed codec handles partial reads and protocol complexity automatically +struct TcpConnection { + addr: SocketAddr, + /// Channel to send requests to the writer task + request_tx: mpsc::Sender, + /// Writer task handle for cleanup + writer_handle: Arc>, + /// Reader task handle for cleanup + reader_handle: Arc>, + /// Health status (false if tasks have failed) + healthy: Arc, +} + +impl TcpConnection { + /// Create a new connection with split read/write tasks + async fn connect(addr: SocketAddr, timeout: Duration, channel_buffer: usize) -> Result { + let stream = tokio::time::timeout(timeout, TcpStream::connect(addr)) + .await + .map_err(|_| anyhow::anyhow!("TCP connect timeout to {}", addr))??; + + // Configure socket for lower latency + Self::configure_socket(&stream)?; + + let (read_half, write_half) = tokio::io::split(stream); + + // Channel for writer task to receive requests + let (request_tx, request_rx) = mpsc::channel::(channel_buffer); + + // Channel for writer to forward response channels to reader (FIFO correlation) + let (response_tx_channel, response_rx_channel) = + mpsc::unbounded_channel::>>(); + + let healthy = Arc::new(AtomicBool::new(true)); + + // Spawn writer task + let writer_handle = { + let healthy = healthy.clone(); + tokio::spawn(async move { + if let Err(e) = Self::writer_task(write_half, request_rx, response_tx_channel).await + { + tracing::debug!("Writer task failed for {}: {}", addr, e); + healthy.store(false, Ordering::Relaxed); + } + }) + }; + + // Spawn reader task + let reader_handle = { + let healthy = healthy.clone(); + tokio::spawn(async move { + if let Err(e) = Self::reader_task(read_half, response_rx_channel).await { + tracing::debug!("Reader task failed for {}: {}", addr, e); + healthy.store(false, Ordering::Relaxed); + } + }) + }; + + Ok(Self { + addr, + request_tx, + writer_handle: Arc::new(writer_handle), + reader_handle: Arc::new(reader_handle), + healthy, + }) + } + + /// Configure socket for ultra-low latency based on dyn-transports patterns + fn configure_socket(stream: &TcpStream) -> Result<()> { + use socket2::{SockRef, Socket}; + + let sock_ref = SockRef::from(stream); + + // TCP_NODELAY - disable Nagle's algorithm for immediate send + sock_ref.set_nodelay(true)?; + + // Increase socket buffer sizes for better throughput under load + sock_ref.set_recv_buffer_size(2 * 1024 * 1024)?; // 2MB + sock_ref.set_send_buffer_size(2 * 1024 * 1024)?; // 2MB + + // Advanced Linux optimizations for ultra-low latency (optional feature) + #[cfg(feature = "tcp-low-latency")] + { + use std::os::unix::io::AsRawFd; + + unsafe { + let fd = stream.as_raw_fd(); + + // TCP_QUICKACK - minimize ACK delay + let quickack: libc::c_int = 1; + libc::setsockopt( + fd, + libc::SOL_TCP, + libc::TCP_QUICKACK, + &quickack as *const _ as *const libc::c_void, + std::mem::size_of_val(&quickack) as libc::socklen_t, + ); + + // SO_BUSY_POLL - enable busy polling for lower latency (50 microseconds) + let busy_poll: libc::c_int = 50; + libc::setsockopt( + fd, + libc::SOL_SOCKET, + libc::SO_BUSY_POLL, + &busy_poll as *const _ as *const libc::c_void, + std::mem::size_of_val(&busy_poll) as libc::socklen_t, + ); + } + + tracing::debug!("TCP low-latency optimizations enabled (TCP_QUICKACK, SO_BUSY_POLL)"); + } + + Ok(()) + } + + /// Writer task: receives pre-encoded requests and writes directly to socket + /// + /// Performance optimization: Pre-encoding happens on caller's thread to enable + /// parallel encoding across multiple request handlers, while this task focuses + /// on sequential socket writes with minimal overhead. + async fn writer_task( + mut write_half: tokio::io::WriteHalf, + mut request_rx: mpsc::Receiver, + response_tx_channel: mpsc::UnboundedSender>>, + ) -> Result<()> { + while let Some(req) = request_rx.recv().await { + // Direct write of pre-encoded data (hot path) + // With TCP_NODELAY, no need for explicit flush() + match write_half.write_all(&req.encoded_data).await { + Ok(()) => { + // Forward response channel to reader task (FIFO ordering) + if response_tx_channel.send(req.response_tx).is_err() { + tracing::debug!("Reader task closed, stopping writer"); + break; + } + } + Err(e) => { + // Write failed, notify caller and stop + let err_msg = format!("Write failed: {}", e); + let _ = req.response_tx.send(Err(anyhow::anyhow!("{}", err_msg))); + return Err(anyhow::anyhow!("{}", err_msg)); + } + } + } + Ok(()) + } + + /// Reader task: reads responses using framed codec and sends them back via oneshot channels + /// Protocol framing handled automatically via TcpResponseCodec + async fn reader_task( + read_half: tokio::io::ReadHalf, + mut response_rx_channel: mpsc::UnboundedReceiver>>, + ) -> Result<()> { + use crate::pipeline::network::codec::TcpResponseCodec; + + let max_message_size = get_max_message_size(); + let codec = TcpResponseCodec::new(Some(max_message_size)); + let mut framed = FramedRead::new(read_half, codec); + + while let Some(response_tx) = response_rx_channel.recv().await { + // Read the next response message from the framed stream + // The codec handles all protocol framing and size checks automatically + match framed.next().await { + Some(Ok(response_msg)) => { + let _ = response_tx.send(Ok(response_msg.data)); + } + Some(Err(e)) => { + let err = anyhow::anyhow!("Failed to decode response: {}", e); + let _ = response_tx.send(Err(err)); + return Err(anyhow::anyhow!("Failed to decode response")); + } + None => { + let err = anyhow::anyhow!("Connection closed by peer"); + let _ = response_tx.send(Err(err)); + return Err(anyhow::anyhow!("Connection closed")); + } + } + } + + Ok(()) + } + + /// Send a request and wait for response + /// + /// Performance: Encoding happens on caller's thread (hot path optimization) + /// to enable parallel encoding across multiple request handlers. The writer + /// task then performs sequential writes with minimal overhead. + async fn send_request(&self, payload: Bytes, headers: &Headers) -> Result { + use crate::pipeline::network::codec::TcpRequestMessage; + + // Check health before sending + if !self.healthy.load(Ordering::Relaxed) { + anyhow::bail!("Connection unhealthy (tasks failed)"); + } + + // Extract endpoint path from headers (required for routing) + let endpoint_path = headers + .get("x-endpoint-path") + .ok_or_else(|| anyhow::anyhow!("Missing x-endpoint-path header for TCP request"))? + .to_string(); + + // Encode request on caller's thread (hot path optimization) + // This allows multiple concurrent callers to encode in parallel + // rather than serializing through the writer task + let request_msg = TcpRequestMessage::new(endpoint_path, payload); + let encoded_data = request_msg.encode()?; + + // Create response channel + let (response_tx, response_rx) = oneshot::channel(); + + // Send to writer task (bounded channel provides backpressure) + let req = TcpRequest { + encoded_data, + response_tx, + }; + + self.request_tx + .send(req) + .await + .map_err(|_| anyhow::anyhow!("Writer task closed"))?; + + // Wait for response from reader task + response_rx + .await + .map_err(|_| anyhow::anyhow!("Reader task closed"))? + } + + /// Check if connection is healthy + fn is_healthy(&self) -> bool { + self.healthy.load(Ordering::Relaxed) + } +} + +/// Connection pool with health checking for TCP connections +struct TcpConnectionPool { + pools: DashMap>>>, + config: TcpRequestConfig, +} + +impl TcpConnectionPool { + fn new(config: TcpRequestConfig) -> Self { + Self { + pools: DashMap::new(), + config, + } + } + + /// Get a connection from the pool or create a new one + /// Automatically filters out unhealthy connections + async fn get_connection(&self, addr: SocketAddr) -> Result { + // Try to get from pool (lock-free read with DashMap) + if let Some(pool) = self.pools.get(&addr) { + let mut pool = pool.lock().await; + + // Try to get a healthy connection, discard unhealthy ones + while let Some(conn) = pool.pop() { + if conn.is_healthy() { + return Ok(conn); + } else { + tracing::debug!("Discarding unhealthy connection for {}", addr); + // Connection will be dropped here, cleaning up tasks + } + } + } + + // Create new connection with configured channel buffer + tracing::debug!("Creating new TCP connection to {}", addr); + TcpConnection::connect( + addr, + self.config.connect_timeout, + self.config.channel_buffer, + ) + .await + } + + /// Return a connection to the pool if it's healthy and there's space + async fn return_connection(&self, conn: TcpConnection) { + // Only return healthy connections + if !conn.is_healthy() { + tracing::debug!("Not returning unhealthy connection to pool"); + return; + } + + let addr = conn.addr; + + // Get or create pool for this address (lock-free with DashMap) + let pool = self + .pools + .entry(addr) + .or_insert_with(|| Arc::new(Mutex::new(Vec::new()))) + .clone(); + + let mut pool = pool.lock().await; + if pool.len() < self.config.pool_size { + pool.push(conn); + } else { + tracing::debug!("Connection pool full for {}, dropping connection", addr); + // Otherwise drop the connection (tasks will be cleaned up) + } + } +} + +/// TCP request plane client +pub struct TcpRequestClient { + pool: Arc, + config: TcpRequestConfig, + stats: Arc, +} + +struct TcpClientStats { + requests_sent: AtomicU64, + responses_received: AtomicU64, + errors: AtomicU64, + bytes_sent: AtomicU64, + bytes_received: AtomicU64, +} + +impl TcpRequestClient { + /// Create a new TCP request client with default configuration + pub fn new() -> Result { + Self::with_config(TcpRequestConfig::default()) + } + + /// Create a new TCP request client with custom configuration + pub fn with_config(config: TcpRequestConfig) -> Result { + Ok(Self { + pool: Arc::new(TcpConnectionPool::new(config.clone())), + config, + stats: Arc::new(TcpClientStats { + requests_sent: AtomicU64::new(0), + responses_received: AtomicU64::new(0), + errors: AtomicU64::new(0), + bytes_sent: AtomicU64::new(0), + bytes_received: AtomicU64::new(0), + }), + }) + } + + /// Create from environment configuration + pub fn from_env() -> Result { + Self::with_config(TcpRequestConfig::from_env()) + } + + /// Parse TCP address from string + /// Supports formats: "host:port" or "tcp://host:port" or "host:port/endpoint_name" + /// Returns (SocketAddr, Option) + fn parse_address(address: &str) -> Result<(SocketAddr, Option)> { + let addr_str = if let Some(stripped) = address.strip_prefix("tcp://") { + stripped + } else { + address + }; + + // Check if endpoint name is included (format: host:port/endpoint_name) + if let Some((socket_part, endpoint_name)) = addr_str.split_once('/') { + let socket_addr = socket_part + .parse::() + .map_err(|e| anyhow::anyhow!("Invalid TCP address '{}': {}", address, e))?; + Ok((socket_addr, Some(endpoint_name.to_string()))) + } else { + let socket_addr = addr_str + .parse::() + .map_err(|e| anyhow::anyhow!("Invalid TCP address '{}': {}", address, e))?; + Ok((socket_addr, None)) + } + } +} + +impl Default for TcpRequestClient { + fn default() -> Self { + Self::new().expect("Failed to create TCP request client") + } +} + +#[async_trait] +impl RequestPlaneClient for TcpRequestClient { + async fn send_request( + &self, + address: String, + payload: Bytes, + mut headers: Headers, + ) -> Result { + tracing::debug!("TCP client sending request to address: {}", address); + self.stats.requests_sent.fetch_add(1, Ordering::Relaxed); + self.stats + .bytes_sent + .fetch_add(payload.len() as u64, Ordering::Relaxed); + + let (addr, endpoint_name) = Self::parse_address(&address)?; + + // Add endpoint path to headers if present in address + if let Some(endpoint_name) = endpoint_name { + headers.insert("x-endpoint-path".to_string(), endpoint_name.clone()); + } + + // Get connection from pool (automatically filters unhealthy connections) + let conn = self.pool.get_connection(addr).await?; + + // Send request with timeout + // Note: The connection's send_request now handles all the async I/O via tasks + let result = tokio::time::timeout( + self.config.request_timeout, + conn.send_request(payload, &headers), + ) + .await; + + match result { + Ok(Ok(response)) => { + self.stats + .responses_received + .fetch_add(1, Ordering::Relaxed); + self.stats + .bytes_received + .fetch_add(response.len() as u64, Ordering::Relaxed); + + // Return connection to pool (health check happens inside) + self.pool.return_connection(conn).await; + + Ok(response) + } + Ok(Err(e)) => { + self.stats.errors.fetch_add(1, Ordering::Relaxed); + tracing::warn!("TCP request failed to {}: {}", addr, e); + // Don't return unhealthy connection to pool, let it drop + Err(e) + } + Err(_) => { + self.stats.errors.fetch_add(1, Ordering::Relaxed); + tracing::warn!("TCP request timeout to {}", addr); + // Don't return timed-out connection to pool + Err(anyhow::anyhow!("TCP request timeout to {}", addr)) + } + } + } + + fn transport_name(&self) -> &'static str { + "tcp" + } + + fn is_healthy(&self) -> bool { + true // TCP client is always healthy if it was created successfully + } + + fn stats(&self) -> ClientStats { + ClientStats { + requests_sent: self.stats.requests_sent.load(Ordering::Relaxed), + responses_received: self.stats.responses_received.load(Ordering::Relaxed), + errors: self.stats.errors.load(Ordering::Relaxed), + bytes_sent: self.stats.bytes_sent.load(Ordering::Relaxed), + bytes_received: self.stats.bytes_received.load(Ordering::Relaxed), + active_connections: 0, // Could track this if needed + idle_connections: 0, + avg_latency_us: 0, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::atomic::AtomicUsize; + use tokio::net::TcpListener; + + #[test] + fn test_tcp_config_default() { + let config = TcpRequestConfig::default(); + assert_eq!(config.pool_size, DEFAULT_POOL_SIZE); + assert_eq!( + config.request_timeout, + Duration::from_secs(DEFAULT_TCP_REQUEST_TIMEOUT_SECS) + ); + assert_eq!(config.channel_buffer, REQUEST_CHANNEL_BUFFER); + } + + #[test] + fn test_tcp_config_from_env() { + unsafe { + std::env::set_var("DYN_TCP_REQUEST_TIMEOUT", "10"); + std::env::set_var("DYN_TCP_POOL_SIZE", "50"); + std::env::set_var("DYN_TCP_CONNECT_TIMEOUT", "3"); + std::env::set_var("DYN_TCP_CHANNEL_BUFFER", "100"); + } + + let config = TcpRequestConfig::from_env(); + assert_eq!(config.request_timeout, Duration::from_secs(10)); + assert_eq!(config.pool_size, 50); + assert_eq!(config.connect_timeout, Duration::from_secs(3)); + assert_eq!(config.channel_buffer, 100); + + // Clean up env vars + unsafe { + std::env::remove_var("DYN_TCP_REQUEST_TIMEOUT"); + std::env::remove_var("DYN_TCP_POOL_SIZE"); + std::env::remove_var("DYN_TCP_CONNECT_TIMEOUT"); + std::env::remove_var("DYN_TCP_CHANNEL_BUFFER"); + } + } + + #[test] + fn test_parse_address() { + let (addr1, _) = TcpRequestClient::parse_address("127.0.0.1:8080").unwrap(); + assert_eq!(addr1.port(), 8080); + + let (addr2, _) = TcpRequestClient::parse_address("tcp://127.0.0.1:9090").unwrap(); + assert_eq!(addr2.port(), 9090); + + let (addr3, endpoint) = + TcpRequestClient::parse_address("127.0.0.1:8080/test_endpoint").unwrap(); + assert_eq!(addr3.port(), 8080); + assert_eq!(endpoint, Some("test_endpoint".to_string())); + + assert!(TcpRequestClient::parse_address("invalid").is_err()); + } + + #[test] + fn test_tcp_client_creation() { + let client = TcpRequestClient::new(); + assert!(client.is_ok()); + + let client = client.unwrap(); + assert_eq!(client.transport_name(), "tcp"); + assert!(client.is_healthy()); + } + + #[tokio::test] + async fn test_connection_health_check() { + use crate::pipeline::network::codec::{TcpRequestMessage, TcpResponseMessage}; + + // Start a mock TCP server + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + + // Spawn server that responds to requests + tokio::spawn(async move { + let (stream, _) = listener.accept().await.unwrap(); + let (mut read_half, mut write_half) = tokio::io::split(stream); + + // Read request + let mut len_buf = [0u8; 2]; + read_half.read_exact(&mut len_buf).await.unwrap(); + let path_len = u16::from_be_bytes(len_buf) as usize; + + let mut path_buf = vec![0u8; path_len]; + read_half.read_exact(&mut path_buf).await.unwrap(); + + let mut len_buf = [0u8; 4]; + read_half.read_exact(&mut len_buf).await.unwrap(); + let payload_len = u32::from_be_bytes(len_buf) as usize; + + let mut payload_buf = vec![0u8; payload_len]; + read_half.read_exact(&mut payload_buf).await.unwrap(); + + // Send response + let response = TcpResponseMessage::new(Bytes::from_static(b"pong")); + let encoded = response.encode().unwrap(); + write_half.write_all(&encoded).await.unwrap(); + }); + + // Create connection + let conn = TcpConnection::connect(addr, Duration::from_secs(5), 10) + .await + .unwrap(); + + assert!(conn.is_healthy(), "New connection should be healthy"); + + // Send a request + let mut headers = Headers::new(); + headers.insert("x-endpoint-path".to_string(), "test".to_string()); + + let result = conn.send_request(Bytes::from("ping"), &headers).await; + assert!(result.is_ok(), "Request should succeed"); + assert_eq!(result.unwrap(), Bytes::from("pong")); + + assert!( + conn.is_healthy(), + "Connection should remain healthy after successful request" + ); + } + + #[tokio::test] + async fn test_concurrent_requests_single_connection() { + use crate::pipeline::network::codec::{TcpRequestMessage, TcpResponseMessage}; + + // Start a mock TCP server that handles multiple requests + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + let request_count = Arc::new(AtomicUsize::new(0)); + let request_count_clone = request_count.clone(); + + // Spawn server that responds to multiple requests + tokio::spawn(async move { + let (stream, _) = listener.accept().await.unwrap(); + let (mut read_half, mut write_half) = tokio::io::split(stream); + + // Handle 5 requests + for _ in 0..5 { + // Read request + let mut len_buf = [0u8; 2]; + if read_half.read_exact(&mut len_buf).await.is_err() { + break; + } + let path_len = u16::from_be_bytes(len_buf) as usize; + + let mut path_buf = vec![0u8; path_len]; + if read_half.read_exact(&mut path_buf).await.is_err() { + break; + } + + let mut len_buf = [0u8; 4]; + if read_half.read_exact(&mut len_buf).await.is_err() { + break; + } + let payload_len = u32::from_be_bytes(len_buf) as usize; + + let mut payload_buf = vec![0u8; payload_len]; + if read_half.read_exact(&mut payload_buf).await.is_err() { + break; + } + + request_count_clone.fetch_add(1, Ordering::SeqCst); + + // Send response + let response = TcpResponseMessage::new(Bytes::from(payload_buf)); + let encoded = response.encode().unwrap(); + if write_half.write_all(&encoded).await.is_err() { + break; + } + } + }); + + // Create connection + let conn = Arc::new( + TcpConnection::connect(addr, Duration::from_secs(5), 10) + .await + .unwrap(), + ); + + // Send 5 concurrent requests + let mut handles = vec![]; + for i in 0..5 { + let conn = conn.clone(); + let handle = tokio::spawn(async move { + let mut headers = Headers::new(); + headers.insert("x-endpoint-path".to_string(), "test".to_string()); + let payload = format!("request_{}", i); + conn.send_request(Bytes::from(payload.clone()), &headers) + .await + .map(|response| (payload, response)) + }); + handles.push(handle); + } + + // Wait for all requests to complete + let mut results = vec![]; + for handle in handles { + let result = handle.await.unwrap(); + assert!(result.is_ok(), "Request should succeed"); + results.push(result.unwrap()); + } + + // Verify all requests got responses + assert_eq!(results.len(), 5); + + // Verify server received all requests + assert_eq!( + request_count.load(Ordering::SeqCst), + 5, + "Server should have received 5 requests" + ); + } + + #[tokio::test] + async fn test_connection_pool_reuse() { + use crate::pipeline::network::codec::TcpResponseMessage; + + // Start a mock TCP server + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + let connection_count = Arc::new(AtomicUsize::new(0)); + let connection_count_clone = connection_count.clone(); + + // Spawn server that accepts multiple connections + tokio::spawn(async move { + loop { + let result = listener.accept().await; + if result.is_err() { + break; + } + let (stream, _) = result.unwrap(); + connection_count_clone.fetch_add(1, Ordering::SeqCst); + + tokio::spawn(async move { + let (mut read_half, mut write_half) = tokio::io::split(stream); + loop { + // Read request + let mut len_buf = [0u8; 2]; + if read_half.read_exact(&mut len_buf).await.is_err() { + break; + } + let path_len = u16::from_be_bytes(len_buf) as usize; + + let mut path_buf = vec![0u8; path_len]; + if read_half.read_exact(&mut path_buf).await.is_err() { + break; + } + + let mut len_buf = [0u8; 4]; + if read_half.read_exact(&mut len_buf).await.is_err() { + break; + } + let payload_len = u32::from_be_bytes(len_buf) as usize; + + let mut payload_buf = vec![0u8; payload_len]; + if read_half.read_exact(&mut payload_buf).await.is_err() { + break; + } + + // Send response + let response = TcpResponseMessage::new(Bytes::from_static(b"ok")); + let encoded = response.encode().unwrap(); + if write_half.write_all(&encoded).await.is_err() { + break; + } + } + }); + } + }); + + let config = TcpRequestConfig { + request_timeout: Duration::from_secs(5), + connect_timeout: Duration::from_secs(5), + pool_size: 2, + channel_buffer: 10, + }; + + let pool = TcpConnectionPool::new(config); + + // Get connection twice from pool + let conn1 = pool.get_connection(addr).await.unwrap(); + pool.return_connection(conn1).await; + + // Small delay to ensure connection is returned + tokio::time::sleep(Duration::from_millis(10)).await; + + let conn2 = pool.get_connection(addr).await.unwrap(); + pool.return_connection(conn2).await; + + // Should have created only 1 TCP connection since we reused + assert_eq!( + connection_count.load(Ordering::SeqCst), + 1, + "Should reuse connection from pool" + ); + } + + #[tokio::test] + async fn test_unhealthy_connection_filtered() { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + + // Server that immediately closes connections + tokio::spawn(async move { + while let Ok((stream, _)) = listener.accept().await { + drop(stream); // Immediately close + } + }); + + let config = TcpRequestConfig { + request_timeout: Duration::from_secs(1), + connect_timeout: Duration::from_secs(1), + pool_size: 2, + channel_buffer: 10, + }; + + let pool = TcpConnectionPool::new(config.clone()); + + // Try to get a connection - it will become unhealthy quickly + let result = + TcpConnection::connect(addr, config.connect_timeout, config.channel_buffer).await; + + if let Ok(conn) = result { + // Mark as unhealthy by trying to use it + let mut headers = Headers::new(); + headers.insert("x-endpoint-path".to_string(), "test".to_string()); + let _ = conn.send_request(Bytes::from("test"), &headers).await; + + // Return to pool + pool.return_connection(conn).await; + + // Try to get from pool again - should get a new connection attempt + let result2 = pool.get_connection(addr).await; + // This might fail or succeed depending on timing, but should not panic + let _ = result2; + } + } +} diff --git a/lib/runtime/src/pipeline/network/egress/unified_client.rs b/lib/runtime/src/pipeline/network/egress/unified_client.rs new file mode 100644 index 000000000..043255e7b --- /dev/null +++ b/lib/runtime/src/pipeline/network/egress/unified_client.rs @@ -0,0 +1,193 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Unified Request Plane Client Interface +//! +//! This module defines a transport-agnostic interface for sending requests +//! in the request plane. All transport implementations (TCP, HTTP, NATS) +//! implement this trait to provide a consistent interface for the egress router. + +use anyhow::Result; +use async_trait::async_trait; +use bytes::Bytes; +use std::collections::HashMap; + +/// Type alias for request headers +pub type Headers = HashMap; + +/// Unified interface for request plane clients +/// +/// This trait abstracts over different transport mechanisms (TCP, HTTP, NATS) +/// providing a consistent interface for sending requests and receiving acknowledgments. +/// +/// # Design Principles +/// +/// 1. **Transport Agnostic**: Implementations can be swapped without changing router logic +/// 2. **Async by Default**: All operations are async to support high concurrency +/// 3. **Headers Support**: All transports must support custom headers for tracing, etc. +/// 4. **Health Checks**: Implementations should provide connection health information +/// 5. **Error Handling**: All errors are wrapped in anyhow::Result for flexibility +/// +/// # Example +/// +/// ```ignore +/// use dynamo_runtime::pipeline::network::egress::RequestPlaneClient; +/// +/// async fn send_request(client: &dyn RequestPlaneClient) -> Result<()> { +/// let mut headers = HashMap::new(); +/// headers.insert("x-request-id".to_string(), "123".to_string()); +/// +/// let response = client.send_request( +/// "service-endpoint".to_string(), +/// Bytes::from("payload"), +/// headers, +/// ).await?; +/// +/// Ok(()) +/// } +/// ``` +#[async_trait] +pub trait RequestPlaneClient: Send + Sync { + /// Send a request to a specific address and wait for acknowledgment + /// + /// # Arguments + /// + /// * `address` - Transport-specific address: + /// - HTTP: `http://host:port/path` + /// - TCP: `host:port` or `tcp://host:port` + /// - NATS: `subject.name` + /// * `payload` - Request payload (encoded as bytes) + /// * `headers` - Custom headers for tracing, authentication, etc. + /// + /// # Returns + /// + /// Returns an acknowledgment response. Note that for streaming responses, + /// the actual response data comes over the TCP response plane, not through + /// this acknowledgment. + /// + /// # Errors + /// + /// Returns an error if: + /// - Connection to the endpoint fails + /// - Request times out + /// - Transport-specific errors occur (e.g., NATS server unavailable) + async fn send_request( + &self, + address: String, + payload: Bytes, + headers: Headers, + ) -> Result; + + /// Get the transport name + /// + /// Returns a static string identifier for the transport type. + /// Used for logging and debugging. + /// + /// # Examples + /// + /// - `"tcp"` - Raw TCP transport + /// - `"http"` or `"http2"` - HTTP/2 transport + /// - `"nats"` - NATS messaging + fn transport_name(&self) -> &'static str; + + /// Check connection health + /// + /// Returns `true` if the client is healthy and ready to send requests. + /// This is a lightweight check that doesn't perform actual network I/O. + /// + /// Implementations should return `false` if: + /// - Connection pool is exhausted + /// - Underlying transport is disconnected + /// - Client has been explicitly closed + fn is_healthy(&self) -> bool; + + /// Get client statistics (optional) + /// + /// Returns runtime statistics about the client for monitoring and debugging. + /// Default implementation returns empty statistics. + fn stats(&self) -> ClientStats { + ClientStats::default() + } + + /// Close the client gracefully (optional) + /// + /// Implementations should: + /// - Close all active connections + /// - Wait for in-flight requests to complete (or timeout) + /// - Release all resources + /// + /// Default implementation does nothing. + async fn close(&self) -> Result<()> { + Ok(()) + } +} + +/// Client runtime statistics +/// +/// Used for monitoring and debugging transport client performance. +#[derive(Debug, Clone, Default)] +pub struct ClientStats { + /// Total number of requests sent + pub requests_sent: u64, + + /// Total number of successful responses + pub responses_received: u64, + + /// Total number of errors + pub errors: u64, + + /// Total bytes sent + pub bytes_sent: u64, + + /// Total bytes received + pub bytes_received: u64, + + /// Number of active connections (for connection-pooled transports) + pub active_connections: usize, + + /// Number of idle connections in pool + pub idle_connections: usize, + + /// Average request latency in microseconds (0 if not available) + pub avg_latency_us: u64, +} + +impl ClientStats { + /// Create new empty statistics + pub fn new() -> Self { + Self::default() + } + + /// Check if statistics are available (non-zero) + pub fn is_available(&self) -> bool { + self.requests_sent > 0 || self.active_connections > 0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_client_stats_default() { + let stats = ClientStats::default(); + assert_eq!(stats.requests_sent, 0); + assert_eq!(stats.responses_received, 0); + assert!(!stats.is_available()); + } + + #[test] + fn test_client_stats_is_available() { + let mut stats = ClientStats::default(); + assert!(!stats.is_available()); + + stats.requests_sent = 1; + assert!(stats.is_available()); + + let stats2 = ClientStats { + active_connections: 1, + ..Default::default() + }; + assert!(stats2.is_available()); + } +} diff --git a/lib/runtime/src/pipeline/network/ingress.rs b/lib/runtime/src/pipeline/network/ingress.rs index f66a53532..e4e3e65da 100644 --- a/lib/runtime/src/pipeline/network/ingress.rs +++ b/lib/runtime/src/pipeline/network/ingress.rs @@ -1,7 +1,11 @@ // SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 +pub mod http_endpoint; +pub mod nats_server; pub mod push_endpoint; pub mod push_handler; +pub mod shared_tcp_endpoint; +pub mod unified_server; use super::*; diff --git a/lib/runtime/src/pipeline/network/ingress/http_endpoint.rs b/lib/runtime/src/pipeline/network/ingress/http_endpoint.rs new file mode 100644 index 000000000..7996c622c --- /dev/null +++ b/lib/runtime/src/pipeline/network/ingress/http_endpoint.rs @@ -0,0 +1,355 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! HTTP endpoint for receiving requests via Axum/HTTP/2 + +use super::*; +use crate::SystemHealth; +use crate::config::HealthStatus; +use crate::logging::TraceParent; +use anyhow::Result; +use axum::{ + Router, + body::Bytes, + extract::{Path, State as AxumState}, + http::{HeaderMap, StatusCode}, + response::IntoResponse, + routing::post, +}; +use dashmap::DashMap; +use hyper_util::rt::{TokioExecutor, TokioIo}; +use hyper_util::server::conn::auto::Builder as Http2Builder; +use hyper_util::service::TowerToHyperService; +use parking_lot::Mutex; +use std::net::SocketAddr; +use std::sync::atomic::{AtomicU64, Ordering}; +use tokio::sync::Notify; +use tokio_util::sync::CancellationToken; +use tower_http::trace::TraceLayer; +use tracing::Instrument; + +/// Default root path for dynamo RPC endpoints +const DEFAULT_RPC_ROOT_PATH: &str = "/v1/rpc"; + +/// version of crate +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +/// Shared HTTP server that handles multiple endpoints on a single port +pub struct SharedHttpServer { + handlers: Arc>>, + bind_addr: SocketAddr, + cancellation_token: CancellationToken, +} + +/// Handler for a specific endpoint +struct EndpointHandler { + service_handler: Arc, + instance_id: u64, + namespace: Arc, + component_name: Arc, + endpoint_name: Arc, + system_health: Arc>, + inflight: Arc, + notify: Arc, +} + +impl SharedHttpServer { + pub fn new(bind_addr: SocketAddr, cancellation_token: CancellationToken) -> Arc { + Arc::new(Self { + handlers: Arc::new(DashMap::new()), + bind_addr, + cancellation_token, + }) + } + + /// Register an endpoint handler with this server + #[allow(clippy::too_many_arguments)] + pub async fn register_endpoint( + &self, + subject: String, + service_handler: Arc, + instance_id: u64, + namespace: String, + component_name: String, + endpoint_name: String, + system_health: Arc>, + ) -> Result<()> { + let handler = Arc::new(EndpointHandler { + service_handler, + instance_id, + namespace: Arc::new(namespace), + component_name: Arc::new(component_name), + endpoint_name: Arc::new(endpoint_name.clone()), + system_health: system_health.clone(), + inflight: Arc::new(AtomicU64::new(0)), + notify: Arc::new(Notify::new()), + }); + + // Set health status + system_health + .lock() + .set_endpoint_health_status(&endpoint_name, HealthStatus::Ready); + + let subject_clone = subject.clone(); + self.handlers.insert(subject, handler); + tracing::debug!("Registered endpoint handler for subject: {}", subject_clone); + Ok(()) + } + + /// Unregister an endpoint handler + pub async fn unregister_endpoint(&self, subject: &str, endpoint_name: &str) { + if let Some((_, handler)) = self.handlers.remove(subject) { + handler + .system_health + .lock() + .set_endpoint_health_status(endpoint_name, HealthStatus::NotReady); + tracing::debug!("Unregistered endpoint handler for subject: {}", subject); + } + } + + /// Start the shared HTTP server + pub async fn start(self: Arc) -> Result<()> { + let rpc_root_path = std::env::var("DYN_HTTP_RPC_ROOT_PATH") + .unwrap_or_else(|_| DEFAULT_RPC_ROOT_PATH.to_string()); + let route_pattern = format!("{}/{{*endpoint}}", rpc_root_path); + + let app = Router::new() + .route(&route_pattern, post(handle_shared_request)) + .layer(TraceLayer::new_for_http()) + .with_state(self.clone()); + + tracing::info!( + "Starting shared HTTP/2 endpoint server on {} at path {}/:endpoint", + self.bind_addr, + rpc_root_path + ); + + let listener = tokio::net::TcpListener::bind(&self.bind_addr).await?; + let cancellation_token = self.cancellation_token.clone(); + + loop { + tokio::select! { + accept_result = listener.accept() => { + match accept_result { + Ok((stream, _addr)) => { + let app_clone = app.clone(); + let cancel_clone = cancellation_token.clone(); + + tokio::spawn(async move { + // Create HTTP/2 connection builder with prior knowledge + let http2_builder = Http2Builder::new(TokioExecutor::new()); + + let io = TokioIo::new(stream); + let tower_service = app_clone.into_service(); + + // Wrap Tower service for Hyper compatibility + let hyper_service = TowerToHyperService::new(tower_service); + + tokio::select! { + result = http2_builder.serve_connection(io, hyper_service) => { + if let Err(e) = result { + tracing::debug!("HTTP/2 connection error: {}", e); + } + } + _ = cancel_clone.cancelled() => { + tracing::trace!("Connection cancelled"); + } + } + }); + } + Err(e) => { + tracing::error!("Failed to accept connection: {}", e); + } + } + } + _ = cancellation_token.cancelled() => { + tracing::info!("SharedHttpServer received cancellation signal, shutting down"); + return Ok(()); + } + } + } + } + + /// Wait for all inflight requests across all endpoints + pub async fn wait_for_inflight(&self) { + for handler in self.handlers.iter() { + while handler.value().inflight.load(Ordering::SeqCst) > 0 { + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + } + } + } +} + +/// HTTP handler for the shared server +async fn handle_shared_request( + AxumState(server): AxumState>, + Path(endpoint_path): Path, + headers: HeaderMap, + body: Bytes, +) -> impl IntoResponse { + // Look up the handler for this endpoint (lock-free read with DashMap) + let handler = match server.handlers.get(&endpoint_path) { + Some(h) => h.clone(), + None => { + tracing::warn!("No handler found for endpoint: {}", endpoint_path); + return (StatusCode::NOT_FOUND, "Endpoint not found"); + } + }; + + // Increment inflight counter + handler.inflight.fetch_add(1, Ordering::SeqCst); + + // Extract tracing headers + let traceparent = TraceParent::from_axum_headers(&headers); + + // Spawn async handler + let service_handler = handler.service_handler.clone(); + let inflight = handler.inflight.clone(); + let notify = handler.notify.clone(); + let namespace = handler.namespace.clone(); + let component_name = handler.component_name.clone(); + let endpoint_name = handler.endpoint_name.clone(); + let instance_id = handler.instance_id; + + tokio::spawn(async move { + tracing::trace!(instance_id, "handling new HTTP request"); + let result = service_handler + .handle_payload(body) + .instrument(tracing::info_span!( + "handle_payload", + component = component_name.as_ref(), + endpoint = endpoint_name.as_ref(), + namespace = namespace.as_ref(), + instance_id = instance_id, + trace_id = traceparent.trace_id, + parent_id = traceparent.parent_id, + x_request_id = traceparent.x_request_id, + x_dynamo_request_id = traceparent.x_dynamo_request_id, + tracestate = traceparent.tracestate + )) + .await; + match result { + Ok(_) => { + tracing::trace!(instance_id, "request handled successfully"); + } + Err(e) => { + tracing::warn!("Failed to handle request: {}", e.to_string()); + } + } + + // Decrease inflight counter + inflight.fetch_sub(1, Ordering::SeqCst); + notify.notify_one(); + }); + + // Return 202 Accepted immediately (like NATS ack) + (StatusCode::ACCEPTED, "") +} + +/// Extension trait for TraceParent to support Axum headers +impl TraceParent { + pub fn from_axum_headers(headers: &HeaderMap) -> Self { + let mut traceparent = TraceParent::default(); + + if let Some(value) = headers.get("traceparent") + && let Ok(s) = value.to_str() + { + traceparent.trace_id = Some(s.to_string()); + } + + if let Some(value) = headers.get("tracestate") + && let Ok(s) = value.to_str() + { + traceparent.tracestate = Some(s.to_string()); + } + + if let Some(value) = headers.get("x-request-id") + && let Ok(s) = value.to_str() + { + traceparent.x_request_id = Some(s.to_string()); + } + + if let Some(value) = headers.get("x-dynamo-request-id") + && let Ok(s) = value.to_str() + { + traceparent.x_dynamo_request_id = Some(s.to_string()); + } + + traceparent + } +} + +// Implement RequestPlaneServer trait for SharedHttpServer +#[async_trait::async_trait] +impl super::unified_server::RequestPlaneServer for SharedHttpServer { + async fn register_endpoint( + &self, + endpoint_name: String, + service_handler: Arc, + instance_id: u64, + namespace: String, + component_name: String, + system_health: Arc>, + ) -> Result<()> { + // For HTTP, we use endpoint_name as both the subject (routing key) and endpoint_name + self.register_endpoint( + endpoint_name.clone(), + service_handler, + instance_id, + namespace, + component_name, + endpoint_name, + system_health, + ) + .await + } + + async fn unregister_endpoint(&self, endpoint_name: &str) -> Result<()> { + self.unregister_endpoint(endpoint_name, endpoint_name).await; + Ok(()) + } + + fn address(&self) -> String { + format!("http://{}:{}", self.bind_addr.ip(), self.bind_addr.port()) + } + + fn transport_name(&self) -> &'static str { + "http" + } + + fn is_healthy(&self) -> bool { + // Server is healthy if it has been created + // TODO: Add more sophisticated health checks (e.g., check if listener is active) + true + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_traceparent_from_axum_headers() { + let mut headers = HeaderMap::new(); + headers.insert("traceparent", "test-trace-id".parse().unwrap()); + headers.insert("tracestate", "test-state".parse().unwrap()); + headers.insert("x-request-id", "req-123".parse().unwrap()); + headers.insert("x-dynamo-request-id", "dyn-456".parse().unwrap()); + + let traceparent = TraceParent::from_axum_headers(&headers); + assert_eq!(traceparent.trace_id, Some("test-trace-id".to_string())); + assert_eq!(traceparent.tracestate, Some("test-state".to_string())); + assert_eq!(traceparent.x_request_id, Some("req-123".to_string())); + assert_eq!(traceparent.x_dynamo_request_id, Some("dyn-456".to_string())); + } + + #[test] + fn test_shared_http_server_creation() { + use std::net::{IpAddr, Ipv4Addr}; + let bind_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 0); + let token = CancellationToken::new(); + + let server = SharedHttpServer::new(bind_addr, token); + assert!(server.handlers.is_empty()); + } +} diff --git a/lib/runtime/src/pipeline/network/ingress/nats_server.rs b/lib/runtime/src/pipeline/network/ingress/nats_server.rs new file mode 100644 index 000000000..2fb9f1d32 --- /dev/null +++ b/lib/runtime/src/pipeline/network/ingress/nats_server.rs @@ -0,0 +1,216 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! NATS Multiplexed Server +//! +//! Provides a multiplexed NATS server that handles multiple endpoints on a single +//! NATS service group. This replaces the per-endpoint PushEndpoint pattern with +//! a unified multiplexed approach consistent with HTTP and TCP servers. + +use super::*; +use crate::SystemHealth; +use crate::config::HealthStatus; +use crate::pipeline::network::ingress::push_endpoint::PushEndpoint; +use anyhow::Result; +use async_trait::async_trait; +use dashmap::DashMap; +use parking_lot::Mutex; +use std::sync::Arc; +use tokio_util::sync::CancellationToken; + +/// Multiplexed NATS server that handles multiple endpoints +/// +/// Unlike the previous per-endpoint approach, this server manages multiple +/// endpoints, getting the service group dynamically from the component registry +/// for each endpoint registration. +pub struct NatsMultiplexedServer { + nats_client: async_nats::Client, + component_registry: crate::component::Registry, + handlers: Arc>, + cancellation_token: CancellationToken, +} + +struct EndpointTask { + cancel_token: CancellationToken, + _endpoint_name: String, +} + +impl NatsMultiplexedServer { + /// Create a new multiplexed NATS server + /// + /// # Arguments + /// + /// * `nats_client` - NATS client for connection management + /// * `component_registry` - Component registry to get service groups from + /// * `cancellation_token` - Token for graceful shutdown + pub fn new( + nats_client: async_nats::Client, + component_registry: crate::component::Registry, + cancellation_token: CancellationToken, + ) -> Arc { + Arc::new(Self { + nats_client, + component_registry, + handlers: Arc::new(DashMap::new()), + cancellation_token, + }) + } +} + +#[async_trait] +impl super::unified_server::RequestPlaneServer for NatsMultiplexedServer { + async fn register_endpoint( + &self, + endpoint_name: String, + service_handler: Arc, + instance_id: u64, + namespace: String, + component_name: String, + system_health: Arc>, + ) -> Result<()> { + tracing::info!( + endpoint_name = %endpoint_name, + namespace = %namespace, + component = %component_name, + instance_id = instance_id, + "NatsMultiplexedServer::register_endpoint called" + ); + + // Get the service group from the component registry + // Service name format matches Component::service_name(): "{namespace}_{component}" slugified + use crate::transports::nats::Slug; + let service_name_raw = format!("{}_{}", namespace, component_name); + let service_name = Slug::slugify(&service_name_raw).to_string(); + + tracing::debug!( + service_name_raw = %service_name_raw, + service_name = %service_name, + "Looking up service group in registry" + ); + + let registry = self.component_registry.inner.lock().await; + let service_group = registry + .services + .get(&service_name) + .map(|service| service.group(&service_name)) + .ok_or_else(|| anyhow::anyhow!("Service '{}' not found in registry", service_name))?; + drop(registry); + + tracing::info!("Successfully retrieved service group"); + + // Construct the full NATS subject with instance ID + // Format: {endpoint_name}-{instance_id_hex} + // This matches Endpoint::name_with_id() and subject_to() format + let endpoint_with_id = format!("{}-{:x}", endpoint_name, instance_id); + + // Create NATS service endpoint with the full subject + let service_endpoint = service_group + .endpoint(&endpoint_with_id) + .await + .map_err(|e| { + anyhow::anyhow!( + "Failed to create NATS endpoint '{}': {}", + endpoint_with_id, + e + ) + })?; + + tracing::info!( + endpoint_name = %endpoint_name, + endpoint_with_id = %endpoint_with_id, + namespace = %namespace, + component = %component_name, + instance_id = instance_id, + "Registering NATS endpoint" + ); + + // Create cancellation token for this specific endpoint + let endpoint_cancel = CancellationToken::new(); + let endpoint_cancel_clone = endpoint_cancel.clone(); + + // Build the push endpoint + let push_endpoint = PushEndpoint::builder() + .service_handler(service_handler) + .cancellation_token(endpoint_cancel_clone) + .graceful_shutdown(true) + .build() + .map_err(|e| anyhow::anyhow!("Failed to build NATS push endpoint: {}", e))?; + + tracing::info!( + endpoint_name = %endpoint_name, + endpoint_with_id = %endpoint_with_id, + "Starting NATS push endpoint listener (blocking)" + ); + + // Spawn task to handle this endpoint using PushEndpoint + // Note: PushEndpoint::start() is a blocking loop that runs until cancelled + let endpoint_name_clone = endpoint_name.clone(); + tokio::spawn(async move { + if let Err(e) = push_endpoint + .start( + service_endpoint, + namespace, + component_name, + endpoint_name_clone.clone(), + instance_id, + system_health, + ) + .await + { + tracing::error!( + endpoint_name = %endpoint_name_clone, + error = %e, + "NATS endpoint task failed" + ); + } else { + tracing::info!( + endpoint_name = %endpoint_name_clone, + "NATS push endpoint listener completed" + ); + } + }); + + // Give the endpoint a moment to start listening + // This prevents a race condition where discovery registers the endpoint + // before NATS is actually ready to receive requests + tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + + // Store task info for later cleanup + self.handlers.insert( + endpoint_name.clone(), + EndpointTask { + cancel_token: endpoint_cancel, + _endpoint_name: endpoint_name, + }, + ); + + Ok(()) + } + + async fn unregister_endpoint(&self, endpoint_name: &str) -> Result<()> { + if let Some((_, task)) = self.handlers.remove(endpoint_name) { + tracing::info!( + endpoint_name = %endpoint_name, + "Unregistering NATS endpoint" + ); + task.cancel_token.cancel(); + } + Ok(()) + } + + fn address(&self) -> String { + // Return NATS server URL from connection info + // NATS client doesn't expose server info directly, return generic address + "nats://connected".to_string() + } + + fn transport_name(&self) -> &'static str { + "nats" + } + + fn is_healthy(&self) -> bool { + // Check if NATS client is connected + // NATS client doesn't expose connection state directly, assume healthy + true + } +} diff --git a/lib/runtime/src/pipeline/network/ingress/shared_tcp_endpoint.rs b/lib/runtime/src/pipeline/network/ingress/shared_tcp_endpoint.rs new file mode 100644 index 000000000..c602de2f7 --- /dev/null +++ b/lib/runtime/src/pipeline/network/ingress/shared_tcp_endpoint.rs @@ -0,0 +1,365 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Shared TCP Server with Endpoint Multiplexing +//! +//! Provides a shared TCP server that can handle multiple endpoints on a single port +//! by adding endpoint routing to the TCP wire protocol. + +use crate::SystemHealth; +use crate::pipeline::network::PushWorkHandler; +use anyhow::Result; +use bytes::Bytes; +use dashmap::DashMap; +use parking_lot::Mutex; +use std::net::SocketAddr; +use std::sync::Arc; +use std::sync::atomic::{AtomicU64, Ordering}; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::{TcpListener, TcpStream}; +use tokio::sync::Notify; +use tokio_util::bytes::BytesMut; +use tokio_util::sync::CancellationToken; +use tracing::Instrument; + +/// Default maximum message size for TCP server (32 MB) +const DEFAULT_MAX_MESSAGE_SIZE: usize = 32 * 1024 * 1024; + +/// Get maximum message size from environment or use default +fn get_max_message_size() -> usize { + std::env::var("DYN_TCP_MAX_MESSAGE_SIZE") + .ok() + .and_then(|s| s.parse::().ok()) + .unwrap_or(DEFAULT_MAX_MESSAGE_SIZE) +} + +/// Shared TCP server that handles multiple endpoints on a single port +pub struct SharedTcpServer { + handlers: Arc>>, + bind_addr: SocketAddr, + cancellation_token: CancellationToken, +} + +struct EndpointHandler { + service_handler: Arc, + instance_id: u64, + namespace: String, + component_name: String, + endpoint_name: String, + system_health: Arc>, + inflight: Arc, + notify: Arc, +} + +impl SharedTcpServer { + pub fn new(bind_addr: SocketAddr, cancellation_token: CancellationToken) -> Arc { + Arc::new(Self { + handlers: Arc::new(DashMap::new()), + bind_addr, + cancellation_token, + }) + } + + #[allow(clippy::too_many_arguments)] + pub async fn register_endpoint( + &self, + endpoint_path: String, + service_handler: Arc, + instance_id: u64, + namespace: String, + component_name: String, + endpoint_name: String, + system_health: Arc>, + ) -> Result<()> { + let handler = Arc::new(EndpointHandler { + service_handler, + instance_id, + namespace, + component_name, + endpoint_name: endpoint_name.clone(), + system_health, + inflight: Arc::new(AtomicU64::new(0)), + notify: Arc::new(Notify::new()), + }); + + self.handlers.insert(endpoint_path, handler); + + tracing::info!( + "Registered endpoint '{}' with shared TCP server on {}", + endpoint_name, + self.bind_addr + ); + + Ok(()) + } + + pub async fn unregister_endpoint(&self, endpoint_path: &str, endpoint_name: &str) { + self.handlers.remove(endpoint_path); + tracing::info!( + "Unregistered endpoint '{}' from shared TCP server", + endpoint_name + ); + } + + pub async fn start(self: Arc) -> Result<()> { + tracing::info!("Starting shared TCP server on {}", self.bind_addr); + + let listener = TcpListener::bind(&self.bind_addr).await?; + let cancellation_token = self.cancellation_token.clone(); + + loop { + tokio::select! { + accept_result = listener.accept() => { + match accept_result { + Ok((stream, peer_addr)) => { + tracing::trace!("Accepted TCP connection from {}", peer_addr); + + let handlers = self.handlers.clone(); + tokio::spawn(async move { + if let Err(e) = Self::handle_connection(stream, handlers).await { + tracing::debug!("TCP connection error: {}", e); + } + }); + } + Err(e) => { + tracing::error!("Failed to accept TCP connection: {}", e); + } + } + } + _ = cancellation_token.cancelled() => { + tracing::info!("SharedTcpServer received cancellation signal, shutting down"); + return Ok(()); + } + } + } + } + + async fn handle_connection( + stream: TcpStream, + handlers: Arc>>, + ) -> Result<()> { + use crate::pipeline::network::codec::{TcpRequestMessage, TcpResponseMessage}; + + // Split stream into read and write halves for concurrent operations + let (read_half, write_half) = tokio::io::split(stream); + + // Channel for sending responses to the write task (zero-copy Bytes) + let (response_tx, response_rx) = tokio::sync::mpsc::unbounded_channel::(); + + // Spawn write task + let write_task = tokio::spawn(Self::write_loop(write_half, response_rx)); + + // Run read task in current context + let read_result = Self::read_loop(read_half, handlers, response_tx).await; + + // Write task will end when response_tx is dropped + write_task.await??; + + read_result + } + + async fn read_loop( + mut read_half: tokio::io::ReadHalf, + handlers: Arc>>, + response_tx: tokio::sync::mpsc::UnboundedSender, + ) -> Result<()> { + use crate::pipeline::network::codec::{TcpRequestMessage, TcpResponseMessage}; + + loop { + // Read endpoint path length (2 bytes) + let mut path_len_buf = [0u8; 2]; + match read_half.read_exact(&mut path_len_buf).await { + Ok(_) => {} + Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => { + break; + } + Err(e) => { + return Err(e.into()); + } + } + + let path_len = u16::from_be_bytes(path_len_buf) as usize; + + // Read endpoint path + let mut path_buf = vec![0u8; path_len]; + read_half.read_exact(&mut path_buf).await?; + + // Read payload length (4 bytes) + let mut len_buf = [0u8; 4]; + read_half.read_exact(&mut len_buf).await?; + let payload_len = u32::from_be_bytes(len_buf) as usize; + + // Sanity check - enforce maximum message size + let max_message_size = get_max_message_size(); + if payload_len > max_message_size { + tracing::warn!( + "Request too large: {} bytes (max: {} bytes), closing connection", + payload_len, + max_message_size + ); + // Send error response + let error_response = + TcpResponseMessage::new(Bytes::from_static(b"Request too large")); + if let Ok(encoded) = error_response.encode() { + let _ = response_tx.send(encoded); + } + break; + } + + // Read request payload + let mut payload_buf = vec![0u8; payload_len]; + read_half.read_exact(&mut payload_buf).await?; + + // Reconstruct the full message buffer for decoding using BytesMut + let mut full_msg = BytesMut::with_capacity(2 + path_len + 4 + payload_len); + full_msg.extend_from_slice(&path_len_buf); + full_msg.extend_from_slice(&path_buf); + full_msg.extend_from_slice(&len_buf); + full_msg.extend_from_slice(&payload_buf); + + // Decode using codec (zero-copy conversion) + let full_msg_bytes = full_msg.freeze(); + let request_msg = match TcpRequestMessage::decode(&full_msg_bytes) { + Ok(msg) => msg, + Err(e) => { + tracing::warn!("Failed to decode TCP request: {}", e); + // Send error response + let error_response = + TcpResponseMessage::new(Bytes::from(format!("Decode error: {}", e))); + if let Ok(encoded) = error_response.encode() { + let _ = response_tx.send(encoded); + } + continue; + } + }; + + let endpoint_path = request_msg.endpoint_path; + let payload = request_msg.payload; + + // Look up handler (lock-free read with DashMap) + let handler = handlers.get(&endpoint_path).map(|h| h.clone()); + + let handler = match handler { + Some(h) => h, + None => { + tracing::warn!("No handler found for endpoint: {}", endpoint_path); + // Send error response using codec + let error_response = TcpResponseMessage::new(Bytes::from(format!( + "Unknown endpoint: {}", + endpoint_path + ))); + if let Ok(encoded) = error_response.encode() { + let _ = response_tx.send(encoded); + } + continue; + } + }; + + handler.inflight.fetch_add(1, Ordering::SeqCst); + + // Send acknowledgment immediately using codec (non-blocking, zero-copy) + let ack_response = TcpResponseMessage::empty(); + if let Ok(encoded_ack) = ack_response.encode() { + // Send to write task without blocking reads + if response_tx.send(encoded_ack).is_err() { + tracing::debug!("Write task closed, ending read loop"); + break; + } + } + + // Process request asynchronously + let service_handler = handler.service_handler.clone(); + let inflight = handler.inflight.clone(); + let notify = handler.notify.clone(); + let instance_id = handler.instance_id; + let namespace = handler.namespace.clone(); + let component_name = handler.component_name.clone(); + let endpoint_name = handler.endpoint_name.clone(); + + tokio::spawn(async move { + tracing::trace!(instance_id, "handling TCP request"); + + let result = service_handler + .handle_payload(payload) + .instrument(tracing::info_span!( + "handle_payload", + component = component_name.as_str(), + endpoint = endpoint_name.as_str(), + namespace = namespace.as_str(), + instance_id = instance_id, + )) + .await; + + match result { + Ok(_) => { + tracing::trace!(instance_id, "TCP request handled successfully"); + } + Err(e) => { + tracing::warn!("Failed to handle TCP request: {}", e); + } + } + + inflight.fetch_sub(1, Ordering::SeqCst); + notify.notify_one(); + }); + } + + Ok(()) + } + + async fn write_loop( + mut write_half: tokio::io::WriteHalf, + mut response_rx: tokio::sync::mpsc::UnboundedReceiver, + ) -> Result<()> { + while let Some(response) = response_rx.recv().await { + write_half.write_all(&response).await?; + write_half.flush().await?; + } + Ok(()) + } +} + +// Implement RequestPlaneServer trait for SharedTcpServer +#[async_trait::async_trait] +impl super::unified_server::RequestPlaneServer for SharedTcpServer { + async fn register_endpoint( + &self, + endpoint_name: String, + service_handler: Arc, + instance_id: u64, + namespace: String, + component_name: String, + system_health: Arc>, + ) -> Result<()> { + // For TCP, we use endpoint_name as both the endpoint_path (routing key) and endpoint_name + self.register_endpoint( + endpoint_name.clone(), + service_handler, + instance_id, + namespace, + component_name, + endpoint_name, + system_health, + ) + .await + } + + async fn unregister_endpoint(&self, endpoint_name: &str) -> Result<()> { + self.unregister_endpoint(endpoint_name, endpoint_name).await; + Ok(()) + } + + fn address(&self) -> String { + format!("tcp://{}:{}", self.bind_addr.ip(), self.bind_addr.port()) + } + + fn transport_name(&self) -> &'static str { + "tcp" + } + + fn is_healthy(&self) -> bool { + // Server is healthy if it has been created + // TODO: Add more sophisticated health checks (e.g., check if listener is active) + true + } +} diff --git a/lib/runtime/src/pipeline/network/ingress/unified_server.rs b/lib/runtime/src/pipeline/network/ingress/unified_server.rs new file mode 100644 index 000000000..45517acd0 --- /dev/null +++ b/lib/runtime/src/pipeline/network/ingress/unified_server.rs @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Unified Request Plane Server Interface +//! +//! This module defines a transport-agnostic interface for request plane servers. +//! All transport implementations (HTTP, TCP, NATS) implement this trait to provide +//! a consistent interface for endpoint registration and management. + +use super::*; +use crate::SystemHealth; +use anyhow::Result; +use async_trait::async_trait; +use parking_lot::Mutex; +use std::sync::Arc; + +/// Unified interface for request plane servers +/// +/// This trait abstracts over different transport mechanisms (HTTP/2, TCP, NATS) +/// providing a consistent interface for registering endpoints and managing server lifecycle. +/// +/// # Design Principles +/// +/// 1. **Transport Agnostic**: Implementations can be swapped without changing business logic +/// 2. **Multiplexed**: All servers handle multiple endpoints on a single port/connection +/// 3. **Async by Default**: All operations are async to support high concurrency +/// 4. **Health Monitoring**: Servers provide health status for monitoring +/// +/// # Example +/// +/// ```ignore +/// use dynamo_runtime::pipeline::network::ingress::RequestPlaneServer; +/// +/// async fn register(server: &dyn RequestPlaneServer) -> Result<()> { +/// server.register_endpoint( +/// "generate".to_string(), +/// handler, +/// instance_id, +/// "dynamo".to_string(), +/// "backend".to_string(), +/// system_health, +/// ).await?; +/// Ok(()) +/// } +/// ``` +#[async_trait] +pub trait RequestPlaneServer: Send + Sync { + /// Register an endpoint handler with the server + /// + /// # Arguments + /// + /// * `endpoint_name` - Name/path for routing (e.g., "generate", "health") + /// * `service_handler` - Handler that processes incoming requests + /// * `instance_id` - Unique instance identifier for this endpoint + /// * `namespace` - Service namespace (e.g., "dynamo") + /// * `component_name` - Component name (e.g., "backend", "frontend") + /// * `system_health` - Health tracking for this endpoint + /// + /// # Returns + /// + /// Returns `Ok(())` if registration succeeds, or an error if: + /// - Endpoint name is already registered + /// - Server is not running or has been stopped + /// - Transport-specific errors occur + async fn register_endpoint( + &self, + endpoint_name: String, + service_handler: Arc, + instance_id: u64, + namespace: String, + component_name: String, + system_health: Arc>, + ) -> Result<()>; + + /// Unregister an endpoint from the server + /// + /// # Arguments + /// + /// * `endpoint_name` - Name of the endpoint to unregister + /// + /// # Returns + /// + /// Returns `Ok(())` if unregistration succeeds or endpoint doesn't exist. + /// Errors are only returned for transport-specific failures. + async fn unregister_endpoint(&self, endpoint_name: &str) -> Result<()>; + + /// Get server bind address or identifier + /// + /// Returns a transport-specific address string: + /// - HTTP: `"http://0.0.0.0:8888"` + /// - TCP: `"tcp://0.0.0.0:9999"` + /// - NATS: `"nats://localhost:4222"` + /// + /// Used for logging, debugging, and service discovery. + fn address(&self) -> String; + + /// Get the transport name + /// + /// Returns a static string identifier for the transport type. + /// Used for logging and debugging. + /// + /// # Examples + /// + /// - `"http"` - HTTP/2 transport + /// - `"tcp"` - Raw TCP transport + /// - `"nats"` - NATS messaging + fn transport_name(&self) -> &'static str; + + /// Check if server is healthy and ready to accept requests + /// + /// Returns `true` if the server is operational and can handle requests. + /// This is a lightweight check that doesn't perform actual network I/O. + /// + /// Implementations should return `false` if: + /// - Server has been explicitly stopped + /// - Underlying transport is disconnected + /// - Server encountered a fatal error + fn is_healthy(&self) -> bool; +} diff --git a/lib/runtime/src/pipeline/network/manager.rs b/lib/runtime/src/pipeline/network/manager.rs new file mode 100644 index 000000000..f5a606d7d --- /dev/null +++ b/lib/runtime/src/pipeline/network/manager.rs @@ -0,0 +1,327 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Network Manager - Single Source of Truth for Network Configuration +//! +//! This module consolidates ALL network-related configuration and creation logic. +//! It is the ONLY place in the codebase that: +//! - Reads environment variables for network configuration +//! - Knows about transport-specific types (SharedHttpServer, TcpRequestClient, etc.) +//! - Performs mode selection based on RequestPlaneMode +//! - Creates servers and clients +//! +//! The rest of the codebase works exclusively with trait objects and never +//! directly accesses transport implementations or configuration. + +use super::egress::unified_client::RequestPlaneClient; +use super::ingress::unified_server::RequestPlaneServer; +use crate::config::RequestPlaneMode; +use anyhow::Result; +use async_once_cell::OnceCell; +use std::sync::Arc; +use tokio_util::sync::CancellationToken; + +/// Network configuration loaded from environment variables +#[derive(Clone)] +struct NetworkConfig { + // HTTP server configuration + http_host: String, + http_port: u16, + http_rpc_root: String, + + // TCP server configuration + tcp_host: String, + tcp_port: u16, + + // HTTP client configuration + http_client_config: super::egress::http_router::Http2Config, + + // TCP client configuration + tcp_client_config: super::egress::tcp_client::TcpRequestConfig, + + // NATS configuration (provided externally, not from env) + nats_client: Option, +} + +impl NetworkConfig { + /// Load configuration from environment variables + /// + /// This is the ONLY place where network-related environment variables are read. + fn from_env(nats_client: Option) -> Self { + Self { + // HTTP server configuration + http_host: std::env::var("DYN_HTTP_RPC_HOST") + .unwrap_or_else(|_| crate::utils::get_http_rpc_host_from_env()), + http_port: std::env::var("DYN_HTTP_RPC_PORT") + .ok() + .and_then(|p| p.parse().ok()) + .unwrap_or(8888), + http_rpc_root: std::env::var("DYN_HTTP_RPC_ROOT_PATH") + .unwrap_or_else(|_| "/v1/rpc".to_string()), + + // TCP server configuration + tcp_host: std::env::var("DYN_TCP_RPC_HOST") + .unwrap_or_else(|_| crate::utils::get_tcp_rpc_host_from_env()), + tcp_port: std::env::var("DYN_TCP_RPC_PORT") + .ok() + .and_then(|p| p.parse().ok()) + .unwrap_or(9999), + + // HTTP client configuration (reads DYN_HTTP2_* env vars) + http_client_config: super::egress::http_router::Http2Config::from_env(), + + // TCP client configuration (reads DYN_TCP_* env vars) + tcp_client_config: super::egress::tcp_client::TcpRequestConfig::from_env(), + + // NATS (external) + nats_client, + } + } +} + +/// Network Manager - Central coordinator for all network resources +/// +/// # Responsibilities +/// +/// 1. **Configuration Management**: Reads and manages all network-related environment variables +/// 2. **Server Creation**: Creates and starts request plane servers based on mode +/// 3. **Client Creation**: Creates request plane clients on demand +/// 4. **Abstraction**: Hides all transport-specific details from the rest of the codebase +/// +/// # Design Principles +/// +/// - **Single Source of Truth**: All network config and creation logic lives here +/// - **Lazy Initialization**: Servers are created only when first accessed +/// - **Transport Agnostic Interface**: Exposes only trait objects to callers +/// - **No Leaky Abstractions**: Transport types never escape this module +/// +/// # Example +/// +/// ```ignore +/// // Create manager (typically done once in DistributedRuntime) +/// let manager = NetworkManager::new(cancel_token, nats_client, component_registry); +/// +/// // Get server (lazy init, cached) +/// let server = manager.server().await?; +/// server.register_endpoint(...).await?; +/// +/// // Create client (not cached, lightweight) +/// let client = manager.create_client()?; +/// client.send_request(...).await?; +/// ``` +pub struct NetworkManager { + mode: RequestPlaneMode, + config: NetworkConfig, + server: Arc>>, + cancellation_token: CancellationToken, + component_registry: crate::component::Registry, +} + +impl NetworkManager { + /// Create a new network manager + /// + /// This is the single constructor for NetworkManager. All configuration + /// is loaded from environment variables internally. + /// + /// # Arguments + /// + /// * `cancellation_token` - Token for graceful shutdown of servers + /// * `nats_client` - Optional NATS client (required only for NATS mode) + /// * `component_registry` - Component registry to get NATS service groups from + /// + /// # Returns + /// + /// Returns an Arc-wrapped NetworkManager ready to create servers and clients. + pub fn new( + cancellation_token: CancellationToken, + nats_client: Option, + component_registry: crate::component::Registry, + ) -> Arc { + let mode = RequestPlaneMode::get(); + let config = NetworkConfig::from_env(nats_client); + + tracing::info!( + mode = %mode, + http_port = config.http_port, + tcp_port = config.tcp_port, + "Initializing NetworkManager" + ); + + Arc::new(Self { + mode, + config, + server: Arc::new(OnceCell::new()), + cancellation_token, + component_registry, + }) + } + + /// Get or create the request plane server + /// + /// The server is created lazily on first access and cached for subsequent calls. + /// The server is automatically started in the background. + /// + /// # Returns + /// + /// Returns a trait object that abstracts over HTTP/TCP/NATS implementations. + /// + /// # Errors + /// + /// Returns an error if: + /// - Server creation fails (e.g., port already in use) + /// - NATS mode is selected but NATS client is not available + /// - Configuration is invalid (e.g., malformed bind address) + pub async fn server(&self) -> Result> { + let server = self + .server + .get_or_try_init(async { self.create_server().await }) + .await?; + + Ok(server.clone()) + } + + /// Create a new request plane client + /// + /// Clients are lightweight and not cached. Each call creates a new client instance. + /// + /// # Returns + /// + /// Returns a trait object that abstracts over HTTP/TCP/NATS implementations. + /// + /// # Errors + /// + /// Returns an error if: + /// - Client creation fails (e.g., invalid configuration) + /// - NATS mode is selected but NATS client is not available + pub fn create_client(&self) -> Result> { + match self.mode { + RequestPlaneMode::Http => self.create_http_client(), + RequestPlaneMode::Tcp => self.create_tcp_client(), + RequestPlaneMode::Nats => self.create_nats_client(), + } + } + + /// Get the current request plane mode + /// + /// This is provided primarily for logging and debugging purposes. + /// Application logic should not branch on mode - use trait objects instead. + pub fn mode(&self) -> RequestPlaneMode { + self.mode + } + + // ============================================================================ + // PRIVATE: Server Creation + // ============================================================================ + + async fn create_server(&self) -> Result> { + match self.mode { + RequestPlaneMode::Http => self.create_http_server().await, + RequestPlaneMode::Tcp => self.create_tcp_server().await, + RequestPlaneMode::Nats => self.create_nats_server().await, + } + } + + async fn create_http_server(&self) -> Result> { + use super::ingress::http_endpoint::SharedHttpServer; + + let bind_addr = format!("{}:{}", self.config.http_host, self.config.http_port) + .parse() + .map_err(|e| anyhow::anyhow!("Invalid HTTP bind address: {}", e))?; + + tracing::info!( + bind_addr = %bind_addr, + rpc_root = %self.config.http_rpc_root, + "Creating HTTP request plane server" + ); + + let server = SharedHttpServer::new(bind_addr, self.cancellation_token.clone()); + + // Start server in background + let server_clone = server.clone(); + tokio::spawn(async move { + if let Err(e) = server_clone.start().await { + tracing::error!("HTTP request plane server error: {}", e); + } + }); + + Ok(server as Arc) + } + + async fn create_tcp_server(&self) -> Result> { + use super::ingress::shared_tcp_endpoint::SharedTcpServer; + + let bind_addr = format!("{}:{}", self.config.tcp_host, self.config.tcp_port) + .parse() + .map_err(|e| anyhow::anyhow!("Invalid TCP bind address: {}", e))?; + + tracing::info!( + bind_addr = %bind_addr, + "Creating TCP request plane server" + ); + + let server = SharedTcpServer::new(bind_addr, self.cancellation_token.clone()); + + // Start server in background + let server_clone = server.clone(); + tokio::spawn(async move { + if let Err(e) = server_clone.start().await { + tracing::error!("TCP request plane server error: {}", e); + } + }); + + Ok(server as Arc) + } + + async fn create_nats_server(&self) -> Result> { + use super::ingress::nats_server::NatsMultiplexedServer; + + let nats_client = self + .config + .nats_client + .as_ref() + .ok_or_else(|| anyhow::anyhow!("NATS client required for NATS mode"))?; + + tracing::info!("Creating NATS request plane server"); + + Ok(NatsMultiplexedServer::new( + nats_client.clone(), + self.component_registry.clone(), + self.cancellation_token.clone(), + ) as Arc) + } + + // ============================================================================ + // PRIVATE: Client Creation + // ============================================================================ + + fn create_http_client(&self) -> Result> { + use super::egress::http_router::HttpRequestClient; + + tracing::debug!("Creating HTTP request plane client with config from NetworkManager"); + Ok(Arc::new(HttpRequestClient::with_config( + self.config.http_client_config.clone(), + )?)) + } + + fn create_tcp_client(&self) -> Result> { + use super::egress::tcp_client::TcpRequestClient; + + tracing::debug!("Creating TCP request plane client with config from NetworkManager"); + Ok(Arc::new(TcpRequestClient::with_config( + self.config.tcp_client_config.clone(), + )?)) + } + + fn create_nats_client(&self) -> Result> { + use super::egress::nats_client::NatsRequestClient; + + let nats_client = self + .config + .nats_client + .as_ref() + .ok_or_else(|| anyhow::anyhow!("NATS client required for NATS mode"))?; + + tracing::debug!("Creating NATS request plane client"); + Ok(Arc::new(NatsRequestClient::new(nats_client.clone()))) + } +} diff --git a/lib/runtime/src/runtime.rs b/lib/runtime/src/runtime.rs index ec7c28398..e03ba5aaa 100644 --- a/lib/runtime/src/runtime.rs +++ b/lib/runtime/src/runtime.rs @@ -27,7 +27,7 @@ use tokio::{signal, sync::Mutex, task::JoinHandle}; pub use tokio_util::sync::CancellationToken; /// Types of Tokio runtimes that can be used to construct a Dynamo [Runtime]. -#[derive(Clone)] +#[derive(Clone, Debug)] enum RuntimeType { Shared(Arc), External(tokio::runtime::Handle), @@ -339,12 +339,3 @@ impl RuntimeType { } } } - -impl std::fmt::Debug for RuntimeType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - RuntimeType::External(_) => write!(f, "RuntimeType::External"), - RuntimeType::Shared(_) => write!(f, "RuntimeType::Shared"), - } - } -} diff --git a/lib/runtime/src/system_status_server.rs b/lib/runtime/src/system_status_server.rs index d44ef83d2..92817c734 100644 --- a/lib/runtime/src/system_status_server.rs +++ b/lib/runtime/src/system_status_server.rs @@ -798,9 +798,7 @@ mod integration_tests { endpoint: "health".to_string(), namespace: "test_namespace".to_string(), instance_id: 1, - transport: crate::component::TransportType::NatsTcp( - endpoint.to_string(), - ), + transport: crate::component::TransportType::Nats(endpoint.to_string()), }, health_check_payload.clone(), ); diff --git a/lib/runtime/src/transports/nats.rs b/lib/runtime/src/transports/nats.rs index 6a6306d3f..eedc1ab4a 100644 --- a/lib/runtime/src/transports/nats.rs +++ b/lib/runtime/src/transports/nats.rs @@ -400,12 +400,6 @@ impl Default for NatsAuth { } } -/// Is this file name / url in the NATS object store? -/// Checks the name only, does not go to the store. -pub fn is_nats_url(s: &str) -> bool { - s.starts_with(URL_PREFIX) -} - /// Extract NATS bucket and key from a nats URL of the form: /// nats://host[:port]/bucket/key pub fn url_to_bucket_and_key(url: &Url) -> anyhow::Result<(String, String)> { diff --git a/lib/runtime/src/utils.rs b/lib/runtime/src/utils.rs index 62d7e0f46..a02fa93f0 100644 --- a/lib/runtime/src/utils.rs +++ b/lib/runtime/src/utils.rs @@ -4,6 +4,7 @@ pub use tokio::time::{Duration, Instant}; pub mod graceful_shutdown; +pub mod ip_resolver; pub mod leader_worker_barrier; pub mod pool; pub mod stream; @@ -12,3 +13,4 @@ pub mod tasks; pub mod typed_prefix_watcher; pub use graceful_shutdown::GracefulShutdownTracker; +pub use ip_resolver::{get_http_rpc_host_from_env, get_tcp_rpc_host_from_env}; diff --git a/lib/runtime/src/utils/ip_resolver.rs b/lib/runtime/src/utils/ip_resolver.rs new file mode 100644 index 000000000..576c4b27d --- /dev/null +++ b/lib/runtime/src/utils/ip_resolver.rs @@ -0,0 +1,157 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! IP resolution utilities for getting local IP addresses with fallback support + +use crate::pipeline::network::tcp::server::{DefaultIpResolver, IpResolver}; +use local_ip_address::Error; +use std::net::IpAddr; + +/// Get the local IP address for HTTP RPC host binding, using IpResolver with fallback to 127.0.0.1 +/// +/// This function attempts to resolve the local IP address using the provided resolver. +/// If resolution fails, it falls back to 127.0.0.1 (localhost). +/// +/// # Arguments +/// * `resolver` - An implementation of IpResolver trait for getting local IP addresses +/// +/// # Returns +/// A string representation of the resolved IP address +pub fn get_http_rpc_host_with_resolver(resolver: R) -> String { + let resolved_ip = resolver.local_ip().or_else(|err| match err { + Error::LocalIpAddressNotFound => resolver.local_ipv6(), + _ => Err(err), + }); + + match resolved_ip { + Ok(addr) => addr, + Err(Error::LocalIpAddressNotFound) => IpAddr::from([127, 0, 0, 1]), + Err(_) => IpAddr::from([127, 0, 0, 1]), // Fallback for any other error + } + .to_string() +} + +/// Get the local IP address for HTTP RPC host binding using the default resolver +/// +/// This is a convenience function that uses the DefaultIpResolver. +/// It follows the same logic as the TcpStreamServer for IP resolution. +/// +/// # Returns +/// A string representation of the resolved IP address, with fallback to "127.0.0.1" +pub fn get_http_rpc_host() -> String { + get_http_rpc_host_with_resolver(DefaultIpResolver) +} + +/// Get the HTTP RPC host from environment variable or resolve local IP as fallback +/// +/// This function checks the DYN_HTTP_RPC_HOST environment variable first. +/// If not set, it uses IP resolution to determine the local IP address. +/// +/// # Returns +/// A string representation of the HTTP RPC host address +pub fn get_http_rpc_host_from_env() -> String { + std::env::var("DYN_HTTP_RPC_HOST").unwrap_or_else(|_| get_http_rpc_host()) +} + +/// Get the TCP RPC host from environment variable or resolve local IP as fallback +/// +/// This function checks the DYN_TCP_RPC_HOST environment variable first. +/// If not set, it uses IP resolution to determine the local IP address. +/// +/// # Returns +/// A string representation of the TCP RPC host address +pub fn get_tcp_rpc_host_from_env() -> String { + std::env::var("DYN_TCP_RPC_HOST").unwrap_or_else(|_| get_http_rpc_host()) +} + +#[cfg(test)] +mod tests { + use super::*; + use local_ip_address::Error; + + // Mock resolver for testing + struct MockIpResolver { + ipv4_result: Result, + ipv6_result: Result, + } + + impl IpResolver for MockIpResolver { + fn local_ip(&self) -> Result { + match &self.ipv4_result { + Ok(addr) => Ok(*addr), + Err(Error::LocalIpAddressNotFound) => Err(Error::LocalIpAddressNotFound), + Err(_) => Err(Error::LocalIpAddressNotFound), // Simplify for testing + } + } + + fn local_ipv6(&self) -> Result { + match &self.ipv6_result { + Ok(addr) => Ok(*addr), + Err(Error::LocalIpAddressNotFound) => Err(Error::LocalIpAddressNotFound), + Err(_) => Err(Error::LocalIpAddressNotFound), // Simplify for testing + } + } + } + + #[test] + fn test_get_http_rpc_host_with_successful_ipv4() { + let resolver = MockIpResolver { + ipv4_result: Ok(IpAddr::from([192, 168, 1, 100])), + ipv6_result: Ok(IpAddr::from([0, 0, 0, 0, 0, 0, 0, 1])), + }; + + let result = get_http_rpc_host_with_resolver(resolver); + assert_eq!(result, "192.168.1.100"); + } + + #[test] + fn test_get_http_rpc_host_with_ipv4_fail_ipv6_success() { + let resolver = MockIpResolver { + ipv4_result: Err(Error::LocalIpAddressNotFound), + ipv6_result: Ok(IpAddr::from([0x2001, 0xdb8, 0, 0, 0, 0, 0, 1])), + }; + + let result = get_http_rpc_host_with_resolver(resolver); + assert_eq!(result, "2001:db8::1"); + } + + #[test] + fn test_get_http_rpc_host_with_both_fail() { + let resolver = MockIpResolver { + ipv4_result: Err(Error::LocalIpAddressNotFound), + ipv6_result: Err(Error::LocalIpAddressNotFound), + }; + + let result = get_http_rpc_host_with_resolver(resolver); + assert_eq!(result, "127.0.0.1"); + } + + #[test] + fn test_get_http_rpc_host_from_env_with_env_var() { + // Set environment variable + unsafe { + std::env::set_var("DYN_HTTP_RPC_HOST", "10.0.0.1"); + } + + let result = get_http_rpc_host_from_env(); + assert_eq!(result, "10.0.0.1"); + + // Clean up + unsafe { + std::env::remove_var("DYN_HTTP_RPC_HOST"); + } + } + + #[test] + fn test_get_http_rpc_host_from_env_without_env_var() { + // Note: We can't reliably unset environment variables in tests + // This test assumes DYN_HTTP_RPC_HOST is not set to a specific test value + + let result = get_http_rpc_host_from_env(); + // Should return some IP address (either resolved or fallback) + assert!(!result.is_empty()); + + // Should be a valid IP address + let _: IpAddr = result.parse().expect("Should be a valid IP address"); + } +} diff --git a/tests/serve/test_vllm.py b/tests/serve/test_vllm.py index ff3cbcccb..264c6e670 100644 --- a/tests/serve/test_vllm.py +++ b/tests/serve/test_vllm.py @@ -48,6 +48,30 @@ vllm_configs = { metric_payload_default(min_num_requests=6, backend="vllm"), ], ), + "agg-request-plane-tcp": VLLMConfig( + name="agg-request-plane-tcp", + directory=vllm_dir, + script_name="agg_request_planes.sh", + marks=[pytest.mark.gpu_1], + model="Qwen/Qwen3-0.6B", + script_args=["--tcp"], + request_payloads=[ + chat_payload_default(), + completion_payload_default(), + ], + ), + "agg-request-plane-http": VLLMConfig( + name="agg-request-plane-http", + directory=vllm_dir, + script_name="agg_request_planes.sh", + marks=[pytest.mark.gpu_1], + model="Qwen/Qwen3-0.6B", + script_args=["--http"], + request_payloads=[ + chat_payload_default(), + completion_payload_default(), + ], + ), "agg-router": VLLMConfig( name="agg-router", directory=vllm_dir,