From e0c5ed2a449cd5b90923ce75db93d17095752652 Mon Sep 17 00:00:00 2001 From: Patrick Siegl <3261314+psiegl@users.noreply.github.com> Date: Fri, 14 Nov 2025 19:04:17 +0100 Subject: [PATCH] Add zenoh as transport --- Cargo.lock | 2539 ++++++++++++++--- Cargo.toml | 14 +- ZENOH.md | 157 + crates/cli/Cargo.toml | 4 +- crates/cli/src/lib.rs | 2 + crates/cli/src/zenoh.rs | 10 + crates/test/Cargo.toml | 5 +- crates/test/src/lib.rs | 51 + crates/transport-zenoh/Cargo.toml | 33 + crates/transport-zenoh/src/lib.rs | 1439 ++++++++++ crates/wasmtime-cli/Cargo.toml | 2 + crates/wasmtime-cli/src/lib.rs | 14 +- crates/wasmtime-cli/src/zenoh.rs | 98 + .../rust/hello-component-zclient/Cargo.toml | 13 + .../rust/hello-component-zclient/src/main.rs | 19 + .../hello-component-zclient/wit/deps.lock | 4 + .../hello-component-zclient/wit/deps.toml | 1 + .../wit/deps/hello/hello.wit | 13 + .../hello-component-zclient/wit/world.wit | 5 + examples/rust/hello-zenoh-client/Cargo.toml | 27 + examples/rust/hello-zenoh-client/src/main.rs | 81 + .../rust/hello-zenoh-client/wit/deps.lock | 4 + .../rust/hello-zenoh-client/wit/deps.toml | 1 + .../wit/deps/hello/hello.wit | 43 + .../rust/hello-zenoh-client/wit/world.wit | 5 + examples/rust/hello-zenoh-server/Cargo.toml | 34 + examples/rust/hello-zenoh-server/src/main.rs | 101 + .../rust/hello-zenoh-server/wit/deps.lock | 4 + .../rust/hello-zenoh-server/wit/deps.toml | 1 + .../wit/deps/hello/hello.wit | 43 + .../rust/hello-zenoh-server/wit/world.wit | 5 + examples/rust/streams-zenoh-client/Cargo.toml | 35 + .../rust/streams-zenoh-client/src/main.rs | 87 + .../rust/streams-zenoh-client/wit/deps.lock | 4 + .../rust/streams-zenoh-client/wit/deps.toml | 1 + .../wit/deps/streams/streams.wit | 17 + .../rust/streams-zenoh-client/wit/world.wit | 5 + examples/rust/streams-zenoh-server/Cargo.toml | 39 + .../rust/streams-zenoh-server/src/main.rs | 119 + .../rust/streams-zenoh-server/wit/deps.lock | 4 + .../rust/streams-zenoh-server/wit/deps.toml | 1 + .../wit/deps/streams/streams.wit | 17 + .../rust/streams-zenoh-server/wit/world.wit | 5 + tests/rust.rs | 42 + zenoh_conf.json5 | 7 + zenoh_conf.json5.template | 6 + 46 files changed, 4815 insertions(+), 346 deletions(-) create mode 100644 ZENOH.md create mode 100644 crates/cli/src/zenoh.rs create mode 100644 crates/transport-zenoh/Cargo.toml create mode 100644 crates/transport-zenoh/src/lib.rs create mode 100644 crates/wasmtime-cli/src/zenoh.rs create mode 100644 examples/rust/hello-component-zclient/Cargo.toml create mode 100644 examples/rust/hello-component-zclient/src/main.rs create mode 100644 examples/rust/hello-component-zclient/wit/deps.lock create mode 100644 examples/rust/hello-component-zclient/wit/deps.toml create mode 100644 examples/rust/hello-component-zclient/wit/deps/hello/hello.wit create mode 100644 examples/rust/hello-component-zclient/wit/world.wit create mode 100644 examples/rust/hello-zenoh-client/Cargo.toml create mode 100644 examples/rust/hello-zenoh-client/src/main.rs create mode 100644 examples/rust/hello-zenoh-client/wit/deps.lock create mode 100644 examples/rust/hello-zenoh-client/wit/deps.toml create mode 100644 examples/rust/hello-zenoh-client/wit/deps/hello/hello.wit create mode 100644 examples/rust/hello-zenoh-client/wit/world.wit create mode 100644 examples/rust/hello-zenoh-server/Cargo.toml create mode 100644 examples/rust/hello-zenoh-server/src/main.rs create mode 100644 examples/rust/hello-zenoh-server/wit/deps.lock create mode 100644 examples/rust/hello-zenoh-server/wit/deps.toml create mode 100644 examples/rust/hello-zenoh-server/wit/deps/hello/hello.wit create mode 100644 examples/rust/hello-zenoh-server/wit/world.wit create mode 100644 examples/rust/streams-zenoh-client/Cargo.toml create mode 100644 examples/rust/streams-zenoh-client/src/main.rs create mode 100644 examples/rust/streams-zenoh-client/wit/deps.lock create mode 100644 examples/rust/streams-zenoh-client/wit/deps.toml create mode 100644 examples/rust/streams-zenoh-client/wit/deps/streams/streams.wit create mode 100644 examples/rust/streams-zenoh-client/wit/world.wit create mode 100644 examples/rust/streams-zenoh-server/Cargo.toml create mode 100644 examples/rust/streams-zenoh-server/src/main.rs create mode 100644 examples/rust/streams-zenoh-server/wit/deps.lock create mode 100644 examples/rust/streams-zenoh-server/wit/deps.toml create mode 100644 examples/rust/streams-zenoh-server/wit/deps/streams/streams.wit create mode 100644 examples/rust/streams-zenoh-server/wit/world.wit create mode 100644 zenoh_conf.json5 create mode 100644 zenoh_conf.json5.template diff --git a/Cargo.lock b/Cargo.lock index 59855ec95..80d5d3b6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,36 @@ dependencies = [ "gimli", ] +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -99,9 +129,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] name = "arbitrary" @@ -111,9 +141,24 @@ checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "arc-swap" -version = "1.7.1" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" +dependencies = [ + "rustversion", +] + +[[package]] +name = "array-init" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + +[[package]] +name = "ascii" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" [[package]] name = "asn1-rs" @@ -127,7 +172,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", ] @@ -139,7 +184,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", "synstructure", ] @@ -151,7 +196,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -199,7 +244,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -287,9 +332,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.1" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "beef" @@ -305,9 +350,12 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] [[package]] name = "block-buffer" @@ -320,13 +368,19 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" dependencies = [ "allocator-api2", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.11.1" @@ -356,7 +410,7 @@ checksum = "20a158160765c6a7d0d8c072a53d772e4cb243f38b04bfcf6b4939cfbe7482e7" dependencies = [ "cap-primitives", "cap-std", - "rustix 1.0.8", + "rustix 1.1.3", "smallvec", ] @@ -372,7 +426,7 @@ dependencies = [ "io-lifetimes", "ipnet", "maybe-owned", - "rustix 1.0.8", + "rustix 1.1.3", "rustix-linux-procfs", "windows-sys 0.59.0", "winx", @@ -397,7 +451,7 @@ dependencies = [ "cap-primitives", "io-extras", "io-lifetimes", - "rustix 1.0.8", + "rustix 1.1.3", ] [[package]] @@ -410,7 +464,7 @@ dependencies = [ "cap-primitives", "iana-time-zone", "once_cell", - "rustix 1.0.8", + "rustix 1.1.3", "winx", ] @@ -422,9 +476,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.49" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "jobserver", @@ -450,6 +504,24 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chrono" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "chunked_transfer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" + [[package]] name = "ciborium" version = "0.2.2" @@ -477,11 +549,21 @@ dependencies = [ "half", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" -version = "4.5.57" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a" +checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" dependencies = [ "clap_builder", "clap_derive", @@ -489,9 +571,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.57" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238" +checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" dependencies = [ "anstream", "anstyle", @@ -508,14 +590,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "cobs" @@ -523,7 +605,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -540,6 +622,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colored" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "combine" version = "4.6.7" @@ -554,12 +645,41 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -789,6 +909,28 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -808,6 +950,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -853,14 +1004,49 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.116", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.116", ] [[package]] name = "data-encoding" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "debugid" @@ -898,9 +1084,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" dependencies = [ "powerfmt", "serde_core", @@ -914,6 +1100,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -926,6 +1113,37 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.5.2", + "windows-sys 0.61.2", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -933,7 +1151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.6", "winapi", ] @@ -945,9 +1163,15 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "ed25519" version = "2.2.3" @@ -988,6 +1212,12 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -999,18 +1229,18 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" dependencies = [ "log", ] [[package]] name = "env_logger" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" dependencies = [ "anstream", "anstyle", @@ -1034,6 +1264,27 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -1053,7 +1304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix 1.0.8", + "rustix 1.1.3", "windows-sys 0.59.0", ] @@ -1065,9 +1316,37 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "spin 0.9.8", +] [[package]] name = "fnv" @@ -1081,6 +1360,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1097,15 +1382,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" dependencies = [ "io-lifetimes", - "rustix 1.0.8", + "rustix 1.1.3", "windows-sys 0.59.0", ] [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -1118,9 +1403,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -1128,15 +1413,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -1145,38 +1430,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -1186,7 +1471,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1196,7 +1480,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25234f20a3ec0a962a61770cfe39ecf03cb529a6e474ad8cff025ed497eda557" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "debugid", "rustc-hash", "serde", @@ -1216,9 +1500,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -1241,6 +1525,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "gimli" version = "0.32.3" @@ -1248,10 +1545,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" dependencies = [ "fallible-iterator", - "indexmap", + "indexmap 2.13.0", "stable_deref_trait", ] +[[package]] +name = "git-version" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" +dependencies = [ + "git-version-macro", +] + +[[package]] +name = "git-version-macro" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.116", +] + [[package]] name = "h2" version = "0.3.27" @@ -1264,7 +1581,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -1273,9 +1590,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", @@ -1283,7 +1600,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.4.0", - "indexmap", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -1301,13 +1618,29 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + [[package]] name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash", + "foldhash 0.1.5", "serde", ] @@ -1316,6 +1649,21 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hdrhistogram" +version = "7.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" +dependencies = [ + "byteorder", + "num-traits", +] [[package]] name = "heck" @@ -1367,7 +1715,14 @@ dependencies = [ ] [[package]] -name = "hello-http-tcp-proxy" +name = "hello-component-zclient" +version = "0.1.0" +dependencies = [ + "wit-bindgen 0.45.1", +] + +[[package]] +name = "hello-http-tcp-proxy" version = "0.1.0" dependencies = [ "anyhow", @@ -1422,7 +1777,7 @@ dependencies = [ "futures", "quinn", "rcgen", - "rustls 0.23.35", + "rustls 0.23.36", "tokio", "tracing", "tracing-subscriber", @@ -1441,7 +1796,7 @@ dependencies = [ "futures", "quinn", "rcgen", - "rustls 0.23.35", + "rustls 0.23.36", "tokio", "tracing", "tracing-subscriber", @@ -1482,7 +1837,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", - "rustls 0.23.35", + "rustls 0.23.36", "tokio", "tracing-subscriber", "url", @@ -1500,7 +1855,7 @@ dependencies = [ "clap", "futures", "rcgen", - "rustls 0.23.35", + "rustls 0.23.36", "tokio", "tracing", "tracing-subscriber", @@ -1510,12 +1865,106 @@ dependencies = [ "wtransport", ] +[[package]] +name = "hello-zenoh-client" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "tokio", + "tracing-subscriber", + "url", + "wit-bindgen-wrpc", + "wrpc-transport-zenoh", + "zenoh", +] + +[[package]] +name = "hello-zenoh-server" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "futures", + "hotpath", + "tokio", + "tracing", + "tracing-subscriber", + "url", + "wit-bindgen-wrpc", + "wrpc-transport-zenoh", + "zenoh", +] + [[package]] name = "hermit-abi" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "hotpath" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3554f9fc054c95f68e9f31196ca3aa77c6ce299f2e5877788e68168d01b7cfab" +dependencies = [ + "arc-swap", + "base64 0.22.1", + "cfg-if", + "clap", + "colored", + "crossbeam-channel", + "eyre", + "futures-util", + "hdrhistogram", + "hotpath-macros", + "libc", + "mach2 0.6.0", + "pin-project-lite", + "prettytable-rs", + "quanta", + "regex", + "serde", + "serde_json", + "tiny_http", + "tokio", +] + +[[package]] +name = "hotpath-macros" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8cf5fa828dd9b99de52bb85f9027c0d5205971cb3c45842b4bf6d7c7f6c679" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.116", +] + [[package]] name = "httlib-huffman" version = "0.3.4" @@ -1635,7 +2084,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2 0.4.12", + "h2 0.4.13", "http 1.4.0", "http-body 1.0.1", "httparse", @@ -1650,12 +2099,11 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "bytes", - "futures-core", "http 1.4.0", "http-body 1.0.1", "hyper 1.8.1", @@ -1666,9 +2114,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1736,9 +2184,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -1750,9 +2198,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" @@ -1771,9 +2219,15 @@ dependencies = [ [[package]] name = "id-arena" -version = "2.2.1" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" @@ -1796,11 +2250,28 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indenter" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -1808,6 +2279,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "io-extras" version = "0.18.4" @@ -1830,6 +2310,15 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + [[package]] name = "is-terminal" version = "0.4.17" @@ -1876,9 +2365,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "ittapi" @@ -1934,14 +2423,43 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keyed-set" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d255a6b6ecd77bb93ce91de984d7039bff7503f500eb4851a1269732f22baf" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1967,23 +2485,33 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.178" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "libc", ] @@ -1995,9 +2523,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" @@ -2005,6 +2533,15 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.29" @@ -2032,7 +2569,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax", - "syn", + "syn 2.0.116", ] [[package]] @@ -2050,6 +2587,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "lz4_flex" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a" +dependencies = [ + "twox-hash", +] + [[package]] name = "mach2" version = "0.4.3" @@ -2059,6 +2605,12 @@ dependencies = [ "libc", ] +[[package]] +name = "mach2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" + [[package]] name = "matchers" version = "0.2.0" @@ -2082,9 +2634,9 @@ checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memfd" @@ -2092,7 +2644,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" dependencies = [ - "rustix 1.0.8", + "rustix 1.1.3", ] [[package]] @@ -2117,6 +2669,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "mio" version = "1.1.1" @@ -2128,6 +2690,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom 0.2.17", +] + [[package]] name = "nkeys" version = "0.4.5" @@ -2137,12 +2708,18 @@ dependencies = [ "data-encoding", "ed25519", "ed25519-dalek", - "getrandom 0.2.16", + "getrandom 0.2.17", "log", "rand 0.8.5", "signatory", ] +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + [[package]] name = "nom" version = "7.1.3" @@ -2153,6 +2730,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonempty-collections" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e216d0e8cf9d54fa66e5780f6e1d5dc96d1c1b3c25aeba3b6758548bcbbd8b9d" +dependencies = [ + "serde", +] + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -2205,6 +2791,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "object" version = "0.37.3" @@ -2213,7 +2809,7 @@ checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "crc32fast", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.13.0", "memchr", ] @@ -2256,6 +2852,53 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pem" version = "3.0.6" @@ -2281,6 +2924,104 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.116", +] + +[[package]] +name = "pest_meta" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +dependencies = [ + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "serde", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.116", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -2298,7 +3039,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -2357,11 +3098,43 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "pnet_base" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc190d4067df16af3aba49b3b74c469e611cad6314676eaf1157f31aa0fb2f7" +dependencies = [ + "no-std-net", +] + +[[package]] +name = "pnet_datalink" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79e70ec0be163102a332e1d2d5586d362ad76b01cec86f830241f2b6452a7b7" +dependencies = [ + "ipnetwork", + "libc", + "pnet_base", + "pnet_sys", + "winapi", +] + +[[package]] +name = "pnet_sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d4643d3d4db6b08741050c2f3afa9a892c4244c085a72fcda93c9c2c9a00f4b" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "postcard" @@ -2406,14 +3179,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.116", +] + +[[package]] +name = "prettytable-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" +dependencies = [ + "encode_unicode", + "is-terminal", + "lazy_static", + "term", + "unicode-width 0.1.14", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -2438,7 +3233,22 @@ checksum = "2cf194f5b1a415ef3a44ee35056f4009092cc4038a9f7e3c7c1e392f48ee7dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", +] + +[[package]] +name = "quanta" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.1+wasi-snapshot-preview1", + "web-sys", + "winapi", ] [[package]] @@ -2453,9 +3263,9 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.35", - "socket2 0.6.1", - "thiserror 2.0.17", + "rustls 0.23.36", + "socket2 0.6.2", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -2473,11 +3283,11 @@ dependencies = [ "rand 0.9.2", "ring", "rustc-hash", - "rustls 0.23.35", + "rustls 0.23.36", "rustls-pki-types", "rustls-platform-verifier", "slab", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -2492,16 +3302,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.1", + "socket2 0.6.2", "tracing", "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -2530,7 +3340,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -2550,7 +3360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -2559,18 +3369,27 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.11.0", +] + [[package]] name = "rayon" version = "1.11.0" @@ -2636,22 +3455,62 @@ dependencies = [ "url", ] +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + [[package]] name = "redox_users" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "libredox", "thiserror 1.0.69", ] +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.116", +] + [[package]] name = "regalloc2" -version = "0.13.3" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e249c660440317032a71ddac302f25f1d5dff387667bcc3978d1f77aa31ac34" +checksum = "08effbc1fa53aaebff69521a5c05640523fab037b34a4a2c109506bc938246fa" dependencies = [ "allocator-api2", "bumpalo", @@ -2663,9 +3522,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -2675,9 +3534,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -2686,9 +3545,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "reqwest" @@ -2748,17 +3607,41 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", ] +[[package]] +name = "ringbuffer-spsc" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3e7aa0a681b232e7cd7f856a53b10603df88ca74b79a8d8088845185492e35" +dependencies = [ + "array-init", + "crossbeam", +] + +[[package]] +name = "ron" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32" +dependencies = [ + "bitflags 2.11.0", + "once_cell", + "serde", + "serde_derive", + "typeid", + "unicode-ident", +] + [[package]] name = "rustc-demangle" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" @@ -2790,7 +3673,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2799,15 +3682,15 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", ] [[package]] @@ -2817,7 +3700,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" dependencies = [ "once_cell", - "rustix 1.0.8", + "rustix 1.1.3", ] [[package]] @@ -2836,15 +3719,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.8", + "rustls-webpki 0.103.9", "subtle", "zeroize", ] @@ -2855,7 +3738,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ - "openssl-probe", + "openssl-probe 0.1.6", "rustls-pemfile", "rustls-pki-types", "schannel", @@ -2864,14 +3747,14 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe", + "openssl-probe 0.2.1", "rustls-pki-types", "schannel", - "security-framework 3.5.1", + "security-framework 3.6.0", ] [[package]] @@ -2885,9 +3768,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "web-time", "zeroize", @@ -2904,11 +3787,11 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.35", - "rustls-native-certs 0.8.2", + "rustls 0.23.36", + "rustls-native-certs 0.8.3", "rustls-platform-verifier-android", - "rustls-webpki 0.103.8", - "security-framework 3.5.1", + "rustls-webpki 0.103.9", + "security-framework 3.6.0", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -2933,9 +3816,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "ring", "rustls-pki-types", @@ -2950,9 +3833,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -2963,6 +3846,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scc" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" +dependencies = [ + "sdd", +] + [[package]] name = "schannel" version = "0.1.28" @@ -2972,13 +3864,73 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "either", + "ref-cast", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.116", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sdd" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -2987,11 +3939,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.5.1" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -3000,9 +3952,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "321c8673b092a9a42605034a9879d73cb79101ed5fd117bc9a597b89b4e9e61a" dependencies = [ "core-foundation-sys", "libc", @@ -3051,20 +4003,31 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.116", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -3084,7 +4047,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -3097,15 +4060,85 @@ dependencies = [ ] [[package]] -name = "serde_urlencoded" -version = "0.7.1" +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.13.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.116", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.13.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "serial_test" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0b343e184fc3b7bb44dff0705fffcf4b3756ba6aff420dddd8b24ca145e555" +dependencies = [ + "futures-executor", + "futures-util", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +checksum = "6f50427f258fb77356e4cd4aa0e87e2bd2c66dbcee41dc405282cae2bfc26c83" dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", + "proc-macro2", + "quote", + "syn 2.0.116", ] [[package]] @@ -3119,6 +4152,22 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -3128,6 +4177,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shellexpand" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1fdf65dd6331831494dd616b30351c38e96e45921a27745cf98490458b90bb" +dependencies = [ + "dirs", +] + [[package]] name = "shlex" version = "1.3.0" @@ -3136,10 +4194,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.7" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -3165,11 +4224,23 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -3192,14 +4263,29 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" + [[package]] name = "spki" version = "0.7.3" @@ -3210,6 +4296,41 @@ dependencies = [ "der", ] +[[package]] +name = "stabby" +version = "72.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976399a0c48ea769ef7f5dc303bb88240ab8d84008647a6b2303eced3dab3945" +dependencies = [ + "rustversion", + "stabby-abi", +] + +[[package]] +name = "stabby-abi" +version = "72.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b54832a9a1f92a0e55e74a5c0332744426edc515bb3fbad82f10b874a87f0d" +dependencies = [ + "rustc_version", + "rustversion", + "sha2-const-stable", + "stabby-macros", +] + +[[package]] +name = "stabby-macros" +version = "72.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a768b1e51e4dbfa4fa52ae5c01241c0a41e2938fdffbb84add0c8238092f9091" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "rand 0.8.5", + "syn 1.0.109", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -3261,7 +4382,7 @@ dependencies = [ "futures", "quinn", "rcgen", - "rustls 0.23.35", + "rustls 0.23.36", "tokio", "tokio-stream", "tracing", @@ -3282,7 +4403,7 @@ dependencies = [ "futures", "quinn", "rcgen", - "rustls 0.23.35", + "rustls 0.23.36", "tokio", "tracing", "tracing-subscriber", @@ -3292,6 +4413,42 @@ dependencies = [ "wrpc-transport-quic", ] +[[package]] +name = "streams-zenoh-client" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "clap", + "futures", + "tokio", + "tokio-stream", + "tracing", + "tracing-subscriber", + "url", + "wit-bindgen-wrpc", + "wrpc-transport-zenoh", + "zenoh", +] + +[[package]] +name = "streams-zenoh-server" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "clap", + "futures", + "hotpath", + "tokio", + "tracing", + "tracing-subscriber", + "url", + "wit-bindgen-wrpc", + "wrpc-transport-zenoh", + "zenoh", +] + [[package]] name = "strsim" version = "0.11.1" @@ -3306,9 +4463,20 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.111" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", @@ -3335,7 +4503,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -3365,7 +4533,7 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc4592f674ce18521c2a81483873a49596655b179f71c5e05d10c1fe66c78745" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cap-fs-ext", "cap-std", "fd-lock", @@ -3377,22 +4545,33 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" +checksum = "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba" [[package]] name = "tempfile" -version = "3.23.0" +version = "3.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ "fastrand", "once_cell", - "rustix 1.0.8", + "rustix 1.1.3", "windows-sys 0.61.2", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -3430,7 +4609,7 @@ checksum = "be35209fd0781c5401458ab66e4f98accf63553e8fae7425503e92fdd319783b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -3444,11 +4623,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -3459,18 +4638,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -3513,6 +4692,18 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny_http" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82" +dependencies = [ + "ascii", + "chunked_transfer", + "httpdate", + "log", +] + [[package]] name = "tinystr" version = "0.8.2" @@ -3548,18 +4739,29 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "token-cell" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb48920ae769b58126c8c93269805011c793201f95fde28b479b81a9a531bbde" +dependencies = [ + "paste", + "portable-atomic", + "rustversion", +] + [[package]] name = "tokio" -version = "1.48.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ "bytes", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2 0.6.2", "tokio-macros", "windows-sys 0.61.2", ] @@ -3572,7 +4774,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -3592,15 +4794,15 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.35", + "rustls 0.23.36", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -3610,14 +4812,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.17" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", + "futures-util", "pin-project-lite", "tokio", ] @@ -3645,11 +4848,11 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.10+spec-1.1.0" +version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0825052159284a1a8b4d6c0c86cbc801f2da5afd2b225fa548c72f2e74002f48" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ - "indexmap", + "indexmap 2.13.0", "serde_core", "serde_spanned", "toml_datetime", @@ -3667,11 +4870,23 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime", + "toml_parser", + "winnow", +] + [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.0.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc" dependencies = [ "winnow", ] @@ -3684,9 +4899,9 @@ checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -3699,11 +4914,11 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "bytes", "futures-core", "futures-util", @@ -3737,9 +4952,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -3755,14 +4970,14 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] name = "tracing-core" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -3779,6 +4994,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.22" @@ -3789,12 +5014,15 @@ dependencies = [ "nu-ansi-term", "once_cell", "regex-automata", + "serde", + "serde_json", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", + "tracing-serde", ] [[package]] @@ -3813,23 +5041,61 @@ dependencies = [ "tokio", ] +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "typenum" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uhlc" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62a645e3e4e6c85b7abe49b086aa3204119431f42b6123b0070419fb6e9d24e" +dependencies = [ + "humantime", + "lazy_static", + "log", + "rand 0.8.5", + "serde", + "spin 0.10.0", +] + [[package]] name = "unicase" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" + +[[package]] +name = "unicode-width" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" @@ -3843,17 +5109,34 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unzip-n" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b5bb2756c16fb66f80cfbf5fb0e0c09a7001e739f453c9ec241b9c8b1556fda" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.116", +] + [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -3885,21 +5168,51 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.1", "js-sys", "wasm-bindgen", ] +[[package]] +name = "validated_struct" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869a93e8a7286e339e1128630051d82babbcd75d585975af07b9f3327220e60e" +dependencies = [ + "json5", + "serde", + "serde_json", + "validated_struct_macros", +] + +[[package]] +name = "validated_struct_macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c44ce98e7227a04eeb4cf9c784109a5c9710e54849ceb4f09f8597247897f1e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.116", + "unzip-n", +] + [[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.5" @@ -3998,7 +5311,7 @@ dependencies = [ "clap", "quinn", "rcgen", - "rustls 0.23.35", + "rustls 0.23.36", "tokio", "tracing", "tracing-subscriber", @@ -4016,7 +5329,7 @@ dependencies = [ "futures", "quinn", "rcgen", - "rustls 0.23.35", + "rustls 0.23.36", "tokio", "tracing", "tracing-subscriber", @@ -4083,7 +5396,7 @@ dependencies = [ "clap", "futures", "quinn", - "rustls 0.23.35", + "rustls 0.23.36", "tokio", "tower", "tower-http", @@ -4122,24 +5435,33 @@ dependencies = [ [[package]] name = "wasi-preview1-component-adapter-provider" -version = "41.0.1" +version = "41.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff0438c62c6bf0c99884538a60546d91310b7e5b947207fd1590e2da4d076d69" +checksum = "d9dd9d6d3211a4f0109862b49dc1de3b7148cc5cdc272cb1700684c9c65f8a0b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen 0.46.0", + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", @@ -4150,11 +5472,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -4163,9 +5486,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4173,22 +5496,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.116", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] @@ -4223,6 +5546,26 @@ dependencies = [ "wasmparser 0.243.0", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser 0.244.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9dca005e69bf015e45577e415b9af8c67e8ee3c0e38b5b0add5aa92581ed5c" +dependencies = [ + "leb128fmt", + "wasmparser 0.245.1", +] + [[package]] name = "wasm-metadata" version = "0.238.1" @@ -4230,7 +5573,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00094573b000c92134f2ef0f8afa4f6f892de37e78442988c946243a8c44364e" dependencies = [ "anyhow", - "indexmap", + "indexmap 2.13.0", "wasm-encoder 0.238.1", "wasmparser 0.238.1", ] @@ -4242,11 +5585,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20b3ec880a9ac69ccd92fbdbcf46ee833071cf09f82bb005b2327c7ae6025ae2" dependencies = [ "anyhow", - "indexmap", + "indexmap 2.13.0", "wasm-encoder 0.239.0", "wasmparser 0.239.0", ] +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder 0.244.0", + "wasmparser 0.244.0", +] + [[package]] name = "wasm-tokio" version = "0.6.0" @@ -4266,9 +5621,9 @@ version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bd23c879ec35d708f4eff3456f33c415d113363a2e38420098bf42976bacb31" dependencies = [ - "indexmap", + "indexmap 2.13.0", "logos", - "thiserror 2.0.17", + "thiserror 2.0.18", "wit-parser 0.243.0", ] @@ -4278,8 +5633,8 @@ version = "0.220.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d07b6a3b550fefa1a914b6d54fc175dd11c3392da11eee604e6ffc759805d25" dependencies = [ - "bitflags 2.10.0", - "indexmap", + "bitflags 2.11.0", + "indexmap 2.13.0", "semver", ] @@ -4289,9 +5644,9 @@ version = "0.238.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fa99c8328024423875ae4a55345cfde8f0371327fb2d0f33b0f52a06fc44408" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.13.0", "semver", ] @@ -4301,9 +5656,9 @@ version = "0.239.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.13.0", "semver", ] @@ -4313,13 +5668,36 @@ version = "0.243.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.13.0", "semver", "serde", ] +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver", +] + +[[package]] +name = "wasmparser" +version = "0.245.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e" +dependencies = [ + "bitflags 2.11.0", + "indexmap 2.13.0", + "semver", +] + [[package]] name = "wasmprinter" version = "0.243.0" @@ -4340,7 +5718,7 @@ dependencies = [ "addr2line", "anyhow", "async-trait", - "bitflags 2.10.0", + "bitflags 2.11.0", "bumpalo", "cc", "cfg-if", @@ -4348,18 +5726,18 @@ dependencies = [ "fxprof-processed-profile", "gimli", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.13.0", "ittapi", "libc", "log", - "mach2", + "mach2 0.4.3", "memfd", "object", "once_cell", "postcard", "pulley-interpreter", "rayon", - "rustix 1.0.8", + "rustix 1.1.3", "semver", "serde", "serde_derive", @@ -4411,7 +5789,7 @@ dependencies = [ "cranelift-bitset", "cranelift-entity", "gimli", - "indexmap", + "indexmap 2.13.0", "log", "object", "postcard", @@ -4437,7 +5815,7 @@ dependencies = [ "directories-next", "log", "postcard", - "rustix 1.0.8", + "rustix 1.1.3", "serde", "serde_derive", "sha2", @@ -4456,7 +5834,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn", + "syn 2.0.116", "wasmtime-internal-component-util", "wasmtime-internal-wit-bindgen", "wit-parser 0.243.0", @@ -4487,7 +5865,7 @@ dependencies = [ "pulley-interpreter", "smallvec", "target-lexicon", - "thiserror 2.0.17", + "thiserror 2.0.18", "wasmparser 0.243.0", "wasmtime-environ", "wasmtime-internal-math", @@ -4504,7 +5882,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "rustix 1.0.8", + "rustix 1.1.3", "wasmtime-environ", "wasmtime-internal-versioned-export-macros", "windows-sys 0.61.2", @@ -4518,7 +5896,7 @@ checksum = "db673148f26e1211db3913c12c75594be9e3858a71fa297561e9162b1a49cfb0" dependencies = [ "cc", "object", - "rustix 1.0.8", + "rustix 1.1.3", "wasmtime-internal-versioned-export-macros", ] @@ -4570,7 +5948,7 @@ checksum = "63ba3124cc2cbcd362672f9f077303ccc4cd61daa908f73447b7fdaece75ff9f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -4597,9 +5975,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87acbd416227cdd279565ba49e57cf7f08d112657c3b3f39b70250acdfd094fe" dependencies = [ "anyhow", - "bitflags 2.10.0", + "bitflags 2.11.0", "heck", - "indexmap", + "indexmap 2.13.0", "wit-parser 0.243.0", ] @@ -4611,7 +5989,7 @@ checksum = "d9a1bdb4948463ed22559a640e687fed0df50b66353144aa6a9496c041ecd927" dependencies = [ "anyhow", "async-trait", - "bitflags 2.10.0", + "bitflags 2.11.0", "bytes", "cap-fs-ext", "cap-net-ext", @@ -4622,9 +6000,9 @@ dependencies = [ "futures", "io-extras", "io-lifetimes", - "rustix 1.0.8", + "rustix 1.1.3", "system-interface", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", "url", @@ -4672,31 +6050,31 @@ dependencies = [ [[package]] name = "wast" -version = "243.0.0" +version = "245.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df21d01c2d91e46cb7a221d79e58a2d210ea02020d57c092e79255cc2999ca7f" +checksum = "28cf1149285569120b8ce39db8b465e8a2b55c34cbb586bd977e43e2bc7300bf" dependencies = [ "bumpalo", "leb128fmt", "memchr", - "unicode-width", - "wasm-encoder 0.243.0", + "unicode-width 0.2.2", + "wasm-encoder 0.245.1", ] [[package]] name = "wat" -version = "1.243.0" +version = "1.245.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226a9a91cd80a50449312fef0c75c23478fcecfcc4092bdebe1dc8e760ef521b" +checksum = "cd48d1679b6858988cb96b154dda0ec5bbb09275b71db46057be37332d5477be" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.83" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ "js-sys", "wasm-bindgen", @@ -4714,9 +6092,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3e3b5f5e80bc89f30ce8d0343bf4e5f12341c51f3e26cbeecbc7c85443e85b" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" dependencies = [ "rustls-pki-types", ] @@ -4727,14 +6105,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.4", + "webpki-roots 1.0.6", ] [[package]] name = "webpki-roots" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" dependencies = [ "rustls-pki-types", ] @@ -4783,7 +6161,7 @@ dependencies = [ "regalloc2", "smallvec", "target-lexicon", - "thiserror 2.0.17", + "thiserror 2.0.18", "wasmparser 0.243.0", "wasmtime-environ", "wasmtime-internal-cranelift", @@ -4811,7 +6189,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -4822,7 +6200,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -5151,6 +6529,9 @@ name = "winnow" version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] [[package]] name = "winreg" @@ -5168,7 +6549,7 @@ version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "windows-sys 0.59.0", ] @@ -5178,14 +6559,17 @@ version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" dependencies = [ - "wit-bindgen-rust-macro", + "wit-bindgen-rust-macro 0.45.1", ] [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro 0.51.0", +] [[package]] name = "wit-bindgen-core" @@ -5209,6 +6593,17 @@ dependencies = [ "wit-parser 0.238.1", ] +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser 0.244.0", +] + [[package]] name = "wit-bindgen-rust" version = "0.45.1" @@ -5217,14 +6612,30 @@ checksum = "f089b7beb50fdcf0b9dc68be920843d743c00cbbd5ef1fa21c727f9b5089dac5" dependencies = [ "anyhow", "heck", - "indexmap", + "indexmap 2.13.0", "prettyplease", - "syn", + "syn 2.0.116", "wasm-metadata 0.238.1", "wit-bindgen-core 0.45.1", "wit-component 0.238.1", ] +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.116", + "wasm-metadata 0.244.0", + "wit-bindgen-core 0.51.0", + "wit-component 0.244.0", +] + [[package]] name = "wit-bindgen-rust-macro" version = "0.45.1" @@ -5235,9 +6646,24 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.116", "wit-bindgen-core 0.45.1", - "wit-bindgen-rust", + "wit-bindgen-rust 0.45.1", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.116", + "wit-bindgen-core 0.51.0", + "wit-bindgen-rust 0.51.0", ] [[package]] @@ -5245,7 +6671,7 @@ name = "wit-bindgen-wrpc" version = "0.11.0" dependencies = [ "anyhow", - "bitflags 2.10.0", + "bitflags 2.11.0", "bytes", "futures", "tokio", @@ -5280,7 +6706,7 @@ dependencies = [ "prettyplease", "serde", "serde_json", - "syn", + "syn 2.0.116", "test-helpers", "tokio", "wit-bindgen-core 0.36.0", @@ -5297,7 +6723,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.116", "wit-bindgen-core 0.36.0", "wit-bindgen-wrpc-rust", ] @@ -5309,8 +6735,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d31c985f541330d1a809547043ad19dd58739a2f83c7f116aeabcab86aed597" dependencies = [ "anyhow", - "bitflags 2.10.0", - "indexmap", + "bitflags 2.11.0", + "indexmap 2.13.0", "log", "serde", "serde_derive", @@ -5328,8 +6754,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88a866b19dba2c94d706ec58c92a4c62ab63e482b4c935d2a085ac94caecb136" dependencies = [ "anyhow", - "bitflags 2.10.0", - "indexmap", + "bitflags 2.11.0", + "indexmap 2.13.0", "log", "serde", "serde_derive", @@ -5340,6 +6766,25 @@ dependencies = [ "wit-parser 0.239.0", ] +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder 0.244.0", + "wasm-metadata 0.244.0", + "wasmparser 0.244.0", + "wit-parser 0.244.0", +] + [[package]] name = "wit-parser" version = "0.220.1" @@ -5348,7 +6793,7 @@ checksum = "ae2a7999ed18efe59be8de2db9cb2b7f84d88b27818c79353dfc53131840fe1a" dependencies = [ "anyhow", "id-arena", - "indexmap", + "indexmap 2.13.0", "log", "semver", "serde", @@ -5366,7 +6811,7 @@ checksum = "1eea12c964ed423ed14745e51aac2f1e28e5572ca012b0503bdcf65ffee3b44c" dependencies = [ "anyhow", "id-arena", - "indexmap", + "indexmap 2.13.0", "log", "semver", "serde", @@ -5384,7 +6829,7 @@ checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d" dependencies = [ "anyhow", "id-arena", - "indexmap", + "indexmap 2.13.0", "log", "semver", "serde", @@ -5402,7 +6847,7 @@ checksum = "df983a8608e513d8997f435bb74207bf0933d0e49ca97aa9d8a6157164b9b7fc" dependencies = [ "anyhow", "id-arena", - "indexmap", + "indexmap 2.13.0", "log", "semver", "serde", @@ -5412,6 +6857,24 @@ dependencies = [ "wasmparser 0.243.0", ] +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.244.0", +] + [[package]] name = "writeable" version = "0.6.2" @@ -5428,6 +6891,7 @@ dependencies = [ "clap", "criterion", "futures", + "serial_test", "tempfile", "test-log", "tokio", @@ -5447,7 +6911,9 @@ dependencies = [ "wrpc-transport-nats", "wrpc-transport-quic", "wrpc-transport-web", + "wrpc-transport-zenoh", "wrpc-wasmtime-cli", + "zenoh", ] [[package]] @@ -5458,6 +6924,7 @@ dependencies = [ "async-nats", "tokio", "tracing-subscriber", + "zenoh", ] [[package]] @@ -5505,11 +6972,13 @@ dependencies = [ "async-nats", "quinn", "rcgen", - "rustls 0.23.35", + "rustls 0.23.36", "tokio", "tracing", "wrpc-cli", + "wrpc-transport-zenoh", "wtransport", + "zenoh", ] [[package]] @@ -5578,6 +7047,28 @@ dependencies = [ "wtransport", ] +[[package]] +name = "wrpc-transport-zenoh" +version = "0.29.0" +dependencies = [ + "anyhow", + "bytes", + "flume", + "futures", + "hotpath", + "nuid", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", + "uuid", + "wasm-tokio", + "wrpc-transport", + "zenoh", +] + [[package]] name = "wrpc-wasi-keyvalue" version = "0.1.1" @@ -5639,6 +7130,8 @@ dependencies = [ "wrpc-runtime-wasmtime", "wrpc-transport", "wrpc-transport-nats", + "wrpc-transport-zenoh", + "zenoh", ] [[package]] @@ -5668,13 +7161,13 @@ dependencies = [ "pem", "quinn", "rcgen", - "rustls 0.23.35", - "rustls-native-certs 0.8.2", + "rustls 0.23.36", + "rustls-native-certs 0.8.3", "rustls-pemfile", "rustls-pki-types", "sha2", "socket2 0.5.10", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tokio", "tracing", @@ -5691,7 +7184,7 @@ checksum = "1a09d89a8dba201c2439d9d5eca55a0faa08909d69da50decdb5ec00be0ac504" dependencies = [ "httlib-huffman", "octets", - "thiserror 2.0.17", + "thiserror 2.0.18", "url", ] @@ -5708,7 +7201,7 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", ] @@ -5740,28 +7233,390 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", "synstructure", ] +[[package]] +name = "zenoh" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9ff8cb89f5267b8486a69466bc42f240f1ee2d5089e72395a23094e7b74f21" +dependencies = [ + "ahash", + "arc-swap", + "async-trait", + "bytes", + "const_format", + "flate2", + "flume", + "futures", + "git-version", + "itertools 0.14.0", + "json5", + "lazy_static", + "nonempty-collections", + "once_cell", + "petgraph", + "phf", + "rand 0.8.5", + "ref-cast", + "rustc_version", + "serde", + "serde_json", + "socket2 0.5.10", + "tokio", + "tokio-util", + "tracing", + "uhlc", + "vec_map", + "zenoh-buffers", + "zenoh-codec", + "zenoh-collections", + "zenoh-config", + "zenoh-core", + "zenoh-keyexpr", + "zenoh-link", + "zenoh-link-commons", + "zenoh-macros", + "zenoh-plugin-trait", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-sync", + "zenoh-task", + "zenoh-transport", + "zenoh-util", +] + +[[package]] +name = "zenoh-buffers" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9216c3d6c84b56f3e3be634e52365022038e1ac1b9f662f10d425cbf6c0fa8" +dependencies = [ + "zenoh-collections", +] + +[[package]] +name = "zenoh-codec" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14bc6747664aa9ecf17becd6e9a29282e535a350cd7c6bd8de7bf2dc662fb93d" +dependencies = [ + "tracing", + "uhlc", + "zenoh-buffers", + "zenoh-protocol", +] + +[[package]] +name = "zenoh-collections" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d642ecfe0d85f0cd846be9bc92805d926c092a6e6c7a575b6346752f8c3ae16" +dependencies = [ + "ahash", +] + +[[package]] +name = "zenoh-config" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39765a5f9975aba204c99f2f65308db4952dbea8e5ac79c78ac1eaf5711e970a" +dependencies = [ + "json5", + "nonempty-collections", + "num_cpus", + "secrecy", + "serde", + "serde_json", + "serde_with", + "serde_yaml", + "tracing", + "uhlc", + "validated_struct", + "zenoh-core", + "zenoh-keyexpr", + "zenoh-macros", + "zenoh-protocol", + "zenoh-result", + "zenoh-util", +] + +[[package]] +name = "zenoh-core" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c0c1388dccf287aec4e9d5e638630dc9d536db9f1da3522889b42697723b9b" +dependencies = [ + "lazy_static", + "tokio", + "zenoh-result", + "zenoh-runtime", +] + +[[package]] +name = "zenoh-crypto" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b433e08df3b03f2af2d23bd29a32aa5f5522c52e66d63e3d135bfa66373736dd" +dependencies = [ + "aes", + "hmac", + "rand 0.8.5", + "rand_chacha 0.3.1", + "sha3", + "zenoh-result", +] + +[[package]] +name = "zenoh-keyexpr" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a3c47c89cb55ea45a1b3fe7d1fe8682ea93530b1fc5245257812db14b55b3d" +dependencies = [ + "getrandom 0.2.17", + "hashbrown 0.16.1", + "keyed-set", + "rand 0.8.5", + "schemars 1.2.1", + "serde", + "token-cell", + "zenoh-result", +] + +[[package]] +name = "zenoh-link" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6218cecab58435f31fb8b2e185f74f35af8aedd96e8bdd3557b333206b1acfda" +dependencies = [ + "zenoh-config", + "zenoh-link-commons", + "zenoh-link-tcp", + "zenoh-protocol", + "zenoh-result", +] + +[[package]] +name = "zenoh-link-commons" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98adc618f7edb570b9333ce583934a7c63e3a619cb49666515bfc06a000d7b6" +dependencies = [ + "async-trait", + "flume", + "futures", + "serde", + "socket2 0.5.10", + "time", + "tokio", + "tokio-util", + "tracing", + "zenoh-buffers", + "zenoh-codec", + "zenoh-core", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-util", +] + +[[package]] +name = "zenoh-link-tcp" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f23bd5d06a0014ce5a205961d6d47c8e8d792d9fd050ae9d0c9b609a187995" +dependencies = [ + "async-trait", + "socket2 0.5.10", + "tokio", + "tokio-util", + "tracing", + "zenoh-config", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", +] + +[[package]] +name = "zenoh-macros" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b760a458cd906ac888b37fd1abdb21a0f58ecc64cc3882f83a976cb5ca8e0632" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.116", + "zenoh-keyexpr", +] + +[[package]] +name = "zenoh-plugin-trait" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7325b773c43a86a94f800cb971ab7e4b7e01ce76819c9c100ea783a47c3a25e4" +dependencies = [ + "git-version", + "libloading", + "serde", + "stabby", + "tracing", + "zenoh-config", + "zenoh-keyexpr", + "zenoh-macros", + "zenoh-result", + "zenoh-util", +] + +[[package]] +name = "zenoh-protocol" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4d3dad7aeeea780495692b195cd56515569c32b76b9dd077cc408c3ebca03f" +dependencies = [ + "const_format", + "rand 0.8.5", + "serde", + "uhlc", + "zenoh-buffers", + "zenoh-keyexpr", + "zenoh-result", +] + +[[package]] +name = "zenoh-result" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b4dbfea68b947a790d5525bcf061e91e2fdc2798bce619851919b353a8580fa" +dependencies = [ + "anyhow", +] + +[[package]] +name = "zenoh-runtime" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760a1f7880f98427ad849d600257d1455a18afe981681f362684a3f91042537e" +dependencies = [ + "lazy_static", + "ron", + "serde", + "tokio", + "tracing", + "zenoh-macros", + "zenoh-result", +] + +[[package]] +name = "zenoh-sync" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f132137bb003f10b7fff086cb18addf8e8273b9c0d2722a53b5074c8a79965" +dependencies = [ + "arc-swap", + "event-listener", + "futures", + "tokio", + "zenoh-buffers", + "zenoh-collections", + "zenoh-core", +] + +[[package]] +name = "zenoh-task" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b17d10136fdabec7e21a3fcef568c210ee6a2d71cde6adcde99e9236584f3a1" +dependencies = [ + "futures", + "tokio", + "tokio-util", + "tracing", + "zenoh-core", + "zenoh-runtime", +] + +[[package]] +name = "zenoh-transport" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50739b4c45e0963df8377abddb74701a4b708b178590eae92f27a604e25daf44" +dependencies = [ + "async-trait", + "crossbeam-utils", + "flume", + "lazy_static", + "lz4_flex", + "rand 0.8.5", + "ringbuffer-spsc", + "serde", + "sha3", + "tokio", + "tokio-util", + "tracing", + "zenoh-buffers", + "zenoh-codec", + "zenoh-config", + "zenoh-core", + "zenoh-crypto", + "zenoh-link", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-sync", + "zenoh-task", + "zenoh-util", +] + +[[package]] +name = "zenoh-util" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9512987c13925d32d3331507c8807853d5b682ea8da94d0ba6534c7a8ace48aa" +dependencies = [ + "async-trait", + "const_format", + "flume", + "home", + "humantime", + "lazy_static", + "libc", + "libloading", + "pnet_datalink", + "schemars 1.2.1", + "serde", + "serde_json", + "shellexpand", + "tokio", + "tracing", + "tracing-subscriber", + "winapi", + "zenoh-core", + "zenoh-result", +] + [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] [[package]] @@ -5781,7 +7636,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", "synstructure", ] @@ -5821,9 +7676,15 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.116", ] +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index 09e27cb92..cf6f57b00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ members = [ ] [features] -default = ["bin", "nats", "net", "quic", "wasmtime", "web-transport"] +default = ["bin", "nats", "net", "quic", "wasmtime", "web-transport", "zenoh-transport"] bin = ["bin-bindgen", "bin-wasmtime"] bin-bindgen = [ @@ -43,6 +43,7 @@ net = ["wrpc-transport/net"] quic = ["dep:wrpc-transport-quic"] wasmtime = ["dep:wrpc-runtime-wasmtime"] web-transport = ["dep:wrpc-transport-web"] +zenoh-transport = ["dep:zenoh", "dep:wrpc-transport-zenoh", "wrpc-cli/zenoh-transport"] [[bin]] name = "wit-bindgen-wrpc" @@ -84,6 +85,10 @@ wrpc-transport-nats = { workspace = true, optional = true } wrpc-transport-quic = { workspace = true, optional = true } wrpc-transport-web = { workspace = true, optional = true } wrpc-wasmtime-cli = { workspace = true, optional = true } +wrpc-transport-zenoh = { workspace = true, features = [ + "zenoh-1_5_0", +], optional = true } +zenoh = { workspace = true, optional = true } [dev-dependencies] anyhow = { workspace = true } @@ -114,8 +119,10 @@ wasmtime-cli-flags = { workspace = true, features = [ "pooling-allocator", "threads", ] } -wrpc-test = { workspace = true, features = ["nats", "quic", "web-transport"] } +wrpc-test = { workspace = true, features = ["nats", "quic", "web-transport", "zenoh-transport"] } wrpc-transport = { workspace = true, features = ["net"] } +serial_test = "*" + [workspace.dependencies] anyhow = { version = "1", default-features = false } @@ -182,8 +189,11 @@ wrpc-transport = { version = "0.29", path = "./crates/transport", default-featur wrpc-transport-nats = { version = "0.31", path = "./crates/transport-nats", default-features = false } wrpc-transport-quic = { version = "0.6", path = "./crates/transport-quic", default-features = false } wrpc-transport-web = { version = "0.3", path = "./crates/transport-web", default-features = false } +wrpc-transport-zenoh = { version = "0.29", path = "./crates/transport-zenoh", default-features = false } wrpc-wasi-keyvalue = { version = "0.1.1", path = "./crates/wasi-keyvalue", default-features = false } wrpc-wasi-keyvalue-mem = { version = "0.2", path = "./crates/wasi-keyvalue-mem", default-features = false } wrpc-wasi-keyvalue-redis = { version = "0.2", path = "./crates/wasi-keyvalue-redis", default-features = false } wrpc-wasmtime-cli = { version = "0.9", path = "./crates/wasmtime-cli", default-features = false } wtransport = { version = "0.6.1", default-features = false } +zenoh = {version = "1.5.0", default-features = false} +flume = {version = "0.11.0", default-features = false} diff --git a/ZENOH.md b/ZENOH.md new file mode 100644 index 000000000..4360b3d7d --- /dev/null +++ b/ZENOH.md @@ -0,0 +1,157 @@ +### Requirements ******************* + +#### Setup zenohd on NixOS + +1. Add zenoh to your configuration.nix file in the environment.systemPackages + ``` + # List packages installed in system profile. To search, run: + # $ nix search wget + environment.systemPackages = with pkgs; [ + ... + zenoh + ]; + ``` + +2. Rebuild NixOS + ``` + sudo nixos-rebuild switch + ``` + +3. Test zenohd + ``` + zenohd + ``` + + - Sample output: + 2025-12-08T12:27:11.419376Z INFO main ThreadId(01) zenohd: zenohd v1.6.1 built with rustc 1.85.0 (4d91de4e4 2025-02-17) + 2025-12-08T12:27:11.423016Z INFO main ThreadId(01) zenohd: Initial conf: {"access_control":{"def ........ ,"qos":{"enabled":true}}}} + 2025-12-08T12:27:11.428864Z INFO main ThreadId(01) zenoh::net::runtime: Using ZID: ba0e4a24bdf641c79bfe9ee37eb9bc4 + 2025-12-08T12:27:11.438761Z INFO main ThreadId(01) zenoh::net::runtime::orchestrator: Zenoh can be reached at: tcp/[fe80::215:5dff:fe00:b079]:7447 + 2025-12-08T12:27:11.439328Z INFO main ThreadId(01) zenoh::net::runtime::orchestrator: Zenoh can be reached at: tcp/[fe80::3842:4ff:fe75:baf1]:7447 + 2025-12-08T12:27:11.439331Z INFO main ThreadId(01) zenoh::net::runtime::orchestrator: Zenoh can be reached at: tcp/[fe80::209d:11ff:fe06:8e06]:7447 + 2025-12-08T12:27:11.439333Z INFO main ThreadId(01) zenoh::net::runtime::orchestrator: Zenoh can be reached at: tcp/10.255.255.254:7447 + 2025-12-08T12:27:11.439334Z INFO main ThreadId(01) zenoh::net::runtime::orchestrator: Zenoh can be reached at: tcp/172.21.8.176:7447 + 2025-12-08T12:27:11.439336Z INFO main ThreadId(01) zenoh::net::runtime::orchestrator: Zenoh can be reached at: tcp/172.18.0.1:7447 + 2025-12-08T12:27:11.439428Z INFO main ThreadId(01) zenoh::net::runtime::orchestrator: zenohd listening scout messages on 224.0.0.224:7446 + +#### Using [zenoh] transport + +We will use the following two Rust wRPC applications using [zenoh] transport: +- [examples/rust/hello-zenoh-client](examples/rust/hello-zenoh-client) +- [examples/rust/hello-zenoh-server](examples/rust/hello-zenoh-server) + +1. Run [zenoh]: + + - Build the repo, so that zenoh transport is compiled for wrpc-wasmtime (runtime) using + ```sh + cargo build --release + ``` + + - Create a zenoh config file at /path/to/config/zenoh_conf.json5 + ```sh + { + mode: "client", + listen: { + endpoints: ["tcp/0.0.0.0:7447"], + }, + } + ``` + This is a minimal example config. + + - Set the config environment variable for zenoh: + > export ZENOH_CONFIG="/path/to/config/zenoh_conf.json5" + + - Running as a daemon with the config above in order to run zenoh as a transport (in Client mode): + ```sh + zenohd + ``` + +2. Serve Wasm `hello` server via [zenoh] + + ```sh + ./target/release/wrpc-wasmtime zenoh serve ./target/wasm32-wasip2/debug/hello_component_server.wasm + ``` + + - Sample output: + > INFO zenoh::net::runtime: Using ZID: 638a012883d98f769cf4367f8457bc66 + > INFO zenoh::net::runtime::orchestrator: Scouting... + > INFO zenoh::net::runtime::orchestrator: Found HelloProto { version: 9, whatami: Router, zid: f3ae70a723144e6675f4c72d30196797, locators: [tcp/[fe80::215:5dff:fe83:cd20]:7447, tcp/[fe80::8d2:a4ff:fed2:f33d]:7447, tcp/[fe80::c431:38ff:fe58:9310]:7447, tcp/10.255.255.254:7447, tcp/172.21.8.176:7447, tcp/172.18.0.1:7447] } + > INFO zenoh::net::runtime::orchestrator: Found HelloProto { version: 9, whatami: Router, zid: f3ae70a723144e6675f4c72d30196797, locators: [tcp/[fe80::215:5dff:fe83:cd20]:7447, tcp/[fe80::8d2:a4ff:fed2:f33d]:7447, tcp/[fe80::c431:38ff:fe58:9310]:7447, tcp/10.255.255.254:7447, tcp/172.21.8.176:7447, tcp/172.18.0.1:7447] } + > INFO wrpc_wasmtime_cli: serving instance function name="hello" + +3. Call Wasm `hello` server using a Wasm `hello` client via [zenoh]: + + ```sh + ./target/release/wrpc-wasmtime zenoh run ./target/wasm32-wasip2/debug/hello-component-client.wasm + ``` + + - Sample output: + > INFO zenoh::net::runtime: Using ZID: e4b5dcb134469e2e5773dd88dfb7a8a + > INFO zenoh::net::runtime::orchestrator: Scouting... + > INFO zenoh::net::runtime::orchestrator: Found HelloProto { version: 9, whatami: Router, zid: f3ae70a723144e6675f4c72d30196797, locators: [tcp/[fe80::215:5dff:fe83:cd20]:7447, tcp/[fe80::8d2:a4ff:fed2:f33d]:7447, tcp/[fe80::c431:38ff:fe58:9310]:7447, tcp/10.255.255.254:7447, tcp/172.21.8.176:7447, tcp/172.18.0.1:7447] } + > INFO zenoh::net::runtime::orchestrator: Found HelloProto { version: 9, whatami: Router, zid: f3ae70a723144e6675f4c72d30196797, locators: [tcp/[fe80::215:5dff:fe83:cd20]:7447, tcp/[fe80::8d2:a4ff:fed2:f33d]:7447, tcp/[fe80::c431:38ff:fe58:9310]:7447, tcp/10.255.255.254:7447, tcp/172.21.8.176:7447, tcp/172.18.0.1:7447] } + hello from Rust + > INFO zenoh::api::session: close session zid=e4b5dcb134469e2e5773dd88dfb7a8a + +4. Call the Wasm `hello` server using a native wRPC `hello` client via [zenoh]: + + ```sh + cargo run -p hello-zenoh-client + ``` + +5. Serve native wRPC `hello` server via [zenoh]: + + ```sh + cargo run -p hello-zenoh-server + ``` + + +#### Testing + +To test the transport-zenoh package run: + + ```sh + cargo test zenoh -- --nocapture + ``` + + - Sample output: + > test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 13 filtered out; finished in 6.17s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +6. Call both the native wRPC `hello` server and Wasm `hello` server using native wRPC `hello` client via [zenoh]: + + ```sh + cargo run -p hello-zenoh-client rust native + ``` + +7. Call native wRPC `hello` server using Wasm `hello` client via [zenoh]: + + ```sh + wrpc-wasmtime zenoh run --import native ./target/wasm32-wasip2/release/hello-component-client.wasm \ No newline at end of file diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index b2d37fd3f..a87497830 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -11,8 +11,9 @@ license.workspace = true repository.workspace = true [features] -default = ["nats"] +default = ["nats", "zenoh-transport"] nats = ["async-nats/ring", "dep:async-nats", "dep:tokio", "tokio/sync"] +zenoh-transport = ["dep:zenoh", "dep:tokio", "tokio/sync"] [dependencies] anyhow = { workspace = true, features = ["std"] } @@ -25,3 +26,4 @@ tracing-subscriber = { workspace = true, features = [ "smallvec", "tracing-log", ] } +zenoh = { workspace = true, optional = true, features = ["transport_tcp"] } diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index f6e19896d..34ac85549 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -1,3 +1,5 @@ #[cfg(feature = "nats")] pub mod nats; pub mod tracing; +#[cfg(feature = "zenoh-transport")] +pub mod zenoh; diff --git a/crates/cli/src/zenoh.rs b/crates/cli/src/zenoh.rs new file mode 100644 index 000000000..a9c2c2784 --- /dev/null +++ b/crates/cli/src/zenoh.rs @@ -0,0 +1,10 @@ +use zenoh::{Config, Session}; + +/// Open a regular Zenoh session with configs supplied by an environment variable. +pub async fn connect() -> anyhow::Result { + let cfg = Config::from_env().expect("Missing environment variable 'ZENOH_CONFIG'"); + + let session = zenoh::open(cfg) + .await.unwrap(); + Ok(session) +} \ No newline at end of file diff --git a/crates/test/Cargo.toml b/crates/test/Cargo.toml index 899055684..b505f4529 100644 --- a/crates/test/Cargo.toml +++ b/crates/test/Cargo.toml @@ -11,7 +11,7 @@ license.workspace = true repository.workspace = true [features] -default = ["nats", "quic", "web-transport"] +default = ["nats", "quic", "web-transport", "zenoh-transport"] nats = ["dep:async-nats", "async-nats/ring", "wrpc-cli/nats"] quic = [ "dep:quinn", @@ -22,6 +22,7 @@ quic = [ "quinn/rustls", ] web-transport = ["dep:wtransport", "wtransport/self-signed"] +zenoh-transport = ["dep:zenoh", "dep:wrpc-transport-zenoh", "wrpc-cli/zenoh-transport"] [dependencies] anyhow = { workspace = true } @@ -33,3 +34,5 @@ tokio = { workspace = true, features = ["net", "process", "rt-multi-thread"] } tracing = { workspace = true } wrpc-cli = { workspace = true } wtransport = { workspace = true, features = ["ring"], optional = true } +wrpc-transport-zenoh = { workspace = true, features = [ "zenoh-1_5_0",], optional = true } +zenoh = { workspace = true, optional = true } diff --git a/crates/test/src/lib.rs b/crates/test/src/lib.rs index b71d6f407..3942087f9 100644 --- a/crates/test/src/lib.rs +++ b/crates/test/src/lib.rs @@ -2,6 +2,7 @@ use core::net::Ipv6Addr; use std::process::ExitStatus; +use std::sync::Arc; use anyhow::Context; use rcgen::{generate_simple_self_signed, CertifiedKey}; use rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer}; @@ -12,6 +13,7 @@ use tokio::process::Command; use tokio::sync::oneshot; use tokio::task::JoinHandle; use tokio::{select, spawn}; +use zenoh::{Config}; pub async fn free_port() -> anyhow::Result { TcpListener::bind((Ipv6Addr::LOCALHOST, 0)) @@ -120,6 +122,55 @@ pub async fn start_nats() -> anyhow::Result<( Ok((port, client, server, stop_tx)) } +#[cfg(feature = "zenoh-transport")] +pub async fn start_zenoh() -> anyhow::Result<( + u16, + wrpc_transport_zenoh::Client, + JoinHandle>, + oneshot::Sender<()>, +)> { + let port = free_port().await?; // not used in setup -- just return + let (server, stop_tx) = + spawn_server(Command::new("zenohd").args(&[] as &[&str])) + .await + .context("failed to start zenohd server")?; + + // connect to zenoh + let cfg = Config::from_env().expect("Missing environment variable 'ZENOH_CONFIG'"); + + let session = zenoh::open(cfg) + .await + .expect("Failed to open a Zenoh session"); + + let arc_session = Arc::new(session); + + let prefix = Arc::::from(""); + + let client = wrpc_transport_zenoh::Client::new(arc_session, prefix) + .await + .context("failed to construct transport client")?; + + Ok((port, client, server, stop_tx)) +} + +#[cfg(feature = "zenoh-transport")] +pub async fn with_zenoh(f: impl FnOnce(u16, wrpc_transport_zenoh::Client) -> Fut) -> anyhow::Result +where + Fut: core::future::Future>, +{ + let (port, zenoh_client, zenoh_server, stop_tx) = start_zenoh() + .await + .context("failed to start Zenoh server")?; + let res = f(port, zenoh_client).await.context("closure failed")?; + + stop_tx.send(()).expect("failed to stop Zenoh server"); + zenoh_server + .await + .context("failed to await Zenoh server stop")? + .context("Zenoh server failed to stop")?; + Ok(res) +} + #[cfg(feature = "nats")] pub async fn with_nats(f: impl FnOnce(u16, async_nats::Client) -> Fut) -> anyhow::Result where diff --git a/crates/transport-zenoh/Cargo.toml b/crates/transport-zenoh/Cargo.toml new file mode 100644 index 000000000..f7284f7e2 --- /dev/null +++ b/crates/transport-zenoh/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "wrpc-transport-zenoh" +version = "0.29.0" +description = "wRPC Zenoh transport" + +authors.workspace = true +categories.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[features] +default = ["zenoh-1_5_0"] +hotpath = ["hotpath/hotpath"] +hotpath-alloc = ["hotpath/hotpath-alloc"] + +[dependencies] +anyhow = { workspace = true, features = ["std"] } +bytes = { workspace = true, features = ["serde"] } +futures = { workspace = true, features = ["async-await"] } +nuid = { workspace = true } +tokio = { workspace = true, features = ["io-util", "rt-multi-thread"] } +tokio-stream = { workspace = true, features = ["sync"] } +tokio-util = { workspace = true, features = ["codec", "io"] } +tracing = { workspace = true, features = ["attributes"] } +wasm-tokio = { workspace = true } +wrpc-transport = { workspace = true } +zenoh-1_5_0 = { package = "zenoh", version = "1.5.0", default-features = false, optional = true } +serde_json = { workspace = true } +serde = { workspace = true } +uuid = { workspace = true } +flume = { workspace = true } +hotpath = "0.9" diff --git a/crates/transport-zenoh/src/lib.rs b/crates/transport-zenoh/src/lib.rs new file mode 100644 index 000000000..8f2ad07fc --- /dev/null +++ b/crates/transport-zenoh/src/lib.rs @@ -0,0 +1,1439 @@ +//! wRPC Zenoh transport + +#![allow(clippy::type_complexity)] + +use anyhow::{anyhow, ensure, Context as _}; +use wrpc_transport::Index; + +use zenoh_1_5_0::sample::Sample; +#[cfg(feature = "zenoh-1_5_0")] +use zenoh_1_5_0 as zenoh; + +use core::ops::{Deref, DerefMut}; +use std::iter::zip; +use std::{io, mem}; +use zenoh::Session; +use zenoh::bytes::ZBytes; +use zenoh::Wait; + +use core::future::Future; +use core::pin::{pin, Pin}; +use core::task::{Context, Poll}; +use core::{str}; + +use std::collections::{HashMap}; +use std::sync::{Arc}; + +use bytes::{Buf as _, Bytes}; +use futures::{Stream, StreamExt}; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; +use tokio::select; +use tokio::sync::{mpsc, oneshot}; +use tokio::task::JoinSet; +use tokio_stream::wrappers::ReceiverStream; + +use tracing::{debug, error, instrument, trace, warn}; + +pub const PROTOCOL: &str = "wrpc.0.0.1"; + +// wrpc_transport_zenoh.rs +// Minimal wRPC transport over Zenoh (no NATS extras) + + +// ---------- Key helpers (slash-separated Zenoh style) ---------- +#[hotpath::measure] +fn send_sync(session: &Session, key: &str, payload: &[u8]) -> io::Result<()> { + // Using the synchronous (blocking) API + // Note: session.put returns a builder; calling `.wait()` executes it synchronously. + session + .put(key, payload) + .wait() + .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + Ok(()) +} + +#[hotpath::measure] +async fn publish_with_reply( + session: &zenoh::Session, + subject: String, + reply: String, + payload: Bytes, + ) -> Result<(), zenoh::Error> { + let zbytes = prepare_payload_zbytes(Some(reply), &payload, None, None); + session.put(subject, zbytes).await.unwrap(); + + Ok(()) + } + +#[hotpath::measure] +fn spawn_async(fut: impl Future + Send + 'static) { + match tokio::runtime::Handle::try_current() { + Ok(rt) => { + rt.spawn(fut); + } + Err(_) => match tokio::runtime::Runtime::new() { + Ok(rt) => { + rt.spawn(fut); + } + Err(err) => error!(?err, "failed to create a new Tokio runtime"), + }, + } +} + +fn child_inbox(base: &str) -> String { + let base = if base.ends_with('/') { base } else { &format!("{base}/") }; + format!("{base}{}", nuid::next()) +} + + +// fn new_inbox() -> String { +// let inbox = "_inbox/"; +// let id = nuid::next(); +// let mut s = String::with_capacity(inbox.len().saturating_add(id.len())); +// s.push_str(inbox); +// s.push_str(&id); +// s +// } + +#[must_use] +#[inline] +pub fn param_subject(prefix: &str) -> String { + format!("{prefix}/params") +} + +#[must_use] +#[inline] +pub fn result_subject(prefix: &str) -> String { + format!("{prefix}/results") +} + +#[must_use] +#[inline] +pub fn index_path(prefix: &str, path: &[usize]) -> String { + let mut s = String::with_capacity(prefix.len() + path.len() * 2); + if !prefix.is_empty() { + s.push_str(prefix); + } + for p in path { + if !s.is_empty() { + s.push('/'); + } + s.push_str(&p.to_string()); + } + s +} + +#[must_use] +#[inline] +pub fn subscribe_path(prefix: &str, path: &[Option]) -> String { + let mut s = String::with_capacity(prefix.len() + path.len() * 2); + if !prefix.is_empty() { + s.push_str(prefix); + } + for p in path { + if !s.is_empty() { + s.push('/'); + } + if let Some(p) = p { + s.push_str(&p.to_string()); + } else { + s.push('*'); + } + } + s +} + +#[must_use] +#[inline] +pub fn invocation_subject(prefix: &str, instance: &str, func: &str) -> String { + let mut s = + String::with_capacity(prefix.len() + PROTOCOL.len() + instance.len() + func.len() + 3); + if !prefix.is_empty() { + s.push_str(prefix); + s.push('/'); + } + s.push_str(PROTOCOL); + s.push('/'); + if !instance.is_empty() { + s.push_str(instance); + s.push('/'); + } + s.push_str(func); + s +} + +fn corrupted_memory_error() -> std::io::Error { + std::io::Error::other("corrupted memory state") +} + + +/// Transport subscriber +pub struct Subscriber { + rx: ReceiverStream, + subject: String, + commands: mpsc::Sender, + tasks: Arc>, +} + +#[hotpath::measure_all] +impl Drop for Subscriber { + fn drop(&mut self) { + let commands = self.commands.clone(); + let subject = self.subject.clone(); + let tasks = Arc::clone(&self.tasks); + spawn_async(async move { + trace!(?subject, "shutting down subscriber"); + if let Err(err) = commands.send(Command::Unsubscribe(subject)).await { + warn!(?err, "failed to shutdown subscriber"); + } + drop(tasks); + }); + } +} + +#[hotpath::measure_all] +impl Deref for Subscriber { + type Target = ReceiverStream; + + fn deref(&self) -> &Self::Target { + &self.rx + } +} + +#[hotpath::measure_all] +impl DerefMut for Subscriber { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.rx + } +} + + +enum Command { + Subscribe(String, mpsc::Sender), + Unsubscribe(String), + Batch(Box<[Command]>, oneshot::Sender<()>), +} + + +/// Subset of [`async_nats::Message`](async_nats::Message) used by this crate +pub struct Message { + subject: String, + reply: Option, + payload: Bytes, + status: Option, + description: Option, +} + +#[derive(Clone, Debug)] +pub struct Client { + session: Arc, + prefix: Arc, + inbox: Arc, + //queue_group: Option>, + commands: mpsc::Sender, + tasks: Arc>, +} + +#[hotpath::measure] +fn parse_zbytes_message(sample: Sample) -> (String, Option, Bytes, Option, Option) { + let key = sample.key_expr().as_str().to_string(); + let zbytes = sample.payload(); + + let bytes = zbytes.to_bytes(); + let mut cursor = 0; + + // Decode reply + let reply = if cursor < bytes.len() && bytes[cursor] == 1 { + cursor += 1; + let len = u32::from_le_bytes([bytes[cursor], bytes[cursor+1], bytes[cursor+2], bytes[cursor+3]]) as usize; + cursor += 4; + let reply_str = String::from_utf8_lossy(&bytes[cursor..cursor+len]).into_owned(); + cursor += len; + Some(reply_str) + } else { + cursor += 1; + None + }; + + // Decode status + let status = if cursor < bytes.len() && bytes[cursor] == 1 { + cursor += 1; + let len = u32::from_le_bytes([bytes[cursor], bytes[cursor+1], bytes[cursor+2], bytes[cursor+3]]) as usize; + cursor += 4; + let status_str = String::from_utf8_lossy(&bytes[cursor..cursor+len]).into_owned(); + cursor += len; + Some(status_str) + } else { + cursor += 1; + None + }; + + // Decode description + let description = if cursor < bytes.len() && bytes[cursor] == 1 { + cursor += 1; + let len = u32::from_le_bytes([bytes[cursor], bytes[cursor+1], bytes[cursor+2], bytes[cursor+3]]) as usize; + cursor += 4; + let desc_str = String::from_utf8_lossy(&bytes[cursor..cursor+len]).into_owned(); + cursor += len; + Some(desc_str) + } else { + cursor += 1; + None + }; + + // Remaining bytes are payload + let payload = if cursor < bytes.len() { + Bytes::copy_from_slice(&bytes[cursor..]) + } else { + Bytes::new() + }; + + (key, reply, payload, status, description) +} + +#[hotpath::measure] +fn prepare_payload_zbytes( + reply: Option, + payload: &[u8], + status: Option, + description: Option +) -> ZBytes { + // use std::io::Write; + + let mut buf = Vec::new(); + + // Encode reply + if let Some(reply) = reply { + buf.push(1u8); // has_reply = true + let reply_bytes = reply.as_bytes(); + buf.extend_from_slice(&(reply_bytes.len() as u32).to_le_bytes()); + buf.extend_from_slice(reply_bytes); + } else { + buf.push(0u8); // has_reply = false + } + + // Encode status + if let Some(status) = status { + buf.push(1u8); + let status_bytes = status.as_bytes(); + buf.extend_from_slice(&(status_bytes.len() as u32).to_le_bytes()); + buf.extend_from_slice(status_bytes); + } else { + buf.push(0u8); + } + + // Encode description + if let Some(description) = description { + buf.push(1u8); + let desc_bytes = description.as_bytes(); + buf.extend_from_slice(&(desc_bytes.len() as u32).to_le_bytes()); + buf.extend_from_slice(desc_bytes); + } else { + buf.push(0u8); + } + + // Append payload + buf.extend_from_slice(payload); + + ZBytes::from(buf) +} + +#[hotpath::measure_all] +impl Client { + pub async fn new( + session: impl Into>, + prefix: impl Into>, + //queue_group: Option>, + ) -> anyhow::Result { + let session: Arc = session.into(); + let root = format!("_inbox/{}/", nuid::next()); + let wildcard = format!("{root}**"); + let mut sub = session + .declare_subscriber(wildcard) + .with(flume::bounded(8192)) + .await.unwrap(); + + let mut tasks = JoinSet::new(); + let (cmd_tx, mut cmd_rx) = mpsc::channel(8192); + tasks.spawn({ + async move { + fn handle_command(subs: &mut HashMap>, cmd: Command) { + //println!("Handle Command Called"); + match cmd { + Command::Subscribe(s, tx) => { + //println!("Handle Command Subcribe: {}", s); + subs.insert(s, tx); + } + Command::Unsubscribe(s) => { + //println!("Handle Command Unsubscribe: {}", s); + subs.remove(&s); + } + Command::Batch(cmds, ack) => { + //println!("Handle Command Batch"); + for cmd in cmds { + handle_command(subs, cmd); + } + let _ = ack.send(()); + } + } + } + + async fn handle_message( + subs: &mut HashMap>, + sample: Sample, + ) { + //println!("Handle Command Called"); + let key = sample.key_expr().clone().as_str().to_string(); + // let msg = parse_message(sample); + + let Some(sub) = subs.get_mut(&key) else { + debug!(?key, "drop message with no subscriber"); + return; + }; + let Ok(sub) = sub.reserve().await else { + debug!(?key, "drop message with closed subscriber"); + subs.remove(&key); + return; + }; + + let (_key_parsed, + reply, + payload, + status, + description) = parse_zbytes_message(sample); + + sub.send(Message { + subject: key, + reply, + payload, + status, + description + }); + } + + let mut subs = HashMap::new(); + loop { + //println!("Loop Called"); + select! { + Ok(msg) = sub.recv_async() => handle_message(&mut subs, msg).await, + Some(cmd) = cmd_rx.recv() => handle_command(&mut subs, cmd), + else => return, + } + } + } + }); + Ok(Self { + session, + prefix: prefix.into(), + inbox: root.into(), + commands: cmd_tx, + tasks: Arc::new(tasks), + }) + } +} + + +pub struct ByteSubscription(Subscriber); + +#[hotpath::measure_all] +impl Stream for ByteSubscription { + type Item = std::io::Result; + + #[instrument(level = "trace", skip_all)] + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.0.poll_next_unpin(cx) { + Poll::Ready(Some(Message { payload, .. })) => Poll::Ready(Some(Ok(payload))), + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, + } + } +} + +#[derive(Default)] +enum IndexTrie { + #[default] + Empty, + Leaf(Subscriber), + IndexNode { + subscriber: Option, + nested: Vec>, + }, + WildcardNode { + subscriber: Option, + nested: Option>, + }, +} + +#[hotpath::measure_all] +impl<'a> From<(&'a [Option], Subscriber)> for IndexTrie { + fn from((path, sub): (&'a [Option], Subscriber)) -> Self { + match path { + [] => Self::Leaf(sub), + [None, path @ ..] => Self::WildcardNode { + subscriber: None, + nested: Some(Box::new(Self::from((path, sub)))), + }, + [Some(i), path @ ..] => Self::IndexNode { + subscriber: None, + nested: { + let n = i.saturating_add(1); + let mut nested = Vec::with_capacity(n); + nested.resize_with(n, Option::default); + nested[*i] = Some(Self::from((path, sub))); + nested + }, + }, + } + } +} + +impl]>> FromIterator<(P, Subscriber)> for IndexTrie { + fn from_iter>(iter: T) -> Self { + let mut root = Self::Empty; + for (path, sub) in iter { + if !root.insert(path.as_ref(), sub) { + return Self::Empty; + } + } + root + } +} + +#[hotpath::measure_all] +impl IndexTrie { + #[inline] + fn is_empty(&self) -> bool { + matches!(self, IndexTrie::Empty) + } + + #[instrument(level = "trace", skip_all)] + fn take(&mut self, path: &[usize]) -> Option { + let Some((i, path)) = path.split_first() else { + return match mem::take(self) { + // TODO: Demux the subscription + //IndexTrie::WildcardNode { subscriber, nested } => { + // if let Some(nested) = nested { + // *self = IndexTrie::WildcardNode { + // subscriber: None, + // nested: Some(nested), + // } + // } + // subscriber + //} + IndexTrie::Empty | IndexTrie::WildcardNode { .. } => None, + IndexTrie::Leaf(subscriber) => Some(subscriber), + IndexTrie::IndexNode { subscriber, nested } => { + if !nested.is_empty() { + *self = IndexTrie::IndexNode { + subscriber: None, + nested, + } + } + subscriber + } + }; + }; + match self { + // TODO: Demux the subscription + //Self::WildcardNode { ref mut nested, .. } => { + // nested.as_mut().and_then(|nested| nested.take(path)) + //} + Self::Empty | Self::Leaf(..) | Self::WildcardNode { .. } => None, + Self::IndexNode { ref mut nested, .. } => nested + .get_mut(*i) + .and_then(|nested| nested.as_mut().and_then(|nested| nested.take(path))), + } + } + + /// Inserts `sub` under a `path` - returns `false` if it failed and `true` if it succeeded. + /// Tree state after `false` is returned in undefined + #[instrument(level = "trace", skip_all)] + fn insert(&mut self, path: &[Option], sub: Subscriber) -> bool { + match self { + Self::Empty => { + *self = Self::from((path, sub)); + true + } + Self::Leaf(..) => { + let Some((i, path)) = path.split_first() else { + return false; + }; + let Self::Leaf(subscriber) = mem::take(self) else { + return false; + }; + if let Some(i) = i { + let n = i.saturating_add(1); + let mut nested = Vec::with_capacity(n); + nested.resize_with(n, Option::default); + nested[*i] = Some(Self::from((path, sub))); + *self = Self::IndexNode { + subscriber: Some(subscriber), + nested, + }; + } else { + *self = Self::WildcardNode { + subscriber: Some(subscriber), + nested: Some(Box::new(Self::from((path, sub)))), + }; + } + true + } + Self::WildcardNode { + ref mut subscriber, + ref mut nested, + } => match (&subscriber, path) { + (None, []) => { + *subscriber = Some(sub); + true + } + (_, [None, path @ ..]) => { + if let Some(nested) = nested { + nested.insert(path, sub) + } else { + *nested = Some(Box::new(Self::from((path, sub)))); + true + } + } + _ => false, + }, + Self::IndexNode { + ref mut subscriber, + ref mut nested, + } => match (&subscriber, path) { + (None, []) => { + *subscriber = Some(sub); + true + } + (_, [Some(i), path @ ..]) => { + let cap = i.saturating_add(1); + if nested.len() < cap { + nested.resize_with(cap, Option::default); + } + let nested = &mut nested[*i]; + if let Some(nested) = nested { + nested.insert(path, sub) + } else { + *nested = Some(Self::from((path, sub))); + true + } + } + _ => false, + }, + } + } +} + + + + +pub struct Reader { + buffer: Bytes, + incoming: Option, + nested: Arc>, + path: Box<[usize]>, +} + +#[hotpath::measure_all] +impl wrpc_transport::Index for Reader { + #[instrument(level = "trace", skip(self))] + fn index(&self, path: &[usize]) -> anyhow::Result { + ensure!(!path.is_empty()); + trace!("locking index tree"); + let mut nested = self + .nested + .lock() + .map_err(|err| anyhow!(err.to_string()).context("failed to lock map"))?; + trace!("taking index subscription"); + let mut p = self.path.to_vec(); + p.extend_from_slice(path); + let incoming = nested.take(&p); + Ok(Self { + buffer: Bytes::default(), + incoming, + nested: Arc::clone(&self.nested), + path: p.into_boxed_slice(), + }) + } +} + +#[hotpath::measure_all] +impl AsyncRead for Reader { + #[instrument(level = "trace", skip_all, ret)] + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + let cap = buf.remaining(); + if cap == 0 { + trace!("attempt to read empty buffer"); + return Poll::Ready(Ok(())); + } + + if !self.buffer.is_empty() { + if self.buffer.len() > cap { + trace!(cap, len = self.buffer.len(), "reading part of buffer"); + buf.put_slice(&self.buffer.split_to(cap)); + } else { + trace!(cap, len = self.buffer.len(), "reading full buffer"); + buf.put_slice(&mem::take(&mut self.buffer)); + } + return Poll::Ready(Ok(())); + } + let Some(incoming) = self.incoming.as_mut() else { + return Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::NotFound, + format!("subscription not found for path {:?}", self.path), + ))); + }; + trace!("polling for next message"); + match incoming.poll_next_unpin(cx) { + Poll::Ready(Some(Message { mut payload, .. })) => { + trace!(?payload, "received message"); + if payload.is_empty() { + trace!("received stream shutdown message"); + return Poll::Ready(Ok(())); + } + if payload.len() > cap { + trace!(len = payload.len(), cap, "partially reading the message"); + buf.put_slice(&payload.split_to(cap)); + self.buffer = payload; + } else { + trace!(len = payload.len(), cap, "filling the buffer with payload"); + buf.put_slice(&payload); + } + Poll::Ready(Ok(())) + } + Poll::Ready(None) => { + trace!("subscription finished"); + Poll::Ready(Ok(())) + } + Poll::Pending => Poll::Pending, + } + } +} + + + +#[derive(Clone, Debug)] +pub struct SubjectWriter { + session: Arc, + tx: String, + shutdown: bool, + tasks: Arc>, +} + +impl SubjectWriter { + fn new(session: Arc, tx: String, tasks: Arc>) -> Self { + Self { + session, + tx, + shutdown: false, + tasks, + } + } +} + +#[hotpath::measure_all] +impl wrpc_transport::Index for SubjectWriter { + #[instrument(level = "trace", skip(self))] + fn index(&self, path: &[usize]) -> anyhow::Result { + ensure!(!path.is_empty()); + let tx = index_path(&self.tx, path); + Ok(Self { + session: self.session.clone(), + tx, + shutdown: false, + tasks: Arc::clone(&self.tasks), + }) + } +} + +impl AsyncWrite for SubjectWriter { + #[instrument(level = "trace", skip_all, ret, fields(subject = self.tx, buf = format!("{buf:02x?}")))] + fn poll_write( + mut self: Pin<&mut Self>, + _cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + trace!("starting send"); + + // let msg = prepare_payload_json(None, Bytes::copy_from_slice(buf), None, None); + let zbytes = prepare_payload_zbytes(None, buf, None, None); + let zbytes_bytes = zbytes.to_bytes(); + + let subject = &self.tx; + let session = &self.session; + + trace!("writing message synchronously: key={} size={}", subject, buf.len()); + + match send_sync(session, subject, &zbytes_bytes) { + Ok(()) => { + trace!("put completed"); + Poll::Ready(Ok(buf.len())) + } + Err(e) => { + warn!(?e, "failed to publish sync put"); + Poll::Ready(Err(e)) + } + } + } + + + #[instrument(level = "trace", skip_all, ret, fields(subject = self.tx))] + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + trace!("flushing"); + Poll::Ready(Ok(())) + } + + #[instrument(level = "trace", skip_all, ret, fields(subject = self.tx))] + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + trace!("writing stream shutdown message"); + if !self.shutdown { + let session = self.session.clone(); + let key = self.tx.clone(); + self.shutdown = true; + + spawn_async(async move { + trace!("writing stream shutdown message (explicit)"); + let zbytes = prepare_payload_zbytes(None, &[], None, None); + if let Err(err) = session.put(key, zbytes).await { + warn!(?err, "failed to publish stream shutdown message"); + } + }); + } + Poll::Ready(Ok(())) + } +} + +#[hotpath::measure_all] +impl Drop for SubjectWriter { + fn drop(&mut self) { + if !self.shutdown { + let session = self.session.clone(); + let key = self.tx.clone(); + let tasks = Arc::clone(&self.tasks); + spawn_async(async move { + trace!("writing stream shutdown message"); + let zbytes = prepare_payload_zbytes(None, &[],None, None); + if let Err(err) = session.put(key, zbytes).await { + warn!(?err, "failed to publish stream shutdown message"); + } + drop(tasks); + }); + } + } +} + + + +#[derive(Default)] +pub enum RootParamWriter { + #[default] + Corrupted, + Handshaking { + session: Arc, + sub: Subscriber, + indexed: std::sync::Mutex, oneshot::Sender)>>, + buffer: Bytes, + tasks: Arc>, + }, + Draining { + tx: SubjectWriter, + buffer: Bytes, + }, + Active(SubjectWriter), +} + +impl RootParamWriter { + fn new( + session: Arc, + sub: Subscriber, + buffer: Bytes, + tasks: Arc>, + ) -> Self { + Self::Handshaking { + session, + sub, + indexed: std::sync::Mutex::default(), + buffer, + tasks, + } + } +} + +#[hotpath::measure] +fn map_status_to_error_kind(code: &str) -> Option { + let c = code.trim(); + match c { + // Allow either symbolic names or common numeric equivalents + c if c.eq_ignore_ascii_case("NO_RESPONDERS") || c == "503" => Some(io::ErrorKind::NotConnected), + c if c.eq_ignore_ascii_case("TIMEOUT") || c == "408" => Some(io::ErrorKind::TimedOut), + c if c.eq_ignore_ascii_case("REQUEST_TERMINATED") => Some(io::ErrorKind::UnexpectedEof), + _ => None, + } +} + +#[hotpath::measure_all] +impl RootParamWriter { + #[instrument(level = "trace", skip_all, ret)] + fn poll_active(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match &mut *self { + Self::Corrupted => Poll::Ready(Err(corrupted_memory_error())), + Self::Handshaking { sub, .. } => { + trace!("polling for handshake response 1"); + match sub.poll_next_unpin(cx) { + Poll::Ready(Some(Message { status: Some(code), description, .. })) => { + if let Some(kind) = map_status_to_error_kind(&code) { + return Poll::Ready(Err(kind.into())); + } + if !code.is_empty() { + let msg = match description { + Some(desc) if !desc.is_empty() => + format!("received a response with code `{code}` ({desc})"), + _ => + format!("received a response with code `{code}`"), + }; + return Poll::Ready(Err(io::Error::other(msg))); + } + // Empty status string: fall through to the generic error below + return Poll::Ready(Err(io::Error::new( + io::ErrorKind::InvalidInput, + "empty status string in handshake response", + ))); + } + Poll::Ready(Some(Message { + reply: Some(tx), .. + })) => { + let Self::Handshaking { + session, + indexed, + buffer, + tasks, + .. + } = mem::take(&mut *self) + else { + return Poll::Ready(Err(corrupted_memory_error())); + }; + let tx = SubjectWriter::new(session, param_subject(&tx), tasks); + let indexed = indexed + .into_inner() + .map_err(|err| std::io::Error::other(err.to_string()))?; + for (path, tx_tx) in indexed { + let tx = tx.index(&path).map_err(std::io::Error::other)?; + tx_tx.send(tx).map_err(|_| { + std::io::Error::from(std::io::ErrorKind::BrokenPipe) + })?; + } + trace!("handshake succeeded"); + if buffer.is_empty() { + *self = Self::Active(tx); + Poll::Ready(Ok(())) + } else { + *self = Self::Draining { tx, buffer }; + self.poll_active(cx) + } + } + Poll::Ready(Some(..)) => Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "peer did not specify a reply subject", + ))), + Poll::Ready(None) => { + *self = Self::Corrupted; + Poll::Ready(Err(std::io::Error::from(std::io::ErrorKind::BrokenPipe))) + } + Poll::Pending => Poll::Pending, + } + } + Self::Draining { tx, buffer } => { + let mut tx = pin!(tx); + while !buffer.is_empty() { + trace!(?tx.tx, "draining parameter buffer"); + match tx.as_mut().poll_write(cx, buffer) { + Poll::Ready(Ok(n)) => { + buffer.advance(n); + } + Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), + Poll::Pending => return Poll::Pending, + } + } + let Self::Draining { tx, .. } = mem::take(&mut *self) else { + return Poll::Ready(Err(corrupted_memory_error())); + }; + trace!("parameter buffer draining succeeded"); + *self = Self::Active(tx); + Poll::Ready(Ok(())) + } + Self::Active(..) => Poll::Ready(Ok(())), + } + } +} + +#[hotpath::measure_all] +impl wrpc_transport::Index for RootParamWriter { + #[instrument(level = "trace", skip(self))] + fn index(&self, path: &[usize]) -> anyhow::Result { + ensure!(!path.is_empty()); + match self { + Self::Corrupted => Err(anyhow!(corrupted_memory_error())), + Self::Handshaking { indexed, .. } => { + let (tx_tx, tx_rx) = oneshot::channel(); + let mut indexed = indexed + .lock() + .map_err(|err| std::io::Error::other(err.to_string()))?; + indexed.push((path.to_vec(), tx_tx)); + Ok(IndexedParamWriter::Handshaking { + tx_rx, + indexed: std::sync::Mutex::default(), + }) + } + Self::Draining { tx, .. } | Self::Active(tx) => { + tx.index(path).map(IndexedParamWriter::Active) + } + } + } +} + +#[hotpath::measure_all] +impl AsyncWrite for RootParamWriter { + #[instrument(level = "trace", skip_all, ret, fields(buf = format!("{buf:02x?}")))] + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + match self.as_mut().poll_active(cx)? { + Poll::Ready(()) => { + let Self::Active(tx) = &mut *self else { + return Poll::Ready(Err(corrupted_memory_error())); + }; + trace!("writing buffer"); + pin!(tx).poll_write(cx, buf) + } + Poll::Pending => Poll::Pending, + } + } + + #[instrument(level = "trace", skip_all, ret)] + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.as_mut().poll_active(cx)? { + Poll::Ready(()) => { + let Self::Active(tx) = &mut *self else { + return Poll::Ready(Err(corrupted_memory_error())); + }; + trace!("flushing"); + pin!(tx).poll_flush(cx) + } + Poll::Pending => Poll::Pending, + } + } + + #[instrument(level = "trace", skip_all, ret)] + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.as_mut().poll_active(cx)? { + Poll::Ready(()) => { + let Self::Active(tx) = &mut *self else { + return Poll::Ready(Err(corrupted_memory_error())); + }; + trace!("shutting down"); + pin!(tx).poll_shutdown(cx) + } + Poll::Pending => Poll::Pending, + } + } +} + +#[derive(Debug, Default)] +pub enum IndexedParamWriter { + #[default] + Corrupted, + Handshaking { + tx_rx: oneshot::Receiver, + indexed: std::sync::Mutex, oneshot::Sender)>>, + }, + Active(SubjectWriter), +} + + +#[hotpath::measure_all] +impl IndexedParamWriter { + #[instrument(level = "trace", skip_all, ret)] + fn poll_active(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match &mut *self { + Self::Corrupted => Poll::Ready(Err(corrupted_memory_error())), + Self::Handshaking { tx_rx, .. } => { + trace!("polling for handshake"); + match pin!(tx_rx).poll(cx) { + Poll::Ready(Ok(tx)) => { + let Self::Handshaking { indexed, .. } = mem::take(&mut *self) else { + return Poll::Ready(Err(corrupted_memory_error())); + }; + let indexed = indexed + .into_inner() + .map_err(|err| std::io::Error::other(err.to_string()))?; + for (path, tx_tx) in indexed { + let tx = tx.index(&path).map_err(std::io::Error::other)?; + tx_tx.send(tx).map_err(|_| { + std::io::Error::from(std::io::ErrorKind::BrokenPipe) + })?; + } + *self = Self::Active(tx); + Poll::Ready(Ok(())) + } + Poll::Ready(Err(..)) => Poll::Ready(Err(std::io::ErrorKind::BrokenPipe.into())), + Poll::Pending => Poll::Pending, + } + } + Self::Active(..) => Poll::Ready(Ok(())), + } + } +} + + +#[hotpath::measure_all] +impl wrpc_transport::Index for IndexedParamWriter { + #[instrument(level = "trace", skip_all)] + fn index(&self, path: &[usize]) -> anyhow::Result { + ensure!(!path.is_empty()); + match self { + Self::Corrupted => Err(anyhow!(corrupted_memory_error())), + Self::Handshaking { indexed, .. } => { + let (tx_tx, tx_rx) = oneshot::channel(); + let mut indexed = indexed + .lock() + .map_err(|err| std::io::Error::other(err.to_string()))?; + indexed.push((path.to_vec(), tx_tx)); + Ok(Self::Handshaking { + tx_rx, + indexed: std::sync::Mutex::default(), + }) + } + Self::Active(tx) => tx.index(path).map(Self::Active), + } + } +} + + +#[hotpath::measure_all] +impl AsyncWrite for IndexedParamWriter { + #[instrument(level = "trace", skip_all, ret, fields(buf = format!("{buf:02x?}")))] + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + match self.as_mut().poll_active(cx)? { + Poll::Ready(()) => { + let Self::Active(tx) = &mut *self else { + return Poll::Ready(Err(corrupted_memory_error())); + }; + trace!("writing buffer"); + pin!(tx).poll_write(cx, buf) + } + Poll::Pending => Poll::Pending, + } + } + + #[instrument(level = "trace", skip_all, ret)] + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.as_mut().poll_active(cx)? { + Poll::Ready(()) => { + let Self::Active(tx) = &mut *self else { + return Poll::Ready(Err(corrupted_memory_error())); + }; + trace!("flushing"); + pin!(tx).poll_flush(cx) + } + Poll::Pending => Poll::Pending, + } + } + + #[instrument(level = "trace", skip_all, ret)] + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.as_mut().poll_active(cx)? { + Poll::Ready(()) => { + let Self::Active(tx) = &mut *self else { + return Poll::Ready(Err(corrupted_memory_error())); + }; + trace!("shutting down"); + pin!(tx).poll_shutdown(cx) + } + Poll::Pending => Poll::Pending, + } + } +} + + +pub enum ParamWriter { + Root(RootParamWriter), + Nested(IndexedParamWriter), +} + +#[hotpath::measure_all] +impl wrpc_transport::Index for ParamWriter { + fn index(&self, path: &[usize]) -> anyhow::Result { + ensure!(!path.is_empty()); + match self { + ParamWriter::Root(w) => w.index(path), + ParamWriter::Nested(w) => w.index(path), + } + .map(Self::Nested) + } +} + +#[hotpath::measure_all] +impl AsyncWrite for ParamWriter { + #[instrument(level = "trace", skip_all, ret, fields(buf = format!("{buf:02x?}")))] + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + match &mut *self { + ParamWriter::Root(w) => pin!(w).poll_write(cx, buf), + ParamWriter::Nested(w) => pin!(w).poll_write(cx, buf), + } + } + + #[instrument(level = "trace", skip_all, ret)] + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match &mut *self { + ParamWriter::Root(w) => pin!(w).poll_flush(cx), + ParamWriter::Nested(w) => pin!(w).poll_flush(cx), + } + } + + #[instrument(level = "trace", skip_all, ret)] + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match &mut *self { + ParamWriter::Root(w) => pin!(w).poll_shutdown(cx), + ParamWriter::Nested(w) => pin!(w).poll_shutdown(cx), + } + } +} + +impl wrpc_transport::Invoke for Client { + type Context = (); + type Outgoing = ParamWriter; + type Incoming = Reader; + + #[instrument(level = "trace", skip(self, paths, params), fields(params = format!("{params:02x?}")))] + async fn invoke]> + Send + Sync>( + &self, + cx: Self::Context, + instance: &str, + func: &str, + mut params: Bytes, + paths: impl AsRef<[P]> + Send, + ) -> anyhow::Result<(Self::Outgoing, Self::Incoming)> { + let paths = paths.as_ref(); + let mut cmds = Vec::with_capacity(paths.len().saturating_add(2)); + + let rx = child_inbox(&self.inbox); + let (handshake_tx, handshake_rx) = mpsc::channel(1); + cmds.push(Command::Subscribe(rx.clone(), handshake_tx)); + + let result = result_subject(&rx); + let (result_tx, result_rx) = mpsc::channel(16); + cmds.push(Command::Subscribe(result.clone(), result_tx)); + + let nested = paths.iter().map(|path| { + let (tx, rx) = mpsc::channel(16); + let subject = subscribe_path(&result, path.as_ref()); + cmds.push(Command::Subscribe(subject.clone(), tx)); + Subscriber { + rx: ReceiverStream::new(rx), + commands: self.commands.clone(), + subject, + tasks: Arc::clone(&self.tasks), + } + }); + let nested: IndexTrie = zip(paths.iter(), nested).collect(); + ensure!( + paths.is_empty() == nested.is_empty(), + "failed to construct subscription tree" + ); + + let (ack_tx, ack_rx) = oneshot::channel(); + + self.commands + .send(Command::Batch(cmds.into_boxed_slice(), ack_tx)) + .await + .context("failed to subscribe")?; + + ack_rx.await?; + + let param_tx = invocation_subject(&self.prefix, instance, func); + trace!("publishing handshake"); + publish_with_reply( + &self.session, + param_tx, + rx.clone(), + params) + .await.unwrap(); + + // let session = Arc::clone(&self.session); + // tokio::spawn(async move { + // if let Err(err) = nats.flush().await { + // error!(?err, "failed to flush"); + // } + // }); + Ok(( + ParamWriter::Root(RootParamWriter::new( + (*self.session).clone().into(), + Subscriber { + rx: ReceiverStream::new(handshake_rx), + commands: self.commands.clone(), + subject: rx, + tasks: Arc::clone(&self.tasks), + }, + Bytes::new(), + Arc::clone(&self.tasks), + )), + Reader { + buffer: Bytes::default(), + incoming: Some(Subscriber { + rx: ReceiverStream::new(result_rx), + commands: self.commands.clone(), + subject: result, + tasks: Arc::clone(&self.tasks), + }), + nested: Arc::new(std::sync::Mutex::new(nested)), + path: Box::default(), + }, + )) + } +} + +#[hotpath::measure] +async fn handle_message( + session: &zenoh::Session, + rx: String, + commands: mpsc::Sender, + Message { + reply: tx, + payload, + .. + }: Message, + paths: &[Box<[Option]>], + tasks: Arc>, +) -> anyhow::Result<((), SubjectWriter, Reader)> { + let tx = tx.clone(); + + let mut cmds = Vec::with_capacity(paths.len().saturating_add(1)); + + let param = param_subject(&rx); + let (param_tx, param_rx) = mpsc::channel(16); + cmds.push(Command::Subscribe(param.clone(), param_tx)); + + let nested = paths.iter().map(|path| { + let (tx, rx) = mpsc::channel(16); + let subject = subscribe_path(¶m, path.as_ref()); + cmds.push(Command::Subscribe(subject.clone(), tx)); + Subscriber { + rx: ReceiverStream::new(rx), + commands: commands.clone(), + subject, + tasks: Arc::clone(&tasks), + } + }); + let nested: IndexTrie = zip(paths.iter(), nested).collect(); + ensure!( + paths.is_empty() == nested.is_empty(), + "failed to construct subscription tree" + ); + + let (ack_tx, ack_rx) = oneshot::channel(); + + commands + .send(Command::Batch(cmds.into_boxed_slice(), ack_tx)) + .await + .context("failed to subscribe")?; + + ack_rx.await?; + + trace!("publishing handshake response"); + publish_with_reply(session, tx.clone().unwrap(), rx, Bytes::default()) + .await.unwrap(); + Ok(( + (), + SubjectWriter::new( + session.clone().into(), + result_subject(&tx.unwrap()), + Arc::clone(&tasks), + ), + Reader { + buffer: payload, + incoming: Some(Subscriber { + rx: ReceiverStream::new(param_rx), + commands, + subject: param, + tasks, + }), + nested: Arc::new(std::sync::Mutex::new(nested)), + path: Box::default(), + }, + )) +} + +#[hotpath::measure_all] +impl wrpc_transport::Serve for Client { + type Context = (); + type Outgoing = SubjectWriter; + type Incoming = Reader; + + #[instrument(level = "trace", skip(self, paths))] + async fn serve( + &self, + instance: &str, + func: &str, + paths: impl Into]>]>> + Send, + ) -> anyhow::Result< + impl Stream> + 'static, + > { + let subject = invocation_subject(&self.prefix, instance, func); + + //println!("Client serve subscribe to: {}", subject); + + let sub = self.session.declare_subscriber(subject).await.unwrap(); + let session = Arc::clone(&self.session); + let paths = paths.into(); + let commands = self.commands.clone(); + let inbox_root = self.inbox.clone(); + let tasks = Arc::clone(&self.tasks); + + let stream = futures::stream::unfold( + (sub, session, paths, commands, tasks, inbox_root), + |(sub, session, paths, commands, tasks, inbox_root)| async move { + match sub.recv_async().await { + Ok(sample) => { + let (subject, + reply, + payload, + status, + description) = parse_zbytes_message(sample); + + let message = Message { + subject, + reply, + payload, + status, + description, + }; + + let rx = child_inbox(inbox_root.as_ref()); + let item = handle_message( + &session, rx, commands.clone(), message, &paths, Arc::clone(&tasks) + ).await; + + // put `inboxroot` back into state for the next loop + Some((item, (sub, session, paths, commands, tasks, inbox_root))) + } + Err(_) => None, + } + }, + ); + + Ok(stream) + } +} diff --git a/crates/wasmtime-cli/Cargo.toml b/crates/wasmtime-cli/Cargo.toml index eee5e0b5a..d547b58c6 100644 --- a/crates/wasmtime-cli/Cargo.toml +++ b/crates/wasmtime-cli/Cargo.toml @@ -69,4 +69,6 @@ wit-component = { workspace = true } wrpc-cli = { workspace = true, features = ["nats"] } wrpc-transport-nats = { workspace = true } wrpc-transport = { workspace = true, features = ["net"] } +wrpc-transport-zenoh = { workspace = true, features = ["zenoh-1_5_0"] } wrpc-runtime-wasmtime = { workspace = true } +zenoh = { workspace = true } \ No newline at end of file diff --git a/crates/wasmtime-cli/src/lib.rs b/crates/wasmtime-cli/src/lib.rs index 4f310adc7..a89eef419 100644 --- a/crates/wasmtime-cli/src/lib.rs +++ b/crates/wasmtime-cli/src/lib.rs @@ -32,6 +32,7 @@ use wrpc_transport::{Invoke, Serve}; mod nats; mod tcp; +mod zenoh; const DEFAULT_TIMEOUT: &str = "10s"; @@ -42,6 +43,8 @@ enum Command { Nats(nats::Command), #[command(subcommand)] Tcp(tcp::Command), + #[command(subcommand)] + Zenoh(zenoh::Command), } pub enum Workload { @@ -495,12 +498,15 @@ where name, ) .await?; + + let name_copy = name.to_owned(); + handlers.spawn(async move { let mut invocations = pin!(invocations); while let Some(invocation) = invocations.next().await { match invocation { Ok((_, fut)) => { - info!("serving instance function invocation"); + info!(?name_copy, "serving instance function invocation"); if let Err(err) = fut.await { warn!( ?err, @@ -508,7 +514,7 @@ where ); } else { info!( - "successfully served instance function invocation" + ?name_copy, "successfully served instance function invocation" ); } } @@ -651,6 +657,7 @@ where name, ) .await?; + handlers.spawn(async move { let mut invocations = pin!(invocations); while let Some(invocation) = invocations.next().await { @@ -664,7 +671,7 @@ where ); } else { info!( - "successfully served instance function invocation" + "successfully served instance function invocation: " ); } } @@ -766,5 +773,6 @@ pub async fn run() -> anyhow::Result<()> { match Command::parse() { Command::Nats(args) => nats::run(args).await, Command::Tcp(args) => tcp::run(args).await, + Command::Zenoh(args) => zenoh::run(args).await, } } diff --git a/crates/wasmtime-cli/src/zenoh.rs b/crates/wasmtime-cli/src/zenoh.rs new file mode 100644 index 000000000..87a7bb4a4 --- /dev/null +++ b/crates/wasmtime-cli/src/zenoh.rs @@ -0,0 +1,98 @@ +use std::sync::Arc; + +use anyhow::Context as _; +use clap::Parser; +use tracing::instrument; + +/// Zenoh transport +#[derive(Parser, Debug)] +pub enum Command { + Run(RunArgs), + Serve(ServeArgs), +} + +/// Run a command component +#[derive(Parser, Debug)] +pub struct RunArgs { + /// Invocation timeout + #[arg(long, default_value = crate::DEFAULT_TIMEOUT)] + timeout: humantime::Duration, + + /// Prefix to send import invocations to + #[arg(long, default_value = "")] + import: String, + + /// Path or URL to Wasm command component + workload: String, +} + +/// Serve a reactor component +#[derive(Parser, Debug)] +pub struct ServeArgs { + /// Invocation timeout + #[arg(long, default_value = crate::DEFAULT_TIMEOUT)] + timeout: humantime::Duration, + + /// Prefix to send import invocations to + #[arg(long, default_value = "")] + import: String, + + /// Prefix to listen for export invocations on + #[arg(long, default_value = "")] + export: String, + + /// Path or URL to Wasm command component + workload: String, +} + +#[instrument(level = "trace", ret(level = "trace"))] +pub async fn handle_run( + RunArgs { + timeout, + import, + ref workload, + }: RunArgs, +) -> anyhow::Result<()> { + let zenoh = wrpc_cli::zenoh::connect() + .await + .context("failed to connect to zenoh")?; + let zenoh_client = wrpc_transport_zenoh::Client::new(zenoh, import) + .await + .context("failed to construct zenoh transport")?; + let res = crate::handle_run(zenoh_client, (), *timeout, workload).await; + //println!("foooooo run"); + res +} + +#[instrument(level = "trace", ret(level = "trace"))] +pub async fn handle_serve( + ServeArgs { + timeout, + export, + import, + ref workload, + }: ServeArgs, +) -> anyhow::Result<()> { + let zenoh = wrpc_cli::zenoh::connect() + .await + .context("failed to connect to zenoh")?; + let zenoh = Arc::new(zenoh); + let exports = wrpc_transport_zenoh::Client::new(zenoh.clone(), export) + .await + .context("failed to construct zenoh transport export client")?; + let imports = wrpc_transport_zenoh::Client::new(zenoh.clone(), import) + .await + .context("failed to construct zenoh transport import client")?; + //println!("foooooo serve"); + // future::pending::<()>().await; + // res + crate::handle_serve(exports, imports, (), *timeout, workload).await +} + +#[instrument(level = "trace", ret(level = "trace"))] +pub async fn run(cmd: Command) -> anyhow::Result<()> { + match cmd { + Command::Run(args) => handle_run(args).await, + Command::Serve(args) => handle_serve(args).await, + } +} diff --git a/examples/rust/hello-component-zclient/Cargo.toml b/examples/rust/hello-component-zclient/Cargo.toml new file mode 100644 index 000000000..e2854e185 --- /dev/null +++ b/examples/rust/hello-component-zclient/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "hello-component-zclient" +version = "0.1.0" + +authors.workspace = true +categories.workspace = true +edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +wit-bindgen = { workspace = true, features = ["realloc", "macros"] } diff --git a/examples/rust/hello-component-zclient/src/main.rs b/examples/rust/hello-component-zclient/src/main.rs new file mode 100644 index 000000000..045b3518e --- /dev/null +++ b/examples/rust/hello-component-zclient/src/main.rs @@ -0,0 +1,19 @@ +use std::time::Instant; + +//WRPC wasm/client to work with hello-zenoh-server(host) + +mod bindings { + wit_bindgen::generate!({ + with: { + "wrpc-examples:hello/handler": generate, + } + }); +} + +fn main() { + let start = Instant::now(); + let response_str = bindings::wrpc_examples::hello::handler::hello(); + println!("*** Response: {response_str}"); + let elapsed = start.elapsed(); + println!("*** Elapsed get: {elapsed:?}"); +} diff --git a/examples/rust/hello-component-zclient/wit/deps.lock b/examples/rust/hello-component-zclient/wit/deps.lock new file mode 100644 index 000000000..275cb66c0 --- /dev/null +++ b/examples/rust/hello-component-zclient/wit/deps.lock @@ -0,0 +1,4 @@ +[hello] +path = "../../../wit/hello" +sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" +sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" diff --git a/examples/rust/hello-component-zclient/wit/deps.toml b/examples/rust/hello-component-zclient/wit/deps.toml new file mode 100644 index 000000000..084f03eb0 --- /dev/null +++ b/examples/rust/hello-component-zclient/wit/deps.toml @@ -0,0 +1 @@ +hello = "../../../wit/hello" diff --git a/examples/rust/hello-component-zclient/wit/deps/hello/hello.wit b/examples/rust/hello-component-zclient/wit/deps/hello/hello.wit new file mode 100644 index 000000000..6c84d66cc --- /dev/null +++ b/examples/rust/hello-component-zclient/wit/deps/hello/hello.wit @@ -0,0 +1,13 @@ +package wrpc-examples:hello; + +interface handler { + hello: func() -> string; +} + +world client { + import handler; +} + +world server { + export handler; +} diff --git a/examples/rust/hello-component-zclient/wit/world.wit b/examples/rust/hello-component-zclient/wit/world.wit new file mode 100644 index 000000000..97aae5a62 --- /dev/null +++ b/examples/rust/hello-component-zclient/wit/world.wit @@ -0,0 +1,5 @@ +package wrpc-examples:hello-component-client; + +world client { + include wrpc-examples:hello/client; +} diff --git a/examples/rust/hello-zenoh-client/Cargo.toml b/examples/rust/hello-zenoh-client/Cargo.toml new file mode 100644 index 000000000..caf6d67ea --- /dev/null +++ b/examples/rust/hello-zenoh-client/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "hello-zenoh-client" +version = "0.1.0" + +authors.workspace = true +categories.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +anyhow = { workspace = true } +zenoh = { workspace = true, features = ["transport_tcp"] } +clap = { workspace = true, features = [ + "color", + "derive", + "error-context", + "help", + "std", + "suggestions", + "usage", +] } +tokio = { workspace = true, features = ["rt-multi-thread"] } +tracing-subscriber = { workspace = true, features = ["ansi", "fmt"] } +url = { workspace = true } +wit-bindgen-wrpc = { workspace = true } +wrpc-transport-zenoh = { workspace = true, features = ["zenoh-1_5_0"] } diff --git a/examples/rust/hello-zenoh-client/src/main.rs b/examples/rust/hello-zenoh-client/src/main.rs new file mode 100644 index 000000000..7abbe08c5 --- /dev/null +++ b/examples/rust/hello-zenoh-client/src/main.rs @@ -0,0 +1,81 @@ +use std::sync::Arc; +use anyhow::Context as _; +use zenoh::{Config}; +use std::time::Instant; + +mod bindings { + wit_bindgen_wrpc::generate!({ + with: { + "wrpc-examples:hello/handler": generate + } + }); +} + + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt().init(); + + let cfg = Config::from_env().expect("Missing environment variable 'ZENOH_CONFIG'"); + + let session = zenoh::open(cfg) + .await + .expect("Failed to open a Zenoh session"); + + let arc_session = Arc::new(session); + + let prefix = Arc::::from(""); + + let wrpc = wrpc_transport_zenoh::Client::new(arc_session, prefix) + .await + .context("failed to construct transport client")?; + + // From hello-nats-client + // let hello = bindings::wrpc_examples::hello::handler::hello(&wrpc, ()) + // .await + // .context("failed to invoke `wrpc-examples.hello/handler.hello`")?; + + // eprintln!("NOT_USED_var:prefix: {hello}"); + + // actually useful stuff + let ipv4_address = bindings::wrpc_examples::hello::handler::Ipv4Address{octets: (0,0,0,0)}; + let timespec = bindings::wrpc_examples::hello::handler::Timespec{tv_sec:-111, tv_nsec:111}; + let tr = bindings::wrpc_examples::hello::handler::Tracking { + ref_id: 32, + ip_addr: ipv4_address, + stratum: 16, + leap_status: 16, + ref_time: timespec, + current_correction: 64.0, + last_offset: 64.0, + rms_offset: 64.0, + freq_ppm: 64.0, + resid_freq_ppm: 64.0, + skew_ppm: 64.0, + root_delay: 64.0, + root_dispersion: 64.0, + last_update_interval: 64.0, + }; + + let start = Instant::now(); + let limit = 100001; + for i in 1..limit { + let t1 = bindings::wrpc_examples::hello::handler::get_tracking(&wrpc, (), &tr) + .await + .context("failed to invoke `wrpc-examples.hello/handler.hello`")?; + + // tiny sleep to allow buffers to clear + // tokio::time::sleep(tokio::time::Duration::from_micros(33)).await; + + // println!("Call {i} {:?}", t1.ref_id); + } + + // Record the time after the loop finishes and calculate the duration + let duration = start.elapsed(); + + // Print the elapsed time + // The {:?} formatter uses the Debug implementation for Duration + println!("Time elapsed in the loop is for {limit} calls. Time Elapsed: {duration:?}"); + + Ok(()) +} diff --git a/examples/rust/hello-zenoh-client/wit/deps.lock b/examples/rust/hello-zenoh-client/wit/deps.lock new file mode 100644 index 000000000..275cb66c0 --- /dev/null +++ b/examples/rust/hello-zenoh-client/wit/deps.lock @@ -0,0 +1,4 @@ +[hello] +path = "../../../wit/hello" +sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" +sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" diff --git a/examples/rust/hello-zenoh-client/wit/deps.toml b/examples/rust/hello-zenoh-client/wit/deps.toml new file mode 100644 index 000000000..084f03eb0 --- /dev/null +++ b/examples/rust/hello-zenoh-client/wit/deps.toml @@ -0,0 +1 @@ +hello = "../../../wit/hello" diff --git a/examples/rust/hello-zenoh-client/wit/deps/hello/hello.wit b/examples/rust/hello-zenoh-client/wit/deps/hello/hello.wit new file mode 100644 index 000000000..29ea9780f --- /dev/null +++ b/examples/rust/hello-zenoh-client/wit/deps/hello/hello.wit @@ -0,0 +1,43 @@ +package wrpc-examples:hello; + +interface handler { + record timespec { + tv-sec: s64, + tv-nsec: u32 + } + + record tracking { + ref-id: u32, + ip-addr: ipv4-address, + stratum: u16, + leap-status: u16, + ref-time: timespec, + current-correction: f64, + last-offset: f64, + rms-offset: f64, + freq-ppm: f64, + resid-freq-ppm: f64, + skew-ppm: f64, + root-delay: f64, + root-dispersion: f64, + last-update-interval: f64, + } + + record ipv4-address { + // It seems that a list with a fixed size is supported in the WIT standard. However I have no clue if wasmtime implements it... + // octets: list, // https: //github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#types + + octets: tuple // Backup solution: closest to a static u8 array with 4 elements + } + + hello: func() -> string; + get-tracking: func(t: tracking) -> tracking; +} + +world client { + import handler; +} + +world server { + export handler; +} diff --git a/examples/rust/hello-zenoh-client/wit/world.wit b/examples/rust/hello-zenoh-client/wit/world.wit new file mode 100644 index 000000000..f9a08b60d --- /dev/null +++ b/examples/rust/hello-zenoh-client/wit/world.wit @@ -0,0 +1,5 @@ +package wrpc-examples:hello-rust-client; + +world client { + include wrpc-examples:hello/client; +} diff --git a/examples/rust/hello-zenoh-server/Cargo.toml b/examples/rust/hello-zenoh-server/Cargo.toml new file mode 100644 index 000000000..02679ae94 --- /dev/null +++ b/examples/rust/hello-zenoh-server/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "hello-zenoh-server" +version = "0.1.0" + +authors.workspace = true +categories.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +anyhow = { workspace = true } +zenoh = { workspace = true, features = ["transport_tcp"] } +clap = { workspace = true, features = [ + "color", + "derive", + "error-context", + "help", + "std", + "suggestions", + "usage", +] } +futures = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread", "signal"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["ansi", "fmt"] } +url = { workspace = true } +wit-bindgen-wrpc = { workspace = true } +wrpc-transport-zenoh = { workspace = true, features = ["zenoh-1_5_0"] } +hotpath = "0.9" + +[features] +hotpath = ["hotpath/hotpath"] +hotpath-alloc = ["hotpath/hotpath-alloc"] diff --git a/examples/rust/hello-zenoh-server/src/main.rs b/examples/rust/hello-zenoh-server/src/main.rs new file mode 100644 index 000000000..6a0bc8759 --- /dev/null +++ b/examples/rust/hello-zenoh-server/src/main.rs @@ -0,0 +1,101 @@ +use core::pin::pin; +use std::sync::Arc; + +use anyhow::Context as _; +use futures::stream::select_all; +use futures::StreamExt as _; +use tokio::task::JoinSet; +use tokio::{select, signal}; +use tracing::{debug, error, info, warn}; +use zenoh::{Config}; + +mod bindings { + wit_bindgen_wrpc::generate!({ + with: { + "wrpc-examples:hello/handler": generate, + } + }); +} + +#[derive(Clone, Copy)] +struct Server; + +impl bindings::exports::wrpc_examples::hello::handler::Handler<()> + for Server +{ + async fn hello(&self, _: ()) -> anyhow::Result { + Ok("hello from Rust".to_string()) + } + + async fn get_tracking(&self, _cx: (), t:bindings::exports::wrpc_examples::hello::handler::Tracking) -> Result { + Ok(t) + } +} + +#[tokio::main] +#[hotpath::main(percentiles = [99])] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt().init(); + + let cfg = Config::from_env().expect("Missing environment variable 'ZENOH_CONFIG'"); + + let session = zenoh::open(cfg) + .await + .expect("Failed to open a Zenoh session"); + + let arc_session = Arc::new(session); + + let prefix = Arc::::from(""); + + let wrpc = wrpc_transport_zenoh::Client::new(arc_session, prefix) + .await + .context("failed to construct transport client")?; + let invocations = bindings::serve(&wrpc, Server) + .await + .context("failed to serve `wrpc-examples.hello/handler.hello`")?; + // NOTE: This will conflate all invocation streams into a single stream via `futures::stream::SelectAll`, + // to customize this, iterate over the returned `invocations` and set up custom handling per export + let mut invocations = select_all( + invocations + .into_iter() + .map(|(instance, name, invocations)| invocations.map(move |res| (instance, name, res))), + ); + let shutdown = signal::ctrl_c(); + let mut shutdown = pin!(shutdown); + let mut tasks = JoinSet::new(); + loop { + select! { + Some((instance, name, res)) = invocations.next() => { + match res { + Ok(fut) => { + debug!(instance, name, "invocation accepted"); + tasks.spawn(async move { + if let Err(err) = fut.await { + warn!(?err, "failed to handle invocation"); + } else { + info!(instance, name, "invocation successfully handled"); + } + }); + } + Err(err) => { + warn!(?err, instance, name, "failed to accept invocation"); + } + } + } + Some(res) = tasks.join_next() => { + if let Err(err) = res { + error!(?err, "failed to join task") + } + } + res = &mut shutdown => { + // wait for all invocations to complete + while let Some(res) = tasks.join_next().await { + if let Err(err) = res { + error!(?err, "failed to join task") + } + } + return res.context("failed to listen for ^C") + } + } + } +} diff --git a/examples/rust/hello-zenoh-server/wit/deps.lock b/examples/rust/hello-zenoh-server/wit/deps.lock new file mode 100644 index 000000000..275cb66c0 --- /dev/null +++ b/examples/rust/hello-zenoh-server/wit/deps.lock @@ -0,0 +1,4 @@ +[hello] +path = "../../../wit/hello" +sha256 = "3680bb734f3fa9f7325674142a2a9b558efd34ea2cb2df7ccb651ad869078d27" +sha512 = "688fdae594dc43bd65bd15ea66b77a8f97cb4bc1c3629719e91d6c1391c66f7c8c6517d096f686cca996188f64f075c4ccb0d70a40097ce76b8b4bcc71dc7506" diff --git a/examples/rust/hello-zenoh-server/wit/deps.toml b/examples/rust/hello-zenoh-server/wit/deps.toml new file mode 100644 index 000000000..084f03eb0 --- /dev/null +++ b/examples/rust/hello-zenoh-server/wit/deps.toml @@ -0,0 +1 @@ +hello = "../../../wit/hello" diff --git a/examples/rust/hello-zenoh-server/wit/deps/hello/hello.wit b/examples/rust/hello-zenoh-server/wit/deps/hello/hello.wit new file mode 100644 index 000000000..29ea9780f --- /dev/null +++ b/examples/rust/hello-zenoh-server/wit/deps/hello/hello.wit @@ -0,0 +1,43 @@ +package wrpc-examples:hello; + +interface handler { + record timespec { + tv-sec: s64, + tv-nsec: u32 + } + + record tracking { + ref-id: u32, + ip-addr: ipv4-address, + stratum: u16, + leap-status: u16, + ref-time: timespec, + current-correction: f64, + last-offset: f64, + rms-offset: f64, + freq-ppm: f64, + resid-freq-ppm: f64, + skew-ppm: f64, + root-delay: f64, + root-dispersion: f64, + last-update-interval: f64, + } + + record ipv4-address { + // It seems that a list with a fixed size is supported in the WIT standard. However I have no clue if wasmtime implements it... + // octets: list, // https: //github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#types + + octets: tuple // Backup solution: closest to a static u8 array with 4 elements + } + + hello: func() -> string; + get-tracking: func(t: tracking) -> tracking; +} + +world client { + import handler; +} + +world server { + export handler; +} diff --git a/examples/rust/hello-zenoh-server/wit/world.wit b/examples/rust/hello-zenoh-server/wit/world.wit new file mode 100644 index 000000000..8fffd81fd --- /dev/null +++ b/examples/rust/hello-zenoh-server/wit/world.wit @@ -0,0 +1,5 @@ +package wrpc-examples:hello-rust-server; + +world server { + include wrpc-examples:hello/server; +} diff --git a/examples/rust/streams-zenoh-client/Cargo.toml b/examples/rust/streams-zenoh-client/Cargo.toml new file mode 100644 index 000000000..698874803 --- /dev/null +++ b/examples/rust/streams-zenoh-client/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "streams-zenoh-client" +version = "0.1.0" + +authors.workspace = true +categories.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +anyhow = { workspace = true } +zenoh = { workspace = true, features = ["transport_tcp"] } +bytes = { workspace = true } +clap = { workspace = true, features = [ + "color", + "derive", + "error-context", + "help", + "std", + "suggestions", + "usage", +] } +futures = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread"] } +tokio-stream = { workspace = true, features = ["time"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = [ + "ansi", + "env-filter", + "fmt", +] } +url = { workspace = true } +wit-bindgen-wrpc = { workspace = true } +wrpc-transport-zenoh = { workspace = true, features = ["zenoh-1_5_0"] } diff --git a/examples/rust/streams-zenoh-client/src/main.rs b/examples/rust/streams-zenoh-client/src/main.rs new file mode 100644 index 000000000..93bf87bd8 --- /dev/null +++ b/examples/rust/streams-zenoh-client/src/main.rs @@ -0,0 +1,87 @@ +use core::time::Duration; +use std::sync::Arc; + +use anyhow::Context as _; +use bytes::Bytes; +use futures::{stream, StreamExt as _}; +use tokio::{time, try_join}; +use tokio_stream::wrappers::IntervalStream; +use tracing::debug; +use zenoh::{Config}; + +mod bindings { + wit_bindgen_wrpc::generate!({ + with: { + "wrpc-examples:streams/handler": generate + } + }); +} + +use bindings::wrpc_examples::streams::handler::{echo, Req}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt().init(); + + let cfg = Config::from_env().expect("Missing environment variable 'ZENOH_CONFIG'"); + + let session = zenoh::open(cfg) + .await + .expect("Failed to open a Zenoh session"); + + let arc_session = Arc::new(session); + + let prefix = Arc::::from("rust"); + //let prefixes = vec!["Hello", "Zenoh", "streams!"]; // Expected was a string vec ... ! + + //for prefix in prefixes { + let numbers = Box::pin( + stream::iter(1..) + .take(10) + .zip(IntervalStream::new(time::interval(Duration::from_secs(1)))) + .map(|(i, _)| i) + .ready_chunks(10), + ); + + // `stream` items are chunked using [`Bytes`] + let bytes = Box::pin( + stream::iter(b"foo bar baz") + .zip(IntervalStream::new(time::interval(Duration::from_secs(1)))) + .map(|(i, _)| *i) + .ready_chunks(10) + .map(Bytes::from), + ); + + // Client creation moved here from top + let wrpc = wrpc_transport_zenoh::Client::new(arc_session, prefix) + .await + .context("failed to construct transport client")?; + + let (mut numbers, mut bytes, io) = echo(&wrpc, (), Req { numbers, bytes }) + .await + .context("failed to invoke `wrpc-examples:streams/handler.echo`")?; + try_join!( + async { + if let Some(io) = io { + debug!("performing async I/O"); + io.await.context("failed to complete async I/O") + } else { + Ok(()) + } + }, + async { + while let Some(item) = numbers.next().await { + eprintln!("numbers: {item:?}"); + } + Ok(()) + }, + async { + while let Some(item) = bytes.next().await { + eprintln!("bytes: {item:?}"); + } + Ok(()) + } + )?; + //} + Ok(()) +} diff --git a/examples/rust/streams-zenoh-client/wit/deps.lock b/examples/rust/streams-zenoh-client/wit/deps.lock new file mode 100644 index 000000000..640642729 --- /dev/null +++ b/examples/rust/streams-zenoh-client/wit/deps.lock @@ -0,0 +1,4 @@ +[streams] +path = "../../../wit/streams" +sha256 = "5064bee90ebea73f1695987191fbbfea71ed2dbb69839814009490b4fbe8e96f" +sha512 = "dfca3844d91c6c8e83fefd7b9511a366b464cf69d017c61b671409cb26dc9490a0e59a8e60ef15b77fdeb4fc1b8d9e6efa11c2fb1a1dabd0141e5e6afe8a59b9" diff --git a/examples/rust/streams-zenoh-client/wit/deps.toml b/examples/rust/streams-zenoh-client/wit/deps.toml new file mode 100644 index 000000000..7ad7d00c7 --- /dev/null +++ b/examples/rust/streams-zenoh-client/wit/deps.toml @@ -0,0 +1 @@ +streams = "../../../wit/streams" diff --git a/examples/rust/streams-zenoh-client/wit/deps/streams/streams.wit b/examples/rust/streams-zenoh-client/wit/deps/streams/streams.wit new file mode 100644 index 000000000..8520741c2 --- /dev/null +++ b/examples/rust/streams-zenoh-client/wit/deps/streams/streams.wit @@ -0,0 +1,17 @@ +package wrpc-examples:streams; + +interface handler { + record req { + numbers: stream, + bytes: stream, + } + echo: func(r: req) -> (numbers: stream, bytes: stream); +} + +world client { + import handler; +} + +world server { + export handler; +} diff --git a/examples/rust/streams-zenoh-client/wit/world.wit b/examples/rust/streams-zenoh-client/wit/world.wit new file mode 100644 index 000000000..5f6997fdc --- /dev/null +++ b/examples/rust/streams-zenoh-client/wit/world.wit @@ -0,0 +1,5 @@ +package wrpc-examples:streams-rust-client; + +world client { + include wrpc-examples:streams/client; +} diff --git a/examples/rust/streams-zenoh-server/Cargo.toml b/examples/rust/streams-zenoh-server/Cargo.toml new file mode 100644 index 000000000..3dbf317e1 --- /dev/null +++ b/examples/rust/streams-zenoh-server/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "streams-zenoh-server" +version = "0.1.0" + +authors.workspace = true +categories.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +anyhow = { workspace = true } +zenoh = { workspace = true, features = ["transport_tcp"] } +bytes = { workspace = true } +clap = { workspace = true, features = [ + "color", + "derive", + "error-context", + "help", + "std", + "suggestions", + "usage", +] } +futures = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread", "signal"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = [ + "ansi", + "env-filter", + "fmt", +] } +url = { workspace = true } +wit-bindgen-wrpc = { workspace = true } +wrpc-transport-zenoh = { workspace = true, features = ["zenoh-1_5_0"] } +hotpath = "0.9" + +[features] +hotpath = ["hotpath/hotpath"] +hotpath-alloc = ["hotpath/hotpath-alloc"] \ No newline at end of file diff --git a/examples/rust/streams-zenoh-server/src/main.rs b/examples/rust/streams-zenoh-server/src/main.rs new file mode 100644 index 000000000..3c0c7f2e8 --- /dev/null +++ b/examples/rust/streams-zenoh-server/src/main.rs @@ -0,0 +1,119 @@ +use core::pin::{pin, Pin}; +use std::sync::Arc; + +use anyhow::Context as _; +use bytes::Bytes; +use futures::stream::select_all; +use futures::{Stream, StreamExt as _}; +use tokio::task::JoinSet; +use tokio::{select, signal}; +use tracing::{debug, error, info, warn}; +use zenoh::{Config}; + +mod bindings { + wit_bindgen_wrpc::generate!({ + with: { + "wrpc-examples:streams/handler": generate, + } + }); +} + +use bindings::exports::wrpc_examples::streams::handler::Req; + +// #[derive(Parser, Debug)] +// #[command(author, version, about, long_about = None)] +// struct Args { +// /// NATS.io URL to connect to +// #[arg(short, long, default_value = "nats://127.0.0.1:4222")] +// nats: Url, + +// /// Prefix to serve `wrpc-examples:streams/handler.echo` on +// #[arg(default_value = "rust")] +// prefix: String, +// } + +#[derive(Clone, Copy)] +struct Server; + +impl bindings::exports::wrpc_examples::streams::handler::Handler<()> for Server +{ + async fn echo( + &self, + _cx: (), + Req { numbers, bytes }: Req, + ) -> anyhow::Result<( + Pin> + Send>>, + Pin + Send>>, + )> { + Ok((numbers, bytes)) + } +} + +#[tokio::main] +#[hotpath::main(percentiles = [99])] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt().init(); + + let cfg = Config::from_env().expect("Missing environment variable 'ZENOH_CONFIG'"); + + let session = zenoh::open(cfg) + .await + .expect("Failed to open a Zenoh session"); + + let arc_session = Arc::new(session); + + let prefix = Arc::::from("rust"); + + let wrpc = wrpc_transport_zenoh::Client::new(arc_session, prefix) + .await + .context("failed to construct transport client")?; + let invocations = bindings::serve(&wrpc, Server) + .await + .context("failed to serve `wrpc-examples:streams/handler.echo`")?; + + // NOTE: This will conflate all invocation streams into a single stream via `futures::stream::SelectAll`, + // to customize this, iterate over the returned `invocations` and set up custom handling per export + let mut invocations = select_all( + invocations + .into_iter() + .map(|(instance, name, invocations)| invocations.map(move |res| (instance, name, res))), + ); + let shutdown = signal::ctrl_c(); + let mut shutdown = pin!(shutdown); + let mut tasks = JoinSet::new(); + loop { + select! { + Some((instance, name, res)) = invocations.next() => { + match res { + Ok(fut) => { + debug!(instance, name, "invocation accepted"); + tasks.spawn(async move { + if let Err(err) = fut.await { + warn!(?err, "failed to handle invocation"); + } else { + info!(instance, name, "invocation successfully handled"); + } + }); + } + Err(err) => { + warn!(?err, instance, name, "failed to accept invocation"); + } + } + } + Some(res) = tasks.join_next() => { + if let Err(err) = res { + error!(?err, "failed to join task") + } + } + res = &mut shutdown => { + // wait for all invocations to complete + while let Some(res) = tasks.join_next().await { + if let Err(err) = res { + error!(?err, "failed to join task") + } + } + return res.context("failed to listen for ^C") + } + } + } +} diff --git a/examples/rust/streams-zenoh-server/wit/deps.lock b/examples/rust/streams-zenoh-server/wit/deps.lock new file mode 100644 index 000000000..640642729 --- /dev/null +++ b/examples/rust/streams-zenoh-server/wit/deps.lock @@ -0,0 +1,4 @@ +[streams] +path = "../../../wit/streams" +sha256 = "5064bee90ebea73f1695987191fbbfea71ed2dbb69839814009490b4fbe8e96f" +sha512 = "dfca3844d91c6c8e83fefd7b9511a366b464cf69d017c61b671409cb26dc9490a0e59a8e60ef15b77fdeb4fc1b8d9e6efa11c2fb1a1dabd0141e5e6afe8a59b9" diff --git a/examples/rust/streams-zenoh-server/wit/deps.toml b/examples/rust/streams-zenoh-server/wit/deps.toml new file mode 100644 index 000000000..7ad7d00c7 --- /dev/null +++ b/examples/rust/streams-zenoh-server/wit/deps.toml @@ -0,0 +1 @@ +streams = "../../../wit/streams" diff --git a/examples/rust/streams-zenoh-server/wit/deps/streams/streams.wit b/examples/rust/streams-zenoh-server/wit/deps/streams/streams.wit new file mode 100644 index 000000000..8520741c2 --- /dev/null +++ b/examples/rust/streams-zenoh-server/wit/deps/streams/streams.wit @@ -0,0 +1,17 @@ +package wrpc-examples:streams; + +interface handler { + record req { + numbers: stream, + bytes: stream, + } + echo: func(r: req) -> (numbers: stream, bytes: stream); +} + +world client { + import handler; +} + +world server { + export handler; +} diff --git a/examples/rust/streams-zenoh-server/wit/world.wit b/examples/rust/streams-zenoh-server/wit/world.wit new file mode 100644 index 000000000..ba3ffa1b6 --- /dev/null +++ b/examples/rust/streams-zenoh-server/wit/world.wit @@ -0,0 +1,5 @@ +package wrpc-examples:streams-rust-server; + +world server { + include wrpc-examples:streams/server; +} diff --git a/tests/rust.rs b/tests/rust.rs index 7a628c25c..3b25c5678 100644 --- a/tests/rust.rs +++ b/tests/rust.rs @@ -21,6 +21,9 @@ use tracing::{info, info_span, instrument, Instrument, Span}; use wrpc_transport::frame::{AcceptExt as _, Oneshot}; use wrpc_transport::{Accept, InvokeExt as _, ResourceBorrow, ResourceOwn, ServeExt as _}; +use zenoh::{Config}; +use serial_test::serial; + #[instrument(skip_all, ret)] async fn assert_bindgen_async(clt: Arc, srv: Arc) -> anyhow::Result<()> where @@ -1028,6 +1031,45 @@ where Ok(()) } +#[cfg(feature = "zenoh-transport")] +#[test_log::test(tokio::test(flavor = "multi_thread"))] +#[serial(zenoh_tests)] +#[instrument(ret)] +async fn rust_bindgen_zenoh_sync() -> anyhow::Result<()> { + wrpc_test::with_zenoh(|_, zenoh_client| async { + let clt = Arc::new(zenoh_client); + assert_bindgen_sync(Arc::clone(&clt), clt).await + }) + .await +} + +#[cfg(feature = "zenoh-transport")] +#[test_log::test(tokio::test(flavor = "multi_thread"))] +#[serial(zenoh_tests)] +#[instrument(ret)] +async fn rust_bindgen_zenoh_async() -> anyhow::Result<()> { + wrpc_test::with_zenoh(|_, zenoh_client| { + async { + let clt = Arc::new(zenoh_client); + assert_bindgen_async(Arc::clone(&clt), clt).await + } + .in_current_span() + }) + .await +} + +#[cfg(feature = "zenoh-transport")] +#[test_log::test(tokio::test(flavor = "multi_thread"))] +#[serial(zenoh_tests)] +#[instrument(ret)] +async fn rust_dynamic_zenoh() -> anyhow::Result<()> { + wrpc_test::with_zenoh(|_, zenoh_client| async { + let clt = Arc::new(zenoh_client); + assert_dynamic(Arc::clone(&clt), clt).await + }) + .await +} + #[cfg(feature = "nats")] #[test_log::test(tokio::test(flavor = "multi_thread"))] #[instrument(ret)] diff --git a/zenoh_conf.json5 b/zenoh_conf.json5 new file mode 100644 index 000000000..6eaf1386b --- /dev/null +++ b/zenoh_conf.json5 @@ -0,0 +1,7 @@ +{ + "mode": "client", + "connect": { + "endpoints": ["tcp/0.0.0.0:7447"] + } +} + \ No newline at end of file diff --git a/zenoh_conf.json5.template b/zenoh_conf.json5.template new file mode 100644 index 000000000..c6ac22108 --- /dev/null +++ b/zenoh_conf.json5.template @@ -0,0 +1,6 @@ +{ + mode: "client", + listen: { + endpoints: ["tcp/172.21.8.176:7447"], + }, +} \ No newline at end of file