Main README covers quick start, API overview, and links to example READMEs. Each example (paste, filemanager, can-sync, canfs) gets its own README with setup instructions, architecture, and configuration details. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
92 lines
4.7 KiB
Markdown
92 lines
4.7 KiB
Markdown
# CAN Sync
|
|
|
|
P2P full-mirror replication for [CAN Service](../../). Two machines with the same passphrase automatically discover each other and sync all assets over encrypted connections. No port forwarding or static IPs needed.
|
|
|
|
```
|
|
┌─────────────┐ protobuf ┌─────────────┐ iroh (QUIC) ┌─────────────┐ protobuf ┌─────────────┐
|
|
│ CAN Service │◄───────────►│ CAN Sync │◄─────────────►│ CAN Sync │◄───────────►│ CAN Service │
|
|
│ Machine A │ sync API │ Agent A │ encrypted │ Agent B │ sync API │ Machine B │
|
|
│ port 3210 │ │ │ │ │ │ port 3210 │
|
|
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
1. **Start CAN Service** on each machine (port 3210):
|
|
```bash
|
|
cargo run
|
|
```
|
|
|
|
2. **Configure the sync agent** -- edit `config.yaml`:
|
|
```yaml
|
|
can_service_url: "http://127.0.0.1:3210"
|
|
sync_api_key: "can-sync-default-key"
|
|
sync_passphrase: "my-secret-phrase" # must be the same on all machines
|
|
poll_interval_secs: 30
|
|
```
|
|
|
|
3. **Start the sync agent** on each machine:
|
|
```bash
|
|
cd examples/can-sync
|
|
cargo run -- config.yaml
|
|
```
|
|
|
|
That's it. Any file uploaded to either CAN Service will appear on the other within seconds.
|
|
|
|
## How It Works
|
|
|
|
### Peer Discovery
|
|
|
|
Peers find each other through two mechanisms (both run simultaneously):
|
|
|
|
- **Gossip** -- [iroh-gossip](https://docs.rs/iroh-gossip) uses a topic derived from the shared passphrase. Peers on the same local network or connected to the same relay discover each other by broadcasting their node IDs.
|
|
- **Internet rendezvous** -- Each agent publishes its node ID to [pkarr](https://pkarr.org) relay servers using deterministic DNS-like "slots" derived from the passphrase. All agents scan these slots periodically to find peers worldwide.
|
|
|
|
### Sync Protocol
|
|
|
|
Once two peers connect over iroh's encrypted QUIC transport:
|
|
|
|
1. **Hash exchange** -- Both sides send their full list of asset hashes
|
|
2. **Diff** -- Each side computes what the other is missing
|
|
3. **Transfer** -- Missing assets are sent concurrently in both directions (metadata + file content bundled together as protobuf)
|
|
4. **Live sync** -- After the initial reconciliation, each agent subscribes to SSE events from its local CAN Service. When a new asset is ingested locally, it's pushed to the connected peer instantly.
|
|
|
|
The live sync uses SSE events (not polling) for instant propagation. A fallback incremental poll runs every 30 seconds as a safety net.
|
|
|
|
### Echo Prevention
|
|
|
|
When peer A sends an asset to peer B, B's CAN Service emits an SSE event for the new ingest. Without protection, B would try to push that asset right back to A. The sync agent tracks which hashes were received from each peer and filters them out of the push loop.
|
|
|
|
## Configuration
|
|
|
|
| Field | Default | Description |
|
|
|-------|---------|-------------|
|
|
| `can_service_url` | (required) | URL of the local CAN Service |
|
|
| `sync_api_key` | (required) | Must match `sync_api_key` in CAN Service's config |
|
|
| `sync_passphrase` | (required) | Shared secret for peer discovery (all peers must match) |
|
|
| `poll_interval_secs` | `3` | Fallback poll interval for catching missed events |
|
|
| `ticket_file` | (none) | Write this node's address to a file (for direct connection in tests) |
|
|
| `connect_ticket_file` | (none) | Read a peer's address from a file (for direct connection in tests) |
|
|
|
|
CAN Service must have `sync_api_key` set in its `config.yaml` for the sync endpoints to be enabled.
|
|
|
|
## Security
|
|
|
|
- **Transport** -- All peer traffic is encrypted with QUIC + TLS 1.3 (mandatory in iroh)
|
|
- **Identity** -- Each node gets an Ed25519 keypair on first run
|
|
- **Discovery** -- Only peers with the same passphrase can find each other
|
|
- **Hash verification** -- Every received asset is re-hashed and compared before being stored
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
src/
|
|
main.rs Entry point: config, iroh endpoint, discovery, peer connections
|
|
config.rs YAML config loading
|
|
can_client.rs HTTP client for CAN Service's sync API (protobuf + SSE)
|
|
protocol.rs Protobuf message types (shared with CAN Service)
|
|
discovery.rs Peer discovery via iroh-gossip
|
|
rendezvous.rs Internet peer discovery via pkarr relay
|
|
peer.rs Per-peer sync: reconciliation, live push/receive, echo prevention
|
|
```
|