# node The `node` crate produces the `swactor` binary — the batteries-included entry point for running a swactor node. It composes the actor runtime, SWIM-based cluster membership, content-addressed datastore, data streams, an HTTP dashboard, and an optional embedded relay server into a single process. Run `swactor --help` for full CLI usage. ## What a Default Node Does ### Identity Every node has a persistent Ed25519 keypair stored at `~/.swactor/identity/node.key.json`. This is the node's identity across restarts — deleting it makes the node appear as a new peer to the cluster. The keypair's public key doubles as the node ID (used in SWIM, peer auth, and invite codes). A deterministic human-readable name (e.g. `swift-falcon`) is derived from the key so you can tell nodes apart in logs and the dashboard. ### Networking The default transport is **iroh** (QUIC over UDP). Nodes find each other via invite codes — base58-encoded public keys exchanged out-of-band. `swactor join ` adds a peer to the allow-list and sets it as the seed node for the next startup. Once connected, **SWIM protocol** handles cluster membership: protocol probes every 500ms, 600ms probe timeout (tuned for relay round-trips), 2 indirect probes, 4s suspicion window. All intervals are in ticks where **1 tick = 100ms** (the main loop period). **Peer auth** operates in two modes: open (no `peers_file`) or allow-list (`peers.json`). In allow-list mode, SWIM messages from unknown nodes are dropped at the transport layer. New peers can be added via `swactor join` or the dashboard UI, both of which hot-update the allow-list. ### Relay Nodes with a public IP auto-promote to embedded relay servers (port 3340). Candidacy is evaluated at startup: the node checks its outbound IP is non-RFC1918 and the relay port is bindable. Relay URLs are announced via SWIM gossip so other nodes discover them automatically. Nodes behind NAT use relays for indirect connectivity — this is why the probe timeout is 600ms instead of the typical 300ms. ### Storage The **datastore** is a content-addressed, chunked store. Default config persists to `~/.swactor/datastore/`. Auth is enabled by default (ACL files in `~/.swactor/auth/`). The datastore runs as a group of actors inside the runtime and is driven by the main tick loop — GC runs every 1000 ticks (~100s) and dissemination every 50 ticks (~5s). A `StreamManager` actor bridges iroh QUIC streams into the datastore for bulk data transfer between nodes. Disable with `--no-datastore`. Use `--storage-path` to change location, or omit it from config for in-memory only. ### Observability An HTTP dashboard serves on **port 9090**. It exposes runtime stats, cluster membership state, tracing output, and a peer management UI (add/remove peers). The dashboard receives a snapshot of the distribution layer every tick. ### State & Lifecycle All persistent state lives under `~/.swactor/`. Deleting this directory fully resets the node (new identity, empty cluster, empty datastore). The node shuts down cleanly on SIGINT (Ctrl+C). `swactor install` copies the binary to `~/.swactor/bin/swactor` and registers it as a system service (systemd user unit, OpenRC/sysvinit init script, or `@reboot` crontab depending on the host). ## Exposed Ports | Port | Service | Configurable via | |------|---------|-----------------| | 9090 | HTTP dashboard | `--dashboard-port` | | 3340 | Embedded relay (if eligible) | `--relay-port` | ## Data Directory (`~/.swactor/`) ``` ~/.swactor/ ├── node.toml # Node configuration ├── peers.json # Peer allow-list ├── identity/ │ └── node.key.json # Persistent Ed25519 keypair ├── datastore/ # Content-addressed chunk storage ├── auth/ # ACL and owner key files └── bin/ └── swactor # Installed binary (after `swactor install`) ``` ## Architecture ``` CLI Args + TOML Config │ ▼ Config Resolution (CLI > config > defaults) │ ▼ Identity (Ed25519 Keypair) ──► Node Name │ ▼ ┌─────────────────────────────────────────────┐ │ Actor Runtime │ │ (2 threads, StdExtension, stats hook) │ │ │ │ ┌──────────────┐ ┌──────────────────────┐ │ │ │ StreamManager │ │ Datastore Group │ │ │ │ (actor) │◄─┤ (store, gateway, │ │ │ │ │ │ bridge actors) │ │ │ └──────────────┘ └──────────────────────┘ │ └──────────────┬──────────────────────────────┘ │ ▼ ┌──────────────────────────────────┐ │ Distribution Driver (iroh) │ │ SWIM probes, gossip, relay │ └──────────────┬───────────────────┘ │ ▼ ┌──────────────────────────────────┐ │ HTTP Dashboard │ │ :9090 — stats, tracing, peers │ └──────────────────────────────────┘ │ ▼ Main Tick Loop (100ms) recv → tick → streams → joins → heartbeats → snapshot → datastore ```