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