libp2p_core/transport/
choice.rs1use crate::either::EitherFuture;
22use crate::transport::{DialOpts, 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(
96 &mut self,
97 addr: Multiaddr,
98 opts: DialOpts,
99 ) -> Result<Self::Dial, TransportError<Self::Error>> {
100 tracing::trace!(
101 address=%addr,
102 "Attempting to dial using {}",
103 std::any::type_name::<A>()
104 );
105 let addr = match self.0.dial(addr, opts) {
106 Ok(connec) => return Ok(EitherFuture::First(connec)),
107 Err(TransportError::MultiaddrNotSupported(addr)) => {
108 tracing::debug!(
109 address=%addr,
110 "Failed to dial using {}",
111 std::any::type_name::<B>(),
112 );
113 addr
114 }
115 Err(TransportError::Other(err)) => {
116 return Err(TransportError::Other(Either::Left(err)))
117 }
118 };
119
120 tracing::trace!(
121 address=%addr,
122 "Attempting to dial {}",
123 std::any::type_name::<A>()
124 );
125 let addr = match self.1.dial(addr, opts) {
126 Ok(connec) => return Ok(EitherFuture::Second(connec)),
127 Err(TransportError::MultiaddrNotSupported(addr)) => {
128 tracing::debug!(
129 address=%addr,
130 "Failed to dial using {}",
131 std::any::type_name::<B>(),
132 );
133 addr
134 }
135 Err(TransportError::Other(err)) => {
136 return Err(TransportError::Other(Either::Right(err)))
137 }
138 };
139
140 Err(TransportError::MultiaddrNotSupported(addr))
141 }
142
143 fn poll(
144 self: Pin<&mut Self>,
145 cx: &mut Context<'_>,
146 ) -> Poll<TransportEvent<Self::ListenerUpgrade, Self::Error>> {
147 let this = self.project();
148 match this.0.poll(cx) {
149 Poll::Ready(ev) => {
150 return Poll::Ready(ev.map_upgrade(EitherFuture::First).map_err(Either::Left))
151 }
152 Poll::Pending => {}
153 }
154 match this.1.poll(cx) {
155 Poll::Ready(ev) => {
156 return Poll::Ready(ev.map_upgrade(EitherFuture::Second).map_err(Either::Right))
157 }
158 Poll::Pending => {}
159 }
160 Poll::Pending
161 }
162}