Macha Logo

Rust library

Embed tunneling directly in your Rust app with no external process.

Quick start

Cargo.toml
[dependencies]
macha = "0.2"
tokio = { version = "1", features = ["full"] }
src/main.rs — one-liner
use macha;

#[tokio::main]
async fn main() -> macha::Result<()> {
    // blocks until disconnected; auto-reconnects by default
    macha::start("myapp", 3000).await
}

Run in the background alongside your server

use macha::Tunnel;

#[tokio::main]
async fn main() -> macha::Result<()> {
    let tunnel = Tunnel::builder("myapp", 3000)
        .build()?;

    tokio::spawn(async move {
        let _ = tunnel.run().await;
    });

    // start your own server here…
    std::future::pending::<()>().await;
    Ok(())
}

Builder API

All options are chainable on Tunnel::builder(subdomain, port).

MethodTypeDescription
.server(host)&strTunnel server hostname (default: "macha.live")
.control_port(n)u16Control plane port (default: 9000)
.data_port(n)u16Data plane port (default: 9001)
.token(t)&strAuth token to send on REGISTER
.reconnect(bool)boolAuto-reconnect on session end (default: true)
.ttl(secs)u64Registration TTL in seconds (default: 3600 = 1 hour). Server drops the subdomain when it elapses; with reconnect (default) the agent re-registers automatically.
.tls()Enable TLS with Mozilla root certs
.tls_custom_ca(path)PathBufEnable TLS with a custom CA cert file
.tls_insecure()Enable TLS, skip cert verification (dev only)
.log_channel(tx)broadcast::Sender<RequestLog>Receive a RequestLog after each completed request
.build()Result<Tunnel>Validates subdomain, returns Tunnel
full example
use macha::Tunnel;

let tunnel = Tunnel::builder("myapp", 3000)
    .server("tunnel.yourcompany.com")
    .token("my-secret-token")
    .tls()
    .reconnect(true)
    .build()?;

tunnel.run().await?;

Log channel

Wire a tokio::sync::broadcast channel into the tunnel to receive a RequestLog after every completed request.

use macha::{Tunnel, RequestLog};
use tokio::sync::broadcast;

let (tx, mutrx) = broadcast::channel::<RequestLog>(256);

// spawn log consumer
tokio::spawn(async move {
    while let Ok(log) = rx.recv().await {
        println!("{} {} — {}ms", log.method, log.path, log.duration_ms);
    }
});

Tunnel::builder("myapp", 3000)
    .log_channel(tx)
    .build()?
    .run().await?;

RequestLog fields

FieldTypeDescription
subdomainStringThe registered subdomain
methodStringHTTP method (GET, POST, …)
pathStringRequest path (/api/users, …)
bytes_inu64Bytes received from visitor (request)
bytes_outu64Bytes sent to visitor (response)
duration_msu64Total time from first byte to connection close
timestamp_msu128Unix epoch milliseconds when request completed