66 lines
3.4 KiB
Markdown
66 lines
3.4 KiB
Markdown
# Archive Clients
|
||
|
||
One Python daemon runs as either an `archive` or `cache` node for Archive
|
||
Control. Both roles use the same code and `sodium/archive-clients` image.
|
||
|
||
The current foundation provides strict TOML configuration, file-backed secrets,
|
||
API/local root mapping, fail-fast permission and sparse-file probes, a durable
|
||
SQLite command inbox, bounded one-writer WebSocket output, registration-first
|
||
authentication, heartbeat handling, duplicate-command acknowledgements, and
|
||
indefinite capped exponential reconnect with optional jitter. The state DB has
|
||
an exclusive process lease plus checksummed, integrity-verified online backups
|
||
with recent/daily/weekly retention.
|
||
Startup probes report qBittorrent/Web API/libtorrent versions, Syncthing
|
||
version/device identity, service health, and per-root hardlink/reflink/sparse
|
||
support without exposing local paths to control.
|
||
|
||
The first read-only discovery layer strictly decodes v1/v2/hybrid metainfo,
|
||
derives canonical resource identities and selection ranges, builds lazy content
|
||
trees, and reports only safe Syncthing folders below the configured root.
|
||
Renamed/noncanonical torrent paths remain visible but are marked noncanonical
|
||
so later job preflight can reject them without hiding the resource.
|
||
The qBittorrent read adapter uses cookie authentication, bounded responses,
|
||
one reauthentication attempt on session expiry, hash-scoped file/metainfo
|
||
fetches, and never logs credentials, cookies, response bodies, or endpoints.
|
||
Durable inventory commands now stream bounded atomic summary, lookup, and
|
||
content-tree chunks. Page tokens are guarded by timestamp-independent snapshot
|
||
revisions, stale trees fail explicitly, and slow scans run outside the socket
|
||
reader so heartbeat acknowledgements remain responsive.
|
||
Durable `EnsureRoute` commands use scoped Syncthing device/folder REST updates,
|
||
safe API/local path mapping, exact pairwise configuration read-back, and
|
||
bidirectional nonce/acknowledgement files. Route attempt nonces, ownership, and
|
||
ordered updates survive restart; accepted attempts resume on reconnect without
|
||
concurrent duplicate execution. Conflicting existing folders and foreign data
|
||
are reported without being overwritten.
|
||
|
||
```bash
|
||
archive-client --config /etc/archive-control/client.toml --check-config
|
||
archive-client --config /etc/archive-control/client.toml --mode archive
|
||
archive-client-backup --database /var/lib/archive-control/client.db \
|
||
--backup-dir /var/backups/archive-control list
|
||
```
|
||
|
||
`--mode` accepts only `archive` or `cache` and overrides the configured role.
|
||
Secrets must be regular files without group/world permissions. The daemon never
|
||
stores them in SQLite or sends the shared token after registration.
|
||
|
||
This foundation currently executes heartbeat, inventory, state-snapshot, and
|
||
route-provisioning commands. Other mutation commands are durably rejected as
|
||
unsupported until their service and file-operation executors are added; they
|
||
are never falsely acknowledged as accepted.
|
||
|
||
Run tests and build using containers:
|
||
|
||
```bash
|
||
docker build --target test -t archive-clients-test .
|
||
docker run --rm archive-clients-test
|
||
docker build -t sodium/archive-clients:dev .
|
||
```
|
||
|
||
The local cross-project route test is under `e2e/`. It brings up isolated
|
||
2×2 cache/archive node stacks plus the standalone control core and verifies all
|
||
four eager-mesh routes without Telegram. See `e2e/README.md`.
|
||
|
||
Generated bindings are pinned to archive-control-proto commit
|
||
`4ec852014dad74606d4078b3ae1aa208c814b033`.
|