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
21const TCP_SEND_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(500);
22
23pub enum TransportHandle {
28 Udp(UdpTransport),
30 NostrRelay(Box<NostrRelayTransport>),
32 #[cfg(feature = "sim-transport")]
34 Sim(SimTransport),
35 #[cfg(any(target_os = "linux", target_os = "macos"))]
37 Ethernet(EthernetTransport),
38 Tcp(TcpTransport),
40 Tor(TorTransport),
42 #[cfg(feature = "webrtc-transport")]
44 WebRtc(Box<WebRtcTransport>),
45 #[cfg(target_os = "linux")]
47 Ble(DefaultBleTransport),
48}
49
50impl TransportHandle {
51 pub(crate) fn canonical_addr(
55 &self,
56 addr: &TransportAddr,
57 ) -> Result<TransportAddr, TransportError> {
58 match self {
59 #[cfg(feature = "webrtc-transport")]
60 TransportHandle::WebRtc(_) => super::webrtc::canonical_webrtc_addr(addr),
61 _ => Ok(addr.clone()),
62 }
63 }
64
65 #[cfg(feature = "webrtc-transport")]
68 pub(crate) fn drain_link_negotiations(
69 &mut self,
70 limit: usize,
71 ) -> Vec<super::link_negotiation::OutboundLinkNegotiation> {
72 match self {
73 TransportHandle::WebRtc(transport) => transport.drain_link_negotiations(limit),
74 _ => Vec::new(),
75 }
76 }
77
78 #[cfg(feature = "webrtc-transport")]
80 pub(crate) fn ingest_link_negotiation(
81 &self,
82 source: secp256k1::PublicKey,
83 message: super::link_negotiation::LinkNegotiationMessage,
84 ) -> Result<(), TransportError> {
85 match self {
86 TransportHandle::WebRtc(transport) if message.link_type == "webrtc" => {
87 transport.ingest_link_negotiation(source, message)
88 }
89 _ => Err(TransportError::NotSupported(
90 "no enabled adapter accepts this link negotiation".into(),
91 )),
92 }
93 }
94
95 pub async fn start(&mut self) -> Result<(), TransportError> {
97 match self {
98 TransportHandle::Udp(t) => t.start_async().await,
99 TransportHandle::NostrRelay(t) => t.start(),
100 #[cfg(feature = "sim-transport")]
101 TransportHandle::Sim(t) => t.start_async().await,
102 #[cfg(any(target_os = "linux", target_os = "macos"))]
103 TransportHandle::Ethernet(t) => t.start_async().await,
104 TransportHandle::Tcp(t) => t.start_async().await,
105 TransportHandle::Tor(t) => t.start_async().await,
106 #[cfg(feature = "webrtc-transport")]
107 TransportHandle::WebRtc(t) => t.start_async().await,
108 #[cfg(target_os = "linux")]
109 TransportHandle::Ble(t) => t.start_async().await,
110 }
111 }
112
113 pub async fn stop(&mut self) -> Result<(), TransportError> {
115 match self {
116 TransportHandle::Udp(t) => t.stop_async().await,
117 TransportHandle::NostrRelay(t) => t.stop(),
118 #[cfg(feature = "sim-transport")]
119 TransportHandle::Sim(t) => t.stop_async().await,
120 #[cfg(any(target_os = "linux", target_os = "macos"))]
121 TransportHandle::Ethernet(t) => t.stop_async().await,
122 TransportHandle::Tcp(t) => t.stop_async().await,
123 TransportHandle::Tor(t) => t.stop_async().await,
124 #[cfg(feature = "webrtc-transport")]
125 TransportHandle::WebRtc(t) => t.stop_async().await,
126 #[cfg(target_os = "linux")]
127 TransportHandle::Ble(t) => t.stop_async().await,
128 }
129 }
130
131 pub async fn send(&self, addr: &TransportAddr, data: &[u8]) -> Result<usize, TransportError> {
133 match self {
134 TransportHandle::Udp(t) => t.send_async(addr, data).await,
135 TransportHandle::NostrRelay(t) => t.send(addr, data).map(|()| data.len()),
136 #[cfg(feature = "sim-transport")]
137 TransportHandle::Sim(t) => t.send_async(addr, data).await,
138 #[cfg(any(target_os = "linux", target_os = "macos"))]
139 TransportHandle::Ethernet(t) => t.send_async(addr, data).await,
140 TransportHandle::Tcp(t) => {
141 tokio::time::timeout(TCP_SEND_TIMEOUT, t.send_async(addr, data))
142 .await
143 .unwrap_or(Err(TransportError::Timeout))
144 }
145 TransportHandle::Tor(t) => t.send_async(addr, data).await,
146 #[cfg(feature = "webrtc-transport")]
147 TransportHandle::WebRtc(t) => Box::pin(t.send_async(addr, data)).await,
149 #[cfg(target_os = "linux")]
150 TransportHandle::Ble(t) => t.send_async(addr, data).await,
151 }
152 }
153
154 pub fn transport_id(&self) -> TransportId {
156 match self {
157 TransportHandle::Udp(t) => t.transport_id(),
158 TransportHandle::NostrRelay(t) => t.transport_id(),
159 #[cfg(feature = "sim-transport")]
160 TransportHandle::Sim(t) => t.transport_id(),
161 #[cfg(any(target_os = "linux", target_os = "macos"))]
162 TransportHandle::Ethernet(t) => t.transport_id(),
163 TransportHandle::Tcp(t) => t.transport_id(),
164 TransportHandle::Tor(t) => t.transport_id(),
165 #[cfg(feature = "webrtc-transport")]
166 TransportHandle::WebRtc(t) => t.transport_id(),
167 #[cfg(target_os = "linux")]
168 TransportHandle::Ble(t) => t.transport_id(),
169 }
170 }
171
172 pub fn name(&self) -> Option<&str> {
174 match self {
175 TransportHandle::Udp(t) => t.name(),
176 TransportHandle::NostrRelay(t) => t.name(),
177 #[cfg(feature = "sim-transport")]
178 TransportHandle::Sim(t) => t.name(),
179 #[cfg(any(target_os = "linux", target_os = "macos"))]
180 TransportHandle::Ethernet(t) => t.name(),
181 TransportHandle::Tcp(t) => t.name(),
182 TransportHandle::Tor(t) => t.name(),
183 #[cfg(feature = "webrtc-transport")]
184 TransportHandle::WebRtc(t) => t.name(),
185 #[cfg(target_os = "linux")]
186 TransportHandle::Ble(t) => t.name(),
187 }
188 }
189
190 pub fn transport_type(&self) -> &TransportType {
192 match self {
193 TransportHandle::Udp(t) => t.transport_type(),
194 TransportHandle::NostrRelay(t) => t.transport_type(),
195 #[cfg(feature = "sim-transport")]
196 TransportHandle::Sim(t) => t.transport_type(),
197 #[cfg(any(target_os = "linux", target_os = "macos"))]
198 TransportHandle::Ethernet(t) => t.transport_type(),
199 TransportHandle::Tcp(t) => t.transport_type(),
200 TransportHandle::Tor(t) => t.transport_type(),
201 #[cfg(feature = "webrtc-transport")]
202 TransportHandle::WebRtc(t) => t.transport_type(),
203 #[cfg(target_os = "linux")]
204 TransportHandle::Ble(t) => t.transport_type(),
205 }
206 }
207
208 pub fn state(&self) -> TransportState {
210 match self {
211 TransportHandle::Udp(t) => t.state(),
212 TransportHandle::NostrRelay(t) => t.state(),
213 #[cfg(feature = "sim-transport")]
214 TransportHandle::Sim(t) => t.state(),
215 #[cfg(any(target_os = "linux", target_os = "macos"))]
216 TransportHandle::Ethernet(t) => t.state(),
217 TransportHandle::Tcp(t) => t.state(),
218 TransportHandle::Tor(t) => t.state(),
219 #[cfg(feature = "webrtc-transport")]
220 TransportHandle::WebRtc(t) => t.state(),
221 #[cfg(target_os = "linux")]
222 TransportHandle::Ble(t) => t.state(),
223 }
224 }
225
226 pub fn mtu(&self) -> u16 {
228 match self {
229 TransportHandle::Udp(t) => t.mtu(),
230 TransportHandle::NostrRelay(t) => t.mtu(),
231 #[cfg(feature = "sim-transport")]
232 TransportHandle::Sim(t) => t.mtu(),
233 #[cfg(any(target_os = "linux", target_os = "macos"))]
234 TransportHandle::Ethernet(t) => t.mtu(),
235 TransportHandle::Tcp(t) => t.mtu(),
236 TransportHandle::Tor(t) => t.mtu(),
237 #[cfg(feature = "webrtc-transport")]
238 TransportHandle::WebRtc(t) => t.mtu(),
239 #[cfg(target_os = "linux")]
240 TransportHandle::Ble(t) => t.mtu(),
241 }
242 }
243
244 pub fn link_mtu(&self, addr: &TransportAddr) -> u16 {
249 match self {
250 TransportHandle::Udp(t) => t.link_mtu(addr),
251 TransportHandle::NostrRelay(t) => t.link_mtu(addr),
252 #[cfg(feature = "sim-transport")]
253 TransportHandle::Sim(t) => t.link_mtu(addr),
254 #[cfg(any(target_os = "linux", target_os = "macos"))]
255 TransportHandle::Ethernet(t) => t.link_mtu(addr),
256 TransportHandle::Tcp(t) => t.link_mtu(addr),
257 TransportHandle::Tor(t) => t.link_mtu(addr),
258 #[cfg(feature = "webrtc-transport")]
259 TransportHandle::WebRtc(t) => t.link_mtu(addr),
260 #[cfg(target_os = "linux")]
261 TransportHandle::Ble(t) => t.link_mtu(addr),
262 }
263 }
264
265 pub fn local_addr(&self) -> Option<std::net::SocketAddr> {
267 match self {
268 TransportHandle::Udp(t) => t.local_addr(),
269 TransportHandle::NostrRelay(_) => None,
270 #[cfg(feature = "sim-transport")]
271 TransportHandle::Sim(_) => None,
272 #[cfg(any(target_os = "linux", target_os = "macos"))]
273 TransportHandle::Ethernet(_) => None,
274 TransportHandle::Tcp(t) => t.local_addr(),
275 TransportHandle::Tor(_) => None,
276 #[cfg(feature = "webrtc-transport")]
277 TransportHandle::WebRtc(_) => None,
278 #[cfg(target_os = "linux")]
279 TransportHandle::Ble(_) => None,
280 }
281 }
282
283 pub(crate) fn resolved_udp_socket_addr_if_cached(
288 &self,
289 addr: &TransportAddr,
290 ) -> Option<std::net::SocketAddr> {
291 match self {
292 TransportHandle::Udp(t) => t.resolved_socket_addr_if_cached(addr),
293 _ => None,
294 }
295 }
296
297 pub fn interface_name(&self) -> Option<&str> {
299 match self {
300 TransportHandle::Udp(_) => None,
301 TransportHandle::NostrRelay(_) => None,
302 #[cfg(feature = "sim-transport")]
303 TransportHandle::Sim(_) => None,
304 #[cfg(any(target_os = "linux", target_os = "macos"))]
305 TransportHandle::Ethernet(t) => Some(t.interface_name()),
306 TransportHandle::Tcp(_) => None,
307 TransportHandle::Tor(_) => None,
308 #[cfg(feature = "webrtc-transport")]
309 TransportHandle::WebRtc(_) => None,
310 #[cfg(target_os = "linux")]
311 TransportHandle::Ble(_) => None,
312 }
313 }
314
315 pub fn onion_address(&self) -> Option<&str> {
317 match self {
318 TransportHandle::Tor(t) => t.onion_address(),
319 _ => None,
320 }
321 }
322
323 pub fn tor_monitoring(&self) -> Option<TorMonitoringInfo> {
325 match self {
326 TransportHandle::Tor(t) => t.cached_monitoring(),
327 _ => None,
328 }
329 }
330
331 pub fn tor_mode(&self) -> Option<&str> {
333 match self {
334 TransportHandle::Tor(t) => Some(t.mode()),
335 _ => None,
336 }
337 }
338
339 pub fn discover(&self) -> Result<Vec<DiscoveredPeer>, TransportError> {
341 match self {
342 TransportHandle::Udp(t) => t.discover(),
343 TransportHandle::NostrRelay(t) => t.discover(),
344 #[cfg(feature = "sim-transport")]
345 TransportHandle::Sim(t) => t.discover(),
346 #[cfg(any(target_os = "linux", target_os = "macos"))]
347 TransportHandle::Ethernet(t) => t.discover(),
348 TransportHandle::Tcp(t) => t.discover(),
349 TransportHandle::Tor(t) => t.discover(),
350 #[cfg(feature = "webrtc-transport")]
351 TransportHandle::WebRtc(t) => t.discover(),
352 #[cfg(target_os = "linux")]
353 TransportHandle::Ble(t) => t.discover(),
354 }
355 }
356
357 pub fn auto_connect(&self) -> bool {
359 match self {
360 TransportHandle::Udp(t) => t.auto_connect(),
361 TransportHandle::NostrRelay(t) => t.auto_connect(),
362 #[cfg(feature = "sim-transport")]
363 TransportHandle::Sim(t) => t.auto_connect(),
364 #[cfg(any(target_os = "linux", target_os = "macos"))]
365 TransportHandle::Ethernet(t) => t.auto_connect(),
366 TransportHandle::Tcp(t) => t.auto_connect(),
367 TransportHandle::Tor(t) => t.auto_connect(),
368 #[cfg(feature = "webrtc-transport")]
369 TransportHandle::WebRtc(t) => t.auto_connect(),
370 #[cfg(target_os = "linux")]
371 TransportHandle::Ble(t) => t.auto_connect(),
372 }
373 }
374
375 pub fn accept_connections(&self) -> bool {
377 match self {
378 TransportHandle::Udp(t) => t.accept_connections(),
379 TransportHandle::NostrRelay(t) => t.accept_connections(),
380 #[cfg(feature = "sim-transport")]
381 TransportHandle::Sim(t) => t.accept_connections(),
382 #[cfg(any(target_os = "linux", target_os = "macos"))]
383 TransportHandle::Ethernet(t) => t.accept_connections(),
384 TransportHandle::Tcp(t) => t.accept_connections(),
385 TransportHandle::Tor(t) => t.accept_connections(),
386 #[cfg(feature = "webrtc-transport")]
387 TransportHandle::WebRtc(t) => t.accept_connections(),
388 #[cfg(target_os = "linux")]
389 TransportHandle::Ble(t) => t.accept_connections(),
390 }
391 }
392
393 pub async fn connect(&self, addr: &TransportAddr) -> Result<(), TransportError> {
401 match self {
402 TransportHandle::Udp(_) => Ok(()), TransportHandle::NostrRelay(_) => Ok(()), #[cfg(feature = "sim-transport")]
405 TransportHandle::Sim(_) => Ok(()), #[cfg(any(target_os = "linux", target_os = "macos"))]
407 TransportHandle::Ethernet(_) => Ok(()), TransportHandle::Tcp(t) => t.connect_async(addr).await,
409 TransportHandle::Tor(t) => t.connect_async(addr).await,
410 #[cfg(feature = "webrtc-transport")]
411 TransportHandle::WebRtc(t) => t.connect_async(addr).await,
412 #[cfg(target_os = "linux")]
413 TransportHandle::Ble(t) => t.connect_async(addr).await,
414 }
415 }
416
417 pub fn connection_state(&self, addr: &TransportAddr) -> ConnectionState {
423 match self {
424 TransportHandle::Udp(_) => ConnectionState::Connected,
425 TransportHandle::NostrRelay(_) => ConnectionState::Connected,
426 #[cfg(feature = "sim-transport")]
427 TransportHandle::Sim(_) => ConnectionState::Connected,
428 #[cfg(any(target_os = "linux", target_os = "macos"))]
429 TransportHandle::Ethernet(_) => ConnectionState::Connected,
430 TransportHandle::Tcp(t) => t.connection_state_sync(addr),
431 TransportHandle::Tor(t) => t.connection_state_sync(addr),
432 #[cfg(feature = "webrtc-transport")]
433 TransportHandle::WebRtc(t) => t.connection_state_sync(addr),
434 #[cfg(target_os = "linux")]
435 TransportHandle::Ble(t) => t.connection_state_sync(addr),
436 }
437 }
438
439 pub async fn close_connection(&self, addr: &TransportAddr) {
444 match self {
445 TransportHandle::Udp(t) => t.close_connection(addr),
446 TransportHandle::NostrRelay(t) => t.close_connection(addr),
447 #[cfg(feature = "sim-transport")]
448 TransportHandle::Sim(t) => t.close_connection(addr),
449 #[cfg(any(target_os = "linux", target_os = "macos"))]
450 TransportHandle::Ethernet(t) => t.close_connection(addr),
451 TransportHandle::Tcp(t) => t.close_connection_async(addr).await,
452 TransportHandle::Tor(t) => t.close_connection_async(addr).await,
453 #[cfg(feature = "webrtc-transport")]
454 TransportHandle::WebRtc(t) => t.close_connection_async(addr).await,
455 #[cfg(target_os = "linux")]
456 TransportHandle::Ble(t) => t.close_connection_async(addr).await,
457 }
458 }
459
460 pub fn close_connection_detached(&self, _addr: &TransportAddr) {
462 #[cfg(feature = "webrtc-transport")]
463 if let TransportHandle::WebRtc(transport) = self {
464 transport.close_connection_detached(_addr);
465 }
466 }
467
468 pub fn is_operational(&self) -> bool {
470 self.state().is_operational()
471 }
472
473 pub fn congestion(&self) -> TransportCongestion {
479 match self {
480 TransportHandle::Udp(t) => t.congestion(),
481 TransportHandle::NostrRelay(_) => TransportCongestion::default(),
482 #[cfg(feature = "sim-transport")]
483 TransportHandle::Sim(_) => TransportCongestion::default(),
484 #[cfg(any(target_os = "linux", target_os = "macos"))]
485 TransportHandle::Ethernet(_) => TransportCongestion::default(),
486 TransportHandle::Tcp(_) => TransportCongestion::default(),
487 TransportHandle::Tor(_) => TransportCongestion::default(),
488 #[cfg(feature = "webrtc-transport")]
489 TransportHandle::WebRtc(_) => TransportCongestion::default(),
490 #[cfg(target_os = "linux")]
491 TransportHandle::Ble(_) => TransportCongestion::default(),
492 }
493 }
494
495 pub fn transport_stats(&self) -> serde_json::Value {
499 match self {
500 TransportHandle::Udp(t) => {
501 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
502 }
503 TransportHandle::NostrRelay(t) => serde_json::json!({
504 "mtu": t.mtu(),
505 "state": t.state().to_string(),
506 }),
507 #[cfg(feature = "sim-transport")]
508 TransportHandle::Sim(t) => serde_json::to_value(t.stats()).unwrap_or_default(),
509 #[cfg(any(target_os = "linux", target_os = "macos"))]
510 TransportHandle::Ethernet(t) => {
511 let snap = t.stats().snapshot();
512 serde_json::json!({
513 "frames_sent": snap.frames_sent,
514 "frames_recv": snap.frames_recv,
515 "bytes_sent": snap.bytes_sent,
516 "bytes_recv": snap.bytes_recv,
517 "send_errors": snap.send_errors,
518 "recv_errors": snap.recv_errors,
519 "beacons_sent": snap.beacons_sent,
520 "beacons_recv": snap.beacons_recv,
521 "frames_too_short": snap.frames_too_short,
522 "frames_too_long": snap.frames_too_long,
523 })
524 }
525 TransportHandle::Tcp(t) => {
526 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
527 }
528 TransportHandle::Tor(t) => {
529 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
530 }
531 #[cfg(feature = "webrtc-transport")]
532 TransportHandle::WebRtc(t) => serde_json::json!({
533 "mtu": t.mtu(),
534 "state": t.state().to_string(),
535 }),
536 #[cfg(target_os = "linux")]
537 TransportHandle::Ble(t) => {
538 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
539 }
540 }
541 }
542}