Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Synchronization Guide

Eidetica's sync system enables real-time data synchronization between distributed peers.

Quick Start

1. Enable Sync

extern crate eidetica;
extern crate tokio;
use eidetica::{Instance, backend::database::Sqlite};

#[tokio::main]
async fn main() -> eidetica::Result<()> {
let backend = Box::new(Sqlite::in_memory().await?);
let instance = Instance::open(backend).await?;
instance.enable_sync().await?;

// Create and login a user (generates authentication key automatically)
instance.create_user("alice", None).await?;
let mut user = instance.login_user("alice", None).await?;
Ok(())
}

2. Start a Server

use eidetica::sync::transports::http::HttpTransport;

let sync = instance.sync().unwrap();

// Register transport with bind address and start accepting connections
sync.register_transport("http", HttpTransport::builder().bind("127.0.0.1:8080")).await?;
sync.accept_connections().await?;

3. Connect and Sync

// Single API handles both bootstrap (new) and incremental (existing) sync
sync.sync_with_peer("127.0.0.1:8080", Some(&tree_id)).await?;

That's it. The system automatically detects whether you need full bootstrap or incremental sync.

Connection Architecture

The sync system separates outbound and inbound connection handling:

  • Outbound (sync_with_peer()): Works immediately after register_transport(). No server needed.
  • Inbound (accept_connections()): Must be called to accept incoming connections.
register_transport()
    │ - Transport ready for outbound requests
    ▼
[OUTBOUND READY]
    │ - sync_with_peer() works
    │ - Push hooks work
    │ - NO incoming connections
    ▼
accept_connections()
    │ - Starts server on registered transports
    ▼
[FULL P2P]
    │ - Outbound works
    │ - Inbound works

This separation provides:

  • Security by default: Nodes don't accept incoming connections unless explicitly enabled
  • Zero-config outbound: Applications can sync data immediately without server setup
  • Flexible deployment: Support client-only, server-only, or full peer-to-peer modes

Transport Options

Eidetica supports multiple transports simultaneously, allowing peers to be reachable via different networks.

HTTP

Simple REST-based sync. Good for development and fixed-IP deployments.

use eidetica::sync::transports::http::HttpTransport;

sync.register_transport("http", HttpTransport::builder().bind("127.0.0.1:8080")).await?;
sync.accept_connections().await?;

QUIC-based with NAT traversal. Works through firewalls.

use eidetica::sync::transports::iroh::IrohTransport;

sync.register_transport("iroh", IrohTransport::builder()).await?;
sync.accept_connections().await?;
let my_address = sync.get_server_address_async().await?;  // Share this with peers

Multiple Transports

Enable multiple transports for maximum connectivity:

use eidetica::sync::transports::http::HttpTransport;
use eidetica::sync::transports::iroh::IrohTransport;

// Register both HTTP (for local network) and Iroh (for P2P)
sync.register_transport("http", HttpTransport::builder().bind("127.0.0.1:0")).await?;
sync.register_transport("iroh", IrohTransport::builder()).await?;

// Start servers on all transports
sync.accept_connections().await?;

// Get all server addresses
let addresses = sync.get_all_server_addresses_async().await?;
for (transport_name, addr) in addresses {
    println!("{}: {}", transport_name, addr);
}

Requests are automatically routed to the appropriate transport based on address type.

Declarative Sync API

For persistent sync relationships:

extern crate eidetica;
extern crate tokio;
use eidetica::sync::{SyncPeerInfo, Address};
use eidetica::{Instance, backend::database::Sqlite, crdt::Doc};

#[tokio::main]
async fn main() -> eidetica::Result<()> {
let backend = Box::new(Sqlite::in_memory().await?);
let instance = Instance::open(backend).await?;
instance.enable_sync().await?;
instance.create_user("alice", None).await?;
let mut user = instance.login_user("alice", None).await?;
let default_key = user.get_default_key()?;
let db = user.create_database(Doc::new(), &default_key).await?;
let tree_id = db.root_id().clone();
let sync = instance.sync().expect("Sync enabled");
let peer_pubkey = "ed25519:abc123".to_string();
// Register a peer for automatic background sync
let handle = sync.register_sync_peer(SyncPeerInfo {
    peer_pubkey,
    tree_id,
    addresses: vec![Address {
        transport_type: "http".to_string(),
        address: "http://peer.example.com:8080".to_string(),
    }],
    auth: None,
    display_name: Some("Peer Device".to_string()),
}).await?;
Ok(())
}

Background sync happens automatically. Check status with handle.status()?.

Sync Settings

Configure per-database sync behavior:

extern crate eidetica;
extern crate tokio;
use eidetica::{Instance, backend::database::Sqlite, crdt::Doc};
use eidetica::user::types::{SyncSettings, TrackedDatabase};

#[tokio::main]
async fn main() -> eidetica::Result<()> {
let backend = Box::new(Sqlite::in_memory().await?);
let instance = Instance::open(backend).await?;
instance.enable_sync().await?;
instance.create_user("alice", None).await?;
let mut user = instance.login_user("alice", None).await?;
let key = user.get_default_key()?;
let db = user.create_database(Doc::new(), &key).await?;
let db_id = db.root_id().clone();
let tracked = TrackedDatabase {
    database_id: db_id,
    key_id: user.get_default_key()?,
    sync_settings: SyncSettings {
        sync_enabled: true,
        sync_on_commit: true,        // Sync immediately on commit
        interval_seconds: Some(60),  // Also sync every 60 seconds
        properties: Default::default(),
    },
};

// Track this database with the User
user.track_database(tracked).await?;
Ok(())
}

Authenticated Bootstrap

For joining databases that require authentication:

// Request database access through User API
user.request_database_access(
    &sync,
    "127.0.0.1:8080",
    &database_id,
    &key_id,  // User's key ID from user.add_private_key()
    eidetica::auth::Permission::Write,
).await?;

See Bootstrap Guide for approval workflows.

Automatic Behavior

Once configured, the sync system handles:

  • Immediate sync on commit (if sync_on_commit: true)
  • Periodic sync at configured intervals
  • Retry with exponential backoff for failed sends
  • Bidirectional transfer in each sync operation

Troubleshooting

IssueSolution
"No transport enabled"Call register_transport() with HTTP or Iroh transport builder
Can't receive connectionsCall accept_connections() to start servers
Sync not happeningCheck peer status, network connectivity
Auth failuresVerify keys are configured, protocol versions match

Example

See the Chat Example for a complete working application demonstrating multi-transport sync, bootstrap, and real-time updates.