Clone this repository
For self-hosted knots, clone URLs may differ based on your setup.
Our NAR reader goes: NARs are parsed by harmonia-file-nar's parse_nar
and written by its restore (async, bounded queue to one writer thread;
it also checks entry names, sorting and padding like Nix). Files come
out with the umask's permissions, so a pass afterwards sets the store's
0444/0555 like our reader did.
The NAR hash is computed with harmonia-utils-hash (aws-lc sha256) in a
tokio-util InspectReader instead of our HashingReader and sha2, and
narinfo NarHashes are parsed with harmonia (any encoding with the
sha256: prefix) instead of comparing base32/base16 strings. Data after
the NAR counts into the size, so the NarSize check still rejects it.
The .ls listings are harmonia-file-core FileTrees now instead of our
Tree enum converted from them. The test unpacks a NAR made by
harmonia's NarByteStream instead of a hand-written one.
The I/O runs on a tokio runtime now:
- HTTP via reqwest (rustls on aws-lc, HTTP/2, bundled webpki roots as
before) instead of ureq. Instead of our own caching ureq::Resolver the
cache hosts are resolved once at startup and pinned with
resolve_to_addrs, which keeps getaddrinfo() (and NSS modules from the
store) out of requests once /nix/store is mounted. The retry loop
stays: reqwest-middleware/retry would not save code, as body read
errors are retried too.
- Decompression via async-compression (zstd, xz, bzip2, gzip, brotli,
concatenated members like Nix) instead of zstd/xz2/bzip2/flate2/
brotli-decompressor; the magic sniffing for narinfo/.ls stays.
- The closure walk and the .ls listings run with buffer_unordered
instead of par_map threads.
- FUSE workers stay threads; open() fetches via Handle::block_on, and
concurrent opens of a path wait on a tokio Mutex.
- The compressed size is counted with tokio-util's InspectReader instead
of our CountingReader. The NAR is still unpacked by our reader for now,
through SyncIoBridge.
Replace our nix32 encoder with harmonia-utils-base-encoding's base32 and
the hand-walked serde_json::Value of the caches' .ls listings with
harmonia-file-core's FileTree, which is the serde model of Nix's file
system object JSON. Both are pure crates (data-encoding/derive_more,
serde/serde_json/thiserror), pulled as a git dependency pinned to
harmonia 3edb37ae: only harmonia-utils-hash and harmonia-store-core exist
on crates.io, as 0.0.0-alpha.0 placeholders. A listing node without
"size" (regular) or "entries" (directory) is now an error instead of
being read as 0 / empty; Nix always writes both.
Kept ours:
- NAR unpacking: harmonia-file-nar is a tokio AsyncRead parser/restorer;
we unpack synchronously from the blocking HTTP/decompressor stream
while hashing, in a sync FUSE daemon.
- narinfo parsing, store path names and NarHash parsing:
harmonia-store-nar-info, -store-path and -utils-hash all pull in
aws-lc-rs (aws-lc-sys C build), blake3 and md5, nar-info also
ed25519-dalek and getrandom: +43 crates for ~15 lines. closure also
passes the narinfo text through verbatim, and harmonia's parser
rejects whole narinfos for fields we don't use (Sig, CA, FileHash).
- The in-memory Tree: matching FileTree(FileSystemObject::Regular(
Regular { .. })) in lazy.rs is clumsier than our flat enum.
Incident 2026-10-17: radio→styx UDP was blackholed for ~40 min after a
sendto() hit ENETUNREACH; tincd never recovered the UDP path on its own.
The fix is upstream as Mic92/tincr#140.
The fork is rebased onto upstream Mic92/tincr main: 6 of the 8 commits on
lassulus/fixes are upstream now, leaving the tunnel-address gate and the
ENETUNREACH fix on lassulus/fixes-rebased (bfcbbc69).
pkgs/tincr pins the same branch and is what every machine runs (the flake
input only provides barnacle's darwin module), so bump it and its update
script along with the input.
RUST_LOG=tinc=warn hid every routing/relay event, so path problems were
only visible over SSH. Enable Info for tincd::graph (became
reachable/unreachable via X), tincd::conn (meta connections up/down) and
tincd::net (key exchange, UDP idle revalidation/timeouts, PMTU
fixed/increase/decrease). Their Debug/Trace stays off because tincd::net
and tincd::proto log per packet there; tincd (autoconnect), tincd::auth
and tincd::proto Info stay off as redundant.
Expected volume is roughly 100-250 lines/h on a hub like neoprism and
30-60/h on leaves, plus autoconnect dial attempts to dead hosts in conn.
iets (numtide/iets, a Nix evaluator in Rust) gives the same drvPath,
isCached and cacheStatus for every machine as nix-eval-jobs 2.35.4, in
24-35s instead of 108-144s (4 workers, coaxmetal). It is a flake input
so CI builds it once and pushes it to cache.lassul.us with niks3 and
the lazy store.