Jason Tudisco 689d14202b Add README for main project and each example
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>
2026-03-17 14:45:20 -06:00

4.7 KiB

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):

    cargo run
    
  2. Configure the sync agent -- edit config.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:

    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 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 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