diff --git a/.github/workflows/beta.yaml b/.github/workflows/beta.yaml index 56bc5da8e..7359d5b5c 100644 --- a/.github/workflows/beta.yaml +++ b/.github/workflows/beta.yaml @@ -38,6 +38,6 @@ jobs: severity: error details: | Rustc beta tests failed in **${{ github.repository }}** - See https://github.com/n0-computer/${{ github.repository }}/actions/workflows/beta.yaml + See https://github.com/${{ github.repository }}/actions/workflows/beta.yaml webhookUrl: ${{ secrets.DISCORD_N0_GITHUB_CHANNEL_WEBHOOK_URL }} diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9b6d085c7..bc45e9a3c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -157,7 +157,7 @@ jobs: with: fetch-depth: 0 - name: Install sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@v0.0.8 - name: Setup Environment (PR) if: ${{ github.event_name == 'pull_request' }} @@ -189,7 +189,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: components: rustfmt - - uses: mozilla-actions/sccache-action@v0.0.7 + - uses: mozilla-actions/sccache-action@v0.0.8 - uses: taiki-e/install-action@cargo-make - run: cargo make format-check @@ -206,7 +206,7 @@ jobs: with: toolchain: nightly-2024-11-30 - name: Install sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@v0.0.8 - name: Docs run: cargo doc --workspace --all-features --no-deps --document-private-items @@ -225,7 +225,7 @@ jobs: with: components: clippy - name: Install sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@v0.0.8 # TODO: We have a bunch of platform-dependent code so should # probably run this job on the full platform matrix @@ -252,7 +252,7 @@ jobs: with: toolchain: ${{ env.MSRV }} - name: Install sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@v0.0.8 - name: Check MSRV all features run: | diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 4b49e3669..f9c5e64b6 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -34,7 +34,7 @@ jobs: with: toolchain: nightly-2024-11-30 - name: Install sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@v0.0.8 - name: Generate Docs run: cargo doc --workspace --all-features --no-deps diff --git a/.github/workflows/project.yaml b/.github/workflows/project.yaml deleted file mode 100644 index 863440d78..000000000 --- a/.github/workflows/project.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: Add PRs and Issues to Project - -on: - issues: - types: - - opened - pull_request: - types: - - opened - -jobs: - add-to-project: - name: Add to project - runs-on: ubuntu-latest - steps: - - uses: actions/add-to-project@v1.0.2 - with: - project-url: https://github.com/orgs/n0-computer/projects/1 - github-token: ${{ secrets.PROJECT_PAT }} \ No newline at end of file diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 920815d67..0acf6c8b4 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -66,10 +66,10 @@ jobs: - name: Install cargo-nextest uses: taiki-e/install-action@v2 with: - tool: nextest + tool: nextest@0.9.80 - name: Install sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@v0.0.8 - name: Select features run: | @@ -199,7 +199,7 @@ jobs: } - name: Install sccache - uses: mozilla-actions/sccache-action@v0.0.7 + uses: mozilla-actions/sccache-action@v0.0.8 - uses: msys2/setup-msys2@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 78863ff33..bc243c6ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,93 @@ All notable changes to iroh-blobs will be documented in this file. +## [0.34.0](https://github.com/n0-computer/iroh-blobs/compare/v0.33.1..0.34.0) - 2025-03-18 + +### ⛰️ Features + +- Richer tags api ([#69](https://github.com/n0-computer/iroh-blobs/issues/69)) - ([387c68c](https://github.com/n0-computer/iroh-blobs/commit/387c68cc4d084b7067bfedae341abb277eaac8c0)) +- Modify Downloader config through Blobs builder ([#75](https://github.com/n0-computer/iroh-blobs/issues/75)) - ([6e9f06b](https://github.com/n0-computer/iroh-blobs/commit/6e9f06b48a97957550e2343694966ac2fee07f39)) +- Enable RPC by default ([#73](https://github.com/n0-computer/iroh-blobs/issues/73)) - ([b1029e2](https://github.com/n0-computer/iroh-blobs/commit/b1029e2f5542b56525d53365b040d874549d9fe7)) + +### ⚙️ Miscellaneous Tasks + +- *(deps)* Bump mozilla-actions/sccache-action from 0.0.7 to 0.0.8 in the github-actions group ([#66](https://github.com/n0-computer/iroh-blobs/issues/66)) - ([3e9662c](https://github.com/n0-computer/iroh-blobs/commit/3e9662c9cdb4948f9f8c59e7c74ce6eca7942cf9)) +- Update to latest iroh ([#77](https://github.com/n0-computer/iroh-blobs/issues/77)) - ([253a8c6](https://github.com/n0-computer/iroh-blobs/commit/253a8c6bf05db30bf39485822f0e2114481e26ce)) +- Update lockfile - ([65a84bb](https://github.com/n0-computer/iroh-blobs/commit/65a84bb011e543e3b752b5d7eda1c5f3c1eba481)) + +## [0.33.1](https://github.com/n0-computer/iroh-blobs/compare/v0.33.0..0.33.1) - 2025-03-11 + +### 🐛 Bug Fixes + +- Do not panic when parsing invalid hashes ([#68](https://github.com/n0-computer/iroh-blobs/issues/68)) - ([cfdfca0](https://github.com/n0-computer/iroh-blobs/commit/cfdfca04760369a9457ea09b4085ab63588398c1)) + +### ⚙️ Miscellaneous Tasks + +- Patch to use main branch of iroh dependencies ([#64](https://github.com/n0-computer/iroh-blobs/issues/64)) - ([d739d52](https://github.com/n0-computer/iroh-blobs/commit/d739d5225029d40749150ad4f2d5e1c1c6f1c0c4)) +- Release ([#70](https://github.com/n0-computer/iroh-blobs/issues/70)) - ([4c282fe](https://github.com/n0-computer/iroh-blobs/commit/4c282fea5536f142fe6aab78de1c58d2871c912f)) +- Update change log ([#71](https://github.com/n0-computer/iroh-blobs/issues/71)) - ([f4feff7](https://github.com/n0-computer/iroh-blobs/commit/f4feff72c79559ff09ddc8091e15996cf2df0c27)) +- Release iroh-blobs version 0.33.1 - ([e4aa724](https://github.com/n0-computer/iroh-blobs/commit/e4aa7245a3ec31a652a5573b70928d0dffd7fbc7)) + +## [0.33.1](https://github.com/n0-computer/iroh-blobs/compare/v0.33.0..0.33.1) - 2025-03-11 + +### 🐛 Bug Fixes + +- Do not panic when parsing invalid hashes ([#68](https://github.com/n0-computer/iroh-blobs/issues/68)) - ([cfdfca0](https://github.com/n0-computer/iroh-blobs/commit/cfdfca04760369a9457ea09b4085ab63588398c1)) + +### ⚙️ Miscellaneous Tasks + +- Patch to use main branch of iroh dependencies ([#64](https://github.com/n0-computer/iroh-blobs/issues/64)) - ([d739d52](https://github.com/n0-computer/iroh-blobs/commit/d739d5225029d40749150ad4f2d5e1c1c6f1c0c4)) +- Release ([#70](https://github.com/n0-computer/iroh-blobs/issues/70)) - ([4c282fe](https://github.com/n0-computer/iroh-blobs/commit/4c282fea5536f142fe6aab78de1c58d2871c912f)) +- Update change log ([#71](https://github.com/n0-computer/iroh-blobs/issues/71)) - ([f4feff7](https://github.com/n0-computer/iroh-blobs/commit/f4feff72c79559ff09ddc8091e15996cf2df0c27)) + +## [0.33.1](https://github.com/n0-computer/iroh-blobs/compare/v0.33.0..0.33.1) - 2025-03-11 + +### 🐛 Bug Fixes + +- Do not panic when parsing invalid hashes ([#68](https://github.com/n0-computer/iroh-blobs/issues/68)) - ([cfdfca0](https://github.com/n0-computer/iroh-blobs/commit/cfdfca04760369a9457ea09b4085ab63588398c1)) + +### ⚙️ Miscellaneous Tasks + +- Patch to use main branch of iroh dependencies ([#64](https://github.com/n0-computer/iroh-blobs/issues/64)) - ([d739d52](https://github.com/n0-computer/iroh-blobs/commit/d739d5225029d40749150ad4f2d5e1c1c6f1c0c4)) +- Release ([#70](https://github.com/n0-computer/iroh-blobs/issues/70)) - ([4c282fe](https://github.com/n0-computer/iroh-blobs/commit/4c282fea5536f142fe6aab78de1c58d2871c912f)) + +## [0.33.0](https://github.com/n0-computer/iroh-blobs/compare/v0.32.0..0.33.0) - 2025-02-25 + +### 📚 Documentation + +- Update readme ([#55](https://github.com/n0-computer/iroh-blobs/issues/55)) - ([d8d2b48](https://github.com/n0-computer/iroh-blobs/commit/d8d2b48fbaaaf4d604e8583e87c874cdc9c5b3c6)) + +### ⚙️ Miscellaneous Tasks + +- Patch to use main branch of iroh dependencies ([#58](https://github.com/n0-computer/iroh-blobs/issues/58)) - ([57cb626](https://github.com/n0-computer/iroh-blobs/commit/57cb62696bbad313d497c4a33821657fb6bf53ee)) +- Upgrade to latest `iroh` and `quic-rpc` ([#63](https://github.com/n0-computer/iroh-blobs/issues/63)) - ([a198ccc](https://github.com/n0-computer/iroh-blobs/commit/a198cccbde55071973e2b637e7e3ea56908f5d7d)) + +### Example + +- Simplify transfer example ([#53](https://github.com/n0-computer/iroh-blobs/issues/53)) - ([bbbb636](https://github.com/n0-computer/iroh-blobs/commit/bbbb63679794345ed9e6155e67d0423667bfbf26)) + +## [0.32.0](https://github.com/n0-computer/iroh-blobs/compare/v0.31.0..0.32.0) - 2025-02-04 + +### ⛰️ Features + +- Update quic-rpc to 0.18 ([#46](https://github.com/n0-computer/iroh-blobs/issues/46)) - ([030420e](https://github.com/n0-computer/iroh-blobs/commit/030420e7fa03c80b44491f8da16b993f4015007f)) +- [**breaking**] Simplify LocalPool handling ([#47](https://github.com/n0-computer/iroh-blobs/issues/47)) - ([b29991d](https://github.com/n0-computer/iroh-blobs/commit/b29991dc913459e034b758271d9b79f8ae6c498e)) + +### ⚙️ Miscellaneous Tasks + +- Fix URL to beta workflow ([#50](https://github.com/n0-computer/iroh-blobs/issues/50)) - ([5cacccb](https://github.com/n0-computer/iroh-blobs/commit/5cacccb33818b11eab487b89da0bb4a69325f52b)) +- Remove individual repo project tracking ([#48](https://github.com/n0-computer/iroh-blobs/issues/48)) - ([64b6ae6](https://github.com/n0-computer/iroh-blobs/commit/64b6ae6a6b1dfcdf639ad55923391957b0b4186e)) +- Upgrade to `iroh@v0.32.0` and `quic-rpc@v0.18.1` ([#52](https://github.com/n0-computer/iroh-blobs/issues/52)) - ([7dccac9](https://github.com/n0-computer/iroh-blobs/commit/7dccac9610482f9acbde4c46a134d99e979e6001)) + +## [0.31.0](https://github.com/n0-computer/iroh-blobs/compare/v0.30.0..0.31.0) - 2025-01-14 + +### ⚙️ Miscellaneous Tasks + +- *(deps)* Bump mozilla-actions/sccache-action ([#40](https://github.com/n0-computer/iroh-blobs/issues/40)) - ([57112e6](https://github.com/n0-computer/iroh-blobs/commit/57112e62618e07a833a261b0dbfd2f64cc22eb82)) +- Add project tracking ([#43](https://github.com/n0-computer/iroh-blobs/issues/43)) - ([a279ad1](https://github.com/n0-computer/iroh-blobs/commit/a279ad1bc0472fb4e47df466ab73ed9e0fa0a50a)) +- Pin nextest version ([#44](https://github.com/n0-computer/iroh-blobs/issues/44)) - ([b1de3b3](https://github.com/n0-computer/iroh-blobs/commit/b1de3b306135984e113d09531beff9ed6463a778)) +- Upgrade to `iroh@v0.31.0` ([#45](https://github.com/n0-computer/iroh-blobs/issues/45)) - ([2b800c9](https://github.com/n0-computer/iroh-blobs/commit/2b800c9264b21dfb73bfecbe9881bc6c07c7e0d1)) + ## [0.30.0](https://github.com/n0-computer/iroh-blobs/compare/v0.29.0..0.30.0) - 2024-12-17 ### ⛰️ Features diff --git a/Cargo.lock b/Cargo.lock index fba9952a0..9a100a632 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,7 +51,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -125,19 +125,20 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "arc-swap" @@ -181,7 +182,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "synstructure", ] @@ -193,7 +194,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -216,18 +217,18 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "d556ec1359574147ec0c4fc5eb525f3f23263a592b1a9c07e0a75b427de55c97" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -318,14 +319,14 @@ dependencies = [ ] [[package]] -name = "backoff" -version = "0.4.0" +name = "backon" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +checksum = "49fef586913a57ff189f25c9b3d034356a5bf6b3fa9a7f067588fe1698ba1f5d" dependencies = [ - "getrandom", - "instant", - "rand", + "fastrand", + "gloo-timers", + "tokio", ] [[package]] @@ -350,7 +351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f7a89a8ee5889d2593ae422ce6e1bb03e48a0e8a16e4fa0882dfcbe7e182ef" dependencies = [ "bytes", - "futures-lite 2.5.0", + "futures-lite", "genawaiter", "iroh-blake3", "iroh-io", @@ -407,9 +408,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "block-buffer" @@ -422,15 +423,15 @@ dependencies = [ [[package]] name = "bounded-integer" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78a6932c88f1d2c29533a3b8a5f5a2f84cc19c3339b431677c3160c5c2e6ca85" +checksum = "102dbef1187b1893e6dfe05a774e79fd52265f49f214f6879c8ff49f52c8188b" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byteorder" @@ -440,9 +441,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" dependencies = [ "serde", ] @@ -480,9 +481,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.4" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "shlex", ] @@ -518,9 +519,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", @@ -528,7 +529,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -544,9 +545,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.23" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" dependencies = [ "clap_builder", "clap_derive", @@ -554,9 +555,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.23" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" dependencies = [ "anstream", "anstyle", @@ -566,14 +567,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -615,9 +616,9 @@ dependencies = [ [[package]] name = "console" -version = "0.15.10" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", "libc", @@ -644,7 +645,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec10f0a762d93c4498d2e97a333805cb6250d60bead623f71d8034f9a4152ba3" dependencies = [ - "loom", + "loom 0.5.6", "tracing", ] @@ -658,6 +659,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -666,9 +677,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -725,7 +736,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -737,7 +748,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "typenum", ] @@ -784,7 +795,7 @@ dependencies = [ "curve25519-dalek-derive", "digest", "fiat-crypto", - "rand_core", + "rand_core 0.6.4", "rustc_version", "serde", "subtle", @@ -799,7 +810,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -818,9 +829,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" [[package]] name = "der" @@ -830,6 +841,7 @@ checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "der_derive", + "pem-rfc7468", "zeroize", ] @@ -855,7 +867,7 @@ checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -884,7 +896,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "unicode-xid", ] @@ -914,7 +926,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -930,24 +942,18 @@ dependencies = [ [[package]] name = "document-features" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" dependencies = [ "litrs", ] [[package]] name = "dtoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" - -[[package]] -name = "dyn-clone" -version = "1.0.17" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" [[package]] name = "ecdsa" @@ -982,7 +988,7 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", - "rand_core", + "rand_core 0.6.4", "serde", "sha2", "subtle", @@ -1002,7 +1008,7 @@ dependencies = [ "generic-array", "group", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -1035,34 +1041,34 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "enumflags2" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" +checksum = "ba2f4b465f5318854c6f8dd686ede6c0a9dc67d4b1ac241cf0eb51521a309147" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" +checksum = "fc4caf64a58d7a6d65ab00639b046ff54399a39f5f2554728895ace4b297cd79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" @@ -1091,9 +1097,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" dependencies = [ "concurrent-queue", "parking", @@ -1116,15 +1122,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - [[package]] name = "fastrand" version = "2.3.0" @@ -1133,11 +1130,11 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "ff" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1147,12 +1144,6 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" -[[package]] -name = "fixedbitset" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" - [[package]] name = "flume" version = "0.11.1" @@ -1173,9 +1164,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "form_urlencoded" @@ -1203,14 +1194,15 @@ dependencies = [ [[package]] name = "futures-buffered" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34acda8ae8b63fbe0b2195c998b180cff89a8212fb2622a78b572a9f1c6f7684" +checksum = "fe940397c8b744b9c2c974791c2c08bca2c3242ce0290393249e98f215a00472" dependencies = [ "cordyceps", "diatomic-waker", "futures-core", "pin-project-lite", + "spin", ] [[package]] @@ -1223,21 +1215,6 @@ dependencies = [ "futures-sink", ] -[[package]] -name = "futures-concurrency" -version = "7.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b724496da7c26fcce66458526ce68fc2ecf4aaaa994281cf322ded5755520c" -dependencies = [ - "fixedbitset", - "futures-buffered", - "futures-core", - "futures-lite 1.13.0", - "pin-project", - "slab", - "smallvec", -] - [[package]] name = "futures-core" version = "0.3.31" @@ -1263,26 +1240,11 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-lite" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" dependencies = [ - "fastrand 2.3.0", + "fastrand", "futures-core", "futures-io", "parking", @@ -1297,7 +1259,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -1380,6 +1342,19 @@ dependencies = [ "windows 0.48.0", ] +[[package]] +name = "generator" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" +dependencies = [ + "cfg-if", + "libc", + "log", + "rustversion", + "windows 0.58.0", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1400,10 +1375,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + [[package]] name = "gimli" version = "0.31.1" @@ -1412,9 +1399,21 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] [[package]] name = "governor" @@ -1432,7 +1431,7 @@ dependencies = [ "parking_lot", "portable-atomic", "quanta", - "rand", + "rand 0.8.5", "smallvec", "spinning_top", ] @@ -1444,15 +1443,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] [[package]] name = "h2" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" dependencies = [ "atomic-waker", "bytes", @@ -1539,9 +1538,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hickory-proto" -version = "0.25.0-alpha.4" +version = "0.25.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d063c0692ee669aa6d261988aa19ca5510f1cc40e4f211024f50c888499a35d7" +checksum = "1d00147af6310f4392a31680db52a3ed45a2e0f68eb18e8c3fe5537ecc96d9e2" dependencies = [ "async-recursion", "async-trait", @@ -1554,8 +1553,8 @@ dependencies = [ "idna", "ipnet", "once_cell", - "rand", - "thiserror 2.0.7", + "rand 0.9.0", + "thiserror 2.0.12", "tinyvec", "tokio", "tracing", @@ -1564,9 +1563,9 @@ dependencies = [ [[package]] name = "hickory-resolver" -version = "0.25.0-alpha.4" +version = "0.25.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42bc352e4412fb657e795f79b4efcf2bd60b59ee5ca0187f3554194cd1107a27" +checksum = "5762f69ebdbd4ddb2e975cd24690bf21fe6b2604039189c26acddbc427f12887" dependencies = [ "cfg-if", "futures-util", @@ -1575,10 +1574,10 @@ dependencies = [ "moka", "once_cell", "parking_lot", - "rand", + "rand 0.9.0", "resolv-conf", "smallvec", - "thiserror 2.0.7", + "thiserror 2.0.12", "tokio", "tracing", ] @@ -1619,17 +1618,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "hostname" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" -dependencies = [ - "cfg-if", - "libc", - "windows 0.52.0", -] - [[package]] name = "hostname-validator" version = "1.1.1" @@ -1683,9 +1671,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -1695,9 +1683,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", @@ -1716,9 +1704,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.3" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http 1.2.0", @@ -1889,7 +1877,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -1928,7 +1916,7 @@ dependencies = [ "hyper", "hyper-util", "log", - "rand", + "rand 0.8.5", "tokio", "url", "xmltree", @@ -1936,9 +1924,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -1946,9 +1934,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.9" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", "number_prefix", @@ -1959,9 +1947,9 @@ dependencies = [ [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array", ] @@ -1982,6 +1970,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -1998,41 +1989,34 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iroh" -version = "0.30.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a59352a43dc4199fc804e1a7f3729bd14baff496fd3efbba98763e204bc4af0" +checksum = "6b7224d4eeec6c8b5b1a9b2347a4dff3588834a7fb17233044bff3e90e7b293d" dependencies = [ "aead", "anyhow", + "atomic-waker", "axum", - "backoff", - "base64", + "backon", "bytes", + "cfg_aliases", "concurrent-queue", "crypto_box", "data-encoding", "der", "derive_more", "ed25519-dalek", - "futures-buffered", - "futures-concurrency", - "futures-lite 2.5.0", - "futures-sink", "futures-util", - "governor", "hickory-resolver", - "hostname 0.4.0", "http 1.2.0", - "http-body-util", - "hyper", - "hyper-util", "igd-next", + "instant", "iroh-base", "iroh-metrics", "iroh-net-report", @@ -2040,66 +2024,50 @@ dependencies = [ "iroh-quinn-proto", "iroh-quinn-udp", "iroh-relay", - "libc", + "n0-future", "netdev", - "netlink-packet-core", - "netlink-packet-route 0.19.0", - "netlink-packet-route 0.21.0", - "netlink-sys", - "netwatch", - "num_enum", - "once_cell", + "netwatch 0.4.0", "pin-project", "pkarr", "portmapper", - "postcard", - "rand", + "rand 0.8.5", "rcgen", "reqwest", "ring", - "rtnetlink 0.13.1", - "rtnetlink 0.14.1", "rustls", "rustls-webpki", "serde", "smallvec", - "socket2", "strum", "stun-rs", - "surge-ping", "swarm-discovery", - "thiserror 2.0.7", + "thiserror 2.0.12", "time", "tokio", - "tokio-rustls", "tokio-stream", - "tokio-tungstenite", - "tokio-tungstenite-wasm", "tokio-util", "tracing", "url", + "wasm-bindgen-futures", "webpki-roots", - "windows 0.58.0", - "wmi", "x509-parser", "z32", ] [[package]] name = "iroh-base" -version = "0.30.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd4101e3f0732d901beb5461cb9bc415feeda8d21281ab5bf5c0c3458eebde2" +checksum = "02bf2374c0f1d01cde6e60de7505e42a604acda1a1bb3f7be19806e466055517" dependencies = [ "curve25519-dalek", "data-encoding", "derive_more", "ed25519-dalek", - "getrandom", "postcard", - "rand_core", + "rand_core 0.6.4", "serde", - "thiserror 2.0.7", + "thiserror 2.0.12", "url", ] @@ -2118,7 +2086,7 @@ dependencies = [ [[package]] name = "iroh-blobs" -version = "0.30.0" +version = "0.34.0" dependencies = [ "anyhow", "async-channel", @@ -2130,7 +2098,7 @@ dependencies = [ "data-encoding", "derive_more", "futures-buffered", - "futures-lite 2.5.0", + "futures-lite", "futures-util", "genawaiter", "hashlink", @@ -2143,7 +2111,6 @@ dependencies = [ "iroh-io", "iroh-metrics", "iroh-quinn", - "iroh-test", "nested_enum_utils", "num_cpus", "oneshot", @@ -2153,7 +2120,7 @@ dependencies = [ "proptest", "quic-rpc", "quic-rpc-derive", - "rand", + "rand 0.8.5", "range-collections", "rcgen", "redb", @@ -2170,12 +2137,13 @@ dependencies = [ "tempfile", "testdir", "testresult", - "thiserror 2.0.7", + "thiserror 2.0.12", "tokio", "tokio-util", "tracing", "tracing-futures", "tracing-subscriber", + "tracing-test", "walkdir", ] @@ -2186,7 +2154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17e302c5ad649c6a7aa9ae8468e1c4dc2469321af0c6de7341c1be1bdaab434b" dependencies = [ "bytes", - "futures-lite 2.5.0", + "futures-lite", "pin-project", "smallvec", "tokio", @@ -2194,47 +2162,46 @@ dependencies = [ [[package]] name = "iroh-metrics" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7efd9d7437db258f4d44852beea820cd872e4db976928ee0c2bc615b8c4fe5a" +checksum = "c0f7cd1ffe3b152a5f4f4c1880e01e07d96001f20e02cc143cb7842987c616b3" dependencies = [ "erased_set", "http-body-util", "hyper", "hyper-util", - "once_cell", "prometheus-client", "reqwest", "serde", "struct_iterable", - "thiserror 2.0.7", + "thiserror 2.0.12", "tokio", "tracing", ] [[package]] name = "iroh-net-report" -version = "0.30.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee04b3b957169e3833f08791802e6bd9878213655d1adbcd9191ea78b8d671a" +checksum = "63407d73331e8e38980be7e39b1db8e173fc28545b3ea0c48c9a718f95877b8e" dependencies = [ "anyhow", "bytes", + "cfg_aliases", "derive_more", - "futures-buffered", - "futures-lite 2.5.0", "hickory-resolver", "iroh-base", "iroh-metrics", "iroh-quinn", "iroh-relay", - "netwatch", + "n0-future", + "netwatch 0.4.0", "portmapper", - "rand", + "rand 0.8.5", "reqwest", "rustls", "surge-ping", - "thiserror 1.0.69", + "thiserror 2.0.12", "tokio", "tokio-util", "tracing", @@ -2243,46 +2210,52 @@ dependencies = [ [[package]] name = "iroh-quinn" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ba75a5c57cff299d2d7ca1ddee053f66339d1756bd79ec637bcad5aa61100e" +checksum = "76c6245c9ed906506ab9185e8d7f64857129aee4f935e899f398a3bd3b70338d" dependencies = [ "bytes", + "cfg_aliases", "iroh-quinn-proto", "iroh-quinn-udp", "pin-project-lite", "rustc-hash", "rustls", "socket2", - "thiserror 1.0.69", + "thiserror 2.0.12", "tokio", "tracing", + "web-time", ] [[package]] name = "iroh-quinn-proto" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2c869ba52683d3d067c83ab4c00a2fda18eaf13b1434d4c1352f428674d4a5d" +checksum = "929d5d8fa77d5c304d3ee7cae9aede31f13908bd049f9de8c7c0094ad6f7c535" dependencies = [ "bytes", - "rand", + "getrandom 0.2.15", + "rand 0.8.5", "ring", "rustc-hash", "rustls", + "rustls-pki-types", "rustls-platform-verifier", "slab", - "thiserror 1.0.69", + "thiserror 2.0.12", "tinyvec", "tracing", + "web-time", ] [[package]] name = "iroh-quinn-udp" -version = "0.5.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfcfc0abc2fdf8cf18a6c72893b7cbebeac2274a3b1306c1760c48c0e10ac5e0" +checksum = "c53afaa1049f7c83ea1331f5ebb9e6ebc5fdd69c468b7a22dd598b02c9bcc973" dependencies = [ + "cfg_aliases", "libc", "once_cell", "socket2", @@ -2292,24 +2265,20 @@ dependencies = [ [[package]] name = "iroh-relay" -version = "0.30.0" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0080c8d0720009dc5fa109ef2ead96c5aeb8bb8e4534de8f13865520818207" +checksum = "21d282c04a71a83a90b8fe6872ba30ae341853255aa908375a3e6181f7215d7b" dependencies = [ "anyhow", - "base64", "bytes", + "cfg_aliases", "clap", + "dashmap", "data-encoding", "derive_more", - "futures-buffered", - "futures-lite 2.5.0", - "futures-sink", - "futures-util", "governor", "hickory-proto", "hickory-resolver", - "hostname 0.4.0", "http 1.2.0", "http-body-util", "hyper", @@ -2318,28 +2287,26 @@ dependencies = [ "iroh-metrics", "iroh-quinn", "iroh-quinn-proto", - "libc", "lru", + "n0-future", "num_enum", - "once_cell", "pin-project", + "pkarr", "postcard", - "rand", + "rand 0.8.5", "rcgen", "regex", "reloadable-state", "reqwest", - "ring", "rustls", "rustls-cert-file-reader", "rustls-cert-reloadable-resolver", "rustls-pemfile", "rustls-webpki", "serde", - "smallvec", - "socket2", + "strum", "stun-rs", - "thiserror 2.0.7", + "thiserror 2.0.12", "time", "tokio", "tokio-rustls", @@ -2352,18 +2319,7 @@ dependencies = [ "tracing-subscriber", "url", "webpki-roots", -] - -[[package]] -name = "iroh-test" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "858814e2810a29cca50e5489f67dd417f38124315d466bf5420b1bedc6923703" -dependencies = [ - "anyhow", - "tokio", - "tracing", - "tracing-subscriber", + "z32", ] [[package]] @@ -2374,22 +2330,24 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jni" -version = "0.19.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ "cesu8", + "cfg-if", "combine", "jni-sys", "log", "thiserror 1.0.69", "walkdir", + "windows-sys 0.45.0", ] [[package]] @@ -2400,9 +2358,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -2419,9 +2377,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.168" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] name = "libm" @@ -2431,15 +2389,15 @@ checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" [[package]] name = "litemap" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" [[package]] name = "litrs" @@ -2459,9 +2417,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "loom" @@ -2470,39 +2428,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" dependencies = [ "cfg-if", - "generator", + "generator 0.7.5", "scoped-tls", "tracing", "tracing-subscriber", ] [[package]] -name = "lru" -version = "0.12.5" +name = "loom" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" dependencies = [ - "hashbrown 0.15.2", + "cfg-if", + "generator 0.8.4", + "scoped-tls", + "tracing", + "tracing-subscriber", ] [[package]] -name = "mainline" -version = "2.0.1" +name = "lru" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b751ffb57303217bcae8f490eee6044a5b40eadf6ca05ff476cad37e7b7970d" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "bytes", - "crc", - "ed25519-dalek", - "flume", - "lru", - "rand", - "serde", - "serde_bencode", - "serde_bytes", - "sha1_smol", - "thiserror 1.0.69", - "tracing", + "hashbrown 0.15.2", ] [[package]] @@ -2552,9 +2503,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" dependencies = [ "adler2", ] @@ -2566,37 +2517,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] [[package]] name = "moka" -version = "0.12.8" +version = "0.12.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32cf62eb4dd975d2dde76432fb1075c49e3ee2331cf36f1f8fd4b66550d32b6f" +checksum = "a9321642ca94a4282428e6ea4af8cc2ca4eac48ac7a6a4ea8f33f76d0ce70926" dependencies = [ "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", - "once_cell", + "loom 0.7.2", "parking_lot", - "quanta", + "portable-atomic", "rustc_version", "smallvec", "tagptr", "thiserror 1.0.69", - "triomphe", "uuid", ] +[[package]] +name = "n0-future" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "399e11dc3b0e8d9d65b27170d22f5d779d52d9bed888db70d7e0c2c7ce3dfc52" +dependencies = [ + "cfg_aliases", + "derive_more", + "futures-buffered", + "futures-lite", + "futures-util", + "js-sys", + "pin-project", + "send_wrapper", + "tokio", + "tokio-util", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-time", +] + [[package]] name = "nanorand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -2667,21 +2638,6 @@ dependencies = [ "netlink-packet-utils", ] -[[package]] -name = "netlink-packet-route" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "483325d4bfef65699214858f097d504eb812c38ce7077d165f301ec406c3066e" -dependencies = [ - "anyhow", - "bitflags 2.6.0", - "byteorder", - "libc", - "log", - "netlink-packet-core", - "netlink-packet-utils", -] - [[package]] name = "netlink-packet-utils" version = "0.5.2" @@ -2696,17 +2652,16 @@ dependencies = [ [[package]] name = "netlink-proto" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b33524dc0968bfad349684447bfce6db937a9ac3332a1fe60c0c5a5ce63f21" +checksum = "72452e012c2f8d612410d89eea01e2d9b56205274abb35d53f60200b2ec41d60" dependencies = [ "bytes", "futures", "log", "netlink-packet-core", "netlink-sys", - "thiserror 1.0.69", - "tokio", + "thiserror 2.0.12", ] [[package]] @@ -2724,15 +2679,15 @@ dependencies = [ [[package]] name = "netwatch" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "304c0c1b348830b016039f2cb1c5ac8217084a78875262c5594925dd08aa77fc" +checksum = "64da82edf903649e6cb6a77b5a6f7fe01387d8865065d411d139018510880302" dependencies = [ "anyhow", "atomic-waker", "bytes", "derive_more", - "futures-lite 2.5.0", + "futures-lite", "futures-sink", "futures-util", "iroh-quinn-udp", @@ -2746,7 +2701,7 @@ dependencies = [ "rtnetlink 0.14.1", "serde", "socket2", - "thiserror 2.0.7", + "thiserror 2.0.12", "time", "tokio", "tokio-util", @@ -2755,6 +2710,39 @@ dependencies = [ "wmi", ] +[[package]] +name = "netwatch" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7879c2cfdf30d92f2be89efa3169b3d78107e3ab7f7b9a37157782569314e1" +dependencies = [ + "atomic-waker", + "bytes", + "cfg_aliases", + "derive_more", + "iroh-quinn-udp", + "js-sys", + "libc", + "n0-future", + "netdev", + "netlink-packet-core", + "netlink-packet-route 0.19.0", + "netlink-sys", + "rtnetlink 0.13.1", + "rtnetlink 0.14.1", + "serde", + "socket2", + "thiserror 2.0.12", + "time", + "tokio", + "tokio-util", + "tracing", + "web-sys", + "windows 0.59.0", + "windows-result 0.3.1", + "wmi", +] + [[package]] name = "nix" version = "0.26.4" @@ -2772,7 +2760,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "cfg-if", "libc", ] @@ -2846,7 +2834,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.5", "smallvec", "zeroize", ] @@ -2915,7 +2903,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2926,9 +2914,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -2944,15 +2932,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "oneshot" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e296cf87e61c9cfc1a61c3c63a0f7f286ed4554e0e22be84e8a38e1d264a2a29" +checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea" [[package]] name = "opaque-debug" @@ -2962,9 +2950,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "overload" @@ -2986,9 +2974,9 @@ dependencies = [ [[package]] name = "p384" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" dependencies = [ "ecdsa", "elliptic-curve", @@ -3006,7 +2994,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "rand_core", + "rand_core 0.6.4", "sha2", ] @@ -3047,9 +3035,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pem" -version = "3.0.4" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" dependencies = [ "base64", "serde", @@ -3077,7 +3065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 2.0.7", + "thiserror 2.0.12", "ucd-trie", ] @@ -3101,7 +3089,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3117,29 +3105,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -3149,22 +3137,20 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkarr" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7945a08031b7e14de57e8385cea3bcc7e10a88701595dc11d82551ba07bae13e" +checksum = "92eff194c72f00f3076855b413ad2d940e3a6e307fa697e5c7733e738341aed4" dependencies = [ "bytes", "document-features", - "dyn-clone", "ed25519-dalek", "flume", "futures", "js-sys", "lru", - "mainline", "self_cell", "simple-dns", - "thiserror 1.0.69", + "thiserror 2.0.12", "tracing", "ureq", "wasm-bindgen", @@ -3212,7 +3198,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3249,32 +3235,31 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "portmapper" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6b2058e5b2c829b7dcc62bb94ec223e2fdf07cad157b09ab05c5520af6f5b6" +checksum = "b715da165f399be093fecb2ca774b00713a3b32f6b27e0752fbf255e3be622af" dependencies = [ - "anyhow", "base64", "bytes", "derive_more", - "futures-lite 2.5.0", + "futures-lite", "futures-util", "igd-next", "iroh-metrics", "libc", - "netwatch", + "netwatch 0.3.0", "num_enum", - "rand", + "rand 0.8.5", "serde", "smallvec", "socket2", - "thiserror 2.0.7", + "thiserror 2.0.12", "time", "tokio", "tokio-util", @@ -3325,11 +3310,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy", + "zerocopy 0.8.23", ] [[package]] @@ -3377,9 +3362,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ "toml_edit", ] @@ -3418,9 +3403,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] @@ -3445,7 +3430,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3456,11 +3441,11 @@ checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.6.0", + "bitflags 2.9.0", "lazy_static", "num-traits", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax 0.8.5", "rusty-fork", @@ -3470,30 +3455,30 @@ dependencies = [ [[package]] name = "quanta" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773ce68d0bb9bc7ef20be3536ffe94e223e1f365bd374108b2659fac0c65cfe6" +checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" dependencies = [ "crossbeam-utils", "libc", "once_cell", "raw-cpuid", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "web-sys", "winapi", ] [[package]] name = "quic-rpc" -version = "0.17.3" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8649f6353ef952672f35ddaf586c1a57152373f3d5b0767c5140b08f2d7ec6f8" +checksum = "89561e5343bcad1c9f84321d9d9bd1619128ad44293faad55a0001b0e52d312b" dependencies = [ "anyhow", "bytes", "document-features", "flume", - "futures-lite 2.5.0", + "futures-lite", "futures-sink", "futures-util", "iroh-quinn", @@ -3513,9 +3498,9 @@ dependencies = [ [[package]] name = "quic-rpc-derive" -version = "0.17.3" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a32e88a525c7616b2bfce4be94a875eeac46bf20faea5e580cb54dc739e64e5" +checksum = "0a99f334af6f23b3de91f6df9ac17237e8b533b676f596c69dcb3b58c3cf8dea" dependencies = [ "proc-macro2", "quic-rpc", @@ -3542,7 +3527,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.7", + "thiserror 2.0.12", "tokio", "tracing", ] @@ -3554,14 +3539,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", - "getrandom", - "rand", + "getrandom 0.2.15", + "rand 0.8.5", "ring", "rustc-hash", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.7", + "thiserror 2.0.12", "tinyvec", "tracing", "web-time", @@ -3569,9 +3554,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" +checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" dependencies = [ "cfg_aliases", "libc", @@ -3583,9 +3568,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" dependencies = [ "proc-macro2", ] @@ -3607,8 +3592,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy 0.8.23", ] [[package]] @@ -3618,7 +3614,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -3627,7 +3633,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", ] [[package]] @@ -3636,14 +3651,14 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[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", @@ -3653,18 +3668,18 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.2.0" +version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" +checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] name = "rcgen" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54077e1872c46788540de1ea3d7f4ccb1983d12f9aa909b234468676c1a36779" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" dependencies = [ "pem", "ring", @@ -3675,51 +3690,52 @@ dependencies = [ [[package]] name = "redb" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c2a94325f9c5826b17c42af11067230f503747f870117a28180e85696e21ba" +checksum = "ea0a72cd7140de9fc3e318823b883abf819c20d478ec89ce880466dc2ef263c6" dependencies = [ "libc", ] [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[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", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "reflink-copy" -version = "0.1.20" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17400ed684c3a0615932f00c271ae3eea13e47056a1455821995122348ab6438" +checksum = "4b86038e146b9a61557e1a2e58cdf2eddc0b46ce141b55541b1c1b9f3189d618" dependencies = [ "cfg-if", + "libc", "rustix", - "windows 0.58.0", + "windows 0.60.0", ] [[package]] @@ -3791,9 +3807,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "base64", "bytes", @@ -3822,10 +3838,13 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-rustls", + "tokio-util", + "tower", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots", "windows-registry", @@ -3837,7 +3856,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" dependencies = [ - "hostname 0.3.1", + "hostname", "quick-error", ] @@ -3853,15 +3872,14 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.8" +version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -3879,7 +3897,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sha2", "signature", "spki", @@ -3931,9 +3949,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc_version" @@ -3955,11 +3973,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.42" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys", @@ -3968,9 +3986,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.20" +version = "0.23.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ "log", "once_cell", @@ -3990,7 +4008,7 @@ dependencies = [ "rustls-cert-read", "rustls-pemfile", "rustls-pki-types", - "thiserror 2.0.7", + "thiserror 2.0.12", "tokio", ] @@ -4013,17 +4031,16 @@ dependencies = [ "reloadable-state", "rustls", "rustls-cert-read", - "thiserror 2.0.7", + "thiserror 2.0.12", ] [[package]] name = "rustls-native-certs" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ "openssl-probe", - "rustls-pemfile", "rustls-pki-types", "schannel", "security-framework", @@ -4040,20 +4057,20 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" dependencies = [ "web-time", ] [[package]] name = "rustls-platform-verifier" -version = "0.3.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" +checksum = "e012c45844a1790332c9386ed4ca3a06def221092eda277e6f079728f8ea99da" dependencies = [ - "core-foundation", + "core-foundation 0.10.0", "core-foundation-sys", "jni", "log", @@ -4064,8 +4081,8 @@ dependencies = [ "rustls-webpki", "security-framework", "security-framework-sys", - "webpki-roots", - "winapi", + "webpki-root-certs", + "windows-sys 0.52.0", ] [[package]] @@ -4087,9 +4104,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "rusty-fork" @@ -4105,9 +4122,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa20" @@ -4164,23 +4181,22 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ - "bitflags 2.6.0", - "core-foundation", + "bitflags 2.9.0", + "core-foundation 0.10.0", "core-foundation-sys", "libc", - "num-bigint", "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "2.12.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -4194,18 +4210,24 @@ checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe" [[package]] name = "semver" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "serde" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -4219,41 +4241,22 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_bencode" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a70dfc7b7438b99896e7f8992363ab8e2c4ba26aa5ec675d32d1c3c2c33d413e" -dependencies = [ - "serde", - "serde_bytes", -] - -[[package]] -name = "serde_bytes" -version = "0.11.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" -dependencies = [ - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -4263,9 +4266,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" dependencies = [ "itoa", "serde", @@ -4322,12 +4325,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sha1_smol" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" - [[package]] name = "sha2" version = "0.10.8" @@ -4370,16 +4367,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] name = "simple-dns" -version = "0.6.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01607fe2e61894468c6dc0b26103abb073fb08b79a3d9e4b6d76a1a341549958" +checksum = "dee851d0e5e7af3721faea1843e8015e820a234f81fda3dea9247e15bac9a86a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] @@ -4393,9 +4390,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" dependencies = [ "serde", ] @@ -4475,7 +4472,7 @@ dependencies = [ "p256", "p384", "p521", - "rand_core", + "rand_core 0.6.4", "rsa", "sec1", "sha2", @@ -4518,7 +4515,7 @@ dependencies = [ "proc-macro2", "quote", "struct_iterable_internal", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -4546,14 +4543,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "stun-rs" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79cc624c9a747353810310af44f1f03f71eb4561284a894acc0396e6d0de76e" +checksum = "c6a47cab181e04277c2ceebe9d4ae102f6a50049b1855fd64546923581665492" dependencies = [ "base64", "bounded-integer", @@ -4570,7 +4567,7 @@ dependencies = [ "precis-core", "precis-profiles", "quoted-string-parser", - "rand", + "rand 0.9.0", ] [[package]] @@ -4581,14 +4578,14 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "surge-ping" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbf95ce4c7c5b311d2ce3f088af2b93edef0f09727fa50fbe03c7a979afce77" +checksum = "6fda78103d8016bb25c331ddc54af634e801806463682cc3e549d335df644d95" dependencies = [ "hex", "parking_lot", "pnet_packet", - "rand", + "rand 0.9.0", "socket2", "thiserror 1.0.69", "tokio", @@ -4597,14 +4594,14 @@ dependencies = [ [[package]] name = "swarm-discovery" -version = "0.3.0-alpha.1" +version = "0.3.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b529764e2f746ef954505dd7cb3c03331bd678c52a387e4a86540577f41e45" +checksum = "6406a372c38c426a841d2c1095204dfb259229e3ab8080b1c4102f8966bedfcd" dependencies = [ "acto", "anyhow", "hickory-proto", - "rand", + "rand 0.8.5", "socket2", "tokio", "tracing", @@ -4623,9 +4620,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -4660,7 +4657,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -4683,8 +4680,8 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.6.0", - "core-foundation", + "bitflags 2.9.0", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -4706,12 +4703,13 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] name = "tempfile" -version = "3.14.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" dependencies = [ "cfg-if", - "fastrand 2.3.0", + "fastrand", + "getrandom 0.3.1", "once_cell", "rustix", "windows-sys 0.59.0", @@ -4749,11 +4747,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.7" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.7", + "thiserror-impl 2.0.12", ] [[package]] @@ -4764,18 +4762,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "thiserror-impl" -version = "2.0.7" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -4790,12 +4788,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8" dependencies = [ "deranged", "itoa", + "js-sys", "num-conv", "powerfmt", "serde", @@ -4805,15 +4804,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" dependencies = [ "num-conv", "time-core", @@ -4831,9 +4830,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -4846,15 +4845,14 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.42.0" +version = "1.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +checksum = "9975ea0f48b5aa3972bf2d888c238182458437cc2a19374b81b25cdf1023fb3a" dependencies = [ "backtrace", "bytes", "libc", "mio", - "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -4864,20 +4862,20 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "tokio-rustls" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ "rustls", "tokio", @@ -4903,7 +4901,7 @@ dependencies = [ "rustls", "serde", "serde_json", - "thiserror 2.0.7", + "thiserror 2.0.12", "time", "tokio", "tokio-rustls", @@ -4932,13 +4930,14 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", + "tokio-util", ] [[package]] name = "tokio-tungstenite" -version = "0.21.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", @@ -4948,9 +4947,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite-wasm" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e57a65894797a018b28345fa298a00c450a574aa9671e50b18218a6292a55ac" +checksum = "e21a5c399399c3db9f08d8297ac12b500e86bca82e930253fdc62eaf9c0de6ae" dependencies = [ "futures-channel", "futures-util", @@ -4982,9 +4981,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", @@ -5003,9 +5002,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", "serde", @@ -5062,7 +5061,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -5115,10 +5114,25 @@ dependencies = [ ] [[package]] -name = "triomphe" -version = "0.1.11" +name = "tracing-test" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" +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.100", +] [[package]] name = "try-lock" @@ -5128,9 +5142,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.21.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" dependencies = [ "byteorder", "bytes", @@ -5138,18 +5152,17 @@ dependencies = [ "http 1.2.0", "httparse", "log", - "rand", + "rand 0.8.5", "sha1", "thiserror 1.0.69", - "url", "utf-8", ] [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "ucd-parse" @@ -5174,9 +5187,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-normalization" @@ -5268,18 +5281,18 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" dependencies = [ - "getrandom", + "getrandom 0.3.1", ] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "version_check" @@ -5289,19 +5302,13 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ "libc", ] -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "walkdir" version = "2.5.0" @@ -5327,6 +5334,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasite" version = "0.1.0" @@ -5335,34 +5351,35 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.49" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", @@ -5373,9 +5390,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5383,28 +5400,44 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -5420,11 +5453,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09aed61f5e8d2c18344b3faa33a4c837855fe56642757754775548fee21386c4" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" -version = "0.26.7" +version = "0.26.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" dependencies = [ "rustls-pki-types", ] @@ -5488,22 +5530,44 @@ dependencies = [ [[package]] name = "windows" -version = "0.52.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core 0.52.0", + "windows-core 0.58.0", "windows-targets 0.52.6", ] [[package]] name = "windows" -version = "0.58.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", + "windows-core 0.59.0", + "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]] @@ -5521,13 +5585,49 @@ version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-strings", + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" +dependencies = [ + "windows-implement 0.59.0", + "windows-interface 0.59.0", + "windows-result 0.3.1", + "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.1", + "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" @@ -5536,7 +5636,18 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", +] + +[[package]] +name = "windows-implement" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] @@ -5547,7 +5658,34 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", +] + +[[package]] +name = "windows-interface" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "windows-link" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" + +[[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]] @@ -5556,8 +5694,8 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows-result", - "windows-strings", + "windows-result 0.2.0", + "windows-strings 0.1.0", "windows-targets 0.52.6", ] @@ -5570,16 +5708,43 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-strings" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" dependencies = [ - "windows-result", + "windows-result 0.2.0", "windows-targets 0.52.6", ] +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "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]] name = "windows-sys" version = "0.48.0" @@ -5607,6 +5772,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" @@ -5631,13 +5811,35 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[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" @@ -5650,6 +5852,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +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" @@ -5662,6 +5876,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +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" @@ -5674,12 +5900,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +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" @@ -5692,6 +5936,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +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" @@ -5704,6 +5960,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +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" @@ -5716,6 +5984,18 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +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" @@ -5728,11 +6008,17 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" dependencies = [ "memchr", ] @@ -5747,19 +6033,28 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.9.0", +] + [[package]] name = "wmi" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc47c0776cc6c00d2f7a874a0c846d94d45535936e5a1187693a24f23b4dd701" +checksum = "7787dacdd8e71cbc104658aade4009300777f9b5fda6a75f19145fedb8a18e71" dependencies = [ "chrono", "futures", "log", "serde", - "thiserror 2.0.7", - "windows 0.58.0", - "windows-core 0.58.0", + "thiserror 2.0.12", + "windows 0.59.0", + "windows-core 0.59.0", ] [[package]] @@ -5793,9 +6088,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432" +checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4" [[package]] name = "xmltree" @@ -5835,15 +6130,15 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "synstructure", ] [[package]] name = "z32" -version = "1.1.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb37266251c28b03d08162174a91c3a092e3bd4f476f8205ee1c507b78b7bdc" +checksum = "2164e798d9e3d84ee2c91139ace54638059a3b23e361f5c11781c2c6459bde0f" [[package]] name = "zerocopy" @@ -5851,8 +6146,16 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +dependencies = [ + "zerocopy-derive 0.8.23", ] [[package]] @@ -5863,27 +6166,38 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "synstructure", ] @@ -5912,5 +6226,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] diff --git a/Cargo.toml b/Cargo.toml index 0dd096a77..d7fbfe83e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iroh-blobs" -version = "0.30.0" +version = "0.34.0" edition = "2021" readme = "README.md" description = "blob and collection transfer support for iroh" @@ -40,10 +40,10 @@ genawaiter = { version = "0.99.1", features = ["futures03"] } hashlink = { version = "0.9.0", optional = true } hex = "0.4.3" indicatif = { version = "0.17.8", optional = true } -iroh-base = { version = "0.30" } +iroh-base = { version = "0.34" } iroh-io = { version = "0.6.0", features = ["stats"] } -iroh-metrics = { version = "0.30.0", default-features = false } -iroh = "0.30" +iroh-metrics = { version = "0.32", default-features = false } +iroh = "0.34" nested_enum_utils = { version = "0.1.0", optional = true } num_cpus = "1.15.0" oneshot = "0.1.8" @@ -54,9 +54,8 @@ postcard = { version = "1", default-features = false, features = [ "use-std", "experimental-derive", ] } -quic-rpc = { version = "0.17.3", optional = true } -quic-rpc-derive = { version = "0.17", optional = true } -quinn = { package = "iroh-quinn", version = "0.12", features = ["ring"] } +quic-rpc = { version = "0.19", optional = true } +quic-rpc-derive = { version = "0.19", optional = true } rand = "0.8" range-collections = "0.4.0" redb = { version = "2.2.0", optional = true } @@ -77,11 +76,12 @@ walkdir = { version = "2.5.0", optional = true } # Examples console = { version = "0.15.8", optional = true } +tracing-test = "0.2.5" [dev-dependencies] http-body = "1.0" -iroh-test = { version = "0.30" } -iroh = { version = "0.30", features = ["test-utils"] } +iroh = { version = "0.34", features = ["test-utils"] } +quinn = { package = "iroh-quinn", version = "0.13", features = ["ring"] } futures-buffered = "0.2.4" proptest = "1.0.0" serde_json = "1.0.107" @@ -96,7 +96,7 @@ futures-util = "0.3.30" testdir = "0.9.1" [features] -default = ["fs-store", "net_protocol"] +default = ["fs-store", "net_protocol", "rpc"] downloader = ["dep:parking_lot", "tokio-util/time", "dep:hashlink"] net_protocol = ["downloader", "dep:futures-util"] fs-store = ["dep:reflink-copy", "redb", "dep:tempfile"] @@ -149,7 +149,7 @@ name = "hello-world-provide" required-features = ["example-iroh"] [[example]] -name = "local-swarm-discovery" +name = "discovery-local-network" required-features = ["example-iroh"] [[example]] diff --git a/README.md b/README.md index 2193daae4..e93564fa4 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,18 @@ # iroh-blobs -This crate provides blob and collection transfer support for iroh. It implements a simple request-response protocol based on blake3 verified streaming. +This crate provides blob and blob sequence transfer support for iroh. It implements a simple request-response protocol based on BLAKE3 verified streaming. -A request describes data in terms of blake3 hashes and byte ranges. It is possible to -request blobs or ranges of blobs, as well as collections. +A request describes data in terms of BLAKE3 hashes and byte ranges. It is possible to request blobs or ranges of blobs, as well as entire sequences of blobs in one request. -The requester opens a quic stream to the provider and sends the request. The provider answers with the requested data, encoded as [blake3](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) verified streams, on the same quic stream. +The requester opens a QUIC stream to the provider and sends the request. The provider answers with the requested data, encoded as [BLAKE3](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) verified streams, on the same QUIC stream. -This crate is usually used together with [iroh](https://crates.io/crates/iroh), but can also be used with normal [quinn](https://crates.io/crates/quinn) connections. Connection establishment is left up to the user or a higher level APIs such as the iroh CLI. +This crate is used together with [iroh](https://crates.io/crates/iroh). Connection establishment is left up to the user or higher level APIs. ## Concepts - **Blob:** a sequence of bytes of arbitrary size, without any metadata. -- **Link:** a 32 byte blake3 hash of a blob. +- **Link:** a 32 byte BLAKE3 hash of a blob. - **HashSeq:** a blob that contains a sequence of links. Its size is a multiple of 32. @@ -32,7 +31,7 @@ Here is a basic example of how to set up `iroh-blobs` with `iroh`: ```rust use iroh::{protocol::Router, Endpoint}; -use iroh_blobs::{net_protocol::Blobs, util::local_pool::LocalPool}; +use iroh_blobs::{store::Store, net_protocol::Blobs}; #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -40,14 +39,10 @@ async fn main() -> anyhow::Result<()> { // we've built at number0 let endpoint = Endpoint::builder().discovery_n0().bind().await?; - // spawn a local pool with one thread per CPU - // for a single threaded pool use `LocalPool::single` - let local_pool = LocalPool::default(); - // create an in-memory blob store // use `iroh_blobs::net_protocol::Blobs::persistent` to load or create a // persistent blob store from a path - let blobs = Blobs::memory().build(local_pool.handle(), &endpoint); + let blobs = Blobs::memory().build(&endpoint); // turn on the "rpc" feature if you need to create blobs and tags clients let blobs_client = blobs.client(); @@ -60,9 +55,7 @@ async fn main() -> anyhow::Result<()> { .await?; // do fun stuff with the blobs protocol! - // make sure not to drop the local_pool before you are finished router.shutdown().await?; - drop(local_pool); drop(tags_client); Ok(()) } @@ -70,8 +63,7 @@ async fn main() -> anyhow::Result<()> { ## Examples -Examples that use `iroh-blobs` can be found in the `iroh` crate. the iroh crate publishes `iroh_blobs` as `iroh::bytes`. - +Examples that use `iroh-blobs` can be found in [this repo](https://github.com/n0-computer/iroh-blobs/tree/main/examples). # License @@ -89,4 +81,3 @@ at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. - diff --git a/deny.toml b/deny.toml index 28b26fe72..fd814582d 100644 --- a/deny.toml +++ b/deny.toml @@ -17,7 +17,6 @@ allow = [ "BSL-1.0", # BOSL license "ISC", "MIT", - "OpenSSL", "Zlib", "MPL-2.0", # https://fossa.com/blog/open-source-software-licenses-101-mozilla-public-license-2-0/ "Unicode-3.0" @@ -32,8 +31,9 @@ license-files = [ [advisories] ignore = [ - "RUSTSEC-2024-0370", # unmaintained, no upgrade available - "RUSTSEC-2024-0384", # unmaintained, no upgrade available + "RUSTSEC-2024-0370", # unmaintained, no upgrade available + "RUSTSEC-2024-0384", # unmaintained, no upgrade available + "RUSTSEC-2024-0436", # unmaintained paste ] [sources] diff --git a/examples/connect/mod.rs b/examples/connect/mod.rs deleted file mode 100644 index acb5481f0..000000000 --- a/examples/connect/mod.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! Common code used to created quinn connections in the examples -use std::{path::PathBuf, sync::Arc}; - -use anyhow::{bail, Context, Result}; -use quinn::crypto::rustls::{QuicClientConfig, QuicServerConfig}; -use rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer}; -use tokio::fs; - -pub const EXAMPLE_ALPN: &[u8] = b"n0/iroh/examples/bytes/0"; - -// Path where the tls certificates are saved. This example expects that you have run the `provide-bytes` example first, which generates the certificates. -pub const CERT_PATH: &str = "./certs"; - -// derived from `quinn/examples/client.rs` -// load the certificates from CERT_PATH -// Assumes that you have already run the `provide-bytes` example, that generates the certificates -#[allow(unused)] -pub async fn load_certs() -> Result { - let mut roots = rustls::RootCertStore::empty(); - let path = PathBuf::from(CERT_PATH).join("cert.der"); - match fs::read(path).await { - Ok(cert) => { - roots.add(rustls::pki_types::CertificateDer::from(cert))?; - } - Err(e) => { - bail!("failed to open local server certificate: {}\nYou must run the `provide-bytes` example to create the certificate.\n\tcargo run --example provide-bytes", e); - } - } - Ok(roots) -} - -// derived from `quinn/examples/server.rs` -// creates a self signed certificate and saves it to "./certs" -#[allow(unused)] -pub async fn make_and_write_certs() -> Result<( - rustls::pki_types::PrivateKeyDer<'static>, - rustls::pki_types::CertificateDer<'static>, -)> { - let path = std::path::PathBuf::from(CERT_PATH); - let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap(); - let key_path = path.join("key.der"); - let cert_path = path.join("cert.der"); - - let key = PrivatePkcs8KeyDer::from(cert.key_pair.serialize_der()); - let cert: CertificateDer = cert.cert.into(); - tokio::fs::create_dir_all(path) - .await - .context("failed to create certificate directory")?; - tokio::fs::write(cert_path, &cert) - .await - .context("failed to write certificate")?; - tokio::fs::write(key_path, key.secret_pkcs8_der()) - .await - .context("failed to write private key")?; - - Ok((rustls::pki_types::PrivateKeyDer::from(key), cert)) -} - -// derived from `quinn/examples/client.rs` -// Creates a client quinn::Endpoint -#[allow(unused)] -pub fn make_client_endpoint(roots: rustls::RootCertStore) -> Result { - let mut client_crypto = rustls::ClientConfig::builder() - .with_root_certificates(roots) - .with_no_client_auth(); - - client_crypto.alpn_protocols = vec![EXAMPLE_ALPN.to_vec()]; - let client_config: QuicClientConfig = client_crypto.try_into()?; - let client_config = quinn::ClientConfig::new(Arc::new(client_config)); - let mut endpoint = quinn::Endpoint::client("[::]:0".parse().unwrap())?; - endpoint.set_default_client_config(client_config); - Ok(endpoint) -} - -// derived from `quinn/examples/server.rs` -// makes a quinn server endpoint -#[allow(unused)] -pub fn make_server_endpoint( - key: rustls::pki_types::PrivateKeyDer<'static>, - cert: rustls::pki_types::CertificateDer<'static>, -) -> Result { - let mut server_crypto = rustls::ServerConfig::builder() - .with_no_client_auth() - .with_single_cert(vec![cert], key)?; - server_crypto.alpn_protocols = vec![EXAMPLE_ALPN.to_vec()]; - let server_config: QuicServerConfig = server_crypto.try_into()?; - let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(server_config)); - let transport_config = Arc::get_mut(&mut server_config.transport).unwrap(); - transport_config.max_concurrent_uni_streams(0_u8.into()); - - let endpoint = quinn::Endpoint::server(server_config, "[::1]:4433".parse()?)?; - Ok(endpoint) -} diff --git a/examples/custom-protocol.rs b/examples/custom-protocol.rs index 31b246f70..2537562fe 100644 --- a/examples/custom-protocol.rs +++ b/examples/custom-protocol.rs @@ -44,13 +44,11 @@ use anyhow::Result; use clap::Parser; use futures_lite::future::Boxed as BoxedFuture; use iroh::{ - endpoint::{get_remote_node_id, Connecting}, + endpoint::Connection, protocol::{ProtocolHandler, Router}, Endpoint, NodeId, }; -use iroh_blobs::{ - net_protocol::Blobs, rpc::client::blobs::MemClient, util::local_pool::LocalPool, Hash, -}; +use iroh_blobs::{net_protocol::Blobs, rpc::client::blobs::MemClient, Hash}; use tracing_subscriber::{prelude::*, EnvFilter}; #[derive(Debug, Parser)] @@ -89,8 +87,7 @@ async fn main() -> Result<()> { // Build a in-memory node. For production code, you'd want a persistent node instead usually. let endpoint = Endpoint::builder().bind().await?; let builder = Router::builder(endpoint); - let local_pool = LocalPool::default(); - let blobs = Blobs::memory().build(local_pool.handle(), builder.endpoint()); + let blobs = Blobs::memory().build(builder.endpoint()); let builder = builder.accept(iroh_blobs::ALPN, blobs.clone()); let blobs_client = blobs.client(); @@ -145,14 +142,12 @@ impl ProtocolHandler for BlobSearch { /// /// The returned future runs on a newly spawned tokio task, so it can run as long as /// the connection lasts. - fn accept(&self, connecting: Connecting) -> BoxedFuture> { + fn accept(&self, connection: Connection) -> BoxedFuture> { let this = self.clone(); // We have to return a boxed future from the handler. Box::pin(async move { - // Wait for the connection to be fully established. - let connection = connecting.await?; // We can get the remote's node id from the connection. - let node_id = get_remote_node_id(&connection)?; + let node_id = connection.remote_node_id()?; println!("accepted connection from {node_id}"); // Our protocol is a simple request-response protocol, so we expect the @@ -228,7 +223,7 @@ impl BlobSearch { match recv.read_exact(&mut hash_bytes).await { // FinishedEarly means that the remote side did not send further data, // so in this case we break our loop. - Err(quinn::ReadExactError::FinishedEarly(_)) => break, + Err(iroh::endpoint::ReadExactError::FinishedEarly(_)) => break, // Other errors are connection errors, so we bail. Err(err) => return Err(err.into()), Ok(_) => {} diff --git a/examples/local-swarm-discovery.rs b/examples/discovery-local-network.rs similarity index 91% rename from examples/local-swarm-discovery.rs rename to examples/discovery-local-network.rs index ccbb93043..44ef6e9b7 100644 --- a/examples/local-swarm-discovery.rs +++ b/examples/discovery-local-network.rs @@ -1,21 +1,19 @@ //! Example that runs and iroh node with local node discovery and no relay server //! //! Run the follow command to run the "accept" side, that hosts the content: -//! $ cargo run --example local_swarm_discovery --features="discovery-local-network" -- accept [FILE_PATH] +//! $ cargo run --example discovery_local_network --features="discovery-local-network" -- accept [FILE_PATH] //! Wait for output that looks like the following: -//! $ cargo run --example local_swarm_discovery --features="discovery-local-network" -- connect [NODE_ID] [HASH] -o [FILE_PATH] +//! $ cargo run --example discovery_local_network --features="discovery-local-network" -- connect [NODE_ID] [HASH] -o [FILE_PATH] //! Run that command on another machine in the same local network, replacing [FILE_PATH] to the path on which you want to save the transferred content. use std::path::PathBuf; use anyhow::ensure; use clap::{Parser, Subcommand}; use iroh::{ - discovery::local_swarm_discovery::LocalSwarmDiscovery, protocol::Router, Endpoint, NodeAddr, - PublicKey, RelayMode, SecretKey, -}; -use iroh_blobs::{ - net_protocol::Blobs, rpc::client::blobs::WrapOption, util::local_pool::LocalPool, Hash, + discovery::mdns::MdnsDiscovery, protocol::Router, Endpoint, NodeAddr, PublicKey, RelayMode, + SecretKey, }; +use iroh_blobs::{net_protocol::Blobs, rpc::client::blobs::WrapOption, Hash}; use tracing_subscriber::{prelude::*, EnvFilter}; use self::progress::show_download_progress; @@ -62,9 +60,9 @@ async fn main() -> anyhow::Result<()> { let cli = Cli::parse(); let key = SecretKey::generate(rand::rngs::OsRng); - let discovery = LocalSwarmDiscovery::new(key.public())?; + let discovery = MdnsDiscovery::new(key.public())?; - println!("Starting iroh node with local node discovery..."); + println!("Starting iroh node with mdns discovery..."); // create a new node let endpoint = Endpoint::builder() .secret_key(key) @@ -73,8 +71,7 @@ async fn main() -> anyhow::Result<()> { .bind() .await?; let builder = Router::builder(endpoint); - let local_pool = LocalPool::default(); - let blobs = Blobs::memory().build(local_pool.handle(), builder.endpoint()); + let blobs = Blobs::memory().build(builder.endpoint()); let builder = builder.accept(iroh_blobs::ALPN, blobs.clone()); let node = builder.spawn().await?; let blobs_client = blobs.client(); @@ -97,7 +94,7 @@ async fn main() -> anyhow::Result<()> { ) .await?; let outcome = stream.finish().await?; - println!("To fetch the blob:\n\tcargo run --example local_swarm_discovery --features=\"local-swarm-discovery\" -- connect {} {} -o [FILE_PATH]", node.endpoint().node_id(), outcome.hash); + println!("To fetch the blob:\n\tcargo run --example discovery_local_network --features=\"discovery-local-network\" -- connect {} {} -o [FILE_PATH]", node.endpoint().node_id(), outcome.hash); tokio::signal::ctrl_c().await?; node.shutdown().await?; std::process::exit(0); diff --git a/examples/fetch-fsm.rs b/examples/fetch-fsm.rs index 6c7379b3a..4e0422043 100644 --- a/examples/fetch-fsm.rs +++ b/examples/fetch-fsm.rs @@ -3,20 +3,19 @@ //! Since this example does not use [`iroh-net::Endpoint`], it does not do any holepunching, and so will only work locally or between two processes that have public IP addresses. //! //! Run the provide-bytes example first. It will give instructions on how to run this example properly. -use std::net::SocketAddr; +use std::str::FromStr; use anyhow::{Context, Result}; use iroh_blobs::{ get::fsm::{AtInitial, ConnectedNext, EndBlobNext}, hashseq::HashSeq, protocol::GetRequest, - Hash, + BlobFormat, }; use iroh_io::ConcatenateSliceWriter; use tracing_subscriber::{prelude::*, EnvFilter}; -mod connect; -use connect::{load_certs, make_client_endpoint}; +const EXAMPLE_ALPN: &[u8] = b"n0/iroh/examples/bytes/0"; // set the RUST_LOG env var to one of {debug,info,warn} to see logging info pub fn setup_logging() { @@ -29,50 +28,49 @@ pub fn setup_logging() { #[tokio::main] async fn main() -> Result<()> { - println!("\nfetch bytes example!"); + println!("\nfetch fsm example!"); setup_logging(); let args: Vec<_> = std::env::args().collect(); - if args.len() != 4 { - anyhow::bail!("usage: fetch-bytes [HASH] [SOCKET_ADDR] [FORMAT]"); + if args.len() != 2 { + anyhow::bail!("usage: fetch-fsm [TICKET]"); } - let hash: Hash = args[1].parse().context("unable to parse [HASH]")?; - let addr: SocketAddr = args[2].parse().context("unable to parse [SOCKET_ADDR]")?; - let format = { - if args[3] != "blob" && args[3] != "collection" { - anyhow::bail!( - "expected either 'blob' or 'collection' for FORMAT argument, got {}", - args[3] - ); - } - args[3].clone() - }; + let ticket = + iroh_blobs::ticket::BlobTicket::from_str(&args[1]).context("unable to parse [TICKET]")?; - // load tls certificates - // This will error if you have not run the `provide-bytes` example - let roots = load_certs().await?; + let (node, hash, format) = ticket.into_parts(); // create an endpoint to listen for incoming connections - let endpoint = make_client_endpoint(roots)?; - println!("\nlistening on {}", endpoint.local_addr()?); - println!("fetching hash {hash} from {addr}"); + let endpoint = iroh::Endpoint::builder() + .relay_mode(iroh::RelayMode::Disabled) + .alpns(vec![EXAMPLE_ALPN.into()]) + .bind() + .await?; + println!( + "\nlistening on {:?}", + endpoint.node_addr().await?.direct_addresses + ); + println!("fetching hash {hash} from {:?}", node.node_id); // connect - let connection = endpoint.connect(addr, "localhost")?.await?; - - if format == "collection" { - // create a request for a collection - let request = GetRequest::all(hash); - // create the initial state of the finite state machine - let initial = iroh_blobs::get::fsm::start(connection, request); - - write_collection(initial).await - } else { - // create a request for a single blob - let request = GetRequest::single(hash); - // create the initial state of the finite state machine - let initial = iroh_blobs::get::fsm::start(connection, request); - - write_blob(initial).await + let connection = endpoint.connect(node, EXAMPLE_ALPN).await?; + + match format { + BlobFormat::HashSeq => { + // create a request for a collection + let request = GetRequest::all(hash); + // create the initial state of the finite state machine + let initial = iroh_blobs::get::fsm::start(connection, request); + + write_collection(initial).await + } + BlobFormat::Raw => { + // create a request for a single blob + let request = GetRequest::single(hash); + // create the initial state of the finite state machine + let initial = iroh_blobs::get::fsm::start(connection, request); + + write_blob(initial).await + } } } diff --git a/examples/fetch-stream.rs b/examples/fetch-stream.rs index 6b50d55f9..f9405abca 100644 --- a/examples/fetch-stream.rs +++ b/examples/fetch-stream.rs @@ -3,7 +3,7 @@ //! Since this example does not use [`iroh-net::Endpoint`], it does not do any holepunching, and so will only work locally or between two processes that have public IP addresses. //! //! Run the provide-bytes example first. It will give instructions on how to run this example properly. -use std::{io, net::SocketAddr}; +use std::{io, str::FromStr}; use anyhow::{Context, Result}; use bao_tree::io::fsm::BaoContentItem; @@ -14,13 +14,12 @@ use iroh_blobs::{ get::fsm::{AtInitial, BlobContentNext, ConnectedNext, EndBlobNext}, hashseq::HashSeq, protocol::GetRequest, - Hash, + BlobFormat, }; use tokio::io::AsyncWriteExt; use tracing_subscriber::{prelude::*, EnvFilter}; -mod connect; -use connect::{load_certs, make_client_endpoint}; +const EXAMPLE_ALPN: &[u8] = b"n0/iroh/examples/bytes/0"; // set the RUST_LOG env var to one of {debug,info,warn} to see logging info pub fn setup_logging() { @@ -36,51 +35,50 @@ async fn main() -> Result<()> { println!("\nfetch stream example!"); setup_logging(); let args: Vec<_> = std::env::args().collect(); - if args.len() != 4 { - anyhow::bail!("usage: fetch-bytes [HASH] [SOCKET_ADDR] [FORMAT]"); + if args.len() != 2 { + anyhow::bail!("usage: fetch-stream [TICKET]"); } - let hash: Hash = args[1].parse().context("unable to parse [HASH]")?; - let addr: SocketAddr = args[2].parse().context("unable to parse [SOCKET_ADDR]")?; - let format = { - if args[3] != "blob" && args[3] != "collection" { - anyhow::bail!( - "expected either 'blob' or 'collection' for FORMAT argument, got {}", - args[3] - ); - } - args[3].clone() - }; + let ticket = + iroh_blobs::ticket::BlobTicket::from_str(&args[1]).context("unable to parse [TICKET]")?; - // load tls certificates - // This will error if you have not run the `provide-bytes` example - let roots = load_certs().await?; + let (node, hash, format) = ticket.into_parts(); // create an endpoint to listen for incoming connections - let endpoint = make_client_endpoint(roots)?; - println!("\nlistening on {}", endpoint.local_addr()?); - println!("fetching hash {hash} from {addr}"); + let endpoint = iroh::Endpoint::builder() + .relay_mode(iroh::RelayMode::Disabled) + .alpns(vec![EXAMPLE_ALPN.into()]) + .bind() + .await?; + println!( + "\nlistening on {:?}", + endpoint.node_addr().await?.direct_addresses + ); + println!("fetching hash {hash} from {:?}", node.node_id); // connect - let connection = endpoint.connect(addr, "localhost")?.await?; + let connection = endpoint.connect(node, EXAMPLE_ALPN).await?; - let mut stream = if format == "collection" { - // create a request for a collection - let request = GetRequest::all(hash); + let mut stream = match format { + BlobFormat::HashSeq => { + // create a request for a collection + let request = GetRequest::all(hash); - // create the initial state of the finite state machine - let initial = iroh_blobs::get::fsm::start(connection, request); + // create the initial state of the finite state machine + let initial = iroh_blobs::get::fsm::start(connection, request); - // create a stream that yields all the data of the blob - stream_children(initial).boxed_local() - } else { - // create a request for a single blob - let request = GetRequest::single(hash); + // create a stream that yields all the data of the blob + stream_children(initial).boxed_local() + } + BlobFormat::Raw => { + // create a request for a single blob + let request = GetRequest::single(hash); - // create the initial state of the finite state machine - let initial = iroh_blobs::get::fsm::start(connection, request); + // create the initial state of the finite state machine + let initial = iroh_blobs::get::fsm::start(connection, request); - // create a stream that yields all the data of the blob - stream_blob(initial).boxed_local() + // create a stream that yields all the data of the blob + stream_blob(initial).boxed_local() + } }; while let Some(item) = stream.next().await { let item = item?; diff --git a/examples/hello-world-fetch.rs b/examples/hello-world-fetch.rs index d8fb68955..74c494c46 100644 --- a/examples/hello-world-fetch.rs +++ b/examples/hello-world-fetch.rs @@ -7,9 +7,7 @@ use std::{env, str::FromStr}; use anyhow::{bail, ensure, Context, Result}; use iroh::{protocol::Router, Endpoint}; -use iroh_blobs::{ - net_protocol::Blobs, ticket::BlobTicket, util::local_pool::LocalPool, BlobFormat, -}; +use iroh_blobs::{net_protocol::Blobs, ticket::BlobTicket, BlobFormat}; use tracing_subscriber::{prelude::*, EnvFilter}; // set the RUST_LOG env var to one of {debug,info,warn} to see logging info @@ -39,8 +37,7 @@ async fn main() -> Result<()> { // create a new node let endpoint = Endpoint::builder().bind().await?; let builder = Router::builder(endpoint); - let local_pool = LocalPool::default(); - let blobs = Blobs::memory().build(local_pool.handle(), builder.endpoint()); + let blobs = Blobs::memory().build(builder.endpoint()); let builder = builder.accept(iroh_blobs::ALPN, blobs.clone()); let node = builder.spawn().await?; let blobs_client = blobs.client(); diff --git a/examples/hello-world-provide.rs b/examples/hello-world-provide.rs index cd614dd9b..aa9fc7737 100644 --- a/examples/hello-world-provide.rs +++ b/examples/hello-world-provide.rs @@ -4,7 +4,7 @@ //! run this example from the project root: //! $ cargo run --example hello-world-provide use iroh::{protocol::Router, Endpoint}; -use iroh_blobs::{net_protocol::Blobs, ticket::BlobTicket, util::local_pool::LocalPool}; +use iroh_blobs::{net_protocol::Blobs, ticket::BlobTicket}; use tracing_subscriber::{prelude::*, EnvFilter}; // set the RUST_LOG env var to one of {debug,info,warn} to see logging info @@ -24,8 +24,7 @@ async fn main() -> anyhow::Result<()> { // create a new node let endpoint = Endpoint::builder().bind().await?; let builder = Router::builder(endpoint); - let local_pool = LocalPool::default(); - let blobs = Blobs::memory().build(local_pool.handle(), builder.endpoint()); + let blobs = Blobs::memory().build(builder.endpoint()); let builder = builder.accept(iroh_blobs::ALPN, blobs.clone()); let blobs_client = blobs.client(); let node = builder.spawn().await?; diff --git a/examples/provide-bytes.rs b/examples/provide-bytes.rs index 98146f28c..7f120ed3b 100644 --- a/examples/provide-bytes.rs +++ b/examples/provide-bytes.rs @@ -10,12 +10,11 @@ //! cargo run --example provide-bytes collection //! To provide a collection (multiple blobs) use anyhow::Result; -use iroh_blobs::{format::collection::Collection, util::local_pool::LocalPool, Hash}; +use iroh_blobs::{format::collection::Collection, util::local_pool::LocalPool, BlobFormat, Hash}; use tracing::warn; use tracing_subscriber::{prelude::*, EnvFilter}; -mod connect; -use connect::{make_and_write_certs, make_server_endpoint, CERT_PATH}; +const EXAMPLE_ALPN: &[u8] = b"n0/iroh/examples/bytes/0"; // set the RUST_LOG env var to one of {debug,info,warn} to see logging info pub fn setup_logging() { @@ -45,7 +44,7 @@ async fn main() -> Result<()> { }; println!("\nprovide bytes {format} example!"); - let (db, hash) = if format == "collection" { + let (db, hash, format) = if format == "collection" { let (mut db, names) = iroh_blobs::store::readonly_mem::Store::new([ ("blob1", b"the first blob of bytes".to_vec()), ("blob2", b"the second blob of bytes".to_vec()), @@ -56,7 +55,7 @@ async fn main() -> Result<()> { .collect(); // add it to the db let hash = db.insert_many(collection.to_blobs()).unwrap(); - (db, hash) + (db, hash, BlobFormat::HashSeq) } else { // create a new database and add a blob let (db, names) = @@ -64,20 +63,23 @@ async fn main() -> Result<()> { // get the hash of the content let hash = names.get("hello").unwrap(); - (db, Hash::from(hash.as_bytes())) + (db, Hash::from(hash.as_bytes()), BlobFormat::Raw) }; - // create tls certs and save to CERT_PATH - let (key, cert) = make_and_write_certs().await?; - // create an endpoint to listen for incoming connections - let endpoint = make_server_endpoint(key, cert)?; - let addr = endpoint.local_addr()?; - println!("\nlistening on {addr}"); + let endpoint = iroh::Endpoint::builder() + .relay_mode(iroh::RelayMode::Disabled) + .alpns(vec![EXAMPLE_ALPN.into()]) + .bind() + .await?; + let addr = endpoint.node_addr().await?; + println!("\nlistening on {:?}", addr.direct_addresses); println!("providing hash {hash}"); - println!("\nfetch the content using a finite state machine by running the following example:\n\ncargo run --example fetch-fsm {hash} \"{addr}\" {format}"); - println!("\nfetch the content using a stream by running the following example:\n\ncargo run --example fetch-stream {hash} \"{addr}\" {format}\n"); + let ticket = iroh_blobs::ticket::BlobTicket::new(addr, hash, format)?; + + println!("\nfetch the content using a finite state machine by running the following example:\n\ncargo run --example fetch-fsm {ticket}"); + println!("\nfetch the content using a stream by running the following example:\n\ncargo run --example fetch-stream {ticket}\n"); // create a new local pool handle with 1 worker thread let lp = LocalPool::single(); @@ -100,11 +102,10 @@ async fn main() -> Result<()> { // spawn a task to handle the connection tokio::spawn(async move { - let remote_addr = conn.remote_address(); let conn = match conn.await { Ok(conn) => conn, Err(err) => { - warn!(%remote_addr, "Error connecting: {err:#}"); + warn!("Error connecting: {err:#}"); return; } }; @@ -115,7 +116,6 @@ async fn main() -> Result<()> { match tokio::signal::ctrl_c().await { Ok(()) => { - tokio::fs::remove_dir_all(std::path::PathBuf::from(CERT_PATH)).await?; accept_task.abort(); Ok(()) } diff --git a/examples/transfer.rs b/examples/transfer.rs index 15b457f05..960274db7 100644 --- a/examples/transfer.rs +++ b/examples/transfer.rs @@ -1,12 +1,13 @@ -use std::{path::PathBuf, str::FromStr}; +use std::path::PathBuf; use anyhow::Result; use iroh::{protocol::Router, Endpoint}; use iroh_blobs::{ net_protocol::Blobs, - rpc::client::blobs::{ReadAtLen, WrapOption}, + rpc::client::blobs::WrapOption, + store::{ExportFormat, ExportMode}, ticket::BlobTicket, - util::{local_pool::LocalPool, SetTagOption}, + util::SetTagOption, }; #[tokio::main] @@ -14,48 +15,58 @@ async fn main() -> Result<()> { // Create an endpoint, it allows creating and accepting // connections in the iroh p2p world let endpoint = Endpoint::builder().discovery_n0().bind().await?; - // We initialize the Blobs protocol in-memory - let local_pool = LocalPool::default(); - let blobs = Blobs::memory().build(&local_pool, &endpoint); + let blobs = Blobs::memory().build(&endpoint); // Now we build a router that accepts blobs connections & routes them // to the blobs protocol. - let node = Router::builder(endpoint) + let router = Router::builder(endpoint) .accept(iroh_blobs::ALPN, blobs.clone()) .spawn() .await?; - let blobs = blobs.client(); + // We use a blobs client to interact with the blobs protocol we're running locally: + let blobs_client = blobs.client(); + + // Grab all passed in arguments, the first one is the binary itself, so we skip it. + let args: Vec = std::env::args().skip(1).collect(); + // Convert to &str, so we can pattern-match easily: + let arg_refs: Vec<&str> = args.iter().map(String::as_str).collect(); - let args = std::env::args().collect::>(); - match &args.iter().map(String::as_str).collect::>()[..] { - [_cmd, "send", path] => { - let abs_path = PathBuf::from_str(path)?.canonicalize()?; + match arg_refs.as_slice() { + ["send", filename] => { + let filename: PathBuf = filename.parse()?; + let abs_path = std::path::absolute(&filename)?; - println!("Analyzing file."); + println!("Hashing file."); - let blob = blobs - .add_from_path(abs_path, true, SetTagOption::Auto, WrapOption::NoWrap) + // keep the file in place and link it, instead of copying it into the in-memory blobs database + let in_place = true; + let blob = blobs_client + .add_from_path(abs_path, in_place, SetTagOption::Auto, WrapOption::NoWrap) .await? .finish() .await?; - let node_id = node.endpoint().node_id(); + let node_id = router.endpoint().node_id(); let ticket = BlobTicket::new(node_id.into(), blob.hash, blob.format)?; - println!("File analyzed. Fetch this file by running:"); - println!("cargo run --example transfer -- receive {ticket} {path}"); + println!("File hashed. Fetch this file by running:"); + println!( + "cargo run --example transfer -- receive {ticket} {}", + filename.display() + ); tokio::signal::ctrl_c().await?; } - [_cmd, "receive", ticket, path] => { - let path_buf = PathBuf::from_str(path)?; - let ticket = BlobTicket::from_str(ticket)?; + ["receive", ticket, filename] => { + let filename: PathBuf = filename.parse()?; + let abs_path = std::path::absolute(filename)?; + let ticket: BlobTicket = ticket.parse()?; println!("Starting download."); - blobs + blobs_client .download(ticket.hash(), ticket.node_addr().clone()) .await? .finish() @@ -64,14 +75,21 @@ async fn main() -> Result<()> { println!("Finished download."); println!("Copying to destination."); - let mut file = tokio::fs::File::create(path_buf).await?; - let mut reader = blobs.read_at(ticket.hash(), 0, ReadAtLen::All).await?; - tokio::io::copy(&mut reader, &mut file).await?; + blobs_client + .export( + ticket.hash(), + abs_path, + ExportFormat::Blob, + ExportMode::Copy, + ) + .await? + .finish() + .await?; println!("Finished copying."); } _ => { - println!("Couldn't parse command line arguments."); + println!("Couldn't parse command line arguments: {args:?}"); println!("Usage:"); println!(" # to send:"); println!(" cargo run --example transfer -- send [FILE]"); @@ -84,8 +102,7 @@ async fn main() -> Result<()> { // Gracefully shut down the node println!("Shutting down."); - node.shutdown().await?; - local_pool.shutdown().await; + router.shutdown().await?; Ok(()) } diff --git a/src/downloader.rs b/src/downloader.rs index a147131ae..87f0462b3 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -1523,7 +1523,7 @@ impl DialerT for Dialer { #[derive(Debug)] struct Dialer { endpoint: Endpoint, - pending: JoinSet<(NodeId, anyhow::Result)>, + pending: JoinSet<(NodeId, anyhow::Result)>, pending_dials: HashMap, } @@ -1572,7 +1572,7 @@ impl Dialer { } impl Stream for Dialer { - type Item = (NodeId, anyhow::Result); + type Item = (NodeId, anyhow::Result); fn poll_next( mut self: Pin<&mut Self>, diff --git a/src/downloader/test.rs b/src/downloader/test.rs index 63c22fe9b..0b5ea1f79 100644 --- a/src/downloader/test.rs +++ b/src/downloader/test.rs @@ -7,6 +7,7 @@ use std::{ use anyhow::anyhow; use futures_util::future::FutureExt; use iroh::SecretKey; +use tracing_test::traced_test; use super::*; use crate::{ @@ -48,8 +49,6 @@ impl Downloader { let lp = LocalPool::default(); lp.spawn_detached(move || async move { // we want to see the logs of the service - let _guard = iroh_test::logging::setup(); - let service = Service::new(getter, dialer, concurrency_limits, retry_config, msg_rx); service.run().await }); @@ -66,8 +65,8 @@ impl Downloader { /// Tests that receiving a download request and performing it doesn't explode. #[tokio::test] +#[traced_test] async fn smoke_test() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); let concurrency_limits = ConcurrencyLimits::default(); @@ -90,8 +89,8 @@ async fn smoke_test() { /// Tests that multiple intents produce a single request. #[tokio::test] +#[traced_test] async fn deduplication() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); // make request take some time to ensure the intents are received before completion @@ -123,8 +122,8 @@ async fn deduplication() { /// Tests that the request is cancelled only when all intents are cancelled. #[ignore = "flaky"] #[tokio::test] +#[traced_test] async fn cancellation() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); // make request take some time to ensure cancellations are received on time @@ -159,8 +158,8 @@ async fn cancellation() { /// maximum number of concurrent requests is not exceed. /// NOTE: This is internally tested by [`Service::check_invariants`]. #[tokio::test] +#[traced_test] async fn max_concurrent_requests_total() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); // make request take some time to ensure concurreny limits are hit @@ -202,8 +201,8 @@ async fn max_concurrent_requests_total() { /// the maximum number of requests per peer is still respected. /// NOTE: This is internally tested by [`Service::check_invariants`]. #[tokio::test] +#[traced_test] async fn max_concurrent_requests_per_peer() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); // make request take some time to ensure concurreny limits are hit @@ -239,8 +238,8 @@ async fn max_concurrent_requests_per_peer() { /// state. The download then finishes, and we make sure that all events are emitted properly, and /// the progress state of the handles converges. #[tokio::test] +#[traced_test] async fn concurrent_progress() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); @@ -356,8 +355,8 @@ async fn concurrent_progress() { } #[tokio::test] +#[traced_test] async fn long_queue() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); let concurrency_limits = ConcurrencyLimits { @@ -394,8 +393,8 @@ async fn long_queue() { /// If a download errors with [`FailureAction::DropPeer`], make sure that the peer is not dropped /// while other transfers are still running. #[tokio::test] +#[traced_test] async fn fail_while_running() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); let (downloader, _lp) = @@ -432,8 +431,8 @@ async fn fail_while_running() { } #[tokio::test] +#[traced_test] async fn retry_nodes_simple() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); let (downloader, _lp) = @@ -453,8 +452,8 @@ async fn retry_nodes_simple() { } #[tokio::test] +#[traced_test] async fn retry_nodes_fail() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); let config = RetryConfig { @@ -491,8 +490,8 @@ async fn retry_nodes_fail() { } #[tokio::test] +#[traced_test] async fn retry_nodes_jump_queue() { - let _guard = iroh_test::logging::setup(); let dialer = dialer::TestingDialer::default(); let getter = getter::TestingGetter::default(); let concurrency_limits = ConcurrencyLimits { diff --git a/src/get.rs b/src/get.rs index 7c1190f34..3365e1407 100644 --- a/src/get.rs +++ b/src/get.rs @@ -20,7 +20,7 @@ use std::{ use anyhow::Result; use bao_tree::{io::fsm::BaoContentItem, ChunkNum}; -use iroh::endpoint::{self, RecvStream, SendStream}; +use iroh::endpoint::{self, ClosedStream, RecvStream, SendStream, WriteError}; use serde::{Deserialize, Serialize}; use tracing::{debug, error}; @@ -189,10 +189,10 @@ pub mod fsm { RequestTooBig, /// Error when writing the request to the [`SendStream`]. #[error("write: {0}")] - Write(#[from] quinn::WriteError), + Write(#[from] WriteError), /// Quic connection is closed. #[error("closed")] - Closed(#[from] quinn::ClosedStream), + Closed(#[from] ClosedStream), /// A generic io error #[error("io {0}")] Io(io::Error), diff --git a/src/get/error.rs b/src/get/error.rs index 95f6beefc..03bec51e0 100644 --- a/src/get/error.rs +++ b/src/get/error.rs @@ -1,6 +1,6 @@ //! Error returned from get operations -use iroh::endpoint; +use iroh::endpoint::{self, ClosedStream}; use crate::util::progress::ProgressSendError; @@ -73,7 +73,7 @@ impl From for GetError { // TODO(@divma): don't see how this is reachable but let's just not use the peer GetError::Io(e.into()) } - e @ quinn::ConnectionError::CidsExhausted => { + e @ ConnectionError::CidsExhausted => { // > The connection could not be created because not enough of the CID space // > is available GetError::Io(e.into()) @@ -97,8 +97,8 @@ impl From for GetError { } } } -impl From for GetError { - fn from(value: quinn::ClosedStream) -> Self { +impl From for GetError { + fn from(value: ClosedStream) -> Self { GetError::Io(value.into()) } } diff --git a/src/hash.rs b/src/hash.rs index abf2327c0..dda748348 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -151,7 +151,12 @@ impl FromStr for Hash { // hex data_encoding::HEXLOWER.decode_mut(s.as_bytes(), &mut bytes) } else { - data_encoding::BASE32_NOPAD.decode_mut(s.to_ascii_uppercase().as_bytes(), &mut bytes) + let input = s.to_ascii_uppercase(); + let input = input.as_bytes(); + if data_encoding::BASE32_NOPAD.decode_len(input.len())? != bytes.len() { + return Err(HexOrBase32ParseError::DecodeInvalidLength); + } + data_encoding::BASE32_NOPAD.decode_mut(input, &mut bytes) }; match res { Ok(len) => { @@ -251,6 +256,12 @@ pub struct HashAndFormat { pub format: BlobFormat, } +impl From for HashAndFormat { + fn from(hash: Hash) -> Self { + Self::raw(hash) + } +} + #[cfg(feature = "redb")] mod redb_support { use postcard::experimental::max_size::MaxSize; @@ -377,7 +388,7 @@ impl FromStr for HashAndFormat { hex::decode_to_slice(s, &mut hash)?; Ok(Self::raw(hash.into())) } - 65 if s[0].to_ascii_lowercase() == b's' => { + 65 if s[0].eq_ignore_ascii_case(&b's') => { hex::decode_to_slice(&s[1..], &mut hash)?; Ok(Self::hash_seq(hash.into())) } @@ -416,11 +427,10 @@ impl<'de> Deserialize<'de> for HashAndFormat { #[cfg(test)] mod tests { - - use iroh_test::{assert_eq_hex, hexdump::parse_hexdump}; use serde_test::{assert_tokens, Configure, Token}; use super::*; + use crate::{assert_eq_hex, util::hexdump::parse_hexdump}; #[test] fn test_display_parse_roundtrip() { @@ -584,4 +594,9 @@ mod tests { let de = serde_json::from_str(&ser).unwrap(); assert_eq!(haf, de); } + + #[test] + fn test_hash_invalid() { + let _ = Hash::from_str("invalid").unwrap_err(); + } } diff --git a/src/lib.rs b/src/lib.rs index 7091ad795..fc9e397bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,17 @@ //! The [downloader] module provides a component to download blobs from //! multiple sources and store them in a store. //! +//! # Feature flags +//! +//! - rpc: Enable the rpc server and client. Enabled by default. +//! - net_protocol: Enable the network protocol. Enabled by default. +//! - downloader: Enable the downloader. Enabled by default. +//! - fs-store: Enable the filesystem store. Enabled by default. +//! +//! - cli: Enable the cli. Disabled by default. +//! - example-iroh: dependencies for examples in this crate. Disabled by default. +//! - test: test utilities. Disabled by default. +//! //! [BLAKE3]: https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf //! [iroh]: https://docs.rs/iroh #![deny(missing_docs, rustdoc::broken_intra_doc_links)] diff --git a/src/net_protocol.rs b/src/net_protocol.rs index ca62c146b..9fc8ba7ee 100644 --- a/src/net_protocol.rs +++ b/src/net_protocol.rs @@ -3,21 +3,26 @@ // TODO: reduce API surface and add documentation #![allow(missing_docs)] -use std::{collections::BTreeSet, fmt::Debug, ops::DerefMut, sync::Arc}; +use std::{ + collections::BTreeSet, + fmt::Debug, + ops::{Deref, DerefMut}, + sync::Arc, +}; use anyhow::{bail, Result}; use futures_lite::future::Boxed as BoxedFuture; use futures_util::future::BoxFuture; -use iroh::{endpoint::Connecting, protocol::ProtocolHandler, Endpoint, NodeAddr}; +use iroh::{endpoint::Connection, protocol::ProtocolHandler, Endpoint, NodeAddr}; use serde::{Deserialize, Serialize}; use tracing::debug; use crate::{ - downloader::Downloader, + downloader::{ConcurrencyLimits, Downloader, RetryConfig}, provider::EventSender, store::GcConfig, util::{ - local_pool::{self, LocalPoolHandle}, + local_pool::{self, LocalPool, LocalPoolHandle}, SetTagOption, }, BlobFormat, Hash, @@ -41,9 +46,26 @@ impl Default for GcState { } } +#[derive(Debug)] +enum Rt { + Handle(LocalPoolHandle), + Owned(LocalPool), +} + +impl Deref for Rt { + type Target = LocalPoolHandle; + + fn deref(&self) -> &Self::Target { + match self { + Self::Handle(ref handle) => handle, + Self::Owned(ref pool) => pool.handle(), + } + } +} + #[derive(Debug)] pub(crate) struct BlobsInner { - pub(crate) rt: LocalPoolHandle, + rt: Rt, pub(crate) store: S, events: EventSender, pub(crate) downloader: Downloader, @@ -53,6 +75,12 @@ pub(crate) struct BlobsInner { pub(crate) batches: tokio::sync::Mutex, } +impl BlobsInner { + pub(crate) fn rt(&self) -> &LocalPoolHandle { + &self.rt + } +} + #[derive(Debug, Clone)] pub struct Blobs { pub(crate) inner: Arc>, @@ -119,6 +147,9 @@ impl BlobBatches { pub struct Builder { store: S, events: Option, + rt: Option, + concurrency_limits: Option, + retry_config: Option, } impl Builder { @@ -128,13 +159,41 @@ impl Builder { self } + /// Set a custom [`LocalPoolHandle`] to use. + pub fn local_pool(mut self, rt: LocalPoolHandle) -> Self { + self.rt = Some(rt); + self + } + + /// Set custom [`ConcurrencyLimits`] to use. + pub fn concurrency_limits(mut self, concurrency_limits: ConcurrencyLimits) -> Self { + self.concurrency_limits = Some(concurrency_limits); + self + } + + /// Set a custom [`RetryConfig`] to use. + pub fn retry_config(mut self, retry_config: RetryConfig) -> Self { + self.retry_config = Some(retry_config); + self + } + /// Build the Blobs protocol handler. - /// You need to provide a local pool handle and an endpoint. - pub fn build(self, rt: &LocalPoolHandle, endpoint: &Endpoint) -> Blobs { - let downloader = Downloader::new(self.store.clone(), endpoint.clone(), rt.clone()); + /// You need to provide a the endpoint. + pub fn build(self, endpoint: &Endpoint) -> Blobs { + let rt = self + .rt + .map(Rt::Handle) + .unwrap_or_else(|| Rt::Owned(LocalPool::default())); + let downloader = Downloader::with_config( + self.store.clone(), + endpoint.clone(), + rt.clone(), + self.concurrency_limits.unwrap_or_default(), + self.retry_config.unwrap_or_default(), + ); Blobs::new( self.store, - rt.clone(), + rt, self.events.unwrap_or_default(), downloader, endpoint.clone(), @@ -148,6 +207,9 @@ impl Blobs { Builder { store, events: None, + rt: None, + concurrency_limits: None, + retry_config: None, } } } @@ -169,9 +231,9 @@ impl Blobs { } impl Blobs { - pub fn new( + fn new( store: S, - rt: LocalPoolHandle, + rt: Rt, events: EventSender, downloader: Downloader, endpoint: Endpoint, @@ -201,7 +263,7 @@ impl Blobs { } pub fn rt(&self) -> &LocalPoolHandle { - &self.inner.rt + self.inner.rt() } pub fn downloader(&self) -> &Downloader { @@ -256,13 +318,13 @@ impl Blobs { } impl ProtocolHandler for Blobs { - fn accept(&self, conn: Connecting) -> BoxedFuture> { + fn accept(&self, conn: Connection) -> BoxedFuture> { let db = self.store().clone(); let events = self.events().clone(); let rt = self.rt().clone(); Box::pin(async move { - crate::provider::handle_connection(conn.await?, db, events, rt).await; + crate::provider::handle_connection(conn, db, events, rt).await; Ok(()) }) } diff --git a/src/protocol.rs b/src/protocol.rs index 5dddace25..5f9d2a1d6 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -483,9 +483,8 @@ impl TryFrom for Closed { #[cfg(test)] mod tests { - use iroh_test::{assert_eq_hex, hexdump::parse_hexdump}; - use super::{GetRequest, Request}; + use crate::{assert_eq_hex, util::hexdump::parse_hexdump}; #[test] fn request_wire_format() { diff --git a/src/protocol/range_spec.rs b/src/protocol/range_spec.rs index fcf608aa1..db3390a29 100644 --- a/src/protocol/range_spec.rs +++ b/src/protocol/range_spec.rs @@ -354,10 +354,10 @@ impl<'a> Iterator for NonEmptyRequestRangeSpecIter<'a> { mod tests { use std::ops::Range; - use iroh_test::{assert_eq_hex, hexdump::parse_hexdump}; use proptest::prelude::*; use super::*; + use crate::{assert_eq_hex, util::hexdump::parse_hexdump}; fn ranges(value_range: Range) -> impl Strategy { prop::collection::vec((value_range.clone(), value_range), 0..16).prop_map(|v| { diff --git a/src/provider.rs b/src/provider.rs index 9ae9c02fc..bf55fe751 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -334,9 +334,7 @@ impl<'a, R: AsyncSliceReader, F: Fn(u64) -> Event> SendingSliceReader<'a, R, F> } } -impl<'a, R: AsyncSliceReader, F: Fn(u64) -> Event> AsyncSliceReader - for SendingSliceReader<'a, R, F> -{ +impl Event> AsyncSliceReader for SendingSliceReader<'_, R, F> { async fn read_at(&mut self, offset: u64, len: usize) -> std::io::Result { let res = self.inner.read_at(offset, len).await; if let Ok(res) = res.as_ref() { @@ -414,9 +412,8 @@ pub async fn handle_connection( events: EventSender, rt: LocalPoolHandle, ) { - let remote_addr = connection.remote_address(); let connection_id = connection.stable_id() as u64; - let span = debug_span!("connection", connection_id, %remote_addr); + let span = debug_span!("connection", connection_id); async move { while let Ok((writer, reader)) = connection.accept_bi().await { // The stream ID index is used to identify this request. Requests only arrive in diff --git a/src/rpc.rs b/src/rpc.rs index e1739b52c..d17364aec 100644 --- a/src/rpc.rs +++ b/src/rpc.rs @@ -30,7 +30,7 @@ use proto::{ }, tags::{ CreateRequest as TagsCreateRequest, DeleteRequest as TagDeleteRequest, - ListRequest as TagListRequest, SetRequest as TagsSetRequest, SyncMode, + ListRequest as TagListRequest, RenameRequest, SetRequest as TagsSetRequest, SyncMode, }, Request, RpcError, RpcResult, RpcService, }; @@ -110,7 +110,7 @@ impl Handler { } fn rt(&self) -> &LocalPoolHandle { - &self.0.rt + self.0.rt() } fn endpoint(&self) -> &Endpoint { @@ -158,6 +158,7 @@ impl Handler { Set(msg) => chan.rpc(msg, self, Self::tags_set).await, DeleteTag(msg) => chan.rpc(msg, self, Self::blob_delete_tag).await, ListTags(msg) => chan.server_streaming(msg, self, Self::blob_list_tags).await, + Rename(msg) => chan.rpc(msg, self, Self::tags_rename).await, } } @@ -295,7 +296,7 @@ impl Handler { async fn blob_delete_tag(self, msg: TagDeleteRequest) -> RpcResult<()> { self.store() - .set_tag(msg.name, None) + .delete_tags(msg.from, msg.to) .await .map_err(|e| RpcError::new(&e))?; Ok(()) @@ -313,7 +314,7 @@ impl Handler { tracing::info!("blob_list_tags"); let blobs = self; Gen::new(|co| async move { - let tags = blobs.store().tags().await.unwrap(); + let tags = blobs.store().tags(msg.from, msg.to).await.unwrap(); #[allow(clippy::manual_flatten)] for item in tags { if let Ok((name, HashAndFormat { hash, format })) = item { @@ -382,6 +383,16 @@ impl Handler { rx.map(AddPathResponse) } + async fn tags_rename(self, msg: RenameRequest) -> RpcResult<()> { + let blobs = self; + blobs + .store() + .rename_tag(msg.from, msg.to) + .await + .map_err(|e| RpcError::new(&e))?; + Ok(()) + } + async fn tags_set(self, msg: TagsSetRequest) -> RpcResult<()> { let blobs = self; blobs @@ -393,13 +404,11 @@ impl Handler { blobs.store().sync().await.map_err(|e| RpcError::new(&e))?; } if let Some(batch) = msg.batch { - if let Some(content) = msg.value.as_ref() { - blobs - .batches() - .await - .remove_one(batch, content) - .map_err(|e| RpcError::new(&*e))?; - } + blobs + .batches() + .await + .remove_one(batch, &msg.value) + .map_err(|e| RpcError::new(&*e))?; } Ok(()) } @@ -572,10 +581,7 @@ impl Handler { let HashAndFormat { hash, format } = *hash_and_format; let tag = match tag { SetTagOption::Named(tag) => { - blobs - .store() - .set_tag(tag.clone(), Some(*hash_and_format)) - .await?; + blobs.store().set_tag(tag.clone(), *hash_and_format).await?; tag } SetTagOption::Auto => blobs.store().create_tag(*hash_and_format).await?, @@ -764,10 +770,7 @@ impl Handler { let HashAndFormat { hash, format } = hash_and_format; let tag = match msg.tag { SetTagOption::Named(tag) => { - blobs - .store() - .set_tag(tag.clone(), Some(hash_and_format)) - .await?; + blobs.store().set_tag(tag.clone(), hash_and_format).await?; tag } SetTagOption::Auto => blobs.store().create_tag(hash_and_format).await?, @@ -907,7 +910,7 @@ impl Handler { SetTagOption::Named(tag) => { blobs .store() - .set_tag(tag.clone(), Some(*hash_and_format)) + .set_tag(tag.clone(), *hash_and_format) .await .map_err(|e| RpcError::new(&e))?; tag @@ -922,7 +925,7 @@ impl Handler { for tag in tags_to_delete { blobs .store() - .set_tag(tag, None) + .delete_tags(Some(tag.clone()), Some(tag.successor())) .await .map_err(|e| RpcError::new(&e))?; } @@ -959,7 +962,7 @@ impl Handler { progress.send(DownloadProgress::AllDone(stats)).await.ok(); match tag { SetTagOption::Named(tag) => { - self.store().set_tag(tag, Some(hash_and_format)).await?; + self.store().set_tag(tag, hash_and_format).await?; } SetTagOption::Auto => { self.store().create_tag(hash_and_format).await?; diff --git a/src/rpc/client/blobs.rs b/src/rpc/client/blobs.rs index 28d73316e..633034c8d 100644 --- a/src/rpc/client/blobs.rs +++ b/src/rpc/client/blobs.rs @@ -1002,6 +1002,7 @@ mod tests { use rand::RngCore; use testresult::TestResult; use tokio::{io::AsyncWriteExt, sync::mpsc}; + use tracing_test::traced_test; use super::*; use crate::{hashseq::HashSeq, ticket::BlobTicket}; @@ -1015,11 +1016,9 @@ mod tests { use super::RpcService; use crate::{ - downloader::Downloader, net_protocol::Blobs, provider::{CustomEventSender, EventSender}, rpc::client::{blobs, tags}, - util::local_pool::LocalPool, }; type RpcClient = quic_rpc::RpcClient; @@ -1029,7 +1028,6 @@ mod tests { pub struct Node { router: iroh::protocol::Router, client: RpcClient, - _local_pool: LocalPool, _rpc_task: AbortOnDropHandle<()>, } @@ -1067,19 +1065,12 @@ mod tests { .unwrap_or_else(|| Endpoint::builder().discovery_n0()) .bind() .await?; - let local_pool = LocalPool::single(); let mut router = Router::builder(endpoint.clone()); // Setup blobs - let downloader = - Downloader::new(store.clone(), endpoint.clone(), local_pool.handle().clone()); - let blobs = Blobs::new( - store.clone(), - local_pool.handle().clone(), - events, - downloader, - endpoint.clone(), - ); + let blobs = Blobs::builder(store.clone()) + .events(events) + .build(&endpoint); router = router.accept(crate::ALPN, blobs.clone()); // Build the router @@ -1096,7 +1087,6 @@ mod tests { router, client, _rpc_task, - _local_pool: local_pool, }) } } @@ -1150,9 +1140,8 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_blob_create_collection() -> Result<()> { - let _guard = iroh_test::logging::setup(); - let node = node::Node::memory().spawn().await?; // create temp file @@ -1234,9 +1223,8 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_blob_read_at() -> Result<()> { - // let _guard = iroh_test::logging::setup(); - let node = node::Node::memory().spawn().await?; // create temp file @@ -1373,9 +1361,8 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_blob_get_collection() -> Result<()> { - let _guard = iroh_test::logging::setup(); - let node = node::Node::memory().spawn().await?; // create temp file @@ -1439,9 +1426,8 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_blob_share() -> Result<()> { - let _guard = iroh_test::logging::setup(); - let node = node::Node::memory().spawn().await?; // create temp file @@ -1513,9 +1499,8 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_blob_provide_events() -> Result<()> { - let _guard = iroh_test::logging::setup(); - let (node1_events, mut node1_events_r) = BlobEvents::new(16); let node1 = node::Node::memory() .blobs_events(node1_events) @@ -1578,9 +1563,8 @@ mod tests { } /// Download a existing blob from oneself #[tokio::test] + #[traced_test] async fn test_blob_get_self_existing() -> TestResult<()> { - let _guard = iroh_test::logging::setup(); - let node = node::Node::memory().spawn().await?; let node_id = node.node_id(); let blobs = node.blobs(); @@ -1626,9 +1610,8 @@ mod tests { /// Download a missing blob from oneself #[tokio::test] + #[traced_test] async fn test_blob_get_self_missing() -> TestResult<()> { - let _guard = iroh_test::logging::setup(); - let node = node::Node::memory().spawn().await?; let node_id = node.node_id(); let blobs = node.blobs(); @@ -1678,9 +1661,8 @@ mod tests { /// Download a existing collection. Check that things succeed and no download is performed. #[tokio::test] + #[traced_test] async fn test_blob_get_existing_collection() -> TestResult<()> { - let _guard = iroh_test::logging::setup(); - let node = node::Node::memory().spawn().await?; // We use a nonexisting node id because we just want to check that this succeeds without // hitting the network. @@ -1750,10 +1732,9 @@ mod tests { } #[tokio::test] + #[traced_test] #[cfg_attr(target_os = "windows", ignore = "flaky")] async fn test_blob_delete_mem() -> Result<()> { - let _guard = iroh_test::logging::setup(); - let node = node::Node::memory().spawn().await?; let res = node.blobs().add_bytes(&b"hello world"[..]).await?; @@ -1772,9 +1753,8 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_blob_delete_fs() -> Result<()> { - let _guard = iroh_test::logging::setup(); - let dir = tempfile::tempdir()?; let node = node::Node::persistent(dir.path()).await?.spawn().await?; @@ -1794,9 +1774,8 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_ticket_multiple_addrs() -> TestResult<()> { - let _guard = iroh_test::logging::setup(); - let node = Node::memory().spawn().await?; let hash = node .blobs() @@ -1812,9 +1791,8 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_node_add_blob_stream() -> Result<()> { - let _guard = iroh_test::logging::setup(); - use std::io::Cursor; let node = Node::memory().spawn().await?; @@ -1830,9 +1808,8 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_node_add_tagged_blob_event() -> Result<()> { - let _guard = iroh_test::logging::setup(); - let node = Node::memory().spawn().await?; let _got_hash = tokio::time::timeout(Duration::from_secs(10), async move { @@ -1867,8 +1844,8 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_download_via_relay() -> Result<()> { - let _guard = iroh_test::logging::setup(); let (relay_map, relay_url, _guard) = iroh::test_utils::run_relay_server().await?; let endpoint1 = iroh::Endpoint::builder() @@ -1897,9 +1874,9 @@ mod tests { } #[tokio::test] + #[traced_test] #[ignore = "flaky"] async fn test_download_via_relay_with_discovery() -> Result<()> { - let _guard = iroh_test::logging::setup(); let (relay_map, _relay_url, _guard) = iroh::test_utils::run_relay_server().await?; let dns_pkarr_server = DnsPkarrServer::run().await?; diff --git a/src/rpc/client/blobs/batch.rs b/src/rpc/client/blobs/batch.rs index b82f17837..5a964441e 100644 --- a/src/rpc/client/blobs/batch.rs +++ b/src/rpc/client/blobs/batch.rs @@ -441,7 +441,7 @@ where .rpc .rpc(tags::SetRequest { name: tag, - value: Some(tt.hash_and_format()), + value: tt.hash_and_format(), batch: Some(self.0.batch), sync: SyncMode::Full, }) diff --git a/src/rpc/client/tags.rs b/src/rpc/client/tags.rs index 103ecc618..cd9000ea6 100644 --- a/src/rpc/client/tags.rs +++ b/src/rpc/client/tags.rs @@ -2,14 +2,26 @@ //! //! The purpose of tags is to mark information as important to prevent it //! from being garbage-collected (if the garbage collector is turned on). -//! Currently this is used for blobs. //! -//! The main entry point is the [`Client`]. +//! A tag has a name that is an arbitrary byte string. In many cases this will be +//! a valid UTF8 string, but there are also use cases where it is useful to have +//! non string data like integer ids in the tag name. +//! +//! Tags point to a [`HashAndFormat`]. +//! +//! A tag can point to a hash with format [`BlobFormat::Raw`]. In that case it will +//! protect *just this blob* from being garbage-collected. //! -//! [`Client::list`] can be used to list all tags. -//! [`Client::list_hash_seq`] can be used to list all tags with a hash_seq format. +//! It can also point to a hash in format [`BlobFormat::HashSeq`]. In that case it will +//! protect the blob itself and all hashes in the blob (the blob must be just a sequence of hashes). +//! Using this format it is possible to protect a large number of blobs with a single tag. //! -//! [`Client::delete`] can be used to delete a tag. +//! Tags can be created, read, renamed and deleted. Tags *do not* have to correspond to +//! already existing data. It is perfectly valid to create a tag for data you don't have yet. +//! +//! The main entry point is the [`Client`]. +use std::ops::{Bound, RangeBounds}; + use anyhow::Result; use futures_lite::{Stream, StreamExt}; use quic_rpc::{client::BoxedConnector, Connector, RpcClient}; @@ -17,10 +29,10 @@ use serde::{Deserialize, Serialize}; use crate::{ rpc::proto::{ - tags::{DeleteRequest, ListRequest}, + tags::{DeleteRequest, ListRequest, RenameRequest, SetRequest, SyncMode}, RpcService, }, - BlobFormat, Hash, Tag, + BlobFormat, Hash, HashAndFormat, Tag, }; /// Iroh tags client. @@ -30,6 +42,147 @@ pub struct Client> { pub(super) rpc: RpcClient, } +/// Options for a list operation. +#[derive(Debug, Clone)] +pub struct ListOptions { + /// List tags to hash seqs + pub hash_seq: bool, + /// List tags to raw blobs + pub raw: bool, + /// Optional from tag (inclusive) + pub from: Option, + /// Optional to tag (exclusive) + pub to: Option, +} + +fn tags_from_range(range: R) -> (Option, Option) +where + R: RangeBounds, + E: AsRef<[u8]>, +{ + let from = match range.start_bound() { + Bound::Included(start) => Some(Tag::from(start.as_ref())), + Bound::Excluded(start) => Some(Tag::from(start.as_ref()).successor()), + Bound::Unbounded => None, + }; + let to = match range.end_bound() { + Bound::Included(end) => Some(Tag::from(end.as_ref()).successor()), + Bound::Excluded(end) => Some(Tag::from(end.as_ref())), + Bound::Unbounded => None, + }; + (from, to) +} + +impl ListOptions { + /// List a range of tags + pub fn range(range: R) -> Self + where + R: RangeBounds, + E: AsRef<[u8]>, + { + let (from, to) = tags_from_range(range); + Self { + from, + to, + raw: true, + hash_seq: true, + } + } + + /// List tags with a prefix + pub fn prefix(prefix: &[u8]) -> Self { + let from = Tag::from(prefix); + let to = from.next_prefix(); + Self { + raw: true, + hash_seq: true, + from: Some(from), + to, + } + } + + /// List a single tag + pub fn single(name: &[u8]) -> Self { + let from = Tag::from(name); + Self { + to: Some(from.successor()), + from: Some(from), + raw: true, + hash_seq: true, + } + } + + /// List all tags + pub fn all() -> Self { + Self { + raw: true, + hash_seq: true, + from: None, + to: None, + } + } + + /// List raw tags + pub fn raw() -> Self { + Self { + raw: true, + hash_seq: false, + from: None, + to: None, + } + } + + /// List hash seq tags + pub fn hash_seq() -> Self { + Self { + raw: false, + hash_seq: true, + from: None, + to: None, + } + } +} + +/// Options for a delete operation. +#[derive(Debug, Clone)] +pub struct DeleteOptions { + /// Optional from tag (inclusive) + pub from: Option, + /// Optional to tag (exclusive) + pub to: Option, +} + +impl DeleteOptions { + /// Delete a single tag + pub fn single(name: &[u8]) -> Self { + let name = Tag::from(name); + Self { + to: Some(name.successor()), + from: Some(name), + } + } + + /// Delete a range of tags + pub fn range(range: R) -> Self + where + R: RangeBounds, + E: AsRef<[u8]>, + { + let (from, to) = tags_from_range(range); + Self { from, to } + } + + /// Delete tags with a prefix + pub fn prefix(prefix: &[u8]) -> Self { + let from = Tag::from(prefix); + let to = from.next_prefix(); + Self { + from: Some(from), + to, + } + } +} + /// A client that uses the memory connector. pub type MemClient = Client; @@ -42,27 +195,122 @@ where Self { rpc } } + /// List all tags with options. + /// + /// This is the most flexible way to list tags. All the other list methods are just convenience + /// methods that call this one with the appropriate options. + pub async fn list_with_opts( + &self, + options: ListOptions, + ) -> Result>> { + let stream = self + .rpc + .server_streaming(ListRequest::from(options)) + .await?; + Ok(stream.map(|res| res.map_err(anyhow::Error::from))) + } + + /// Set the value for a single tag + pub async fn set(&self, name: impl AsRef<[u8]>, value: impl Into) -> Result<()> { + self.rpc + .rpc(SetRequest { + name: Tag::from(name.as_ref()), + value: value.into(), + batch: None, + sync: SyncMode::Full, + }) + .await??; + Ok(()) + } + + /// Get the value of a single tag + pub async fn get(&self, name: impl AsRef<[u8]>) -> Result> { + let mut stream = self + .list_with_opts(ListOptions::single(name.as_ref())) + .await?; + stream.next().await.transpose() + } + + /// Rename a tag atomically + /// + /// If the tag does not exist, this will return an error. + pub async fn rename(&self, from: impl AsRef<[u8]>, to: impl AsRef<[u8]>) -> Result<()> { + self.rpc + .rpc(RenameRequest { + from: Tag::from(from.as_ref()), + to: Tag::from(to.as_ref()), + }) + .await??; + Ok(()) + } + + /// List a range of tags + pub async fn list_range(&self, range: R) -> Result>> + where + R: RangeBounds, + E: AsRef<[u8]>, + { + self.list_with_opts(ListOptions::range(range)).await + } + + /// Lists all tags with the given prefix. + pub async fn list_prefix( + &self, + prefix: impl AsRef<[u8]>, + ) -> Result>> { + self.list_with_opts(ListOptions::prefix(prefix.as_ref())) + .await + } + /// Lists all tags. pub async fn list(&self) -> Result>> { - let stream = self.rpc.server_streaming(ListRequest::all()).await?; - Ok(stream.map(|res| res.map_err(anyhow::Error::from))) + self.list_with_opts(ListOptions::all()).await } /// Lists all tags with a hash_seq format. pub async fn list_hash_seq(&self) -> Result>> { - let stream = self.rpc.server_streaming(ListRequest::hash_seq()).await?; - Ok(stream.map(|res| res.map_err(anyhow::Error::from))) + self.list_with_opts(ListOptions::hash_seq()).await } /// Deletes a tag. - pub async fn delete(&self, name: Tag) -> Result<()> { - self.rpc.rpc(DeleteRequest { name }).await??; + pub async fn delete_with_opts(&self, options: DeleteOptions) -> Result<()> { + self.rpc.rpc(DeleteRequest::from(options)).await??; Ok(()) } + + /// Deletes a tag. + pub async fn delete(&self, name: impl AsRef<[u8]>) -> Result<()> { + self.delete_with_opts(DeleteOptions::single(name.as_ref())) + .await + } + + /// Deletes a range of tags. + pub async fn delete_range(&self, range: R) -> Result<()> + where + R: RangeBounds, + E: AsRef<[u8]>, + { + self.delete_with_opts(DeleteOptions::range(range)).await + } + + /// Delete all tags with the given prefix. + pub async fn delete_prefix(&self, prefix: impl AsRef<[u8]>) -> Result<()> { + self.delete_with_opts(DeleteOptions::prefix(prefix.as_ref())) + .await + } + + /// Delete all tags. Use with care. After this, all data will be garbage collected. + pub async fn delete_all(&self) -> Result<()> { + self.delete_with_opts(DeleteOptions { + from: None, + to: None, + }) + .await + } } /// Information about a tag. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] pub struct TagInfo { /// Name of the tag pub name: Tag, @@ -71,3 +319,24 @@ pub struct TagInfo { /// Hash of the data pub hash: Hash, } + +impl TagInfo { + /// Create a new tag info. + pub fn new(name: impl AsRef<[u8]>, value: impl Into) -> Self { + let name = name.as_ref(); + let value = value.into(); + Self { + name: Tag::from(name), + hash: value.hash, + format: value.format, + } + } + + /// Get the hash and format of the tag. + pub fn hash_and_format(&self) -> HashAndFormat { + HashAndFormat { + hash: self.hash, + format: self.format, + } + } +} diff --git a/src/rpc/proto/tags.rs b/src/rpc/proto/tags.rs index 54d35f625..f30547fa7 100644 --- a/src/rpc/proto/tags.rs +++ b/src/rpc/proto/tags.rs @@ -4,7 +4,11 @@ use quic_rpc_derive::rpc_requests; use serde::{Deserialize, Serialize}; use super::{RpcResult, RpcService}; -use crate::{net_protocol::BatchId, rpc::client::tags::TagInfo, HashAndFormat, Tag}; +use crate::{ + net_protocol::BatchId, + rpc::client::tags::{DeleteOptions, ListOptions, TagInfo}, + HashAndFormat, Tag, +}; #[allow(missing_docs)] #[derive(strum::Display, Debug, Serialize, Deserialize)] @@ -16,6 +20,8 @@ pub enum Request { #[rpc(response = RpcResult<()>)] Set(SetRequest), #[rpc(response = RpcResult<()>)] + Rename(RenameRequest), + #[rpc(response = RpcResult<()>)] DeleteTag(DeleteRequest), #[server_streaming(response = TagInfo)] ListTags(ListRequest), @@ -56,8 +62,8 @@ pub struct CreateRequest { pub struct SetRequest { /// Name of the tag pub name: Tag, - /// Value of the tag, None to delete - pub value: Option, + /// Value of the tag + pub value: HashAndFormat, /// Batch to use, none for global pub batch: Option, /// Sync mode @@ -73,37 +79,46 @@ pub struct ListRequest { pub raw: bool, /// List hash seq tags pub hash_seq: bool, + /// From tag (inclusive) + pub from: Option, + /// To tag (exclusive) + pub to: Option, } -impl ListRequest { - /// List all tags - pub fn all() -> Self { +impl From for ListRequest { + fn from(options: ListOptions) -> Self { Self { - raw: true, - hash_seq: true, + raw: options.raw, + hash_seq: options.hash_seq, + from: options.from, + to: options.to, } } +} - /// List raw tags - pub fn raw() -> Self { - Self { - raw: true, - hash_seq: false, - } - } +/// Delete a tag +#[derive(Debug, Serialize, Deserialize)] +pub struct DeleteRequest { + /// From tag (inclusive) + pub from: Option, + /// To tag (exclusive) + pub to: Option, +} - /// List hash seq tags - pub fn hash_seq() -> Self { +impl From for DeleteRequest { + fn from(options: DeleteOptions) -> Self { Self { - raw: false, - hash_seq: true, + from: options.from, + to: options.to, } } } -/// Delete a tag +/// Rename a tag atomically #[derive(Debug, Serialize, Deserialize)] -pub struct DeleteRequest { - /// Name of the tag - pub name: Tag, +pub struct RenameRequest { + /// Old tag name + pub from: Tag, + /// New tag name + pub to: Tag, } diff --git a/src/store/fs.rs b/src/store/fs.rs index 2b8bf95aa..0628dc183 100644 --- a/src/store/fs.rs +++ b/src/store/fs.rs @@ -67,6 +67,7 @@ use std::{ collections::{BTreeMap, BTreeSet}, future::Future, io, + ops::Bound, path::{Path, PathBuf}, sync::{Arc, RwLock}, time::{Duration, SystemTime}, @@ -85,7 +86,6 @@ use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use tokio::io::AsyncWriteExt; use tracing::trace_span; - mod tables; #[doc(hidden)] pub mod test_support; @@ -601,17 +601,23 @@ pub(crate) enum ActorMessage { }, /// Bulk query method: get the entire tags table Tags { - #[debug(skip)] - filter: FilterPredicate, + from: Option, + to: Option, #[allow(clippy::type_complexity)] tx: oneshot::Sender< ActorResult>>, >, }, - /// Modification method: set a tag to a value, or remove it. + /// Modification method: set a tag to a value. SetTag { tag: Tag, - value: Option, + value: HashAndFormat, + tx: oneshot::Sender>, + }, + /// Modification method: set a tag to a value. + DeleteTags { + from: Option, + to: Option, tx: oneshot::Sender>, }, /// Modification method: create a new unique tag and set it to a value. @@ -619,6 +625,12 @@ pub(crate) enum ActorMessage { hash: HashAndFormat, tx: oneshot::Sender>, }, + /// Modification method: rename a tag atomically. + RenameTag { + from: Tag, + to: Tag, + tx: oneshot::Sender>, + }, /// Modification method: unconditional delete the data for a number of hashes Delete { hashes: Vec, @@ -673,6 +685,8 @@ impl ActorMessage { | Self::CreateTag { .. } | Self::SetFullEntryState { .. } | Self::Delete { .. } + | Self::DeleteTags { .. } + | Self::RenameTag { .. } | Self::GcDelete { .. } => MessageCategory::ReadWrite, Self::UpdateInlineOptions { .. } | Self::Sync { .. } @@ -856,11 +870,13 @@ impl StoreInner { Ok(res) } - async fn tags(&self) -> OuterResult>> { + async fn tags( + &self, + from: Option, + to: Option, + ) -> OuterResult>> { let (tx, rx) = oneshot::channel(); - let filter: FilterPredicate = - Box::new(|_i, k, v| Some((k.value(), v.value()))); - self.tx.send(ActorMessage::Tags { filter, tx }).await?; + self.tx.send(ActorMessage::Tags { from, to, tx }).await?; let tags = rx.await?; // transform the internal error type into io::Error let tags = tags? @@ -870,7 +886,7 @@ impl StoreInner { Ok(tags) } - async fn set_tag(&self, tag: Tag, value: Option) -> OuterResult<()> { + async fn set_tag(&self, tag: Tag, value: HashAndFormat) -> OuterResult<()> { let (tx, rx) = oneshot::channel(); self.tx .send(ActorMessage::SetTag { tag, value, tx }) @@ -878,12 +894,28 @@ impl StoreInner { Ok(rx.await??) } + async fn delete_tags(&self, from: Option, to: Option) -> OuterResult<()> { + let (tx, rx) = oneshot::channel(); + self.tx + .send(ActorMessage::DeleteTags { from, to, tx }) + .await?; + Ok(rx.await??) + } + async fn create_tag(&self, hash: HashAndFormat) -> OuterResult { let (tx, rx) = oneshot::channel(); self.tx.send(ActorMessage::CreateTag { hash, tx }).await?; Ok(rx.await??) } + async fn rename_tag(&self, from: Tag, to: Tag) -> OuterResult<()> { + let (tx, rx) = oneshot::channel(); + self.tx + .send(ActorMessage::RenameTag { from, to, tx }) + .await?; + Ok(rx.await??) + } + async fn delete(&self, hashes: Vec) -> OuterResult<()> { let (tx, rx) = oneshot::channel(); self.tx.send(ActorMessage::Delete { hashes, tx }).await?; @@ -1247,7 +1279,7 @@ impl super::Map for Store { type Entry = Entry; async fn get(&self, hash: &Hash) -> io::Result> { - Ok(self.0.get(*hash).await?.map(From::from)) + Ok(self.0.get(*hash).await?) } } @@ -1284,8 +1316,12 @@ impl super::ReadableStore for Store { Ok(Box::new(self.0.partial_blobs().await?.into_iter())) } - async fn tags(&self) -> io::Result> { - Ok(Box::new(self.0.tags().await?.into_iter())) + async fn tags( + &self, + from: Option, + to: Option, + ) -> io::Result> { + Ok(Box::new(self.0.tags(from, to).await?.into_iter())) } fn temp_tags(&self) -> Box + Send + Sync + 'static> { @@ -1371,14 +1407,22 @@ impl super::Store for Store { .await??) } - async fn set_tag(&self, name: Tag, hash: Option) -> io::Result<()> { + async fn set_tag(&self, name: Tag, hash: HashAndFormat) -> io::Result<()> { Ok(self.0.set_tag(name, hash).await?) } + async fn delete_tags(&self, from: Option, to: Option) -> io::Result<()> { + Ok(self.0.delete_tags(from, to).await?) + } + async fn create_tag(&self, hash: HashAndFormat) -> io::Result { Ok(self.0.create_tag(hash).await?) } + async fn rename_tag(&self, from: Tag, to: Tag) -> io::Result<()> { + Ok(self.0.rename_tag(from, to).await?) + } + async fn delete(&self, hashes: Vec) -> io::Result<()> { Ok(self.0.delete(hashes).await?) } @@ -1468,8 +1512,8 @@ impl super::Store for Store { } } -pub(super) async fn gc_sweep_task<'a>( - store: &'a Store, +pub(super) async fn gc_sweep_task( + store: &Store, live: &BTreeSet, co: &Co, ) -> anyhow::Result<()> { @@ -1966,23 +2010,21 @@ impl ActorState { fn tags( &mut self, tables: &impl ReadableTables, - filter: FilterPredicate, + from: Option, + to: Option, ) -> ActorResult>> { let mut res = Vec::new(); - let mut index = 0u64; - #[allow(clippy::explicit_counter_loop)] - for item in tables.tags().iter()? { + let from = from.map(Bound::Included).unwrap_or(Bound::Unbounded); + let to = to.map(Bound::Excluded).unwrap_or(Bound::Unbounded); + for item in tables.tags().range((from, to))? { match item { Ok((k, v)) => { - if let Some(item) = filter(index, k, v) { - res.push(Ok(item)); - } + res.push(Ok((k.value(), v.value()))); } Err(e) => { res.push(Err(e)); } } - index += 1; } Ok(res) } @@ -1998,19 +2040,35 @@ impl ActorState { Ok(tag) } - fn set_tag( + fn rename_tag(&mut self, tables: &mut Tables, from: Tag, to: Tag) -> ActorResult<()> { + let value = tables + .tags + .remove(from)? + .ok_or_else(|| { + ActorError::Io(io::Error::new(io::ErrorKind::NotFound, "tag not found")) + })? + .value(); + tables.tags.insert(to, value)?; + Ok(()) + } + + fn set_tag(&self, tables: &mut Tables, tag: Tag, value: HashAndFormat) -> ActorResult<()> { + tables.tags.insert(tag, value)?; + Ok(()) + } + + fn delete_tags( &self, tables: &mut Tables, - tag: Tag, - value: Option, + from: Option, + to: Option, ) -> ActorResult<()> { - match value { - Some(value) => { - tables.tags.insert(tag, value)?; - } - None => { - tables.tags.remove(tag)?; - } + let from = from.map(Bound::Included).unwrap_or(Bound::Unbounded); + let to = to.map(Bound::Excluded).unwrap_or(Bound::Unbounded); + let removing = tables.tags.extract_from_if((from, to), |_, _| true)?; + // drain the iterator to actually remove the tags + for res in removing { + res?; } Ok(()) } @@ -2319,8 +2377,8 @@ impl ActorState { let res = self.blobs(tables, filter); tx.send(res).ok(); } - ActorMessage::Tags { filter, tx } => { - let res = self.tags(tables, filter); + ActorMessage::Tags { from, to, tx } => { + let res = self.tags(tables, from, to); tx.send(res).ok(); } ActorMessage::GcStart { tx } => { @@ -2358,10 +2416,18 @@ impl ActorState { let res = self.set_tag(tables, tag, value); tx.send(res).ok(); } + ActorMessage::DeleteTags { from, to, tx } => { + let res = self.delete_tags(tables, from, to); + tx.send(res).ok(); + } ActorMessage::CreateTag { hash, tx } => { let res = self.create_tag(tables, hash); tx.send(res).ok(); } + ActorMessage::RenameTag { from, to, tx } => { + let res = self.rename_tag(tables, from, to); + tx.send(res).ok(); + } ActorMessage::Delete { hashes, tx } => { let res = self.delete(tables, hashes, true); tx.send(res).ok(); diff --git a/src/store/mem.rs b/src/store/mem.rs index 89d8fffd7..105b8ddd5 100644 --- a/src/store/mem.rs +++ b/src/store/mem.rs @@ -17,6 +17,7 @@ use bao_tree::{ use bytes::{Bytes, BytesMut}; use futures_lite::{Stream, StreamExt}; use iroh_io::AsyncSliceReader; +use tracing::info; use super::{ temp_name, BaoBatchWriter, ConsistencyCheckProgress, ExportMode, ExportProgressCb, ImportMode, @@ -207,13 +208,43 @@ impl super::Store for Store { .await? } - async fn set_tag(&self, name: Tag, value: Option) -> io::Result<()> { + async fn rename_tag(&self, from: Tag, to: Tag) -> io::Result<()> { let mut state = self.write_lock(); - if let Some(value) = value { - state.tags.insert(name, value); - } else { - state.tags.remove(&name); - } + let value = state.tags.remove(&from).ok_or_else(|| { + io::Error::new( + io::ErrorKind::NotFound, + format!("tag not found: {:?}", from), + ) + })?; + state.tags.insert(to, value); + Ok(()) + } + + async fn set_tag(&self, name: Tag, value: HashAndFormat) -> io::Result<()> { + let mut state = self.write_lock(); + state.tags.insert(name, value); + Ok(()) + } + + async fn delete_tags(&self, from: Option, to: Option) -> io::Result<()> { + let mut state = self.write_lock(); + info!("deleting tags from {:?} to {:?}", from, to); + // state.tags.remove(&from.unwrap()); + // todo: more efficient impl + state.tags.retain(|tag, _| { + if let Some(from) = &from { + if tag < from { + return true; + } + } + if let Some(to) = &to { + if tag >= to { + return true; + } + } + info!(" removing {:?}", tag); + false + }); Ok(()) } @@ -427,10 +458,30 @@ impl ReadableStore for Store { )) } - async fn tags(&self) -> io::Result> { + async fn tags( + &self, + from: Option, + to: Option, + ) -> io::Result> { #[allow(clippy::mutable_key_type)] let tags = self.read_lock().tags.clone(); - Ok(Box::new(tags.into_iter().map(Ok))) + let tags = tags + .into_iter() + .filter(move |(tag, _)| { + if let Some(from) = &from { + if tag < from { + return false; + } + } + if let Some(to) = &to { + if tag >= to { + return false; + } + } + true + }) + .map(Ok); + Ok(Box::new(tags)) } fn temp_tags(&self) -> Box + Send + Sync + 'static> { diff --git a/src/store/readonly_mem.rs b/src/store/readonly_mem.rs index a04161554..ec8f1b5f3 100644 --- a/src/store/readonly_mem.rs +++ b/src/store/readonly_mem.rs @@ -232,7 +232,11 @@ impl ReadableStore for Store { )) } - async fn tags(&self) -> io::Result> { + async fn tags( + &self, + _from: Option, + _to: Option, + ) -> io::Result> { Ok(Box::new(std::iter::empty())) } @@ -303,6 +307,10 @@ impl super::Store for Store { Err(io::Error::new(io::ErrorKind::Other, "not implemented")) } + async fn rename_tag(&self, _from: Tag, _to: Tag) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "not implemented")) + } + async fn import_stream( &self, data: impl Stream> + Unpin + Send, @@ -313,7 +321,11 @@ impl super::Store for Store { Err(io::Error::new(io::ErrorKind::Other, "not implemented")) } - async fn set_tag(&self, _name: Tag, _hash: Option) -> io::Result<()> { + async fn set_tag(&self, _name: Tag, _hash: HashAndFormat) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Other, "not implemented")) + } + + async fn delete_tags(&self, _from: Option, _to: Option) -> io::Result<()> { Err(io::Error::new(io::ErrorKind::Other, "not implemented")) } diff --git a/src/store/traits.rs b/src/store/traits.rs index 1c6ade5df..3c41686fa 100644 --- a/src/store/traits.rs +++ b/src/store/traits.rs @@ -292,7 +292,11 @@ pub trait ReadableStore: Map { /// been imported, and hash sequences that have been created internally. fn blobs(&self) -> impl Future>> + Send; /// list all tags (collections or other explicitly added things) in the database - fn tags(&self) -> impl Future>> + Send; + fn tags( + &self, + from: Option, + to: Option, + ) -> impl Future>> + Send; /// Temp tags fn temp_tags(&self) -> Box + Send + Sync + 'static>; @@ -443,7 +447,22 @@ pub trait Store: ReadableStore + MapMut + std::fmt::Debug { fn set_tag( &self, name: Tag, - hash: Option, + hash: HashAndFormat, + ) -> impl Future> + Send; + + /// Rename a tag + fn rename_tag(&self, from: Tag, to: Tag) -> impl Future> + Send; + + /// Delete a single tag + fn delete_tag(&self, name: Tag) -> impl Future> + Send { + self.delete_tags(Some(name.clone()), Some(name.successor())) + } + + /// Bulk delete tags + fn delete_tags( + &self, + from: Option, + to: Option, ) -> impl Future> + Send; /// Create a new tag @@ -726,7 +745,7 @@ pub(super) async fn gc_mark_task<'a>( } let mut roots = BTreeSet::new(); debug!("traversing tags"); - for item in store.tags().await? { + for item in store.tags(None, None).await? { let (name, haf) = item?; debug!("adding root {:?} {:?}", name, haf); roots.insert(haf); @@ -774,8 +793,8 @@ pub(super) async fn gc_mark_task<'a>( Ok(()) } -async fn gc_sweep_task<'a>( - store: &'a impl Store, +async fn gc_sweep_task( + store: &impl Store, live: &BTreeSet, co: &Co, ) -> anyhow::Result<()> { diff --git a/src/ticket.rs b/src/ticket.rs index 1cde760d7..69c512d14 100644 --- a/src/ticket.rs +++ b/src/ticket.rs @@ -154,9 +154,9 @@ mod tests { use std::net::SocketAddr; use iroh::{PublicKey, SecretKey}; - use iroh_test::{assert_eq_hex, hexdump::parse_hexdump}; use super::*; + use crate::{assert_eq_hex, util::hexdump::parse_hexdump}; fn make_ticket() -> BlobTicket { let hash = Hash::new(b"hi there"); diff --git a/src/util.rs b/src/util.rs index 735a9feb1..fcf3115bf 100644 --- a/src/util.rs +++ b/src/util.rs @@ -24,6 +24,9 @@ mod sparse_mem_file; pub use sparse_mem_file::SparseMemFile; pub mod local_pool; +#[cfg(test)] +pub(crate) mod hexdump; + /// A tag #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, From, Into)] pub struct Tag(pub Bytes); @@ -71,6 +74,18 @@ mod redb_support { } } +impl From<&[u8]> for Tag { + fn from(value: &[u8]) -> Self { + Self(Bytes::copy_from_slice(value)) + } +} + +impl AsRef<[u8]> for Tag { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + impl Borrow<[u8]> for Tag { fn borrow(&self) -> &[u8] { self.0.as_ref() @@ -129,6 +144,26 @@ impl Tag { i += 1; } } + + /// The successor of this tag in lexicographic order. + pub fn successor(&self) -> Self { + let mut bytes = self.0.to_vec(); + // increment_vec(&mut bytes); + bytes.push(0); + Self(bytes.into()) + } + + /// If this is a prefix, get the next prefix. + /// + /// This is like successor, except that it will return None if the prefix is all 0xFF instead of appending a 0 byte. + pub fn next_prefix(&self) -> Option { + let mut bytes = self.0.to_vec(); + if next_prefix(&mut bytes) { + Some(Self(bytes.into())) + } else { + None + } + } } /// Option for commands that allow setting a tag @@ -299,6 +334,22 @@ pub(crate) fn raw_outboard_size(size: u64) -> u64 { BaoTree::new(size, IROH_BLOCK_SIZE).outboard_size() } +/// Given a prefix, increment it lexographically. +/// +/// If the prefix is all FF, this will return false because there is no +/// higher prefix than that. +#[allow(dead_code)] +pub(crate) fn next_prefix(bytes: &mut [u8]) -> bool { + for byte in bytes.iter_mut().rev() { + if *byte < 255 { + *byte += 1; + return true; + } + *byte = 0; + } + false +} + /// Synchronously compute the outboard of a file, and return hash and outboard. /// /// It is assumed that the file is not modified while this is running. diff --git a/src/util/hexdump.rs b/src/util/hexdump.rs new file mode 100644 index 000000000..0c36b1bc8 --- /dev/null +++ b/src/util/hexdump.rs @@ -0,0 +1,181 @@ +use anyhow::{ensure, Context, Result}; + +/// Parses a commented multi line hexdump into a vector of bytes. +/// +/// This is useful to write wire level protocol tests. +pub fn parse_hexdump(s: &str) -> Result> { + let mut result = Vec::new(); + + for (line_number, line) in s.lines().enumerate() { + let data_part = line.split('#').next().unwrap_or(""); + let cleaned: String = data_part.chars().filter(|c| !c.is_whitespace()).collect(); + + ensure!( + cleaned.len() % 2 == 0, + "Non-even number of hex chars detected on line {}.", + line_number + 1 + ); + + for i in (0..cleaned.len()).step_by(2) { + let byte_str = &cleaned[i..i + 2]; + let byte = u8::from_str_radix(byte_str, 16) + .with_context(|| format!("Invalid hex data on line {}.", line_number + 1))?; + + result.push(byte); + } + } + + Ok(result) +} + +/// Returns a hexdump of the given bytes in multiple lines as a String. +pub fn print_hexdump(bytes: impl AsRef<[u8]>, line_lengths: impl AsRef<[usize]>) -> String { + let line_lengths = line_lengths.as_ref(); + let mut bytes_iter = bytes.as_ref().iter(); + let default_line_length = line_lengths + .last() + .filter(|x| **x != 0) + .copied() + .unwrap_or(16); + let mut line_lengths_iter = line_lengths.iter(); + let mut output = String::new(); + + loop { + let line_length = line_lengths_iter + .next() + .copied() + .unwrap_or(default_line_length); + if line_length == 0 { + output.push('\n'); + } else { + let line: Vec<_> = bytes_iter.by_ref().take(line_length).collect(); + + if line.is_empty() { + break; + } + + for byte in &line { + output.push_str(&format!("{:02x} ", byte)); + } + output.pop(); // Remove the trailing space + output.push('\n'); + } + } + + output +} + +/// This is a macro to assert that two byte slices are equal. +/// +/// It is like assert_eq!, but it will print a nicely formatted hexdump of the +/// two slices if they are not equal. This makes it much easier to track down +/// a difference in a large byte slice. +#[macro_export] +macro_rules! assert_eq_hex { + ($a:expr, $b:expr) => { + assert_eq_hex!($a, $b, []) + }; + ($a:expr, $b:expr, $hint:expr) => { + let a = $a; + let b = $b; + let hint = $hint; + let ar: &[u8] = a.as_ref(); + let br: &[u8] = b.as_ref(); + let hintr: &[usize] = hint.as_ref(); + if ar != br { + use $crate::util::hexdump::print_hexdump; + panic!( + "assertion failed: `(left == right)`\nleft:\n{}\nright:\n{}\n", + print_hexdump(ar, hintr), + print_hexdump(br, hintr), + ) + } + }; +} + +#[cfg(test)] +mod tests { + use super::{parse_hexdump, print_hexdump}; + + #[test] + fn test_basic() { + let input = r" + a1b2 # comment + 3c4d + "; + let result = parse_hexdump(input).unwrap(); + assert_eq!(result, vec![0xa1, 0xb2, 0x3c, 0x4d]); + } + + #[test] + fn test_upper_case() { + let input = r" + A1B2 # comment + 3C4D + "; + let result = parse_hexdump(input).unwrap(); + assert_eq!(result, vec![0xa1, 0xb2, 0x3c, 0x4d]); + } + + #[test] + fn test_mixed_case() { + let input = r" + a1B2 # comment + 3C4d + "; + let result = parse_hexdump(input).unwrap(); + assert_eq!(result, vec![0xa1, 0xb2, 0x3c, 0x4d]); + } + + #[test] + fn test_odd_characters() { + let input = r" + a1b + "; + let result = parse_hexdump(input); + assert!(result.is_err()); + } + + #[test] + fn test_invalid_characters() { + let input = r" + a1g2 # 'g' is not valid in hex + "; + let result = parse_hexdump(input); + assert!(result.is_err()); + } + #[test] + fn test_basic_hexdump() { + let data: &[u8] = &[0x1, 0x2, 0x3, 0x4, 0x5]; + let output = print_hexdump(data, [1, 2]); + assert_eq!(output, "01\n02 03\n04 05\n"); + } + + #[test] + fn test_newline_insertion() { + let data: &[u8] = &[0x1, 0x2, 0x3, 0x4]; + let output = print_hexdump(data, [1, 0, 2]); + assert_eq!(output, "01\n\n02 03\n04\n"); + } + + #[test] + fn test_indefinite_line_length() { + let data: &[u8] = &[0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + let output = print_hexdump(data, [2, 4]); + assert_eq!(output, "01 02\n03 04 05 06\n07 08\n"); + } + + #[test] + fn test_empty_data() { + let data: &[u8] = &[]; + let output = print_hexdump(data, [1, 2]); + assert_eq!(output, ""); + } + + #[test] + fn test_zeros_then_default() { + let data: &[u8] = &[0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]; + let output = print_hexdump(data, [1, 0, 0, 2]); + assert_eq!(output, "01\n\n\n02 03\n04 05\n06 07\n08\n"); + } +} diff --git a/src/util/local_pool.rs b/src/util/local_pool.rs index e4a804a38..5b0880dd9 100644 --- a/src/util/local_pool.rs +++ b/src/util/local_pool.rs @@ -543,6 +543,7 @@ mod tests { use std::{sync::atomic::AtomicU64, time::Duration}; use tracing::info; + use tracing_test::traced_test; use super::*; @@ -586,6 +587,7 @@ mod tests { } #[tokio::test] + #[traced_test] async fn test_tracing() { // This test wants to make sure that logging inside the pool propagates to the // tracing subscriber that was set for the current thread at the time the pool was @@ -599,7 +601,6 @@ mod tests { // cargo nextest run -p iroh-blobs local_pool::tests::test_tracing --success-output final // // and eyeball the output. yolo - let _guard = iroh_test::logging::setup(); info!("hello from the test"); let pool = LocalPool::single(); pool.spawn(|| async move { diff --git a/tests/blobs.rs b/tests/blobs.rs index c74484050..6779ebe9a 100644 --- a/tests/blobs.rs +++ b/tests/blobs.rs @@ -5,14 +5,13 @@ use std::{ }; use iroh::Endpoint; -use iroh_blobs::{net_protocol::Blobs, store::GcConfig, util::local_pool::LocalPool}; +use iroh_blobs::{net_protocol::Blobs, store::GcConfig}; use testresult::TestResult; #[tokio::test] async fn blobs_gc_smoke() -> TestResult<()> { - let pool = LocalPool::default(); let endpoint = Endpoint::builder().bind().await?; - let blobs = Blobs::memory().build(pool.handle(), &endpoint); + let blobs = Blobs::memory().build(&endpoint); let client = blobs.client(); blobs.start_gc(GcConfig { period: Duration::from_millis(1), @@ -29,9 +28,8 @@ async fn blobs_gc_smoke() -> TestResult<()> { #[tokio::test] async fn blobs_gc_protected() -> TestResult<()> { - let pool = LocalPool::default(); let endpoint = Endpoint::builder().bind().await?; - let blobs = Blobs::memory().build(pool.handle(), &endpoint); + let blobs = Blobs::memory().build(&endpoint); let client = blobs.client(); let h1 = client.add_bytes(b"test".to_vec()).await?; let protected = Arc::new(Mutex::new(Vec::new())); diff --git a/tests/gc.rs b/tests/gc.rs index 56ab4746c..dcf76b4ef 100644 --- a/tests/gc.rs +++ b/tests/gc.rs @@ -26,7 +26,6 @@ use iroh_blobs::{ MapMut, ReportLevel, Store, }, util::{ - local_pool::LocalPool, progress::{AsyncChannelProgressSender, ProgressSender as _}, Tag, }, @@ -42,7 +41,6 @@ pub struct Node { pub router: iroh::protocol::Router, pub blobs: Blobs, pub store: S, - pub _local_pool: LocalPool, } impl Node { @@ -100,8 +98,7 @@ pub fn simulate_remote(data: &[u8]) -> (blake3::Hash, Cursor) { async fn node(store: S, gc_period: Duration) -> (Node, async_channel::Receiver<()>) { let (gc_send, gc_recv) = async_channel::unbounded(); let endpoint = Endpoint::builder().discovery_n0().bind().await.unwrap(); - let local_pool = LocalPool::single(); - let blobs = Blobs::builder(store.clone()).build(&local_pool, &endpoint); + let blobs = Blobs::builder(store.clone()).build(&endpoint); let router = Router::builder(endpoint) .accept(iroh_blobs::ALPN, blobs.clone()) .spawn() @@ -120,7 +117,6 @@ async fn node(store: S, gc_period: Duration) -> (Node, async_channe store, router, blobs, - _local_pool: local_pool, }, gc_recv, ) @@ -192,7 +188,7 @@ async fn gc_basics() -> Result<()> { // create an explicit tag for h1 (as raw) and then delete the temp tag. Entry should still be there. let tag = Tag::from("test"); bao_store - .set_tag(tag.clone(), Some(HashAndFormat::raw(h2))) + .set_tag(tag.clone(), HashAndFormat::raw(h2)) .await?; drop(tt2); tracing::info!("dropped tt2"); @@ -200,7 +196,7 @@ async fn gc_basics() -> Result<()> { assert_eq!(bao_store.entry_status(&h2).await?, EntryStatus::Complete); // delete the explicit tag, entry should be gone - bao_store.set_tag(tag, None).await?; + bao_store.delete_tag(tag).await?; step(&evs).await; assert_eq!(bao_store.entry_status(&h2).await?, EntryStatus::NotFound); @@ -238,7 +234,7 @@ async fn gc_hashseq_impl() -> Result<()> { // make a permanent tag for the link seq, then delete the temp tag. Entries should still be there. let tag = Tag::from("test"); bao_store - .set_tag(tag.clone(), Some(HashAndFormat::hash_seq(hr))) + .set_tag(tag.clone(), HashAndFormat::hash_seq(hr)) .await?; drop(ttr); step(&evs).await; @@ -248,7 +244,7 @@ async fn gc_hashseq_impl() -> Result<()> { // change the permanent tag to be just for the linkseq itself as a blob. Only the linkseq should be there, not the entries. bao_store - .set_tag(tag.clone(), Some(HashAndFormat::raw(hr))) + .set_tag(tag.clone(), HashAndFormat::raw(hr)) .await?; step(&evs).await; assert_eq!(bao_store.entry_status(&h1).await?, EntryStatus::NotFound); @@ -256,7 +252,7 @@ async fn gc_hashseq_impl() -> Result<()> { assert_eq!(bao_store.entry_status(&hr).await?, EntryStatus::Complete); // delete the permanent tag, everything should be gone - bao_store.set_tag(tag, None).await?; + bao_store.delete_tag(tag).await?; step(&evs).await; assert_eq!(bao_store.entry_status(&h1).await?, EntryStatus::NotFound); assert_eq!(bao_store.entry_status(&h2).await?, EntryStatus::NotFound); @@ -343,7 +339,7 @@ async fn gc_file_basics() -> Result<()> { drop(tt2); let tag = Tag::from("test"); bao_store - .set_tag(tag.clone(), Some(HashAndFormat::hash_seq(*ttr.hash()))) + .set_tag(tag.clone(), HashAndFormat::hash_seq(*ttr.hash())) .await?; drop(ttr); @@ -363,7 +359,7 @@ async fn gc_file_basics() -> Result<()> { tracing::info!("changing tag from hashseq to raw, this should orphan the children"); bao_store - .set_tag(tag.clone(), Some(HashAndFormat::raw(hr))) + .set_tag(tag.clone(), HashAndFormat::raw(hr)) .await?; // now only hr itself should be protected, but not its children @@ -380,7 +376,7 @@ async fn gc_file_basics() -> Result<()> { assert!(!path(&hr).exists()); assert!(!outboard_path(&hr).exists()); - bao_store.set_tag(tag, None).await?; + bao_store.delete_tag(tag).await?; step(&evs).await; bao_store.sync().await?; assert!(check_consistency(&bao_store).await? <= ReportLevel::Info); @@ -508,7 +504,7 @@ async fn gc_file_stress() -> Result<()> { if i % 100 == 0 { let tag = Tag::from(format!("test{}", i)); bao_store - .set_tag(tag.clone(), Some(HashAndFormat::raw(*tt.hash()))) + .set_tag(tag.clone(), HashAndFormat::raw(*tt.hash())) .await?; live.push(*tt.hash()); } else { diff --git a/tests/rpc.rs b/tests/rpc.rs index 6eefc4930..7dc12e7b2 100644 --- a/tests/rpc.rs +++ b/tests/rpc.rs @@ -1,7 +1,7 @@ #![cfg(feature = "test")] use std::{net::SocketAddr, path::PathBuf, vec}; -use iroh_blobs::{net_protocol::Blobs, util::local_pool::LocalPool}; +use iroh_blobs::net_protocol::Blobs; use quic_rpc::client::QuinnConnector; use tempfile::TempDir; use testresult::TestResult; @@ -15,16 +15,14 @@ type BlobsClient = iroh_blobs::rpc::client::blobs::Client; pub struct Node { pub router: iroh::protocol::Router, pub blobs: Blobs, - pub local_pool: LocalPool, pub rpc_task: AbortOnDropHandle<()>, } impl Node { pub async fn new(path: PathBuf) -> anyhow::Result<(Self, SocketAddr, Vec)> { let store = iroh_blobs::store::fs::Store::load(path).await?; - let local_pool = LocalPool::default(); let endpoint = iroh::Endpoint::builder().bind().await?; - let blobs = Blobs::builder(store).build(local_pool.handle(), &endpoint); + let blobs = Blobs::builder(store).build(&endpoint); let router = iroh::protocol::Router::builder(endpoint) .accept(iroh_blobs::ALPN, blobs.clone()) .spawn() @@ -41,7 +39,6 @@ impl Node { let node = Self { router, blobs, - local_pool, rpc_task, }; Ok((node, local_addr, key)) diff --git a/tests/tags.rs b/tests/tags.rs new file mode 100644 index 000000000..8a4af2d54 --- /dev/null +++ b/tests/tags.rs @@ -0,0 +1,150 @@ +#![cfg(all(feature = "net_protocol", feature = "rpc"))] +use futures_lite::StreamExt; +use futures_util::Stream; +use iroh::Endpoint; +use iroh_blobs::{ + net_protocol::Blobs, + rpc::{ + client::tags::{self, TagInfo}, + proto::RpcService, + }, + Hash, HashAndFormat, +}; +use testresult::TestResult; + +async fn to_vec(stream: impl Stream>) -> anyhow::Result> { + let res = stream.collect::>().await; + res.into_iter().collect::>>() +} + +fn expected(tags: impl IntoIterator) -> Vec { + tags.into_iter() + .map(|tag| TagInfo::new(tag, Hash::new(tag))) + .collect() +} + +async fn set>( + tags: &tags::Client, + names: impl IntoIterator, +) -> TestResult<()> { + for name in names { + tags.set(name, Hash::new(name)).await?; + } + Ok(()) +} + +async fn tags_smoke>(tags: tags::Client) -> TestResult<()> { + set(&tags, ["a", "b", "c", "d", "e"]).await?; + let stream = tags.list().await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected(["a", "b", "c", "d", "e"])); + + let stream = tags.list_range("b".."d").await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected(["b", "c"])); + + let stream = tags.list_range("b"..).await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected(["b", "c", "d", "e"])); + + let stream = tags.list_range(.."d").await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected(["a", "b", "c"])); + + let stream = tags.list_range(..="d").await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected(["a", "b", "c", "d"])); + + tags.delete_range("b"..).await?; + let stream = tags.list().await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected(["a"])); + + tags.delete_range(..="a").await?; + let stream = tags.list().await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected([])); + + set(&tags, ["a", "aa", "aaa", "aab", "b"]).await?; + + let stream = tags.list_prefix("aa").await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected(["aa", "aaa", "aab"])); + + tags.delete_prefix("aa").await?; + let stream = tags.list().await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected(["a", "b"])); + + tags.delete_prefix("").await?; + let stream = tags.list().await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected([])); + + set(&tags, ["a", "b", "c"]).await?; + + assert_eq!( + tags.get("b").await?, + Some(TagInfo::new("b", Hash::new("b"))) + ); + + tags.delete("b").await?; + let stream = tags.list().await?; + let res = to_vec(stream).await?; + assert_eq!(res, expected(["a", "c"])); + + assert_eq!(tags.get("b").await?, None); + + tags.delete_all().await?; + + tags.set("a", HashAndFormat::hash_seq(Hash::new("a"))) + .await?; + tags.set("b", HashAndFormat::raw(Hash::new("b"))).await?; + let stream = tags.list_hash_seq().await?; + let res = to_vec(stream).await?; + assert_eq!( + res, + vec![TagInfo { + name: "a".into(), + hash: Hash::new("a"), + format: iroh_blobs::BlobFormat::HashSeq, + }] + ); + + tags.delete_all().await?; + set(&tags, ["c"]).await?; + tags.rename("c", "f").await?; + let stream = tags.list().await?; + let res = to_vec(stream).await?; + assert_eq!( + res, + vec![TagInfo { + name: "f".into(), + hash: Hash::new("c"), + format: iroh_blobs::BlobFormat::Raw, + }] + ); + + let res = tags.rename("y", "z").await; + assert!(res.is_err()); + Ok(()) +} + +#[tokio::test] +async fn tags_smoke_mem() -> TestResult<()> { + let endpoint = Endpoint::builder().bind().await?; + let blobs = Blobs::memory().build(&endpoint); + let client = blobs.client(); + tags_smoke(client.tags()).await +} + +#[tokio::test] +async fn tags_smoke_fs() -> TestResult<()> { + let td = tempfile::tempdir()?; + let endpoint = Endpoint::builder().bind().await?; + let blobs = Blobs::persistent(td.path().join("blobs.db")) + .await? + .build(&endpoint); + let client = blobs.client(); + tags_smoke(client.tags()).await +}