A high-performance, type-safe Rust implementation of the OpenIGTLink protocol for real-time communication in image-guided therapy and surgical navigation systems.
OpenIGTLink is the industry-standard open network protocol used in medical applications like 3D Slicer, PLUS Toolkit, and numerous surgical navigation systems worldwide.
- π¦ Memory Safety - Rust's ownership system eliminates memory leaks and buffer overflows common in medical software
- π High Performance - Zero-copy parsing and efficient serialization for real-time surgical applications
- β 100% Compatible - Binary-compatible with the official C++ library - works with all existing OpenIGTLink software
- π― Dynamic Dispatch - Receive any message type at runtime, just like C++ MessageFactory (v0.3.0+)
- π Production Ready - 102+ comprehensive tests, extensive documentation, and real-world examples
- ποΈ Type-Safe Builder - Compile-time guarantees prevent invalid client configurations
The most common use case is receiving messages dynamically without knowing the type in advance:
use openigtlink_rust::io::builder::ClientBuilder;
use openigtlink_rust::protocol::AnyMessage;
// Connect to an OpenIGTLink server
let mut client = ClientBuilder::new()
.tcp("127.0.0.1:18944")
.async_mode()
.build()
.await?;
// Receive any message type dynamically
let msg = client.receive_any().await?;
// Pattern match to handle different message types
match msg {
AnyMessage::Transform(transform_msg) => {
println!("Received transform from {}", transform_msg.header.device_name.as_str()?);
// Access the 4x4 transformation matrix
let matrix = &transform_msg.content.matrix;
}
AnyMessage::Image(image_msg) => {
println!("Received {}x{}x{} image",
image_msg.content.size[0],
image_msg.content.size[1],
image_msg.content.size[2]);
}
AnyMessage::Status(status_msg) => {
println!("Status: {}", status_msg.content.status_string);
}
_ => println!("Received: {}", msg.message_type()),
}Try it now - Run your first example in 30 seconds:
# Terminal 1: Start a server that sends various message types
cargo run --example async_server
# Terminal 2: Receive and handle messages dynamically
cargo run --example async_dynamic_receiverFor sending specific message types, use the type-safe API:
use openigtlink_rust::protocol::message::IgtlMessage;
use openigtlink_rust::protocol::types::TransformMessage;
let transform = TransformMessage::identity();
let msg = IgtlMessage::new(transform, "SurgicalTool")?;
client.send(&msg).await?;Receive any message type without compile-time knowledge - perfect for monitoring tools, protocol analyzers, and multi-device applications:
use openigtlink_rust::protocol::AnyMessage;
// Receive messages dynamically at runtime
let msg = client.receive_any().await?;
// Access common header information
println!("Device: {}, Type: {}", msg.device_name()?, msg.message_type());
// Pattern match for specific handling
match msg {
AnyMessage::Transform(t) => { /* handle transform */ },
AnyMessage::Image(i) => { /* handle image */ },
AnyMessage::Status(s) => { /* handle status */ },
AnyMessage::Unknown { header, body } => {
// Handle custom/unknown message types
println!("Custom type: {}", header.type_name.as_str()?);
}
_ => { /* handle other types */ }
}Use cases:
- Generic receivers for multiple devices (surgical tools, scanners, sensors)
- Message logging and monitoring dashboards
- Protocol debugging and testing tools
- Applications receiving unknown or custom message types
See dynamic_receiver.rs and async_dynamic_receiver.rs for complete examples.
Create clients with exactly the features you need using the type-state builder pattern:
use openigtlink_rust::io::{builder::ClientBuilder, ReconnectConfig};
use std::sync::Arc;
use tokio_rustls::rustls;
// Simple TCP client
let client = ClientBuilder::new()
.tcp("127.0.0.1:18944")
.async_mode()
.build()
.await?;
// TLS-encrypted client
let tls_config = Arc::new(
rustls::ClientConfig::builder()
.with_root_certificates(rustls::RootCertStore::empty())
.with_no_client_auth()
);
let client = ClientBuilder::new()
.tcp("hospital-server.local:18944")
.async_mode()
.with_tls(tls_config.clone())
.build()
.await?;
// Auto-reconnecting client
let reconnect_config = ReconnectConfig::with_max_attempts(10);
let client = ClientBuilder::new()
.tcp("127.0.0.1:18944")
.async_mode()
.with_reconnect(reconnect_config.clone())
.build()
.await?;
// TLS + Auto-reconnect (previously impossible!)
let client = ClientBuilder::new()
.tcp("hospital-server.local:18944")
.async_mode()
.with_tls(tls_config.clone())
.with_reconnect(reconnect_config)
.build()
.await?;
// UDP for low-latency tracking (bind any available local port)
let client = ClientBuilder::new()
.udp("0.0.0.0:0")
.build()?;Compile-time safety: Unsupported combinations (like UDP + TLS) are prevented at compile time!
- 20/20 Message Types - Complete implementation of all OpenIGTLink messages
- Medical images (CT/MRI/Ultrasound) with compression
- Real-time video streaming (H.264, VP9, MJPEG)
- Surgical tool tracking (60-120 Hz)
- Sensor data (force sensors, IMU)
- 3D visualization (meshes, point clouds)
- Flexible Builder API - Type-safe client construction with compile-time validation
- Async/Sync I/O - Choose between blocking or Tokio async for your use case
- UDP Support - Low-latency tracking data transmission (120+ Hz)
- TLS/SSL Encryption - Secure medical data transfer with certificate validation
- Auto-reconnection - Robust network error handling with exponential backoff
- Multi-client Server - Built-in session management for concurrent connections
- Zero-copy Parsing - Minimal overhead for real-time applications
- Image Compression - 98-99% reduction for medical images (Deflate/Gzip)
- Message Queuing - Backpressure control for high-throughput scenarios
- CRC-64 Validation - Optional integrity checking
- Structured Logging - Production-ready tracing integration
Add to your Cargo.toml:
[dependencies]
openigtlink-rust = "0.4" # Latest: Dynamic message dispatch supportOr install from source:
git clone https://github.com/gongfour/openigtlink-rust.git
cd openigtlink-rust
cargo build --releaseThe library uses a type-state builder pattern to ensure compile-time safety:
ClientBuilder::new()
.tcp(addr) // Or .udp(addr)
.async_mode() // Or .sync() for blocking I/O
.with_tls(config) // Optional: Add TLS encryption
.with_reconnect(cfg) // Optional: Enable auto-reconnection
.verify_crc(true) // Optional: CRC verification
.build() // Returns Result<Client>Key Design Decisions:
-
No Variant Explosion: Instead of creating separate types for every feature combination (TcpAsync, TcpAsyncTls, TcpAsyncReconnect, TcpAsyncTlsReconnect...), we use a single
UnifiedAsyncClientwith optional features. -
Type-Safe States: The builder uses Rust's type system to prevent invalid configurations at compile time. For example, you cannot call
.with_tls()on a UDP client. -
Zero Runtime Cost: The
PhantomDatamarkers used for type states have zero size and are optimized away at compile time.
pub struct UnifiedAsyncClient {
// Internal transport (Plain TCP or TLS)
transport: Option<Transport>,
// Optional auto-reconnection
reconnect_config: Option<ReconnectConfig>,
// Connection parameters
conn_params: ConnectionParams,
// CRC verification
verify_crc: bool,
}
enum Transport {
Plain(TcpStream),
Tls(TlsStream<TcpStream>),
}This design:
- β Scales to any number of features without combinatorial explosion
- β Maintains type safety and compile-time guarantees
- β Enables previously impossible combinations (TLS + Reconnect)
- β Easy to extend with new features (compression, authentication, etc.)
| Builder | Result Type | Best For | Key Features |
|---|---|---|---|
.tcp().sync() |
SyncIgtlClient |
Simple applications | Blocking I/O, easy to use |
.tcp().async_mode() |
UnifiedAsyncClient |
High concurrency | Tokio async, 100+ clients |
.tcp().async_mode().with_tls() |
UnifiedAsyncClient |
Secure networks | Certificate-based encryption |
.tcp().async_mode().with_reconnect() |
UnifiedAsyncClient |
Unreliable networks | Auto-reconnect with backoff |
.udp() |
UdpClient |
Real-time tracking | Low latency (120+ Hz) |
// Track surgical tools in real-time with UDP
let mut client = ClientBuilder::new()
.udp("127.0.0.1:18944")
.build()?;
loop {
let transform = get_tool_position();
let msg = IgtlMessage::new(transform, "Scalpel")?;
client.send(&msg)?;
tokio::time::sleep(Duration::from_millis(8)).await; // 120 Hz
}use openigtlink_rust::protocol::types::ImageMessage;
// Stream CT/MRI scans with compression
let image = ImageMessage::new(
ImageScalarType::Uint16,
[512, 512, 100],
image_data
)?;
let msg = IgtlMessage::new(image, "CTScan")?;
client.send(&msg).await?;use openigtlink_rust::io::tls_client::insecure_tls_config;
use std::sync::Arc;
// TLS-encrypted communication with auto-reconnection
let tls_config = Arc::new(insecure_tls_config());
let reconnect_config = ReconnectConfig::with_max_attempts(10);
let mut client = ClientBuilder::new()
.tcp("hospital-server.local:18944")
.async_mode()
.with_tls(tls_config)
.with_reconnect(reconnect_config)
.build()
.await?;
client.send(&patient_data).await?;// Production-ready client with all features
let client = ClientBuilder::new()
.tcp("production-server:18944")
.async_mode()
.with_tls(load_production_certs()?)
.with_reconnect(
ReconnectConfig::with_max_attempts(100)
)
.verify_crc(true)
.build()
.await?;β 20/20 message types fully implemented - Complete OpenIGTLink protocol coverage
π‘ Tracking & Position (6 types)
- TRANSFORM - 4x4 transformation matrices
- POSITION - Position + quaternion orientation
- QTDATA - Quaternion tracking for surgical tools
- TDATA - Transform tracking data (3x4 matrices)
- TRAJECTORY - 3D surgical trajectories
- POINT - Fiducial points for navigation
π₯ Medical Imaging (4 types)
- IMAGE - 2D/3D medical images (CT/MRI/Ultrasound)
- VIDEO - Video streaming (H.264/VP9/MJPEG/Raw)
- IMGMETA - Image metadata (patient info, modality)
- VIDEOMETA - Video metadata (codec, resolution, bitrate)
π Data & Sensors (2 types)
- SENSOR - Sensor arrays (force, IMU, etc.)
- NDARRAY - N-dimensional numerical arrays
π¨ Visualization (3 types)
- POLYDATA - 3D meshes and polygons
- LBMETA - Segmentation labels
- COLORTABLE - Color lookup tables
π¬ Communication (5 types)
- STRING - Text messages
- COMMAND - XML commands
- STATUS - Device status
- CAPABILITY - Protocol negotiation
- BIND - Message grouping
Plus 22 query/control messages: GET_, STT_, STP_, RTS_
π Ready-to-run examples covering all features - Browse all examples
New to OpenIGTLink? Start here:
# 1. Dynamic message receiver (recommended - works with any message type)
cargo run --example async_server # Terminal 1
cargo run --example async_dynamic_receiver # Terminal 2
# 2. Basic client/server (specific message types)
cargo run --example server # Terminal 1
cargo run --example client # Terminal 2Key examples:
- async_dynamic_receiver.rs - Start here! Receive any message type dynamically (v0.3.0+)
- dynamic_receiver.rs - Sync version of dynamic receiver
- client.rs - Basic client with specific message types
- server.rs - Basic server example
Medical Imaging
# CT/MRI/Ultrasound streaming
cargo run --example image_streaming ct
cargo run --example image_streaming ultrasound
# Real-time video
cargo run --example video_streaming h264Surgical Navigation
# Tool tracking at 60-120 Hz
cargo run --example tracking_server
cargo run --example udp_tracking
# Fiducial registration
cargo run --example point_navigationSensor Integration
# Force/torque sensors
cargo run --example sensor_logger force
# IMU data
cargo run --example sensor_logger imuSecurity & Networking
# TLS encryption
./examples/generate_test_certs.sh
cargo run --example tls_communication
# Auto-reconnection
cargo run --example reconnect
# Multi-client server
cargo run --example session_managerPerformance Optimization
# Image compression (98-99% ratio)
cargo run --example compression
# UDP low-latency
cargo run --example udp_tracking compare
# Message queuing
cargo run --example message_queue3D Slicer Integration
# Query & streaming control
cargo run --example query_streaming
# Connect to remote Slicer
cargo run --example query_streaming -- 192.168.1.100:18944cargo test # 102 tests
cargo bench # Performance benchmarks
RUST_LOG=debug cargo run --example loggingReal-world benchmarks on Apple M1:
| Operation | Performance | Details |
|---|---|---|
| Message Throughput | 10,000+ msg/sec | TRANSFORM, STATUS messages |
| Image Encoding | ~50ms | 512Γ512Γ100 CT scan (16-bit) |
| Compression | 98-99% | Medical images (Deflate) |
| UDP Latency | <1ms RTT | TRANSFORM messages |
| Concurrency | 100+ clients | Single async thread |
Run benchmarks:
cargo bench- β OpenIGTLink C++ 3.0+ - 100% binary compatible
- β 3D Slicer - Medical imaging platform
- β PLUS Toolkit - Image-guided intervention
- MSRV: Rust 1.70+
- Platforms: Linux, macOS, Windows
- π API Docs - Complete API reference
- π Examples - 17+ practical examples
- π Query Guide - Streaming control protocol
- π Benchmarks - Performance analysis
- π OpenIGTLink Protocol - Official specification
Contributions welcome! Feel free to:
- π Report bugs via issues
- π‘ Suggest features or improvements
- π§ Submit pull requests
β Production-ready - Used in real surgical navigation systems
| Metric | Status |
|---|---|
| Message Types | 20/20 β |
| Query/Control | 22/22 β |
| Tests | 102 passing β |
| C++ Compatibility | 100% β |
| Documentation | Complete β |
MIT License - See LICENSE for details
β Star on GitHub β’ π¦ View on crates.io β’ π Read the Docs
Built with β€οΈ for the medical robotics community