# irtt-rs

`irtt-rs` is a Rust implementation of an IRTT-compatible client.

It is not the upstream IRTT project. For the original implementation, protocol background, and broader project documentation, see:

<https://github.com/heistp/irtt>

## Status

This repository currently provides:

- `irtt-cli`, a command-line IRTT-compatible client
- `irtt-client`, a Rust library for running client sessions and consuming events
- finite and continuous probe runs
- human, simple, machine-readable, and RTT-only output modes
- optional local summary statistics

Server support is not implemented.

## Install

Requires Rust 1.75 or newer.

From a local checkout:

```sh
git clone https://github.com/Lochnair/irtt-rs.git
cd irtt-rs
cargo install --path crates/irtt-cli
```

Or run it directly without installing:

```sh
cargo run -p irtt-cli -- <server>
```

## CLI usage

Basic test:

```sh
irtt-cli <server>
```

Set duration and interval:

```sh
irtt-cli <server> --duration 30s --interval 100ms
```

Run continuously:

```sh
irtt-cli <server> --duration 0
```

Use a specific output mode:

```sh
irtt-cli <server> --output human
irtt-cli <server> --output simple
irtt-cli <server> --output machine
irtt-cli <server> --output rtt-us
```

For available options:

```sh
irtt-cli --help
```

## Machine output

Use `--output machine` for line-oriented `key=value` output intended for scripts, monitoring, and autorate consumers.

Example:

```sh
irtt-cli <server> --duration 0 --interval 250ms --output machine
```

Each line represents one client event and starts with an `event` field, for example:

```text
event=echo_reply seq=4 logical_seq=4 remote=203.0.113.10:2112 raw_rtt_us=12400 effective_rtt_us=12100 adjusted_rtt_us=12100 server_processing_us=300 dscp=0 ecn=0 kernel_rx_ns=none
```

Consumers should match on `event=...` and read the fields they need. Unknown fields should be ignored.

For consumers that only need RTT values, use:

```sh
irtt-cli <server> --output rtt-us
```

## Library usage

`irtt-client` can be used directly from Rust code.

Example `Cargo.toml` dependency from a local checkout:

```toml
[dependencies]
irtt-client = { path = "crates/irtt-client" }
```

Minimal managed-client example:

```rust
use std::time::Duration;

use irtt_client::{
    ClientConfig, ClientEvent, ManagedClient, SubscriberConfig,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ClientConfig {
        server_addr: "netperf-eu.bufferbloat.net:2112".to_owned(),
        duration: Some(Duration::from_secs(10)),
        interval: Duration::from_secs(1),
        ..ClientConfig::default()
    };

    let (session, events) =
        ManagedClient::start_with_subscription(config, SubscriberConfig::default())?;

    while let Ok(event) = events.recv() {
        match event {
            ClientEvent::EchoReply { seq, rtt, .. } => {
                println!("seq={seq} rtt_us={}", rtt.effective.as_micros());
            }
            ClientEvent::SessionClosed { .. } => break,
            _ => {}
        }
    }

    let outcome = session.join()?;
    println!("session ended: {:?}", outcome.end_reason);

    Ok(())
}
```
