libp2p_swarm/behaviour/
either.rs

1// Copyright 2021 Protocol Labs.
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::behaviour::{self, NetworkBehaviour, ToSwarm};
22use crate::connection::ConnectionId;
23use crate::{ConnectionDenied, THandler, THandlerInEvent, THandlerOutEvent};
24use either::Either;
25use libp2p_core::transport::PortUse;
26use libp2p_core::{Endpoint, Multiaddr};
27use libp2p_identity::PeerId;
28use std::{task::Context, task::Poll};
29
30/// Implementation of [`NetworkBehaviour`] that can be either of two implementations.
31impl<L, R> NetworkBehaviour for Either<L, R>
32where
33    L: NetworkBehaviour,
34    R: NetworkBehaviour,
35{
36    type ConnectionHandler = Either<THandler<L>, THandler<R>>;
37    type ToSwarm = Either<L::ToSwarm, R::ToSwarm>;
38
39    fn handle_pending_inbound_connection(
40        &mut self,
41        id: ConnectionId,
42        local_addr: &Multiaddr,
43        remote_addr: &Multiaddr,
44    ) -> Result<(), ConnectionDenied> {
45        match self {
46            Either::Left(a) => a.handle_pending_inbound_connection(id, local_addr, remote_addr),
47            Either::Right(b) => b.handle_pending_inbound_connection(id, local_addr, remote_addr),
48        }
49    }
50
51    fn handle_established_inbound_connection(
52        &mut self,
53        connection_id: ConnectionId,
54        peer: PeerId,
55        local_addr: &Multiaddr,
56        remote_addr: &Multiaddr,
57    ) -> Result<THandler<Self>, ConnectionDenied> {
58        let handler = match self {
59            Either::Left(inner) => Either::Left(inner.handle_established_inbound_connection(
60                connection_id,
61                peer,
62                local_addr,
63                remote_addr,
64            )?),
65            Either::Right(inner) => Either::Right(inner.handle_established_inbound_connection(
66                connection_id,
67                peer,
68                local_addr,
69                remote_addr,
70            )?),
71        };
72
73        Ok(handler)
74    }
75
76    fn handle_pending_outbound_connection(
77        &mut self,
78        connection_id: ConnectionId,
79        maybe_peer: Option<PeerId>,
80        addresses: &[Multiaddr],
81        effective_role: Endpoint,
82    ) -> Result<Vec<Multiaddr>, ConnectionDenied> {
83        let addresses = match self {
84            Either::Left(inner) => inner.handle_pending_outbound_connection(
85                connection_id,
86                maybe_peer,
87                addresses,
88                effective_role,
89            )?,
90            Either::Right(inner) => inner.handle_pending_outbound_connection(
91                connection_id,
92                maybe_peer,
93                addresses,
94                effective_role,
95            )?,
96        };
97
98        Ok(addresses)
99    }
100
101    fn handle_established_outbound_connection(
102        &mut self,
103        connection_id: ConnectionId,
104        peer: PeerId,
105        addr: &Multiaddr,
106        role_override: Endpoint,
107        port_use: PortUse,
108    ) -> Result<THandler<Self>, ConnectionDenied> {
109        let handler = match self {
110            Either::Left(inner) => Either::Left(inner.handle_established_outbound_connection(
111                connection_id,
112                peer,
113                addr,
114                role_override,
115                port_use,
116            )?),
117            Either::Right(inner) => Either::Right(inner.handle_established_outbound_connection(
118                connection_id,
119                peer,
120                addr,
121                role_override,
122                port_use,
123            )?),
124        };
125
126        Ok(handler)
127    }
128
129    fn on_swarm_event(&mut self, event: behaviour::FromSwarm) {
130        match self {
131            Either::Left(b) => b.on_swarm_event(event),
132            Either::Right(b) => b.on_swarm_event(event),
133        }
134    }
135
136    fn on_connection_handler_event(
137        &mut self,
138        peer_id: PeerId,
139        connection_id: ConnectionId,
140        event: THandlerOutEvent<Self>,
141    ) {
142        match (self, event) {
143            (Either::Left(left), Either::Left(event)) => {
144                left.on_connection_handler_event(peer_id, connection_id, event);
145            }
146            (Either::Right(right), Either::Right(event)) => {
147                right.on_connection_handler_event(peer_id, connection_id, event);
148            }
149            _ => unreachable!(),
150        }
151    }
152
153    fn poll(
154        &mut self,
155        cx: &mut Context<'_>,
156    ) -> Poll<ToSwarm<Self::ToSwarm, THandlerInEvent<Self>>> {
157        let event = match self {
158            Either::Left(behaviour) => futures::ready!(behaviour.poll(cx))
159                .map_out(Either::Left)
160                .map_in(Either::Left),
161            Either::Right(behaviour) => futures::ready!(behaviour.poll(cx))
162                .map_out(Either::Right)
163                .map_in(Either::Right),
164        };
165
166        Poll::Ready(event)
167    }
168}