1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//! Dynamic message receiver example
//!
//! This example demonstrates how to receive OpenIGTLink messages without knowing
//! the message type in advance. This is similar to the C++ OpenIGTLink library's
//! MessageFactory pattern.
//!
//! # Usage
//!
//! 1. Start a server that sends various message types:
//! ```bash
//! cargo run --example server
//! ```
//!
//! 2. Run this example:
//! ```bash
//! cargo run --example dynamic_receiver
//! ```
//!
//! # How it works
//!
//! - The client uses `receive_any()` instead of `receive::<T>()`
//! - The message type is determined at runtime from the header
//! - Messages are returned as an `AnyMessage` enum
//! - You can pattern match to handle different message types
//!
//! This is useful for:
//! - Generic receivers that handle multiple message types
//! - Message logging/monitoring tools
//! - Protocol debugging and inspection
//! - Applications that receive unknown or custom message types
use openigtlink_rust::io::builder::ClientBuilder;
use openigtlink_rust::protocol::AnyMessage;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize logging
tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.init();
println!("Dynamic Message Receiver Example");
println!("=================================\n");
// Connect to server
println!("Connecting to server at 127.0.0.1:18944...");
let mut client = ClientBuilder::new().tcp("127.0.0.1:18944").sync().build()?;
println!("Connected! Waiting for messages...\n");
// Receive messages in a loop
let mut message_count = 0;
loop {
match client.receive_any() {
Ok(msg) => {
message_count += 1;
println!("Message #{}: {}", message_count, format_message(&msg)?);
println!();
// You can also access common header information
println!(
" Header info: device='{}', timestamp={}.{}",
msg.device_name()?,
msg.header().timestamp.seconds,
msg.header().timestamp.fraction
);
println!();
// Handle specific message types
match msg {
AnyMessage::Transform(transform_msg) => {
println!(" Transform matrix:");
let m = &transform_msg.content.matrix;
for row in m.iter().take(4) {
println!(
" [{:8.4}, {:8.4}, {:8.4}, {:8.4}]",
row[0], row[1], row[2], row[3]
);
}
}
AnyMessage::Status(status_msg) => {
println!(
" Status: code={}, name='{}'",
status_msg.content.code, status_msg.content.error_name
);
println!(" Message: '{}'", status_msg.content.status_string);
}
AnyMessage::Image(image_msg) => {
println!(
" Image: {}x{}x{}, type={:?}",
image_msg.content.size[0],
image_msg.content.size[1],
image_msg.content.size[2],
image_msg.content.scalar_type
);
println!(" Data size: {} bytes", image_msg.content.data.len());
}
AnyMessage::Position(position_msg) => {
println!(
" Position: ({:.2}, {:.2}, {:.2})",
position_msg.content.position[0],
position_msg.content.position[1],
position_msg.content.position[2]
);
println!(
" Quaternion: ({:.3}, {:.3}, {:.3}, {:.3})",
position_msg.content.quaternion[0],
position_msg.content.quaternion[1],
position_msg.content.quaternion[2],
position_msg.content.quaternion[3]
);
}
AnyMessage::String(string_msg) => {
println!(" String encoding: {}", string_msg.content.encoding);
println!(" Content: '{}'", string_msg.content.string);
}
AnyMessage::Capability(capability_msg) => {
println!(" Supported message types:");
for type_name in &capability_msg.content.types {
println!(" - {}", type_name);
}
}
AnyMessage::Sensor(sensor_msg) => {
println!(" Sensor data: {} values", sensor_msg.content.data.len());
if !sensor_msg.content.data.is_empty() {
print!(" Values: ");
for (i, value) in sensor_msg.content.data.iter().enumerate() {
if i > 0 {
print!(", ");
}
print!("{:.3}", value);
if i >= 9 {
// Limit display to first 10 values
if sensor_msg.content.data.len() > 10 {
print!(
", ... ({} more)",
sensor_msg.content.data.len() - 10
);
}
break;
}
}
println!();
}
}
AnyMessage::Point(point_msg) => {
println!(" Point list: {} points", point_msg.content.points.len());
for (i, point) in point_msg.content.points.iter().enumerate() {
println!(
" Point {}: ({:.2}, {:.2}, {:.2}) - {}",
i,
point.position[0],
point.position[1],
point.position[2],
point.name
);
}
}
AnyMessage::Unknown { header: _, body } => {
println!(" ⚠️ Unknown message type!");
println!(" Raw body size: {} bytes", body.len());
println!(
" This might be a custom message type not yet supported by this library."
);
}
_ => {
println!(" (No detailed handler for this message type)");
}
}
println!("{}", "=".repeat(60));
}
Err(e) => {
eprintln!("Error receiving message: {}", e);
break;
}
}
}
println!("\nReceived {} messages total.", message_count);
Ok(())
}
/// Format a message for display
fn format_message(msg: &AnyMessage) -> Result<String, Box<dyn std::error::Error>> {
let msg_type = msg.message_type();
let device_name = msg.device_name()?;
Ok(format!("{} from '{}'", msg_type, device_name))
}