Add flit watch: one-way folder sync to a trusted peer
Watches local directories and auto-pushes new/changed files to a known daemon peer via fsnotify, with startup reconciliation, a stable_after debounce, and per-file JSON state so failed sends retry on the next connection. Multiple watch entries targeting the same peer share a single connection/room (watchPeerGroup), resolving the room-name-collision question flagged in PROPOSAL-watch.md. Push-only, never propagates deletes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
34
README.md
34
README.md
@@ -20,6 +20,7 @@ It is deliberately not a replacement for [Zipline](https://github.com/diced/zipl
|
||||
- Auto-downloads on the receiver side — no "click to save" step.
|
||||
- In-app QR scanner (Chrome/Android) — scan the sender's QR without leaving flit.
|
||||
- Android share sheet integration — "Share → flit" works from Photos, Files, any app.
|
||||
- One-way folder sync (`flit watch`) — drop a file into a watched folder, it gets pushed to a trusted peer automatically, no manual send.
|
||||
|
||||
---
|
||||
|
||||
@@ -101,6 +102,7 @@ For headless machines (homelab boxes, servers) that can't run a browser.
|
||||
flit send path/to/file.tar.gz # print QR + invite, wait for peer, send
|
||||
flit recv "flit:eyJhbmNob3..." # join from invite string, accept file
|
||||
flit daemon # persistent receiver for trusted peers
|
||||
flit watch [--dry-run] # watch folders, auto-push new files to trusted peers
|
||||
```
|
||||
|
||||
**Built with:** Go, pion/webrtc, libsodium (via nhooyr.io/websocket + internal crypto).
|
||||
@@ -132,6 +134,38 @@ Copy `cli/daemon.toml.example` to `~/.flit/daemon.toml` to get started. The daem
|
||||
|
||||
**Bootstrapping:** to get a peer's `id`, pair once via QR (`flit send` / PWA "Invite new") and copy the hex ID from the "peer connected" log line, or read it from the PWA's Known devices list after tapping "Remember this device."
|
||||
|
||||
### Watch mode
|
||||
|
||||
`flit watch` is the send-side sibling of `flit daemon`: it watches one or more local folders and automatically pushes new or changed files to a specific trusted peer — no manual `flit send`, no QR, no per-file interaction. It's **one-way sync only** (source → destination, push only) — deliberately not a general bidirectional sync tool, and it never propagates deletes.
|
||||
|
||||
The receiving side needs no changes: an already-running `flit daemon`, configured with the watcher's device as a trusted peer, already does the right thing on receipt.
|
||||
|
||||
Config lives at `~/.flit/watch.toml`:
|
||||
|
||||
```toml
|
||||
signal_url = "wss://your-anchor.example.com/ws"
|
||||
turn_url = "" # optional
|
||||
turn_secret = "" # optional
|
||||
|
||||
[[watch]]
|
||||
dir = "/home/user/backups/documents"
|
||||
peer_id = "<hex Ed25519 pubkey of the destination device>"
|
||||
peer_label = "home-server"
|
||||
pattern = "*.pdf,*.docx" # optional glob include-list; default "*" if omitted
|
||||
stable_after = "10s" # optional quiet period before considering a file ready
|
||||
```
|
||||
|
||||
Multiple `[[watch]]` blocks are allowed — different folders can go to different peers, or the same peer (entries sharing a `peer_id` share a single connection).
|
||||
|
||||
Copy `cli/watch.toml.example` to `~/.flit/watch.toml` to get started. Notes on behavior:
|
||||
|
||||
- **Startup reconciliation** — on start, before subscribing to filesystem events, `flit watch` walks each `dir` and diffs it against local state, so anything that changed while the watcher wasn't running gets picked up (not just live events going forward).
|
||||
- **Debounce (`stable_after`)** — a file is only considered ready to send after this quiet period has passed since its last write, so a large file being actively written isn't offered mid-write.
|
||||
- **State tracking** — one JSON state file per `[[watch]]` entry lives in `~/.flit/watch-state/`, recording what's been sent. If a send fails partway (peer disconnects mid-transfer), the file is retried on the next successful connection — no separate retry logic needed. Losing this state is harmless (worst case: the whole directory gets re-sent) but not something to engineer around.
|
||||
- **`flit watch --dry-run`** walks the configured directories and prints what *would* be sent, without connecting to anything — use it to sanity-check a new `watch.toml` before it goes live.
|
||||
- **`pattern` should be as narrow as your use case allows.** `*` is the default if omitted, but an unconstrained watch on a broad directory turns "sync my documents" into "sync everything that ever lands in this tree." There's no per-file confirmation in watch mode — the directory and pattern in `watch.toml` are the only safety knob.
|
||||
- Reconnects with the same exponential backoff (2s → 30s cap) as daemon mode, and reuses the same trusted-peer identity model — a `peer_id` here is the same kind of already-known device as anything in the PWA's Known devices list or `daemon.toml`.
|
||||
|
||||
---
|
||||
|
||||
## Self-hosting
|
||||
|
||||
Reference in New Issue
Block a user