diff --git a/Cargo.lock b/Cargo.lock index 2a90569..25b689b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aead" version = "0.6.0-rc.2" @@ -30,9 +15,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -107,9 +92,6 @@ name = "anyhow" version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" -dependencies = [ - "backtrace", -] [[package]] name = "arrayref" @@ -144,7 +126,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -202,21 +184,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link 0.2.1", -] - [[package]] name = "base16ct" version = "0.3.0" @@ -270,12 +237,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "btparse" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387e80962b798815a2b5c4bcfdb6bf626fa922ffe9f74e373103b858738e9f31" - [[package]] name = "bumpalo" version = "3.19.0" @@ -296,9 +257,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.41" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "shlex", @@ -360,9 +321,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -370,9 +331,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -389,7 +350,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -407,17 +368,6 @@ dependencies = [ "thiserror 2.0.17", ] -[[package]] -name = "color-backtrace" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e49b1973af2a47b5b44f7dd0a344598da95c872e1556b045607888784e973b91" -dependencies = [ - "backtrace", - "btparse", - "termcolor", -] - [[package]] name = "colorchoice" version = "1.0.4" @@ -589,7 +539,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -611,9 +561,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -644,7 +594,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", "unicode-xid", ] @@ -656,7 +606,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", "unicode-xid", ] @@ -685,7 +635,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -701,9 +651,9 @@ dependencies = [ [[package]] name = "document-features" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" dependencies = [ "litrs", ] @@ -762,7 +712,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -892,7 +842,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -966,12 +916,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "glob" version = "0.3.3" @@ -1254,9 +1198,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -1267,9 +1211,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1280,11 +1224,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -1295,42 +1238,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -1431,9 +1370,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -1441,9 +1380,9 @@ dependencies = [ [[package]] name = "iroh" -version = "0.94.0" +version = "0.95.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9428cef1eafd2eac584269986d1949e693877ac12065b401dfde69f664b07ac" +checksum = "2374ba3cdaac152dc6ada92d971f7328e6408286faab3b7350842b2ebbed4789" dependencies = [ "aead", "backon", @@ -1465,10 +1404,9 @@ dependencies = [ "iroh-quinn-proto", "iroh-quinn-udp", "iroh-relay", + "n0-error", "n0-future", - "n0-snafu", "n0-watcher", - "nested_enum_utils", "netdev", "netwatch", "pin-project", @@ -1483,7 +1421,6 @@ dependencies = [ "rustls-webpki", "serde", "smallvec", - "snafu", "strum", "time", "tokio", @@ -1498,19 +1435,17 @@ dependencies = [ [[package]] name = "iroh-base" -version = "0.94.0" +version = "0.95.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db942f6f3d6fa9b475690c6e8e6684d60591dd886bf1bdfef4c60d89d502215c" +checksum = "25a8c5fb1cc65589f0d7ab44269a76f615a8c4458356952c9b0ef1c93ea45ff8" dependencies = [ "curve25519-dalek", "data-encoding", "derive_more 2.0.1", "ed25519-dalek", - "n0-snafu", - "nested_enum_utils", + "n0-error", "rand_core 0.9.3", "serde", - "snafu", "url", "zeroize", "zeroize_derive", @@ -1518,29 +1453,29 @@ dependencies = [ [[package]] name = "iroh-metrics" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84c167b59ae22f940e78eb347ca5f02aa25608e994cb5a7cc016ac2d5eada18" +checksum = "79e3381da7c93c12d353230c74bba26131d1c8bf3a4d8af0fec041546454582e" dependencies = [ "iroh-metrics-derive", "itoa", + "n0-error", "postcard", "ryu", "serde", - "snafu", "tracing", ] [[package]] name = "iroh-metrics-derive" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "748d380f26f7c25307c0a7acd181b84b977ddc2a1b7beece1e5998623c323aa1" +checksum = "d4e12bd0763fd16062f5cc5e8db15dd52d26e75a8af4c7fb57ccee3589b344b8" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -1599,9 +1534,9 @@ dependencies = [ [[package]] name = "iroh-relay" -version = "0.94.0" +version = "0.95.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360e201ab1803201de9a125dd838f7a4d13e6ba3a79aeb46c7fbf023266c062e" +checksum = "43fbdf2aeffa7d6ede1a31f6570866c2199b1cee96a0b563994623795d1bac2c" dependencies = [ "blake3", "bytes", @@ -1619,9 +1554,8 @@ dependencies = [ "iroh-quinn", "iroh-quinn-proto", "lru 0.16.2", + "n0-error", "n0-future", - "n0-snafu", - "nested_enum_utils", "num_enum", "pin-project", "pkarr", @@ -1633,7 +1567,6 @@ dependencies = [ "serde", "serde_bytes", "sha1", - "snafu", "strum", "tokio", "tokio-rustls", @@ -1656,6 +1589,7 @@ dependencies = [ "futures-util", "iroh-quinn", "irpc-derive", + "n0-error", "n0-future", "postcard", "rcgen", @@ -1663,7 +1597,6 @@ dependencies = [ "serde", "smallvec", "testresult", - "thiserror 2.0.17", "thousands", "tokio", "tokio-util", @@ -1678,7 +1611,7 @@ version = "0.8.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -1694,6 +1627,7 @@ dependencies = [ "iroh-base", "irpc", "irpc-derive", + "n0-error", "n0-future", "postcard", "rand 0.9.2", @@ -1705,9 +1639,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" @@ -1739,9 +1673,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -1761,15 +1695,15 @@ checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" -version = "0.4.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "lock_api" @@ -1835,15 +1769,6 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" version = "1.1.0" @@ -1873,6 +1798,29 @@ dependencies = [ "uuid", ] +[[package]] +name = "n0-error" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a4839a11b62f1fdd75be912ee20634053c734c2240e867ded41c7f50822c549" +dependencies = [ + "derive_more 2.0.1", + "n0-error-macros", + "spez", +] + +[[package]] +name = "n0-error-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed2a7e5ca3cb5729d4a162d7bcab5b338bed299a2fee8457568d7e0a747ed89" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "n0-future" version = "0.3.0" @@ -1894,40 +1842,15 @@ dependencies = [ "web-time", ] -[[package]] -name = "n0-snafu" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1815107e577a95bfccedb4cfabc73d709c0db6d12de3f14e0f284a8c5036dc4f" -dependencies = [ - "anyhow", - "btparse", - "color-backtrace", - "snafu", - "tracing-error", -] - [[package]] name = "n0-watcher" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34c65e127e06e5a2781b28df6a33ea474a7bddc0ac0cfea888bd20c79a1b6516" +checksum = "38acf13c1ddafc60eb7316d52213467f8ccb70b6f02b65e7d97f7799b1f50be4" dependencies = [ "derive_more 2.0.1", + "n0-error", "n0-future", - "snafu", -] - -[[package]] -name = "nested_enum_utils" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43fa9161ed44d30e9702fe42bd78693bceac0fed02f647da749f36109023d3a3" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", ] [[package]] @@ -1997,9 +1920,9 @@ dependencies = [ [[package]] name = "netwatch" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98d7ec7abdbfe67ee70af3f2002326491178419caea22254b9070e6ff0c83491" +checksum = "26f2acd376ef48b6c326abf3ba23c449e0cb8aa5c2511d189dd8a8a3bfac889b" dependencies = [ "atomic-waker", "bytes", @@ -2008,9 +1931,9 @@ dependencies = [ "iroh-quinn-udp", "js-sys", "libc", + "n0-error", "n0-future", "n0-watcher", - "nested_enum_utils", "netdev", "netlink-packet-core", "netlink-packet-route", @@ -2018,7 +1941,6 @@ dependencies = [ "netlink-sys", "pin-project-lite", "serde", - "snafu", "socket2 0.6.1", "time", "tokio", @@ -2088,16 +2010,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.107", -] - -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", + "syn", ] [[package]] @@ -2112,9 +2025,9 @@ dependencies = [ [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "openssl-probe" @@ -2209,7 +2122,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -2283,9 +2196,9 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portmapper" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d73aa9bd141e0ff6060fea89a5437883f3b9ceea1cda71c790b90e17d072a3b3" +checksum = "7b575f975dcf03e258b0c7ab3f81497d7124f508884c37da66a7314aa2a8d467" dependencies = [ "base64", "bytes", @@ -2296,13 +2209,12 @@ dependencies = [ "igd-next", "iroh-metrics", "libc", - "nested_enum_utils", + "n0-error", "netwatch", "num_enum", "rand 0.9.2", "serde", "smallvec", - "snafu", "socket2 0.6.1", "time", "tokio", @@ -2334,14 +2246,14 @@ checksum = "e0232bd009a197ceec9cc881ba46f727fcd8060a2d8d6a9dde7a69030a6fe2bb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -2372,9 +2284,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -2608,12 +2520,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -2631,9 +2537,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.33" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "751e04a496ca00bb97a5e043158d23d66b5aabf2e1d5aa2a0aaebb1aafe6f82c" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "log", "once_cell", @@ -2658,9 +2564,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "web-time", "zeroize", @@ -2695,9 +2601,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.7" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -2781,9 +2687,9 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749" +checksum = "16c2f82143577edb4921b71ede051dac62ca3c16084e918bf7b40c96ae10eb33" [[package]] name = "semver" @@ -2834,7 +2740,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -2935,9 +2841,9 @@ dependencies = [ [[package]] name = "signature" -version = "3.0.0-rc.4" +version = "3.0.0-rc.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc280a6ff65c79fbd6622f64d7127f32b85563bca8c53cd2e9141d6744a9056d" +checksum = "2a0251c9d6468f4ba853b6352b190fb7c1e405087779917c238445eb03993826" [[package]] name = "simdutf8" @@ -2966,28 +2872,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "snafu" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2" -dependencies = [ - "backtrace", - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.107", -] - [[package]] name = "socket2" version = "0.5.10" @@ -3008,6 +2892,17 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "spez" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87e960f4dca2788eeb86bbdde8dd246be8948790b7618d656e68f9b720a86e8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "spin" version = "0.9.8" @@ -3063,7 +2958,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -3074,20 +2969,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", @@ -3111,7 +2995,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -3143,9 +3027,9 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] name = "target-triple" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790" +checksum = "591ef38edfb78ca4771ee32cf494cb8771944bee237a9b91fc9c1424ac4b777b" [[package]] name = "termcolor" @@ -3188,7 +3072,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -3199,7 +3083,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -3239,9 +3123,9 @@ checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -3287,7 +3171,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -3314,9 +3198,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -3464,7 +3348,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -3477,16 +3361,6 @@ dependencies = [ "valuable", ] -[[package]] -name = "tracing-error" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" -dependencies = [ - "tracing", - "tracing-subscriber", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -3524,9 +3398,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.112" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d66678374d835fe847e0dc8348fde2ceb5be4a7ec204437d8367f0d8df266a5" +checksum = "559b6a626c0815c942ac98d434746138b4f89ddd6a1b8cbb168c6845fb3376c5" dependencies = [ "glob", "serde", @@ -3545,9 +3419,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-xid" @@ -3648,9 +3522,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -3659,25 +3533,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.107", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -3688,9 +3548,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3698,22 +3558,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.107", - "wasm-bindgen-backend", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -3733,9 +3593,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -3757,23 +3617,23 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" dependencies = [ - "webpki-root-certs 1.0.3", + "webpki-root-certs 1.0.4", ] [[package]] name = "webpki-root-certs" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d651ec480de84b762e7be71e6efa7461699c19d9e2c272c8d93455f567786e" +checksum = "ee3e3b5f5e80bc89f30ce8d0343bf4e5f12341c51f3e26cbeecbc7c85443e85b" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] @@ -3914,7 +3774,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -3925,7 +3785,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -4353,9 +4213,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "ws_stream_wasm" @@ -4378,9 +4238,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.27" +version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" [[package]] name = "xmltree" @@ -4402,11 +4262,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -4414,13 +4273,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", "synstructure", ] @@ -4447,7 +4306,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] @@ -4467,7 +4326,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", "synstructure", ] @@ -4488,14 +4347,14 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -4504,9 +4363,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -4515,11 +4374,11 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index b26b7d8..604542e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ tokio = { workspace = true, features = ["sync", "macros"] } # for PollSender (which for some reason is not available in the main tokio api) tokio-util = { version = "0.7.14", default-features = false } # errors -thiserror = "2.0.12" +n0-error = { workspace = true } # used in the endpoint handler code when using rpc tracing = { workspace = true, optional = true } @@ -37,8 +37,6 @@ smallvec = { version = "1.14.0", features = ["write"], optional = true } rustls = { version = "0.23.5", default-features = false, features = ["std"], optional = true } # used in the test utils to generate quinn endpoints rcgen = { version = "0.14.5", optional = true } -# used in the test utils to generate quinn endpoints -anyhow = { workspace = true, optional = true } # used in the benches futures-buffered ={ version = "0.2.9", optional = true } # for AbortOnDropHandle @@ -61,12 +59,14 @@ thousands = "0.2.0" # macro tests trybuild = "1.0.104" testresult = "0.4.1" +# used in examples +anyhow = { workspace = true } [features] # enable the remote transport -rpc = ["dep:quinn", "dep:postcard", "dep:anyhow", "dep:smallvec", "dep:tracing", "tokio/io-util"] +rpc = ["dep:quinn", "dep:postcard", "dep:smallvec", "dep:tracing", "tokio/io-util"] # add test utilities -quinn_endpoint_setup = ["rpc", "dep:rustls", "dep:rcgen", "dep:anyhow", "dep:futures-buffered", "quinn/rustls-ring"] +quinn_endpoint_setup = ["rpc", "dep:rustls", "dep:rcgen", "dep:futures-buffered", "quinn/rustls-ring"] # pick up parent span when creating channel messages spans = ["dep:tracing"] stream = ["dep:futures-util"] @@ -101,14 +101,15 @@ rustdoc-args = ["--cfg", "quicrpc_docsrs"] unexpected_cfgs = { level = "warn", check-cfg = ["cfg(quicrpc_docsrs)"] } [workspace.dependencies] -anyhow = { version = "1.0.98" } +anyhow = { version = "1" } tokio = { version = "1.44", default-features = false } postcard = { version = "1.1.1", default-features = false } serde = { version = "1", default-features = false, features = ["derive"] } tracing = { version = "0.1.41", default-features = false } n0-future = { version = "0.3", default-features = false } +n0-error = { version = "0.1.0" } tracing-subscriber = { version = "0.3.20" } -iroh = { version = "0.94" } -iroh-base = { version = "0.94" } +iroh = { version = "0.95" } +iroh-base = { version = "0.95" } quinn = { package = "iroh-quinn", version = "0.14.0", default-features = false } futures-util = { version = "0.3", features = ["sink"] } diff --git a/irpc-iroh/Cargo.toml b/irpc-iroh/Cargo.toml index 616ce44..9bf886d 100644 --- a/irpc-iroh/Cargo.toml +++ b/irpc-iroh/Cargo.toml @@ -13,12 +13,12 @@ description = "Iroh transport for irpc" crate-type = ["cdylib", "rlib"] [dependencies] -anyhow = { workspace = true } iroh = { workspace = true } tokio = { workspace = true, features = ["sync"] } tracing = { workspace = true } serde = { workspace = true } postcard = { workspace = true, features = ["alloc", "use-std"] } +n0-error = { workspace = true } n0-future = { workspace = true } irpc = { version = "0.10.0", path = ".." } iroh-base.workspace = true @@ -34,3 +34,4 @@ clap = { version = "4.5.41", features = ["derive"] } futures-util.workspace = true hex = "0.4.3" rand = "0.9.2" +anyhow = { workspace = true } diff --git a/irpc-iroh/examples/0rtt.rs b/irpc-iroh/examples/0rtt.rs index 985a885..1bfeef1 100644 --- a/irpc-iroh/examples/0rtt.rs +++ b/irpc-iroh/examples/0rtt.rs @@ -187,11 +187,11 @@ mod cli { mod ping { use anyhow::{Context, Result}; - use futures_util::FutureExt; use iroh::Endpoint; use irpc::{channel::oneshot, rpc::RemoteService, rpc_requests, Client, WithChannels}; - use irpc_iroh::{Iroh0RttProtocol, IrohProtocol, IrohRemoteConnection}; - use n0_future::future; + use irpc_iroh::{ + Iroh0RttProtocol, IrohProtocol, IrohRemoteConnection, IrohZrttRemoteConnection, + }; use serde::{Deserialize, Serialize}; use tracing::info; @@ -205,7 +205,6 @@ mod ping { pub struct EchoApi { inner: Client, - zero_rtt_accepted: futures_util::future::Shared>, } impl EchoApi { @@ -216,9 +215,7 @@ mod ping { } pub async fn echo_0rtt(&self, data: Vec) -> irpc::Result> { - self.inner - .rpc_0rtt(Echo { data }, self.zero_rtt_accepted.clone()) - .await + self.inner.rpc_0rtt(Echo { data }).await } pub fn expose_0rtt(self) -> Result> { @@ -245,10 +242,8 @@ mod ping { .connect(addr, Self::ALPN) .await .context("failed to connect to remote service")?; - let fut: future::Boxed = Box::pin(async { true }); Ok(EchoApi { inner: Client::boxed(IrohRemoteConnection::new(conn)), - zero_rtt_accepted: fut.shared(), }) } @@ -261,21 +256,17 @@ mod ping { .await .context("failed to connect to remote service")?; match connecting.into_0rtt() { - Ok((conn, zero_rtt_accepted)) => { + Ok(conn) => { info!("0-RTT possible from our side"); - let fut: future::Boxed = Box::pin(zero_rtt_accepted); Ok(EchoApi { - inner: Client::boxed(IrohRemoteConnection::new(conn)), - zero_rtt_accepted: fut.shared(), + inner: Client::boxed(IrohZrttRemoteConnection::new(conn)), }) } Err(connecting) => { info!("0-RTT not possible from our side"); - let fut: future::Boxed = Box::pin(async { true }); let conn = connecting.await?; Ok(EchoApi { inner: Client::boxed(IrohRemoteConnection::new(conn)), - zero_rtt_accepted: fut.shared(), }) } } @@ -295,10 +286,8 @@ mod ping { let (tx, rx) = tokio::sync::mpsc::channel(1); let actor = Self { recv: rx }; n0_future::task::spawn(actor.run()); - let fut: future::Boxed = Box::pin(async { true }); EchoApi { inner: Client::local(tx), - zero_rtt_accepted: fut.shared(), } } diff --git a/irpc-iroh/src/lib.rs b/irpc-iroh/src/lib.rs index 6971a1b..a7b695f 100644 --- a/irpc-iroh/src/lib.rs +++ b/irpc-iroh/src/lib.rs @@ -1,11 +1,18 @@ use std::{ - fmt, io, + fmt, + future::Future, + io, sync::{atomic::AtomicU64, Arc}, }; use iroh::{ - endpoint::{Connecting, Connection, ConnectionError, RecvStream, SendStream}, + endpoint::{ + Accepting, ConnectingError, Connection, ConnectionError, IncomingZeroRttConnection, + OutgoingZeroRttConnection, RecvStream, RemoteEndpointIdError, SendStream, VarInt, + ZeroRttStatus, + }, protocol::{AcceptError, ProtocolHandler}, + EndpointId, }; use irpc::{ channel::oneshot, @@ -16,6 +23,7 @@ use irpc::{ util::AsyncReadVarintExt, LocalSender, RequestError, }; +use n0_error::{e, Result}; use n0_future::{future::Boxed as BoxFuture, TryFutureExt}; use serde::de::DeserializeOwned; use tracing::{debug, error_span, trace, trace_span, warn, Instrument}; @@ -60,6 +68,47 @@ impl irpc::rpc::RemoteConnection for IrohRemoteConnection { Ok((send, recv)) }) } + + fn zero_rtt_accepted(&self) -> BoxFuture { + Box::pin(async { true }) + } +} + +#[derive(Debug, Clone)] +pub struct IrohZrttRemoteConnection(OutgoingZeroRttConnection); + +impl IrohZrttRemoteConnection { + pub fn new(connection: OutgoingZeroRttConnection) -> Self { + Self(connection) + } +} + +impl irpc::rpc::RemoteConnection for IrohZrttRemoteConnection { + fn clone_boxed(&self) -> Box { + Box::new(self.clone()) + } + + fn open_bi( + &self, + ) -> n0_future::future::Boxed> + { + let conn = self.0.clone(); + Box::pin(async move { + let (send, recv) = conn.open_bi().await?; + Ok((send, recv)) + }) + } + + fn zero_rtt_accepted(&self) -> BoxFuture { + let conn = self.0.clone(); + Box::pin(async move { + match conn.handshake_completed().await { + Err(_) => false, + Ok(ZeroRttStatus::Accepted(_)) => true, + Ok(ZeroRttStatus::Rejected(_)) => false, + } + }) + } } /// A connection to a remote service. @@ -106,18 +155,19 @@ impl RemoteConnection for IrohLazyRemoteConnection { // try with a new connection, just once *guard = None; connect_and_open_bi(&this.endpoint, &this.addr, &this.alpn, guard) - .await - .map_err(RequestError::Other)? + .await? } } } - None => connect_and_open_bi(&this.endpoint, &this.addr, &this.alpn, guard) - .await - .map_err(RequestError::Other)?, + None => connect_and_open_bi(&this.endpoint, &this.addr, &this.alpn, guard).await?, }; Ok(pair) }) } + + fn zero_rtt_accepted(&self) -> BoxFuture { + Box::pin(async { true }) + } } async fn connect_and_open_bi( @@ -125,8 +175,11 @@ async fn connect_and_open_bi( addr: &iroh::EndpointAddr, alpn: &[u8], mut guard: tokio::sync::MutexGuard<'_, Option>, -) -> anyhow::Result<(SendStream, RecvStream)> { - let conn = endpoint.connect(addr.clone(), alpn).await?; +) -> Result<(SendStream, RecvStream), RequestError> { + let conn = endpoint + .connect(addr.clone(), alpn) + .await + .map_err(|err| e!(RequestError::Other, err.into()))?; let (send, recv) = conn.open_bi().await?; *guard = Some(conn); Ok((send, recv)) @@ -165,17 +218,14 @@ impl IrohProtocol { } impl ProtocolHandler for IrohProtocol { - fn accept( - &self, - connection: Connection, - ) -> impl std::future::Future> + Send { + async fn accept(&self, connection: Connection) -> Result<(), AcceptError> { let handler = self.handler.clone(); let request_id = self .request_id .fetch_add(1, std::sync::atomic::Ordering::AcqRel); - let fut = handle_connection(connection, handler).map_err(AcceptError::from_err); + let fut = handle_connection(&connection, handler).map_err(AcceptError::from_err); let span = trace_span!("rpc", id = request_id); - Box::pin(fut.instrument(span)) + fut.instrument(span).await } } @@ -214,30 +264,32 @@ impl Iroh0RttProtocol { } impl ProtocolHandler for Iroh0RttProtocol { - async fn on_connecting(&self, connecting: Connecting) -> Result { - let (conn, _zero_rtt_accepted) = connecting - .into_0rtt() - .expect("accept into 0.5 RTT always succeeds"); - Ok(conn) - } - - fn accept( - &self, - connection: Connection, - ) -> impl std::future::Future> + Send { + async fn on_accepting(&self, accepting: Accepting) -> Result { + let zrtt_conn = accepting.into_0rtt(); let handler = self.handler.clone(); let request_id = self .request_id .fetch_add(1, std::sync::atomic::Ordering::AcqRel); - let fut = handle_connection(connection, handler).map_err(AcceptError::from_err); - let span = trace_span!("rpc", id = request_id); - Box::pin(fut.instrument(span)) + handle_connection(&zrtt_conn, handler) + .map_err(AcceptError::from_err) + .instrument(trace_span!("rpc", id = request_id)) + .await?; + let conn = zrtt_conn + .handshake_completed() + .await + .map_err(|err| AcceptError::from(ConnectingError::from(err)))?; + Ok(conn) + } + + async fn accept(&self, _connection: Connection) -> Result<(), AcceptError> { + // Noop, handled in [`Self::on_accepting`] + Ok(()) } } /// Handles a single iroh connection with the provided `handler`. pub async fn handle_connection( - connection: Connection, + connection: &impl IncomingRemoteConnection, handler: Handler, ) -> io::Result<()> { if let Ok(remote) = connection.remote_id() { @@ -245,21 +297,66 @@ pub async fn handle_connection( } debug!("connection accepted"); loop { - let Some((msg, rx, tx)) = read_request_raw(&connection).await? else { + let Some((msg, rx, tx)) = read_request_raw(connection).await? else { return Ok(()); }; handler(msg, rx, tx).await?; } } +/// Reads a single request from a connection, and a message with channels. pub async fn read_request( - connection: &Connection, + connection: &impl IncomingRemoteConnection, ) -> std::io::Result> { Ok(read_request_raw::(connection) .await? .map(|(msg, rx, tx)| S::with_remote_channels(msg, rx, tx))) } +/// Abstracts over [`Connection`] and [`IncomingZeroRttConnection`]. +/// +/// You don't need to implement this trait yourself. It is used by [`read_request`] and +/// [`handle_connection`] to work with both fully authenticated connections and with +/// 0-RTT connections. +pub trait IncomingRemoteConnection { + /// Accepts a single bidirectional stream. + fn accept_bi( + &self, + ) -> impl Future> + Send; + /// Close the connection. + fn close(&self, error_code: VarInt, reason: &[u8]); + /// Returns the remote's endpoint id. + /// + /// This may only fail for 0-RTT connections. + fn remote_id(&self) -> Result; +} + +impl IncomingRemoteConnection for IncomingZeroRttConnection { + async fn accept_bi(&self) -> Result<(SendStream, RecvStream), ConnectionError> { + self.accept_bi().await + } + + fn close(&self, error_code: VarInt, reason: &[u8]) { + self.close(error_code, reason) + } + fn remote_id(&self) -> Result { + self.remote_id() + } +} + +impl IncomingRemoteConnection for Connection { + async fn accept_bi(&self) -> Result<(SendStream, RecvStream), ConnectionError> { + self.accept_bi().await + } + + fn close(&self, error_code: VarInt, reason: &[u8]) { + self.close(error_code, reason) + } + fn remote_id(&self) -> Result { + Ok(self.remote_id()) + } +} + /// Reads a single request from the connection. /// /// This accepts a bi-directional stream from the connection and reads and parses the request. @@ -268,7 +365,7 @@ pub async fn read_request( /// Returns None if the remote closed the connection with error code `0`. /// Returns an error for all other failure cases. pub async fn read_request_raw( - connection: &Connection, + connection: &impl IncomingRemoteConnection, ) -> std::io::Result> { let (send, mut recv) = match connection.accept_bi().await { Ok((s, r)) => (s, r), @@ -290,7 +387,7 @@ pub async fn read_request_raw( ERROR_CODE_MAX_MESSAGE_SIZE_EXCEEDED.into(), b"request exceeded max message size", ); - return Err(oneshot::RecvError::MaxMessageSizeExceeded.into()); + return Err(e!(oneshot::RecvError::MaxMessageSizeExceeded).into()); } let mut buf = vec![0; size as usize]; recv.read_exact(&mut buf) @@ -323,7 +420,7 @@ pub async fn listen(endpoint: iroh::Endpoint, han let handler = handler.clone(); let fut = async move { match incoming.await { - Ok(connection) => match handle_connection(connection, handler).await { + Ok(connection) => match handle_connection(&connection, handler).await { Err(err) => warn!("connection closed with error: {err:?}"), Ok(()) => debug!("connection closed"), }, diff --git a/src/lib.rs b/src/lib.rs index 1da5f2c..7494c3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,7 +80,7 @@ //! use serde::{Deserialize, Serialize}; //! //! #[tokio::main] -//! async fn main() -> anyhow::Result<()> { +//! async fn main() -> n0_error::Result<()> { //! let client = spawn_server(); //! let res = client.rpc(Multiply(3, 7)).await?; //! assert_eq!(res, 21); @@ -266,7 +266,7 @@ use std::{fmt::Debug, future::Future, io, marker::PhantomData, ops::Deref, resul /// Set { key: String, value: String }, /// } /// -/// async fn client_usage(client: Client) -> anyhow::Result<()> { +/// async fn client_usage(client: Client) -> n0_error::Result<()> { /// client /// .rpc(SetRequest { /// key: "foo".to_string(), @@ -295,6 +295,9 @@ use std::{fmt::Debug, future::Future, io, marker::PhantomData, ops::Deref, resul #[cfg(feature = "derive")] #[cfg_attr(quicrpc_docsrs, doc(cfg(feature = "derive")))] pub use irpc_derive::rpc_requests; +use n0_error::stack_error; +#[cfg(feature = "rpc")] +use n0_error::AnyError; use serde::{de::DeserializeOwned, Serialize}; use self::{ @@ -365,10 +368,13 @@ pub trait Channels: Send + 'static { pub mod channel { use std::io; + use n0_error::stack_error; + /// Oneshot channel, similar to tokio's oneshot channel pub mod oneshot { use std::{fmt::Debug, future::Future, io, pin::Pin, task}; + use n0_error::{e, stack_error}; use n0_future::future::Boxed as BoxFuture; use super::SendError; @@ -379,29 +385,32 @@ pub mod channel { /// /// For rpc communication, there can be any number of errors, so this is a /// generic io error. - #[derive(Debug, thiserror::Error)] + #[stack_error(derive, add_meta, from_sources)] pub enum RecvError { /// The sender has been closed. This is the only error that can occur /// for local communication. - #[error("sender closed")] + #[error("Sender closed")] SenderClosed, /// The message exceeded the maximum allowed message size (see [`MAX_MESSAGE_SIZE`]). /// /// [`MAX_MESSAGE_SIZE`]: crate::rpc::MAX_MESSAGE_SIZE - #[error("maximum message size exceeded")] + #[error("Maximum message size exceeded")] MaxMessageSizeExceeded, /// An io error occurred. This can occur for remote communication, /// due to a network error or deserialization error. - #[error("io error: {0}")] - Io(#[from] io::Error), + #[error("Io error")] + Io { + #[error(std_err)] + source: io::Error, + }, } impl From for io::Error { fn from(e: RecvError) -> Self { match e { - RecvError::Io(e) => e, - RecvError::SenderClosed => io::Error::new(io::ErrorKind::BrokenPipe, e), - RecvError::MaxMessageSizeExceeded => { + RecvError::Io { source, .. } => source, + RecvError::SenderClosed { .. } => io::Error::new(io::ErrorKind::BrokenPipe, e), + RecvError::MaxMessageSizeExceeded { .. } => { io::Error::new(io::ErrorKind::InvalidData, e) } } @@ -491,7 +500,7 @@ pub mod channel { /// Local senders will never yield, but can fail if the receiver has been closed. pub async fn send(self, value: T) -> std::result::Result<(), SendError> { match self { - Sender::Tokio(tx) => tx.send(value).map_err(|_| SendError::ReceiverClosed), + Sender::Tokio(tx) => tx.send(value).map_err(|_| e!(SendError::ReceiverClosed)), Sender::Boxed(f) => f(value).await, } } @@ -564,7 +573,9 @@ pub mod channel { fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> task::Poll { match self.get_mut() { - Self::Tokio(rx) => Pin::new(rx).poll(cx).map_err(|_| RecvError::SenderClosed), + Self::Tokio(rx) => Pin::new(rx) + .poll(cx) + .map_err(|_| e!(RecvError::SenderClosed)), Self::Boxed(rx) => Pin::new(rx).poll(cx), } } @@ -618,6 +629,8 @@ pub mod channel { pub mod mpsc { use std::{fmt::Debug, future::Future, io, marker::PhantomData, pin::Pin, sync::Arc}; + use n0_error::{e, stack_error}; + use super::SendError; /// Error when receiving a oneshot or mpsc message. For local communication, @@ -625,24 +638,27 @@ pub mod channel { /// /// For rpc communication, there can be any number of errors, so this is a /// generic io error. - #[derive(Debug, thiserror::Error)] + #[stack_error(derive, add_meta, from_sources)] pub enum RecvError { /// The message exceeded the maximum allowed message size (see [`MAX_MESSAGE_SIZE`]). /// /// [`MAX_MESSAGE_SIZE`]: crate::rpc::MAX_MESSAGE_SIZE - #[error("maximum message size exceeded")] + #[error("Maximum message size exceeded")] MaxMessageSizeExceeded, /// An io error occurred. This can occur for remote communication, /// due to a network error or deserialization error. - #[error("io error: {0}")] - Io(#[from] io::Error), + #[error("Io error")] + Io { + #[error(std_err)] + source: io::Error, + }, } impl From for io::Error { fn from(e: RecvError) -> Self { match e { - RecvError::Io(e) => e, - RecvError::MaxMessageSizeExceeded => { + RecvError::Io { source, .. } => source, + RecvError::MaxMessageSizeExceeded { .. } => { io::Error::new(io::ErrorKind::InvalidData, e) } } @@ -832,9 +848,10 @@ pub mod channel { /// future until completion if you want to reuse the sender or any clone afterwards. pub async fn send(&self, value: T) -> std::result::Result<(), SendError> { match self { - Sender::Tokio(tx) => { - tx.send(value).await.map_err(|_| SendError::ReceiverClosed) - } + Sender::Tokio(tx) => tx + .send(value) + .await + .map_err(|_| e!(SendError::ReceiverClosed)), Sender::Boxed(sink) => sink.send(value).await, } } @@ -865,7 +882,7 @@ pub mod channel { Sender::Tokio(tx) => match tx.try_send(value) { Ok(()) => Ok(true), Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => { - Err(SendError::ReceiverClosed) + Err(e!(SendError::ReceiverClosed)) } Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => Ok(false), }, @@ -1100,29 +1117,34 @@ pub mod channel { /// /// For rpc communication, there can be any number of errors, so this is a /// generic io error. - #[derive(Debug, thiserror::Error)] + #[stack_error(derive, add_meta, from_sources)] pub enum SendError { /// The receiver has been closed. This is the only error that can occur /// for local communication. - #[error("receiver closed")] + #[error("Receiver closed")] ReceiverClosed, /// The message exceeded the maximum allowed message size (see [`MAX_MESSAGE_SIZE`]). /// /// [`MAX_MESSAGE_SIZE`]: crate::rpc::MAX_MESSAGE_SIZE - #[error("maximum message size exceeded")] + #[error("Maximum message size exceeded")] MaxMessageSizeExceeded, /// The underlying io error. This can occur for remote communication, /// due to a network error or serialization error. - #[error("io error: {0}")] - Io(#[from] io::Error), + #[error("Io error")] + Io { + #[error(std_err)] + source: io::Error, + }, } impl From for io::Error { fn from(e: SendError) -> Self { match e { - SendError::ReceiverClosed => io::Error::new(io::ErrorKind::BrokenPipe, e), - SendError::MaxMessageSizeExceeded => io::Error::new(io::ErrorKind::InvalidData, e), - SendError::Io(e) => e, + SendError::ReceiverClosed { .. } => io::Error::new(io::ErrorKind::BrokenPipe, e), + SendError::MaxMessageSizeExceeded { .. } => { + io::Error::new(io::ErrorKind::InvalidData, e) + } + SendError::Io { source, .. } => source, } } } @@ -1519,11 +1541,7 @@ impl Client { /// Compared to [Self::notify], this variant takes a future that returns true /// if 0rtt has been accepted. If not, the data is sent again via the same /// remote channel. For local requests, the future is ignored. - pub fn notify_0rtt( - &self, - msg: Req, - zero_rtt_accepted: impl Future + Send + 'static, - ) -> impl Future> + Send + 'static + pub fn notify_0rtt(&self, msg: Req) -> impl Future> + Send + 'static where S: From, S::Message: From>, @@ -1534,7 +1552,6 @@ impl Client { match this.request().await? { Request::Local(request) => { request.send((msg,)).await?; - zero_rtt_accepted.await; } #[cfg(not(feature = "rpc"))] Request::Remote(_request) => unreachable!(), @@ -1543,7 +1560,7 @@ impl Client { // see https://www.iroh.computer/blog/0rtt-api#connect-side let buf = rpc::prepare_write::(msg)?; let (_tx, _rx) = request.write_raw(&buf).await?; - if !zero_rtt_accepted.await { + if !this.0.zero_rtt_accepted().await { // 0rtt was not accepted, the data is lost, send it again! let Request::Remote(request) = this.request().await? else { unreachable!() @@ -1561,11 +1578,7 @@ impl Client { /// Compared to [Self::rpc], this variant takes a future that returns true /// if 0rtt has been accepted. If not, the data is sent again via the same /// remote channel. For local requests, the future is ignored. - pub fn rpc_0rtt( - &self, - msg: Req, - zero_rtt_accepted: impl Future + Send + 'static, - ) -> impl Future> + Send + 'static + pub fn rpc_0rtt(&self, msg: Req) -> impl Future> + Send + 'static where S: From, S::Message: From>, @@ -1578,7 +1591,6 @@ impl Client { Request::Local(request) => { let (tx, rx) = oneshot::channel(); request.send((msg, tx)).await?; - zero_rtt_accepted.await; rx } #[cfg(not(feature = "rpc"))] @@ -1588,7 +1600,7 @@ impl Client { // see https://www.iroh.computer/blog/0rtt-api#connect-side let buf = rpc::prepare_write::(msg)?; let (_tx, rx) = request.write_raw(&buf).await?; - if zero_rtt_accepted.await { + if this.0.zero_rtt_accepted().await { rx } else { // 0rtt was not accepted, the data is lost, send it again! @@ -1615,7 +1627,6 @@ impl Client { &self, msg: Req, local_response_cap: usize, - zero_rtt_accepted: impl Future + Send + 'static, ) -> impl Future>> + Send + 'static where S: From, @@ -1629,7 +1640,6 @@ impl Client { Request::Local(request) => { let (tx, rx) = mpsc::channel(local_response_cap); request.send((msg, tx)).await?; - zero_rtt_accepted.await; rx } #[cfg(not(feature = "rpc"))] @@ -1639,7 +1649,7 @@ impl Client { // see https://www.iroh.computer/blog/0rtt-api#connect-side let buf = rpc::prepare_write::(msg)?; let (_tx, rx) = request.write_raw(&buf).await?; - if zero_rtt_accepted.await { + if this.0.zero_rtt_accepted().await { rx } else { // 0rtt was not accepted, the data is lost, send it again! @@ -1681,25 +1691,44 @@ impl Clone for ClientInner { } } +impl ClientInner { + #[allow(dead_code)] + async fn zero_rtt_accepted(&self) -> bool { + match self { + ClientInner::Local(_sender) => true, + #[cfg(feature = "rpc")] + ClientInner::Remote(remote_connection) => remote_connection.zero_rtt_accepted().await, + #[cfg(not(feature = "rpc"))] + Self::Remote(_) => unreachable!(), + } + } +} + /// Error when opening a request. When cross-process rpc is disabled, this is /// an empty enum since local requests can not fail. -#[derive(Debug, thiserror::Error)] +#[stack_error(derive, add_meta, from_sources)] pub enum RequestError { /// Error in quinn during connect #[cfg(feature = "rpc")] #[cfg_attr(quicrpc_docsrs, doc(cfg(feature = "rpc")))] - #[error("error establishing connection: {0}")] - Connect(#[from] quinn::ConnectError), + #[error("Error establishing connection")] + Connect { + #[error(std_err)] + source: quinn::ConnectError, + }, /// Error in quinn when the connection already exists, when opening a stream pair #[cfg(feature = "rpc")] #[cfg_attr(quicrpc_docsrs, doc(cfg(feature = "rpc")))] - #[error("error opening stream: {0}")] - Connection(#[from] quinn::ConnectionError), + #[error("Error opening stream")] + Connection { + #[error(std_err)] + source: quinn::ConnectionError, + }, /// Generic error for non-quinn transports #[cfg(feature = "rpc")] #[cfg_attr(quicrpc_docsrs, doc(cfg(feature = "rpc")))] - #[error("error opening stream: {0}")] - Other(#[from] anyhow::Error), + #[error("Error opening stream")] + Other { source: AnyError }, #[cfg(not(feature = "rpc"))] #[error("(Without the rpc feature, requests cannot fail")] @@ -1707,19 +1736,19 @@ pub enum RequestError { } /// Error type that subsumes all possible errors in this crate, for convenience. -#[derive(Debug, thiserror::Error)] +#[stack_error(derive, add_meta, from_sources)] pub enum Error { - #[error("request error: {0}")] - Request(#[from] RequestError), - #[error("send error: {0}")] - Send(#[from] channel::SendError), - #[error("mpsc recv error: {0}")] - MpscRecv(#[from] channel::mpsc::RecvError), - #[error("oneshot recv error: {0}")] - OneshotRecv(#[from] channel::oneshot::RecvError), + #[error("Request error")] + Request { source: RequestError }, + #[error("Send error")] + Send { source: channel::SendError }, + #[error("Mpsc recv error")] + MpscRecv { source: channel::mpsc::RecvError }, + #[error("Oneshot recv error")] + OneshotRecv { source: channel::oneshot::RecvError }, #[cfg(feature = "rpc")] - #[error("recv error: {0}")] - Write(#[from] rpc::WriteError), + #[error("Recv error")] + Write { source: rpc::WriteError }, } /// Type alias for a result with an irpc error type. @@ -1728,12 +1757,12 @@ pub type Result = std::result::Result; impl From for io::Error { fn from(e: Error) -> Self { match e { - Error::Request(e) => e.into(), - Error::Send(e) => e.into(), - Error::MpscRecv(e) => e.into(), - Error::OneshotRecv(e) => e.into(), + Error::Request { source, .. } => source.into(), + Error::Send { source, .. } => source.into(), + Error::MpscRecv { source, .. } => source.into(), + Error::OneshotRecv { source, .. } => source.into(), #[cfg(feature = "rpc")] - Error::Write(e) => e.into(), + Error::Write { source, .. } => source.into(), } } } @@ -1742,13 +1771,13 @@ impl From for io::Error { fn from(e: RequestError) -> Self { match e { #[cfg(feature = "rpc")] - RequestError::Connect(e) => io::Error::other(e), + RequestError::Connect { source, .. } => io::Error::other(source), #[cfg(feature = "rpc")] - RequestError::Connection(e) => e.into(), + RequestError::Connection { source, .. } => source.into(), #[cfg(feature = "rpc")] - RequestError::Other(e) => io::Error::other(e), + RequestError::Other { source, .. } => io::Error::other(source), #[cfg(not(feature = "rpc"))] - RequestError::Unreachable => unreachable!(), + RequestError::Unreachable { .. } => unreachable!(), } } } @@ -1793,6 +1822,7 @@ pub mod rpc { fmt::Debug, future::Future, io, marker::PhantomData, ops::DerefMut, pin::Pin, sync::Arc, }; + use n0_error::{e, stack_error}; use n0_future::{future::Boxed as BoxFuture, task::JoinSet}; /// This is used by irpc-derive to refer to quinn types (SendStream and RecvStream) /// to make generated code work for users without having to depend on quinn directly @@ -1825,38 +1855,46 @@ pub mod rpc { /// Error that can occur when writing the initial message when doing a /// cross-process RPC. - #[derive(Debug, thiserror::Error)] + #[stack_error(derive, add_meta, from_sources)] pub enum WriteError { /// Error writing to the stream with quinn - #[error("error writing to stream: {0}")] - Quinn(#[from] quinn::WriteError), + #[error("Error writing to stream")] + Quinn { + #[error(std_err)] + source: quinn::WriteError, + }, /// The message exceeded the maximum allowed message size (see [`MAX_MESSAGE_SIZE`]). - #[error("maximum message size exceeded")] + #[error("Maximum message size exceeded")] MaxMessageSizeExceeded, /// Generic IO error, e.g. when serializing the message or when using /// other transports. - #[error("error serializing: {0}")] - Io(#[from] io::Error), + #[error("Error serializing")] + Io { + #[error(std_err)] + source: io::Error, + }, } impl From for WriteError { fn from(value: postcard::Error) -> Self { - Self::Io(io::Error::new(io::ErrorKind::InvalidData, value)) + e!(Self::Io, io::Error::new(io::ErrorKind::InvalidData, value)) } } impl From for SendError { fn from(value: postcard::Error) -> Self { - Self::Io(io::Error::new(io::ErrorKind::InvalidData, value)) + e!(Self::Io, io::Error::new(io::ErrorKind::InvalidData, value)) } } impl From for io::Error { fn from(e: WriteError) -> Self { match e { - WriteError::Io(e) => e, - WriteError::MaxMessageSizeExceeded => io::Error::new(io::ErrorKind::InvalidData, e), - WriteError::Quinn(e) => e.into(), + WriteError::Io { source, .. } => source, + WriteError::MaxMessageSizeExceeded { .. } => { + io::Error::new(io::ErrorKind::InvalidData, e) + } + WriteError::Quinn { source, .. } => source.into(), } } } @@ -1867,9 +1905,9 @@ pub mod rpc { quinn::WriteError::Stopped(code) if code == ERROR_CODE_MAX_MESSAGE_SIZE_EXCEEDED.into() => { - SendError::MaxMessageSizeExceeded + e!(SendError::MaxMessageSizeExceeded) } - _ => SendError::Io(io::Error::from(err)), + _ => e!(SendError::Io, io::Error::from(err)), } } } @@ -1892,6 +1930,11 @@ pub mod rpc { fn open_bi( &self, ) -> BoxFuture>; + + /// Returns whether 0-RTT data was accepted by the server. + /// + /// For connections that were fully authenticated before allowing to send any data, this should return `true`. + fn zero_rtt_accepted(&self) -> BoxFuture; } /// A connection to a remote service. @@ -1923,6 +1966,10 @@ pub mod rpc { Ok(pair) }) } + + fn zero_rtt_accepted(&self) -> BoxFuture { + Box::pin(async { true }) + } } impl QuinnLazyRemoteConnection { @@ -1964,6 +2011,10 @@ pub mod rpc { Ok(pair) }) } + + fn zero_rtt_accepted(&self) -> BoxFuture { + Box::pin(async { true }) + } } async fn connect_and_open_bi( @@ -1990,7 +2041,7 @@ pub mod rpc { ) -> std::result::Result, WriteError> { let msg = msg.into(); if postcard::experimental::serialized_size(&msg)? as u64 > MAX_MESSAGE_SIZE { - return Err(WriteError::MaxMessageSizeExceeded); + return Err(e!(WriteError::MaxMessageSizeExceeded)); } let mut buf = SmallVec::<[u8; 128]>::new(); buf.write_length_prefixed(&msg)?; @@ -2029,7 +2080,7 @@ pub mod rpc { ))?; if size > MAX_MESSAGE_SIZE { read.stop(ERROR_CODE_MAX_MESSAGE_SIZE_EXCEEDED.into()).ok(); - return Err(oneshot::RecvError::MaxMessageSizeExceeded); + return Err(e!(oneshot::RecvError::MaxMessageSizeExceeded)); } let rest = read .read_to_end(size as usize) @@ -2074,17 +2125,17 @@ pub mod rpc { Ok(size) => size, Err(e) => { writer.reset(ERROR_CODE_INVALID_POSTCARD.into()).ok(); - return Err(SendError::Io(io::Error::new( - io::ErrorKind::InvalidData, - e, - ))); + return Err(e!( + SendError::Io, + io::Error::new(io::ErrorKind::InvalidData, e,) + )); } }; if size as u64 > MAX_MESSAGE_SIZE { writer .reset(ERROR_CODE_MAX_MESSAGE_SIZE_EXCEEDED.into()) .ok(); - return Err(SendError::MaxMessageSizeExceeded); + return Err(e!(SendError::MaxMessageSizeExceeded)); } // write via a small buffer to avoid allocation for small values let mut buf = SmallVec::<[u8; 128]>::new(); @@ -2142,7 +2193,7 @@ pub mod rpc { self.recv .stop(ERROR_CODE_MAX_MESSAGE_SIZE_EXCEEDED.into()) .ok(); - return Err(mpsc::RecvError::MaxMessageSizeExceeded); + return Err(e!(mpsc::RecvError::MaxMessageSizeExceeded)); } let mut buf = vec![0; size as usize]; read.read_exact(&mut buf) @@ -2175,14 +2226,17 @@ pub mod rpc { Ok(size) => size, Err(e) => { self.send.reset(ERROR_CODE_INVALID_POSTCARD.into()).ok(); - return Err(SendError::Io(io::Error::new(io::ErrorKind::InvalidData, e))); + return Err(e!( + SendError::Io, + io::Error::new(io::ErrorKind::InvalidData, e) + )); } }; if size as u64 > MAX_MESSAGE_SIZE { self.send .reset(ERROR_CODE_MAX_MESSAGE_SIZE_EXCEEDED.into()) .ok(); - return Err(SendError::MaxMessageSizeExceeded); + return Err(e!(SendError::MaxMessageSizeExceeded)); } let value = value; self.buffer.clear(); @@ -2202,7 +2256,7 @@ pub mod rpc { ) -> Pin> + Send + Sync + '_>> { Box::pin(async { if postcard::experimental::serialized_size(&value)? as u64 > MAX_MESSAGE_SIZE { - return Err(SendError::MaxMessageSizeExceeded); + return Err(e!(SendError::MaxMessageSizeExceeded)); } // todo: move the non-async part out of the box. Will require a new return type. let value = value; @@ -2430,7 +2484,7 @@ pub mod rpc { ERROR_CODE_MAX_MESSAGE_SIZE_EXCEEDED.into(), b"request exceeded max message size", ); - return Err(mpsc::RecvError::MaxMessageSizeExceeded.into()); + return Err(e!(mpsc::RecvError::MaxMessageSizeExceeded).into()); } let mut buf = vec![0; size as usize]; recv.read_exact(&mut buf) diff --git a/src/util.rs b/src/util.rs index 558a24c..76803b1 100644 --- a/src/util.rs +++ b/src/util.rs @@ -7,7 +7,7 @@ mod quinn_setup_utils { use std::{sync::Arc, time::Duration}; - use anyhow::Result; + use n0_error::{Result, StdResultExt}; use quinn::{crypto::rustls::QuicClientConfig, ClientConfig, ServerConfig}; /// Create a quinn client config and trusts given certificates. @@ -19,7 +19,7 @@ mod quinn_setup_utils { let mut certs = rustls::RootCertStore::empty(); for cert in server_certs { let cert = rustls::pki_types::CertificateDer::from(cert.to_vec()); - certs.add(cert)?; + certs.add(cert).std_context("Error configuring certs")?; } let provider = rustls::crypto::ring::default_provider(); @@ -29,7 +29,8 @@ mod quinn_setup_utils { .with_root_certificates(certs) .with_no_client_auth(); let quic_client_config = - quinn::crypto::rustls::QuicClientConfig::try_from(crypto_client_config)?; + quinn::crypto::rustls::QuicClientConfig::try_from(crypto_client_config) + .std_context("Error creating QUIC client config")?; let mut transport_config = quinn::TransportConfig::default(); transport_config.keep_alive_interval(Some(Duration::from_secs(1))); @@ -41,14 +42,16 @@ mod quinn_setup_utils { /// Create a quinn server config with a self-signed certificate /// /// Returns the server config and the certificate in DER format - pub fn configure_server() -> anyhow::Result<(ServerConfig, Vec)> { - let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()])?; + pub fn configure_server() -> Result<(ServerConfig, Vec)> { + let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]) + .std_context("Error generating self-signed cert")?; let cert_der = cert.cert.der(); let priv_key = rustls::pki_types::PrivatePkcs8KeyDer::from(cert.signing_key.serialize_der()); let cert_chain = vec![cert_der.clone()]; - let mut server_config = ServerConfig::with_single_cert(cert_chain, priv_key.into())?; + let mut server_config = ServerConfig::with_single_cert(cert_chain, priv_key.into()) + .std_context("Error creating server config")?; Arc::get_mut(&mut server_config.transport) .unwrap() .max_concurrent_uni_streams(0_u8.into()); @@ -65,7 +68,8 @@ mod quinn_setup_utils { .dangerous() .with_custom_certificate_verifier(Arc::new(SkipServerVerification)) .with_no_client_auth(); - let client_cfg = QuicClientConfig::try_from(crypto)?; + let client_cfg = + QuicClientConfig::try_from(crypto).std_context("Error creating QUIC client config")?; let client_cfg = ClientConfig::new(Arc::new(client_cfg)); Ok(client_cfg) } diff --git a/tests/common.rs b/tests/common.rs index bdc3021..1e18203 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -3,6 +3,7 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use irpc::util::{make_client_endpoint, make_server_endpoint}; +use n0_error::stack_error; use quinn::Endpoint; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use testresult::TestResult; @@ -19,8 +20,8 @@ pub fn create_connected_endpoints() -> TestResult<(Endpoint, Endpoint, SocketAdd #[derive(Debug)] pub struct NoSer(pub u64); -#[derive(Debug, thiserror::Error)] -#[error("Cannot serialize odd number: {0}")] +#[stack_error(derive)] +#[error("Cannot serialize odd number")] pub struct OddNumberError(u64); impl Serialize for NoSer { diff --git a/tests/mpsc_channel.rs b/tests/mpsc_channel.rs index 4717fd1..6d1e83f 100644 --- a/tests/mpsc_channel.rs +++ b/tests/mpsc_channel.rs @@ -12,6 +12,7 @@ use irpc::{ }, util::AsyncWriteVarintExt, }; +use n0_error::e; use quinn::Endpoint; use testresult::TestResult; use tokio::time::timeout; @@ -44,7 +45,9 @@ async fn mpsc_sender_clone_closed_error() -> TestResult<()> { // this should fail with an io error, since the stream was stopped loop { match send3.send(vec![1, 2, 3]).await { - Err(SendError::Io(e)) if e.kind() == ErrorKind::BrokenPipe => break, + Err(SendError::Io { source, .. }) if source.kind() == ErrorKind::BrokenPipe => { + break + } _ => {} }; } @@ -52,7 +55,7 @@ async fn mpsc_sender_clone_closed_error() -> TestResult<()> { // send until we get an error because the remote side stopped the stream while send1.send(vec![1, 2, 3]).await.is_ok() {} match send1.send(vec![4, 5, 6]).await { - Err(SendError::Io(e)) if e.kind() == ErrorKind::BrokenPipe => {} + Err(SendError::Io { source, .. }) if source.kind() == ErrorKind::BrokenPipe => {} e => panic!("Expected SendError::Io with kind BrokenPipe, got {e:?}"), }; // check that closed signal was received by the second sender @@ -90,7 +93,9 @@ async fn mpsc_sender_clone_drop_error() -> TestResult<()> { // this should fail with an io error, since the stream was stopped loop { match send3.send(vec![1, 2, 3]).await { - Err(SendError::Io(e)) if e.kind() == ErrorKind::BrokenPipe => break, + Err(SendError::Io { source, .. }) if source.kind() == ErrorKind::BrokenPipe => { + break + } _ => {} }; } @@ -120,14 +125,14 @@ async fn vec_receiver(server: Endpoint) -> Result<(), RecvError> { .await .unwrap() .await - .map_err(|e| RecvError::Io(e.into()))?; + .map_err(|err| e!(RecvError::Io, err.into()))?; let (_, recv) = conn .accept_bi() .await - .map_err(|e| RecvError::Io(e.into()))?; + .map_err(|err| e!(RecvError::Io, err.into()))?; let mut recv = Receiver::>::from(recv); while recv.recv().await?.is_some() {} - Err(RecvError::Io(io::ErrorKind::UnexpectedEof.into())) + Err(e!(RecvError::Io, io::ErrorKind::UnexpectedEof.into())) } /// Checks that the max message size is enforced on the sender side and that errors are propagated to the receiver side. @@ -144,11 +149,13 @@ async fn mpsc_max_message_size_send() -> TestResult<()> { let Err(cause) = send.send(vec![0u8; 1024 * 1024 * 32]).await else { panic!("client should have failed due to max message size"); }; - assert!(matches!(cause, SendError::MaxMessageSizeExceeded)); + assert!(matches!(cause, SendError::MaxMessageSizeExceeded { .. })); let Err(cause) = server.await? else { panic!("server should have failed due to max message size"); }; - assert!(matches!(cause, mpsc::RecvError::Io(e) if e.kind() == ErrorKind::ConnectionReset)); + assert!( + matches!(cause, mpsc::RecvError::Io { source, .. } if source.kind() == ErrorKind::ConnectionReset) + ); Ok(()) } @@ -168,7 +175,10 @@ async fn mpsc_max_message_size_recv() -> TestResult<()> { let Err(cause) = server.await? else { panic!("server should have failed due to max message size"); }; - assert!(matches!(cause, mpsc::RecvError::MaxMessageSizeExceeded)); + assert!(matches!( + cause, + mpsc::RecvError::MaxMessageSizeExceeded { .. } + )); Ok(()) } @@ -178,14 +188,14 @@ async fn noser_receiver(server: Endpoint) -> Result<(), mpsc::RecvError> { .await .unwrap() .await - .map_err(|e| mpsc::RecvError::Io(e.into()))?; + .map_err(|err| e!(mpsc::RecvError::Io, err.into()))?; let (_, recv) = conn .accept_bi() .await - .map_err(|e| mpsc::RecvError::Io(e.into()))?; + .map_err(|err| e!(mpsc::RecvError::Io, err.into()))?; let mut recv = mpsc::Receiver::::from(recv); while recv.recv().await?.is_some() {} - Err(mpsc::RecvError::Io(io::ErrorKind::UnexpectedEof.into())) + Err(e!(mpsc::RecvError::Io, io::ErrorKind::UnexpectedEof.into())) } /// Checks that a serialization error is caught and propagated to the receiver. @@ -202,11 +212,15 @@ async fn mpsc_serialize_error_send() -> TestResult<()> { let Err(cause) = send.send(NoSer(1)).await else { panic!("client should have failed due to serialization error"); }; - assert!(matches!(cause, SendError::Io(e) if e.kind() == ErrorKind::InvalidData)); + assert!( + matches!(cause, SendError::Io { source, .. } if source.kind() == ErrorKind::InvalidData) + ); let Err(cause) = server.await? else { panic!("server should have failed due to serialization error"); }; - assert!(matches!(cause, mpsc::RecvError::Io(e) if e.kind() == ErrorKind::ConnectionReset)); + assert!( + matches!(cause, mpsc::RecvError::Io { source, .. } if source.kind() == ErrorKind::ConnectionReset) + ); Ok(()) } @@ -223,6 +237,8 @@ async fn mpsc_serialize_error_recv() -> TestResult<()> { let Err(cause) = server.await? else { panic!("server should have failed due to serialization error"); }; - assert!(matches!(cause, mpsc::RecvError::Io(e) if e.kind() == ErrorKind::InvalidData)); + assert!( + matches!(cause, mpsc::RecvError::Io { source, .. } if source.kind() == ErrorKind::InvalidData) + ); Ok(()) } diff --git a/tests/oneshot_channel.rs b/tests/oneshot_channel.rs index 72202e9..d63ad0c 100644 --- a/tests/oneshot_channel.rs +++ b/tests/oneshot_channel.rs @@ -9,6 +9,7 @@ use irpc::{ }, util::AsyncWriteVarintExt, }; +use n0_error::e; use quinn::Endpoint; use testresult::TestResult; @@ -21,14 +22,14 @@ async fn vec_receiver(server: Endpoint) -> Result<(), RecvError> { .await .unwrap() .await - .map_err(|e| RecvError::Io(e.into()))?; + .map_err(|err| e!(RecvError::Io, err.into()))?; let (_, recv) = conn .accept_bi() .await - .map_err(|e| RecvError::Io(e.into()))?; + .map_err(|err| e!(RecvError::Io, err.into()))?; let recv = oneshot::Receiver::>::from(recv); recv.await?; - Err(RecvError::Io(io::ErrorKind::UnexpectedEof.into())) + Err(e!(RecvError::Io, io::ErrorKind::UnexpectedEof.into())) } /// Checks that the max message size is enforced on the sender side and that errors are propagated to the receiver side. @@ -43,11 +44,13 @@ async fn oneshot_max_message_size_send() -> TestResult<()> { let Err(cause) = send.send(vec![0u8; 1024 * 1024 * 32]).await else { panic!("client should have failed due to max message size"); }; - assert!(matches!(cause, SendError::MaxMessageSizeExceeded)); + assert!(matches!(cause, SendError::MaxMessageSizeExceeded { .. })); let Err(cause) = server.await? else { panic!("server should have failed due to max message size"); }; - assert!(matches!(cause, RecvError::Io(e) if e.kind() == ErrorKind::ConnectionReset)); + assert!( + matches!(cause, RecvError::Io { source, .. } if source.kind() == ErrorKind::ConnectionReset) + ); Ok(()) } @@ -65,7 +68,7 @@ async fn oneshot_max_message_size_recv() -> TestResult<()> { let Err(cause) = server.await? else { panic!("server should have failed due to max message size"); }; - assert!(matches!(cause, RecvError::MaxMessageSizeExceeded)); + assert!(matches!(cause, RecvError::MaxMessageSizeExceeded { .. })); Ok(()) } @@ -75,14 +78,14 @@ async fn noser_receiver(server: Endpoint) -> Result<(), RecvError> { .await .unwrap() .await - .map_err(|e| RecvError::Io(e.into()))?; + .map_err(|err| e!(RecvError::Io, err.into()))?; let (_, recv) = conn .accept_bi() .await - .map_err(|e| RecvError::Io(e.into()))?; + .map_err(|err| e!(RecvError::Io, err.into()))?; let recv = oneshot::Receiver::::from(recv); recv.await?; - Err(RecvError::Io(io::ErrorKind::UnexpectedEof.into())) + Err(e!(RecvError::Io, io::ErrorKind::UnexpectedEof.into())) } /// Checks that trying to send a message that cannot be serialized results in an error on the sender side and a connection reset on the receiver side. @@ -97,12 +100,16 @@ async fn oneshot_serialize_error_send() -> TestResult<()> { let Err(cause) = send.send(NoSer(1)).await else { panic!("client should have failed due to serialization error"); }; - assert!(matches!(cause, SendError::Io(e) if e.kind() == ErrorKind::InvalidData)); + assert!( + matches!(cause, SendError::Io { source, .. } if source.kind() == ErrorKind::InvalidData) + ); let Err(cause) = server.await? else { panic!("server should have failed due to serialization error"); }; println!("Server error: {cause:?}"); - assert!(matches!(cause, RecvError::Io(e) if e.kind() == ErrorKind::ConnectionReset)); + assert!( + matches!(cause, RecvError::Io { source, .. } if source.kind() == ErrorKind::ConnectionReset) + ); Ok(()) } @@ -119,6 +126,8 @@ async fn oneshot_serialize_error_recv() -> TestResult<()> { panic!("server should have failed due to serialization error"); }; println!("Server error: {cause:?}"); - assert!(matches!(cause, RecvError::Io(e) if e.kind() == ErrorKind::InvalidData)); + assert!( + matches!(cause, RecvError::Io { source, .. } if source.kind() == ErrorKind::InvalidData) + ); Ok(()) }