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 #[cfg(feature = "webrtc-transport")]
54 pub(crate) fn drain_link_negotiations(
55 &mut self,
56 limit: usize,
57 ) -> Vec<super::link_negotiation::OutboundLinkNegotiation> {
58 match self {
59 TransportHandle::WebRtc(transport) => transport.drain_link_negotiations(limit),
60 _ => Vec::new(),
61 }
62 }
63
64 #[cfg(feature = "webrtc-transport")]
66 pub(crate) fn ingest_link_negotiation(
67 &self,
68 source: secp256k1::PublicKey,
69 message: super::link_negotiation::LinkNegotiationMessage,
70 ) -> Result<(), TransportError> {
71 match self {
72 TransportHandle::WebRtc(transport) if message.link_type == "webrtc" => {
73 transport.ingest_link_negotiation(source, message)
74 }
75 _ => Err(TransportError::NotSupported(
76 "no enabled adapter accepts this link negotiation".into(),
77 )),
78 }
79 }
80
81 pub async fn start(&mut self) -> Result<(), TransportError> {
83 match self {
84 TransportHandle::Udp(t) => t.start_async().await,
85 TransportHandle::NostrRelay(t) => t.start(),
86 #[cfg(feature = "sim-transport")]
87 TransportHandle::Sim(t) => t.start_async().await,
88 #[cfg(any(target_os = "linux", target_os = "macos"))]
89 TransportHandle::Ethernet(t) => t.start_async().await,
90 TransportHandle::Tcp(t) => t.start_async().await,
91 TransportHandle::Tor(t) => t.start_async().await,
92 #[cfg(feature = "webrtc-transport")]
93 TransportHandle::WebRtc(t) => t.start_async().await,
94 #[cfg(target_os = "linux")]
95 TransportHandle::Ble(t) => t.start_async().await,
96 }
97 }
98
99 pub async fn stop(&mut self) -> Result<(), TransportError> {
101 match self {
102 TransportHandle::Udp(t) => t.stop_async().await,
103 TransportHandle::NostrRelay(t) => t.stop(),
104 #[cfg(feature = "sim-transport")]
105 TransportHandle::Sim(t) => t.stop_async().await,
106 #[cfg(any(target_os = "linux", target_os = "macos"))]
107 TransportHandle::Ethernet(t) => t.stop_async().await,
108 TransportHandle::Tcp(t) => t.stop_async().await,
109 TransportHandle::Tor(t) => t.stop_async().await,
110 #[cfg(feature = "webrtc-transport")]
111 TransportHandle::WebRtc(t) => t.stop_async().await,
112 #[cfg(target_os = "linux")]
113 TransportHandle::Ble(t) => t.stop_async().await,
114 }
115 }
116
117 pub async fn send(&self, addr: &TransportAddr, data: &[u8]) -> Result<usize, TransportError> {
119 match self {
120 TransportHandle::Udp(t) => t.send_async(addr, data).await,
121 TransportHandle::NostrRelay(t) => t.send(addr, data).map(|()| data.len()),
122 #[cfg(feature = "sim-transport")]
123 TransportHandle::Sim(t) => t.send_async(addr, data).await,
124 #[cfg(any(target_os = "linux", target_os = "macos"))]
125 TransportHandle::Ethernet(t) => t.send_async(addr, data).await,
126 TransportHandle::Tcp(t) => {
127 tokio::time::timeout(TCP_SEND_TIMEOUT, t.send_async(addr, data))
128 .await
129 .unwrap_or(Err(TransportError::Timeout))
130 }
131 TransportHandle::Tor(t) => t.send_async(addr, data).await,
132 #[cfg(feature = "webrtc-transport")]
133 TransportHandle::WebRtc(t) => Box::pin(t.send_async(addr, data)).await,
135 #[cfg(target_os = "linux")]
136 TransportHandle::Ble(t) => t.send_async(addr, data).await,
137 }
138 }
139
140 pub fn transport_id(&self) -> TransportId {
142 match self {
143 TransportHandle::Udp(t) => t.transport_id(),
144 TransportHandle::NostrRelay(t) => t.transport_id(),
145 #[cfg(feature = "sim-transport")]
146 TransportHandle::Sim(t) => t.transport_id(),
147 #[cfg(any(target_os = "linux", target_os = "macos"))]
148 TransportHandle::Ethernet(t) => t.transport_id(),
149 TransportHandle::Tcp(t) => t.transport_id(),
150 TransportHandle::Tor(t) => t.transport_id(),
151 #[cfg(feature = "webrtc-transport")]
152 TransportHandle::WebRtc(t) => t.transport_id(),
153 #[cfg(target_os = "linux")]
154 TransportHandle::Ble(t) => t.transport_id(),
155 }
156 }
157
158 pub fn name(&self) -> Option<&str> {
160 match self {
161 TransportHandle::Udp(t) => t.name(),
162 TransportHandle::NostrRelay(t) => t.name(),
163 #[cfg(feature = "sim-transport")]
164 TransportHandle::Sim(t) => t.name(),
165 #[cfg(any(target_os = "linux", target_os = "macos"))]
166 TransportHandle::Ethernet(t) => t.name(),
167 TransportHandle::Tcp(t) => t.name(),
168 TransportHandle::Tor(t) => t.name(),
169 #[cfg(feature = "webrtc-transport")]
170 TransportHandle::WebRtc(t) => t.name(),
171 #[cfg(target_os = "linux")]
172 TransportHandle::Ble(t) => t.name(),
173 }
174 }
175
176 pub fn transport_type(&self) -> &TransportType {
178 match self {
179 TransportHandle::Udp(t) => t.transport_type(),
180 TransportHandle::NostrRelay(t) => t.transport_type(),
181 #[cfg(feature = "sim-transport")]
182 TransportHandle::Sim(t) => t.transport_type(),
183 #[cfg(any(target_os = "linux", target_os = "macos"))]
184 TransportHandle::Ethernet(t) => t.transport_type(),
185 TransportHandle::Tcp(t) => t.transport_type(),
186 TransportHandle::Tor(t) => t.transport_type(),
187 #[cfg(feature = "webrtc-transport")]
188 TransportHandle::WebRtc(t) => t.transport_type(),
189 #[cfg(target_os = "linux")]
190 TransportHandle::Ble(t) => t.transport_type(),
191 }
192 }
193
194 pub fn state(&self) -> TransportState {
196 match self {
197 TransportHandle::Udp(t) => t.state(),
198 TransportHandle::NostrRelay(t) => t.state(),
199 #[cfg(feature = "sim-transport")]
200 TransportHandle::Sim(t) => t.state(),
201 #[cfg(any(target_os = "linux", target_os = "macos"))]
202 TransportHandle::Ethernet(t) => t.state(),
203 TransportHandle::Tcp(t) => t.state(),
204 TransportHandle::Tor(t) => t.state(),
205 #[cfg(feature = "webrtc-transport")]
206 TransportHandle::WebRtc(t) => t.state(),
207 #[cfg(target_os = "linux")]
208 TransportHandle::Ble(t) => t.state(),
209 }
210 }
211
212 pub fn mtu(&self) -> u16 {
214 match self {
215 TransportHandle::Udp(t) => t.mtu(),
216 TransportHandle::NostrRelay(t) => t.mtu(),
217 #[cfg(feature = "sim-transport")]
218 TransportHandle::Sim(t) => t.mtu(),
219 #[cfg(any(target_os = "linux", target_os = "macos"))]
220 TransportHandle::Ethernet(t) => t.mtu(),
221 TransportHandle::Tcp(t) => t.mtu(),
222 TransportHandle::Tor(t) => t.mtu(),
223 #[cfg(feature = "webrtc-transport")]
224 TransportHandle::WebRtc(t) => t.mtu(),
225 #[cfg(target_os = "linux")]
226 TransportHandle::Ble(t) => t.mtu(),
227 }
228 }
229
230 pub fn link_mtu(&self, addr: &TransportAddr) -> u16 {
235 match self {
236 TransportHandle::Udp(t) => t.link_mtu(addr),
237 TransportHandle::NostrRelay(t) => t.link_mtu(addr),
238 #[cfg(feature = "sim-transport")]
239 TransportHandle::Sim(t) => t.link_mtu(addr),
240 #[cfg(any(target_os = "linux", target_os = "macos"))]
241 TransportHandle::Ethernet(t) => t.link_mtu(addr),
242 TransportHandle::Tcp(t) => t.link_mtu(addr),
243 TransportHandle::Tor(t) => t.link_mtu(addr),
244 #[cfg(feature = "webrtc-transport")]
245 TransportHandle::WebRtc(t) => t.link_mtu(addr),
246 #[cfg(target_os = "linux")]
247 TransportHandle::Ble(t) => t.link_mtu(addr),
248 }
249 }
250
251 pub fn local_addr(&self) -> Option<std::net::SocketAddr> {
253 match self {
254 TransportHandle::Udp(t) => t.local_addr(),
255 TransportHandle::NostrRelay(_) => None,
256 #[cfg(feature = "sim-transport")]
257 TransportHandle::Sim(_) => None,
258 #[cfg(any(target_os = "linux", target_os = "macos"))]
259 TransportHandle::Ethernet(_) => None,
260 TransportHandle::Tcp(t) => t.local_addr(),
261 TransportHandle::Tor(_) => None,
262 #[cfg(feature = "webrtc-transport")]
263 TransportHandle::WebRtc(_) => None,
264 #[cfg(target_os = "linux")]
265 TransportHandle::Ble(_) => None,
266 }
267 }
268
269 pub(crate) fn resolved_udp_socket_addr_if_cached(
274 &self,
275 addr: &TransportAddr,
276 ) -> Option<std::net::SocketAddr> {
277 match self {
278 TransportHandle::Udp(t) => t.resolved_socket_addr_if_cached(addr),
279 _ => None,
280 }
281 }
282
283 pub fn interface_name(&self) -> Option<&str> {
285 match self {
286 TransportHandle::Udp(_) => None,
287 TransportHandle::NostrRelay(_) => None,
288 #[cfg(feature = "sim-transport")]
289 TransportHandle::Sim(_) => None,
290 #[cfg(any(target_os = "linux", target_os = "macos"))]
291 TransportHandle::Ethernet(t) => Some(t.interface_name()),
292 TransportHandle::Tcp(_) => None,
293 TransportHandle::Tor(_) => None,
294 #[cfg(feature = "webrtc-transport")]
295 TransportHandle::WebRtc(_) => None,
296 #[cfg(target_os = "linux")]
297 TransportHandle::Ble(_) => None,
298 }
299 }
300
301 pub fn onion_address(&self) -> Option<&str> {
303 match self {
304 TransportHandle::Tor(t) => t.onion_address(),
305 _ => None,
306 }
307 }
308
309 pub fn tor_monitoring(&self) -> Option<TorMonitoringInfo> {
311 match self {
312 TransportHandle::Tor(t) => t.cached_monitoring(),
313 _ => None,
314 }
315 }
316
317 pub fn tor_mode(&self) -> Option<&str> {
319 match self {
320 TransportHandle::Tor(t) => Some(t.mode()),
321 _ => None,
322 }
323 }
324
325 pub fn discover(&self) -> Result<Vec<DiscoveredPeer>, TransportError> {
327 match self {
328 TransportHandle::Udp(t) => t.discover(),
329 TransportHandle::NostrRelay(t) => t.discover(),
330 #[cfg(feature = "sim-transport")]
331 TransportHandle::Sim(t) => t.discover(),
332 #[cfg(any(target_os = "linux", target_os = "macos"))]
333 TransportHandle::Ethernet(t) => t.discover(),
334 TransportHandle::Tcp(t) => t.discover(),
335 TransportHandle::Tor(t) => t.discover(),
336 #[cfg(feature = "webrtc-transport")]
337 TransportHandle::WebRtc(t) => t.discover(),
338 #[cfg(target_os = "linux")]
339 TransportHandle::Ble(t) => t.discover(),
340 }
341 }
342
343 pub fn auto_connect(&self) -> bool {
345 match self {
346 TransportHandle::Udp(t) => t.auto_connect(),
347 TransportHandle::NostrRelay(t) => t.auto_connect(),
348 #[cfg(feature = "sim-transport")]
349 TransportHandle::Sim(t) => t.auto_connect(),
350 #[cfg(any(target_os = "linux", target_os = "macos"))]
351 TransportHandle::Ethernet(t) => t.auto_connect(),
352 TransportHandle::Tcp(t) => t.auto_connect(),
353 TransportHandle::Tor(t) => t.auto_connect(),
354 #[cfg(feature = "webrtc-transport")]
355 TransportHandle::WebRtc(t) => t.auto_connect(),
356 #[cfg(target_os = "linux")]
357 TransportHandle::Ble(t) => t.auto_connect(),
358 }
359 }
360
361 pub fn accept_connections(&self) -> bool {
363 match self {
364 TransportHandle::Udp(t) => t.accept_connections(),
365 TransportHandle::NostrRelay(t) => t.accept_connections(),
366 #[cfg(feature = "sim-transport")]
367 TransportHandle::Sim(t) => t.accept_connections(),
368 #[cfg(any(target_os = "linux", target_os = "macos"))]
369 TransportHandle::Ethernet(t) => t.accept_connections(),
370 TransportHandle::Tcp(t) => t.accept_connections(),
371 TransportHandle::Tor(t) => t.accept_connections(),
372 #[cfg(feature = "webrtc-transport")]
373 TransportHandle::WebRtc(t) => t.accept_connections(),
374 #[cfg(target_os = "linux")]
375 TransportHandle::Ble(t) => t.accept_connections(),
376 }
377 }
378
379 pub async fn connect(&self, addr: &TransportAddr) -> Result<(), TransportError> {
387 match self {
388 TransportHandle::Udp(_) => Ok(()), TransportHandle::NostrRelay(_) => Ok(()), #[cfg(feature = "sim-transport")]
391 TransportHandle::Sim(_) => Ok(()), #[cfg(any(target_os = "linux", target_os = "macos"))]
393 TransportHandle::Ethernet(_) => Ok(()), TransportHandle::Tcp(t) => t.connect_async(addr).await,
395 TransportHandle::Tor(t) => t.connect_async(addr).await,
396 #[cfg(feature = "webrtc-transport")]
397 TransportHandle::WebRtc(t) => t.connect_async(addr).await,
398 #[cfg(target_os = "linux")]
399 TransportHandle::Ble(t) => t.connect_async(addr).await,
400 }
401 }
402
403 pub fn connection_state(&self, addr: &TransportAddr) -> ConnectionState {
409 match self {
410 TransportHandle::Udp(_) => ConnectionState::Connected,
411 TransportHandle::NostrRelay(_) => ConnectionState::Connected,
412 #[cfg(feature = "sim-transport")]
413 TransportHandle::Sim(_) => ConnectionState::Connected,
414 #[cfg(any(target_os = "linux", target_os = "macos"))]
415 TransportHandle::Ethernet(_) => ConnectionState::Connected,
416 TransportHandle::Tcp(t) => t.connection_state_sync(addr),
417 TransportHandle::Tor(t) => t.connection_state_sync(addr),
418 #[cfg(feature = "webrtc-transport")]
419 TransportHandle::WebRtc(t) => t.connection_state_sync(addr),
420 #[cfg(target_os = "linux")]
421 TransportHandle::Ble(t) => t.connection_state_sync(addr),
422 }
423 }
424
425 pub async fn close_connection(&self, addr: &TransportAddr) {
430 match self {
431 TransportHandle::Udp(t) => t.close_connection(addr),
432 TransportHandle::NostrRelay(t) => t.close_connection(addr),
433 #[cfg(feature = "sim-transport")]
434 TransportHandle::Sim(t) => t.close_connection(addr),
435 #[cfg(any(target_os = "linux", target_os = "macos"))]
436 TransportHandle::Ethernet(t) => t.close_connection(addr),
437 TransportHandle::Tcp(t) => t.close_connection_async(addr).await,
438 TransportHandle::Tor(t) => t.close_connection_async(addr).await,
439 #[cfg(feature = "webrtc-transport")]
440 TransportHandle::WebRtc(t) => t.close_connection_async(addr).await,
441 #[cfg(target_os = "linux")]
442 TransportHandle::Ble(t) => t.close_connection_async(addr).await,
443 }
444 }
445
446 pub fn close_connection_detached(&self, _addr: &TransportAddr) {
448 #[cfg(feature = "webrtc-transport")]
449 if let TransportHandle::WebRtc(transport) = self {
450 transport.close_connection_detached(_addr);
451 }
452 }
453
454 pub fn is_operational(&self) -> bool {
456 self.state().is_operational()
457 }
458
459 pub fn congestion(&self) -> TransportCongestion {
465 match self {
466 TransportHandle::Udp(t) => t.congestion(),
467 TransportHandle::NostrRelay(_) => TransportCongestion::default(),
468 #[cfg(feature = "sim-transport")]
469 TransportHandle::Sim(_) => TransportCongestion::default(),
470 #[cfg(any(target_os = "linux", target_os = "macos"))]
471 TransportHandle::Ethernet(_) => TransportCongestion::default(),
472 TransportHandle::Tcp(_) => TransportCongestion::default(),
473 TransportHandle::Tor(_) => TransportCongestion::default(),
474 #[cfg(feature = "webrtc-transport")]
475 TransportHandle::WebRtc(_) => TransportCongestion::default(),
476 #[cfg(target_os = "linux")]
477 TransportHandle::Ble(_) => TransportCongestion::default(),
478 }
479 }
480
481 pub fn transport_stats(&self) -> serde_json::Value {
485 match self {
486 TransportHandle::Udp(t) => {
487 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
488 }
489 TransportHandle::NostrRelay(t) => serde_json::json!({
490 "mtu": t.mtu(),
491 "state": t.state().to_string(),
492 }),
493 #[cfg(feature = "sim-transport")]
494 TransportHandle::Sim(t) => serde_json::to_value(t.stats()).unwrap_or_default(),
495 #[cfg(any(target_os = "linux", target_os = "macos"))]
496 TransportHandle::Ethernet(t) => {
497 let snap = t.stats().snapshot();
498 serde_json::json!({
499 "frames_sent": snap.frames_sent,
500 "frames_recv": snap.frames_recv,
501 "bytes_sent": snap.bytes_sent,
502 "bytes_recv": snap.bytes_recv,
503 "send_errors": snap.send_errors,
504 "recv_errors": snap.recv_errors,
505 "beacons_sent": snap.beacons_sent,
506 "beacons_recv": snap.beacons_recv,
507 "frames_too_short": snap.frames_too_short,
508 "frames_too_long": snap.frames_too_long,
509 })
510 }
511 TransportHandle::Tcp(t) => {
512 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
513 }
514 TransportHandle::Tor(t) => {
515 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
516 }
517 #[cfg(feature = "webrtc-transport")]
518 TransportHandle::WebRtc(t) => serde_json::json!({
519 "mtu": t.mtu(),
520 "state": t.state().to_string(),
521 }),
522 #[cfg(target_os = "linux")]
523 TransportHandle::Ble(t) => {
524 serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
525 }
526 }
527 }
528}