libp2p_webtransport_websys/
transport.rs

1use std::{
2    future::Future,
3    pin::Pin,
4    task::{Context, Poll},
5};
6
7use futures::future::FutureExt;
8use libp2p_core::{
9    muxing::StreamMuxerBox,
10    transport::{Boxed, DialOpts, ListenerId, Transport as _, TransportError, TransportEvent},
11};
12use libp2p_identity::{Keypair, PeerId};
13use multiaddr::Multiaddr;
14
15use crate::{endpoint::Endpoint, Connection, Error};
16
17/// Config for the [`Transport`].
18pub struct Config {
19    keypair: Keypair,
20}
21
22/// A WebTransport [`Transport`](libp2p_core::Transport) that works with `web-sys`.
23pub struct Transport {
24    config: Config,
25}
26
27impl Config {
28    /// Constructs a new configuration for the [`Transport`].
29    pub fn new(keypair: &Keypair) -> Self {
30        Config {
31            keypair: keypair.to_owned(),
32        }
33    }
34}
35
36impl Transport {
37    /// Constructs a new `Transport` with the given [`Config`].
38    pub fn new(config: Config) -> Transport {
39        Transport { config }
40    }
41
42    /// Wraps `Transport` in [`Boxed`] and makes it ready to be consumed by
43    /// SwarmBuilder.
44    pub fn boxed(self) -> Boxed<(PeerId, StreamMuxerBox)> {
45        self.map(|(peer_id, muxer), _| (peer_id, StreamMuxerBox::new(muxer)))
46            .boxed()
47    }
48}
49
50impl libp2p_core::Transport for Transport {
51    type Output = (PeerId, Connection);
52    type Error = Error;
53    type ListenerUpgrade = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
54    type Dial = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
55
56    fn listen_on(
57        &mut self,
58        _id: ListenerId,
59        addr: Multiaddr,
60    ) -> Result<(), TransportError<Self::Error>> {
61        Err(TransportError::MultiaddrNotSupported(addr))
62    }
63
64    fn remove_listener(&mut self, _id: ListenerId) -> bool {
65        false
66    }
67
68    fn dial(
69        &mut self,
70        addr: Multiaddr,
71        dial_opts: DialOpts,
72    ) -> Result<Self::Dial, TransportError<Self::Error>> {
73        if dial_opts.role.is_listener() {
74            return Err(TransportError::MultiaddrNotSupported(addr));
75        }
76
77        let endpoint = Endpoint::from_multiaddr(&addr).map_err(|e| match e {
78            e @ Error::InvalidMultiaddr(_) => {
79                tracing::debug!("{}", e);
80                TransportError::MultiaddrNotSupported(addr)
81            }
82            e => TransportError::Other(e),
83        })?;
84
85        let mut session = Connection::new(&endpoint).map_err(TransportError::Other)?;
86        let keypair = self.config.keypair.clone();
87
88        Ok(async move {
89            let peer_id = session
90                .authenticate(&keypair, endpoint.remote_peer, endpoint.certhashes)
91                .await?;
92            Ok((peer_id, session))
93        }
94        .boxed())
95    }
96
97    fn poll(
98        self: Pin<&mut Self>,
99        _cx: &mut Context<'_>,
100    ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
101        Poll::Pending
102    }
103}