libp2p_core/transport/
choice.rs1use crate::either::EitherFuture;
22use crate::transport::{ListenerId, Transport, TransportError, TransportEvent};
23use either::Either;
24use futures::future;
25use multiaddr::Multiaddr;
26use std::{pin::Pin, task::Context, task::Poll};
27
28#[derive(Debug, Copy, Clone)]
30#[pin_project::pin_project]
31pub struct OrTransport<A, B>(#[pin] A, #[pin] B);
32
33impl<A, B> OrTransport<A, B> {
34 pub fn new(a: A, b: B) -> OrTransport<A, B> {
35 OrTransport(a, b)
36 }
37}
38
39impl<A, B> Transport for OrTransport<A, B>
40where
41 B: Transport,
42 A: Transport,
43{
44 type Output = future::Either<A::Output, B::Output>;
45 type Error = Either<A::Error, B::Error>;
46 type ListenerUpgrade = EitherFuture<A::ListenerUpgrade, B::ListenerUpgrade>;
47 type Dial = EitherFuture<A::Dial, B::Dial>;
48
49 fn listen_on(
50 &mut self,
51 id: ListenerId,
52 addr: Multiaddr,
53 ) -> Result<(), TransportError<Self::Error>> {
54 tracing::trace!(
55 address=%addr,
56 "Attempting to listen on address using {}",
57 std::any::type_name::<A>()
58 );
59 let addr = match self.0.listen_on(id, addr) {
60 Err(TransportError::MultiaddrNotSupported(addr)) => {
61 tracing::debug!(
62 address=%addr,
63 "Failed to listen on address using {}",
64 std::any::type_name::<A>()
65 );
66 addr
67 }
68 res => return res.map_err(|err| err.map(Either::Left)),
69 };
70
71 tracing::trace!(
72 address=%addr,
73 "Attempting to listen on address using {}",
74 std::any::type_name::<B>()
75 );
76 let addr = match self.1.listen_on(id, addr) {
77 Err(TransportError::MultiaddrNotSupported(addr)) => {
78 tracing::debug!(
79 address=%addr,
80 "Failed to listen on address using {}",
81 std::any::type_name::<B>()
82 );
83 addr
84 }
85 res => return res.map_err(|err| err.map(Either::Right)),
86 };
87
88 Err(TransportError::MultiaddrNotSupported(addr))
89 }
90
91 fn remove_listener(&mut self, id: ListenerId) -> bool {
92 self.0.remove_listener(id) || self.1.remove_listener(id)
93 }
94
95 fn dial(&mut self, addr: Multiaddr) -> Result<Self::Dial, TransportError<Self::Error>> {
96 tracing::trace!(
97 address=%addr,
98 "Attempting to dial address using {}",
99 std::any::type_name::<A>()
100 );
101 let addr = match self.0.dial(addr) {
102 Ok(connec) => return Ok(EitherFuture::First(connec)),
103 Err(TransportError::MultiaddrNotSupported(addr)) => {
104 tracing::debug!(
105 address=%addr,
106 "Failed to dial address using {}",
107 std::any::type_name::<A>()
108 );
109 addr
110 }
111 Err(TransportError::Other(err)) => {
112 return Err(TransportError::Other(Either::Left(err)))
113 }
114 };
115
116 tracing::trace!(
117 address=%addr,
118 "Attempting to dial address using {}",
119 std::any::type_name::<A>()
120 );
121 let addr = match self.1.dial(addr) {
122 Ok(connec) => return Ok(EitherFuture::Second(connec)),
123 Err(TransportError::MultiaddrNotSupported(addr)) => {
124 tracing::debug!(
125 address=%addr,
126 "Failed to dial address using {}",
127 std::any::type_name::<A>()
128 );
129 addr
130 }
131 Err(TransportError::Other(err)) => {
132 return Err(TransportError::Other(Either::Right(err)))
133 }
134 };
135
136 Err(TransportError::MultiaddrNotSupported(addr))
137 }
138
139 fn dial_as_listener(
140 &mut self,
141 addr: Multiaddr,
142 ) -> Result<Self::Dial, TransportError<Self::Error>> {
143 let addr = match self.0.dial_as_listener(addr) {
144 Ok(connec) => return Ok(EitherFuture::First(connec)),
145 Err(TransportError::MultiaddrNotSupported(addr)) => addr,
146 Err(TransportError::Other(err)) => {
147 return Err(TransportError::Other(Either::Left(err)))
148 }
149 };
150
151 let addr = match self.1.dial_as_listener(addr) {
152 Ok(connec) => return Ok(EitherFuture::Second(connec)),
153 Err(TransportError::MultiaddrNotSupported(addr)) => addr,
154 Err(TransportError::Other(err)) => {
155 return Err(TransportError::Other(Either::Right(err)))
156 }
157 };
158
159 Err(TransportError::MultiaddrNotSupported(addr))
160 }
161
162 fn address_translation(&self, server: &Multiaddr, observed: &Multiaddr) -> Option<Multiaddr> {
163 if let Some(addr) = self.0.address_translation(server, observed) {
164 Some(addr)
165 } else {
166 self.1.address_translation(server, observed)
167 }
168 }
169
170 fn poll(
171 self: Pin<&mut Self>,
172 cx: &mut Context<'_>,
173 ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
174 let this = self.project();
175 match this.0.poll(cx) {
176 Poll::Ready(ev) => {
177 return Poll::Ready(ev.map_upgrade(EitherFuture::First).map_err(Either::Left))
178 }
179 Poll::Pending => {}
180 }
181 match this.1.poll(cx) {
182 Poll::Ready(ev) => {
183 return Poll::Ready(ev.map_upgrade(EitherFuture::Second).map_err(Either::Right))
184 }
185 Poll::Pending => {}
186 }
187 Poll::Pending
188 }
189}