Dashboard
Binboi Docs/SDKs/Rust

Rust SDK

The Binboi Rust SDK provides async tunnel management via Tokio. Use it to embed tunnels directly in Rust applications, integration tests, or CLI tools.

Add the Dependency

# Cargo.toml
[dependencies]
binboi = "1"
tokio = { version = "1", features = ["full"] }

Authentication

Set environment variables before running your application:

export BINBOI_TOKEN=tok_alice_abc123
export BINBOI_SERVER=https://tunnel.example.com

Or configure in code:

use binboi::Client;
 
let client = Client::builder()
    .token("tok_alice_abc123")
    .server("https://tunnel.example.com")
    .build()
    .await?;

Opening an HTTP Tunnel

use binboi::Client;
 
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = Client::from_env().await?;
 
    let tunnel = client
        .http()
        .addr(3000)
        .subdomain("myapp")
        .start()
        .await?;
 
    println!("Tunnel URL: {}", tunnel.url());
 
    // Keep alive until Ctrl-C
    tokio::signal::ctrl_c().await?;
    tunnel.close().await?;
 
    Ok(())
}

Integrating with Axum

use axum::{routing::post, Json, Router};
use binboi::Client;
use serde_json::{json, Value};
use std::net::SocketAddr;
 
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let app = Router::new().route("/webhook", post(handle_webhook));
 
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    let listener = tokio::net::TcpListener::bind(addr).await?;
 
    // Open Binboi tunnel
    let client = Client::from_env().await?;
    let tunnel = client.http().addr(3000).subdomain("axum-app").start().await?;
    println!("Public URL: {}", tunnel.url());
 
    axum::serve(listener, app).await?;
    Ok(())
}
 
async fn handle_webhook(Json(body): Json<Value>) -> Json<Value> {
    println!("Received: {body}");
    Json(json!({ "ok": true }))
}

TCP Tunnels

let tunnel = client
    .tcp()
    .addr(5432)
    .remote_port(15432)
    .start()
    .await?;
 
println!("TCP endpoint: {}", tunnel.addr());
// TCP endpoint: tunnel.example.com:15432

Tunnel Options

let tunnel = client
    .http()
    .addr(3000)
    .subdomain("myapp")           // Reserved subdomain
    .hostname("dev.my.com")       // Custom domain
    .region("eu-west")            // Region
    .inspect(false)               // Disable local inspector
    .start()
    .await?;

Listening Directly

The SDK can accept connections itself without binding a separate TCP socket:

use binboi::Client;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
 
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = Client::from_env().await?;
    let mut listener = client.http().listen().await?;
 
    println!("Public URL: {}", listener.url());
 
    while let Some(mut conn) = listener.accept().await {
        tokio::spawn(async move {
            let response = b"HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nHello";
            conn.write_all(response).await.ok();
        });
    }
 
    Ok(())
}

Use in Tests

#[cfg(test)]
mod tests {
    use super::*;
    use binboi::Client;
 
    #[tokio::test]
    async fn test_webhook_endpoint() {
        let client = Client::from_env().await.unwrap();
        let tunnel = client.http().addr(3000).start().await.unwrap();
 
        let res = reqwest::Client::new()
            .post(format!("{}/webhook", tunnel.url()))
            .json(&serde_json::json!({ "event": "test" }))
            .send()
            .await
            .unwrap();
 
        assert_eq!(res.status(), 200);
        tunnel.close().await.unwrap();
    }
}

Error Handling

use binboi::{Client, Error};
 
match client.http().addr(3000).subdomain("taken").start().await {
    Ok(tunnel) => println!("URL: {}", tunnel.url()),
    Err(Error::SubdomainInUse(name)) => eprintln!("Subdomain '{name}' is taken"),
    Err(Error::Auth(msg)) => eprintln!("Auth error: {msg}"),
    Err(e) => eprintln!("Error: {e}"),
}

Feature Flags

| Feature | Description | Default | |---|---|---| | default | HTTP and TCP tunnels, Tokio runtime | enabled | | tls-native | Use native OS TLS (SChannel / Secure Transport) | disabled | | tls-rustls | Use rustls instead of OpenSSL | disabled |