1#[cfg(target_os = "linux")]
4use super::ble::DefaultBleTransport;
5#[cfg(any(target_os = "linux", target_os = "macos"))]
6use super::ethernet::EthernetTransport;
7#[cfg(feature = "sim-transport")]
8use super::sim::SimTransport;
9use super::tcp::TcpTransport;
10use super::tor::TorTransport;
11use super::tor::control::TorMonitoringInfo;
12use super::udp::UdpTransport;
13#[cfg(feature = "webrtc-transport")]
14use super::webrtc::WebRtcTransport;
15use super::{
16 ConnectionState, DiscoveredPeer, Transport, TransportAddr, TransportCongestion, TransportError,
17 TransportId, TransportState, TransportType,
18};
19
20const TCP_SEND_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(500);
21
22pub enum TransportHandle {
27 Udp(UdpTransport),
29 #[cfg(feature = "sim-transport")]
31 Sim(SimTransport),
32 #[cfg(any(target_os = "linux", target_os = "macos"))]
34 Ethernet(EthernetTransport),
35 Tcp(TcpTransport),
37 Tor(TorTransport),
39 #[cfg(feature = "webrtc-transport")]
41 WebRtc(Box<WebRtcTransport>),
42 #[cfg(target_os = "linux")]
44 Ble(DefaultBleTransport),
45}
46
47impl TransportHandle {
48 pub async fn start(&mut self) -> Result<(), TransportError> {
50 match self {
51 TransportHandle::Udp(t) => t.start_async().await,
52 #[cfg(feature = "sim-transport")]
53 TransportHandle::Sim(t) => t.start_async().await,
54 #[cfg(any(target_os = "linux", target_os = "macos"))]
55 TransportHandle::Ethernet(t) => t.start_async().await,
56 TransportHandle::Tcp(t) => t.start_async().await,
57 TransportHandle::Tor(t) => t.start_async().await,
58 #[cfg(feature = "webrtc-transport")]
59 TransportHandle::WebRtc(t) => t.start_async().await,
60 #[cfg(target_os = "linux")]
61 TransportHandle::Ble(t) => t.start_async().await,
62 }
63 }
64
65 pub async fn stop(&mut self) -> Result<(), TransportError> {
67 match self {
68 TransportHandle::Udp(t) => t.stop_async().await,
69 #[cfg(feature = "sim-transport")]
70 TransportHandle::Sim(t) => t.stop_async().await,
71 #[cfg(any(target_os = "linux", target_os = "macos"))]
72 TransportHandle::Ethernet(t) => t.stop_async().await,
73 TransportHandle::Tcp(t) => t.stop_async().await,
74 TransportHandle::Tor(t) => t.stop_async().await,
75 #[cfg(feature = "webrtc-transport")]
76 TransportHandle::WebRtc(t) => t.stop_async().await,
77 #[cfg(target_os = "linux")]
78 TransportHandle::Ble(t) => t.stop_async().await,
79 }
80 }
81
82 pub async fn send(&self, addr: &TransportAddr, data: &[u8]) -> Result<usize, TransportError> {
84 match self {
85 TransportHandle::Udp(t) => t.send_async(addr, data).await,
86 #[cfg(feature = "sim-transport")]
87 TransportHandle::Sim(t) => t.send_async(addr, data).await,
88 #[cfg(any(target_os = "linux", target_os = "macos"))]
89 TransportHandle::Ethernet(t) => t.send_async(addr, data).await,
90 TransportHandle::Tcp(t) => {
91 tokio::time::timeout(TCP_SEND_TIMEOUT, t.send_async(addr, data))
92 .await
93 .unwrap_or(Err(TransportError::Timeout))
94 }
95 TransportHandle::Tor(t) => t.send_async(addr, data).await,
96 #[cfg(feature = "webrtc-transport")]
97 TransportHandle::WebRtc(t) => t.send_async(addr, data).await,
98 #[cfg(target_os = "linux")]
99 TransportHandle::Ble(t) => t.send_async(addr, data).await,
100 }
101 }
102
103 pub fn transport_id(&self) -> TransportId {
105 match self {
106 TransportHandle::Udp(t) => t.transport_id(),
107 #[cfg(feature = "sim-transport")]
108 TransportHandle::Sim(t) => t.transport_id(),
109 #[cfg(any(target_os = "linux", target_os = "macos"))]
110 TransportHandle::Ethernet(t) => t.transport_id(),
111 TransportHandle::Tcp(t) => t.transport_id(),
112 TransportHandle::Tor(t) => t.transport_id(),
113 #[cfg(feature = "webrtc-transport")]
114 TransportHandle::WebRtc(t) => t.transport_id(),
115 #[cfg(target_os = "linux")]
116 TransportHandle::Ble(t) => t.transport_id(),
117 }
118 }
119
120 pub fn name(&self) -> Option<&str> {
122 match self {
123 TransportHandle::Udp(t) => t.name(),
124 #[cfg(feature = "sim-transport")]
125 TransportHandle::Sim(t) => t.name(),
126 #[cfg(any(target_os = "linux", target_os = "macos"))]
127 TransportHandle::Ethernet(t) => t.name(),
128 TransportHandle::Tcp(t) => t.name(),
129 TransportHandle::Tor(t) => t.name(),
130 #[cfg(feature = "webrtc-transport")]
131 TransportHandle::WebRtc(t) => t.name(),
132 #[cfg(target_os = "linux")]
133 TransportHandle::Ble(t) => t.name(),
134 }
135 }
136
137 pub fn transport_type(&self) -> &TransportType {
139 match self {
140 TransportHandle::Udp(t) => t.transport_type(),
141 #[cfg(feature = "sim-transport")]
142 TransportHandle::Sim(t) => t.transport_type(),
143 #[cfg(any(target_os = "linux", target_os = "macos"))]
144 TransportHandle::Ethernet(t) => t.transport_type(),
145 TransportHandle::Tcp(t) => t.transport_type(),
146 TransportHandle::Tor(t) => t.transport_type(),
147 #[cfg(feature = "webrtc-transport")]
148 TransportHandle::WebRtc(t) => t.transport_type(),
149 #[cfg(target_os = "linux")]
150 TransportHandle::Ble(t) => t.transport_type(),
151 }
152 }
153
154 pub fn state(&self) -> TransportState {
156 match self {
157 TransportHandle::Udp(t) => t.state(),
158 #[cfg(feature = "sim-transport")]
159 TransportHandle::Sim(t) => t.state(),
160 #[cfg(any(target_os = "linux", target_os = "macos"))]
161 TransportHandle::Ethernet(t) => t.state(),
162 TransportHandle::Tcp(t) => t.state(),
163 TransportHandle::Tor(t) => t.state(),
164 #[cfg(feature = "webrtc-transport")]
165 TransportHandle::WebRtc(t) => t.state(),
166 #[cfg(target_os = "linux")]
167 TransportHandle::Ble(t) => t.state(),
168 }
169 }
170
171 pub fn mtu(&self) -> u16 {
173 match self {
174 TransportHandle::Udp(t) => t.mtu(),
175 #[cfg(feature = "sim-transport")]
176 TransportHandle::Sim(t) => t.mtu(),
177 #[cfg(any(target_os = "linux", target_os = "macos"))]
178 TransportHandle::Ethernet(t) => t.mtu(),
179 TransportHandle::Tcp(t) => t.mtu(),
180 TransportHandle::Tor(t) => t.mtu(),
181 #[cfg(feature = "webrtc-transport")]
182 TransportHandle::WebRtc(t) => t.mtu(),
183 #[cfg(target_os = "linux")]
184 TransportHandle::Ble(t) => t.mtu(),
185 }
186 }
187
188 pub fn link_mtu(&self, addr: &TransportAddr) -> u16 {
193 match self {
194 TransportHandle::Udp(t) => t.link_mtu(addr),
195 #[cfg(feature = "sim-transport")]
196 TransportHandle::Sim(t) => t.link_mtu(addr),
197 #[cfg(any(target_os = "linux", target_os = "macos"))]
198 TransportHandle::Ethernet(t) => t.link_mtu(addr),
199 TransportHandle::Tcp(t) => t.link_mtu(addr),
200 TransportHandle::Tor(t) => t.link_mtu(addr),
201 #[cfg(feature = "webrtc-transport")]
202 TransportHandle::WebRtc(t) => t.link_mtu(addr),
203 #[cfg(target_os = "linux")]
204 TransportHandle::Ble(t) => t.link_mtu(addr),
205 }
206 }
207
208 pub fn local_addr(&self) -> Option<std::net::SocketAddr> {
210 match self {
211 TransportHandle::Udp(t) => t.local_addr(),
212 #[cfg(feature = "sim-transport")]
213 TransportHandle::Sim(_) => None,
214 #[cfg(any(target_os = "linux", target_os = "macos"))]
215 TransportHandle::Ethernet(_) => None,
216 TransportHandle::Tcp(t) => t.local_addr(),
217 TransportHandle::Tor(_) => None,
218 #[cfg(feature = "webrtc-transport")]
219 TransportHandle::WebRtc(_) => None,
220 #[cfg(target_os = "linux")]
221 TransportHandle::Ble(_) => None,
222 }
223 }
224
225 pub(crate) fn resolved_udp_socket_addr_if_cached(
230 &self,
231 addr: &TransportAddr,
232 ) -> Option<std::net::SocketAddr> {
233 match self {
234 TransportHandle::Udp(t) => t.resolved_socket_addr_if_cached(addr),
235 _ => None,
236 }
237 }
238
239 pub fn interface_name(&self) -> Option<&str> {
241 match self {
242 TransportHandle::Udp(_) => None,
243 #[cfg(feature = "sim-transport")]
244 TransportHandle::Sim(_) => None,
245 #[cfg(any(target_os = "linux", target_os = "macos"))]
246 TransportHandle::Ethernet(t) => Some(t.interface_name()),
247 TransportHandle::Tcp(_) => None,
248 TransportHandle::Tor(_) => None,
249 #[cfg(feature = "webrtc-transport")]
250 TransportHandle::WebRtc(_) => None,
251 #[cfg(target_os = "linux")]
252 TransportHandle::Ble(_) => None,
253 }
254 }
255
256 pub fn onion_address(&self) -> Option<&str> {
258 match self {
259 TransportHandle::Tor(t) => t.onion_address(),
260 _ => None,
261 }
262 }
263
264 pub fn tor_monitoring(&self) -> Option<TorMonitoringInfo> {
266 match self {
267 TransportHandle::Tor(t) => t.cached_monitoring(),
268 _ => None,
269 }
270 }
271
272 pub fn tor_mode(&self) -> Option<&str> {
274 match self {
275 TransportHandle::Tor(t) => Some(t.mode()),
276 _ => None,
277 }
278 }
279
280 pub fn discover(&self) -> Result<Vec<DiscoveredPeer>, TransportError> {
282 match self {
283 TransportHandle::Udp(t) => t.discover(),
284 #[cfg(feature = "sim-transport")]
285 TransportHandle::Sim(t) => t.discover(),
286 #[cfg(any(target_os = "linux", target_os = "macos"))]
287 TransportHandle::Ethernet(t) => t.discover(),
288 TransportHandle::Tcp(t) => t.discover(),
289 TransportHandle::Tor(t) => t.discover(),
290 #[cfg(feature = "webrtc-transport")]
291 TransportHandle::WebRtc(t) => t.discover(),
292 #[cfg(target_os = "linux")]
293 TransportHandle::Ble(t) => t.discover(),
294 }
295 }
296
297 pub fn auto_connect(&self) -> bool {
299 match self {
300 TransportHandle::Udp(t) => t.auto_connect(),
301 #[cfg(feature = "sim-transport")]
302 TransportHandle::Sim(t) => t.auto_connect(),
303 #[cfg(any(target_os = "linux", target_os = "macos"))]
304 TransportHandle::Ethernet(t) => t.auto_connect(),
305 TransportHandle::Tcp(t) => t.auto_connect(),
306 TransportHandle::Tor(t) => t.auto_connect(),
307 #[cfg(feature = "webrtc-transport")]
308 TransportHandle::WebRtc(t) => t.auto_connect(),
309 #[cfg(target_os = "linux")]
310 TransportHandle::Ble(t) => t.auto_connect(),
311 }
312 }
313
314 pub fn accept_connections(&self) -> bool {
316 match self {
317 TransportHandle::Udp(t) => t.accept_connections(),
318 #[cfg(feature = "sim-transport")]
319 TransportHandle::Sim(t) => t.accept_connections(),
320 #[cfg(any(target_os = "linux", target_os = "macos"))]
321 TransportHandle::Ethernet(t) => t.accept_connections(),
322 TransportHandle::Tcp(t) => t.accept_connections(),
323 TransportHandle::Tor(t) => t.accept_connections(),
324 #[cfg(feature = "webrtc-transport")]
325 TransportHandle::WebRtc(t) => t.accept_connections(),
326 #[cfg(target_os = "linux")]
327 TransportHandle::Ble(t) => t.accept_connections(),
328 }
329 }
330
331 pub async fn connect(&self, addr: &TransportAddr) -> Result<(), TransportError> {
339 match self {
340 TransportHandle::Udp(_) => Ok(()), #[cfg(feature = "sim-transport")]
342 TransportHandle::Sim(_) => Ok(()), #[cfg(any(target_os = "linux", target_os = "macos"))]
344 TransportHandle::Ethernet(_) => Ok(()), TransportHandle::Tcp(t) => t.connect_async(addr).await,
346 TransportHandle::Tor(t) => t.connect_async(addr).await,
347 #[cfg(feature = "webrtc-transport")]
348 TransportHandle::WebRtc(t) => t.connect_async(addr).await,
349 #[cfg(target_os = "linux")]
350 TransportHandle::Ble(t) => t.connect_async(addr).await,
351 }
352 }
353
354 pub fn connection_state(&self, addr: &TransportAddr) -> ConnectionState {
360 match self {
361 TransportHandle::Udp(_) => ConnectionState::Connected,
362 #[cfg(feature = "sim-transport")]
363 TransportHandle::Sim(_) => ConnectionState::Connected,
364 #[cfg(any(target_os = "linux", target_os = "macos"))]
365 TransportHandle::Ethernet(_) => ConnectionState::Connected,
366 TransportHandle::Tcp(t) => t.connection_state_sync(addr),
367 TransportHandle::Tor(t) => t.connection_state_sync(addr),
368 #[cfg(feature = "webrtc-transport")]
369 TransportHandle::WebRtc(t) => t.connection_state_sync(addr),
370 #[cfg(target_os = "linux")]
371 TransportHandle::Ble(t) => t.connection_state_sync(addr),
372 }
373 }
374
375 pub async fn close_connection(&self, addr: &TransportAddr) {
380 match self {
381 TransportHandle::Udp(t) => t.close_connection(addr),
382 #[cfg(feature = "sim-transport")]
383 TransportHandle::Sim(t) => t.close_connection(addr),
384 #[cfg(any(target_os = "linux", target_os = "macos"))]
385 TransportHandle::Ethernet(t) => t.close_connection(addr),
386 TransportHandle::Tcp(t) => t.close_connection_async(addr).await,
387 TransportHandle::Tor(t) => t.close_connection_async(addr).await,
388 #[cfg(feature = "webrtc-transport")]
389 TransportHandle::WebRtc(t) => t.close_connection_async(addr).await,
390 #[cfg(target_os = "linux")]
391 TransportHandle::Ble(t) => t.close_connection_async(addr).await,
392 }
393 }
394
395 pub fn is_operational(&self) -> bool {
397 self.state().is_operational()
398 }
399
400 pub fn congestion(&self) -> TransportCongestion {
406 match self {
407 TransportHandle::Udp(t) => t.congestion(),
408 #[cfg(feature = "sim-transport")]
409 TransportHandle::Sim(_) => TransportCongestion::default(),
410 #[cfg(any(target_os = "linux", target_os = "macos"))]
411 TransportHandle::Ethernet(_) => TransportCongestion::default(),
412 TransportHandle::Tcp(_) => TransportCongestion::default(),
413 TransportHandle::Tor(_) => TransportCongestion::default(),
414 #[cfg(feature = "webrtc-transport")]
415 TransportHandle::WebRtc(_) => TransportCongestion::default(),
416 #[cfg(target_os = "linux")]
417 TransportHandle::Ble(_) => TransportCongestion::default(),
418 }
419 }
420
421 pub fn transport_stats(&self) -> serde_json::Value {
425 match self {
426 TransportHandle::Udp(t) => {
427 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
428 }
429 #[cfg(feature = "sim-transport")]
430 TransportHandle::Sim(t) => serde_json::to_value(t.stats()).unwrap_or_default(),
431 #[cfg(any(target_os = "linux", target_os = "macos"))]
432 TransportHandle::Ethernet(t) => {
433 let snap = t.stats().snapshot();
434 serde_json::json!({
435 "frames_sent": snap.frames_sent,
436 "frames_recv": snap.frames_recv,
437 "bytes_sent": snap.bytes_sent,
438 "bytes_recv": snap.bytes_recv,
439 "send_errors": snap.send_errors,
440 "recv_errors": snap.recv_errors,
441 "beacons_sent": snap.beacons_sent,
442 "beacons_recv": snap.beacons_recv,
443 "frames_too_short": snap.frames_too_short,
444 "frames_too_long": snap.frames_too_long,
445 })
446 }
447 TransportHandle::Tcp(t) => {
448 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
449 }
450 TransportHandle::Tor(t) => {
451 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
452 }
453 #[cfg(feature = "webrtc-transport")]
454 TransportHandle::WebRtc(t) => serde_json::json!({
455 "mtu": t.mtu(),
456 "state": t.state().to_string(),
457 }),
458 #[cfg(target_os = "linux")]
459 TransportHandle::Ble(t) => {
460 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
461 }
462 }
463 }
464}