Compare commits
+3
-10
@@ -12,17 +12,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: rust:1
|
container: rust:1
|
||||||
steps:
|
steps:
|
||||||
# Not the checkout action: it runs on node, which the rust:1 job
|
# v4 built-in checkout: native Go, needs no Node (rust:1 has none) and
|
||||||
# container doesn't have and this runner doesn't inject (the v5
|
# keeps the token out of a fetch URL. Uses the job token for the private repo.
|
||||||
# run died with 'exec: "node": not found'). Plain git needs
|
|
||||||
# neither, and the token URL works against the private repo.
|
|
||||||
- name: checkout
|
- name: checkout
|
||||||
run: |
|
uses: builtin:checkout
|
||||||
git init -q .
|
|
||||||
git fetch --depth 1 \
|
|
||||||
"https://gitea:${{ secrets.GITHUB_TOKEN }}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git" \
|
|
||||||
"$GITHUB_SHA"
|
|
||||||
git checkout -q FETCH_HEAD
|
|
||||||
- name: rustfmt
|
- name: rustfmt
|
||||||
run: |
|
run: |
|
||||||
rustup component add rustfmt
|
rustup component add rustfmt
|
||||||
|
|||||||
@@ -19,24 +19,22 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
target: [x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu]
|
target: [x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu]
|
||||||
steps:
|
steps:
|
||||||
# Not the checkout action: it runs on node, which the rust:1 job
|
# v4 built-in checkout: native Go, needs no Node (rust:1 has none) and
|
||||||
# container doesn't have and this runner doesn't inject (the v5
|
# keeps the token out of a fetch URL. Uses the job token for the private repo.
|
||||||
# run died with 'exec: "node": not found'). Plain git needs
|
|
||||||
# neither, and the token URL works against the private repo.
|
|
||||||
- name: checkout
|
- name: checkout
|
||||||
run: |
|
uses: builtin:checkout
|
||||||
git init -q .
|
|
||||||
git fetch --depth 1 \
|
|
||||||
"https://gitea:${{ secrets.GITHUB_TOKEN }}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git" \
|
|
||||||
"$GITHUB_SHA"
|
|
||||||
git checkout -q FETCH_HEAD
|
|
||||||
|
|
||||||
- name: install tooling
|
- name: install tooling
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y --no-install-recommends scdoc jq
|
apt-get install -y --no-install-recommends scdoc jq
|
||||||
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
|
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
|
||||||
apt-get install -y --no-install-recommends gcc-aarch64-linux-gnu
|
# libc6-dev-arm64-cross is a Recommends of the cross gcc, so
|
||||||
|
# --no-install-recommends skips it — without it cc-rs builds
|
||||||
|
# (blake3's NEON unit) fall back to host headers and die on
|
||||||
|
# bits/wordsize.h.
|
||||||
|
apt-get install -y --no-install-recommends \
|
||||||
|
gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||||
fi
|
fi
|
||||||
rustup target add ${{ matrix.target }}
|
rustup target add ${{ matrix.target }}
|
||||||
|
|
||||||
@@ -50,7 +48,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
VERSION="${GITHUB_REF_NAME#v}"
|
VERSION="${GITHUB_REF_NAME#v}"
|
||||||
PKG="varde-${VERSION}-${{ matrix.target }}"
|
PKG="varde-${VERSION}-${{ matrix.target }}"
|
||||||
mkdir -p "$PKG"/{bin,systemd/user,man}
|
# Steps run under plain `sh`, which has no brace expansion —
|
||||||
|
# spell the directories out.
|
||||||
|
mkdir -p "$PKG/bin" "$PKG/systemd/user" "$PKG/man"
|
||||||
cp "target/${{ matrix.target }}/release/varde-daemon" \
|
cp "target/${{ matrix.target }}/release/varde-daemon" \
|
||||||
"target/${{ matrix.target }}/release/varde-ctl" "$PKG/bin/"
|
"target/${{ matrix.target }}/release/varde-ctl" "$PKG/bin/"
|
||||||
# Cross-strip is unavailable for the foreign target; native
|
# Cross-strip is unavailable for the foreign target; native
|
||||||
@@ -89,3 +89,45 @@ jobs:
|
|||||||
-H "Authorization: token $TOKEN" \
|
-H "Authorization: token $TOKEN" \
|
||||||
-F "attachment=@$f"
|
-F "attachment=@$f"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# The uhhm Arch registry (pacman.conf: .../api/packages/bl/arch/uhhm),
|
||||||
|
# from the tarballs just released. On klokka: an Arch host with
|
||||||
|
# makepkg. REGISTRY_TOKEN is the uhhm org's write:package token.
|
||||||
|
publish:
|
||||||
|
needs: build
|
||||||
|
runs-on: aarch64
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: builtin:checkout
|
||||||
|
- name: fetch tarballs and pin the PKGBUILD
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
TAG="${GITHUB_REF_NAME}"
|
||||||
|
VERSION="${TAG#v}"
|
||||||
|
BASE="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${TAG}"
|
||||||
|
cd dist/arch
|
||||||
|
for t in x86_64 aarch64; do
|
||||||
|
f="varde-${VERSION}-${t}-unknown-linux-gnu.tar.gz"
|
||||||
|
# The repo is private: anonymous release downloads 404.
|
||||||
|
curl -fsSL -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -o "$f" "$BASE/$f"
|
||||||
|
done
|
||||||
|
SUM_X86=$(sha256sum "varde-${VERSION}-x86_64-unknown-linux-gnu.tar.gz" | cut -d' ' -f1)
|
||||||
|
SUM_AARCH=$(sha256sum "varde-${VERSION}-aarch64-unknown-linux-gnu.tar.gz" | cut -d' ' -f1)
|
||||||
|
sed -i "s/^pkgver=.*/pkgver=${VERSION}/" PKGBUILD
|
||||||
|
sed -i "s/sha256sums_x86_64=('.*')/sha256sums_x86_64=('${SUM_X86}')/" PKGBUILD
|
||||||
|
sed -i "s/sha256sums_aarch64=('.*')/sha256sums_aarch64=('${SUM_AARCH}')/" PKGBUILD
|
||||||
|
- name: publish to the uhhm Arch registry
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
if [ -z "${{ secrets.REGISTRY_TOKEN }}" ]; then
|
||||||
|
echo "::error::REGISTRY_TOKEN not set - add it to publish"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cd dist/arch
|
||||||
|
for carch in aarch64 x86_64; do
|
||||||
|
pkgfile=$(CARCH="$carch" makepkg --packagelist | tail -1)
|
||||||
|
CARCH="$carch" makepkg -f --nodeps --noconfirm
|
||||||
|
curl --fail-with-body --user "bl:${{ secrets.REGISTRY_TOKEN }}" \
|
||||||
|
--upload-file "$pkgfile" \
|
||||||
|
"${GITHUB_SERVER_URL}/api/packages/bl/arch/uhhm"
|
||||||
|
done
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
target/
|
target/
|
||||||
.claude/
|
.claude/
|
||||||
|
.DS_Store
|
||||||
|
|||||||
Generated
+149
-371
@@ -431,9 +431,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg_aliases"
|
name = "cfg_aliases"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chacha20"
|
name = "chacha20"
|
||||||
@@ -581,16 +581,6 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core-foundation"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
|
||||||
dependencies = [
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
@@ -631,24 +621,6 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-channel"
|
|
||||||
version = "0.5.16"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.9.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.22"
|
version = "0.8.22"
|
||||||
@@ -722,41 +694,6 @@ dependencies = [
|
|||||||
"syn 2.0.118",
|
"syn 2.0.118",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling"
|
|
||||||
version = "0.20.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
|
|
||||||
dependencies = [
|
|
||||||
"darling_core",
|
|
||||||
"darling_macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling_core"
|
|
||||||
version = "0.20.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
|
|
||||||
dependencies = [
|
|
||||||
"fnv",
|
|
||||||
"ident_case",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"strsim",
|
|
||||||
"syn 2.0.118",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "darling_macro"
|
|
||||||
version = "0.20.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
|
||||||
dependencies = [
|
|
||||||
"darling_core",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.118",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "data-encoding"
|
name = "data-encoding"
|
||||||
version = "2.11.0"
|
version = "2.11.0"
|
||||||
@@ -814,65 +751,13 @@ version = "0.5.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_builder"
|
|
||||||
version = "0.20.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
|
|
||||||
dependencies = [
|
|
||||||
"derive_builder_macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_builder_core"
|
|
||||||
version = "0.20.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
|
|
||||||
dependencies = [
|
|
||||||
"darling",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.118",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_builder_macro"
|
|
||||||
version = "0.20.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
|
|
||||||
dependencies = [
|
|
||||||
"derive_builder_core",
|
|
||||||
"syn 2.0.118",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_more"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
|
|
||||||
dependencies = [
|
|
||||||
"derive_more-impl 1.0.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
|
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more-impl 2.1.1",
|
"derive_more-impl",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "derive_more-impl"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.118",
|
|
||||||
"unicode-xid",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -966,12 +851,6 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "either"
|
|
||||||
version = "1.17.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embedded-io"
|
name = "embedded-io"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -1406,35 +1285,6 @@ version = "0.4.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hickory-net"
|
|
||||||
version = "0.26.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2295ed2f9c31e471e1428a8f88a3f0e1f4b27c15049592138d1eebe9c35b183"
|
|
||||||
dependencies = [
|
|
||||||
"async-trait",
|
|
||||||
"bytes",
|
|
||||||
"cfg-if",
|
|
||||||
"data-encoding",
|
|
||||||
"futures-channel",
|
|
||||||
"futures-io",
|
|
||||||
"futures-util",
|
|
||||||
"h2",
|
|
||||||
"hickory-proto",
|
|
||||||
"http",
|
|
||||||
"idna",
|
|
||||||
"ipnet",
|
|
||||||
"jni 0.22.4",
|
|
||||||
"rand 0.10.2",
|
|
||||||
"rustls",
|
|
||||||
"thiserror 2.0.18",
|
|
||||||
"tinyvec",
|
|
||||||
"tokio",
|
|
||||||
"tokio-rustls",
|
|
||||||
"tracing",
|
|
||||||
"url",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hickory-proto"
|
name = "hickory-proto"
|
||||||
version = "0.26.1"
|
version = "0.26.1"
|
||||||
@@ -1446,43 +1296,13 @@ dependencies = [
|
|||||||
"ipnet",
|
"ipnet",
|
||||||
"jni 0.22.4",
|
"jni 0.22.4",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"prefix-trie",
|
|
||||||
"rand 0.10.2",
|
"rand 0.10.2",
|
||||||
"ring",
|
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hickory-resolver"
|
|
||||||
version = "0.26.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f0d58d28879ceecde6607729660c2667a081ccdc082e082675042793960f178c"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"futures-util",
|
|
||||||
"hickory-net",
|
|
||||||
"hickory-proto",
|
|
||||||
"ipconfig",
|
|
||||||
"ipnet",
|
|
||||||
"jni 0.22.4",
|
|
||||||
"moka",
|
|
||||||
"ndk-context",
|
|
||||||
"once_cell",
|
|
||||||
"parking_lot",
|
|
||||||
"rand 0.10.2",
|
|
||||||
"resolv-conf",
|
|
||||||
"rustls",
|
|
||||||
"smallvec",
|
|
||||||
"system-configuration",
|
|
||||||
"thiserror 2.0.18",
|
|
||||||
"tokio",
|
|
||||||
"tokio-rustls",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.4.2"
|
version = "1.4.2"
|
||||||
@@ -1703,12 +1523,6 @@ dependencies = [
|
|||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ident_case"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "identity-hash"
|
name = "identity-hash"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -1802,15 +1616,12 @@ name = "ipnet"
|
|||||||
version = "2.12.0"
|
version = "2.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
|
checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iroh"
|
name = "iroh"
|
||||||
version = "1.0.2"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fca9b4b462c343ff88fc0af4096c186f939b602a0bc08723536ef2c31c93971"
|
checksum = "885787b892b5e2507c701f132ecbd45d2bad4bbb75157a19427087c16dadb833"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backon",
|
"backon",
|
||||||
"blake3",
|
"blake3",
|
||||||
@@ -1818,11 +1629,10 @@ dependencies = [
|
|||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"ctutils",
|
"ctutils",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"hickory-resolver",
|
|
||||||
"http",
|
"http",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"iroh-base",
|
"iroh-base",
|
||||||
@@ -1830,7 +1640,7 @@ dependencies = [
|
|||||||
"iroh-metrics",
|
"iroh-metrics",
|
||||||
"iroh-relay",
|
"iroh-relay",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"n0-watcher",
|
"n0-watcher",
|
||||||
"netwatch",
|
"netwatch",
|
||||||
"noq",
|
"noq",
|
||||||
@@ -1859,14 +1669,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iroh-base"
|
name = "iroh-base"
|
||||||
version = "1.0.3"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6be73e16ee21c923aca9b3121aaa0db936f7c7ecc156ff47b8dac944c68d59a8"
|
checksum = "6ae9092be76c9f5429776ab3394f5a5a78dc19dc2524267e884a5b9781546c3f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"data-encoding-macro",
|
"data-encoding-macro",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
@@ -1889,7 +1699,7 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"constant_time_eq",
|
"constant_time_eq",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"genawaiter",
|
"genawaiter",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -1901,7 +1711,7 @@ dependencies = [
|
|||||||
"iroh-util",
|
"iroh-util",
|
||||||
"irpc",
|
"irpc",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"nested_enum_utils",
|
"nested_enum_utils",
|
||||||
"noq",
|
"noq",
|
||||||
"postcard",
|
"postcard",
|
||||||
@@ -1919,18 +1729,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iroh-dns"
|
name = "iroh-dns"
|
||||||
version = "1.0.2"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "516e4eedc38e33ab69a6bd325520332dc3d67b25454e2d590ebb84a25240dd9a"
|
checksum = "80276761b56e904e26ea71d0863beef0bb8d5ab6b639cbd1338e4b615209e3a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"hickory-resolver",
|
|
||||||
"iroh-base",
|
"iroh-base",
|
||||||
|
"n0-dns-resolver",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"ndk-context",
|
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"rand 0.10.2",
|
"rand 0.10.2",
|
||||||
"rustls",
|
"rustls",
|
||||||
@@ -1956,17 +1765,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iroh-mdns-address-lookup"
|
name = "iroh-mdns-address-lookup"
|
||||||
version = "0.4.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7c1f941695731bc3999d8c13d7e94d50e229427da81ac957eec3818264f17559"
|
checksum = "7afb03c296022fcb724a7bb76dbb8dcca6aac4f4eb65df161e084b7276c93d8c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"iroh",
|
"iroh",
|
||||||
"iroh-base",
|
"iroh-base",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"n0-watcher",
|
"n0-watcher",
|
||||||
"swarm-discovery",
|
"swarm-discovery",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -1976,9 +1785,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iroh-metrics"
|
name = "iroh-metrics"
|
||||||
version = "1.0.1"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "291065721ad7c477b972e581bbc528df031dc8eb5e39fe1ff3300ae5dfb157ef"
|
checksum = "8ede55536349842337f7cdc63012ec33dc637945f3259c98a0763aac364cdf09"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iroh-metrics-derive",
|
"iroh-metrics-derive",
|
||||||
"itoa",
|
"itoa",
|
||||||
@@ -2003,17 +1812,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iroh-relay"
|
name = "iroh-relay"
|
||||||
version = "1.0.2"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8149bb6a57126225a07d6928846d82dcedfd24ea0f863ef7b2eb475e1d726354"
|
checksum = "ee116a8233f84980574bb8d11e4517503080cd2c3605bafca04ee9c35d708bd9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake3",
|
"blake3",
|
||||||
"bytes",
|
"bytes",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"hickory-resolver",
|
|
||||||
"http",
|
"http",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
@@ -2023,7 +1831,7 @@ dependencies = [
|
|||||||
"iroh-metrics",
|
"iroh-metrics",
|
||||||
"lru",
|
"lru",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"noq",
|
"noq",
|
||||||
"noq-proto",
|
"noq-proto",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
@@ -2042,7 +1850,6 @@ dependencies = [
|
|||||||
"tokio-websockets",
|
"tokio-websockets",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
"vergen-gitcl",
|
|
||||||
"webpki-roots",
|
"webpki-roots",
|
||||||
"ws_stream_wasm",
|
"ws_stream_wasm",
|
||||||
]
|
]
|
||||||
@@ -2054,7 +1861,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "da53233419ca36bf521ed45683b7748366f9b233032891eefc2d70567a84ac54"
|
checksum = "da53233419ca36bf521ed45683b7748366f9b233032891eefc2d70567a84ac54"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"iroh-base",
|
"iroh-base",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"postcard",
|
"postcard",
|
||||||
@@ -2067,10 +1874,10 @@ version = "0.6.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "20e41eb982f15230c55f0a70a74a514360e1f565b07861924fd0e8db172b3d00"
|
checksum = "20e41eb982f15230c55f0a70a74a514360e1f565b07861924fd0e8db172b3d00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"iroh",
|
"iroh",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -2085,7 +1892,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"irpc-derive",
|
"irpc-derive",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"noq",
|
"noq",
|
||||||
"postcard",
|
"postcard",
|
||||||
"rcgen",
|
"rcgen",
|
||||||
@@ -2326,20 +2133,28 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moka"
|
name = "n0-dns-resolver"
|
||||||
version = "0.12.15"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046"
|
checksum = "535c99c9a786bee714155d2ee4fc2477405c2c43536e1bc6a51de09a0d1448f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-channel",
|
"derive_more",
|
||||||
"crossbeam-epoch",
|
"ipconfig",
|
||||||
"crossbeam-utils",
|
"jni 0.22.4",
|
||||||
"equivalent",
|
"lru",
|
||||||
"parking_lot",
|
"n0-error",
|
||||||
"portable-atomic",
|
"n0-future",
|
||||||
"smallvec",
|
"ndk-context",
|
||||||
"tagptr",
|
"rand 0.10.2",
|
||||||
"uuid",
|
"reqwest",
|
||||||
|
"rustc-hash",
|
||||||
|
"rustls",
|
||||||
|
"simple-dns",
|
||||||
|
"system-configuration",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
"tracing",
|
||||||
|
"webpki-roots",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2363,27 +2178,6 @@ dependencies = [
|
|||||||
"syn 2.0.118",
|
"syn 2.0.118",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "n0-future"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794"
|
|
||||||
dependencies = [
|
|
||||||
"cfg_aliases",
|
|
||||||
"derive_more 1.0.0",
|
|
||||||
"futures-buffered",
|
|
||||||
"futures-lite",
|
|
||||||
"futures-util",
|
|
||||||
"js-sys",
|
|
||||||
"pin-project",
|
|
||||||
"send_wrapper",
|
|
||||||
"tokio",
|
|
||||||
"tokio-util",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"wasm-bindgen-futures",
|
|
||||||
"web-time",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "n0-future"
|
name = "n0-future"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
@@ -2391,7 +2185,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e2ab99dfb861450e68853d34ae665243a88b8c493d01ba957321a1e9b2312bbe"
|
checksum = "e2ab99dfb861450e68853d34ae665243a88b8c493d01ba957321a1e9b2312bbe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"futures-buffered",
|
"futures-buffered",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@@ -2411,9 +2205,9 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbc618745ad0b7414b149d0517ad8b5573b2fb4d4e2717add3d2446ce1fdd826"
|
checksum = "bbc618745ad0b7414b149d0517ad8b5573b2fb4d4e2717add3d2446ce1fdd826"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2448,9 +2242,9 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"mac-addr",
|
"mac-addr",
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
"netlink-packet-core",
|
"netlink-packet-core 0.8.2",
|
||||||
"netlink-packet-route",
|
"netlink-packet-route 0.31.0",
|
||||||
"netlink-sys",
|
"netlink-sys 0.8.8",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-core-wlan",
|
"objc2-core-wlan",
|
||||||
@@ -2461,6 +2255,30 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "netdev"
|
||||||
|
version = "0.46.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3c52c2584961c68f5a6e3356797344061f818c93b8acc9cd6d7e284795e563e"
|
||||||
|
dependencies = [
|
||||||
|
"block2",
|
||||||
|
"dispatch2",
|
||||||
|
"dlopen2",
|
||||||
|
"ipnet",
|
||||||
|
"jni 0.21.1",
|
||||||
|
"libc",
|
||||||
|
"mac-addr",
|
||||||
|
"ndk-context",
|
||||||
|
"netlink-packet-core 0.9.0",
|
||||||
|
"netlink-packet-route 0.33.0",
|
||||||
|
"netlink-sys 0.9.0",
|
||||||
|
"objc2-core-foundation",
|
||||||
|
"objc2-system-configuration",
|
||||||
|
"once_cell",
|
||||||
|
"plist",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "netlink-packet-core"
|
name = "netlink-packet-core"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@@ -2470,6 +2288,12 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "netlink-packet-core"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2d6e2daf9a8c2e21302714706860a0e6be02e03d17294ecc66b354ea7d4059dd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "netlink-packet-route"
|
name = "netlink-packet-route"
|
||||||
version = "0.31.0"
|
version = "0.31.0"
|
||||||
@@ -2479,7 +2303,20 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"netlink-packet-core",
|
"netlink-packet-core 0.8.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "netlink-packet-route"
|
||||||
|
version = "0.33.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59d48ffc8b73a506e1ff0878528c72668f2bfbc3d875b6be890a96be5d0d5576"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"netlink-packet-core 0.9.0",
|
||||||
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2492,8 +2329,8 @@ dependencies = [
|
|||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"log",
|
"log",
|
||||||
"netlink-packet-core",
|
"netlink-packet-core 0.8.2",
|
||||||
"netlink-sys",
|
"netlink-sys 0.8.8",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2511,26 +2348,38 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "netwatch"
|
name = "netlink-sys"
|
||||||
version = "0.19.1"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d9cbe01741347ef750d743d6690603f5eed8341e679fb51c8e629337aa11976"
|
checksum = "c99d38e00b420df49e940fe0826e667c3dad82ac68eb4c2bbf754c1c14a83a10"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "netwatch"
|
||||||
|
version = "0.19.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39da9cad5f23aa43401f09497d3b280e51b5feba115d9ffbf38ca35d6ff95e96"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"bytes",
|
"bytes",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"ipnet",
|
"ipnet",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"n0-watcher",
|
"n0-watcher",
|
||||||
"netdev",
|
"netdev 0.45.0",
|
||||||
"netlink-packet-core",
|
"netdev 0.46.3",
|
||||||
"netlink-packet-route",
|
"netlink-packet-core 0.8.2",
|
||||||
|
"netlink-packet-route 0.31.0",
|
||||||
"netlink-proto",
|
"netlink-proto",
|
||||||
"netlink-sys",
|
"netlink-sys 0.8.8",
|
||||||
"noq-udp",
|
"noq-udp",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-system-configuration",
|
"objc2-system-configuration",
|
||||||
@@ -2559,13 +2408,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "noq"
|
name = "noq"
|
||||||
version = "1.0.1"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4bf95190af1bd4a00a10e8255ca0c8ddd9e9a9f5e79151d7a7eb6d56aff5dc89"
|
checksum = "b78be567e796cfa74bb9bdc4117790af2d505eb887019cf8803244353eb09d89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"noq-proto",
|
"noq-proto",
|
||||||
"noq-udp",
|
"noq-udp",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -2581,13 +2430,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "noq-proto"
|
name = "noq-proto"
|
||||||
version = "1.1.1"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baa7b5ccd819a9c68a0d955e67a881032d09b1a17219b1f90b0997a0888e1a15"
|
checksum = "7c1e5b6fe668491eca022f745a0a9402585626c73a7b839b3424ace15d6a9c8f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"bytes",
|
"bytes",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"enum-assoc",
|
"enum-assoc",
|
||||||
"fastbloom",
|
"fastbloom",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
@@ -2610,9 +2459,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "noq-udp"
|
name = "noq-udp"
|
||||||
version = "1.0.1"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3137a52df66c20090a889828d1c655f21f52294cba64e5c4fbb04fc83eee7c8e"
|
checksum = "4dc50afea61aff926e150a36c31f06094608848e114a3fe667d76ec233163b1c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -2686,15 +2535,6 @@ dependencies = [
|
|||||||
"syn 2.0.118",
|
"syn 2.0.118",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_threads"
|
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2"
|
name = "objc2"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
@@ -2984,19 +2824,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portmapper"
|
name = "portmapper"
|
||||||
version = "0.19.1"
|
version = "0.19.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb3713e4977408279158444a18c1a01ac9bf2e7eaf1fbfd1a19ac9cd18d90721"
|
checksum = "ca97242f016e090a25330613bc2382aab65eb22f9149dbe84d8f8e711d49a530"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
"derive_more 2.1.1",
|
"derive_more",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"igd-next",
|
"igd-next",
|
||||||
"iroh-metrics",
|
"iroh-metrics",
|
||||||
"libc",
|
"libc",
|
||||||
"n0-error",
|
"n0-error",
|
||||||
"n0-future 0.3.2",
|
"n0-future",
|
||||||
"netwatch",
|
"netwatch",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"rand 0.10.2",
|
"rand 0.10.2",
|
||||||
@@ -3070,17 +2910,6 @@ dependencies = [
|
|||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "prefix-trie"
|
|
||||||
version = "0.8.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4cf6e3177f0684016a5c209b00882e15f8bdd3f3bb48f0491df10cd102d0c6e7"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"ipnet",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "3.5.0"
|
version = "3.5.0"
|
||||||
@@ -3381,12 +3210,6 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "resolv-conf"
|
|
||||||
version = "0.7.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.17.14"
|
version = "0.17.14"
|
||||||
@@ -3481,7 +3304,7 @@ version = "0.7.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
|
checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation 0.10.1",
|
"core-foundation",
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"jni 0.22.4",
|
"jni 0.22.4",
|
||||||
"log",
|
"log",
|
||||||
@@ -3574,7 +3397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
|
checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"core-foundation 0.10.1",
|
"core-foundation",
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"security-framework-sys",
|
"security-framework-sys",
|
||||||
@@ -3767,9 +3590,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simple-dns"
|
name = "simple-dns"
|
||||||
version = "0.11.3"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a75cbde1bf934313596a004973e462f9a82caa814dcf1a5f507bdf51597eeb4"
|
checksum = "2b6f884fa9a8d48101774bfbd3aeb81e968dd22cffd19a372da69f183db22c1a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
@@ -3973,12 +3796,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-configuration"
|
name = "system-configuration"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
|
checksum = "501336eb7ba9e417300a6a0fa985721065467aa83a6dcf0422a8e43e4c0328fa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"core-foundation 0.9.4",
|
"core-foundation",
|
||||||
"system-configuration-sys",
|
"system-configuration-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3992,12 +3815,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tagptr"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.27.0"
|
version = "3.27.0"
|
||||||
@@ -4005,7 +3822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.3.4",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
@@ -4068,9 +3885,7 @@ checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
|
||||||
"num-conv",
|
"num-conv",
|
||||||
"num_threads",
|
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
"time-core",
|
"time-core",
|
||||||
@@ -4477,7 +4292,6 @@ version = "1.23.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea5fab0d6c3c01ae70085a09cb03d4c7a1d6314e2b3e075392783396d724ca0a"
|
checksum = "ea5fab0d6c3c01ae70085a09cb03d4c7a1d6314e2b3e075392783396d724ca0a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.4.3",
|
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -4491,7 +4305,7 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "varde-ctl"
|
name = "varde-ctl"
|
||||||
version = "0.1.0"
|
version = "0.1.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -4504,14 +4318,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "varde-daemon"
|
name = "varde-daemon"
|
||||||
version = "0.1.0"
|
version = "0.1.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"base64",
|
||||||
"iroh",
|
"iroh",
|
||||||
"iroh-blobs",
|
"iroh-blobs",
|
||||||
"iroh-mdns-address-lookup",
|
"iroh-mdns-address-lookup",
|
||||||
"irpc",
|
"irpc",
|
||||||
"n0-future 0.1.3",
|
"n0-future",
|
||||||
"postcard",
|
"postcard",
|
||||||
"proptest",
|
"proptest",
|
||||||
"reflink-copy",
|
"reflink-copy",
|
||||||
@@ -4529,49 +4344,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "varde-proto"
|
name = "varde-proto"
|
||||||
version = "0.1.0"
|
version = "0.1.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vergen"
|
|
||||||
version = "9.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"derive_builder",
|
|
||||||
"rustversion",
|
|
||||||
"vergen-lib",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vergen-gitcl"
|
|
||||||
version = "9.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77ff3b5300a085d6bcd8fc96a507f706a28ae3814693236c9b409db71a1d15b9"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"derive_builder",
|
|
||||||
"rustversion",
|
|
||||||
"time",
|
|
||||||
"vergen",
|
|
||||||
"vergen-lib",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vergen-lib"
|
|
||||||
version = "9.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"derive_builder",
|
|
||||||
"rustversion",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.5"
|
version = "0.9.5"
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ resolver = "2"
|
|||||||
members = ["varde-proto", "varde-daemon", "varde-ctl"]
|
members = ["varde-proto", "varde-daemon", "varde-ctl"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.0"
|
version = "0.1.10"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://project.uhhm.no/uhhm/varde"
|
repository = "https://project.uhhm.no/uhhm/varde"
|
||||||
|
|||||||
Vendored
+41
@@ -0,0 +1,41 @@
|
|||||||
|
# The uhhm Arch registry package, built by .gitea/workflows/release.yml
|
||||||
|
# from the release tarballs (the CI pins pkgver and the sums). For a
|
||||||
|
# from-source build (AUR style) see ../PKGBUILD.
|
||||||
|
pkgname=varde
|
||||||
|
pkgver=0.1.3
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="Content-addressed blob mirror daemon on iroh"
|
||||||
|
arch=('x86_64' 'aarch64')
|
||||||
|
url="https://project.uhhm.no/uhhm/varde"
|
||||||
|
license=('MIT OR Apache-2.0')
|
||||||
|
depends=('gcc-libs' 'glibc')
|
||||||
|
optdepends=('networkmanager: metered-connection detection')
|
||||||
|
backup=('etc/varde/config.toml')
|
||||||
|
install=varde.install
|
||||||
|
options=('!strip' '!debug')
|
||||||
|
source_x86_64=("varde-${pkgver}-x86_64-unknown-linux-gnu.tar.gz")
|
||||||
|
source_aarch64=("varde-${pkgver}-aarch64-unknown-linux-gnu.tar.gz")
|
||||||
|
sha256sums_x86_64=('SKIP')
|
||||||
|
sha256sums_aarch64=('SKIP')
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd "varde-${pkgver}-${CARCH}-unknown-linux-gnu"
|
||||||
|
install -Dm755 bin/varde-daemon "$pkgdir/usr/bin/varde-daemon"
|
||||||
|
install -Dm755 bin/varde-ctl "$pkgdir/usr/bin/varde-ctl"
|
||||||
|
|
||||||
|
install -Dm644 systemd/varde.service "$pkgdir/usr/lib/systemd/system/varde.service"
|
||||||
|
install -Dm644 systemd/varde.socket "$pkgdir/usr/lib/systemd/system/varde.socket"
|
||||||
|
install -Dm644 systemd/user/varde.service "$pkgdir/usr/lib/systemd/user/varde.service"
|
||||||
|
install -Dm644 systemd/user/varde.socket "$pkgdir/usr/lib/systemd/user/varde.socket"
|
||||||
|
# The per-user socket is on for every session, the way PipeWire's
|
||||||
|
# is: it costs nothing until an app connects, and then the daemon
|
||||||
|
# starts by socket activation. The system daemon stays opt-in.
|
||||||
|
install -dm755 "$pkgdir/usr/lib/systemd/user/sockets.target.wants"
|
||||||
|
ln -s ../varde.socket "$pkgdir/usr/lib/systemd/user/sockets.target.wants/varde.socket"
|
||||||
|
|
||||||
|
install -Dm644 config.toml.example "$pkgdir/etc/varde/config.toml"
|
||||||
|
install -Dm644 man/varde.8 "$pkgdir/usr/share/man/man8/varde.8"
|
||||||
|
install -Dm644 man/varde-ctl.1 "$pkgdir/usr/share/man/man1/varde-ctl.1"
|
||||||
|
install -Dm644 LICENSE-MIT "$pkgdir/usr/share/licenses/$pkgname/LICENSE-MIT"
|
||||||
|
install -Dm644 LICENSE-APACHE "$pkgdir/usr/share/licenses/$pkgname/LICENSE-APACHE"
|
||||||
|
}
|
||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
post_install() {
|
||||||
|
echo ":: The per-user varde socket starts with your next login."
|
||||||
|
echo " To use it now: systemctl --user daemon-reload && systemctl --user start varde.socket"
|
||||||
|
echo " The system daemon is opt-in: systemctl enable --now varde.socket"
|
||||||
|
}
|
||||||
|
|
||||||
|
post_upgrade() {
|
||||||
|
echo ":: Restart a running daemon to pick up the new version - the socket, not the service:"
|
||||||
|
echo " systemctl try-restart varde.socket; systemctl --user try-restart varde.socket"
|
||||||
|
}
|
||||||
Vendored
+7
-1
@@ -15,7 +15,13 @@ Restart=on-failure
|
|||||||
# Hardening
|
# Hardening
|
||||||
DynamicUser=yes
|
DynamicUser=yes
|
||||||
StateDirectory=varde
|
StateDirectory=varde
|
||||||
RuntimeDirectory=varde
|
# No RuntimeDirectory= here: varde.socket creates /run/varde for its
|
||||||
|
# socket file, and the service only uses the activation socket. With
|
||||||
|
# RuntimeDirectory= on the service, stopping it removed the socket file
|
||||||
|
# from under the socket unit (0.1.6 and earlier), and preserving it
|
||||||
|
# (0.1.7/0.1.8) made systemd privatise the directory under DynamicUser -
|
||||||
|
# /run/varde -> /run/private/varde, 0700 - so no unprivileged client
|
||||||
|
# could connect at all.
|
||||||
NoNewPrivileges=yes
|
NoNewPrivileges=yes
|
||||||
ProtectSystem=strict
|
ProtectSystem=strict
|
||||||
ProtectHome=yes
|
ProtectHome=yes
|
||||||
|
|||||||
Vendored
+3
@@ -5,6 +5,9 @@ Description=varde API socket
|
|||||||
[Socket]
|
[Socket]
|
||||||
ListenStream=/run/varde/varde.sock
|
ListenStream=/run/varde/varde.sock
|
||||||
SocketMode=0666
|
SocketMode=0666
|
||||||
|
# The directory is this unit's, world-readable, so clients of any user
|
||||||
|
# reach the socket (see varde.service for why the service must not own it).
|
||||||
|
DirectoryMode=0755
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=sockets.target
|
WantedBy=sockets.target
|
||||||
|
|||||||
+23
-1
@@ -73,7 +73,8 @@ enum Command {
|
|||||||
/// Peer trust operations
|
/// Peer trust operations
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
Peer(PeerCommand),
|
Peer(PeerCommand),
|
||||||
/// Push fully-present content to a trusted peer
|
/// Push fully-present content to a trusted peer, or one allowed to
|
||||||
|
/// exchange pushes
|
||||||
Push {
|
Push {
|
||||||
/// BLAKE3 hash (hex)
|
/// BLAKE3 hash (hex)
|
||||||
hash: String,
|
hash: String,
|
||||||
@@ -116,6 +117,14 @@ enum PeerCommand {
|
|||||||
/// iroh NodeId (z-base-32)
|
/// iroh NodeId (z-base-32)
|
||||||
node_id: String,
|
node_id: String,
|
||||||
},
|
},
|
||||||
|
/// Allow pushes with a peer for a while, without trusting it
|
||||||
|
AllowPush {
|
||||||
|
/// iroh NodeId (z-base-32)
|
||||||
|
node_id: String,
|
||||||
|
/// How long, in seconds (at most a day)
|
||||||
|
#[arg(long, default_value_t = 1800)]
|
||||||
|
ttl: u64,
|
||||||
|
},
|
||||||
/// List trusted peers
|
/// List trusted peers
|
||||||
List,
|
List,
|
||||||
}
|
}
|
||||||
@@ -187,6 +196,9 @@ fn to_request(command: Command) -> Result<Request> {
|
|||||||
},
|
},
|
||||||
Command::Peer(PeerCommand::Trust { node_id }) => Request::PeerTrust { node_id },
|
Command::Peer(PeerCommand::Trust { node_id }) => Request::PeerTrust { node_id },
|
||||||
Command::Peer(PeerCommand::Untrust { node_id }) => Request::PeerUntrust { node_id },
|
Command::Peer(PeerCommand::Untrust { node_id }) => Request::PeerUntrust { node_id },
|
||||||
|
Command::Peer(PeerCommand::AllowPush { node_id, ttl }) => {
|
||||||
|
Request::PeerAllowPush { node_id, ttl_secs: ttl }
|
||||||
|
}
|
||||||
Command::Peer(PeerCommand::List) => Request::PeerList {},
|
Command::Peer(PeerCommand::List) => Request::PeerList {},
|
||||||
Command::Push { hash, node_id } => Request::Push { hash, node_id },
|
Command::Push { hash, node_id } => Request::Push { hash, node_id },
|
||||||
Command::Gc => Request::Gc {},
|
Command::Gc => Request::Gc {},
|
||||||
@@ -246,6 +258,7 @@ fn print_human(data: Option<&ResponseData>) {
|
|||||||
match data {
|
match data {
|
||||||
ResponseData::Added { hash, bytes } => println!("added {hash} ({bytes} bytes)"),
|
ResponseData::Added { hash, bytes } => println!("added {hash} ({bytes} bytes)"),
|
||||||
ResponseData::Pinned { hash } => println!("pinned {hash}"),
|
ResponseData::Pinned { hash } => println!("pinned {hash}"),
|
||||||
|
ResponseData::Bytes { data } => println!("{data}"),
|
||||||
ResponseData::Done {} => println!("ok"),
|
ResponseData::Done {} => println!("ok"),
|
||||||
ResponseData::Materialized { bytes, reflinked } => {
|
ResponseData::Materialized { bytes, reflinked } => {
|
||||||
let how = if *reflinked { "reflinked" } else { "copied" };
|
let how = if *reflinked { "reflinked" } else { "copied" };
|
||||||
@@ -259,6 +272,15 @@ fn print_human(data: Option<&ResponseData>) {
|
|||||||
println!("store: {}", s.store_path);
|
println!("store: {}", s.store_path);
|
||||||
println!("pins: {}", s.pins);
|
println!("pins: {}", s.pins);
|
||||||
println!("peers: {} connected", s.connected_peers);
|
println!("peers: {} connected", s.connected_peers);
|
||||||
|
for r in &s.relays {
|
||||||
|
let how = match (&r.auth_denied, &r.last_error, r.connected) {
|
||||||
|
(Some(reason), _, _) => format!("denied: {reason}"),
|
||||||
|
(None, Some(err), false) => format!("down: {err}"),
|
||||||
|
(None, None, false) => "connecting".to_string(),
|
||||||
|
(None, _, true) => "connected".to_string(),
|
||||||
|
};
|
||||||
|
println!("relay: {} {how}", r.url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ResponseData::HashStatus(h) => {
|
ResponseData::HashStatus(h) => {
|
||||||
println!("hash: {}", h.hash);
|
println!("hash: {}", h.hash);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ fn ctl_status_round_trips() {
|
|||||||
max_download_bytes_per_sec: 0,
|
max_download_bytes_per_sec: 0,
|
||||||
discovery: false,
|
discovery: false,
|
||||||
wan_upload: false,
|
wan_upload: false,
|
||||||
|
relay_url: None,
|
||||||
gc_interval_secs: 300,
|
gc_interval_secs: 300,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,13 @@ required-features = ["socket-api"]
|
|||||||
varde-proto = { workspace = true }
|
varde-proto = { workspace = true }
|
||||||
iroh = { workspace = true }
|
iroh = { workspace = true }
|
||||||
iroh-blobs = { workspace = true }
|
iroh-blobs = { workspace = true }
|
||||||
|
# Request::Put / Read carry content inline, base64.
|
||||||
|
base64 = "0.22"
|
||||||
# mDNS/local-network address lookup left iroh core in 1.0.
|
# mDNS/local-network address lookup left iroh core in 1.0.
|
||||||
iroh-mdns-address-lookup = "0.4"
|
iroh-mdns-address-lookup = "0.6"
|
||||||
# Interop with iroh-blobs streams and channels; both are already in the
|
# Interop with iroh-blobs streams and channels; both are already in the
|
||||||
# dependency tree via iroh-blobs.
|
# dependency tree via iroh-blobs.
|
||||||
n0-future = "0.1"
|
n0-future = "0.3"
|
||||||
irpc = "0.17"
|
irpc = "0.17"
|
||||||
# Feature-gated D-Bus client for NetworkManager metered status.
|
# Feature-gated D-Bus client for NetworkManager metered status.
|
||||||
zbus = { version = "5", optional = true, default-features = false, features = ["tokio"] }
|
zbus = { version = "5", optional = true, default-features = false, features = ["tokio"] }
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ pub struct Config {
|
|||||||
/// Whether any WAN (non-link-local) upload is permitted. Default off:
|
/// Whether any WAN (non-link-local) upload is permitted. Default off:
|
||||||
/// LAN-only posture with zero WAN upload.
|
/// LAN-only posture with zero WAN upload.
|
||||||
pub wan_upload: bool,
|
pub wan_upload: bool,
|
||||||
|
/// A self-hosted iroh relay URL for NAT traversal. When set, the
|
||||||
|
/// endpoint uses this relay (`RelayMode::Custom`) instead of n0's
|
||||||
|
/// or none — the sovereign hole-punch coordinator an embedder runs
|
||||||
|
/// on its own infrastructure. Takes precedence over `wan_upload`'s
|
||||||
|
/// n0 defaults. `None` keeps the LAN-only / n0 behaviour.
|
||||||
|
pub relay_url: Option<String>,
|
||||||
/// Interval of the store's built-in garbage collector in seconds.
|
/// Interval of the store's built-in garbage collector in seconds.
|
||||||
/// Since iroh-blobs 0.103 there is no on-demand gc; unpinned blobs
|
/// Since iroh-blobs 0.103 there is no on-demand gc; unpinned blobs
|
||||||
/// are swept by this loop.
|
/// are swept by this loop.
|
||||||
@@ -41,6 +47,7 @@ struct FileConfig {
|
|||||||
max_download_bytes_per_sec: Option<u64>,
|
max_download_bytes_per_sec: Option<u64>,
|
||||||
discovery: Option<bool>,
|
discovery: Option<bool>,
|
||||||
wan_upload: Option<bool>,
|
wan_upload: Option<bool>,
|
||||||
|
relay_url: Option<String>,
|
||||||
gc_interval_secs: Option<u64>,
|
gc_interval_secs: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +183,10 @@ impl Config {
|
|||||||
wan_upload: env_bool("VARDE_WAN_UPLOAD")?
|
wan_upload: env_bool("VARDE_WAN_UPLOAD")?
|
||||||
.or(file.wan_upload)
|
.or(file.wan_upload)
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
|
relay_url: std::env::var("VARDE_RELAY_URL")
|
||||||
|
.ok()
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.or(file.relay_url),
|
||||||
gc_interval_secs: env_u64("VARDE_GC_INTERVAL")?
|
gc_interval_secs: env_u64("VARDE_GC_INTERVAL")?
|
||||||
.or(file.gc_interval_secs)
|
.or(file.gc_interval_secs)
|
||||||
.unwrap_or(300),
|
.unwrap_or(300),
|
||||||
|
|||||||
@@ -335,6 +335,26 @@ impl Daemon {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The peer a request names: a NodeId, or a blob ticket from it (whose
|
||||||
|
/// addresses are remembered, so dialing it needs no discovery). An app
|
||||||
|
/// that knows peers by the tickets they hand out - redoal does - can
|
||||||
|
/// allow and push without unpacking them.
|
||||||
|
fn peer_of(&self, peer: &str) -> Result<iroh::EndpointId, OpError> {
|
||||||
|
if let Ok(id) = peer.parse::<iroh::EndpointId>() {
|
||||||
|
return Ok(id);
|
||||||
|
}
|
||||||
|
match crate::transfer::parse_ticket(peer) {
|
||||||
|
Ok((_, _, addr)) => {
|
||||||
|
let id = addr.id;
|
||||||
|
self.transfer.remember(addr);
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
Err(_) => Err(OpError::InvalidArgument(format!(
|
||||||
|
"{peer:?} is neither a node id nor a ticket"
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Trusted peers seen on the LAN recently.
|
/// Trusted peers seen on the LAN recently.
|
||||||
fn present_trusted_peers(&self) -> Vec<PeerInfo> {
|
fn present_trusted_peers(&self) -> Vec<PeerInfo> {
|
||||||
let peers = self.lan_peers.lock().expect("lan peers lock");
|
let peers = self.lan_peers.lock().expect("lan peers lock");
|
||||||
@@ -371,6 +391,39 @@ impl Daemon {
|
|||||||
bytes,
|
bytes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Request::Put { data } => {
|
||||||
|
use base64::Engine as _;
|
||||||
|
let bytes = base64::engine::general_purpose::STANDARD
|
||||||
|
.decode(data.as_bytes())
|
||||||
|
.map_err(|e| OpError::InvalidArgument(format!("put: data is not base64: {e}")))?;
|
||||||
|
if bytes.len() as u64 > varde_proto::MAX_INLINE_BYTES {
|
||||||
|
return Err(OpError::InvalidArgument(format!(
|
||||||
|
"put: {} bytes, more than {} inline; add it by path",
|
||||||
|
bytes.len(),
|
||||||
|
varde_proto::MAX_INLINE_BYTES
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let (hash, bytes) = self.store.add_bytes(bytes).await?;
|
||||||
|
self.meta.record_format(&hash.to_hex(), StoredFormat::Raw)?;
|
||||||
|
Ok(ResponseData::Added {
|
||||||
|
hash: hash.to_hex().to_string(),
|
||||||
|
bytes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Request::Read { hash } => {
|
||||||
|
use base64::Engine as _;
|
||||||
|
let parsed = parse_hash(&hash)?;
|
||||||
|
if self.meta.format_of(&parsed.to_hex()) == StoredFormat::HashSeq {
|
||||||
|
return Err(OpError::InvalidArgument(format!(
|
||||||
|
"read: {} is a collection; materialize it",
|
||||||
|
parsed.to_hex()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
let bytes = self.store.read_bytes(parsed, varde_proto::MAX_INLINE_BYTES).await?;
|
||||||
|
Ok(ResponseData::Bytes {
|
||||||
|
data: base64::engine::general_purpose::STANDARD.encode(bytes),
|
||||||
|
})
|
||||||
|
}
|
||||||
Request::Pin { hash, policy } => {
|
Request::Pin { hash, policy } => {
|
||||||
let parsed = parse_hash(&hash)?;
|
let parsed = parse_hash(&hash)?;
|
||||||
self.meta.pin(&parsed.to_hex(), policy)?;
|
self.meta.pin(&parsed.to_hex(), policy)?;
|
||||||
@@ -433,6 +486,7 @@ impl Daemon {
|
|||||||
store_path: self.config.store_dir.display().to_string(),
|
store_path: self.config.store_dir.display().to_string(),
|
||||||
pins: self.meta.pins().len() as u64,
|
pins: self.meta.pins().len() as u64,
|
||||||
connected_peers: connected,
|
connected_peers: connected,
|
||||||
|
relays: self.transfer.relay_status(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Request::Status { hash: Some(hash) } => {
|
Request::Status { hash: Some(hash) } => {
|
||||||
@@ -533,24 +587,33 @@ impl Daemon {
|
|||||||
let parsed: iroh::EndpointId = node_id
|
let parsed: iroh::EndpointId = node_id
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|e| OpError::InvalidArgument(format!("invalid node id: {e}")))?;
|
.map_err(|e| OpError::InvalidArgument(format!("invalid node id: {e}")))?;
|
||||||
if !self.meta.untrust_peer(&parsed.to_string())? {
|
let was_trusted = self.meta.untrust_peer(&parsed.to_string())?;
|
||||||
|
let was_allowed = self.meta.disallow_push(&parsed.to_string())?;
|
||||||
|
if !was_trusted && !was_allowed {
|
||||||
return Err(OpError::NotFound(format!("{parsed} was not trusted")));
|
return Err(OpError::NotFound(format!("{parsed} was not trusted")));
|
||||||
}
|
}
|
||||||
Ok(ResponseData::Done {})
|
Ok(ResponseData::Done {})
|
||||||
}
|
}
|
||||||
|
Request::PeerAllowPush { node_id, ttl_secs } => {
|
||||||
|
let parsed = self.peer_of(&node_id)?;
|
||||||
|
let ttl = ttl_secs.min(varde_proto::MAX_PUSH_TTL_SECS);
|
||||||
|
self.meta
|
||||||
|
.allow_push(&parsed.to_string(), crate::meta::unix_now() + ttl)?;
|
||||||
|
debug!(peer = %parsed, ttl, "pushes allowed");
|
||||||
|
Ok(ResponseData::Done {})
|
||||||
|
}
|
||||||
Request::PeerList {} => Ok(ResponseData::Peers {
|
Request::PeerList {} => Ok(ResponseData::Peers {
|
||||||
peers: self.present_trusted_peers(),
|
peers: self.present_trusted_peers(),
|
||||||
}),
|
}),
|
||||||
Request::Push { hash, node_id } => {
|
Request::Push { hash, node_id } => {
|
||||||
let parsed = parse_hash(&hash)?;
|
let parsed = parse_hash(&hash)?;
|
||||||
let peer: iroh::EndpointId = node_id
|
let peer = self.peer_of(&node_id)?;
|
||||||
.parse()
|
// Consent, sending side: we only push to peers we trust or
|
||||||
.map_err(|e| OpError::InvalidArgument(format!("invalid node id: {e}")))?;
|
// hold a push allowance for. (The receiver independently
|
||||||
// Consent, sending side: we only push to peers we trust.
|
// requires the same of us.)
|
||||||
// (The receiver independently requires that it trusts us.)
|
if !self.meta.may_push(&peer.to_string()) {
|
||||||
if !self.meta.is_trusted(&peer.to_string()) {
|
|
||||||
return Err(OpError::InvalidArgument(format!(
|
return Err(OpError::InvalidArgument(format!(
|
||||||
"{peer} is not a trusted peer; trust it before pushing"
|
"{peer} is neither trusted nor allowed to exchange pushes; trust it or allow pushes first"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let (_, _, complete) = self.store.presence(parsed).await?;
|
let (_, _, complete) = self.store.presence(parsed).await?;
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ struct MetaState {
|
|||||||
/// Trusted peer NodeIds (z-base-32).
|
/// Trusted peer NodeIds (z-base-32).
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
trusted_peers: BTreeSet<String>,
|
trusted_peers: BTreeSet<String>,
|
||||||
|
/// Peers allowed to push to us and be pushed to, until a unix time
|
||||||
|
/// (`PeerAllowPush`): consent for that one thing, lapsing on its own.
|
||||||
|
#[serde(default)]
|
||||||
|
push_peers: BTreeMap<String, u64>,
|
||||||
/// Hashes (hex) the user shared via ticket export: standing consent
|
/// Hashes (hex) the user shared via ticket export: standing consent
|
||||||
/// to serve them to anyone, like an `open_lan` pin.
|
/// to serve them to anyone, like an `open_lan` pin.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -164,6 +168,31 @@ impl Meta {
|
|||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allow pushes with `node_id` until `until` (unix seconds). Extends,
|
||||||
|
/// never shortens, an allowance already held; expired ones are
|
||||||
|
/// dropped on the way.
|
||||||
|
pub fn allow_push(&self, node_id: &str, until: u64) -> Result<()> {
|
||||||
|
let now = unix_now();
|
||||||
|
self.mutate(|s| {
|
||||||
|
s.push_peers.retain(|_, u| *u > now);
|
||||||
|
let entry = s.push_peers.entry(node_id.to_string()).or_insert(0);
|
||||||
|
*entry = (*entry).max(until);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether pushes with `node_id` are allowed now: a trusted peer, or
|
||||||
|
/// one holding an unexpired push allowance.
|
||||||
|
pub fn may_push(&self, node_id: &str) -> bool {
|
||||||
|
let state = self.state.lock().expect("meta lock poisoned");
|
||||||
|
state.trusted_peers.contains(node_id)
|
||||||
|
|| state.push_peers.get(node_id).is_some_and(|u| *u > unix_now())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// End a push allowance. Returns whether there was one.
|
||||||
|
pub fn disallow_push(&self, node_id: &str) -> Result<bool> {
|
||||||
|
self.mutate(|s| s.push_peers.remove(node_id).is_some())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_trusted(&self, node_id: &str) -> bool {
|
pub fn is_trusted(&self, node_id: &str) -> bool {
|
||||||
self.state
|
self.state
|
||||||
.lock()
|
.lock()
|
||||||
@@ -173,6 +202,14 @@ impl Meta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Seconds since the unix epoch.
|
||||||
|
pub fn unix_now() -> u64 {
|
||||||
|
std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.map(|d| d.as_secs())
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -201,4 +238,27 @@ mod tests {
|
|||||||
assert!(meta.unpin("h").unwrap());
|
assert!(meta.unpin("h").unwrap());
|
||||||
assert!(!meta.is_pinned("h"));
|
assert!(!meta.is_pinned("h"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_push_allowance_lapses_and_never_shortens() {
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let meta = Meta::load(dir.path()).unwrap();
|
||||||
|
let now = unix_now();
|
||||||
|
assert!(!meta.may_push("p"));
|
||||||
|
meta.allow_push("p", now + 600).unwrap();
|
||||||
|
assert!(meta.may_push("p"));
|
||||||
|
assert!(!meta.is_trusted("p"), "a push allowance is not trust");
|
||||||
|
meta.allow_push("p", now + 10).unwrap();
|
||||||
|
assert!(meta.may_push("p"), "a shorter ask does not cut it short");
|
||||||
|
meta.allow_push("q", now.saturating_sub(1)).unwrap();
|
||||||
|
assert!(!meta.may_push("q"), "expired");
|
||||||
|
// Survives a reload.
|
||||||
|
let again = Meta::load(dir.path()).unwrap();
|
||||||
|
assert!(again.may_push("p"));
|
||||||
|
assert!(again.disallow_push("p").unwrap());
|
||||||
|
assert!(!again.may_push("p"));
|
||||||
|
// Full trust allows pushes too.
|
||||||
|
again.trust_peer("t").unwrap();
|
||||||
|
assert!(again.may_push("t"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ pub struct Gate {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct ConnInfo {
|
struct ConnInfo {
|
||||||
trusted: bool,
|
trusted: bool,
|
||||||
|
/// Trusted, or holding a push allowance (`PeerAllowPush`).
|
||||||
|
may_push: bool,
|
||||||
endpoint_id: Option<String>,
|
endpoint_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +144,11 @@ pub fn provider_events(gate: Gate) -> EventSender {
|
|||||||
.endpoint_id
|
.endpoint_id
|
||||||
.map(|id| gate.meta.is_trusted(&id.to_string()))
|
.map(|id| gate.meta.is_trusted(&id.to_string()))
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
|
let may_push = m
|
||||||
|
.inner
|
||||||
|
.endpoint_id
|
||||||
|
.map(|id| gate.meta.may_push(&id.to_string()))
|
||||||
|
.unwrap_or(false);
|
||||||
let ClientConnected {
|
let ClientConnected {
|
||||||
connection_id,
|
connection_id,
|
||||||
endpoint_id,
|
endpoint_id,
|
||||||
@@ -151,6 +158,7 @@ pub fn provider_events(gate: Gate) -> EventSender {
|
|||||||
connection_id,
|
connection_id,
|
||||||
ConnInfo {
|
ConnInfo {
|
||||||
trusted,
|
trusted,
|
||||||
|
may_push,
|
||||||
endpoint_id: endpoint_id.map(|id| id.to_string()),
|
endpoint_id: endpoint_id.map(|id| id.to_string()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -192,11 +200,12 @@ pub fn provider_events(gate: Gate) -> EventSender {
|
|||||||
ProviderMessage::ObserveRequestReceived(m) => {
|
ProviderMessage::ObserveRequestReceived(m) => {
|
||||||
// Presence is information too: gate it like data.
|
// Presence is information too: gate it like data.
|
||||||
// Bitfields are metadata, not payload, so trusted
|
// Bitfields are metadata, not payload, so trusted
|
||||||
// peers may observe even while serving is off or the
|
// peers - and peers allowed to push, whose push is
|
||||||
// connection is metered (push confirmation needs it).
|
// confirmed by observing it - may observe even while
|
||||||
|
// serving is off or the connection is metered.
|
||||||
let trusted = conns
|
let trusted = conns
|
||||||
.get(&m.inner.connection_id)
|
.get(&m.inner.connection_id)
|
||||||
.map(|i| i.trusted)
|
.map(|i| i.trusted || i.may_push)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
let allowed = trusted
|
let allowed = trusted
|
||||||
|| allow(&gate, &conns, m.inner.connection_id, [m.inner.request.hash]);
|
|| allow(&gate, &conns, m.inner.connection_id, [m.inner.request.hash]);
|
||||||
@@ -208,12 +217,13 @@ pub fn provider_events(gate: Gate) -> EventSender {
|
|||||||
m.tx.send(verdict).await.ok();
|
m.tx.send(verdict).await.ok();
|
||||||
}
|
}
|
||||||
ProviderMessage::PushRequestReceived(m) => {
|
ProviderMessage::PushRequestReceived(m) => {
|
||||||
// Inbound writes: trusted peers only, deferred while
|
// Inbound writes: trusted peers and push allowances
|
||||||
// metered (RateLimited invites a retry later).
|
// only, deferred while metered (RateLimited invites a
|
||||||
|
// retry later).
|
||||||
let info = conns.get(&m.inner.connection_id);
|
let info = conns.get(&m.inner.connection_id);
|
||||||
let trusted = info.map(|i| i.trusted).unwrap_or(false);
|
let may_push = info.map(|i| i.may_push).unwrap_or(false);
|
||||||
debug!(hash = %m.inner.request.hash.to_hex(), trusted, "push request received");
|
debug!(hash = %m.inner.request.hash.to_hex(), may_push, "push request received");
|
||||||
let verdict = if !trusted {
|
let verdict = if !may_push {
|
||||||
Err(AbortReason::Permission)
|
Err(AbortReason::Permission)
|
||||||
} else if gate.metered.is_metered() {
|
} else if gate.metered.is_metered() {
|
||||||
Err(AbortReason::RateLimited)
|
Err(AbortReason::RateLimited)
|
||||||
|
|||||||
@@ -228,6 +228,30 @@ impl BlobStore {
|
|||||||
|
|
||||||
/// Export `hash` to `dest`. Returns bytes written and whether at least
|
/// Export `hash` to `dest`. Returns bytes written and whether at least
|
||||||
/// one file was reflinked.
|
/// one file was reflinked.
|
||||||
|
/// Import `data` as one raw blob (`Request::Put`).
|
||||||
|
pub async fn add_bytes(&self, data: Vec<u8>) -> Result<(Hash, u64), OpError> {
|
||||||
|
let size = data.len() as u64;
|
||||||
|
let tag = self.store.add_bytes(data).temp_tag().await.map_err(internal)?;
|
||||||
|
info!(hash = %tag.hash().to_hex(), size, "imported bytes");
|
||||||
|
Ok((tag.hash(), size))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The whole content of a complete raw blob (`Request::Read`), when it
|
||||||
|
/// is no larger than `limit`.
|
||||||
|
pub async fn read_bytes(&self, hash: Hash, limit: u64) -> Result<Vec<u8>, OpError> {
|
||||||
|
match self.store.blobs().status(hash).await.map_err(internal)? {
|
||||||
|
BlobStatus::Complete { size } if size > limit => Err(OpError::InvalidArgument(format!(
|
||||||
|
"{} is {size} bytes, more than {limit} can be read inline; materialize it",
|
||||||
|
hash.to_hex()
|
||||||
|
))),
|
||||||
|
BlobStatus::Complete { .. } => {
|
||||||
|
let bytes = self.store.blobs().get_bytes(hash).await.map_err(internal)?;
|
||||||
|
Ok(bytes.to_vec())
|
||||||
|
}
|
||||||
|
_ => Err(OpError::NotFound(format!("{} is not complete in the store", hash.to_hex()))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn materialize(
|
pub async fn materialize(
|
||||||
&self,
|
&self,
|
||||||
hash: Hash,
|
hash: Hash,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use std::time::Duration;
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use iroh::address_lookup::memory::MemoryLookup;
|
use iroh::address_lookup::memory::MemoryLookup;
|
||||||
use iroh::protocol::Router;
|
use iroh::protocol::Router;
|
||||||
use iroh::{Endpoint, EndpointAddr, EndpointId, RelayMode, SecretKey};
|
use iroh::{Endpoint, EndpointAddr, EndpointId, RelayMode, SecretKey, Watcher as _};
|
||||||
use iroh_blobs::api::downloader::{DownloadOptions, Downloader, Shuffled, SplitStrategy};
|
use iroh_blobs::api::downloader::{DownloadOptions, Downloader, Shuffled, SplitStrategy};
|
||||||
use iroh_blobs::protocol::GetRequest;
|
use iroh_blobs::protocol::GetRequest;
|
||||||
use iroh_blobs::{BlobFormat, BlobsProtocol, Hash, HashAndFormat};
|
use iroh_blobs::{BlobFormat, BlobsProtocol, Hash, HashAndFormat};
|
||||||
@@ -62,10 +62,19 @@ impl Transfer {
|
|||||||
metered: MeteredState,
|
metered: MeteredState,
|
||||||
) -> Result<Transfer> {
|
) -> Result<Transfer> {
|
||||||
let secret = load_or_create_secret(&config.store_dir.join("secret.key"))?;
|
let secret = load_or_create_secret(&config.store_dir.join("secret.key"))?;
|
||||||
// With wan_upload the n0 defaults apply (their relays and DNS
|
// A self-hosted relay (relay_url) is the sovereign hole-punch
|
||||||
// lookup, matching the pre-1.0 default relay mode); otherwise the
|
// path and takes precedence: the endpoint coordinates through
|
||||||
// endpoint gets no external services at all.
|
// the operator's own iroh relay, never n0's. Failing that,
|
||||||
let builder = if config.wan_upload {
|
// wan_upload opts into n0's relays + DNS; otherwise the endpoint
|
||||||
|
// gets no external services at all (LAN-only).
|
||||||
|
let builder = if let Some(url) = &config.relay_url {
|
||||||
|
let relay_url: iroh::RelayUrl = url
|
||||||
|
.parse()
|
||||||
|
.with_context(|| format!("parsing relay_url {url:?}"))?;
|
||||||
|
let relay_map = iroh::RelayMap::from(relay_url);
|
||||||
|
Endpoint::builder(iroh::endpoint::presets::Minimal)
|
||||||
|
.relay_mode(RelayMode::Custom(relay_map))
|
||||||
|
} else if config.wan_upload {
|
||||||
Endpoint::builder(iroh::endpoint::presets::N0)
|
Endpoint::builder(iroh::endpoint::presets::N0)
|
||||||
} else {
|
} else {
|
||||||
Endpoint::builder(iroh::endpoint::presets::Minimal).relay_mode(RelayMode::Disabled)
|
Endpoint::builder(iroh::endpoint::presets::Minimal).relay_mode(RelayMode::Disabled)
|
||||||
@@ -147,6 +156,22 @@ impl Transfer {
|
|||||||
self.endpoint.id().to_string()
|
self.endpoint.id().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How each home relay is doing right now: connected, or why not.
|
||||||
|
/// Empty with relays disabled.
|
||||||
|
pub fn relay_status(&self) -> Vec<varde_proto::RelayInfo> {
|
||||||
|
self.endpoint
|
||||||
|
.home_relay_status()
|
||||||
|
.get()
|
||||||
|
.iter()
|
||||||
|
.map(|r| varde_proto::RelayInfo {
|
||||||
|
url: r.url().to_string(),
|
||||||
|
connected: r.is_connected(),
|
||||||
|
last_error: r.last_error().map(|e| format!("{e:#}")),
|
||||||
|
auth_denied: r.auth_denied_reason().map(str::to_string),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// The endpoint's identity key (also signs our announcements).
|
/// The endpoint's identity key (also signs our announcements).
|
||||||
pub fn secret_key(&self) -> SecretKey {
|
pub fn secret_key(&self) -> SecretKey {
|
||||||
self.endpoint.secret_key().clone()
|
self.endpoint.secret_key().clone()
|
||||||
@@ -289,6 +314,15 @@ impl Transfer {
|
|||||||
Ok(ticket.to_string())
|
Ok(ticket.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Teach the endpoint where a peer can be reached (the addresses a
|
||||||
|
/// ticket carries), so a push dials it directly instead of waiting on
|
||||||
|
/// discovery.
|
||||||
|
pub fn remember(&self, addr: EndpointAddr) {
|
||||||
|
if !addr.addrs.is_empty() {
|
||||||
|
self.known_addrs.add_endpoint_info(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Queue a background fetch of `content` from `providers`. Emits
|
/// Queue a background fetch of `content` from `providers`. Emits
|
||||||
/// progress events and [`Event::PinComplete`] when fully verified.
|
/// progress events and [`Event::PinComplete`] when fully verified.
|
||||||
pub fn spawn_fetch(&self, content: HashAndFormat, providers: Vec<EndpointAddr>) {
|
pub fn spawn_fetch(&self, content: HashAndFormat, providers: Vec<EndpointAddr>) {
|
||||||
|
|||||||
@@ -422,3 +422,61 @@ fn push_rejected_without_receiver_trust() {
|
|||||||
// And the receiver holds none of it.
|
// And the receiver holds none of it.
|
||||||
assert!(!is_complete(&b.socket, &hash));
|
assert!(!is_complete(&b.socket, &hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A push allowance is enough on both sides: two daemons that only
|
||||||
|
/// allowed pushes with each other (strangers sharing a place, in redoal)
|
||||||
|
/// exchange content without trusting each other - and the allowance
|
||||||
|
/// grants nothing else, so neither lists the other as a trusted peer.
|
||||||
|
#[test]
|
||||||
|
fn push_allowance_is_enough_and_is_not_trust() {
|
||||||
|
let _serial = MDNS_SERIAL.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
|
let dir_a = tempfile::tempdir().unwrap();
|
||||||
|
let dir_b = tempfile::tempdir().unwrap();
|
||||||
|
let a = support::spawn_daemon_with_env(dir_a.path(), &[("VARDE_DISCOVERY", "true")]);
|
||||||
|
let b = support::spawn_daemon_with_env(dir_b.path(), &[("VARDE_DISCOVERY", "true")]);
|
||||||
|
let mut client_a = support::Client::connect(&a.socket);
|
||||||
|
let mut client_b = support::Client::connect(&b.socket);
|
||||||
|
let id_a = node_id(&mut client_a);
|
||||||
|
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let src = dir.path().join("voice.bin");
|
||||||
|
let payload = vec![7u8; 120_000];
|
||||||
|
std::fs::write(&src, &payload).unwrap();
|
||||||
|
let hash = add_file(&mut client_a, &src);
|
||||||
|
pin(&mut client_a, &hash, false);
|
||||||
|
|
||||||
|
// A knows B by a ticket B handed out (as redoal peers do), not by
|
||||||
|
// its bare node id.
|
||||||
|
let b_src = dir.path().join("b-own.bin");
|
||||||
|
std::fs::write(&b_src, vec![1u8; 1_000]).unwrap();
|
||||||
|
let b_hash = add_file(&mut client_b, &b_src);
|
||||||
|
let b_ticket = match client_b.request(&Request::TicketExport { hash: b_hash }).data {
|
||||||
|
Some(ResponseData::Ticket { ticket }) => ticket,
|
||||||
|
other => panic!("unexpected ticket reply: {other:?}"),
|
||||||
|
};
|
||||||
|
assert!(client_a.request(&Request::PeerAllowPush { node_id: b_ticket.clone(), ttl_secs: 600 }).ok);
|
||||||
|
assert!(client_b.request(&Request::PeerAllowPush { node_id: id_a, ttl_secs: 600 }).ok);
|
||||||
|
match client_a.request(&Request::PeerList {}).data {
|
||||||
|
Some(ResponseData::Peers { peers }) => assert!(peers.is_empty(), "an allowance is not trust: {peers:?}"),
|
||||||
|
other => panic!("unexpected peer list: {other:?}"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// The peer's address arrives by mdns; retry until it does.
|
||||||
|
let deadline = Instant::now() + Duration::from_secs(30);
|
||||||
|
let reply = loop {
|
||||||
|
let reply = client_a.request(&Request::Push { hash: hash.clone(), node_id: b_ticket.clone() });
|
||||||
|
if reply.ok || Instant::now() > deadline {
|
||||||
|
break reply;
|
||||||
|
}
|
||||||
|
std::thread::sleep(Duration::from_millis(500));
|
||||||
|
};
|
||||||
|
if !reply.ok {
|
||||||
|
let message = reply.error.map(|e| e.message).unwrap_or_default();
|
||||||
|
// Only an unreachable peer is the environment's fault; any other
|
||||||
|
// refusal is a real failure.
|
||||||
|
assert!(message.contains("connect"), "push failed: {message}");
|
||||||
|
eprintln!("SKIP: push never reached the peer (multicast unavailable?): {message}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert!(wait_complete(&b.socket, &hash, Duration::from_secs(60)), "pushed content not complete on receiver");
|
||||||
|
}
|
||||||
|
|||||||
@@ -276,3 +276,45 @@ fn reflink_when_supported() {
|
|||||||
drop(daemon);
|
drop(daemon);
|
||||||
let _ = std::fs::remove_dir_all(&base);
|
let _ = std::fs::remove_dir_all(&base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Put and Read carry the bytes on the socket: a client that shares no
|
||||||
|
/// filesystem with the daemon (a desktop app and the system daemon, which
|
||||||
|
/// runs as its own user behind ProtectHome) stores and reads back without
|
||||||
|
/// a path either side must reach. A Put blob reads back by Materialize too.
|
||||||
|
#[test]
|
||||||
|
fn bytes_round_trip_inline() {
|
||||||
|
use base64::Engine as _;
|
||||||
|
let b64 = base64::engine::general_purpose::STANDARD;
|
||||||
|
let daemon = support::spawn_daemon();
|
||||||
|
let mut client = support::Client::connect(&daemon.socket);
|
||||||
|
let payload: Vec<u8> = (0..50_000u32).flat_map(|i| i.to_le_bytes()).collect();
|
||||||
|
|
||||||
|
let reply = client.request(&Request::Put { data: b64.encode(&payload) });
|
||||||
|
assert!(reply.ok, "put failed: {:?}", reply.error);
|
||||||
|
let hash = match reply.data {
|
||||||
|
Some(ResponseData::Added { hash, bytes }) => {
|
||||||
|
assert_eq!(bytes, payload.len() as u64);
|
||||||
|
hash
|
||||||
|
}
|
||||||
|
other => panic!("unexpected put reply: {other:?}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let reply = client.request(&Request::Read { hash: hash.clone() });
|
||||||
|
assert!(reply.ok, "read failed: {:?}", reply.error);
|
||||||
|
match reply.data {
|
||||||
|
Some(ResponseData::Bytes { data }) => assert_eq!(b64.decode(data).unwrap(), payload),
|
||||||
|
other => panic!("unexpected read reply: {other:?}"),
|
||||||
|
}
|
||||||
|
|
||||||
|
let dir = tempfile::tempdir().unwrap();
|
||||||
|
let dest = dir.path().join("out.bin");
|
||||||
|
materialize(&mut client, &hash, &dest, MaterializeMode::Copy).unwrap();
|
||||||
|
assert_eq!(std::fs::read(&dest).unwrap(), payload);
|
||||||
|
|
||||||
|
// Not base64: refused, not stored.
|
||||||
|
let reply = client.request(&Request::Put { data: "not base64!".into() });
|
||||||
|
assert_eq!(reply.error.expect("error body").code, ErrorCode::InvalidArgument);
|
||||||
|
// Unknown hash: not found.
|
||||||
|
let reply = client.request(&Request::Read { hash: "0".repeat(64) });
|
||||||
|
assert!(!reply.ok);
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,13 @@ use serde::{Deserialize, Serialize};
|
|||||||
/// Bumped on incompatible changes; reported in [`GlobalStatus`].
|
/// Bumped on incompatible changes; reported in [`GlobalStatus`].
|
||||||
pub const PROTOCOL_VERSION: u32 = 2;
|
pub const PROTOCOL_VERSION: u32 = 2;
|
||||||
|
|
||||||
|
/// The longest a [`Request::PeerAllowPush`] allowance may last: a day.
|
||||||
|
pub const MAX_PUSH_TTL_SECS: u64 = 24 * 60 * 60;
|
||||||
|
|
||||||
|
/// The most bytes a [`Request::Put`] or a [`Request::Read`] reply carries
|
||||||
|
/// inline. Larger content goes through `Add`/`Materialize` and a path.
|
||||||
|
pub const MAX_INLINE_BYTES: u64 = 16 * 1024 * 1024;
|
||||||
|
|
||||||
/// A request from a client to the daemon. One JSON object per line.
|
/// A request from a client to the daemon. One JSON object per line.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(tag = "type", rename_all = "snake_case")]
|
#[serde(tag = "type", rename_all = "snake_case")]
|
||||||
@@ -61,6 +68,24 @@ pub enum Request {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
mode: MaterializeMode,
|
mode: MaterializeMode,
|
||||||
},
|
},
|
||||||
|
/// Import bytes carried in the request, base64 (standard alphabet),
|
||||||
|
/// at most [`MAX_INLINE_BYTES`]. Replies [`ResponseData::Added`].
|
||||||
|
///
|
||||||
|
/// For a client that shares no filesystem with the daemon: the system
|
||||||
|
/// daemon runs as its own user with `ProtectHome`, so it can neither
|
||||||
|
/// read a file a desktop app wrote for `Add` nor write one back for
|
||||||
|
/// `Materialize`. Added in varde 0.1.4.
|
||||||
|
Put {
|
||||||
|
/// The content, base64.
|
||||||
|
data: String,
|
||||||
|
},
|
||||||
|
/// Read a complete raw blob back in the reply, base64, at most
|
||||||
|
/// [`MAX_INLINE_BYTES`]. Replies [`ResponseData::Bytes`]. The
|
||||||
|
/// counterpart of [`Request::Put`]; added in varde 0.1.4.
|
||||||
|
Read {
|
||||||
|
/// Hash (hex) of the blob.
|
||||||
|
hash: String,
|
||||||
|
},
|
||||||
/// Query daemon status, globally or for one hash.
|
/// Query daemon status, globally or for one hash.
|
||||||
Status {
|
Status {
|
||||||
/// If set, report on this hash; otherwise report global status.
|
/// If set, report on this hash; otherwise report global status.
|
||||||
@@ -94,6 +119,20 @@ pub enum Request {
|
|||||||
/// The peer's iroh NodeId (z-base-32).
|
/// The peer's iroh NodeId (z-base-32).
|
||||||
node_id: String,
|
node_id: String,
|
||||||
},
|
},
|
||||||
|
/// Allow pushes between this daemon and a peer for `ttl_secs` (at most
|
||||||
|
/// [`MAX_PUSH_TTL_SECS`]): we may push to it, and accept what it pushes
|
||||||
|
/// to us. Nothing else - unlike [`Request::PeerTrust`] it neither
|
||||||
|
/// syncs the peer's pins nor serves it our content - so an app can
|
||||||
|
/// grant it to strangers it shares something with for a while (two
|
||||||
|
/// phones at the same place) and let it lapse. Asking again extends
|
||||||
|
/// it; [`Request::PeerUntrust`] ends it early. Added in varde 0.1.5.
|
||||||
|
PeerAllowPush {
|
||||||
|
/// The peer's iroh NodeId (z-base-32), or a blob ticket it issued
|
||||||
|
/// (varde 0.1.6+), whose addresses are then used to reach it.
|
||||||
|
node_id: String,
|
||||||
|
/// How long the allowance lasts, in seconds.
|
||||||
|
ttl_secs: u64,
|
||||||
|
},
|
||||||
/// List trusted peers and their current connectivity.
|
/// List trusted peers and their current connectivity.
|
||||||
PeerList {},
|
PeerList {},
|
||||||
/// Push fully-present content to a trusted peer, unprompted.
|
/// Push fully-present content to a trusted peer, unprompted.
|
||||||
@@ -104,6 +143,9 @@ pub enum Request {
|
|||||||
/// policy), so the content survives gc and shows up in `List`.
|
/// policy), so the content survives gc and shows up in `List`.
|
||||||
Push {
|
Push {
|
||||||
/// Hash (hex) of the fully-present blob or HashSeq root to push.
|
/// Hash (hex) of the fully-present blob or HashSeq root to push.
|
||||||
|
///
|
||||||
|
/// The receiver below may be a NodeId or, from varde 0.1.6, a blob
|
||||||
|
/// ticket it issued.
|
||||||
hash: String,
|
hash: String,
|
||||||
/// The receiving peer's iroh NodeId (z-base-32).
|
/// The receiving peer's iroh NodeId (z-base-32).
|
||||||
node_id: String,
|
node_id: String,
|
||||||
@@ -228,6 +270,11 @@ pub enum ResponseData {
|
|||||||
/// Whether at least one file was reflinked rather than copied.
|
/// Whether at least one file was reflinked rather than copied.
|
||||||
reflinked: bool,
|
reflinked: bool,
|
||||||
},
|
},
|
||||||
|
/// A blob's content, base64. Reply to [`Request::Read`].
|
||||||
|
Bytes {
|
||||||
|
/// The content, base64 (standard alphabet).
|
||||||
|
data: String,
|
||||||
|
},
|
||||||
/// Global daemon status. Reply to [`Request::Status`] without a hash.
|
/// Global daemon status. Reply to [`Request::Status`] without a hash.
|
||||||
Status(GlobalStatus),
|
Status(GlobalStatus),
|
||||||
/// Per-hash status. Reply to [`Request::Status`] with a hash.
|
/// Per-hash status. Reply to [`Request::Status`] with a hash.
|
||||||
@@ -277,6 +324,27 @@ pub struct GlobalStatus {
|
|||||||
pub pins: u64,
|
pub pins: u64,
|
||||||
/// Number of connected trusted peers.
|
/// Number of connected trusted peers.
|
||||||
pub connected_peers: u64,
|
pub connected_peers: u64,
|
||||||
|
/// The home relays this endpoint uses and how each is doing. Empty
|
||||||
|
/// when relays are off (LAN-only) or on a daemon before 0.1.10.
|
||||||
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub relays: Vec<RelayInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// One home relay's connection state (iroh's `home_relay_status`).
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct RelayInfo {
|
||||||
|
/// The relay URL.
|
||||||
|
pub url: String,
|
||||||
|
/// Whether the endpoint holds a connection to it right now.
|
||||||
|
pub connected: bool,
|
||||||
|
/// The most recent connection error, when not connected and an
|
||||||
|
/// attempt has failed; for a person to read, not to match on.
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub last_error: Option<String>,
|
||||||
|
/// The relay's reason when it denied this endpoint's authentication:
|
||||||
|
/// the one failure retrying will not cure.
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
pub auth_denied: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Status of one hash.
|
/// Status of one hash.
|
||||||
@@ -431,4 +499,13 @@ mod tests {
|
|||||||
_ => panic!("wrong variant"),
|
_ => panic!("wrong variant"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn a_status_from_before_relays_still_parses() {
|
||||||
|
let old = r#"{"version":"0.1.9","protocol":2,"store_path":"/s","pins":1,"connected_peers":0}"#;
|
||||||
|
let status: GlobalStatus = serde_json::from_str(old).unwrap();
|
||||||
|
assert!(status.relays.is_empty());
|
||||||
|
let back = serde_json::to_string(&status).unwrap();
|
||||||
|
assert!(!back.contains("relays"), "empty stays absent for old clients: {back}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user