libp2p_webrtc_websys/
transport.rs1use std::{
2 future::Future,
3 pin::Pin,
4 task::{Context, Poll},
5};
6
7use futures::future::FutureExt;
8use libp2p_core::{
9 multiaddr::Multiaddr,
10 muxing::StreamMuxerBox,
11 transport::{Boxed, DialOpts, ListenerId, Transport as _, TransportError, TransportEvent},
12};
13use libp2p_identity::{Keypair, PeerId};
14
15use super::{upgrade, Connection, Error};
16
17#[derive(Clone)]
19pub struct Config {
20 keypair: Keypair,
21}
22
23pub struct Transport {
25 config: Config,
26}
27
28impl Config {
29 pub fn new(keypair: &Keypair) -> Self {
31 Config {
32 keypair: keypair.to_owned(),
33 }
34 }
35}
36
37impl Transport {
38 pub fn new(config: Config) -> Transport {
40 Transport { config }
41 }
42
43 pub fn boxed(self) -> Boxed<(PeerId, StreamMuxerBox)> {
46 self.map(|(peer_id, muxer), _| (peer_id, StreamMuxerBox::new(muxer)))
47 .boxed()
48 }
49}
50
51impl libp2p_core::Transport for Transport {
52 type Output = (PeerId, Connection);
53 type Error = Error;
54 type ListenerUpgrade = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
55 type Dial = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
56
57 fn listen_on(
58 &mut self,
59 _id: ListenerId,
60 addr: Multiaddr,
61 ) -> Result<(), TransportError<Self::Error>> {
62 Err(TransportError::MultiaddrNotSupported(addr))
63 }
64
65 fn remove_listener(&mut self, _id: ListenerId) -> bool {
66 false
67 }
68
69 fn dial(
70 &mut self,
71 addr: Multiaddr,
72 dial_opts: DialOpts,
73 ) -> Result<Self::Dial, TransportError<Self::Error>> {
74 if dial_opts.role.is_listener() {
75 return Err(TransportError::MultiaddrNotSupported(addr));
76 }
77
78 if maybe_local_firefox() {
79 return Err(TransportError::Other(
80 "Firefox does not support WebRTC over localhost or 127.0.0.1"
81 .to_string()
82 .into(),
83 ));
84 }
85
86 let (sock_addr, server_fingerprint) = libp2p_webrtc_utils::parse_webrtc_dial_addr(&addr)
87 .ok_or_else(|| TransportError::MultiaddrNotSupported(addr.clone()))?;
88
89 if sock_addr.port() == 0 || sock_addr.ip().is_unspecified() {
90 return Err(TransportError::MultiaddrNotSupported(addr));
91 }
92
93 let config = self.config.clone();
94
95 Ok(async move {
96 let (peer_id, connection) =
97 upgrade::outbound(sock_addr, server_fingerprint, config.keypair.clone()).await?;
98
99 Ok((peer_id, connection))
100 }
101 .boxed())
102 }
103
104 fn poll(
105 self: Pin<&mut Self>,
106 _cx: &mut Context<'_>,
107 ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
108 Poll::Pending
109 }
110}
111
112fn maybe_local_firefox() -> bool {
116 let window = &web_sys::window().expect("window should be available");
117 let ua = match window.navigator().user_agent() {
118 Ok(agent) => agent.to_lowercase(),
119 Err(_) => return false,
120 };
121
122 let hostname = match window
123 .document()
124 .expect("should be valid document")
125 .location()
126 {
127 Some(location) => match location.hostname() {
128 Ok(hostname) => hostname,
129 Err(_) => return false,
130 },
131 None => return false,
132 };
133
134 (ua.contains("firefox") || ua.contains("seamonkey") || ua.contains("iceape"))
140 && (hostname == "localhost" || hostname == "127.0.0.1" || hostname == "[::1]")
141}