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