Build and test fsend (CLI and server are the same binary; the server
is the fsend server subcommand) from source.
- Go ≥ 1.26 (matches
go.mod). - Optional: Docker + docker compose v2, only for the reverse-proxy
stack in
deploy/compose/.
go build -o /tmp/fsend ./cmd/fsend/tmp/fsend --version
/tmp/fsend server --helpgo test ./... # unit + E2E (~30s)
go test -short ./... # skip E2E
go test -race ./...
go test -v ./test/e2e/The E2E suite builds its own binary in a temp dir and runs an isolated server on loopback — no shell wrapper needed.
scripts/coverage.shpython3 scripts/validate-ux.pyEmpirical audit of the terminal UI: builds the CLI, starts an isolated
pairing server on loopback (isolated HOME — your real config is never
touched), and runs every user-facing scenario as concurrent pty
sessions. Each element's rendered colour is parsed from the raw SGR
stream and asserted against the design tokens in
internal/uxlog/glyphs.go; degradation contracts (NO_COLOR, piped
stderr, ASCII fallbacks) must hold byte-clean. Unix only. Run it before
merging any change that touches internal/uxlog or the CLI's stderr
surfaces — it is a manual gate, not wired into CI, because its
assertions are design choices (exact hues) that are meant to evolve.
Runs unit and E2E tests with coverage and prints the merged total. When
invoked with -cover, the E2E suite builds fsend with
-cover -coverpkg=./..., so the orchestration code it exercises —
sender/receiver pairing, ICE, relay — counts toward the number instead of
reading as 0% (which is how per-package profiling reports it). Run the
script for the current total.
fsend uses mDNS for direct peer-to-peer on the same LAN.
Terminal A (sender):
echo "hello" > /tmp/hello.txt
/tmp/fsend /tmp/hello.txt
# → abc-defg-jkmTerminal B (receiver):
mkdir -p /tmp/recv && cd /tmp/recv
/tmp/fsend --yes abc-defg-jkmFor internet transfers (one peer behind NAT), the client needs a pairing server. To exercise the full client↔server↔client path:
FSEND_SERVER_ADDR=":18080" \
FSEND_RELAY_ADDR=":18443" \
FSEND_LOG_LEVEL=debug \
/tmp/fsend serverPorts 18080/18443 are chosen to avoid the privileged-port requirement
of :443 (would need root) and the common port collision on :8080.
Point a client at it (this writes to your real config file; see Isolated config below to use a throwaway one instead):
/tmp/fsend --connect 127.0.0.1:18080Reset to the public default:
/tmp/fsend --connect defaultHealth check (the env var tells the probe where to look):
FSEND_SERVER_ADDR=":18080" /tmp/fsend server --health-check| Var | Default | Notes |
|---|---|---|
FSEND_LOG_LEVEL |
info |
debug / info / warn / error |
FSEND_SERVER_ADDR |
:8080 |
Signaling listener (TCP) |
FSEND_RELAY_ADDR |
:443 |
Relay listener (UDP); also the STUN endpoint |
FSEND_RELAY_MAX_BYTES_PER_SESSION |
0 (unlimited) |
Per-session relay cap (wire bytes, post-compression). |
Full list: /tmp/fsend server --help. For deployment, ports, and all
tunables, see Self-hosting.
To experiment with --connect without overwriting your real config,
point the client at a throwaway config root:
XDG_CONFIG_HOME=/tmp/fsend-dev /tmp/fsend --connect 127.0.0.1:18080Config lives in the per-OS path listed in Usage.