1#[cfg(target_os = "linux")]
4use super::ble::DefaultBleTransport;
5#[cfg(any(target_os = "linux", target_os = "macos"))]
6use super::ethernet::EthernetTransport;
7use super::nostr_relay::NostrRelayTransport;
8#[cfg(feature = "sim-transport")]
9use super::sim::SimTransport;
10use super::tcp::TcpTransport;
11use super::tor::TorTransport;
12use super::tor::control::TorMonitoringInfo;
13use super::udp::UdpTransport;
14#[cfg(feature = "webrtc-transport")]
15use super::webrtc::WebRtcTransport;
16use super::{
17 ConnectionState, DiscoveredPeer, Transport, TransportAddr, TransportCongestion, TransportError,
18 TransportId, TransportState, TransportType,
19};
20
21pub enum TransportHandle {
26 Udp(UdpTransport),
28 NostrRelay(Box<NostrRelayTransport>),
30 #[cfg(feature = "sim-transport")]
32 Sim(SimTransport),
33 #[cfg(any(target_os = "linux", target_os = "macos"))]
35 Ethernet(EthernetTransport),
36 Tcp(TcpTransport),
38 Tor(TorTransport),
40 #[cfg(feature = "webrtc-transport")]
42 WebRtc(Box<WebRtcTransport>),
43 #[cfg(target_os = "linux")]
45 Ble(DefaultBleTransport),
46}
47
48impl TransportHandle {
49 pub(crate) fn canonical_addr(
53 &self,
54 addr: &TransportAddr,
55 ) -> Result<TransportAddr, TransportError> {
56 match self {
57 #[cfg(feature = "webrtc-transport")]
58 TransportHandle::WebRtc(_) => super::webrtc::canonical_webrtc_addr(addr),
59 _ => Ok(addr.clone()),
60 }
61 }
62
63 #[cfg(feature = "webrtc-transport")]
66 pub(crate) fn drain_link_negotiations(
67 &mut self,
68 limit: usize,
69 ) -> Vec<super::link_negotiation::OutboundLinkNegotiation> {
70 match self {
71 TransportHandle::WebRtc(transport) => transport.drain_link_negotiations(limit),
72 _ => Vec::new(),
73 }
74 }
75
76 #[cfg(feature = "webrtc-transport")]
78 pub(crate) fn ingest_link_negotiation(
79 &self,
80 source: secp256k1::PublicKey,
81 message: super::link_negotiation::LinkNegotiationMessage,
82 ) -> Result<(), TransportError> {
83 match self {
84 TransportHandle::WebRtc(transport) if message.link_type == "webrtc" => {
85 transport.ingest_link_negotiation(source, message)
86 }
87 _ => Err(TransportError::NotSupported(
88 "no enabled adapter accepts this link negotiation".into(),
89 )),
90 }
91 }
92
93 pub async fn start(&mut self) -> Result<(), TransportError> {
95 match self {
96 TransportHandle::Udp(t) => t.start_async().await,
97 TransportHandle::NostrRelay(t) => t.start(),
98 #[cfg(feature = "sim-transport")]
99 TransportHandle::Sim(t) => t.start_async().await,
100 #[cfg(any(target_os = "linux", target_os = "macos"))]
101 TransportHandle::Ethernet(t) => t.start_async().await,
102 TransportHandle::Tcp(t) => t.start_async().await,
103 TransportHandle::Tor(t) => t.start_async().await,
104 #[cfg(feature = "webrtc-transport")]
105 TransportHandle::WebRtc(t) => t.start_async().await,
106 #[cfg(target_os = "linux")]
107 TransportHandle::Ble(t) => t.start_async().await,
108 }
109 }
110
111 pub async fn stop(&mut self) -> Result<(), TransportError> {
113 match self {
114 TransportHandle::Udp(t) => t.stop_async().await,
115 TransportHandle::NostrRelay(t) => t.stop(),
116 #[cfg(feature = "sim-transport")]
117 TransportHandle::Sim(t) => t.stop_async().await,
118 #[cfg(any(target_os = "linux", target_os = "macos"))]
119 TransportHandle::Ethernet(t) => t.stop_async().await,
120 TransportHandle::Tcp(t) => t.stop_async().await,
121 TransportHandle::Tor(t) => t.stop_async().await,
122 #[cfg(feature = "webrtc-transport")]
123 TransportHandle::WebRtc(t) => t.stop_async().await,
124 #[cfg(target_os = "linux")]
125 TransportHandle::Ble(t) => t.stop_async().await,
126 }
127 }
128
129 pub async fn send(&self, addr: &TransportAddr, data: &[u8]) -> Result<usize, TransportError> {
131 match self {
132 TransportHandle::Udp(t) => t.send_async(addr, data).await,
133 TransportHandle::NostrRelay(t) => t.send(addr, data).map(|()| data.len()),
134 #[cfg(feature = "sim-transport")]
135 TransportHandle::Sim(t) => t.send_async(addr, data).await,
136 #[cfg(any(target_os = "linux", target_os = "macos"))]
137 TransportHandle::Ethernet(t) => t.send_async(addr, data).await,
138 TransportHandle::Tcp(t) => t.send_async(addr, data).await,
139 TransportHandle::Tor(t) => t.send_async(addr, data).await,
140 #[cfg(feature = "webrtc-transport")]
141 TransportHandle::WebRtc(t) => Box::pin(t.send_async(addr, data)).await,
143 #[cfg(target_os = "linux")]
144 TransportHandle::Ble(t) => t.send_async(addr, data).await,
145 }
146 }
147
148 pub(crate) async fn send_with_timeout(
149 &self,
150 addr: &TransportAddr,
151 data: &[u8],
152 timeout: std::time::Duration,
153 ) -> Result<usize, TransportError> {
154 match self {
155 TransportHandle::Tcp(transport) => {
156 transport.send_async_with_timeout(addr, data, timeout).await
157 }
158 _ => self.send(addr, data).await,
159 }
160 }
161
162 pub fn transport_id(&self) -> TransportId {
164 match self {
165 TransportHandle::Udp(t) => t.transport_id(),
166 TransportHandle::NostrRelay(t) => t.transport_id(),
167 #[cfg(feature = "sim-transport")]
168 TransportHandle::Sim(t) => t.transport_id(),
169 #[cfg(any(target_os = "linux", target_os = "macos"))]
170 TransportHandle::Ethernet(t) => t.transport_id(),
171 TransportHandle::Tcp(t) => t.transport_id(),
172 TransportHandle::Tor(t) => t.transport_id(),
173 #[cfg(feature = "webrtc-transport")]
174 TransportHandle::WebRtc(t) => t.transport_id(),
175 #[cfg(target_os = "linux")]
176 TransportHandle::Ble(t) => t.transport_id(),
177 }
178 }
179
180 pub(crate) fn uses_fips_byte_stream_framing(&self) -> bool {
182 matches!(self, TransportHandle::Tcp(_) | TransportHandle::Tor(_))
183 }
184
185 pub fn name(&self) -> Option<&str> {
187 match self {
188 TransportHandle::Udp(t) => t.name(),
189 TransportHandle::NostrRelay(t) => t.name(),
190 #[cfg(feature = "sim-transport")]
191 TransportHandle::Sim(t) => t.name(),
192 #[cfg(any(target_os = "linux", target_os = "macos"))]
193 TransportHandle::Ethernet(t) => t.name(),
194 TransportHandle::Tcp(t) => t.name(),
195 TransportHandle::Tor(t) => t.name(),
196 #[cfg(feature = "webrtc-transport")]
197 TransportHandle::WebRtc(t) => t.name(),
198 #[cfg(target_os = "linux")]
199 TransportHandle::Ble(t) => t.name(),
200 }
201 }
202
203 pub fn transport_type(&self) -> &TransportType {
205 match self {
206 TransportHandle::Udp(t) => t.transport_type(),
207 TransportHandle::NostrRelay(t) => t.transport_type(),
208 #[cfg(feature = "sim-transport")]
209 TransportHandle::Sim(t) => t.transport_type(),
210 #[cfg(any(target_os = "linux", target_os = "macos"))]
211 TransportHandle::Ethernet(t) => t.transport_type(),
212 TransportHandle::Tcp(t) => t.transport_type(),
213 TransportHandle::Tor(t) => t.transport_type(),
214 #[cfg(feature = "webrtc-transport")]
215 TransportHandle::WebRtc(t) => t.transport_type(),
216 #[cfg(target_os = "linux")]
217 TransportHandle::Ble(t) => t.transport_type(),
218 }
219 }
220
221 pub fn state(&self) -> TransportState {
223 match self {
224 TransportHandle::Udp(t) => t.state(),
225 TransportHandle::NostrRelay(t) => t.state(),
226 #[cfg(feature = "sim-transport")]
227 TransportHandle::Sim(t) => t.state(),
228 #[cfg(any(target_os = "linux", target_os = "macos"))]
229 TransportHandle::Ethernet(t) => t.state(),
230 TransportHandle::Tcp(t) => t.state(),
231 TransportHandle::Tor(t) => t.state(),
232 #[cfg(feature = "webrtc-transport")]
233 TransportHandle::WebRtc(t) => t.state(),
234 #[cfg(target_os = "linux")]
235 TransportHandle::Ble(t) => t.state(),
236 }
237 }
238
239 pub fn mtu(&self) -> u16 {
241 match self {
242 TransportHandle::Udp(t) => t.mtu(),
243 TransportHandle::NostrRelay(t) => t.mtu(),
244 #[cfg(feature = "sim-transport")]
245 TransportHandle::Sim(t) => t.mtu(),
246 #[cfg(any(target_os = "linux", target_os = "macos"))]
247 TransportHandle::Ethernet(t) => t.mtu(),
248 TransportHandle::Tcp(t) => t.mtu(),
249 TransportHandle::Tor(t) => t.mtu(),
250 #[cfg(feature = "webrtc-transport")]
251 TransportHandle::WebRtc(t) => t.mtu(),
252 #[cfg(target_os = "linux")]
253 TransportHandle::Ble(t) => t.mtu(),
254 }
255 }
256
257 pub fn link_mtu(&self, addr: &TransportAddr) -> u16 {
262 match self {
263 TransportHandle::Udp(t) => t.link_mtu(addr),
264 TransportHandle::NostrRelay(t) => t.link_mtu(addr),
265 #[cfg(feature = "sim-transport")]
266 TransportHandle::Sim(t) => t.link_mtu(addr),
267 #[cfg(any(target_os = "linux", target_os = "macos"))]
268 TransportHandle::Ethernet(t) => t.link_mtu(addr),
269 TransportHandle::Tcp(t) => t.link_mtu(addr),
270 TransportHandle::Tor(t) => t.link_mtu(addr),
271 #[cfg(feature = "webrtc-transport")]
272 TransportHandle::WebRtc(t) => t.link_mtu(addr),
273 #[cfg(target_os = "linux")]
274 TransportHandle::Ble(t) => t.link_mtu(addr),
275 }
276 }
277
278 pub fn local_addr(&self) -> Option<std::net::SocketAddr> {
280 match self {
281 TransportHandle::Udp(t) => t.local_addr(),
282 TransportHandle::NostrRelay(_) => None,
283 #[cfg(feature = "sim-transport")]
284 TransportHandle::Sim(_) => None,
285 #[cfg(any(target_os = "linux", target_os = "macos"))]
286 TransportHandle::Ethernet(_) => None,
287 TransportHandle::Tcp(t) => t.local_addr(),
288 TransportHandle::Tor(_) => None,
289 #[cfg(feature = "webrtc-transport")]
290 TransportHandle::WebRtc(_) => None,
291 #[cfg(target_os = "linux")]
292 TransportHandle::Ble(_) => None,
293 }
294 }
295
296 pub(crate) fn resolved_udp_socket_addr_if_cached(
301 &self,
302 addr: &TransportAddr,
303 ) -> Option<std::net::SocketAddr> {
304 match self {
305 TransportHandle::Udp(t) => t.resolved_socket_addr_if_cached(addr),
306 _ => None,
307 }
308 }
309
310 pub fn interface_name(&self) -> Option<&str> {
312 match self {
313 TransportHandle::Udp(_) => None,
314 TransportHandle::NostrRelay(_) => None,
315 #[cfg(feature = "sim-transport")]
316 TransportHandle::Sim(_) => None,
317 #[cfg(any(target_os = "linux", target_os = "macos"))]
318 TransportHandle::Ethernet(t) => Some(t.interface_name()),
319 TransportHandle::Tcp(_) => None,
320 TransportHandle::Tor(_) => None,
321 #[cfg(feature = "webrtc-transport")]
322 TransportHandle::WebRtc(_) => None,
323 #[cfg(target_os = "linux")]
324 TransportHandle::Ble(_) => None,
325 }
326 }
327
328 pub fn onion_address(&self) -> Option<&str> {
330 match self {
331 TransportHandle::Tor(t) => t.onion_address(),
332 _ => None,
333 }
334 }
335
336 pub fn tor_monitoring(&self) -> Option<TorMonitoringInfo> {
338 match self {
339 TransportHandle::Tor(t) => t.cached_monitoring(),
340 _ => None,
341 }
342 }
343
344 pub fn tor_mode(&self) -> Option<&str> {
346 match self {
347 TransportHandle::Tor(t) => Some(t.mode()),
348 _ => None,
349 }
350 }
351
352 pub fn discover(&self) -> Result<Vec<DiscoveredPeer>, TransportError> {
354 match self {
355 TransportHandle::Udp(t) => t.discover(),
356 TransportHandle::NostrRelay(t) => t.discover(),
357 #[cfg(feature = "sim-transport")]
358 TransportHandle::Sim(t) => t.discover(),
359 #[cfg(any(target_os = "linux", target_os = "macos"))]
360 TransportHandle::Ethernet(t) => t.discover(),
361 TransportHandle::Tcp(t) => t.discover(),
362 TransportHandle::Tor(t) => t.discover(),
363 #[cfg(feature = "webrtc-transport")]
364 TransportHandle::WebRtc(t) => t.discover(),
365 #[cfg(target_os = "linux")]
366 TransportHandle::Ble(t) => t.discover(),
367 }
368 }
369
370 pub fn auto_connect(&self) -> bool {
372 match self {
373 TransportHandle::Udp(t) => t.auto_connect(),
374 TransportHandle::NostrRelay(t) => t.auto_connect(),
375 #[cfg(feature = "sim-transport")]
376 TransportHandle::Sim(t) => t.auto_connect(),
377 #[cfg(any(target_os = "linux", target_os = "macos"))]
378 TransportHandle::Ethernet(t) => t.auto_connect(),
379 TransportHandle::Tcp(t) => t.auto_connect(),
380 TransportHandle::Tor(t) => t.auto_connect(),
381 #[cfg(feature = "webrtc-transport")]
382 TransportHandle::WebRtc(t) => t.auto_connect(),
383 #[cfg(target_os = "linux")]
384 TransportHandle::Ble(t) => t.auto_connect(),
385 }
386 }
387
388 pub fn accept_connections(&self) -> bool {
390 match self {
391 TransportHandle::Udp(t) => t.accept_connections(),
392 TransportHandle::NostrRelay(t) => t.accept_connections(),
393 #[cfg(feature = "sim-transport")]
394 TransportHandle::Sim(t) => t.accept_connections(),
395 #[cfg(any(target_os = "linux", target_os = "macos"))]
396 TransportHandle::Ethernet(t) => t.accept_connections(),
397 TransportHandle::Tcp(t) => t.accept_connections(),
398 TransportHandle::Tor(t) => t.accept_connections(),
399 #[cfg(feature = "webrtc-transport")]
400 TransportHandle::WebRtc(t) => t.accept_connections(),
401 #[cfg(target_os = "linux")]
402 TransportHandle::Ble(t) => t.accept_connections(),
403 }
404 }
405
406 pub async fn connect(&self, addr: &TransportAddr) -> Result<(), TransportError> {
414 match self {
415 TransportHandle::Udp(_) => Ok(()), TransportHandle::NostrRelay(_) => Ok(()), #[cfg(feature = "sim-transport")]
418 TransportHandle::Sim(_) => Ok(()), #[cfg(any(target_os = "linux", target_os = "macos"))]
420 TransportHandle::Ethernet(_) => Ok(()), TransportHandle::Tcp(t) => t.connect_async(addr).await,
422 TransportHandle::Tor(t) => t.connect_async(addr).await,
423 #[cfg(feature = "webrtc-transport")]
424 TransportHandle::WebRtc(t) => t.connect_async(addr).await,
425 #[cfg(target_os = "linux")]
426 TransportHandle::Ble(t) => t.connect_async(addr).await,
427 }
428 }
429
430 pub fn connection_state(&self, addr: &TransportAddr) -> ConnectionState {
436 match self {
437 TransportHandle::Udp(_) => ConnectionState::Connected,
438 TransportHandle::NostrRelay(_) => ConnectionState::Connected,
439 #[cfg(feature = "sim-transport")]
440 TransportHandle::Sim(_) => ConnectionState::Connected,
441 #[cfg(any(target_os = "linux", target_os = "macos"))]
442 TransportHandle::Ethernet(_) => ConnectionState::Connected,
443 TransportHandle::Tcp(t) => t.connection_state_sync(addr),
444 TransportHandle::Tor(t) => t.connection_state_sync(addr),
445 #[cfg(feature = "webrtc-transport")]
446 TransportHandle::WebRtc(t) => t.connection_state_sync(addr),
447 #[cfg(target_os = "linux")]
448 TransportHandle::Ble(t) => t.connection_state_sync(addr),
449 }
450 }
451
452 pub async fn close_connection(&self, addr: &TransportAddr) {
457 match self {
458 TransportHandle::Udp(t) => t.close_connection(addr),
459 TransportHandle::NostrRelay(t) => t.close_connection(addr),
460 #[cfg(feature = "sim-transport")]
461 TransportHandle::Sim(t) => t.close_connection(addr),
462 #[cfg(any(target_os = "linux", target_os = "macos"))]
463 TransportHandle::Ethernet(t) => t.close_connection(addr),
464 TransportHandle::Tcp(t) => t.close_connection_async(addr).await,
465 TransportHandle::Tor(t) => t.close_connection_async(addr).await,
466 #[cfg(feature = "webrtc-transport")]
467 TransportHandle::WebRtc(t) => t.close_connection_async(addr).await,
468 #[cfg(target_os = "linux")]
469 TransportHandle::Ble(t) => t.close_connection_async(addr).await,
470 }
471 }
472
473 pub fn close_connection_detached(&self, _addr: &TransportAddr) {
475 #[cfg(feature = "webrtc-transport")]
476 if let TransportHandle::WebRtc(transport) = self {
477 transport.close_connection_detached(_addr);
478 }
479 }
480
481 pub fn is_operational(&self) -> bool {
483 self.state().is_operational()
484 }
485
486 pub fn congestion(&self) -> TransportCongestion {
492 match self {
493 TransportHandle::Udp(t) => t.congestion(),
494 TransportHandle::NostrRelay(_) => TransportCongestion::default(),
495 #[cfg(feature = "sim-transport")]
496 TransportHandle::Sim(_) => TransportCongestion::default(),
497 #[cfg(any(target_os = "linux", target_os = "macos"))]
498 TransportHandle::Ethernet(_) => TransportCongestion::default(),
499 TransportHandle::Tcp(_) => TransportCongestion::default(),
500 TransportHandle::Tor(_) => TransportCongestion::default(),
501 #[cfg(feature = "webrtc-transport")]
502 TransportHandle::WebRtc(_) => TransportCongestion::default(),
503 #[cfg(target_os = "linux")]
504 TransportHandle::Ble(_) => TransportCongestion::default(),
505 }
506 }
507
508 pub fn transport_stats(&self) -> serde_json::Value {
512 match self {
513 TransportHandle::Udp(t) => {
514 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
515 }
516 TransportHandle::NostrRelay(t) => serde_json::json!({
517 "mtu": t.mtu(),
518 "state": t.state().to_string(),
519 }),
520 #[cfg(feature = "sim-transport")]
521 TransportHandle::Sim(t) => serde_json::to_value(t.stats()).unwrap_or_default(),
522 #[cfg(any(target_os = "linux", target_os = "macos"))]
523 TransportHandle::Ethernet(t) => {
524 let snap = t.stats().snapshot();
525 serde_json::json!({
526 "frames_sent": snap.frames_sent,
527 "frames_recv": snap.frames_recv,
528 "bytes_sent": snap.bytes_sent,
529 "bytes_recv": snap.bytes_recv,
530 "send_errors": snap.send_errors,
531 "recv_errors": snap.recv_errors,
532 "beacons_sent": snap.beacons_sent,
533 "beacons_recv": snap.beacons_recv,
534 "frames_too_short": snap.frames_too_short,
535 "frames_too_long": snap.frames_too_long,
536 })
537 }
538 TransportHandle::Tcp(t) => {
539 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
540 }
541 TransportHandle::Tor(t) => {
542 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
543 }
544 #[cfg(feature = "webrtc-transport")]
545 TransportHandle::WebRtc(t) => serde_json::json!({
546 "mtu": t.mtu(),
547 "state": t.state().to_string(),
548 }),
549 #[cfg(target_os = "linux")]
550 TransportHandle::Ble(t) => {
551 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
552 }
553 }
554 }
555}