libp2p/builder/phase/
other_transport.rs

1use std::{convert::Infallible, marker::PhantomData, sync::Arc};
2
3use libp2p_core::{
4    upgrade::{InboundConnectionUpgrade, OutboundConnectionUpgrade},
5    Transport,
6};
7#[cfg(feature = "relay")]
8use libp2p_core::{Negotiated, UpgradeInfo};
9#[cfg(feature = "relay")]
10use libp2p_identity::PeerId;
11
12use super::*;
13use crate::SwarmBuilder;
14
15pub struct OtherTransportPhase<T> {
16    pub(crate) transport: T,
17}
18
19impl<Provider, T: AuthenticatedMultiplexedTransport>
20    SwarmBuilder<Provider, OtherTransportPhase<T>>
21{
22    pub fn with_other_transport<
23        Muxer: libp2p_core::muxing::StreamMuxer + Send + 'static,
24        OtherTransport: Transport<Output = (libp2p_identity::PeerId, Muxer)> + Send + Unpin + 'static,
25        R: TryIntoTransport<OtherTransport>,
26    >(
27        self,
28        constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
29    ) -> Result<
30        SwarmBuilder<Provider, OtherTransportPhase<impl AuthenticatedMultiplexedTransport>>,
31        R::Error,
32    >
33    where
34        <OtherTransport as Transport>::Error: Send + Sync + 'static,
35        <OtherTransport as Transport>::Dial: Send,
36        <OtherTransport as Transport>::ListenerUpgrade: Send,
37        <Muxer as libp2p_core::muxing::StreamMuxer>::Substream: Send,
38        <Muxer as libp2p_core::muxing::StreamMuxer>::Error: Send + Sync,
39    {
40        Ok(SwarmBuilder {
41            phase: OtherTransportPhase {
42                transport: self
43                    .phase
44                    .transport
45                    .or_transport(
46                        constructor(&self.keypair)
47                            .try_into_transport()?
48                            .map(|(peer_id, conn), _| (peer_id, StreamMuxerBox::new(conn))),
49                    )
50                    .map(|either, _| either.into_inner()),
51            },
52            keypair: self.keypair,
53            phantom: PhantomData,
54        })
55    }
56
57    pub(crate) fn without_any_other_transports(self) -> SwarmBuilder<Provider, DnsPhase<T>> {
58        SwarmBuilder {
59            keypair: self.keypair,
60            phantom: PhantomData,
61            phase: DnsPhase {
62                transport: self.phase.transport,
63            },
64        }
65    }
66}
67
68// Shortcuts
69#[cfg(all(not(target_arch = "wasm32"), feature = "async-std", feature = "dns"))]
70impl<T: AuthenticatedMultiplexedTransport>
71    SwarmBuilder<super::provider::AsyncStd, OtherTransportPhase<T>>
72{
73    pub fn with_dns(
74        self,
75    ) -> Result<
76        SwarmBuilder<
77            super::provider::AsyncStd,
78            WebsocketPhase<impl AuthenticatedMultiplexedTransport>,
79        >,
80        std::io::Error,
81    > {
82        self.without_any_other_transports().with_dns()
83    }
84}
85#[cfg(all(not(target_arch = "wasm32"), feature = "tokio", feature = "dns"))]
86impl<T: AuthenticatedMultiplexedTransport>
87    SwarmBuilder<super::provider::Tokio, OtherTransportPhase<T>>
88{
89    pub fn with_dns(
90        self,
91    ) -> Result<
92        SwarmBuilder<
93            super::provider::Tokio,
94            WebsocketPhase<impl AuthenticatedMultiplexedTransport>,
95        >,
96        std::io::Error,
97    > {
98        self.without_any_other_transports().with_dns()
99    }
100}
101#[cfg(all(not(target_arch = "wasm32"), feature = "async-std", feature = "dns"))]
102impl<T: AuthenticatedMultiplexedTransport>
103    SwarmBuilder<super::provider::AsyncStd, OtherTransportPhase<T>>
104{
105    pub fn with_dns_config(
106        self,
107        cfg: libp2p_dns::ResolverConfig,
108        opts: libp2p_dns::ResolverOpts,
109    ) -> SwarmBuilder<
110        super::provider::AsyncStd,
111        WebsocketPhase<impl AuthenticatedMultiplexedTransport>,
112    > {
113        self.without_any_other_transports()
114            .with_dns_config(cfg, opts)
115    }
116}
117#[cfg(all(not(target_arch = "wasm32"), feature = "tokio", feature = "dns"))]
118impl<T: AuthenticatedMultiplexedTransport>
119    SwarmBuilder<super::provider::Tokio, OtherTransportPhase<T>>
120{
121    pub fn with_dns_config(
122        self,
123        cfg: libp2p_dns::ResolverConfig,
124        opts: libp2p_dns::ResolverOpts,
125    ) -> SwarmBuilder<super::provider::Tokio, WebsocketPhase<impl AuthenticatedMultiplexedTransport>>
126    {
127        self.without_any_other_transports()
128            .with_dns_config(cfg, opts)
129    }
130}
131#[cfg(feature = "relay")]
132impl<T: AuthenticatedMultiplexedTransport, Provider>
133    SwarmBuilder<Provider, OtherTransportPhase<T>>
134{
135    /// See [`SwarmBuilder::with_relay_client`].
136    pub fn with_relay_client<SecUpgrade, SecStream, SecError, MuxUpgrade, MuxStream, MuxError>(
137        self,
138        security_upgrade: SecUpgrade,
139        multiplexer_upgrade: MuxUpgrade,
140    ) -> Result<
141        SwarmBuilder<
142            Provider,
143            BandwidthMetricsPhase<impl AuthenticatedMultiplexedTransport, libp2p_relay::client::Behaviour>,
144        >,
145        SecUpgrade::Error,
146        > where
147
148        SecStream: futures::AsyncRead + futures::AsyncWrite + Unpin + Send + 'static,
149        SecError: std::error::Error + Send + Sync + 'static,
150        SecUpgrade: IntoSecurityUpgrade<libp2p_relay::client::Connection>,
151        SecUpgrade::Upgrade: InboundConnectionUpgrade<Negotiated<libp2p_relay::client::Connection>, Output = (PeerId, SecStream), Error = SecError> + OutboundConnectionUpgrade<Negotiated<libp2p_relay::client::Connection>, Output = (PeerId, SecStream), Error = SecError> + Clone + Send + 'static,
152    <SecUpgrade::Upgrade as InboundConnectionUpgrade<Negotiated<libp2p_relay::client::Connection>>>::Future: Send,
153    <SecUpgrade::Upgrade as OutboundConnectionUpgrade<Negotiated<libp2p_relay::client::Connection>>>::Future: Send,
154    <<<SecUpgrade as IntoSecurityUpgrade<libp2p_relay::client::Connection>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
155    <<SecUpgrade as IntoSecurityUpgrade<libp2p_relay::client::Connection>>::Upgrade as UpgradeInfo>::Info: Send,
156
157        MuxStream: libp2p_core::muxing::StreamMuxer + Send + 'static,
158        MuxStream::Substream: Send + 'static,
159        MuxStream::Error: Send + Sync + 'static,
160        MuxUpgrade: IntoMultiplexerUpgrade<SecStream>,
161        MuxUpgrade::Upgrade: InboundConnectionUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + OutboundConnectionUpgrade<Negotiated<SecStream>, Output = MuxStream, Error = MuxError> + Clone + Send + 'static,
162    <MuxUpgrade::Upgrade as InboundConnectionUpgrade<Negotiated<SecStream>>>::Future: Send,
163    <MuxUpgrade::Upgrade as OutboundConnectionUpgrade<Negotiated<SecStream>>>::Future: Send,
164        MuxError: std::error::Error + Send + Sync + 'static,
165    <<<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::InfoIter as IntoIterator>::IntoIter: Send,
166    <<MuxUpgrade as IntoMultiplexerUpgrade<SecStream>>::Upgrade as UpgradeInfo>::Info: Send,
167    {
168        self.without_any_other_transports()
169            .without_dns()
170            .without_websocket()
171            .with_relay_client(security_upgrade, multiplexer_upgrade)
172    }
173}
174#[cfg(feature = "metrics")]
175impl<Provider, T: AuthenticatedMultiplexedTransport>
176    SwarmBuilder<Provider, OtherTransportPhase<T>>
177{
178    pub fn with_bandwidth_metrics(
179        self,
180        registry: &mut libp2p_metrics::Registry,
181    ) -> SwarmBuilder<
182        Provider,
183        BehaviourPhase<impl AuthenticatedMultiplexedTransport, NoRelayBehaviour>,
184    > {
185        self.without_any_other_transports()
186            .without_dns()
187            .without_websocket()
188            .without_relay()
189            .with_bandwidth_metrics(registry)
190    }
191}
192impl<Provider, T: AuthenticatedMultiplexedTransport>
193    SwarmBuilder<Provider, OtherTransportPhase<T>>
194{
195    pub fn with_behaviour<B, R: TryIntoBehaviour<B>>(
196        self,
197        constructor: impl FnOnce(&libp2p_identity::Keypair) -> R,
198    ) -> Result<SwarmBuilder<Provider, SwarmPhase<T, B>>, R::Error> {
199        self.without_any_other_transports()
200            .without_dns()
201            .without_websocket()
202            .without_relay()
203            .with_behaviour(constructor)
204    }
205}
206
207pub trait TryIntoTransport<T>: private::Sealed<Self::Error> {
208    type Error;
209
210    fn try_into_transport(self) -> Result<T, Self::Error>;
211}
212
213impl<T: Transport> TryIntoTransport<T> for T {
214    type Error = Infallible;
215
216    fn try_into_transport(self) -> Result<T, Self::Error> {
217        Ok(self)
218    }
219}
220
221impl<T: Transport> TryIntoTransport<T> for Result<T, Box<dyn std::error::Error + Send + Sync>> {
222    type Error = TransportError;
223
224    fn try_into_transport(self) -> Result<T, Self::Error> {
225        self.map_err(TransportError)
226    }
227}
228
229mod private {
230    pub trait Sealed<Error> {}
231}
232
233impl<T: Transport> private::Sealed<Infallible> for T {}
234
235impl<T: Transport> private::Sealed<TransportError>
236    for Result<T, Box<dyn std::error::Error + Send + Sync>>
237{
238}
239
240#[derive(Debug, thiserror::Error)]
241#[error("failed to build transport: {0}")]
242pub struct TransportError(Box<dyn std::error::Error + Send + Sync + 'static>);