Getting Started with the SDK

Connect your first device to Tetrapus in under 5 minutes.

1. Add the Crate

Bash
cargo add nerve-sdk

# With compression support:
cargo add nerve-sdk --features full

2. Configure the Client

Rust
use nerve_sdk::{NerveClient, NerveConfig, SchemaId};
use std::time::Duration;

let config = NerveConfig::new("127.0.0.1:4433")
    .with_queue_capacity(10_000)       // in-memory buffer
    .with_batch_size(1_400)            // MTU-sized batches
    .with_flush_interval(Duration::from_millis(10));  // 100 Hz max flush

See Client API for the full NerveConfig reference.

3. Connect

Rust
let client = NerveClient::connect(config).await?;
// Connection probe: full TLS 1.3 handshake + teardown
// Background SendWorker spawned automatically

4. Define a Schema

Schema IDs are content-addressed: first 4 bytes of SHA-256, as a 32-bit big-endian integer.

Rust
// From a FlatBuffers schema file:
let schema = SchemaId::from_file("schemas/fleet_gps_v2.fbs")?;

// Or from raw bytes:
let schema = SchemaId::from_bytes(b"my_sensor_schema_v1");

// Or a known constant:
let schema = SchemaId::new(0x00000002);

5. Send Data

Rust
loop {
    let payload = read_sensor_data();

    // Non-blocking: ~50 ns, pushes to in-memory queue
    client.send_raw(schema, &payload)?;

    // Or with explicit priority:
    // client.send_priority(schema, &payload, Priority::Critical)?;

    tokio::time::sleep(Duration::from_millis(100)).await; // 10 Hz
}

That's it. The background worker handles batching, compression, reconnection, and spill-to-disk automatically. Your application thread never blocks.

6. Monitor Health

Rust
// Check queue pressure
println!("Queue: {}", client.queue_depth());
println!("Spilled: {}", client.spill_depth());

// Access atomic counters
let m = client.metrics();
println!("Sent: {}, Bytes: {}", m.messages_sent(), m.bytes_sent());

// All counters as (name, value) pairs — for Prometheus/StatsD
for (name, value) in m.snapshot() {
    println!("{}: {}", name, value);
}

7. Graceful Shutdown

Rust
// Drain remaining messages with a 5-second timeout
let unflushed = client.shutdown(Duration::from_secs(5)).await?;
if unflushed > 0 {
    eprintln!("{} messages were not flushed", unflushed);
}

Complete Example

Rust
use nerve_sdk::{NerveClient, NerveConfig, SchemaId};
use std::time::Duration;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let config = NerveConfig::new("127.0.0.1:4433")
        .with_queue_capacity(50_000)
        .with_batch_size(1_400)
        .with_flush_interval(Duration::from_millis(10));

    let client = NerveClient::connect(config).await?;
    let schema = SchemaId::from_bytes(b"temperature_v1");

    for i in 0..1000 {
        let temp: f32 = 20.0 + (i as f32 * 0.01).sin() * 5.0;
        client.send_raw(schema, &temp.to_le_bytes())?;
        tokio::time::sleep(Duration::from_millis(10)).await;
    }

    let unflushed = client.shutdown(Duration::from_secs(5)).await?;
    println!("Done. Unflushed: {}", unflushed);
    Ok(())
}

Next Steps

Questions?

Reach out for help with integration, deployment, or custom domain codecs.