diff --git a/.gitignore b/.gitignore index 2bc7d63..15e3f74 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target tmp/* +tmp2/* .sendme-* diff --git a/Cargo.lock b/Cargo.lock index 39c3b04..d74a6eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,18 +28,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy 0.7.35", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -122,9 +110,12 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +dependencies = [ + "backtrace", +] [[package]] name = "arboard" @@ -156,57 +147,6 @@ 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.69", - "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.98", - "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.98", -] - -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - [[package]] name = "async-compat" version = "0.2.4" @@ -242,6 +182,15 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -305,7 +254,9 @@ dependencies = [ "positioned-io", "range-collections", "self_cell", + "serde", "smallvec", + "tokio", ] [[package]] @@ -387,6 +338,12 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "102dbef1187b1893e6dfe05a774e79fd52265f49f214f6879c8ff49f52c8188b" +[[package]] +name = "btparse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387e80962b798815a2b5c4bcfdb6bf626fa922ffe9f74e373103b858738e9f31" + [[package]] name = "bumpalo" version = "3.17.0" @@ -429,6 +386,12 @@ dependencies = [ "shlex", ] +[[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" @@ -533,6 +496,17 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +[[package]] +name = "color-backtrace" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2123a5984bd52ca861c66f66a9ab9883b27115c607f801f86c1bc2a84eb69f0f" +dependencies = [ + "backtrace", + "btparse", + "termcolor", +] + [[package]] name = "colorchoice" version = "1.0.3" @@ -540,12 +514,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] -name = "concurrent-queue" -version = "2.5.0" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "crossbeam-utils", + "bytes", + "memchr", ] [[package]] @@ -593,6 +568,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -606,7 +591,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "core-graphics-types", "foreign-types", "libc", @@ -619,7 +604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "libc", ] @@ -686,18 +671,6 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" -[[package]] -name = "crypto-bigint" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -788,20 +761,6 @@ dependencies = [ "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 = "der_derive" version = "0.7.3" @@ -828,7 +787,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "derive_more-impl", + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl 2.0.1", ] [[package]] @@ -843,6 +811,18 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "unicode-xid", +] + [[package]] name = "diatomic-waker" version = "0.2.3" @@ -856,7 +836,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "const-oid", "crypto-common", "subtle", ] @@ -910,20 +889,6 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" -[[package]] -name = "ecdsa" -version = "0.16.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", - "spki", -] - [[package]] name = "ed25519" version = "2.2.3" @@ -950,25 +915,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "elliptic-curve" -version = "0.13.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "embedded-io" version = "0.4.0" @@ -1041,27 +987,6 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" -[[package]] -name = "event-listener" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" -dependencies = [ - "event-listener", - "pin-project-lite", -] - [[package]] name = "fallible-iterator" version = "0.3.0" @@ -1083,16 +1008,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "ff" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1109,18 +1024,6 @@ dependencies = [ "miniz_oxide", ] -[[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" @@ -1413,17 +1316,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "h2" version = "0.4.7" @@ -1444,12 +1336,12 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.14.5" +name = "hash32" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" dependencies = [ - "ahash", + "byteorder", ] [[package]] @@ -1465,11 +1357,25 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.9.1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "heapless" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" dependencies = [ - "hashbrown 0.14.5", + "atomic-polyfill", + "hash32", + "rustc_version", + "serde", + "spin", + "stable_deref_trait", ] [[package]] @@ -1508,7 +1414,7 @@ dependencies = [ "once_cell", "rand 0.9.0", "ring", - "thiserror 2.0.11", + "thiserror 2.0.12", "tinyvec", "tokio", "tracing", @@ -1531,7 +1437,7 @@ dependencies = [ "rand 0.9.0", "resolv-conf", "smallvec", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", ] @@ -1897,7 +1803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown", ] [[package]] @@ -1963,21 +1869,18 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iroh" -version = "0.35.0" +version = "0.90.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ca758f4ce39ae3f07de922be6c73de6a48a07f39554e78b5745585652ce38f5" +checksum = "9436f319c2d24bca1b28a2fab4477c8d2ac795ab2d3aeda142d207b38ec068f4" dependencies = [ "aead", - "anyhow", - "atomic-waker", "backon", "bytes", "cfg_aliases", - "concurrent-queue", "crypto_box", "data-encoding", "der", - "derive_more", + "derive_more 1.0.0", "ed25519-dalek", "futures-buffered", "futures-util", @@ -1993,24 +1896,27 @@ dependencies = [ "iroh-quinn-udp", "iroh-relay", "n0-future", + "n0-snafu", + "n0-watcher", + "nested_enum_utils", "netdev", "netwatch", "pin-project", "pkarr", "portmapper", "rand 0.8.5", - "rcgen", "reqwest", "ring", "rustls", + "rustls-pki-types", "rustls-webpki", "serde", "smallvec", + "snafu", "spki", "strum", "stun-rs", "surge-ping", - "thiserror 2.0.11", "time", "tokio", "tokio-stream", @@ -2019,44 +1925,43 @@ dependencies = [ "url", "wasm-bindgen-futures", "webpki-roots", - "x509-parser", "z32", ] [[package]] name = "iroh-base" -version = "0.35.0" +version = "0.90.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91ac4aaab68153d726c4e6b39c30f9f9253743f0e25664e52f4caeb46f48d11" +checksum = "8e0090050c4055b21e61cbcb856f043a2b24ad22c65d76bab91f121b4c7bece3" dependencies = [ "curve25519-dalek", "data-encoding", - "derive_more", + "derive_more 1.0.0", "ed25519-dalek", + "n0-snafu", + "nested_enum_utils", "postcard", "rand_core 0.6.4", "serde", - "thiserror 2.0.11", + "snafu", "url", ] [[package]] name = "iroh-blobs" -version = "0.35.0" +version = "0.90.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "817b785193b73c34ef1f2dcb5ddf8729ecef9b72a8fc0e706ee6d7a9bf8766a6" +checksum = "e5b6e39e8a3e9dded2eb0083fe5decf8a17000f22ba9b0b500ae1f476ce877b4" dependencies = [ "anyhow", - "async-channel", + "arrayvec", "bao-tree", - "blake3", "bytes", "chrono", "data-encoding", - "derive_more", + "derive_more 2.0.1", "futures-buffered", "futures-lite", - "futures-util", "genawaiter", "hashlink", "hex", @@ -2064,32 +1969,24 @@ dependencies = [ "iroh-base", "iroh-io", "iroh-metrics", - "nested_enum_utils 0.1.0", - "num_cpus", - "oneshot", - "parking_lot", - "portable-atomic", + "iroh-quinn", + "irpc", + "n0-future", + "n0-snafu", + "nested_enum_utils", "postcard", - "quic-rpc", - "quic-rpc-derive", "rand 0.8.5", "range-collections", "redb", + "ref-cast", "reflink-copy", "self_cell", "serde", - "serde-error", "smallvec", - "ssh-key", - "strum", - "tempfile", - "thiserror 2.0.11", + "snafu", "tokio", "tokio-util", "tracing", - "tracing-futures", - "tracing-test", - "walkdir", ] [[package]] @@ -2107,12 +2004,13 @@ dependencies = [ [[package]] name = "iroh-metrics" -version = "0.34.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f70466f14caff7420a14373676947e25e2917af6a5b1bec45825beb2bf1eb6a7" +checksum = "c8922c169f1b84d39d325c02ef1bbe1419d4de6e35f0403462b3c7e60cc19634" dependencies = [ "iroh-metrics-derive", "itoa", + "postcard", "serde", "snafu", "tracing", @@ -2132,9 +2030,9 @@ dependencies = [ [[package]] name = "iroh-quinn" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c6245c9ed906506ab9185e8d7f64857129aee4f935e899f398a3bd3b70338d" +checksum = "0cde160ebee7aabede6ae887460cd303c8b809054224815addf1469d54a6fcf7" dependencies = [ "bytes", "cfg_aliases", @@ -2144,7 +2042,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", "web-time", @@ -2163,8 +2061,9 @@ dependencies = [ "rustc-hash", "rustls", "rustls-pki-types", + "rustls-platform-verifier", "slab", - "thiserror 2.0.11", + "thiserror 2.0.12", "tinyvec", "tracing", "web-time", @@ -2186,15 +2085,14 @@ dependencies = [ [[package]] name = "iroh-relay" -version = "0.35.0" +version = "0.90.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c63f122cdfaa4b4e0e7d6d3921d2b878f42a0c6d3ee5a29456dc3f5ab5ec931f" +checksum = "c3f3cdbdaebc92835452e4e1d0d4b36118206b0950089b7bc3654f13e843475b" dependencies = [ - "anyhow", "bytes", "cfg_aliases", "data-encoding", - "derive_more", + "derive_more 1.0.0", "getrandom 0.3.3", "hickory-resolver", "http 1.2.0", @@ -2205,8 +2103,10 @@ dependencies = [ "iroh-metrics", "iroh-quinn", "iroh-quinn-proto", - "lru 0.12.5", + "lru", "n0-future", + "n0-snafu", + "nested_enum_utils", "num_enum", "pin-project", "pkarr", @@ -2214,12 +2114,12 @@ dependencies = [ "rand 0.8.5", "reqwest", "rustls", + "rustls-pki-types", "rustls-webpki", "serde", "sha1", + "snafu", "strum", - "stun-rs", - "thiserror 2.0.11", "tokio", "tokio-rustls", "tokio-util", @@ -2231,6 +2131,40 @@ dependencies = [ "z32", ] +[[package]] +name = "irpc" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b355fe12226ee885e1c1056a867c2cf37be2b22032a16f5ab7091069e98a966f" +dependencies = [ + "anyhow", + "futures-buffered", + "futures-util", + "iroh-quinn", + "irpc-derive", + "n0-future", + "postcard", + "rcgen", + "rustls", + "serde", + "smallvec", + "thiserror 2.0.12", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "irpc-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efeabe1ee5615ea0416340b1a6d71a16f971495859c87fad48633b6497ee7a77" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -2244,10 +2178,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] -name = "jpeg-decoder" -version = "0.3.1" +name = "jni" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" @@ -2264,9 +2220,6 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] [[package]] name = "libc" @@ -2275,16 +2228,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] -name = "libm" -version = "0.2.11" +name = "linux-raw-sys" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.4.15" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" @@ -2340,20 +2293,14 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "lru" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.2", -] - [[package]] name = "lru" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" +dependencies = [ + "hashbrown", +] [[package]] name = "match_cfg" @@ -2388,12 +2335,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.4" @@ -2441,7 +2382,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794" dependencies = [ "cfg_aliases", - "derive_more", + "derive_more 1.0.0", "futures-buffered", "futures-lite", "futures-util", @@ -2456,24 +2397,27 @@ dependencies = [ ] [[package]] -name = "nanorand" -version = "0.7.0" +name = "n0-snafu" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +checksum = "c4fed465ff57041f29db78a9adc8864296ef93c6c16029f9e192dc303404ebd0" dependencies = [ - "getrandom 0.2.15", + "anyhow", + "btparse", + "color-backtrace", + "snafu", + "tracing-error", ] [[package]] -name = "nested_enum_utils" -version = "0.1.0" +name = "n0-watcher" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f256ef99e7ac37428ef98c89bef9d84b590172de4bbfbe81b68a4cd3abadb32" +checksum = "f216d4ebc5fcf9548244803cbb93f488a2ae160feba3706cd17040d69cf7a368" dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", + "derive_more 1.0.0", + "n0-future", + "snafu", ] [[package]] @@ -2568,7 +2512,7 @@ dependencies = [ "log", "netlink-packet-core", "netlink-sys", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -2586,24 +2530,26 @@ dependencies = [ [[package]] name = "netwatch" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eeaa5f7505c93c5a9b35ba84fd21fb8aa3f24678c76acfe8716af7862fb07a" +checksum = "2a829a830199b14989f9bccce6136ab928ab48336ab1f8b9002495dbbbb2edbe" dependencies = [ "atomic-waker", "bytes", "cfg_aliases", - "derive_more", + "derive_more 1.0.0", "iroh-quinn-udp", "js-sys", "libc", "n0-future", - "nested_enum_utils 0.2.2", + "n0-watcher", + "nested_enum_utils", "netdev", "netlink-packet-core", "netlink-packet-route 0.23.0", "netlink-proto", "netlink-sys", + "pin-project-lite", "serde", "snafu", "socket2", @@ -2613,7 +2559,7 @@ dependencies = [ "tracing", "web-sys", "windows 0.59.0", - "windows-result 0.3.0", + "windows-result 0.3.4", "wmi", ] @@ -2635,16 +2581,6 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "ntimestamp" version = "1.0.0" @@ -2670,59 +2606,12 @@ 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 0.8.5", - "smallvec", - "zeroize", -] - [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[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" @@ -2730,7 +2619,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -2878,15 +2766,6 @@ 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.20.3" @@ -2897,18 +2776,18 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "oneshot" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d72a7c0f743d2ebb0a2ad1d219db75fdc799092ed3a884c9144c42a31225bd" - [[package]] name = "opaque-debug" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + [[package]] name = "os_pipe" version = "1.2.1" @@ -2925,44 +2804,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" -[[package]] -name = "p256" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", -] - -[[package]] -name = "p384" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" -dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", -] - -[[package]] -name = "p521" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" -dependencies = [ - "base16ct", - "ecdsa", - "elliptic-curve", - "primeorder", - "rand_core 0.6.4", - "sha2", -] - [[package]] name = "parking" version = "2.2.1" @@ -3030,7 +2871,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 2.0.11", + "thiserror 2.0.12", "ucd-trie", ] @@ -3127,31 +2968,20 @@ dependencies = [ "futures-lite", "getrandom 0.2.15", "log", - "lru 0.13.0", + "lru", "ntimestamp", "reqwest", "self_cell", "serde", "sha1_smol", "simple-dns", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", "url", "wasm-bindgen-futures", ] -[[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" @@ -3236,20 +3066,20 @@ checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "portmapper" -version = "0.5.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d6db66007eac4a0ec8331d0d20c734bd64f6445d64bbaf0d0a27fea7a054e36" +checksum = "2d82975dc029c00d566f4e0f61f567d31f0297a290cb5416b5580dd8b4b54ade" dependencies = [ "base64", "bytes", - "derive_more", + "derive_more 1.0.0", "futures-lite", "futures-util", "hyper-util", "igd-next", "iroh-metrics", "libc", - "nested_enum_utils 0.2.2", + "nested_enum_utils", "netwatch", "num_enum", "rand 0.8.5", @@ -3284,6 +3114,7 @@ dependencies = [ "cobs", "embedded-io 0.4.0", "embedded-io 0.6.1", + "heapless", "postcard-derive", "serde", ] @@ -3348,15 +3179,6 @@ dependencies = [ "ucd-parse", ] -[[package]] -name = "primeorder" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" -dependencies = [ - "elliptic-curve", -] - [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -3407,40 +3229,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quic-rpc" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18bad98bd048264ceb1361ff9d77a031535d8c1e3fe8f12c6966ec825bf68eb7" -dependencies = [ - "anyhow", - "document-features", - "flume", - "futures-lite", - "futures-sink", - "futures-util", - "pin-project", - "serde", - "slab", - "smallvec", - "time", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "quic-rpc-derive" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf13f1bced5f2f2642d9d89a29d75f2d81ab34c4acfcb434c209d6094b9b2b7" -dependencies = [ - "proc-macro2", - "quic-rpc", - "quote", - "syn 1.0.109", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -3460,7 +3248,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tracing", ] @@ -3479,7 +3267,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.11", + "thiserror 2.0.12", "tinyvec", "tracing", "web-time", @@ -3587,13 +3375,14 @@ dependencies = [ [[package]] name = "range-collections" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca9edd21e2db51000ac63eccddabba622f826e631a60be7bade9bd6a76b69537" +checksum = "861706ea9c4aded7584c5cd1d241cec2ea7f5f50999f236c22b65409a1f1a0d0" dependencies = [ "binary-merge", "inplace-vec-builder", "ref-cast", + "serde", "smallvec", ] @@ -3630,18 +3419,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ "proc-macro2", "quote", @@ -3650,14 +3439,14 @@ dependencies = [ [[package]] name = "reflink-copy" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd3533fd4222b8337470456ea84d80436b4c91c53db51c372461d5f7e6eb0b4" +checksum = "4b86038e146b9a61557e1a2e58cdf2eddc0b46ce141b55541b1c1b9f3189d618" dependencies = [ "cfg-if", "libc", - "rustix", - "windows 0.59.0", + "rustix 1.0.7", + "windows 0.60.0", ] [[package]] @@ -3765,16 +3554,6 @@ dependencies = [ "quick-error", ] -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac", - "subtle", -] - [[package]] name = "ring" version = "0.17.9" @@ -3789,27 +3568,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rsa" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "sha2", - "signature", - "spki", - "subtle", - "zeroize", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3832,32 +3590,36 @@ dependencies = [ ] [[package]] -name = "rusticata-macros" -version = "4.1.0" +name = "rustix" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "nom", + "bitflags 2.8.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", ] [[package]] name = "rustix" -version = "0.38.44" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags 2.8.0", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.9.4", "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.23" +version = "0.23.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" +checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" dependencies = [ "log", "once_cell", @@ -3868,6 +3630,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -3879,18 +3653,46 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" +dependencies = [ + "core-foundation 0.10.1", + "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 0.26.11", + "windows-sys 0.59.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" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "ring", "rustls-pki-types", @@ -3927,6 +3729,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -3940,17 +3751,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "sec1" -version = "0.7.3" +name = "security-framework" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ - "base16ct", - "der", - "generic-array", - "pkcs8", - "subtle", - "zeroize", + "bitflags 2.8.0", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -3977,18 +3797,16 @@ version = "0.26.0" dependencies = [ "anyhow", "arboard", - "async-channel", "clap", "console", "data-encoding", - "derive_more", + "derive_more 1.0.0", "duct", "futures-buffered", - "futures-lite", + "hex", "indicatif", "iroh", "iroh-blobs", - "iroh-io", "n0-future", "nix", "num_cpus", @@ -4011,15 +3829,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-error" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342110fb7a5d801060c885da03bf91bfa7c7ca936deafcc64bb6706375605d47" -dependencies = [ - "serde", -] - [[package]] name = "serde_derive" version = "1.0.219" @@ -4133,7 +3942,6 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", "rand_core 0.6.4", ] @@ -4169,27 +3977,28 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" dependencies = [ "serde", ] [[package]] name = "snafu" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" +checksum = "320b01e011bf8d5d7a4a4a4be966d9160968935849c83b918827f6a435e7f627" dependencies = [ + "backtrace", "snafu-derive", ] [[package]] name = "snafu-derive" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" +checksum = "1961e2ef424c1424204d3a5d6975f934f56b6d50ff5732382d84ebf460e147f7" dependencies = [ "heck", "proc-macro2", @@ -4226,48 +4035,6 @@ dependencies = [ "der", ] -[[package]] -name = "ssh-cipher" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f" -dependencies = [ - "cipher", - "ssh-encoding", -] - -[[package]] -name = "ssh-encoding" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15" -dependencies = [ - "base64ct", - "pem-rfc7468", - "sha2", -] - -[[package]] -name = "ssh-key" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3" -dependencies = [ - "ed25519-dalek", - "p256", - "p384", - "p521", - "rand_core 0.6.4", - "rsa", - "sec1", - "sha2", - "signature", - "ssh-cipher", - "ssh-encoding", - "subtle", - "zeroize", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -4408,7 +4175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.8.0", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -4438,10 +4205,19 @@ dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix", + "rustix 0.38.44", "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -4453,11 +4229,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -4473,9 +4249,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -4510,13 +4286,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", - "itoa", "js-sys", "num-conv", "powerfmt", "serde", "time-core", - "time-macros", ] [[package]] @@ -4525,16 +4299,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" -[[package]] -name = "time-macros" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinystr" version = "0.7.6" @@ -4619,9 +4383,10 @@ checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "futures-util", - "hashbrown 0.15.2", + "hashbrown", "pin-project-lite", "slab", "tokio", @@ -4727,13 +4492,13 @@ dependencies = [ ] [[package]] -name = "tracing-futures" -version = "0.2.5" +name = "tracing-error" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ - "pin-project", "tracing", + "tracing-subscriber", ] [[package]] @@ -4765,27 +4530,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "tracing-test" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557b891436fe0d5e0e363427fc7f217abf9ccd510d5136549847bdcbcd011d68" -dependencies = [ - "tracing-core", - "tracing-subscriber", - "tracing-test-macro", -] - -[[package]] -name = "tracing-test-macro" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" -dependencies = [ - "quote", - "syn 2.0.98", -] - [[package]] name = "try-lock" version = "0.2.5" @@ -5045,6 +4789,24 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" +dependencies = [ + "webpki-root-certs 1.0.1", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86138b15b2b7d561bc4469e77027b8dd005a43dc502e9031d1f5afc8ce1f280e" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.26.8" @@ -5126,6 +4888,28 @@ dependencies = [ "windows-targets 0.53.0", ] +[[package]] +name = "windows" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529" +dependencies = [ + "windows-collections", + "windows-core 0.60.1", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec" +dependencies = [ + "windows-core 0.60.1", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -5156,11 +4940,34 @@ checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" dependencies = [ "windows-implement 0.59.0", "windows-interface 0.59.0", - "windows-result 0.3.0", - "windows-strings 0.3.0", + "windows-result 0.3.4", + "windows-strings 0.3.1", "windows-targets 0.53.0", ] +[[package]] +name = "windows-core" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" +dependencies = [ + "windows-implement 0.59.0", + "windows-interface 0.59.0", + "windows-link", + "windows-result 0.3.4", + "windows-strings 0.3.1", +] + +[[package]] +name = "windows-future" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0" +dependencies = [ + "windows-core 0.60.1", + "windows-link", +] + [[package]] name = "windows-implement" version = "0.58.0" @@ -5205,14 +5012,30 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-numerics" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed" +dependencies = [ + "windows-core 0.60.1", + "windows-link", +] + [[package]] name = "windows-registry" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "windows-result 0.3.0", - "windows-strings 0.3.0", + "windows-result 0.3.4", + "windows-strings 0.3.1", "windows-targets 0.53.0", ] @@ -5227,11 +5050,11 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08106ce80268c4067c0571ca55a9b4e9516518eaa1a1fe9b37ca403ae1d1a34" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-targets 0.53.0", + "windows-link", ] [[package]] @@ -5246,11 +5069,20 @@ dependencies = [ [[package]] name = "windows-strings" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b888f919960b42ea4e11c2f408fadb55f78a9f236d5eef084103c8ce52893491" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-targets 0.53.0", + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", ] [[package]] @@ -5280,6 +5112,21 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -5327,6 +5174,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -5345,6 +5198,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -5363,6 +5222,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -5393,6 +5258,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -5411,6 +5282,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -5429,6 +5306,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -5447,6 +5330,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -5503,7 +5392,7 @@ dependencies = [ "futures", "log", "serde", - "thiserror 2.0.11", + "thiserror 2.0.12", "windows 0.59.0", "windows-core 0.59.0", ] @@ -5546,7 +5435,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ "gethostname", - "rustix", + "rustix 0.38.44", "x11rb-protocol", ] @@ -5556,23 +5445,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" -[[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.69", - "time", -] - [[package]] name = "xml-rs" version = "0.8.25" diff --git a/Cargo.toml b/Cargo.toml index 62d62ad..c642316 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,19 +15,17 @@ rust-version = "1.81" [dependencies] anyhow = "1.0.75" -async-channel = "2.3.1" clap = { version = "4.4.10", features = ["derive"] } console = "0.15.7" derive_more = { version = "1.0.0", features = [ "display", "from_str" ] } -futures-buffered = "0.2.4" -futures-lite = "2.3.0" +# I had some issues with futures-buffered 0.2.9 +futures-buffered = "0.2.11" indicatif = "0.17.7" -iroh-blobs = { version = "0.35", features = ["net_protocol"] } -iroh-io = "0.6" -iroh = "0.35" +iroh-blobs = { version = "0.90" } +iroh = "0.90" num_cpus = "1.16.0" rand = "0.8.5" serde = { version = "1", features = ["derive"] } @@ -38,6 +36,7 @@ walkdir = "2.4.0" data-encoding = "2.6.0" n0-future = "0.1.2" arboard = "3.4.1" +hex = "0.4.3" [dev-dependencies] duct = "0.13.6" diff --git a/src/main.rs b/src/main.rs index bac1fab..780ae7e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,14 @@ //! Command line arguments. +use std::{ + collections::BTreeMap, + fmt::{Display, Formatter}, + net::{SocketAddrV4, SocketAddrV6}, + path::{Component, Path, PathBuf}, + str::FromStr, + time::{Duration, Instant}, +}; + use anyhow::Context; use arboard::Clipboard; use clap::{ @@ -14,33 +23,30 @@ use indicatif::{ }; use iroh::{ discovery::{dns::DnsDiscovery, pkarr::PkarrPublisher}, - Endpoint, NodeAddr, RelayMode, RelayUrl, SecretKey, + Endpoint, NodeAddr, RelayMode, RelayUrl, SecretKey, Watcher, }; use iroh_blobs::{ - format::collection::Collection, - get::{ - db::DownloadProgress, - fsm::{AtBlobHeaderNextError, DecodeError}, - request::get_hash_seq_and_sizes, + api::{ + blobs::{ + AddPathOptions, AddProgressItem, ExportMode, ExportOptions, ExportProgressItem, + ImportMode, + }, + remote::GetProgressItem, + Store, TempTag, }, + format::collection::Collection, + get::{request::get_hash_seq_and_sizes, GetError, Stats}, net_protocol::Blobs, - provider::{self, CustomEventSender}, - store::{ExportMode, ImportMode, ImportProgress}, + provider::{self, Event}, + store::fs::FsStore, ticket::BlobTicket, - BlobFormat, Hash, HashAndFormat, TempTag, + BlobFormat, Hash, }; -use n0_future::{future::Boxed, StreamExt}; +use n0_future::{task::AbortOnDropHandle, StreamExt}; use rand::Rng; use serde::{Deserialize, Serialize}; -use std::{ - collections::BTreeMap, - fmt::{Display, Formatter}, - net::{SocketAddrV4, SocketAddrV6}, - path::{Component, Path, PathBuf}, - str::FromStr, - sync::Arc, - time::Duration, -}; +use tokio::{select, sync::mpsc}; +use tracing::{error, trace}; use walkdir::WalkDir; /// Send a file or directory between two machines, using blake3 verified streaming. @@ -98,6 +104,7 @@ pub enum Commands { Send(SendArgs), /// Receive a file or directory. + #[clap(visible_alias = "recv")] Receive(ReceiveArgs), } @@ -123,12 +130,19 @@ pub struct CommonArgs { #[clap(short = 'v', long, action = clap::ArgAction::Count)] pub verbose: u8, + /// Suppress progress bars. + #[clap(long, default_value_t = false)] + pub no_progress: bool, + /// The relay URL to use as a home relay, /// /// Can be set to "disabled" to disable relay servers and "default" /// to configure default servers. #[clap(long, default_value_t = RelayModeOption::Default)] pub relay: RelayModeOption, + + #[clap(long)] + pub show_secret: bool, } /// Available command line options for configuring relays. @@ -269,7 +283,8 @@ fn get_or_create_secret(print: bool) -> anyhow::Result { Err(_) => { let key = SecretKey::generate(rand::rngs::OsRng); if print { - eprintln!("using secret key {}", key); + let key = hex::encode(key.to_bytes()); + eprintln!("using secret key {key}"); } Ok(key) } @@ -329,68 +344,6 @@ pub fn canonicalized_path_to_string( Ok(path_str) } -pub async fn show_ingest_progress( - recv: async_channel::Receiver, -) -> anyhow::Result<()> { - let mp = MultiProgress::new(); - mp.set_draw_target(ProgressDrawTarget::stderr()); - let op = mp.add(ProgressBar::hidden()); - op.set_style( - ProgressStyle::default_spinner().template("{spinner:.green} [{elapsed_precise}] {msg}")?, - ); - // op.set_message(format!("{} Ingesting ...\n", style("[1/2]").bold().dim())); - // op.set_length(total_files); - let mut names = BTreeMap::new(); - let mut sizes = BTreeMap::new(); - let mut pbs = BTreeMap::new(); - loop { - let event = recv.recv().await; - match event { - Ok(ImportProgress::Found { id, name }) => { - names.insert(id, name); - } - Ok(ImportProgress::Size { id, size }) => { - sizes.insert(id, size); - let total_size = sizes.values().sum::(); - op.set_message(format!( - "{} Ingesting {} files, {}\n", - style("[1/2]").bold().dim(), - sizes.len(), - HumanBytes(total_size) - )); - let name = names.get(&id).cloned().unwrap_or_default(); - let pb = mp.add(ProgressBar::hidden()); - pb.set_style(ProgressStyle::with_template( - "{msg}{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes}", - )?.progress_chars("#>-")); - pb.set_message(format!("{} {}", style("[2/2]").bold().dim(), name)); - pb.set_length(size); - pbs.insert(id, pb); - } - Ok(ImportProgress::OutboardProgress { id, offset }) => { - if let Some(pb) = pbs.get(&id) { - pb.set_position(offset); - } - } - Ok(ImportProgress::OutboardDone { id, .. }) => { - // you are not guaranteed to get any OutboardProgress - if let Some(pb) = pbs.remove(&id) { - pb.finish_and_clear(); - } - } - Ok(ImportProgress::CopyProgress { .. }) => { - // we are not copying anything - } - Err(e) => { - op.set_message(format!("Error receiving progress: {e}")); - break; - } - } - } - op.finish_and_clear(); - Ok(()) -} - /// Import from a file or directory into the database. /// /// The returned tag always refers to a collection. If the input is a file, this @@ -400,8 +353,10 @@ pub async fn show_ingest_progress( /// directory. async fn import( path: PathBuf, - db: impl iroh_blobs::store::Store, + db: &Store, + mp: &mut MultiProgress, ) -> anyhow::Result<(TempTag, u64, Collection)> { + let parallelism = num_cpus::get(); let path = path.canonicalize()?; anyhow::ensure!(path.exists(), "path {} does not exist", path.display()); let root = path.parent().context("context get parent")?; @@ -423,27 +378,66 @@ async fn import( }) .filter_map(Result::transpose) .collect::>>()?; - let (send, recv) = async_channel::bounded(32); - let progress = iroh_blobs::util::progress::AsyncChannelProgressSender::new(send); - let show_progress = tokio::spawn(show_ingest_progress(recv)); // import all the files, using num_cpus workers, return names and temp tags - let mut names_and_tags = futures_lite::stream::iter(data_sources) + let op = mp.add(make_import_overall_progress()); + op.set_message(format!("importing {} files", data_sources.len())); + op.set_length(data_sources.len() as u64); + let mut names_and_tags = n0_future::stream::iter(data_sources) .map(|(name, path)| { let db = db.clone(); - let progress = progress.clone(); + let op = op.clone(); + let mp = mp.clone(); async move { - let (temp_tag, file_size) = db - .import_file(path, ImportMode::TryReference, BlobFormat::Raw, progress) - .await?; - anyhow::Ok((name, temp_tag, file_size)) + op.inc(1); + let pb = mp.add(make_import_item_progress()); + pb.set_message(format!("copying {name}")); + let import = db.add_path_with_opts(AddPathOptions { + path, + mode: ImportMode::TryReference, + format: BlobFormat::Raw, + }); + let mut stream = import.stream().await; + let mut item_size = 0; + let temp_tag = loop { + let item = stream + .next() + .await + .context("import stream ended without a tag")?; + trace!("importing {name} {item:?}"); + match item { + AddProgressItem::Size(size) => { + item_size = size; + pb.set_length(size); + } + AddProgressItem::CopyProgress(offset) => { + pb.set_position(offset); + } + AddProgressItem::CopyDone => { + pb.set_message(format!("computing outboard {name}")); + pb.set_position(0); + } + AddProgressItem::OutboardProgress(offset) => { + pb.set_position(offset); + } + AddProgressItem::Error(cause) => { + pb.finish_and_clear(); + anyhow::bail!("error importing {}: {}", name, cause); + } + AddProgressItem::Done(tt) => { + pb.finish_and_clear(); + break tt; + } + } + }; + anyhow::Ok((name, temp_tag, item_size)) } }) - .buffered_unordered(num_cpus::get()) + .buffered_unordered(parallelism) .collect::>() .await .into_iter() .collect::>>()?; - drop(progress); + op.finish_and_clear(); names_and_tags.sort_by(|(a, _, _), (b, _, _)| a.cmp(b)); // total size of all files let size = names_and_tags.iter().map(|(_, _, size)| *size).sum::(); @@ -453,11 +447,10 @@ async fn import( .into_iter() .map(|(name, tag, _)| ((name, *tag.hash()), tag)) .unzip::<_, _, Collection, Vec<_>>(); - let temp_tag = collection.clone().store(&db).await?; + let temp_tag = collection.clone().store(db).await?; // now that the collection is stored, we can drop the tags // data is protected by the collection drop(tags); - show_progress.await??; Ok((temp_tag, size, collection)) } @@ -471,9 +464,12 @@ fn get_export_path(root: &Path, name: &str) -> anyhow::Result { Ok(path) } -async fn export(db: impl iroh_blobs::store::Store, collection: Collection) -> anyhow::Result<()> { +async fn export(db: &Store, collection: Collection, mp: &mut MultiProgress) -> anyhow::Result<()> { let root = std::env::current_dir()?; - for (name, hash) in collection.iter() { + let op = mp.add(make_export_overall_progress()); + op.set_length(collection.len() as u64); + for (i, (name, hash)) in collection.iter().enumerate() { + op.set_position(i as u64); let target = get_export_path(&root, name)?; if target.exists() { eprintln!( @@ -483,114 +479,180 @@ async fn export(db: impl iroh_blobs::store::Store, collection: Collection) -> an eprintln!("You can remove the file or directory and try again. The download will not be repeated."); anyhow::bail!("target {} already exists", target.display()); } - db.export( - *hash, - target, - ExportMode::TryReference, - Box::new(move |_position| Ok(())), - ) - .await?; - } - Ok(()) -} - -#[derive(Debug, Clone)] -struct SendStatus { - /// the multiprogress bar - mp: MultiProgress, -} - -impl SendStatus { - fn new() -> Self { - let mp = MultiProgress::new(); - mp.set_draw_target(ProgressDrawTarget::stderr()); - Self { mp } - } - - fn new_client(&self) -> ClientStatus { - let current = self.mp.add(ProgressBar::hidden()); - current.set_style( - ProgressStyle::default_spinner() - .template("{spinner:.green} [{elapsed_precise}] {msg}") - .unwrap(), - ); - current.enable_steady_tick(Duration::from_millis(100)); - current.set_message("waiting for requests"); - ClientStatus { - current: current.into(), + let mut stream = db + .export_with_opts(ExportOptions { + hash: *hash, + target, + mode: ExportMode::TryReference, + }) + .stream() + .await; + let pb = mp.add(make_export_item_progress()); + pb.set_message(format!("exporting {name}")); + while let Some(item) = stream.next().await { + match item { + ExportProgressItem::Size(size) => { + pb.set_length(size); + } + ExportProgressItem::CopyProgress(offset) => { + pb.set_position(offset); + } + ExportProgressItem::Done => { + pb.finish_and_clear(); + } + ExportProgressItem::Error(cause) => { + pb.finish_and_clear(); + anyhow::bail!("error exporting {}: {}", name, cause); + } + } } } + op.finish_and_clear(); + Ok(()) } -#[derive(Debug, Clone)] -struct ClientStatus { - current: Arc, +#[derive(Debug)] +struct PerConnectionProgress { + main: ProgressBar, + requests: BTreeMap, } -impl Drop for ClientStatus { - fn drop(&mut self) { - if Arc::strong_count(&self.current) == 1 { - self.current.finish_and_clear(); - } - } -} - -impl CustomEventSender for ClientStatus { - fn send(&self, event: iroh_blobs::provider::Event) -> Boxed<()> { - self.try_send(event); - Box::pin(std::future::ready(())) - } - - fn try_send(&self, event: provider::Event) { - tracing::info!("{:?}", event); - let msg = match event { - provider::Event::ClientConnected { connection_id } => { - Some(format!("{} got connection", connection_id)) +async fn show_provide_progress( + mp: MultiProgress, + mut recv: mpsc::Receiver, +) -> anyhow::Result<()> { + let mut connections = BTreeMap::new(); + while let Some(item) = recv.recv().await { + trace!("got event {item:?}"); + match item { + Event::ClientConnected { + connection_id, + node_id, + permitted, + } => { + permitted.send(true).await.ok(); + let pb = mp.add(ProgressBar::hidden()); + pb.set_style( + indicatif::ProgressStyle::default_bar() + .template("{msg}") // Only display the message + .unwrap(), + ); + pb.set_message(format!("{node_id} {connection_id}")); + connections.insert( + connection_id, + PerConnectionProgress { + main: pb, + requests: BTreeMap::new(), + }, + ); + } + Event::ConnectionClosed { connection_id } => { + let Some(connection) = connections.remove(&connection_id) else { + error!("got close for unknown connection {connection_id}"); + continue; + }; + for pb in connection.requests.values() { + pb.finish_and_clear(); + } + connection.main.finish_and_clear(); } - provider::Event::TransferBlobCompleted { + Event::GetRequestReceived { connection_id, + request_id, hash, - index, - size, .. - } => Some(format!( - "{} transfer blob completed {} {} {}", + } => { + let pb = mp.add(ProgressBar::hidden()); + pb.set_style( + ProgressStyle::with_template( + "{msg}{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes}", + )? + .progress_chars("#>-"), + ); + pb.set_message(format!("{request_id} {hash}")); + let Some(connection) = connections.get_mut(&connection_id) else { + error!("got request for unknown connection {connection_id}"); + continue; + }; + connection.requests.insert(request_id, pb); + } + Event::TransferStarted { connection_id, + request_id, hash, + size, index, - HumanBytes(size) - )), - provider::Event::TransferCompleted { + } => { + let Some(connection) = connections.get_mut(&connection_id) else { + error!("got request for unknown connection {connection_id}"); + continue; + }; + let Some(pb) = connection.requests.get_mut(&request_id) else { + error!("got update for unknown request {request_id}"); + continue; + }; + pb.set_message(format!(" {} {} {}", request_id, index, hash.fmt_short())); + pb.set_length(size); + } + Event::TransferProgress { + connection_id, + request_id, + end_offset, + .. + } => { + let Some(connection) = connections.get_mut(&connection_id) else { + error!("got request for unknown connection {connection_id}"); + continue; + }; + let Some(pb) = connection.requests.get_mut(&request_id) else { + error!("got update for unknown request {request_id}"); + continue; + }; + pb.set_position(end_offset); + } + Event::TransferCompleted { connection_id, - stats, + request_id, .. - } => Some(format!( - "{} transfer completed {} {}", + } => { + if let Some(msg) = connections.get_mut(&connection_id) { + if let Some(pb) = msg.requests.remove(&request_id) { + // todo: show stats and hide after a delay + pb.finish_and_clear(); + } + } + } + Event::TransferAborted { connection_id, - stats.send.write_bytes.size, - HumanDuration(stats.send.write_bytes.stats.duration) - )), - provider::Event::TransferAborted { connection_id, .. } => { - Some(format!("{} transfer completed", connection_id)) + request_id, + .. + } => { + if let Some(msg) = connections.get_mut(&connection_id) { + if let Some(pb) = msg.requests.remove(&request_id) { + // todo: show stats and hide after a delay + pb.finish_and_clear(); + } + } } - _ => None, - }; - if let Some(msg) = msg { - self.current.set_message(msg); + _ => {} } } + Ok(()) } async fn send(args: SendArgs) -> anyhow::Result<()> { let secret_key = get_or_create_secret(args.common.verbose > 0)?; + if args.common.show_secret { + let secret_key = hex::encode(secret_key.to_bytes()); + eprintln!("using secret key {secret_key}"); + } // create a magicsocket endpoint let mut builder = Endpoint::builder() .alpns(vec![iroh_blobs::protocol::ALPN.to_vec()]) .secret_key(secret_key) .relay_mode(args.common.relay.into()); if args.ticket_type == AddrInfoOptions::Id { - builder = - builder.add_discovery(|secret_key| Some(PkarrPublisher::n0_dns(secret_key.clone()))); + builder = builder.add_discovery(PkarrPublisher::n0_dns()); } if let Some(addr) = args.common.magic_ipv4_addr { builder = builder.bind_addr_v4(addr); @@ -611,46 +673,73 @@ async fn send(args: SendArgs) -> anyhow::Result<()> { std::process::exit(1); } - tokio::fs::create_dir_all(&blobs_data_dir).await?; - - let endpoint = builder.bind().await?; - let ps = SendStatus::new(); - let blobs = Blobs::persistent(&blobs_data_dir) - .await? - .events(ps.new_client().into()) - .build(&endpoint); - - let router = iroh::protocol::Router::builder(endpoint) - .accept(iroh_blobs::ALPN, blobs.clone()) - .spawn(); - + let mut mp = MultiProgress::new(); + let mp2 = mp.clone(); let path = args.path; - let (temp_tag, size, collection) = import(path.clone(), blobs.store().clone()).await?; + let path2 = path.clone(); + let blobs_data_dir2 = blobs_data_dir.clone(); + let (progress_tx, progress_rx) = mpsc::channel(32); + let progress = AbortOnDropHandle::new(n0_future::task::spawn(show_provide_progress( + mp2, + progress_rx, + ))); + let setup = async move { + let t0 = Instant::now(); + tokio::fs::create_dir_all(&blobs_data_dir2).await?; + + let endpoint = builder.bind().await?; + let draw_target = if args.common.no_progress { + ProgressDrawTarget::hidden() + } else { + ProgressDrawTarget::stderr() + }; + mp.set_draw_target(draw_target); + let store = FsStore::load(&blobs_data_dir2).await?; + let blobs = Blobs::new(&store, endpoint.clone(), Some(progress_tx)); + + let import_result = import(path2, blobs.store(), &mut mp).await?; + let dt = t0.elapsed(); + + let router = iroh::protocol::Router::builder(endpoint) + .accept(iroh_blobs::ALPN, blobs.clone()) + .spawn(); + // wait for the endpoint to figure out its address before making a ticket + let _ = router.endpoint().home_relay().initialized().await?; + anyhow::Ok((router, import_result, dt)) + }; + let (router, (temp_tag, size, collection), dt) = select! { + x = setup => x?, + _ = tokio::signal::ctrl_c() => { + std::process::exit(130); + } + }; let hash = *temp_tag.hash(); - // wait for the endpoint to figure out its address before making a ticket - let _ = router.endpoint().home_relay().initialized().await?; - // make a ticket - let mut addr = router.endpoint().node_addr().await?; + let mut addr = router.endpoint().node_addr().initialized().await?; apply_options(&mut addr, args.ticket_type); - let ticket = BlobTicket::new(addr, hash, BlobFormat::HashSeq)?; + let ticket = BlobTicket::new(addr, hash, BlobFormat::HashSeq); let entry_type = if path.is_file() { "file" } else { "directory" }; println!( "imported {} {}, {}, hash {}", entry_type, path.display(), HumanBytes(size), - print_hash(&hash, args.common.format) + print_hash(&hash, args.common.format), ); - if args.common.verbose > 0 { + if args.common.verbose > 1 { for (name, hash) in collection.iter() { println!(" {} {name}", print_hash(hash, args.common.format)); } + println!( + "{}s, {}/s", + dt.as_secs_f64(), + HumanBytes(((size as f64) / dt.as_secs_f64()).floor() as u64) + ); } println!("to get this data, use"); - println!("sendme receive {}", ticket); + println!("sendme receive {ticket}"); // Add command to the clipboard if args.clipboard { @@ -674,6 +763,10 @@ async fn send(args: SendArgs) -> anyhow::Result<()> { println!("shutting down"); tokio::time::timeout(Duration::from_secs(2), router.shutdown()).await??; tokio::fs::remove_dir_all(blobs_data_dir).await?; + // drop everything that owns blobs to close the progress sender + drop(router); + // await progress completion so the progress bar is cleared + progress.await.ok(); Ok(()) } @@ -682,22 +775,97 @@ fn add_to_clipboard(ticket: &BlobTicket) { let clipboard = Clipboard::new(); match clipboard { Ok(mut clip) => { - if let Err(e) = clip.set_text(format!("sendme receive {}", ticket)) { - eprintln!("Could not add to clipboard: {}", e); + if let Err(e) = clip.set_text(format!("sendme receive {ticket}")) { + eprintln!("Could not add to clipboard: {e}"); } else { println!("Command added to clipboard.") } } - Err(e) => eprintln!("Could not access clipboard: {}", e), + Err(e) => eprintln!("Could not access clipboard: {e}"), } } +const TICK_MS: u64 = 250; + +fn make_import_overall_progress() -> ProgressBar { + let pb = ProgressBar::hidden(); + pb.enable_steady_tick(std::time::Duration::from_millis(TICK_MS)); + pb.set_style( + ProgressStyle::with_template( + "{msg}{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {pos}/{len}", + ) + .unwrap() + .progress_chars("#>-"), + ); + pb +} + +fn make_import_item_progress() -> ProgressBar { + let pb = ProgressBar::hidden(); + pb.enable_steady_tick(std::time::Duration::from_millis(TICK_MS)); + pb.set_style( + ProgressStyle::with_template("{msg}{spinner:.green} XXXX [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes}") + .unwrap() + .progress_chars("#>-"), + ); + pb +} + +fn make_connect_progress() -> ProgressBar { + let pb = ProgressBar::hidden(); + pb.set_style( + ProgressStyle::with_template("{prefix}{spinner:.green} Connecting ... [{elapsed_precise}]") + .unwrap(), + ); + pb.set_prefix(format!("{} ", style("[1/4]").bold().dim())); + pb.enable_steady_tick(Duration::from_millis(TICK_MS)); + pb +} + +fn make_get_sizes_progress() -> ProgressBar { + let pb = ProgressBar::hidden(); + pb.set_style( + ProgressStyle::with_template( + "{prefix}{spinner:.green} Getting sizes... [{elapsed_precise}]", + ) + .unwrap(), + ); + pb.set_prefix(format!("{} ", style("[2/4]").bold().dim())); + pb.enable_steady_tick(Duration::from_millis(TICK_MS)); + pb +} + fn make_download_progress() -> ProgressBar { + let pb = ProgressBar::hidden(); + pb.enable_steady_tick(std::time::Duration::from_millis(TICK_MS)); + pb.set_style( + ProgressStyle::with_template("{prefix}{spinner:.green}{msg} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} {binary_bytes_per_sec}") + .unwrap() + .progress_chars("#>-"), + ); + pb.set_prefix(format!("{} ", style("[3/4]").bold().dim())); + pb.set_message("Downloading ...".to_string()); + pb +} + +fn make_export_overall_progress() -> ProgressBar { + let pb = ProgressBar::hidden(); + pb.enable_steady_tick(std::time::Duration::from_millis(TICK_MS)); + pb.set_style( + ProgressStyle::with_template("{prefix}{msg}{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {human_pos}/{human_len} {per_sec}") + .unwrap() + .progress_chars("#>-"), + ); + pb.set_prefix(format!("{}", style("[4/4]").bold().dim())); + pb +} + +fn make_export_item_progress() -> ProgressBar { let pb = ProgressBar::hidden(); pb.enable_steady_tick(std::time::Duration::from_millis(100)); pb.set_style( ProgressStyle::with_template( - "{msg}{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} {binary_bytes_per_sec}", + "{msg}{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes}", ) .unwrap() .progress_chars("#>-"), @@ -706,103 +874,37 @@ fn make_download_progress() -> ProgressBar { } pub async fn show_download_progress( - recv: async_channel::Receiver, + mp: MultiProgress, + mut recv: mpsc::Receiver, + local_size: u64, total_size: u64, ) -> anyhow::Result<()> { - let mp = MultiProgress::new(); - mp.set_draw_target(ProgressDrawTarget::stderr()); let op = mp.add(make_download_progress()); - op.set_message(format!("{} Connecting ...\n", style("[1/3]").bold().dim())); - let mut total_done = 0; - let mut sizes = BTreeMap::new(); - loop { - let x = recv.recv().await; - match x { - Ok(DownloadProgress::Connected) => { - op.set_message(format!("{} Requesting ...\n", style("[2/3]").bold().dim())); - } - Ok(DownloadProgress::FoundHashSeq { children, .. }) => { - op.set_message(format!( - "{} Downloading {} blob(s)\n", - style("[3/3]").bold().dim(), - children + 1, - )); - op.set_length(total_size); - op.reset(); - } - Ok(DownloadProgress::Found { id, size, .. }) => { - sizes.insert(id, size); - } - Ok(DownloadProgress::Progress { offset, .. }) => { - op.set_position(total_done + offset); - } - Ok(DownloadProgress::Done { id }) => { - total_done += sizes.remove(&id).unwrap_or_default(); - } - Ok(DownloadProgress::AllDone(stats)) => { - op.finish_and_clear(); - eprintln!( - "Transferred {} in {}, {}/s", - HumanBytes(stats.bytes_read), - HumanDuration(stats.elapsed), - HumanBytes((stats.bytes_read as f64 / stats.elapsed.as_secs_f64()) as u64) - ); - break; - } - Ok(DownloadProgress::Abort(e)) => { - anyhow::bail!("download aborted: {e:?}"); - } - Err(e) => { - anyhow::bail!("error reading progress: {e:?}"); - } - _ => {} - } + op.set_length(total_size); + while let Some(offset) = recv.recv().await { + op.set_position(local_size + offset); } + op.finish_and_clear(); Ok(()) } -fn show_get_error(e: anyhow::Error) -> anyhow::Error { - if let Some(err) = e.downcast_ref::() { - match err { - DecodeError::NotFound => { - eprintln!("{}", style("send side no longer has a file").yellow()) - } - DecodeError::LeafNotFound(_) | DecodeError::ParentNotFound(_) => eprintln!( - "{}", - style("send side no longer has part of a file").yellow() - ), - DecodeError::Io(err) => eprintln!( - "{}", - style(format!("generic network error: {}", err)).yellow() - ), - DecodeError::Read(err) => eprintln!( - "{}", - style(format!("error reading data from quinn: {}", err)).yellow() - ), - DecodeError::LeafHashMismatch(_) | DecodeError::ParentHashMismatch(_) => { - eprintln!("{}", style("send side sent wrong data").red()) - } - }; - } else if let Some(header_error) = e.downcast_ref::() { - // TODO(iroh-bytes): get_to_db should have a concrete error type so you don't have to guess - match header_error { - AtBlobHeaderNextError::Io(err) => eprintln!( - "{}", - style(format!("generic network error: {}", err)).yellow() - ), - AtBlobHeaderNextError::Read(err) => eprintln!( - "{}", - style(format!("error reading data from quinn: {}", err)).yellow() - ), - AtBlobHeaderNextError::NotFound => { - eprintln!("{}", style("send side no longer has a file").yellow()) - } - }; - } else { - eprintln!( +fn show_get_error(e: GetError) -> GetError { + match &e { + GetError::NotFound { .. } => { + eprintln!("{}", style("send side no longer has a file").yellow()) + } + GetError::RemoteReset { .. } => eprintln!("{}", style("remote reset").yellow()), + GetError::NoncompliantNode { .. } => { + eprintln!("{}", style("non-compliant remote").yellow()) + } + GetError::Io { source, .. } => eprintln!( "{}", - style(format!("generic error: {:?}", e.root_cause())).red() - ); + style(format!("generic network error: {source}")).yellow() + ), + GetError::BadRequest { .. } => eprintln!("{}", style("bad request").yellow()), + GetError::LocalFailure { source, .. } => { + eprintln!("{} {source:?}", style("local failure").yellow()) + } } e } @@ -817,7 +919,7 @@ async fn receive(args: ReceiveArgs) -> anyhow::Result<()> { .relay_mode(args.common.relay.into()); if ticket.node_addr().relay_url.is_none() && ticket.node_addr().direct_addresses.is_empty() { - builder = builder.add_discovery(|_| Some(DnsDiscovery::n0_dns())); + builder = builder.add_discovery(DnsDiscovery::n0_dns()); } if let Some(addr) = args.common.magic_ipv4_addr { builder = builder.bind_addr_v4(addr); @@ -826,60 +928,117 @@ async fn receive(args: ReceiveArgs) -> anyhow::Result<()> { builder = builder.bind_addr_v6(addr); } let endpoint = builder.bind().await?; - let dir_name = format!(".sendme-get-{}", ticket.hash().to_hex()); + let dir_name = format!(".sendme-recv-{}", ticket.hash().to_hex()); let iroh_data_dir = std::env::current_dir()?.join(dir_name); - let db = iroh_blobs::store::fs::Store::load(&iroh_data_dir).await?; - let mp = MultiProgress::new(); - let connect_progress = mp.add(ProgressBar::hidden()); - connect_progress.set_draw_target(ProgressDrawTarget::stderr()); - connect_progress.set_style(ProgressStyle::default_spinner()); - connect_progress.set_message(format!("connecting to {}", addr.node_id)); - let connection = endpoint.connect(addr, iroh_blobs::protocol::ALPN).await?; - let hash_and_format = HashAndFormat { - hash: ticket.hash(), - format: ticket.format(), - }; - connect_progress.finish_and_clear(); - let (send, recv) = async_channel::bounded(32); - let progress = iroh_blobs::util::progress::AsyncChannelProgressSender::new(send); - let (_hash_seq, sizes) = - get_hash_seq_and_sizes(&connection, &hash_and_format.hash, 1024 * 1024 * 32) - .await - .map_err(show_get_error)?; - let total_size = sizes.iter().sum::(); - let total_files = sizes.len().saturating_sub(1); - let payload_size = sizes.iter().skip(1).sum::(); - eprintln!( - "getting collection {} {} files, {}", - print_hash(&ticket.hash(), args.common.format), - total_files, - HumanBytes(payload_size) - ); - // print the details of the collection only in verbose mode - if args.common.verbose > 0 { - eprintln!( - "getting {} blobs in total, {}", - sizes.len(), - HumanBytes(total_size) - ); - } - let _task = tokio::spawn(show_download_progress(recv, total_size)); - let get_conn = || async move { Ok(connection) }; - let stats = iroh_blobs::get::db::get_to_db(&db, get_conn, &hash_and_format, progress) - .await - .map_err(|e| show_get_error(anyhow::anyhow!(e)))?; - let collection = Collection::load_db(&db, &hash_and_format.hash).await?; - if args.common.verbose > 0 { - for (name, hash) in collection.iter() { - println!(" {} {name}", print_hash(hash, args.common.format)); + let db = iroh_blobs::store::fs::FsStore::load(&iroh_data_dir).await?; + let db2 = db.clone(); + trace!("load done!"); + let fut = async move { + trace!("running"); + let mut mp: MultiProgress = MultiProgress::new(); + let draw_target = if args.common.no_progress { + ProgressDrawTarget::hidden() + } else { + ProgressDrawTarget::stderr() + }; + mp.set_draw_target(draw_target); + let hash_and_format = ticket.hash_and_format(); + trace!("computing local"); + let local = db.remote().local(hash_and_format).await?; + trace!("local done"); + let (stats, total_files, payload_size) = if !local.is_complete() { + trace!("{} not complete", hash_and_format.hash); + let cp = mp.add(make_connect_progress()); + let connection = endpoint.connect(addr, iroh_blobs::protocol::ALPN).await?; + cp.finish_and_clear(); + let sp = mp.add(make_get_sizes_progress()); + let (_hash_seq, sizes) = + get_hash_seq_and_sizes(&connection, &hash_and_format.hash, 1024 * 1024 * 32, None) + .await + .map_err(show_get_error)?; + sp.finish_and_clear(); + let total_size = sizes.iter().copied().sum::(); + let payload_size = sizes.iter().skip(2).copied().sum::(); + let total_files = (sizes.len().saturating_sub(1)) as u64; + eprintln!( + "getting collection {} {} files, {}", + print_hash(&ticket.hash(), args.common.format), + total_files, + HumanBytes(payload_size) + ); + // print the details of the collection only in verbose mode + if args.common.verbose > 0 { + eprintln!( + "getting {} blobs in total, {}", + total_files + 1, + HumanBytes(total_size) + ); + } + let (tx, rx) = mpsc::channel(32); + let local_size = local.local_bytes(); + let get = db.remote().execute_get(connection, local.missing()); + let task = tokio::spawn(show_download_progress( + mp.clone(), + rx, + local_size, + total_size, + )); + // let mut stream = get.stream(); + let mut stats = Stats::default(); + let mut stream = get.stream(); + while let Some(item) = stream.next().await { + trace!("got item {item:?}"); + match item { + GetProgressItem::Progress(offset) => { + tx.send(offset).await.ok(); + } + GetProgressItem::Done(value) => { + stats = value; + break; + } + GetProgressItem::Error(cause) => { + anyhow::bail!(show_get_error(cause)); + } + } + } + drop(tx); + task.await.ok(); + (stats, total_files, payload_size) + } else { + println!("{} already complete", hash_and_format.hash); + let total_files = local.children().unwrap() - 1; + let payload_bytes = 0; // todo local.sizes().skip(2).map(Option::unwrap).sum::(); + (Stats::default(), total_files, payload_bytes) + }; + let collection = Collection::load(hash_and_format.hash, db.as_ref()).await?; + if args.common.verbose > 1 { + for (name, hash) in collection.iter() { + println!(" {} {name}", print_hash(hash, args.common.format)); + } } - } - if let Some((name, _)) = collection.iter().next() { - if let Some(first) = name.split('/').next() { - println!("downloading to: {};", first); + if let Some((name, _)) = collection.iter().next() { + if let Some(first) = name.split('/').next() { + println!("exporting to {first}"); + } } - } - export(db, collection).await?; + export(&db, collection, &mut mp).await?; + anyhow::Ok((total_files, payload_size, stats)) + }; + let (total_files, payload_size, stats) = select! { + x = fut => match x { + Ok(x) => x, + Err(e) => { + // make sure we shutdown the db before exiting + db2.shutdown().await?; + eprintln!("error: {e}"); + std::process::exit(1); + } + }, + _ = tokio::signal::ctrl_c() => { + db2.shutdown().await?; + std::process::exit(130); + } + }; tokio::fs::remove_dir_all(iroh_data_dir).await?; if args.common.verbose > 0 { println!( @@ -887,7 +1046,7 @@ async fn receive(args: ReceiveArgs) -> anyhow::Result<()> { total_files, HumanBytes(payload_size), HumanDuration(stats.elapsed), - HumanBytes((stats.bytes_read as f64 / stats.elapsed.as_secs_f64()) as u64), + HumanBytes((stats.total_bytes_read() as f64 / stats.elapsed.as_secs_f64()) as u64), ); } Ok(()) diff --git a/tests/cli.rs b/tests/cli.rs index 7ef738c..7c6a6bd 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -82,9 +82,9 @@ fn send_recv_file() { fn send_recv_dir() { fn create_file(base: &Path, i: usize, j: usize, k: usize) -> (PathBuf, Vec) { let name = base - .join(format!("dir-{}", i)) - .join(format!("subdir-{}", j)) - .join(format!("file-{}", k)); + .join(format!("dir-{i}")) + .join(format!("subdir-{j}")) + .join(format!("file-{k}")); let len = i * 100 + j * 10 + k; let data = vec![0u8; len]; (name, data)