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 log::{debug, trace};
26use multiaddr::Multiaddr;
27use std::{pin::Pin, task::Context, task::Poll};
28
29/// Struct returned by `or_transport()`.
30#[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}