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#[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 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>);