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