libp2p_core/transport/
choice.rs

1// Copyright 2017 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21use 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/// Struct returned by `or_transport()`.
29#[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}