From 4c07d65887ff5d39b3dd1150a209ddf5a684e7cd Mon Sep 17 00:00:00 2001 From: mexskican Date: Tue, 7 Dec 2021 22:14:10 -0800 Subject: [PATCH 1/7] swarm/src/either: impl `NetworkBehaviour` on `Either` Implement `NetworkBehaviour` on `either::Either` where both L and R both implement `NetworkBehaviour`. Add NetworkBehaviour derive tests for Either and Toggle --- swarm-derive/Cargo.toml | 1 + swarm-derive/tests/test.rs | 98 +++++++++++++++ swarm/src/behaviour.rs | 44 +++++++ swarm/src/either.rs | 248 +++++++++++++++++++++++++++++++++++++ swarm/src/lib.rs | 1 + 5 files changed, 392 insertions(+) create mode 100644 swarm/src/either.rs diff --git a/swarm-derive/Cargo.toml b/swarm-derive/Cargo.toml index e562859b522..c53240ada0d 100644 --- a/swarm-derive/Cargo.toml +++ b/swarm-derive/Cargo.toml @@ -19,4 +19,5 @@ quote = "1.0" [dev-dependencies] libp2p = { path = "../" } +either = "1.6.0" futures = "0.3.1" diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index 829c9b71e34..aa193b8b9b4 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -324,3 +324,101 @@ fn event_process_false() { }; } } + +#[test] +fn with_toggle() { + use libp2p::swarm::toggle::Toggle; + + #[allow(dead_code)] + #[derive(NetworkBehaviour)] + #[behaviour(event_process = true)] + struct Foo { + indentify: libp2p::identify::Identify, + ping: Toggle, + } + + impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { + fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {} + } + + impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { + fn inject_event(&mut self, _: libp2p::ping::PingEvent) {} + } + + #[allow(dead_code)] + fn foo() { + require_net_behaviour::(); + } +} + +#[test] +fn with_either() { + use either::Either; + + #[allow(dead_code)] + #[derive(NetworkBehaviour)] + #[behaviour(event_process = true)] + struct Foo { + kad: libp2p::kad::Kademlia, + ping_or_identify: Either, + } + + impl libp2p::swarm::NetworkBehaviourEventProcess for Foo { + fn inject_event(&mut self, _: libp2p::kad::KademliaEvent) {} + } + + impl + libp2p::swarm::NetworkBehaviourEventProcess< + Either, + > for Foo + { + fn inject_event( + &mut self, + _: Either, + ) { + } + } + + #[allow(dead_code)] + fn foo() { + require_net_behaviour::(); + } +} + +#[test] +fn no_event_with_either() { + use either::Either; + + enum BehaviourOutEvent { + Kad(libp2p::kad::KademliaEvent), + PingOrIdentify(Either), + } + + #[allow(dead_code)] + #[derive(NetworkBehaviour)] + #[behaviour(out_event = "BehaviourOutEvent", event_process = false)] + struct Foo { + kad: libp2p::kad::Kademlia, + ping_or_identify: Either, + } + + impl From for BehaviourOutEvent { + fn from(event: libp2p::kad::KademliaEvent) -> Self { + BehaviourOutEvent::Kad(event) + } + } + + impl From> for BehaviourOutEvent { + fn from(event: Either) -> Self { + match event { + Either::Left(event) => BehaviourOutEvent::PingOrIdentify(Either::Left(event)), + Either::Right(event) => BehaviourOutEvent::PingOrIdentify(Either::Right(event)), + } + } + } + + #[allow(dead_code)] + fn foo() { + require_net_behaviour::(); + } +} diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index f50b0250f6f..14e93287d05 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -621,6 +621,50 @@ where } } +impl NetworkBehaviourAction +where + THandlerOld: IntoProtocolsHandler, + ::Handler: ProtocolsHandler, +{ + /// Map the handler and hanlder event + pub fn map_handler_and_in_event( + self, + f_handler: impl FnOnce(THandlerOld) -> THandlerNew, + f_in_event: impl FnOnce(TInEventOld) -> TInEventNew, + ) -> NetworkBehaviourAction + where + THandlerNew: IntoProtocolsHandler, + ::Handler: ProtocolsHandler, + { + match self { + NetworkBehaviourAction::GenerateEvent(e) => NetworkBehaviourAction::GenerateEvent(e), + NetworkBehaviourAction::Dial { opts, handler } => NetworkBehaviourAction::Dial { + opts, + handler: f_handler(handler), + }, + NetworkBehaviourAction::NotifyHandler { + peer_id, + handler, + event, + } => NetworkBehaviourAction::NotifyHandler { + peer_id, + handler, + event: f_in_event(event), + }, + NetworkBehaviourAction::ReportObservedAddr { address, score } => { + NetworkBehaviourAction::ReportObservedAddr { address, score } + } + NetworkBehaviourAction::CloseConnection { + peer_id, + connection, + } => NetworkBehaviourAction::CloseConnection { + peer_id, + connection, + }, + } + } +} + /// The options w.r.t. which connection handler to notify of an event. #[derive(Debug, Clone)] pub enum NotifyHandler { diff --git a/swarm/src/either.rs b/swarm/src/either.rs new file mode 100644 index 00000000000..3b4c284ecc7 --- /dev/null +++ b/swarm/src/either.rs @@ -0,0 +1,248 @@ +// Copyright 2021 Protocol Labs. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +use crate::protocols_handler::{either::IntoEitherHandler, IntoProtocolsHandler, ProtocolsHandler}; +use crate::{ + DialError, NetworkBehaviour, NetworkBehaviourAction, NetworkBehaviourEventProcess, + PollParameters, +}; +use either::Either; +use libp2p_core::{ + connection::{ConnectionId, ListenerId}, + ConnectedPoint, Multiaddr, PeerId, +}; +use std::{task::Context, task::Poll}; + +/// Implementation of [`NetworkBehaviour`] that can be either of two implementations. +impl NetworkBehaviour for Either +where + L: NetworkBehaviour, + R: NetworkBehaviour, +{ + type ProtocolsHandler = IntoEitherHandler; + type OutEvent = Either; + + fn new_handler(&mut self) -> Self::ProtocolsHandler { + match self { + Either::Left(a) => IntoEitherHandler::Left(a.new_handler()), + Either::Right(b) => IntoEitherHandler::Right(b.new_handler()), + } + } + + fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { + match self { + Either::Left(a) => a.addresses_of_peer(peer_id), + Either::Right(b) => b.addresses_of_peer(peer_id), + } + } + + fn inject_connected(&mut self, peer_id: &PeerId) { + match self { + Either::Left(a) => a.inject_connected(peer_id), + Either::Right(b) => b.inject_connected(peer_id), + }; + } + + fn inject_disconnected(&mut self, peer_id: &PeerId) { + match self { + Either::Left(a) => a.inject_disconnected(peer_id), + Either::Right(b) => b.inject_disconnected(peer_id), + } + } + + fn inject_connection_established( + &mut self, + peer_id: &PeerId, + connection: &ConnectionId, + endpoint: &ConnectedPoint, + errors: Option<&Vec>, + ) { + match self { + Either::Left(a) => { + a.inject_connection_established(peer_id, connection, endpoint, errors) + } + Either::Right(b) => { + b.inject_connection_established(peer_id, connection, endpoint, errors) + } + } + } + + fn inject_connection_closed( + &mut self, + peer_id: &PeerId, + connection: &ConnectionId, + endpoint: &ConnectedPoint, + handler: ::Handler, + ) { + match (self, handler) { + (Either::Left(behaviour), Either::Left(handler)) => { + behaviour.inject_connection_closed(peer_id, connection, endpoint, handler) + } + (Either::Right(behaviour), Either::Right(handler)) => { + behaviour.inject_connection_closed(peer_id, connection, endpoint, handler) + } + _ => unreachable!(), + } + } + + fn inject_address_change( + &mut self, + peer_id: &PeerId, + connection: &ConnectionId, + old: &ConnectedPoint, + new: &ConnectedPoint, + ) { + match self { + Either::Left(a) => a.inject_address_change(peer_id, connection, old, new), + Either::Right(b) => b.inject_address_change(peer_id, connection, old, new), + } + } + + fn inject_event( + &mut self, + peer_id: PeerId, + connection: ConnectionId, + event: <::Handler as ProtocolsHandler>::OutEvent, + ) { + match (self, event) { + (Either::Left(behaviour), Either::Left(event)) => { + behaviour.inject_event(peer_id, connection, event) + } + (Either::Right(behaviour), Either::Right(event)) => { + behaviour.inject_event(peer_id, connection, event) + } + _ => unreachable!(), + } + } + + fn inject_dial_failure( + &mut self, + peer_id: Option, + handler: Self::ProtocolsHandler, + error: &DialError, + ) { + match (self, handler) { + (Either::Left(behaviour), IntoEitherHandler::Left(handler)) => { + behaviour.inject_dial_failure(peer_id, handler, error) + } + (Either::Right(behaviour), IntoEitherHandler::Right(handler)) => { + behaviour.inject_dial_failure(peer_id, handler, error) + } + _ => unreachable!(), + } + } + + fn inject_listen_failure( + &mut self, + local_addr: &Multiaddr, + send_back_addr: &Multiaddr, + handler: Self::ProtocolsHandler, + ) { + match (self, handler) { + (Either::Left(behaviour), IntoEitherHandler::Left(handler)) => { + behaviour.inject_listen_failure(local_addr, send_back_addr, handler) + } + (Either::Right(behaviour), IntoEitherHandler::Right(handler)) => { + behaviour.inject_listen_failure(local_addr, send_back_addr, handler) + } + _ => unreachable!(), + } + } + + fn inject_new_listener(&mut self, id: ListenerId) { + match self { + Either::Left(a) => a.inject_new_listener(id), + Either::Right(b) => b.inject_new_listener(id), + } + } + + fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { + match self { + Either::Left(a) => a.inject_new_listen_addr(id, addr), + Either::Right(b) => b.inject_new_listen_addr(id, addr), + } + } + + fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { + match self { + Either::Left(a) => a.inject_expired_listen_addr(id, addr), + Either::Right(b) => b.inject_expired_listen_addr(id, addr), + } + } + + fn inject_new_external_addr(&mut self, addr: &Multiaddr) { + match self { + Either::Left(a) => a.inject_new_external_addr(addr), + Either::Right(b) => b.inject_new_external_addr(addr), + } + } + + fn inject_expired_external_addr(&mut self, addr: &Multiaddr) { + match self { + Either::Left(a) => a.inject_expired_external_addr(addr), + Either::Right(b) => b.inject_expired_external_addr(addr), + } + } + + fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) { + match self { + Either::Left(a) => a.inject_listener_error(id, err), + Either::Right(b) => b.inject_listener_error(id, err), + } + } + + fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &std::io::Error>) { + match self { + Either::Left(a) => a.inject_listener_closed(id, reason), + Either::Right(b) => b.inject_listener_closed(id, reason), + } + } + + fn poll( + &mut self, + cx: &mut Context<'_>, + params: &mut impl PollParameters, + ) -> Poll> { + let event = match self { + Either::Left(behaviour) => futures::ready!(behaviour.poll(cx, params)) + .map_out(|h| Either::Left(h)) + .map_handler_and_in_event(|h| IntoEitherHandler::Left(h), |h| Either::Left(h)), + Either::Right(behaviour) => futures::ready!(behaviour.poll(cx, params)) + .map_out(|h| Either::Right(h)) + .map_handler_and_in_event(|h| IntoEitherHandler::Right(h), |h| Either::Right(h)), + }; + + Poll::Ready(event) + } +} + +impl NetworkBehaviourEventProcess + for Either +where + TBehaviourLeft: NetworkBehaviourEventProcess, + TBehaviourRight: NetworkBehaviourEventProcess, +{ + fn inject_event(&mut self, event: TEvent) { + match self { + Either::Left(a) => a.inject_event(event), + Either::Right(b) => b.inject_event(event), + } + } +} diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index c28bcee9dc4..34b6ce4249b 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -60,6 +60,7 @@ mod test; mod upgrade; pub mod dial_opts; +pub mod either; pub mod protocols_handler; pub mod toggle; From 6a3b489d71b9f062929e1a5ace0ce77be873ce36 Mon Sep 17 00:00:00 2001 From: mexskican Date: Wed, 8 Dec 2021 14:26:37 -0800 Subject: [PATCH 2/7] swarm/src: Fix minor naming inconsistency --- swarm-derive/tests/test.rs | 5 +---- swarm/src/behaviour.rs | 4 ++-- swarm/src/either.rs | 8 ++++---- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index aa193b8b9b4..b55601655f7 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -410,10 +410,7 @@ fn no_event_with_either() { impl From> for BehaviourOutEvent { fn from(event: Either) -> Self { - match event { - Either::Left(event) => BehaviourOutEvent::PingOrIdentify(Either::Left(event)), - Either::Right(event) => BehaviourOutEvent::PingOrIdentify(Either::Right(event)), - } + BehaviourOutEvent::PingOrIdentify(event) } } diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index 14e93287d05..f4001d9c4d4 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -626,8 +626,8 @@ where THandlerOld: IntoProtocolsHandler, ::Handler: ProtocolsHandler, { - /// Map the handler and hanlder event - pub fn map_handler_and_in_event( + /// Map the handler and handler event + pub fn map_handler_and_in( self, f_handler: impl FnOnce(THandlerOld) -> THandlerNew, f_in_event: impl FnOnce(TInEventOld) -> TInEventNew, diff --git a/swarm/src/either.rs b/swarm/src/either.rs index 3b4c284ecc7..3dd6d28a3d2 100644 --- a/swarm/src/either.rs +++ b/swarm/src/either.rs @@ -222,11 +222,11 @@ where ) -> Poll> { let event = match self { Either::Left(behaviour) => futures::ready!(behaviour.poll(cx, params)) - .map_out(|h| Either::Left(h)) - .map_handler_and_in_event(|h| IntoEitherHandler::Left(h), |h| Either::Left(h)), + .map_out(|e| Either::Left(e)) + .map_handler_and_in(|h| IntoEitherHandler::Left(h), |e| Either::Left(e)), Either::Right(behaviour) => futures::ready!(behaviour.poll(cx, params)) - .map_out(|h| Either::Right(h)) - .map_handler_and_in_event(|h| IntoEitherHandler::Right(h), |h| Either::Right(h)), + .map_out(|e| Either::Right(e)) + .map_handler_and_in(|h| IntoEitherHandler::Right(h), |e| Either::Right(e)), }; Poll::Ready(event) From 4b52c66023dbfb40acbee667cb4b67885ef411b8 Mon Sep 17 00:00:00 2001 From: mexskican Date: Wed, 8 Dec 2021 17:08:00 -0800 Subject: [PATCH 3/7] swarm-derive/test: Fix typo --- swarm-derive/tests/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index b55601655f7..1f40d505fae 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -333,7 +333,7 @@ fn with_toggle() { #[derive(NetworkBehaviour)] #[behaviour(event_process = true)] struct Foo { - indentify: libp2p::identify::Identify, + identify: libp2p::identify::Identify, ping: Toggle, } From c91aa923ef9721096f7539ec9698e59654e4c350 Mon Sep 17 00:00:00 2001 From: mexskican Date: Thu, 9 Dec 2021 17:42:47 -0800 Subject: [PATCH 4/7] swarm-derive/test: Fix Toggle NetworkBehaviour derive test import --- swarm-derive/tests/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swarm-derive/tests/test.rs b/swarm-derive/tests/test.rs index 1f40d505fae..c5182b0481a 100644 --- a/swarm-derive/tests/test.rs +++ b/swarm-derive/tests/test.rs @@ -327,7 +327,7 @@ fn event_process_false() { #[test] fn with_toggle() { - use libp2p::swarm::toggle::Toggle; + use libp2p::swarm::behaviour::toggle::Toggle; #[allow(dead_code)] #[derive(NetworkBehaviour)] From f1020e4a9caf0f62116d462ea55266cc5138eb9d Mon Sep 17 00:00:00 2001 From: mexskican Date: Thu, 9 Dec 2021 17:45:05 -0800 Subject: [PATCH 5/7] swarm/src/behaviour: Move `Either` into `swarm::behaviour` --- swarm/src/behaviour.rs | 1 + swarm/src/{ => behaviour}/either.rs | 0 swarm/src/lib.rs | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename swarm/src/{ => behaviour}/either.rs (100%) diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index e6af73c260c..5789570a110 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -18,6 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +pub mod either; pub mod toggle; use crate::dial_opts::DialOpts; diff --git a/swarm/src/either.rs b/swarm/src/behaviour/either.rs similarity index 100% rename from swarm/src/either.rs rename to swarm/src/behaviour/either.rs diff --git a/swarm/src/lib.rs b/swarm/src/lib.rs index c37da325445..25539294d8a 100644 --- a/swarm/src/lib.rs +++ b/swarm/src/lib.rs @@ -60,7 +60,6 @@ mod upgrade; pub mod behaviour; pub mod dial_opts; -pub mod either; pub mod protocols_handler; pub use behaviour::{ From 6968963a83f723312c7697a526412854152cebdf Mon Sep 17 00:00:00 2001 From: mexskican Date: Thu, 9 Dec 2021 17:46:22 -0800 Subject: [PATCH 6/7] swarm/CHANGELOG: Add PR info --- swarm/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/swarm/CHANGELOG.md b/swarm/CHANGELOG.md index 2e524f91fea..867d07a6a33 100644 --- a/swarm/CHANGELOG.md +++ b/swarm/CHANGELOG.md @@ -10,9 +10,12 @@ - Move `swarm::Toggle` to `swarm::behaviour::Toggle` (see [PR 2375]). +- Implement `swarm::NetworkBehaviour` on `either::Either` (see [PR 2370]). + [PR 2339]: https://github.com/libp2p/rust-libp2p/pull/2339 [PR 2350]: https://github.com/libp2p/rust-libp2p/pull/2350 [PR 2362]: https://github.com/libp2p/rust-libp2p/pull/2362 +[PR 2370]: https://github.com/libp2p/rust-libp2p/pull/2370 [PR 2375]: https://github.com/libp2p/rust-libp2p/pull/2375 # 0.32.0 [2021-11-16] From 694ca058c76e0e67fbcf5a95502dc7e589844f4c Mon Sep 17 00:00:00 2001 From: Max Inden Date: Sat, 11 Dec 2021 19:38:32 +0100 Subject: [PATCH 7/7] swarm/src/behaviour.rs: Add period on doc comment --- swarm/src/behaviour.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index 5789570a110..269bddf3bad 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -724,7 +724,7 @@ where THandlerOld: IntoProtocolsHandler, ::Handler: ProtocolsHandler, { - /// Map the handler and handler event + /// Map the handler and handler event. pub fn map_handler_and_in( self, f_handler: impl FnOnce(THandlerOld) -> THandlerNew,