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