From f60bcd99267b45cc43c5723847043fee8623c469 Mon Sep 17 00:00:00 2001 From: carter Date: Mon, 2 Dec 2024 12:38:13 -0700 Subject: [PATCH 01/16] Working zenoh subscriber --- Cargo.lock | 1955 ++++++++++++++++++++++- Cargo.toml | 2 +- roslibrust_zenoh/Cargo.toml | 17 + roslibrust_zenoh/README.md | 7 + roslibrust_zenoh/examples/subscriber.rs | 35 + roslibrust_zenoh/src/lib.rs | 4 + roslibrust_zenoh/src/zenoh_client.rs | 129 ++ 7 files changed, 2073 insertions(+), 76 deletions(-) create mode 100644 roslibrust_zenoh/Cargo.toml create mode 100644 roslibrust_zenoh/README.md create mode 100644 roslibrust_zenoh/examples/subscriber.rs create mode 100644 roslibrust_zenoh/src/lib.rs create mode 100644 roslibrust_zenoh/src/zenoh_client.rs diff --git a/Cargo.lock b/Cargo.lock index 6d8217b3..4b7d1a73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[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.11" @@ -48,6 +59,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anes" version = "0.1.6" @@ -105,9 +122,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "array-init" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" [[package]] name = "arrayvec" @@ -115,6 +138,56 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.63", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "atty" version = "0.2.14" @@ -165,6 +238,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" @@ -176,6 +255,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -210,6 +292,12 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +[[package]] +name = "cache-padded" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "981520c98f422fcc584dc1a95c334e6953900b9106bc47a9839b81790009eb21" + [[package]] name = "cargo-emit" version = "0.2.1" @@ -228,12 +316,24 @@ version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "ciborium" version = "0.2.2" @@ -261,6 +361,16 @@ 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 = "3.2.25" @@ -304,7 +414,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", ] [[package]] @@ -338,20 +448,45 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[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.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" dependencies = [ "proc-macro2", "quote", @@ -493,6 +628,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "deadqueue" version = "0.2.4" @@ -512,6 +653,31 @@ dependencies = [ "uuid", ] +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.3.11" @@ -537,9 +703,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + [[package]] name = "either" version = "1.13.0" @@ -617,6 +823,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + [[package]] name = "example_package" version = "0.1.0" @@ -651,6 +868,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -737,7 +972,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", ] [[package]] @@ -797,8 +1032,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -807,6 +1044,26 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +[[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.90", +] + [[package]] name = "h2" version = "0.3.26" @@ -818,7 +1075,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap 2.3.0", "slab", "tokio", @@ -847,6 +1104,10 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "heck" @@ -869,6 +1130,30 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "0.2.12" @@ -880,6 +1165,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -887,7 +1183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", "pin-project-lite", ] @@ -920,7 +1216,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "httparse", "httpdate", @@ -994,12 +1290,30 @@ dependencies = [ "str_stack", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "ipnet" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[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.12" @@ -1044,12 +1358,41 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror 1.0.63", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "js-sys" version = "0.3.69" @@ -1060,50 +1403,117 @@ dependencies = [ ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "json5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] [[package]] -name = "libc" -version = "0.2.155" +name = "keccak" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] [[package]] -name = "linux-raw-sys" -version = "0.4.14" +name = "keyed-set" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "0a3ec39d2dc17953a1540d63906a112088f79b2e46833b4ed65bc9de3904ae34" +dependencies = [ + "hashbrown 0.14.5", +] [[package]] -name = "lock_api" -version = "0.4.12" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "autocfg", - "scopeguard", + "spin", ] [[package]] -name = "log" -version = "0.4.22" +name = "libc" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] -name = "matchers" -version = "0.1.0" +name = "libloading" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ - "regex-automata 0.1.10", + "cfg-if", + "windows-targets 0.52.6", ] [[package]] -name = "md5" +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lz4_flex" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "md5" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" @@ -1165,6 +1575,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -1193,6 +1612,24 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[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" @@ -1213,6 +1650,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -1229,6 +1693,26 @@ dependencies = [ "itoa", ] +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1236,6 +1720,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", ] [[package]] @@ -1256,6 +1751,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -1291,7 +1795,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", ] [[package]] @@ -1312,6 +1816,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "os_str_bytes" version = "6.6.1" @@ -1324,6 +1834,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[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.3" @@ -1347,12 +1863,124 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +dependencies = [ + "memchr", + "thiserror 1.0.63", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "pest_meta" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap 2.3.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1365,6 +1993,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.30" @@ -1399,6 +2048,38 @@ 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 = "powerfmt" version = "0.2.0" @@ -1418,13 +2099,13 @@ dependencies = [ "inferno", "libc", "log", - "nix", + "nix 0.26.4", "once_cell", "parking_lot", "smallvec", "symbolic-demangle", "tempfile", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1438,9 +2119,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1463,11 +2144,64 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.3", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom", + "rand", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "slab", + "thiserror 2.0.3", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1531,6 +2265,17 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror 1.0.63", +] + [[package]] name = "regex" version = "1.10.6" @@ -1587,7 +2332,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", + "http 0.2.12", "http-body", "hyper", "hyper-tls", @@ -1599,7 +2344,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -1625,12 +2370,49 @@ dependencies = [ ] [[package]] -name = "roslibrust" -version = "0.11.1" +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ - "abort-on-drop", - "anyhow", - "byteorder", + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ringbuffer-spsc" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1938faa63a2362ee1747afb2d10567d0fb1413b9cbd6198a8541485c4f773" +dependencies = [ + "array-init", + "cache-padded", +] + +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.6.0", + "serde", + "serde_derive", +] + +[[package]] +name = "roslibrust" +version = "0.11.1" +dependencies = [ + "abort-on-drop", + "anyhow", + "byteorder", "dashmap", "deadqueue", "env_logger 0.10.2", @@ -1654,9 +2436,9 @@ dependencies = [ "simple_logger", "smart-default 0.6.0", "test-log", - "thiserror", + "thiserror 1.0.63", "tokio", - "tokio-tungstenite", + "tokio-tungstenite 0.17.2", "uuid", ] @@ -1736,12 +2518,70 @@ dependencies = [ "tokio", ] +[[package]] +name = "roslibrust_zenoh" +version = "0.1.0" +dependencies = [ + "anyhow", + "hex", + "roslibrust", + "roslibrust_codegen", + "roslibrust_codegen_macro", + "roslibrust_serde_rosmsg", + "tokio", + "zenoh", +] + +[[package]] +name = "rsa" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "0.38.34" @@ -1755,6 +2595,34 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.23.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -1764,6 +2632,62 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c7dc240fec5517e6c4eab3310438636cfe6391dfc345ba013109909a90d136" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.18" @@ -1788,12 +2712,47 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "either", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.90", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[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" @@ -1804,6 +2763,7 @@ dependencies = [ "core-foundation", "core-foundation-sys", "libc", + "num-bigint", "security-framework-sys", ] @@ -1817,11 +2777,17 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" -version = "1.0.204" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] @@ -1855,20 +2821,31 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -1900,7 +2877,20 @@ dependencies = [ "quick-xml 0.31.0", "serde", "serde-transcode", - "thiserror", + "thiserror 1.0.63", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.3.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", ] [[package]] @@ -1914,6 +2904,38 @@ dependencies = [ "digest", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[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" @@ -1923,6 +2945,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shellexpand" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" +dependencies = [ + "dirs", +] + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1932,6 +2963,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "simple-error" version = "0.3.1" @@ -1950,6 +2991,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -1984,7 +3031,7 @@ checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", ] [[package]] @@ -1997,12 +3044,37 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "str_stack" version = "0.1.0" @@ -2015,6 +3087,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "symbolic-common" version = "10.2.1" @@ -2051,9 +3129,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -2066,6 +3144,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -2128,7 +3217,7 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", ] [[package]] @@ -2143,7 +3232,16 @@ version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.63", +] + +[[package]] +name = "thiserror" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +dependencies = [ + "thiserror-impl 2.0.3", ] [[package]] @@ -2154,7 +3252,18 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -2225,11 +3334,33 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tls-listener" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1d8809f604e448c7bc53a5a0e4c2a0a20ba44cb1fb407314c8eeccb92127f9" +dependencies = [ + "futures-util", + "pin-project-lite", + "thiserror 1.0.63", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "token-cell" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a2b964fdb303b08a4eab04d7c1bad2bca33f8eee334ccd28802f1041c6eb87" +dependencies = [ + "paste", +] + [[package]] name = "tokio" -version = "1.39.2" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -2251,7 +3382,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", ] [[package]] @@ -2264,6 +3395,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-tungstenite" version = "0.17.2" @@ -2273,18 +3415,32 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite", + "tungstenite 0.17.3", ] [[package]] -name = "tokio-util" -version = "0.7.11" +name = "tokio-tungstenite" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.24.0", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", "futures-sink", + "futures-util", + "hashbrown 0.14.5", "pin-project-lite", "tokio", ] @@ -2301,10 +3457,23 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -2326,6 +3495,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -2336,11 +3515,15 @@ dependencies = [ "nu-ansi-term", "once_cell", "regex", + "serde", + "serde_json", "sharded-slab", + "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", + "tracing-serde", ] [[package]] @@ -2358,22 +3541,70 @@ dependencies = [ "base64 0.13.1", "byteorder", "bytes", - "http", + "http 0.2.12", "httparse", "log", "rand", "sha-1", - "thiserror", + "thiserror 1.0.63", "url", "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "sha1", + "thiserror 1.0.63", + "utf-8", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79ac3c37bd9506595768f0387bd39d644525728b4a1d783218acabfb56356db7" +dependencies = [ + "humantime", + "lazy_static", + "log", + "rand", + "serde", + "spin", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -2401,6 +3632,29 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e7e85a0596447f0f2ac090e16bc4c516c6fe91771fb0c0ccf7fa3dae896b9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "url" version = "2.5.2" @@ -2433,6 +3687,30 @@ dependencies = [ "getrandom", ] +[[package]] +name = "validated_struct" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feef04c049b4beae3037a2a31b8da40d8cebec0b97456f24c7de0ede4ed9efed" +dependencies = [ + "json5", + "serde", + "serde_json", + "validated_struct_macros", +] + +[[package]] +name = "validated_struct_macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4444a980afa9ef0d29c2a3f4d952ec0495a7a996a9c78b52698b71bc21edb4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unzip-n", +] + [[package]] name = "valuable" version = "0.1.0" @@ -2445,6 +3723,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[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" @@ -2497,7 +3781,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", "wasm-bindgen-shared", ] @@ -2531,7 +3815,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2552,6 +3836,34 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd5da49bdf1f30054cfe0b8ce2958b8fbeb67c4d82c8967a598af481bef255c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2741,12 +4053,499 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 1.0.63", + "time", +] + [[package]] name = "xml-rs" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601" +[[package]] +name = "zenoh" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71a28149fe9eaa0500febec22cace12c27a4fd13ac962199bd1f45fc4fa4531" +dependencies = [ + "ahash", + "async-trait", + "bytes", + "flume", + "futures", + "git-version", + "itertools 0.13.0", + "json5", + "lazy_static", + "once_cell", + "paste", + "petgraph", + "phf", + "rand", + "rustc_version", + "serde", + "serde_json", + "socket2", + "tokio", + "tokio-util", + "tracing", + "uhlc", + "vec_map", + "zenoh-buffers", + "zenoh-codec", + "zenoh-collections", + "zenoh-config", + "zenoh-core", + "zenoh-keyexpr", + "zenoh-link", + "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.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5461699c2691656bc8f5f1f7f81baf0b7d333a7196192642cbd8ef7cde4c7d59" +dependencies = [ + "zenoh-collections", +] + +[[package]] +name = "zenoh-codec" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6a648ba93f60d5d4d7ca75ea230a4ab3699ae86060c72b4bcbd72bcd255693a" +dependencies = [ + "tracing", + "uhlc", + "zenoh-buffers", + "zenoh-protocol", +] + +[[package]] +name = "zenoh-collections" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba9c78667083e23e6413554b914db5a0b3950ef3a2b15af9e0e1dc7b5113231d" + +[[package]] +name = "zenoh-config" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58e6d4f2a8ec45c856ba0347526011fdac631bfd4bfad68fe1c5ad128644b8b6" +dependencies = [ + "json5", + "num_cpus", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "tracing", + "uhlc", + "validated_struct", + "zenoh-core", + "zenoh-macros", + "zenoh-protocol", + "zenoh-result", + "zenoh-util", +] + +[[package]] +name = "zenoh-core" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d500800376ac3fb7daf8ab44b9a28e8abcdf5b997ff5f0bde0b8580c3479c" +dependencies = [ + "lazy_static", + "tokio", + "zenoh-result", + "zenoh-runtime", +] + +[[package]] +name = "zenoh-crypto" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2b573b3f0433d3210cee18852b8a3b7f3a82718e5dcec85169b68519341161" +dependencies = [ + "aes", + "hmac", + "rand", + "rand_chacha", + "sha3", + "zenoh-result", +] + +[[package]] +name = "zenoh-keyexpr" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f351eccd2ba89cf1339bddba6b2ae7b80ed10038e06de949811cff6806395a1" +dependencies = [ + "hashbrown 0.14.5", + "keyed-set", + "rand", + "schemars", + "serde", + "token-cell", + "zenoh-result", +] + +[[package]] +name = "zenoh-link" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18d2bcb9ffd298cb2694e370f82e85f8d626c10ff8a1e545ef6b85e694981e8" +dependencies = [ + "zenoh-config", + "zenoh-link-commons", + "zenoh-link-quic", + "zenoh-link-tcp", + "zenoh-link-tls", + "zenoh-link-udp", + "zenoh-link-unixsock_stream", + "zenoh-link-ws", + "zenoh-protocol", + "zenoh-result", +] + +[[package]] +name = "zenoh-link-commons" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c9892602983a19df376062a0a6a629c37456e3df9a02ffa51ae33de1b6a736" +dependencies = [ + "async-trait", + "flume", + "futures", + "rustls", + "rustls-webpki", + "serde", + "time", + "tokio", + "tokio-util", + "tracing", + "zenoh-buffers", + "zenoh-codec", + "zenoh-core", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-util", +] + +[[package]] +name = "zenoh-link-quic" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c44b993753915cabf6cbe62cfc03ca762432429e99e3cb3c855fa28c5712d481" +dependencies = [ + "async-trait", + "base64 0.22.1", + "quinn", + "rustls", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "rustls-webpki", + "secrecy", + "time", + "tokio", + "tokio-util", + "tracing", + "webpki-roots", + "x509-parser", + "zenoh-config", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", +] + +[[package]] +name = "zenoh-link-tcp" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7752376ae1a30b3d03036bccd307b357b432d4187aeb84b7923228965f5b3fc6" +dependencies = [ + "async-trait", + "socket2", + "tokio", + "tokio-util", + "tracing", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-util", +] + +[[package]] +name = "zenoh-link-tls" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebff0f7565d6823127f1ab64e1814cc7b2d890c0c53a6821c55d5489b6808c4e" +dependencies = [ + "async-trait", + "base64 0.22.1", + "rustls", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "rustls-webpki", + "secrecy", + "socket2", + "time", + "tls-listener", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "webpki-roots", + "x509-parser", + "zenoh-config", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", +] + +[[package]] +name = "zenoh-link-udp" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df5d88c7276b92c1227e55fa1a5a7ee7787b3655911e3f37b3abbcfcd28e197" +dependencies = [ + "async-trait", + "socket2", + "tokio", + "tokio-util", + "tracing", + "zenoh-buffers", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-sync", + "zenoh-util", +] + +[[package]] +name = "zenoh-link-unixsock_stream" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9eacd5af312c0e86d7aba32b08b841902fe0c6c11d0082905629f614f8d043d" +dependencies = [ + "async-trait", + "nix 0.29.0", + "tokio", + "tokio-util", + "tracing", + "uuid", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", +] + +[[package]] +name = "zenoh-link-ws" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37153f5e67115d1cb787ad9a910253ff95e57a4c64940b51c2b2ce6e2d723a7" +dependencies = [ + "async-trait", + "futures-util", + "tokio", + "tokio-tungstenite 0.24.0", + "tokio-util", + "tracing", + "url", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-util", +] + +[[package]] +name = "zenoh-macros" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12fdfa5b74ef5d5e5f9917d28d466dd1a4aa2579a46d29c59d67bc02c598a157" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "zenoh-keyexpr", +] + +[[package]] +name = "zenoh-plugin-trait" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a5e6d6bcb414162e1c720dc7a381b73b7f88a67add9c034f4ee720446e7d71" +dependencies = [ + "git-version", + "libloading", + "serde", + "tracing", + "zenoh-config", + "zenoh-keyexpr", + "zenoh-macros", + "zenoh-result", + "zenoh-util", +] + +[[package]] +name = "zenoh-protocol" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852ab258382046994e01787f537169b153f349b15489ea2fe439afc16a169a52" +dependencies = [ + "const_format", + "rand", + "serde", + "uhlc", + "zenoh-buffers", + "zenoh-keyexpr", + "zenoh-result", +] + +[[package]] +name = "zenoh-result" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "025e1488cf486da60de80197565654eb479f7253251f32814b11ce7ddd8ba138" +dependencies = [ + "anyhow", +] + +[[package]] +name = "zenoh-runtime" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de628abfd88c1f9acc58e5cb396aa55885035225a46d6cdc29ab8453243a37d8" +dependencies = [ + "lazy_static", + "ron", + "serde", + "tokio", + "zenoh-macros", + "zenoh-result", +] + +[[package]] +name = "zenoh-sync" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd06d513ed659d1290260ddb73eaf503dbe4ce7d12fe48a7dac1eaa7801756f" +dependencies = [ + "event-listener", + "futures", + "tokio", + "zenoh-buffers", + "zenoh-collections", + "zenoh-core", +] + +[[package]] +name = "zenoh-task" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83661218a1e7376de6c7d0ecf308b74f10eb4713771e94b4646c54b9b139ed2" +dependencies = [ + "futures", + "tokio", + "tokio-util", + "tracing", + "zenoh-core", + "zenoh-runtime", +] + +[[package]] +name = "zenoh-transport" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d4be84994418dad55efebfd31eb4942278bccbe9bfdda3241d418154de5bca6" +dependencies = [ + "async-trait", + "crossbeam-utils", + "flume", + "lazy_static", + "lz4_flex", + "paste", + "rand", + "ringbuffer-spsc", + "rsa", + "serde", + "sha3", + "tokio", + "tokio-util", + "tracing", + "zenoh-buffers", + "zenoh-codec", + "zenoh-config", + "zenoh-core", + "zenoh-crypto", + "zenoh-link", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-sync", + "zenoh-task", + "zenoh-util", +] + +[[package]] +name = "zenoh-util" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237b18361bc2db1c35d188d84eec65166477b156ac91908709ec70285fcfd201" +dependencies = [ + "async-trait", + "const_format", + "flume", + "home", + "humantime", + "lazy_static", + "libc", + "libloading", + "pnet_datalink", + "serde", + "serde_json", + "shellexpand", + "tokio", + "tracing", + "tracing-subscriber", + "winapi", + "zenoh-core", + "zenoh-result", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -2765,5 +4564,11 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.90", ] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index ebfd533d..95abe3e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,6 @@ members = [ "roslibrust_codegen", "roslibrust_codegen_macro", "roslibrust_genmsg", - "roslibrust_test", + "roslibrust_test", "roslibrust_zenoh", ] resolver = "2" diff --git a/roslibrust_zenoh/Cargo.toml b/roslibrust_zenoh/Cargo.toml new file mode 100644 index 00000000..9c7e526f --- /dev/null +++ b/roslibrust_zenoh/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "roslibrust_zenoh" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tokio = { version = "1.41", features = ["rt-multi-thread", "sync", "macros"] } +roslibrust_codegen_macro = { path = "../roslibrust_codegen_macro" } +roslibrust_codegen = { path = "../roslibrust_codegen" } +roslibrust = { path = "../roslibrust", features = ["topic_provider"] } +zenoh = "1.0" +hex = "0.4" +anyhow = "1.0" +roslibrust_serde_rosmsg = "0.3" + diff --git a/roslibrust_zenoh/README.md b/roslibrust_zenoh/README.md new file mode 100644 index 00000000..7bbe76f5 --- /dev/null +++ b/roslibrust_zenoh/README.md @@ -0,0 +1,7 @@ +# RosLibRust Zenoh + +This crate provides a Zenoh client that is compatible with the zenoh-ros1-plugin / zenoh-ros1-bridge. + +The plugin / bridge performs "topic mangling" that makes it challenging to directly subscribe to the bridged topics from zenoh. + +The goal of this crate is to provide an effective intermediary between ros1 and zenoh, and eventually unify this behind the single TopicProvider trait. \ No newline at end of file diff --git a/roslibrust_zenoh/examples/subscriber.rs b/roslibrust_zenoh/examples/subscriber.rs new file mode 100644 index 00000000..dae0ab25 --- /dev/null +++ b/roslibrust_zenoh/examples/subscriber.rs @@ -0,0 +1,35 @@ +use roslibrust_zenoh::ZenohClient; + +// IMPORTANT to bring this trait into scope so we can access the functions it provides +// This trait provides the [subscribe] and [advertise] functions on ZenohCilent +use roslibrust::topic_provider::TopicProvider; +// IMPORTANT to bring this trait into scope so we can access the functions it provides +// This trait provides the [next] function on ZenohSubscriber +use roslibrust::topic_provider::Subscribe; + +// Generate rust definitions for our messages +roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces/std_msgs"); + +// The example expects a zenoh-ros1-bridge to be running see [here](https://github.com/eclipse-zenoh/zenoh-plugin-ros1) +// for details on running the bridge. + +// While the bridge is running (with a rosmaster either internally or externally), the following command can be used +// to test the functionality: `rostopic pub /chatter std_msgs/String "data: 'hello world'"` +#[tokio::main] +async fn main() { + + let session = zenoh::open(zenoh::Config::default()).await.unwrap(); + let client = ZenohClient::new(session); + + // Create a zenoh subscriber to the ros topic /chatter + // Internally this handles the "topic mangling" that zenoh-ros1-plugin / zenoh-ros1-bridge performs + // and sets up deserialization of the ROS1 type into our Rust type + let mut subscriber = client.subscribe::("/chatter").await.unwrap(); + + loop { + // Get the next message + let msg = subscriber.next().await.unwrap(); + // Publish + println!("Got message: {}", msg.data); + } +} diff --git a/roslibrust_zenoh/src/lib.rs b/roslibrust_zenoh/src/lib.rs new file mode 100644 index 00000000..e3203b23 --- /dev/null +++ b/roslibrust_zenoh/src/lib.rs @@ -0,0 +1,4 @@ +//! A crate for interfacing to ROS1 via the [zenoh-ros1-plugin / zenoh-ros1-bridge](https://github.com/eclipse-zenoh/zenoh-plugin-ros1). + +mod zenoh_client; +pub use zenoh_client::*; \ No newline at end of file diff --git a/roslibrust_zenoh/src/zenoh_client.rs b/roslibrust_zenoh/src/zenoh_client.rs new file mode 100644 index 00000000..8174f3b5 --- /dev/null +++ b/roslibrust_zenoh/src/zenoh_client.rs @@ -0,0 +1,129 @@ +use anyhow::bail; +use roslibrust::topic_provider::{Publish, Subscribe, TopicProvider}; +use roslibrust::{RosLibRustError, RosLibRustResult}; +use roslibrust_codegen::RosMessageType; +use zenoh::handlers::FifoChannelHandler; +use zenoh::key_expr::OwnedKeyExpr; + +pub struct ZenohClient { + session: zenoh::Session, +} + +impl ZenohClient { + /// Creates a new client wrapped around a Zenoh session + pub fn new(session: zenoh::Session) -> Self { + Self { session } + } +} + +pub struct ZenohPublisher { + topic: String, + _marker: std::marker::PhantomData, +} + +impl Publish for ZenohPublisher { + async fn publish(&self, data: &T) -> RosLibRustResult<()> { + todo!() + } +} + +// Using type alias here, I have no idea why zenoh has this type so deep +type ZenohSubInner = + zenoh::pubsub::Subscriber>; +pub struct ZenohSubscriber { + sub: ZenohSubInner, + _marker: std::marker::PhantomData, +} + +impl Subscribe for ZenohSubscriber { + async fn next(&mut self) -> RosLibRustResult { + let next = self.sub.recv_async().await; + + let sample = match next { + Ok(sample) => sample, + Err(e) => { + // TODO errors still suck with this API + return Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to receive next sample: {e:?}" + ))); + } + }; + + let bytes = sample.payload().to_bytes(); + + // This is messy roslibrust expects the starting bytes to be total message size + // which Zenoh or the bridge is stripping somewhere, so I'm just manually sticking them back for now + // This is very inefficient, but it works for now. + let starting_bytes = (bytes.len() as u32).to_le_bytes(); + let bytes = [&starting_bytes, &bytes[..]].concat(); + + let msg = roslibrust_serde_rosmsg::from_slice(&bytes).map_err(|e| { + RosLibRustError::SerializationError(format!("Failed to deserialize sample: {e:?}")) + })?; + Ok(msg) + } +} + +impl TopicProvider for ZenohClient { + type Publisher = ZenohPublisher; + + type Subscriber = ZenohSubscriber; + + async fn advertise( + &self, + topic: &str, + ) -> RosLibRustResult> { + todo!() + } + + async fn subscribe( + &self, + topic: &str, + ) -> RosLibRustResult> { + let mangled_topic = mangle_topic(topic, T::ROS_TYPE_NAME, T::MD5SUM); + let sub = match self.session.declare_subscriber(mangled_topic).await { + Ok(sub) => sub, + Err(e) => { + // TODO errors still suck with this API... + return Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to declare subscriber: {e:?}" + ))); + } + }; + Ok(ZenohSubscriber { + sub, + _marker: std::marker::PhantomData, + }) + } +} + +/// Takes in a regular ros topic and type and returns a zenoh topic mangled in the way the zenoh-ros1-plugin does +fn mangle_topic(topic: &str, type_str: &str, md5sum: &str) -> String { + // Name mangling stuff! + // See: https://github.com/eclipse-zenoh/zenoh-plugin-ros1/issues/131 + // Explicit implementation at: https://github.com/eclipse-zenoh/zenoh-plugin-ros1/blob/main/zenoh-plugin-ros1/src/ros_to_zenoh_bridge/topic_utilities.rs + // Note: the implementation inside of the bridge uses unstable zenoh, duplicating implementation here with stable zenoh instead. + + // Remove leading and trailing slashes in the topic + let topic = topic.trim_start_matches('/').trim_end_matches("/"); + // Encode the type as hex + let type_str = hex::encode(type_str.as_bytes()); + format!("{type_str}/{md5sum}/{topic}") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mangle_topic() { + assert_eq!( + mangle_topic( + "/chatter", + "std_msgs/String", + "992ce8a1687cec8c8bd883ec73ca41d1" + ), + "7374645f6d7367732f537472696e67/992ce8a1687cec8c8bd883ec73ca41d1/chatter" + ); + } +} From ea62db04e8ca0c496c784b767b71c374c0dad660 Mon Sep 17 00:00:00 2001 From: carter Date: Mon, 2 Dec 2024 12:38:39 -0700 Subject: [PATCH 02/16] lint --- roslibrust_zenoh/examples/subscriber.rs | 6 ++++-- roslibrust_zenoh/src/lib.rs | 2 +- roslibrust_zenoh/src/zenoh_client.rs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/roslibrust_zenoh/examples/subscriber.rs b/roslibrust_zenoh/examples/subscriber.rs index dae0ab25..a96a253c 100644 --- a/roslibrust_zenoh/examples/subscriber.rs +++ b/roslibrust_zenoh/examples/subscriber.rs @@ -17,14 +17,16 @@ roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_in // to test the functionality: `rostopic pub /chatter std_msgs/String "data: 'hello world'"` #[tokio::main] async fn main() { - let session = zenoh::open(zenoh::Config::default()).await.unwrap(); let client = ZenohClient::new(session); // Create a zenoh subscriber to the ros topic /chatter // Internally this handles the "topic mangling" that zenoh-ros1-plugin / zenoh-ros1-bridge performs // and sets up deserialization of the ROS1 type into our Rust type - let mut subscriber = client.subscribe::("/chatter").await.unwrap(); + let mut subscriber = client + .subscribe::("/chatter") + .await + .unwrap(); loop { // Get the next message diff --git a/roslibrust_zenoh/src/lib.rs b/roslibrust_zenoh/src/lib.rs index e3203b23..7ca38c39 100644 --- a/roslibrust_zenoh/src/lib.rs +++ b/roslibrust_zenoh/src/lib.rs @@ -1,4 +1,4 @@ //! A crate for interfacing to ROS1 via the [zenoh-ros1-plugin / zenoh-ros1-bridge](https://github.com/eclipse-zenoh/zenoh-plugin-ros1). mod zenoh_client; -pub use zenoh_client::*; \ No newline at end of file +pub use zenoh_client::*; diff --git a/roslibrust_zenoh/src/zenoh_client.rs b/roslibrust_zenoh/src/zenoh_client.rs index 8174f3b5..3586ea94 100644 --- a/roslibrust_zenoh/src/zenoh_client.rs +++ b/roslibrust_zenoh/src/zenoh_client.rs @@ -50,7 +50,7 @@ impl Subscribe for ZenohSubscriber { }; let bytes = sample.payload().to_bytes(); - + // This is messy roslibrust expects the starting bytes to be total message size // which Zenoh or the bridge is stripping somewhere, so I'm just manually sticking them back for now // This is very inefficient, but it works for now. From 44785a01a7e264b1868348a72f38144a8e43803b Mon Sep 17 00:00:00 2001 From: carter Date: Mon, 2 Dec 2024 12:57:59 -0700 Subject: [PATCH 03/16] Working publisher too! --- roslibrust_zenoh/examples/publisher.rs | 43 +++++++++++++++++++++++++ roslibrust_zenoh/examples/subscriber.rs | 3 +- roslibrust_zenoh/src/zenoh_client.rs | 38 ++++++++++++++++++---- 3 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 roslibrust_zenoh/examples/publisher.rs diff --git a/roslibrust_zenoh/examples/publisher.rs b/roslibrust_zenoh/examples/publisher.rs new file mode 100644 index 00000000..05a4a148 --- /dev/null +++ b/roslibrust_zenoh/examples/publisher.rs @@ -0,0 +1,43 @@ +use roslibrust_zenoh::ZenohClient; + +// IMPORTANT to bring this trait into scope so we can access the functions it provides +// This trait provides the [subscribe] and [advertise] functions on ZenohCilent +use roslibrust::topic_provider::TopicProvider; +// IMPORTANT to bring this trait into scope so we can access the functions it provides +// This trait provides the [next] function on ZenohSubscriber +use roslibrust::topic_provider::Publish; + +// Generate rust definitions for our messages +roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces/std_msgs"); + +// The example expects a zenoh-ros1-bridge to be running see [here](https://github.com/eclipse-zenoh/zenoh-plugin-ros1) +// for details on running the bridge. + +// While the bridge is running (with a rosmaster either internally or externally), the following command can be used +// to test the functionality: `rostopic echo /chatter` +// Or run the subscriber example `cargo run --example subscriber` +#[tokio::main] +async fn main() { + let session = zenoh::open(zenoh::Config::default()).await.unwrap(); + let client = ZenohClient::new(session); + + // Create a zenoh subscriber to the ros topic /chatter + // Internally this handles the "topic mangling" that zenoh-ros1-plugin / zenoh-ros1-bridge performs + // and sets up deserialization of the ROS1 type into our Rust type + let publisher = client + .advertise::("/chatter") + .await + .unwrap(); + + // Run at 1Hz + let mut interval = tokio::time::interval(std::time::Duration::from_secs(1)); + + loop { + let msg = std_msgs::String { + data: "Hello world".to_string(), + }; + publisher.publish(&msg).await.unwrap(); + println!("Published!"); + interval.tick().await; + } +} diff --git a/roslibrust_zenoh/examples/subscriber.rs b/roslibrust_zenoh/examples/subscriber.rs index a96a253c..8fcd02a8 100644 --- a/roslibrust_zenoh/examples/subscriber.rs +++ b/roslibrust_zenoh/examples/subscriber.rs @@ -14,7 +14,8 @@ roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_in // for details on running the bridge. // While the bridge is running (with a rosmaster either internally or externally), the following command can be used -// to test the functionality: `rostopic pub /chatter std_msgs/String "data: 'hello world'"` +// to test the functionality: `rostopic pub -r 1 /chatter std_msgs/String "data: 'hello world'"` +// Or run the publisher example `cargo run --example publisher` #[tokio::main] async fn main() { let session = zenoh::open(zenoh::Config::default()).await.unwrap(); diff --git a/roslibrust_zenoh/src/zenoh_client.rs b/roslibrust_zenoh/src/zenoh_client.rs index 3586ea94..ee286a97 100644 --- a/roslibrust_zenoh/src/zenoh_client.rs +++ b/roslibrust_zenoh/src/zenoh_client.rs @@ -17,13 +17,24 @@ impl ZenohClient { } pub struct ZenohPublisher { - topic: String, + publisher: zenoh::pubsub::Publisher<'static>, _marker: std::marker::PhantomData, } impl Publish for ZenohPublisher { async fn publish(&self, data: &T) -> RosLibRustResult<()> { - todo!() + let bytes = roslibrust_serde_rosmsg::to_vec(data).map_err(|e| { + RosLibRustError::SerializationError(format!("Failed to serialize message: {e:?}")) + })?; + + // Note: serde_rosmsg places the length of the message as the first four bytes + // Which zenoh ros1 bridge does not expect, so we need to strip it off. + match self.publisher.put(&bytes[4..]).await { + Ok(()) => Ok(()), + Err(e) => Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to publish message to zenoh: {e:?}" + ))), + } } } @@ -31,13 +42,13 @@ impl Publish for ZenohPublisher { type ZenohSubInner = zenoh::pubsub::Subscriber>; pub struct ZenohSubscriber { - sub: ZenohSubInner, + subscriber: ZenohSubInner, _marker: std::marker::PhantomData, } impl Subscribe for ZenohSubscriber { async fn next(&mut self) -> RosLibRustResult { - let next = self.sub.recv_async().await; + let next = self.subscriber.recv_async().await; let sample = match next { Ok(sample) => sample, @@ -73,7 +84,22 @@ impl TopicProvider for ZenohClient { &self, topic: &str, ) -> RosLibRustResult> { - todo!() + let mangled_topic = mangle_topic(topic, T::ROS_TYPE_NAME, T::MD5SUM); + let publisher = match self.session.declare_publisher(mangled_topic).await { + Ok(publisher) => publisher, + Err(e) => { + // TODO errors still suck with this API... + return Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to declare publisher: {e:?}" + ))); + } + }; + + println!("type of pub: {:?}", std::any::type_name_of_val(&publisher)); + Ok(ZenohPublisher { + publisher, + _marker: std::marker::PhantomData, + }) } async fn subscribe( @@ -91,7 +117,7 @@ impl TopicProvider for ZenohClient { } }; Ok(ZenohSubscriber { - sub, + subscriber: sub, _marker: std::marker::PhantomData, }) } From e2e3998531d4132ae7654c15cbf2fcbf4876c279 Mon Sep 17 00:00:00 2001 From: carter Date: Mon, 2 Dec 2024 13:21:03 -0700 Subject: [PATCH 04/16] Removed debug print, fix Ci, fix warnings --- roslibrust_zenoh/examples/publisher.rs | 4 +++- roslibrust_zenoh/examples/subscriber.rs | 4 +++- roslibrust_zenoh/src/zenoh_client.rs | 4 ---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/roslibrust_zenoh/examples/publisher.rs b/roslibrust_zenoh/examples/publisher.rs index 05a4a148..e252316e 100644 --- a/roslibrust_zenoh/examples/publisher.rs +++ b/roslibrust_zenoh/examples/publisher.rs @@ -8,7 +8,9 @@ use roslibrust::topic_provider::TopicProvider; use roslibrust::topic_provider::Publish; // Generate rust definitions for our messages -roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces/std_msgs"); +roslibrust_codegen_macro::find_and_generate_ros_messages!( + "../assets/ros1_common_interfaces/std_msgs" +); // The example expects a zenoh-ros1-bridge to be running see [here](https://github.com/eclipse-zenoh/zenoh-plugin-ros1) // for details on running the bridge. diff --git a/roslibrust_zenoh/examples/subscriber.rs b/roslibrust_zenoh/examples/subscriber.rs index 8fcd02a8..f6d4fd19 100644 --- a/roslibrust_zenoh/examples/subscriber.rs +++ b/roslibrust_zenoh/examples/subscriber.rs @@ -8,7 +8,9 @@ use roslibrust::topic_provider::TopicProvider; use roslibrust::topic_provider::Subscribe; // Generate rust definitions for our messages -roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces/std_msgs"); +roslibrust_codegen_macro::find_and_generate_ros_messages!( + "../assets/ros1_common_interfaces/std_msgs" +); // The example expects a zenoh-ros1-bridge to be running see [here](https://github.com/eclipse-zenoh/zenoh-plugin-ros1) // for details on running the bridge. diff --git a/roslibrust_zenoh/src/zenoh_client.rs b/roslibrust_zenoh/src/zenoh_client.rs index ee286a97..b7c6c454 100644 --- a/roslibrust_zenoh/src/zenoh_client.rs +++ b/roslibrust_zenoh/src/zenoh_client.rs @@ -1,9 +1,6 @@ -use anyhow::bail; use roslibrust::topic_provider::{Publish, Subscribe, TopicProvider}; use roslibrust::{RosLibRustError, RosLibRustResult}; use roslibrust_codegen::RosMessageType; -use zenoh::handlers::FifoChannelHandler; -use zenoh::key_expr::OwnedKeyExpr; pub struct ZenohClient { session: zenoh::Session, @@ -95,7 +92,6 @@ impl TopicProvider for ZenohClient { } }; - println!("type of pub: {:?}", std::any::type_name_of_val(&publisher)); Ok(ZenohPublisher { publisher, _marker: std::marker::PhantomData, From 08c7584141d502f41ac041c7a95b2e55dbe3c970 Mon Sep 17 00:00:00 2001 From: carter Date: Mon, 2 Dec 2024 13:27:10 -0700 Subject: [PATCH 05/16] CI fix attempt, update changelog --- CHANGELOG.md | 2 ++ roslibrust_zenoh/examples/publisher.rs | 4 +--- roslibrust_zenoh/examples/subscriber.rs | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 547687ac..90c41faa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- roslibrust_zenoh now proivides a Zenoh client that is compatible with the zenoh-ros1-plugin / zenoh-ros1-bridge + ### Fixed - Keeping a ros1::ServiceServer alive no longer keeps the underlying node alive past the last ros1::NodeHandle being dropped. diff --git a/roslibrust_zenoh/examples/publisher.rs b/roslibrust_zenoh/examples/publisher.rs index e252316e..05a4a148 100644 --- a/roslibrust_zenoh/examples/publisher.rs +++ b/roslibrust_zenoh/examples/publisher.rs @@ -8,9 +8,7 @@ use roslibrust::topic_provider::TopicProvider; use roslibrust::topic_provider::Publish; // Generate rust definitions for our messages -roslibrust_codegen_macro::find_and_generate_ros_messages!( - "../assets/ros1_common_interfaces/std_msgs" -); +roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces/std_msgs"); // The example expects a zenoh-ros1-bridge to be running see [here](https://github.com/eclipse-zenoh/zenoh-plugin-ros1) // for details on running the bridge. diff --git a/roslibrust_zenoh/examples/subscriber.rs b/roslibrust_zenoh/examples/subscriber.rs index f6d4fd19..8fcd02a8 100644 --- a/roslibrust_zenoh/examples/subscriber.rs +++ b/roslibrust_zenoh/examples/subscriber.rs @@ -8,9 +8,7 @@ use roslibrust::topic_provider::TopicProvider; use roslibrust::topic_provider::Subscribe; // Generate rust definitions for our messages -roslibrust_codegen_macro::find_and_generate_ros_messages!( - "../assets/ros1_common_interfaces/std_msgs" -); +roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces/std_msgs"); // The example expects a zenoh-ros1-bridge to be running see [here](https://github.com/eclipse-zenoh/zenoh-plugin-ros1) // for details on running the bridge. From f4e6a96d449041c20c3f26d726a0199e87144e38 Mon Sep 17 00:00:00 2001 From: carter Date: Mon, 2 Dec 2024 13:29:23 -0700 Subject: [PATCH 06/16] This will FIX CI --- roslibrust_zenoh/examples/publisher.rs | 2 +- roslibrust_zenoh/examples/subscriber.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/roslibrust_zenoh/examples/publisher.rs b/roslibrust_zenoh/examples/publisher.rs index 05a4a148..66ff56e9 100644 --- a/roslibrust_zenoh/examples/publisher.rs +++ b/roslibrust_zenoh/examples/publisher.rs @@ -8,7 +8,7 @@ use roslibrust::topic_provider::TopicProvider; use roslibrust::topic_provider::Publish; // Generate rust definitions for our messages -roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces/std_msgs"); +roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); // The example expects a zenoh-ros1-bridge to be running see [here](https://github.com/eclipse-zenoh/zenoh-plugin-ros1) // for details on running the bridge. diff --git a/roslibrust_zenoh/examples/subscriber.rs b/roslibrust_zenoh/examples/subscriber.rs index 8fcd02a8..b2d8b900 100644 --- a/roslibrust_zenoh/examples/subscriber.rs +++ b/roslibrust_zenoh/examples/subscriber.rs @@ -8,7 +8,7 @@ use roslibrust::topic_provider::TopicProvider; use roslibrust::topic_provider::Subscribe; // Generate rust definitions for our messages -roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces/std_msgs"); +roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); // The example expects a zenoh-ros1-bridge to be running see [here](https://github.com/eclipse-zenoh/zenoh-plugin-ros1) // for details on running the bridge. From 9150633fe54b92202bf7af7acb7460982150086f Mon Sep 17 00:00:00 2001 From: carter Date: Mon, 2 Dec 2024 13:37:55 -0700 Subject: [PATCH 07/16] Reorg zenoh lib, fix ci, start on service --- roslibrust/examples/generic_client.rs | 4 +- .../examples/generic_client_services.rs | 4 +- roslibrust/examples/generic_message.rs | 6 +- roslibrust_zenoh/README.md | 2 +- roslibrust_zenoh/src/lib.rs | 176 +++++++++++++++++- roslibrust_zenoh/src/zenoh_client.rs | 151 --------------- 6 files changed, 179 insertions(+), 164 deletions(-) delete mode 100644 roslibrust_zenoh/src/zenoh_client.rs diff --git a/roslibrust/examples/generic_client.rs b/roslibrust/examples/generic_client.rs index 137254c0..74a4f37e 100644 --- a/roslibrust/examples/generic_client.rs +++ b/roslibrust/examples/generic_client.rs @@ -12,9 +12,7 @@ async fn main() { use roslibrust::topic_provider::*; - roslibrust_codegen_macro::find_and_generate_ros_messages!( - "assets/ros1_common_interfaces/std_msgs" - ); + roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); // TopicProvider cannot be an "Object Safe Trait" due to its generic parameters // This means we can't do: diff --git a/roslibrust/examples/generic_client_services.rs b/roslibrust/examples/generic_client_services.rs index 5460a1e9..6b0fd87a 100644 --- a/roslibrust/examples/generic_client_services.rs +++ b/roslibrust/examples/generic_client_services.rs @@ -12,9 +12,7 @@ async fn main() { use roslibrust::topic_provider::*; - roslibrust_codegen_macro::find_and_generate_ros_messages!( - "assets/ros1_common_interfaces/ros_comm_msgs/std_srvs" - ); + roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); // TopicProvider cannot be an "Object Safe Trait" due to its generic parameters // This means we can't do: diff --git a/roslibrust/examples/generic_message.rs b/roslibrust/examples/generic_message.rs index 1eb1e456..1a1ba67a 100644 --- a/roslibrust/examples/generic_message.rs +++ b/roslibrust/examples/generic_message.rs @@ -7,14 +7,12 @@ use roslibrust_codegen::RosMessageType; /// We place the ros1 generate code into a module to prevent name collisions with the identically /// named ros2 types. mod ros1 { - roslibrust_codegen_macro::find_and_generate_ros_messages!( - "assets/ros1_common_interfaces/std_msgs" - ); + roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); } mod ros2 { roslibrust_codegen_macro::find_and_generate_ros_messages_without_ros_package_path!( - "assets/ros2_common_interfaces/std_msgs" + "assets/ros2_common_interfaces" ); } diff --git a/roslibrust_zenoh/README.md b/roslibrust_zenoh/README.md index 7bbe76f5..616fa806 100644 --- a/roslibrust_zenoh/README.md +++ b/roslibrust_zenoh/README.md @@ -4,4 +4,4 @@ This crate provides a Zenoh client that is compatible with the zenoh-ros1-plugin The plugin / bridge performs "topic mangling" that makes it challenging to directly subscribe to the bridged topics from zenoh. -The goal of this crate is to provide an effective intermediary between ros1 and zenoh, and eventually unify this behind the single TopicProvider trait. \ No newline at end of file +The goal of this crate is to provide an effective intermediary between ros1 and zenoh, and eventually unify this behind the single TopicProvider trait. diff --git a/roslibrust_zenoh/src/lib.rs b/roslibrust_zenoh/src/lib.rs index 7ca38c39..1fd7da35 100644 --- a/roslibrust_zenoh/src/lib.rs +++ b/roslibrust_zenoh/src/lib.rs @@ -1,4 +1,176 @@ //! A crate for interfacing to ROS1 via the [zenoh-ros1-plugin / zenoh-ros1-bridge](https://github.com/eclipse-zenoh/zenoh-plugin-ros1). -mod zenoh_client; -pub use zenoh_client::*; +use roslibrust::topic_provider::{Publish, ServiceProvider, Subscribe, TopicProvider}; +use roslibrust::{RosLibRustError, RosLibRustResult}; +use roslibrust_codegen::{RosMessageType, RosServiceType}; + +pub struct ZenohClient { + session: zenoh::Session, +} + +impl ZenohClient { + /// Creates a new client wrapped around a Zenoh session + pub fn new(session: zenoh::Session) -> Self { + Self { session } + } +} + +pub struct ZenohPublisher { + publisher: zenoh::pubsub::Publisher<'static>, + _marker: std::marker::PhantomData, +} + +impl Publish for ZenohPublisher { + async fn publish(&self, data: &T) -> RosLibRustResult<()> { + let bytes = roslibrust_serde_rosmsg::to_vec(data).map_err(|e| { + RosLibRustError::SerializationError(format!("Failed to serialize message: {e:?}")) + })?; + + // Note: serde_rosmsg places the length of the message as the first four bytes + // Which zenoh ros1 bridge does not expect, so we need to strip it off. + match self.publisher.put(&bytes[4..]).await { + Ok(()) => Ok(()), + Err(e) => Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to publish message to zenoh: {e:?}" + ))), + } + } +} + +// Using type alias here, I have no idea why zenoh has this type so deep +type ZenohSubInner = + zenoh::pubsub::Subscriber>; +pub struct ZenohSubscriber { + subscriber: ZenohSubInner, + _marker: std::marker::PhantomData, +} + +impl Subscribe for ZenohSubscriber { + async fn next(&mut self) -> RosLibRustResult { + let next = self.subscriber.recv_async().await; + + let sample = match next { + Ok(sample) => sample, + Err(e) => { + // TODO errors still suck with this API + return Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to receive next sample: {e:?}" + ))); + } + }; + + let bytes = sample.payload().to_bytes(); + + // This is messy roslibrust expects the starting bytes to be total message size + // which Zenoh or the bridge is stripping somewhere, so I'm just manually sticking them back for now + // This is very inefficient, but it works for now. + let starting_bytes = (bytes.len() as u32).to_le_bytes(); + let bytes = [&starting_bytes, &bytes[..]].concat(); + + let msg = roslibrust_serde_rosmsg::from_slice(&bytes).map_err(|e| { + RosLibRustError::SerializationError(format!("Failed to deserialize sample: {e:?}")) + })?; + Ok(msg) + } +} + +impl TopicProvider for ZenohClient { + type Publisher = ZenohPublisher; + + type Subscriber = ZenohSubscriber; + + async fn advertise( + &self, + topic: &str, + ) -> RosLibRustResult> { + let mangled_topic = mangle_topic(topic, T::ROS_TYPE_NAME, T::MD5SUM); + let publisher = match self.session.declare_publisher(mangled_topic).await { + Ok(publisher) => publisher, + Err(e) => { + // TODO errors still suck with this API... + return Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to declare publisher: {e:?}" + ))); + } + }; + + Ok(ZenohPublisher { + publisher, + _marker: std::marker::PhantomData, + }) + } + + async fn subscribe( + &self, + topic: &str, + ) -> RosLibRustResult> { + let mangled_topic = mangle_topic(topic, T::ROS_TYPE_NAME, T::MD5SUM); + let sub = match self.session.declare_subscriber(mangled_topic).await { + Ok(sub) => sub, + Err(e) => { + // TODO errors still suck with this API... + return Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to declare subscriber: {e:?}" + ))); + } + }; + Ok(ZenohSubscriber { + subscriber: sub, + _marker: std::marker::PhantomData, + }) + } +} + +/// Takes in a regular ros topic and type and returns a zenoh topic mangled in the way the zenoh-ros1-plugin does +fn mangle_topic(topic: &str, type_str: &str, md5sum: &str) -> String { + // Name mangling stuff! + // See: https://github.com/eclipse-zenoh/zenoh-plugin-ros1/issues/131 + // Explicit implementation at: https://github.com/eclipse-zenoh/zenoh-plugin-ros1/blob/main/zenoh-plugin-ros1/src/ros_to_zenoh_bridge/topic_utilities.rs + // Note: the implementation inside of the bridge uses unstable zenoh, duplicating implementation here with stable zenoh instead. + + // Remove leading and trailing slashes in the topic + let topic = topic.trim_start_matches('/').trim_end_matches("/"); + // Encode the type as hex + let type_str = hex::encode(type_str.as_bytes()); + format!("{type_str}/{md5sum}/{topic}") +} + +impl ServiceProvider for ZenohClient { + type ServiceClient = (); + type ServiceServer = (); + + async fn service_client( + &self, + topic: &str, + ) -> RosLibRustResult> { + todo!() + } + + async fn advertise_service< + T: roslibrust_codegen::RosServiceType + 'static, + F: roslibrust::ServiceFn, + >( + &self, + topic: &str, + server: F, + ) -> RosLibRustResult { + todo!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mangle_topic() { + assert_eq!( + mangle_topic( + "/chatter", + "std_msgs/String", + "992ce8a1687cec8c8bd883ec73ca41d1" + ), + "7374645f6d7367732f537472696e67/992ce8a1687cec8c8bd883ec73ca41d1/chatter" + ); + } +} diff --git a/roslibrust_zenoh/src/zenoh_client.rs b/roslibrust_zenoh/src/zenoh_client.rs deleted file mode 100644 index b7c6c454..00000000 --- a/roslibrust_zenoh/src/zenoh_client.rs +++ /dev/null @@ -1,151 +0,0 @@ -use roslibrust::topic_provider::{Publish, Subscribe, TopicProvider}; -use roslibrust::{RosLibRustError, RosLibRustResult}; -use roslibrust_codegen::RosMessageType; - -pub struct ZenohClient { - session: zenoh::Session, -} - -impl ZenohClient { - /// Creates a new client wrapped around a Zenoh session - pub fn new(session: zenoh::Session) -> Self { - Self { session } - } -} - -pub struct ZenohPublisher { - publisher: zenoh::pubsub::Publisher<'static>, - _marker: std::marker::PhantomData, -} - -impl Publish for ZenohPublisher { - async fn publish(&self, data: &T) -> RosLibRustResult<()> { - let bytes = roslibrust_serde_rosmsg::to_vec(data).map_err(|e| { - RosLibRustError::SerializationError(format!("Failed to serialize message: {e:?}")) - })?; - - // Note: serde_rosmsg places the length of the message as the first four bytes - // Which zenoh ros1 bridge does not expect, so we need to strip it off. - match self.publisher.put(&bytes[4..]).await { - Ok(()) => Ok(()), - Err(e) => Err(RosLibRustError::Unexpected(anyhow::anyhow!( - "Failed to publish message to zenoh: {e:?}" - ))), - } - } -} - -// Using type alias here, I have no idea why zenoh has this type so deep -type ZenohSubInner = - zenoh::pubsub::Subscriber>; -pub struct ZenohSubscriber { - subscriber: ZenohSubInner, - _marker: std::marker::PhantomData, -} - -impl Subscribe for ZenohSubscriber { - async fn next(&mut self) -> RosLibRustResult { - let next = self.subscriber.recv_async().await; - - let sample = match next { - Ok(sample) => sample, - Err(e) => { - // TODO errors still suck with this API - return Err(RosLibRustError::Unexpected(anyhow::anyhow!( - "Failed to receive next sample: {e:?}" - ))); - } - }; - - let bytes = sample.payload().to_bytes(); - - // This is messy roslibrust expects the starting bytes to be total message size - // which Zenoh or the bridge is stripping somewhere, so I'm just manually sticking them back for now - // This is very inefficient, but it works for now. - let starting_bytes = (bytes.len() as u32).to_le_bytes(); - let bytes = [&starting_bytes, &bytes[..]].concat(); - - let msg = roslibrust_serde_rosmsg::from_slice(&bytes).map_err(|e| { - RosLibRustError::SerializationError(format!("Failed to deserialize sample: {e:?}")) - })?; - Ok(msg) - } -} - -impl TopicProvider for ZenohClient { - type Publisher = ZenohPublisher; - - type Subscriber = ZenohSubscriber; - - async fn advertise( - &self, - topic: &str, - ) -> RosLibRustResult> { - let mangled_topic = mangle_topic(topic, T::ROS_TYPE_NAME, T::MD5SUM); - let publisher = match self.session.declare_publisher(mangled_topic).await { - Ok(publisher) => publisher, - Err(e) => { - // TODO errors still suck with this API... - return Err(RosLibRustError::Unexpected(anyhow::anyhow!( - "Failed to declare publisher: {e:?}" - ))); - } - }; - - Ok(ZenohPublisher { - publisher, - _marker: std::marker::PhantomData, - }) - } - - async fn subscribe( - &self, - topic: &str, - ) -> RosLibRustResult> { - let mangled_topic = mangle_topic(topic, T::ROS_TYPE_NAME, T::MD5SUM); - let sub = match self.session.declare_subscriber(mangled_topic).await { - Ok(sub) => sub, - Err(e) => { - // TODO errors still suck with this API... - return Err(RosLibRustError::Unexpected(anyhow::anyhow!( - "Failed to declare subscriber: {e:?}" - ))); - } - }; - Ok(ZenohSubscriber { - subscriber: sub, - _marker: std::marker::PhantomData, - }) - } -} - -/// Takes in a regular ros topic and type and returns a zenoh topic mangled in the way the zenoh-ros1-plugin does -fn mangle_topic(topic: &str, type_str: &str, md5sum: &str) -> String { - // Name mangling stuff! - // See: https://github.com/eclipse-zenoh/zenoh-plugin-ros1/issues/131 - // Explicit implementation at: https://github.com/eclipse-zenoh/zenoh-plugin-ros1/blob/main/zenoh-plugin-ros1/src/ros_to_zenoh_bridge/topic_utilities.rs - // Note: the implementation inside of the bridge uses unstable zenoh, duplicating implementation here with stable zenoh instead. - - // Remove leading and trailing slashes in the topic - let topic = topic.trim_start_matches('/').trim_end_matches("/"); - // Encode the type as hex - let type_str = hex::encode(type_str.as_bytes()); - format!("{type_str}/{md5sum}/{topic}") -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_mangle_topic() { - assert_eq!( - mangle_topic( - "/chatter", - "std_msgs/String", - "992ce8a1687cec8c8bd883ec73ca41d1" - ), - "7374645f6d7367732f537472696e67/992ce8a1687cec8c8bd883ec73ca41d1/chatter" - ); - } -} From 533d21f782f2e01ff563094ba69f706470df7623 Mon Sep 17 00:00:00 2001 From: carter Date: Mon, 2 Dec 2024 13:54:14 -0700 Subject: [PATCH 08/16] Fix some shenanigans --- roslibrust/examples/generic_client.rs | 6 +++--- roslibrust/examples/generic_client_services.rs | 6 +++--- roslibrust_codegen/src/lib.rs | 6 +++--- roslibrust_zenoh/src/lib.rs | 14 ++++++++++++-- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/roslibrust/examples/generic_client.rs b/roslibrust/examples/generic_client.rs index 74a4f37e..50b4081e 100644 --- a/roslibrust/examples/generic_client.rs +++ b/roslibrust/examples/generic_client.rs @@ -1,5 +1,8 @@ //! Purpose of this example is to show how the TopicProvider trait can be use //! to create code that is generic of which communication backend it will use. +use roslibrust::topic_provider::*; + +roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces/std_msgs"); #[cfg(feature = "topic_provider")] #[tokio::main] @@ -10,9 +13,6 @@ async fn main() { .init() .unwrap(); - use roslibrust::topic_provider::*; - - roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); // TopicProvider cannot be an "Object Safe Trait" due to its generic parameters // This means we can't do: diff --git a/roslibrust/examples/generic_client_services.rs b/roslibrust/examples/generic_client_services.rs index 6b0fd87a..28fec204 100644 --- a/roslibrust/examples/generic_client_services.rs +++ b/roslibrust/examples/generic_client_services.rs @@ -1,5 +1,8 @@ //! Purpose of this example is to show how the ServiceProvider trait can be use //! to create code that is generic of which communication backend it will use. +use roslibrust::topic_provider::*; + +roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); #[cfg(feature = "topic_provider")] #[tokio::main] @@ -10,9 +13,6 @@ async fn main() { .init() .unwrap(); - use roslibrust::topic_provider::*; - - roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); // TopicProvider cannot be an "Object Safe Trait" due to its generic parameters // This means we can't do: diff --git a/roslibrust_codegen/src/lib.rs b/roslibrust_codegen/src/lib.rs index a031008d..d1ae5adb 100644 --- a/roslibrust_codegen/src/lib.rs +++ b/roslibrust_codegen/src/lib.rs @@ -730,7 +730,7 @@ pub fn generate_rust_ros_message_definitions( } Ok(()) }) - .collect::>()?; + .collect::>()?; // Do the same for services services .into_iter() @@ -744,7 +744,7 @@ pub fn generate_rust_ros_message_definitions( } Ok(()) }) - .collect::>()?; + .collect::>()?; // Now generate modules to wrap all of the TokenStreams in a module for each package let all_pkgs = modules_to_struct_definitions .keys() @@ -753,7 +753,7 @@ pub fn generate_rust_ros_message_definitions( let module_definitions = modules_to_struct_definitions .into_iter() .map(|(pkg, struct_defs)| generate_mod(pkg, struct_defs, &all_pkgs[..])) - .collect::>(); + .collect::>(); Ok(quote! { #(#module_definitions)* diff --git a/roslibrust_zenoh/src/lib.rs b/roslibrust_zenoh/src/lib.rs index 1fd7da35..de309fb0 100644 --- a/roslibrust_zenoh/src/lib.rs +++ b/roslibrust_zenoh/src/lib.rs @@ -1,6 +1,6 @@ //! A crate for interfacing to ROS1 via the [zenoh-ros1-plugin / zenoh-ros1-bridge](https://github.com/eclipse-zenoh/zenoh-plugin-ros1). -use roslibrust::topic_provider::{Publish, ServiceProvider, Subscribe, TopicProvider}; +use roslibrust::topic_provider::{Publish, Service, ServiceProvider, Subscribe, TopicProvider}; use roslibrust::{RosLibRustError, RosLibRustResult}; use roslibrust_codegen::{RosMessageType, RosServiceType}; @@ -135,8 +135,18 @@ fn mangle_topic(topic: &str, type_str: &str, md5sum: &str) -> String { format!("{type_str}/{md5sum}/{topic}") } +pub struct ZenohServiceClient { + _marker: std::marker::PhantomData, +} + +impl Service for ZenohServiceClient { + async fn call(&self, request: &T::Request) -> RosLibRustResult { + todo!() + } +} + impl ServiceProvider for ZenohClient { - type ServiceClient = (); + type ServiceClient = ZenohServiceClient; type ServiceServer = (); async fn service_client( From 7770747a50af15b377bbbd648c473d6a10a62886 Mon Sep 17 00:00:00 2001 From: carter Date: Tue, 3 Dec 2024 09:34:35 -0700 Subject: [PATCH 09/16] Start of zenoh service implementation, hit bugs --- Cargo.lock | 4 +- roslibrust/examples/ros1_service_server.rs | 32 ++++----- roslibrust_zenoh/Cargo.toml | 3 + roslibrust_zenoh/examples/publisher.rs | 4 ++ roslibrust_zenoh/examples/service_call.rs | 33 ++++++++++ roslibrust_zenoh/src/lib.rs | 76 +++++++++++++++++++++- 6 files changed, 133 insertions(+), 19 deletions(-) create mode 100644 roslibrust_zenoh/examples/service_call.rs diff --git a/Cargo.lock b/Cargo.lock index 4b7d1a73..a8d8de81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "abort-on-drop" @@ -2523,7 +2523,9 @@ name = "roslibrust_zenoh" version = "0.1.0" dependencies = [ "anyhow", + "env_logger 0.11.5", "hex", + "log", "roslibrust", "roslibrust_codegen", "roslibrust_codegen_macro", diff --git a/roslibrust/examples/ros1_service_server.rs b/roslibrust/examples/ros1_service_server.rs index 016f826f..abe9afec 100644 --- a/roslibrust/examples/ros1_service_server.rs +++ b/roslibrust/examples/ros1_service_server.rs @@ -13,7 +13,7 @@ async fn main() -> Result<(), anyhow::Error> { .init() .unwrap(); - let nh = NodeHandle::new("http://localhost:11311", "service_server_rs").await?; + let nh = NodeHandle::new("http://127.0.0.1:11311", "service_server_rs").await?; log::info!("Connected!"); // Because our service server can run from any thread at any time @@ -37,7 +37,7 @@ async fn main() -> Result<(), anyhow::Error> { // Start our service running! let _handle = nh - .advertise_service::("~/my_set_bool", server_fn) + .advertise_service::("/my_set_bool", server_fn) .await?; info!("Service has started"); @@ -50,20 +50,20 @@ async fn main() -> Result<(), anyhow::Error> { // As long as _handle is kept alive our service will continue to run // For funsies we can also spawn a task to periodically call our service - let service_client = nh - .service_client::("~/my_set_bool") - .await?; - tokio::spawn(async move { - let mut bool = false; - loop { - bool = !bool; - service_client - .call(&std_srvs::SetBoolRequest { data: bool }) - .await - .unwrap(); - tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; - } - }); + // let service_client = nh + // .service_client::("~/my_set_bool") + // .await?; + // tokio::spawn(async move { + // let mut bool = false; + // loop { + // bool = !bool; + // service_client + // .call(&std_srvs::SetBoolRequest { data: bool }) + // .await + // .unwrap(); + // tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; + // } + // }); // We can still access our shared state, we just have to do it safely loop { diff --git a/roslibrust_zenoh/Cargo.toml b/roslibrust_zenoh/Cargo.toml index 9c7e526f..e3b2c526 100644 --- a/roslibrust_zenoh/Cargo.toml +++ b/roslibrust_zenoh/Cargo.toml @@ -14,4 +14,7 @@ zenoh = "1.0" hex = "0.4" anyhow = "1.0" roslibrust_serde_rosmsg = "0.3" +log = "0.4" +[dev-dependencies] +env_logger = "0.11" diff --git a/roslibrust_zenoh/examples/publisher.rs b/roslibrust_zenoh/examples/publisher.rs index 66ff56e9..781b8903 100644 --- a/roslibrust_zenoh/examples/publisher.rs +++ b/roslibrust_zenoh/examples/publisher.rs @@ -18,6 +18,10 @@ roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_in // Or run the subscriber example `cargo run --example subscriber` #[tokio::main] async fn main() { + // Setup a logger for debugging purposes + // use RUST_LOG=debug for more information if this doesn't work for you + env_logger::init(); + let session = zenoh::open(zenoh::Config::default()).await.unwrap(); let client = ZenohClient::new(session); diff --git a/roslibrust_zenoh/examples/service_call.rs b/roslibrust_zenoh/examples/service_call.rs new file mode 100644 index 00000000..3c951726 --- /dev/null +++ b/roslibrust_zenoh/examples/service_call.rs @@ -0,0 +1,33 @@ +//! Purpose of this example is to show how to call a ROS1 service from a Zenoh client. + +// IMPORTANT to bring this trait into scope so we can access the functions it provides +// [Service] is what allows us to actually access [call] +use roslibrust::topic_provider::Service; + +// IMPORTANT to bring this trait into scope so we can access the functions it provides +// [ServiceProvider] is what allows us to actually access .service_client() +use roslibrust::topic_provider::ServiceProvider; + +use roslibrust_zenoh::ZenohClient; + +roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); + +#[tokio::main] +async fn main() { + env_logger::init(); + + let session = zenoh::open(zenoh::Config::default()).await.unwrap(); + let client = ZenohClient::new(session); + + let client = client + .service_client::("/my_set_bool") + .await + .unwrap(); + + let response = client + .call(&std_srvs::SetBoolRequest { data: true }) + .await + .unwrap(); + + println!("Got response: {response:?}"); +} diff --git a/roslibrust_zenoh/src/lib.rs b/roslibrust_zenoh/src/lib.rs index de309fb0..1aa40e80 100644 --- a/roslibrust_zenoh/src/lib.rs +++ b/roslibrust_zenoh/src/lib.rs @@ -4,6 +4,8 @@ use roslibrust::topic_provider::{Publish, Service, ServiceProvider, Subscribe, T use roslibrust::{RosLibRustError, RosLibRustResult}; use roslibrust_codegen::{RosMessageType, RosServiceType}; +use log::*; + pub struct ZenohClient { session: zenoh::Session, } @@ -136,12 +138,65 @@ fn mangle_topic(topic: &str, type_str: &str, md5sum: &str) -> String { } pub struct ZenohServiceClient { + session: zenoh::Session, + zenoh_query: String, _marker: std::marker::PhantomData, } impl Service for ZenohServiceClient { async fn call(&self, request: &T::Request) -> RosLibRustResult { - todo!() + let request_bytes = roslibrust_serde_rosmsg::to_vec(request).map_err(|e| { + RosLibRustError::SerializationError(format!("Failed to serialize message: {e:?}")) + })?; + debug!("request bytes: {request_bytes:?}"); + + let query = match self + .session + .get(&self.zenoh_query) + .payload(&request_bytes[4..]) + // .timeout(tokio::time::Duration::from_secs(1)) + .await + { + Ok(query) => query, + Err(e) => { + // TODO errors still suck with this API... + return Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to create query for service: {e:?}" + ))); + } + }; + + let response = match query.recv_async().await { + Ok(data) => data, + Err(e) => { + return Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to receive response from service: {e:?}" + ))); + } + }; + + // TODO unclear why this is double failable in the API + let sample = match response.into_result() { + Ok(bytes) => bytes, + Err(e) => { + return Err(RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to receive sample from service: {e:?}" + ))); + } + }; + + let bytes = sample.payload().to_bytes(); + + // This is messy roslibrust expects the starting bytes to be total message size + // which Zenoh or the bridge is stripping somewhere, so I'm just manually sticking them back for now + // This is very inefficient, but it works for now. + let starting_bytes = (bytes.len() as u32).to_le_bytes(); + let bytes = [&starting_bytes, &bytes[..]].concat(); + + let msg = roslibrust_serde_rosmsg::from_slice(&bytes).map_err(|e| { + RosLibRustError::SerializationError(format!("Failed to deserialize sample: {e:?}")) + })?; + Ok(msg) } } @@ -153,7 +208,13 @@ impl ServiceProvider for ZenohClient { &self, topic: &str, ) -> RosLibRustResult> { - todo!() + let mangled_topic = mangle_topic(topic, T::ROS_SERVICE_NAME, T::MD5SUM); + + Ok(ZenohServiceClient { + session: self.session.clone(), + zenoh_query: mangled_topic, + _marker: std::marker::PhantomData, + }) } async fn advertise_service< @@ -183,4 +244,15 @@ mod tests { "7374645f6d7367732f537472696e67/992ce8a1687cec8c8bd883ec73ca41d1/chatter" ); } + + #[test] + fn test_mangle_service() { + assert_eq!( + mangle_topic( + "/service_server_rs/my_set_bool", + "std_srvs/SetBool", + "09fb03525b03e7ea1fd3992bafd87e16" + ), + "7374645f737276732f536574426f6f6c/09fb03525b03e7ea1fd3992bafd87e16/service_server_rs/my_set_bool"); + } } From 7214d0c0c34925a3292830c61a3492baed0e8d06 Mon Sep 17 00:00:00 2001 From: carter Date: Tue, 3 Dec 2024 11:17:28 -0700 Subject: [PATCH 10/16] Got it working :( --- roslibrust/src/ros1/service_server.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/roslibrust/src/ros1/service_server.rs b/roslibrust/src/ros1/service_server.rs index 5abc3def..cd677aae 100644 --- a/roslibrust/src/ros1/service_server.rs +++ b/roslibrust/src/ros1/service_server.rs @@ -161,7 +161,10 @@ impl ServiceServerLink { debug!("Received service_request connection from {peer_addr} for {service_name}"); let connection_header = match tcpros::receive_header(&mut stream).await { - Ok(header) => header, + Ok(header) => { + debug!("Received service request for {service_name} with header {header:?}"); + header + } Err(e) => { warn!("Communication error while handling service request connection for {service_name}, could not parse header: {e:?}"); // TODO returning here simply closes the socket? Should we respond with an error instead? @@ -215,6 +218,11 @@ impl ServiceServerLink { let full_response = [vec![1u8], response].concat(); stream.write_all(&full_response).await.unwrap(); + debug!("Wrote full service response for {service_name}"); + // Temporary change for testing with zenoh-ros1-bridge + // THIS MAGICALLY MAKES IT WORK, THEIR CODE IS NOT "RECEIVING THE RESPONSE" UNTIL THE TCP SOCKET IS CLOSED!! + stream.shutdown().await.unwrap(); + break; } Err(e) => { warn!("Error from user service method for {service_name}: {e:?}"); From 7262ad684896c6124dccb0d4e12398f4ef18d721 Mon Sep 17 00:00:00 2001 From: carter Date: Tue, 3 Dec 2024 15:24:32 -0700 Subject: [PATCH 11/16] Working both ways zenoh services --- roslibrust_zenoh/examples/service_server.rs | 47 ++++++ .../examples/snoop_on_discovery.rs | 16 ++ roslibrust_zenoh/src/lib.rs | 138 +++++++++++++++++- 3 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 roslibrust_zenoh/examples/service_server.rs create mode 100644 roslibrust_zenoh/examples/snoop_on_discovery.rs diff --git a/roslibrust_zenoh/examples/service_server.rs b/roslibrust_zenoh/examples/service_server.rs new file mode 100644 index 00000000..f0879036 --- /dev/null +++ b/roslibrust_zenoh/examples/service_server.rs @@ -0,0 +1,47 @@ +//! Purpose of this example is to show how to host service visible to ROS1 from a Zenoh client. + +// IMPORTANT to bring this trait into scope so we can access the functions it provides +// [ServiceProvider] is what allows us to actually access .service_client() +use roslibrust::topic_provider::ServiceProvider; +use roslibrust_zenoh::ZenohClient; + +// IMPORTANT this example will not work with the default zenoh-ros1-bridge settings! +// It requires the flag `--client_bridging_mode auto` to be set when the bridge is started +// Otherwise the service will not be advertised to ROS1 master. + +// Generate rust definitions for our messages +roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); + +#[tokio::main] +async fn main() { + // Setup a logger for debugging purposes + // Run this example with RUST_LOG=debug for more information if this doesn't work for you + env_logger::init(); + + // Create our zenoh client, depending on how you are running zenoh / the bridge you may + // need to pass specific configuration in here. + let session = zenoh::open(zenoh::Config::default()).await.unwrap(); + let client = ZenohClient::new(session); + + // Service will remain alive until handle is dropped + let _handle = client + .advertise_service::( + "/my_set_bool", + |request: std_srvs::SetBoolRequest| { + log::info!("Got request to set bool: {request:?}"); + Ok(std_srvs::SetBoolResponse { + success: true, + message: "You set my bool!".to_string(), + }) + }, + ) + .await + .unwrap(); + + // Wait for ctrl_c to kill this process + tokio::signal::ctrl_c().await.unwrap(); + + // While this example is running: + // `rosservice list` should show /my_set_bool + // `rosservice call /my_set_bool "data: true"` should work +} diff --git a/roslibrust_zenoh/examples/snoop_on_discovery.rs b/roslibrust_zenoh/examples/snoop_on_discovery.rs new file mode 100644 index 00000000..85ba9d68 --- /dev/null +++ b/roslibrust_zenoh/examples/snoop_on_discovery.rs @@ -0,0 +1,16 @@ +//! Not actually an example for this crate, just peeping on how discovery for zenoh-ros1-bridge works + +#[tokio::main] +async fn main() { + let session = zenoh::open(zenoh::Config::default()).await.unwrap(); + + let sub = session + .declare_subscriber("ros1_discovery_info/**") + .await + .unwrap(); + + loop { + let sample = sub.recv_async().await.unwrap(); + println!("Got sample: {sample:?}"); + } +} diff --git a/roslibrust_zenoh/src/lib.rs b/roslibrust_zenoh/src/lib.rs index 1aa40e80..fe57286a 100644 --- a/roslibrust_zenoh/src/lib.rs +++ b/roslibrust_zenoh/src/lib.rs @@ -5,6 +5,8 @@ use roslibrust::{RosLibRustError, RosLibRustResult}; use roslibrust_codegen::{RosMessageType, RosServiceType}; use log::*; +use tokio::select; +use zenoh::bytes::ZBytes; pub struct ZenohClient { session: zenoh::Session, @@ -137,6 +139,17 @@ fn mangle_topic(topic: &str, type_str: &str, md5sum: &str) -> String { format!("{type_str}/{md5sum}/{topic}") } +/// Identical to mangle_topic, but for services we want to separate the datatype stuff from the service name +fn mangle_service(service: &str, type_str: &str, md5sum: &str) -> (String, String) { + let service = service.trim_start_matches('/').trim_end_matches("/"); + + let type_str = hex::encode(type_str.as_bytes()); + ( + format!("{type_str}/{md5sum}"), + format!("{service}").to_string(), + ) +} + pub struct ZenohServiceClient { session: zenoh::Session, zenoh_query: String, @@ -200,9 +213,18 @@ impl Service for ZenohServiceClient { } } +/// The "holder type" returned when advertising a service +/// Dropping this will stop the service server +pub struct ZenohServiceServer { + // Dropping this will stop zenoh's declaration of the queryable + _queryable: zenoh::query::Queryable<()>, + // Dropping this will stop the advertising of the service + _shutdown_channel: tokio::sync::oneshot::Sender<()>, +} + impl ServiceProvider for ZenohClient { type ServiceClient = ZenohServiceClient; - type ServiceServer = (); + type ServiceServer = ZenohServiceServer; async fn service_client( &self, @@ -225,7 +247,119 @@ impl ServiceProvider for ZenohClient { topic: &str, server: F, ) -> RosLibRustResult { - todo!() + let mangled_topic = mangle_topic(topic, T::ROS_SERVICE_NAME, T::MD5SUM); + + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel(); + let (shutdown_tx, mut shutdown_rx) = tokio::sync::oneshot::channel(); + + let x = self + .session + .declare_queryable(mangled_topic) + .callback(move |query| { + let _ = tx.send(query).map_err(|e| { + error!("Failed to send query: {e:?}"); + }); + }) + .await + .map_err(|e| { + RosLibRustError::Unexpected(anyhow::anyhow!("Failed to declare queryable: {e:?}")) + })?; + + // Spawn a task to handle the queries + // This task will shut down when queryable is dropped + tokio::spawn(async move { + while let Some(query) = rx.recv().await { + debug!("Got query: {query:?}"); + let Some(payload) = query.payload() else { + error!("Received a query with no payload for a ros0 service {query:?}"); + continue; + }; + let bytes = payload.to_bytes(); + debug!("Got bytes: {bytes:?}"); + // TODO MAJOR HACK HERE STILL + // Our deserialization still expects the first four bytes to be the total message size + // So we're just going to manually add the bytes back in + let starting_bytes = (bytes.len() as u32).to_le_bytes(); + let bytes = [&starting_bytes, &bytes[..]].concat(); + + let Ok(request) = roslibrust_serde_rosmsg::from_slice(&bytes).map_err(|e| { + error!("Failed to deserialize request: {e:?}"); + }) else { + continue; + }; + + let Ok(response) = server(request).map_err(|e| { + error!("Failed to handle request: {e:?}"); + }) else { + continue; + }; + + let Ok(response_bytes) = roslibrust_serde_rosmsg::to_vec(&response).map_err(|e| { + error!("Failed to serialize response: {e:?}"); + }) else { + continue; + }; + + // TODO HACK HERE STILL + // Zenoh doesn't want the first four bytes that are the overall message size: + let response_bytes = &response_bytes[4..]; + + let _ = query + .reply(query.key_expr(), response_bytes) + .await + .map_err(|e| { + error!("Failed to reply to query: {e:?}"); + }); + } + }); + // zenoh-ros1-bridge won't serve our service without us publishing info on 'ros1_discovery_info' + // We don't have to worry about this for publishers, because zenoh will initiate the bridge whenever someone subscribes on the ros side. + // For service, zenoh-ros1-bridge has to create the service before anyone can call it so it has to know that it needs to do that. + // This is a bit of a brittle implementation as it relies on internal implementation details for zenoh-ros1-bridge, but it works for now. + // See: https://github.com/eclipse-zenoh/zenoh-plugin-ros1/blob/main/zenoh-plugin-ros1/src/ros_to_zenoh_bridge/discovery.rs + + // Note: I'm uncertain about "discovery_namespace" and just using * for now + // Note: I'm uncertain about "bridge_namespace" and just using * for now + let (type_mangle, service_name) = mangle_service(topic, T::ROS_SERVICE_NAME, T::MD5SUM); + let zenoh_info_topic = format!("ros1_discovery_info/*/srv/{type_mangle}/*/{service_name}"); + + let q2 = self + .session + .declare_publisher(zenoh_info_topic) + .await + .map_err(|e| { + RosLibRustError::Unexpected(anyhow::anyhow!( + "Failed to declare queryable for service discovery: {e:?}" + )) + })?; + tokio::spawn(async move { + let mut interval = tokio::time::interval(std::time::Duration::from_secs(1)); + loop { + let shutdown = shutdown_rx.try_recv(); + match shutdown { + Ok(_) => { + break; + } + Err(tokio::sync::oneshot::error::TryRecvError::Empty) => { + // Continue no shutdown yet + } + Err(tokio::sync::oneshot::error::TryRecvError::Closed) => { + break; + } + } + // Send an empty message to the discovery topic + let res = q2.put(ZBytes::default()).await; + if let Err(e) = res { + error!("Failed to publish service discovery info: {e:?}"); + } + interval.tick().await; + } + }); + + Ok(ZenohServiceServer { + _queryable: x, + _shutdown_channel: shutdown_tx, + }) } } From 032254b4a521ec26c2e1ff9f77aba99996d8d236 Mon Sep 17 00:00:00 2001 From: carter Date: Tue, 3 Dec 2024 15:54:50 -0700 Subject: [PATCH 12/16] Removed temprorary line not needed now that main fix was merged to master --- roslibrust/src/ros1/service_server.rs | 4 ---- roslibrust/src/ros1/tcpros.rs | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/roslibrust/src/ros1/service_server.rs b/roslibrust/src/ros1/service_server.rs index c20880f2..affa6394 100644 --- a/roslibrust/src/ros1/service_server.rs +++ b/roslibrust/src/ros1/service_server.rs @@ -217,10 +217,6 @@ impl ServiceServerLink { stream.write_all(&full_response).await.unwrap(); debug!("Wrote full service response for {service_name}"); - // Temporary change for testing with zenoh-ros1-bridge - // THIS MAGICALLY MAKES IT WORK, THEIR CODE IS NOT "RECEIVING THE RESPONSE" UNTIL THE TCP SOCKET IS CLOSED!! - stream.shutdown().await.unwrap(); - break; } Err(e) => { warn!("Error from user service method for {service_name}: {e:?}"); diff --git a/roslibrust/src/ros1/tcpros.rs b/roslibrust/src/ros1/tcpros.rs index c95dc99e..a4379ece 100644 --- a/roslibrust/src/ros1/tcpros.rs +++ b/roslibrust/src/ros1/tcpros.rs @@ -212,6 +212,7 @@ pub async fn establish_connection( // Write our own connection header to the stream let conn_header_bytes = conn_header.to_bytes(true)?; + trace!("Sending connection header to server {server_uri} for topic {topic_name}: {conn_header:?}"); stream.write_all(&conn_header_bytes[..]).await?; // Recieve the header from the server From b828b8683b708aae1feb59a6a8fa0f14c0620d3d Mon Sep 17 00:00:00 2001 From: carter Date: Tue, 3 Dec 2024 15:55:00 -0700 Subject: [PATCH 13/16] Removed temprorary line not needed now that main fix was merged to master --- roslibrust/src/ros1/tcpros.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/roslibrust/src/ros1/tcpros.rs b/roslibrust/src/ros1/tcpros.rs index a4379ece..5075a3bf 100644 --- a/roslibrust/src/ros1/tcpros.rs +++ b/roslibrust/src/ros1/tcpros.rs @@ -212,7 +212,9 @@ pub async fn establish_connection( // Write our own connection header to the stream let conn_header_bytes = conn_header.to_bytes(true)?; - trace!("Sending connection header to server {server_uri} for topic {topic_name}: {conn_header:?}"); + trace!( + "Sending connection header to server {server_uri} for topic {topic_name}: {conn_header:?}" + ); stream.write_all(&conn_header_bytes[..]).await?; // Recieve the header from the server From d06e59bbd74363b289dd3bfeecf962f15aae966d Mon Sep 17 00:00:00 2001 From: carter Date: Tue, 3 Dec 2024 16:06:44 -0700 Subject: [PATCH 14/16] remove unused include --- roslibrust_zenoh/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/roslibrust_zenoh/src/lib.rs b/roslibrust_zenoh/src/lib.rs index fe57286a..523cdaee 100644 --- a/roslibrust_zenoh/src/lib.rs +++ b/roslibrust_zenoh/src/lib.rs @@ -5,7 +5,6 @@ use roslibrust::{RosLibRustError, RosLibRustResult}; use roslibrust_codegen::{RosMessageType, RosServiceType}; use log::*; -use tokio::select; use zenoh::bytes::ZBytes; pub struct ZenohClient { From db0b43d21d236e30e1e35812ca4d5a4f76c5226a Mon Sep 17 00:00:00 2001 From: carter Date: Wed, 4 Dec 2024 09:25:25 -0700 Subject: [PATCH 15/16] Cleanups --- roslibrust/examples/ros1_service_server.rs | 32 +++++++++++----------- roslibrust_zenoh/Cargo.toml | 8 ++++-- roslibrust_zenoh/examples/service_call.rs | 10 +++++++ 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/roslibrust/examples/ros1_service_server.rs b/roslibrust/examples/ros1_service_server.rs index abe9afec..016f826f 100644 --- a/roslibrust/examples/ros1_service_server.rs +++ b/roslibrust/examples/ros1_service_server.rs @@ -13,7 +13,7 @@ async fn main() -> Result<(), anyhow::Error> { .init() .unwrap(); - let nh = NodeHandle::new("http://127.0.0.1:11311", "service_server_rs").await?; + let nh = NodeHandle::new("http://localhost:11311", "service_server_rs").await?; log::info!("Connected!"); // Because our service server can run from any thread at any time @@ -37,7 +37,7 @@ async fn main() -> Result<(), anyhow::Error> { // Start our service running! let _handle = nh - .advertise_service::("/my_set_bool", server_fn) + .advertise_service::("~/my_set_bool", server_fn) .await?; info!("Service has started"); @@ -50,20 +50,20 @@ async fn main() -> Result<(), anyhow::Error> { // As long as _handle is kept alive our service will continue to run // For funsies we can also spawn a task to periodically call our service - // let service_client = nh - // .service_client::("~/my_set_bool") - // .await?; - // tokio::spawn(async move { - // let mut bool = false; - // loop { - // bool = !bool; - // service_client - // .call(&std_srvs::SetBoolRequest { data: bool }) - // .await - // .unwrap(); - // tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; - // } - // }); + let service_client = nh + .service_client::("~/my_set_bool") + .await?; + tokio::spawn(async move { + let mut bool = false; + loop { + bool = !bool; + service_client + .call(&std_srvs::SetBoolRequest { data: bool }) + .await + .unwrap(); + tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; + } + }); // We can still access our shared state, we just have to do it safely loop { diff --git a/roslibrust_zenoh/Cargo.toml b/roslibrust_zenoh/Cargo.toml index e3b2c526..53d1e431 100644 --- a/roslibrust_zenoh/Cargo.toml +++ b/roslibrust_zenoh/Cargo.toml @@ -7,9 +7,11 @@ edition = "2021" [dependencies] tokio = { version = "1.41", features = ["rt-multi-thread", "sync", "macros"] } -roslibrust_codegen_macro = { path = "../roslibrust_codegen_macro" } -roslibrust_codegen = { path = "../roslibrust_codegen" } +# We currently need to depend on these crates for trait information +# I think we should move topic_provider and the generic message traits into their own crate +# Then more things can work with them generically with less compile time dependencies roslibrust = { path = "../roslibrust", features = ["topic_provider"] } +roslibrust_codegen = { path = "../roslibrust_codegen" } zenoh = "1.0" hex = "0.4" anyhow = "1.0" @@ -18,3 +20,5 @@ log = "0.4" [dev-dependencies] env_logger = "0.11" +# Used to generate message types for the examples +roslibrust_codegen_macro = { path = "../roslibrust_codegen_macro" } diff --git a/roslibrust_zenoh/examples/service_call.rs b/roslibrust_zenoh/examples/service_call.rs index 3c951726..e40b97e6 100644 --- a/roslibrust_zenoh/examples/service_call.rs +++ b/roslibrust_zenoh/examples/service_call.rs @@ -8,22 +8,32 @@ use roslibrust::topic_provider::Service; // [ServiceProvider] is what allows us to actually access .service_client() use roslibrust::topic_provider::ServiceProvider; +// Bring our client type into scope use roslibrust_zenoh::ZenohClient; +// Generate rust definitions for our messages compatible with roslibrust roslibrust_codegen_macro::find_and_generate_ros_messages!("assets/ros1_common_interfaces"); #[tokio::main] async fn main() { + // Initialize a logger for debug information while running the example. + // Setting the RUST_LOG environment variable can be used to get debug + // information if you have issues with this example. env_logger::init(); + // Start a zenoh session, depending on how you are running zenoh / the bridge you may + // need to pass specific configuration into zenoh::open(). let session = zenoh::open(zenoh::Config::default()).await.unwrap(); + // Wrap the zenoh session into a roslibrust client let client = ZenohClient::new(session); + // Create a service client we'll use to call the service let client = client .service_client::("/my_set_bool") .await .unwrap(); + // Actually makes the call, sending in the request data, and getting back the response let response = client .call(&std_srvs::SetBoolRequest { data: true }) .await From 13f9ecd05e3780618d289b5cdb83bab73a80e317 Mon Sep 17 00:00:00 2001 From: carter Date: Wed, 4 Dec 2024 11:46:01 -0700 Subject: [PATCH 16/16] Move to updated version of roslibrust_serde_rosmsg so that we can avoid a lot of byte shuffling --- Cargo.lock | 5 ++- roslibrust/Cargo.toml | 2 +- roslibrust_zenoh/Cargo.toml | 2 +- roslibrust_zenoh/src/lib.rs | 71 +++++++++++++++---------------------- 4 files changed, 33 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8d8de81..ea02e785 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2493,14 +2493,13 @@ dependencies = [ [[package]] name = "roslibrust_serde_rosmsg" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee7ea0fc21625dd94a69e126b9f2c1eab4b60dd80a6abf3e0a3e284f9d648586" +checksum = "dfcb4a6411b4969947dd4fcc23488c4fd7e2e3c180c8d167bece0661df5c0fae" dependencies = [ "byteorder", "error-chain", "serde", - "serde_derive", ] [[package]] diff --git a/roslibrust/Cargo.toml b/roslibrust/Cargo.toml index b8810433..7bc8db04 100644 --- a/roslibrust/Cargo.toml +++ b/roslibrust/Cargo.toml @@ -38,7 +38,7 @@ roslibrust_codegen_macro = { path = "../roslibrust_codegen_macro", version = "0. roslibrust_codegen = { path = "../roslibrust_codegen", version = "0.11.1" } reqwest = { version = "0.11", optional = true } # Only used with native ros1 serde_xmlrpc = { version = "0.2", optional = true } # Only used with native ros1 -roslibrust_serde_rosmsg = { version = "0.3", optional = true } # Only used with native ros1 +roslibrust_serde_rosmsg = { version = "0.4", optional = true } # Only used with native ros1 hyper = { version = "0.14", features = [ "server", ], optional = true } # Only used with native ros1 diff --git a/roslibrust_zenoh/Cargo.toml b/roslibrust_zenoh/Cargo.toml index 53d1e431..729b2f90 100644 --- a/roslibrust_zenoh/Cargo.toml +++ b/roslibrust_zenoh/Cargo.toml @@ -15,7 +15,7 @@ roslibrust_codegen = { path = "../roslibrust_codegen" } zenoh = "1.0" hex = "0.4" anyhow = "1.0" -roslibrust_serde_rosmsg = "0.3" +roslibrust_serde_rosmsg = "0.4" log = "0.4" [dev-dependencies] diff --git a/roslibrust_zenoh/src/lib.rs b/roslibrust_zenoh/src/lib.rs index 523cdaee..64ad1ac0 100644 --- a/roslibrust_zenoh/src/lib.rs +++ b/roslibrust_zenoh/src/lib.rs @@ -25,13 +25,11 @@ pub struct ZenohPublisher { impl Publish for ZenohPublisher { async fn publish(&self, data: &T) -> RosLibRustResult<()> { - let bytes = roslibrust_serde_rosmsg::to_vec(data).map_err(|e| { + let bytes = roslibrust_serde_rosmsg::to_vec_skip_length(data).map_err(|e| { RosLibRustError::SerializationError(format!("Failed to serialize message: {e:?}")) })?; - // Note: serde_rosmsg places the length of the message as the first four bytes - // Which zenoh ros1 bridge does not expect, so we need to strip it off. - match self.publisher.put(&bytes[4..]).await { + match self.publisher.put(&bytes).await { Ok(()) => Ok(()), Err(e) => Err(RosLibRustError::Unexpected(anyhow::anyhow!( "Failed to publish message to zenoh: {e:?}" @@ -63,16 +61,12 @@ impl Subscribe for ZenohSubscriber { }; let bytes = sample.payload().to_bytes(); - - // This is messy roslibrust expects the starting bytes to be total message size - // which Zenoh or the bridge is stripping somewhere, so I'm just manually sticking them back for now - // This is very inefficient, but it works for now. - let starting_bytes = (bytes.len() as u32).to_le_bytes(); - let bytes = [&starting_bytes, &bytes[..]].concat(); - - let msg = roslibrust_serde_rosmsg::from_slice(&bytes).map_err(|e| { - RosLibRustError::SerializationError(format!("Failed to deserialize sample: {e:?}")) - })?; + // Note: Zenoh decided to not make the 4 byte length header part of the payload + // So we use the known length version of the deserialization + let msg = roslibrust_serde_rosmsg::from_slice_known_length(&bytes, bytes.len() as u32) + .map_err(|e| { + RosLibRustError::SerializationError(format!("Failed to deserialize sample: {e:?}")) + })?; Ok(msg) } } @@ -157,7 +151,8 @@ pub struct ZenohServiceClient { impl Service for ZenohServiceClient { async fn call(&self, request: &T::Request) -> RosLibRustResult { - let request_bytes = roslibrust_serde_rosmsg::to_vec(request).map_err(|e| { + // Note: Zenoh decided the 4 byte length header is not part of the payload + let request_bytes = roslibrust_serde_rosmsg::to_vec_skip_length(request).map_err(|e| { RosLibRustError::SerializationError(format!("Failed to serialize message: {e:?}")) })?; debug!("request bytes: {request_bytes:?}"); @@ -165,8 +160,7 @@ impl Service for ZenohServiceClient { let query = match self .session .get(&self.zenoh_query) - .payload(&request_bytes[4..]) - // .timeout(tokio::time::Duration::from_secs(1)) + .payload(&request_bytes) .await { Ok(query) => query, @@ -199,15 +193,11 @@ impl Service for ZenohServiceClient { let bytes = sample.payload().to_bytes(); - // This is messy roslibrust expects the starting bytes to be total message size - // which Zenoh or the bridge is stripping somewhere, so I'm just manually sticking them back for now - // This is very inefficient, but it works for now. - let starting_bytes = (bytes.len() as u32).to_le_bytes(); - let bytes = [&starting_bytes, &bytes[..]].concat(); - - let msg = roslibrust_serde_rosmsg::from_slice(&bytes).map_err(|e| { - RosLibRustError::SerializationError(format!("Failed to deserialize sample: {e:?}")) - })?; + // Note: Zenoh decided to not make the 4 byte length header part of the payload + let msg = roslibrust_serde_rosmsg::from_slice_known_length(&bytes, bytes.len() as u32) + .map_err(|e| { + RosLibRustError::SerializationError(format!("Failed to deserialize sample: {e:?}")) + })?; Ok(msg) } } @@ -275,15 +265,14 @@ impl ServiceProvider for ZenohClient { }; let bytes = payload.to_bytes(); debug!("Got bytes: {bytes:?}"); - // TODO MAJOR HACK HERE STILL - // Our deserialization still expects the first four bytes to be the total message size - // So we're just going to manually add the bytes back in - let starting_bytes = (bytes.len() as u32).to_le_bytes(); - let bytes = [&starting_bytes, &bytes[..]].concat(); - - let Ok(request) = roslibrust_serde_rosmsg::from_slice(&bytes).map_err(|e| { - error!("Failed to deserialize request: {e:?}"); - }) else { + + // Note: Zenoh decided the 4 byte length header is not part of the payload + let Ok(request) = + roslibrust_serde_rosmsg::from_slice_known_length(&bytes, bytes.len() as u32) + .map_err(|e| { + error!("Failed to deserialize request: {e:?}"); + }) + else { continue; }; @@ -293,16 +282,14 @@ impl ServiceProvider for ZenohClient { continue; }; - let Ok(response_bytes) = roslibrust_serde_rosmsg::to_vec(&response).map_err(|e| { - error!("Failed to serialize response: {e:?}"); - }) else { + let Ok(response_bytes) = roslibrust_serde_rosmsg::to_vec_skip_length(&response) + .map_err(|e| { + error!("Failed to serialize response: {e:?}"); + }) + else { continue; }; - // TODO HACK HERE STILL - // Zenoh doesn't want the first four bytes that are the overall message size: - let response_bytes = &response_bytes[4..]; - let _ = query .reply(query.key_expr(), response_bytes) .await