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