swarm/behaviour: Replace inject_* with on_event (#3011)

This commit is contained in:
João Oliveira
2022-11-17 09:28:40 +00:00
committed by GitHub
parent a714864885
commit 3df3c88f3d
38 changed files with 2482 additions and 1652 deletions

View File

@ -6,6 +6,11 @@
- Update to `libp2p-request-response` `v0.23.0`. - Update to `libp2p-request-response` `v0.23.0`.
- Replace `Behaviour`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
# 0.8.0 # 0.8.0
- Update to `libp2p-core` `v0.37.0`. - Update to `libp2p-core` `v0.37.0`.

View File

@ -29,15 +29,19 @@ pub use as_server::{InboundProbeError, InboundProbeEvent};
use futures_timer::Delay; use futures_timer::Delay;
use instant::Instant; use instant::Instant;
use libp2p_core::{ use libp2p_core::{
connection::ConnectionId, multiaddr::Protocol, transport::ListenerId, ConnectedPoint, Endpoint, connection::ConnectionId, multiaddr::Protocol, ConnectedPoint, Endpoint, Multiaddr, PeerId,
Multiaddr, PeerId,
}; };
use libp2p_request_response::{ use libp2p_request_response::{
handler::RequestResponseHandlerEvent, ProtocolSupport, RequestId, RequestResponse, ProtocolSupport, RequestId, RequestResponse, RequestResponseConfig, RequestResponseEvent,
RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, ResponseChannel, RequestResponseMessage, ResponseChannel,
}; };
use libp2p_swarm::{ use libp2p_swarm::{
DialError, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters, behaviour::{
AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredExternalAddr,
ExpiredListenAddr, FromSwarm,
},
ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction,
PollParameters,
}; };
use std::{ use std::{
collections::{HashMap, VecDeque}, collections::{HashMap, VecDeque},
@ -298,28 +302,17 @@ impl Behaviour {
ongoing_inbound: &mut self.ongoing_inbound, ongoing_inbound: &mut self.ongoing_inbound,
} }
} }
}
impl NetworkBehaviour for Behaviour { fn on_connection_established(
type ConnectionHandler = <RequestResponse<AutoNatCodec> as NetworkBehaviour>::ConnectionHandler;
type OutEvent = Event;
fn inject_connection_established(
&mut self, &mut self,
peer: &PeerId, ConnectionEstablished {
conn: &ConnectionId, peer_id: peer,
endpoint: &ConnectedPoint, connection_id: conn,
failed_addresses: Option<&Vec<Multiaddr>>,
other_established: usize,
) {
self.inner.inject_connection_established(
peer,
conn,
endpoint, endpoint,
failed_addresses, ..
other_established, }: ConnectionEstablished,
); ) {
let connections = self.connected.entry(*peer).or_default(); let connections = self.connected.entry(peer).or_default();
let addr = endpoint.get_remote_address(); let addr = endpoint.get_remote_address();
let observed_addr = let observed_addr =
if !endpoint.is_relayed() && (!self.config.only_global_ips || addr.is_global_ip()) { if !endpoint.is_relayed() && (!self.config.only_global_ips || addr.is_global_ip()) {
@ -327,14 +320,14 @@ impl NetworkBehaviour for Behaviour {
} else { } else {
None None
}; };
connections.insert(*conn, observed_addr); connections.insert(conn, observed_addr);
match endpoint { match endpoint {
ConnectedPoint::Dialer { ConnectedPoint::Dialer {
address, address,
role_override: Endpoint::Dialer, role_override: Endpoint::Dialer,
} => { } => {
if let Some(event) = self.as_server().on_outbound_connection(peer, address) { if let Some(event) = self.as_server().on_outbound_connection(&peer, address) {
self.pending_out_events self.pending_out_events
.push_back(Event::InboundProbe(event)); .push_back(Event::InboundProbe(event));
} }
@ -351,50 +344,69 @@ impl NetworkBehaviour for Behaviour {
} }
} }
fn inject_connection_closed( fn on_connection_closed(
&mut self, &mut self,
peer: &PeerId, ConnectionClosed {
conn: &ConnectionId, peer_id,
endpoint: &ConnectedPoint, connection_id,
handler: <Self::ConnectionHandler as IntoConnectionHandler>::Handler, endpoint,
remaining_established: usize, handler,
remaining_established,
}: ConnectionClosed<<Self as NetworkBehaviour>::ConnectionHandler>,
) { ) {
self.inner self.inner
.inject_connection_closed(peer, conn, endpoint, handler, remaining_established); .on_swarm_event(FromSwarm::ConnectionClosed(ConnectionClosed {
peer_id,
connection_id,
endpoint,
handler,
remaining_established,
}));
if remaining_established == 0 { if remaining_established == 0 {
self.connected.remove(peer); self.connected.remove(&peer_id);
} else { } else {
let connections = self.connected.get_mut(peer).expect("Peer is connected."); let connections = self
connections.remove(conn); .connected
.get_mut(&peer_id)
.expect("Peer is connected.");
connections.remove(&connection_id);
} }
} }
fn inject_dial_failure( fn on_dial_failure(
&mut self, &mut self,
peer: Option<PeerId>, DialFailure {
handler: Self::ConnectionHandler, peer_id,
error: &DialError, handler,
error,
}: DialFailure<<Self as NetworkBehaviour>::ConnectionHandler>,
) { ) {
self.inner.inject_dial_failure(peer, handler, error); self.inner
if let Some(event) = self.as_server().on_outbound_dial_error(peer, error) { .on_swarm_event(FromSwarm::DialFailure(DialFailure {
peer_id,
handler,
error,
}));
if let Some(event) = self.as_server().on_outbound_dial_error(peer_id, error) {
self.pending_out_events self.pending_out_events
.push_back(Event::InboundProbe(event)); .push_back(Event::InboundProbe(event));
} }
} }
fn inject_address_change( fn on_address_change(
&mut self, &mut self,
peer: &PeerId, AddressChange {
conn: &ConnectionId, peer_id: peer,
old: &ConnectedPoint, connection_id: conn,
new: &ConnectedPoint, old,
new,
}: AddressChange,
) { ) {
self.inner.inject_address_change(peer, conn, old, new);
if old.is_relayed() && new.is_relayed() { if old.is_relayed() && new.is_relayed() {
return; return;
} }
let connections = self.connected.get_mut(peer).expect("Peer is connected."); let connections = self.connected.get_mut(&peer).expect("Peer is connected.");
let addr = new.get_remote_address(); let addr = new.get_remote_address();
let observed_addr = let observed_addr =
if !new.is_relayed() && (!self.config.only_global_ips || addr.is_global_ip()) { if !new.is_relayed() && (!self.config.only_global_ips || addr.is_global_ip()) {
@ -402,28 +414,13 @@ impl NetworkBehaviour for Behaviour {
} else { } else {
None None
}; };
connections.insert(*conn, observed_addr); connections.insert(conn, observed_addr);
} }
}
fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) { impl NetworkBehaviour for Behaviour {
self.inner.inject_new_listen_addr(id, addr); type ConnectionHandler = <RequestResponse<AutoNatCodec> as NetworkBehaviour>::ConnectionHandler;
self.as_client().on_new_address(); type OutEvent = Event;
}
fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) {
self.inner.inject_expired_listen_addr(id, addr);
self.as_client().on_expired_address(addr);
}
fn inject_new_external_addr(&mut self, addr: &Multiaddr) {
self.inner.inject_new_external_addr(addr);
self.as_client().on_new_address();
}
fn inject_expired_external_addr(&mut self, addr: &Multiaddr) {
self.inner.inject_expired_external_addr(addr);
self.as_client().on_expired_address(addr);
}
fn poll(&mut self, cx: &mut Context<'_>, params: &mut impl PollParameters) -> Poll<Action> { fn poll(&mut self, cx: &mut Context<'_>, params: &mut impl PollParameters) -> Poll<Action> {
loop { loop {
@ -478,35 +475,65 @@ impl NetworkBehaviour for Behaviour {
self.inner.addresses_of_peer(peer) self.inner.addresses_of_peer(peer)
} }
fn inject_event( fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(connection_established) => {
self.inner
.on_swarm_event(FromSwarm::ConnectionEstablished(connection_established));
self.on_connection_established(connection_established)
}
FromSwarm::ConnectionClosed(connection_closed) => {
self.on_connection_closed(connection_closed)
}
FromSwarm::DialFailure(dial_failure) => self.on_dial_failure(dial_failure),
FromSwarm::AddressChange(address_change) => {
self.inner
.on_swarm_event(FromSwarm::AddressChange(address_change));
self.on_address_change(address_change)
}
listen_addr @ FromSwarm::NewListenAddr(_) => {
self.inner.on_swarm_event(listen_addr);
self.as_client().on_new_address();
}
FromSwarm::ExpiredListenAddr(ExpiredListenAddr { listener_id, addr }) => {
self.inner
.on_swarm_event(FromSwarm::ExpiredListenAddr(ExpiredListenAddr {
listener_id,
addr,
}));
self.as_client().on_expired_address(addr);
}
FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }) => {
self.inner
.on_swarm_event(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }));
self.as_client().on_expired_address(addr);
}
external_addr @ FromSwarm::NewExternalAddr(_) => {
self.inner.on_swarm_event(external_addr);
self.as_client().on_new_address();
}
listen_failure @ FromSwarm::ListenFailure(_) => {
self.inner.on_swarm_event(listen_failure)
}
new_listener @ FromSwarm::NewListener(_) => self.inner.on_swarm_event(new_listener),
listener_error @ FromSwarm::ListenerError(_) => {
self.inner.on_swarm_event(listener_error)
}
listener_closed @ FromSwarm::ListenerClosed(_) => {
self.inner.on_swarm_event(listener_closed)
}
}
}
fn on_connection_handler_event(
&mut self, &mut self,
peer_id: PeerId, peer_id: PeerId,
conn: ConnectionId, connection_id: ConnectionId,
event: RequestResponseHandlerEvent<AutoNatCodec>, event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as
) { ConnectionHandler>::OutEvent,
self.inner.inject_event(peer_id, conn, event)
}
fn inject_listen_failure(
&mut self,
local_addr: &Multiaddr,
send_back_addr: &Multiaddr,
handler: Self::ConnectionHandler,
) { ) {
self.inner self.inner
.inject_listen_failure(local_addr, send_back_addr, handler) .on_connection_handler_event(peer_id, connection_id, event)
}
fn inject_new_listener(&mut self, id: ListenerId) {
self.inner.inject_new_listener(id)
}
fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) {
self.inner.inject_listener_error(id, err)
}
fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &std::io::Error>) {
self.inner.inject_listener_closed(id, reason)
} }
} }

View File

@ -6,6 +6,11 @@
- Update to `libp2p-swarm` `v0.41.0`. - Update to `libp2p-swarm` `v0.41.0`.
- Replace `Behaviour`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
# 0.7.0 # 0.7.0
- Update to `libp2p-core` `v0.37.0`. - Update to `libp2p-core` `v0.37.0`.

View File

@ -26,10 +26,11 @@ use either::Either;
use libp2p_core::connection::{ConnectedPoint, ConnectionId}; use libp2p_core::connection::{ConnectedPoint, ConnectionId};
use libp2p_core::multiaddr::Protocol; use libp2p_core::multiaddr::Protocol;
use libp2p_core::{Multiaddr, PeerId}; use libp2p_core::{Multiaddr, PeerId};
use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm};
use libp2p_swarm::dial_opts::{self, DialOpts}; use libp2p_swarm::dial_opts::{self, DialOpts};
use libp2p_swarm::{ use libp2p_swarm::{
ConnectionHandler, ConnectionHandlerUpgrErr, DialError, IntoConnectionHandler, ConnectionHandler, ConnectionHandlerUpgrErr, IntoConnectionHandler, NetworkBehaviour,
NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, NetworkBehaviourAction, NotifyHandler, PollParameters,
}; };
use std::collections::{HashMap, HashSet, VecDeque}; use std::collections::{HashMap, HashSet, VecDeque};
use std::task::{Context, Poll}; use std::task::{Context, Poll};
@ -81,30 +82,18 @@ impl Behaviour {
direct_connections: Default::default(), direct_connections: Default::default(),
} }
} }
}
impl NetworkBehaviour for Behaviour { fn on_connection_established(
type ConnectionHandler = handler::Prototype;
type OutEvent = Event;
fn new_handler(&mut self) -> Self::ConnectionHandler {
handler::Prototype::UnknownConnection
}
fn addresses_of_peer(&mut self, _peer_id: &PeerId) -> Vec<Multiaddr> {
vec![]
}
fn inject_connection_established(
&mut self, &mut self,
peer_id: &PeerId, ConnectionEstablished {
connection_id: &ConnectionId, peer_id,
connected_point: &ConnectedPoint, connection_id,
_failed_addresses: Option<&Vec<Multiaddr>>, endpoint: connected_point,
_other_established: usize, ..
}: ConnectionEstablished,
) { ) {
if connected_point.is_relayed() { if connected_point.is_relayed() {
if connected_point.is_listener() && !self.direct_connections.contains_key(peer_id) { if connected_point.is_listener() && !self.direct_connections.contains_key(&peer_id) {
// TODO: Try dialing the remote peer directly. Specification: // TODO: Try dialing the remote peer directly. Specification:
// //
// > The protocol starts with the completion of a relay connection from A to B. Upon // > The protocol starts with the completion of a relay connection from A to B. Upon
@ -116,13 +105,13 @@ impl NetworkBehaviour for Behaviour {
// https://github.com/libp2p/specs/blob/master/relay/DCUtR.md#the-protocol // https://github.com/libp2p/specs/blob/master/relay/DCUtR.md#the-protocol
self.queued_actions.extend([ self.queued_actions.extend([
ActionBuilder::Connect { ActionBuilder::Connect {
peer_id: *peer_id, peer_id,
attempt: 1, attempt: 1,
handler: NotifyHandler::One(*connection_id), handler: NotifyHandler::One(connection_id),
}, },
NetworkBehaviourAction::GenerateEvent( NetworkBehaviourAction::GenerateEvent(
Event::InitiatedDirectConnectionUpgrade { Event::InitiatedDirectConnectionUpgrade {
remote_peer_id: *peer_id, remote_peer_id: peer_id,
local_relayed_addr: match connected_point { local_relayed_addr: match connected_point {
ConnectedPoint::Listener { local_addr, .. } => local_addr.clone(), ConnectedPoint::Listener { local_addr, .. } => local_addr.clone(),
ConnectedPoint::Dialer { .. } => unreachable!("Due to outer if."), ConnectedPoint::Dialer { .. } => unreachable!("Due to outer if."),
@ -134,17 +123,17 @@ impl NetworkBehaviour for Behaviour {
} }
} else { } else {
self.direct_connections self.direct_connections
.entry(*peer_id) .entry(peer_id)
.or_default() .or_default()
.insert(*connection_id); .insert(connection_id);
} }
} }
fn inject_dial_failure( fn on_dial_failure(
&mut self, &mut self,
peer_id: Option<PeerId>, DialFailure {
handler: Self::ConnectionHandler, peer_id, handler, ..
_error: &DialError, }: DialFailure<<Self as NetworkBehaviour>::ConnectionHandler>,
) { ) {
if let handler::Prototype::DirectConnection { if let handler::Prototype::DirectConnection {
relayed_connection_id, relayed_connection_id,
@ -178,34 +167,45 @@ impl NetworkBehaviour for Behaviour {
} }
} }
fn inject_connection_closed( fn on_connection_closed(
&mut self, &mut self,
peer_id: &PeerId, ConnectionClosed {
connection_id: &ConnectionId, peer_id,
connected_point: &ConnectedPoint, connection_id,
_handler: <<Self as NetworkBehaviour>::ConnectionHandler as IntoConnectionHandler>::Handler, endpoint: connected_point,
_remaining_established: usize, ..
}: ConnectionClosed<<Self as NetworkBehaviour>::ConnectionHandler>,
) { ) {
if !connected_point.is_relayed() { if !connected_point.is_relayed() {
let connections = self let connections = self
.direct_connections .direct_connections
.get_mut(peer_id) .get_mut(&peer_id)
.expect("Peer of direct connection to be tracked."); .expect("Peer of direct connection to be tracked.");
connections connections
.remove(connection_id) .remove(&connection_id)
.then(|| ()) .then(|| ())
.expect("Direct connection to be tracked."); .expect("Direct connection to be tracked.");
if connections.is_empty() { if connections.is_empty() {
self.direct_connections.remove(peer_id); self.direct_connections.remove(&peer_id);
} }
} }
} }
}
fn inject_event( impl NetworkBehaviour for Behaviour {
type ConnectionHandler = handler::Prototype;
type OutEvent = Event;
fn new_handler(&mut self) -> Self::ConnectionHandler {
handler::Prototype::UnknownConnection
}
fn on_connection_handler_event(
&mut self, &mut self,
event_source: PeerId, event_source: PeerId,
connection: ConnectionId, connection: ConnectionId,
handler_event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent, handler_event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as
ConnectionHandler>::OutEvent,
) { ) {
match handler_event { match handler_event {
Either::Left(handler::relayed::Event::InboundConnectRequest { Either::Left(handler::relayed::Event::InboundConnectRequest {
@ -316,6 +316,27 @@ impl NetworkBehaviour for Behaviour {
Poll::Pending Poll::Pending
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(connection_established) => {
self.on_connection_established(connection_established)
}
FromSwarm::ConnectionClosed(connection_closed) => {
self.on_connection_closed(connection_closed)
}
FromSwarm::DialFailure(dial_failure) => self.on_dial_failure(dial_failure),
FromSwarm::AddressChange(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }
/// A [`NetworkBehaviourAction`], either complete, or still requiring data from [`PollParameters`] /// A [`NetworkBehaviourAction`], either complete, or still requiring data from [`PollParameters`]

View File

@ -4,6 +4,11 @@
- Update to `libp2p-swarm` `v0.41.0`. - Update to `libp2p-swarm` `v0.41.0`.
- Replace `Floodsub`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
# 0.40.0 # 0.40.0
- Bump rand to 0.8 and quickcheck to 1. See [PR 2857]. - Bump rand to 0.8 and quickcheck to 1. See [PR 2857].

View File

@ -27,11 +27,12 @@ use crate::FloodsubConfig;
use cuckoofilter::{CuckooError, CuckooFilter}; use cuckoofilter::{CuckooError, CuckooFilter};
use fnv::FnvHashSet; use fnv::FnvHashSet;
use libp2p_core::{connection::ConnectionId, PeerId}; use libp2p_core::{connection::ConnectionId, PeerId};
use libp2p_core::{ConnectedPoint, Multiaddr}; use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, FromSwarm};
use libp2p_swarm::{ use libp2p_swarm::{
dial_opts::DialOpts, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, OneShotHandler, dial_opts::DialOpts, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, OneShotHandler,
PollParameters, PollParameters,
}; };
use libp2p_swarm::{ConnectionHandler, IntoConnectionHandler};
use log::warn; use log::warn;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::collections::hash_map::{DefaultHasher, HashMap}; use std::collections::hash_map::{DefaultHasher, HashMap};
@ -276,23 +277,14 @@ impl Floodsub {
}); });
} }
} }
}
impl NetworkBehaviour for Floodsub { fn on_connection_established(
type ConnectionHandler = OneShotHandler<FloodsubProtocol, FloodsubRpc, InnerMessage>;
type OutEvent = FloodsubEvent;
fn new_handler(&mut self) -> Self::ConnectionHandler {
Default::default()
}
fn inject_connection_established(
&mut self, &mut self,
id: &PeerId, ConnectionEstablished {
_: &ConnectionId, peer_id,
_: &ConnectedPoint, other_established,
_: Option<&Vec<Multiaddr>>, ..
other_established: usize, }: ConnectionEstablished,
) { ) {
if other_established > 0 { if other_established > 0 {
// We only care about the first time a peer connects. // We only care about the first time a peer connects.
@ -300,11 +292,11 @@ impl NetworkBehaviour for Floodsub {
} }
// We need to send our subscriptions to the newly-connected node. // We need to send our subscriptions to the newly-connected node.
if self.target_peers.contains(id) { if self.target_peers.contains(&peer_id) {
for topic in self.subscribed_topics.iter().cloned() { for topic in self.subscribed_topics.iter().cloned() {
self.events self.events
.push_back(NetworkBehaviourAction::NotifyHandler { .push_back(NetworkBehaviourAction::NotifyHandler {
peer_id: *id, peer_id,
handler: NotifyHandler::Any, handler: NotifyHandler::Any,
event: FloodsubRpc { event: FloodsubRpc {
messages: Vec::new(), messages: Vec::new(),
@ -317,41 +309,51 @@ impl NetworkBehaviour for Floodsub {
} }
} }
self.connected_peers.insert(*id, SmallVec::new()); self.connected_peers.insert(peer_id, SmallVec::new());
} }
fn inject_connection_closed( fn on_connection_closed(
&mut self, &mut self,
id: &PeerId, ConnectionClosed {
_: &ConnectionId, peer_id,
_: &ConnectedPoint, remaining_established,
_: Self::ConnectionHandler, ..
remaining_established: usize, }: ConnectionClosed<<Self as NetworkBehaviour>::ConnectionHandler>,
) { ) {
if remaining_established > 0 { if remaining_established > 0 {
// we only care about peer disconnections // we only care about peer disconnections
return; return;
} }
let was_in = self.connected_peers.remove(id); let was_in = self.connected_peers.remove(&peer_id);
debug_assert!(was_in.is_some()); debug_assert!(was_in.is_some());
// We can be disconnected by the remote in case of inactivity for example, so we always // We can be disconnected by the remote in case of inactivity for example, so we always
// try to reconnect. // try to reconnect.
if self.target_peers.contains(id) { if self.target_peers.contains(&peer_id) {
let handler = self.new_handler(); let handler = self.new_handler();
self.events.push_back(NetworkBehaviourAction::Dial { self.events.push_back(NetworkBehaviourAction::Dial {
opts: DialOpts::peer_id(*id).build(), opts: DialOpts::peer_id(peer_id).build(),
handler, handler,
}); });
} }
} }
}
fn inject_event( impl NetworkBehaviour for Floodsub {
type ConnectionHandler = OneShotHandler<FloodsubProtocol, FloodsubRpc, InnerMessage>;
type OutEvent = FloodsubEvent;
fn new_handler(&mut self) -> Self::ConnectionHandler {
Default::default()
}
fn on_connection_handler_event(
&mut self, &mut self,
propagation_source: PeerId, propagation_source: PeerId,
_connection: ConnectionId, _connection_id: ConnectionId,
event: InnerMessage, event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as
ConnectionHandler>::OutEvent,
) { ) {
// We ignore successful sends or timeouts. // We ignore successful sends or timeouts.
let event = match event { let event = match event {
@ -477,6 +479,27 @@ impl NetworkBehaviour for Floodsub {
Poll::Pending Poll::Pending
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(connection_established) => {
self.on_connection_established(connection_established)
}
FromSwarm::ConnectionClosed(connection_closed) => {
self.on_connection_closed(connection_closed)
}
FromSwarm::AddressChange(_)
| FromSwarm::DialFailure(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }
/// Transmission between the `OneShotHandler` and the `FloodsubHandler`. /// Transmission between the `OneShotHandler` and the `FloodsubHandler`.

View File

@ -8,7 +8,11 @@
- Refactoring GossipsubCodec to use common protobuf Codec. See [PR 3070]. - Refactoring GossipsubCodec to use common protobuf Codec. See [PR 3070].
- Replace `Gossipsub`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
[PR 3070]: https://github.com/libp2p/rust-libp2p/pull/3070 [PR 3070]: https://github.com/libp2p/rust-libp2p/pull/3070
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
# 0.42.0 # 0.42.0

View File

@ -38,10 +38,12 @@ use rand::{seq::SliceRandom, thread_rng};
use libp2p_core::{ use libp2p_core::{
connection::ConnectionId, identity::Keypair, multiaddr::Protocol::Ip4, connection::ConnectionId, identity::Keypair, multiaddr::Protocol::Ip4,
multiaddr::Protocol::Ip6, ConnectedPoint, Multiaddr, PeerId, multiaddr::Protocol::Ip6, Multiaddr, PeerId,
}; };
use libp2p_swarm::{ use libp2p_swarm::{
dial_opts::DialOpts, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, behaviour::{AddressChange, ConnectionClosed, ConnectionEstablished, FromSwarm},
dial_opts::DialOpts,
ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction,
NotifyHandler, PollParameters, NotifyHandler, PollParameters,
}; };
use wasm_timer::Instant; use wasm_timer::Instant;
@ -3028,6 +3030,261 @@ where
Ok(rpc_list) Ok(rpc_list)
} }
fn on_connection_established(
&mut self,
ConnectionEstablished {
peer_id,
connection_id,
endpoint,
other_established,
..
}: ConnectionEstablished,
) {
// Diverging from the go implementation we only want to consider a peer as outbound peer
// if its first connection is outbound.
if endpoint.is_dialer() && other_established == 0 && !self.px_peers.contains(&peer_id) {
// The first connection is outbound and it is not a peer from peer exchange => mark
// it as outbound peer
self.outbound_peers.insert(peer_id);
}
// Add the IP to the peer scoring system
if let Some((peer_score, ..)) = &mut self.peer_score {
if let Some(ip) = get_ip_addr(endpoint.get_remote_address()) {
peer_score.add_ip(&peer_id, ip);
} else {
trace!(
"Couldn't extract ip from endpoint of peer {} with endpoint {:?}",
peer_id,
endpoint
)
}
}
// By default we assume a peer is only a floodsub peer.
//
// The protocol negotiation occurs once a message is sent/received. Once this happens we
// update the type of peer that this is in order to determine which kind of routing should
// occur.
self.connected_peers
.entry(peer_id)
.or_insert(PeerConnections {
kind: PeerKind::Floodsub,
connections: vec![],
})
.connections
.push(connection_id);
if other_established == 0 {
// Ignore connections from blacklisted peers.
if self.blacklisted_peers.contains(&peer_id) {
debug!("Ignoring connection from blacklisted peer: {}", peer_id);
} else {
debug!("New peer connected: {}", peer_id);
// We need to send our subscriptions to the newly-connected node.
let mut subscriptions = vec![];
for topic_hash in self.mesh.keys() {
subscriptions.push(GossipsubSubscription {
topic_hash: topic_hash.clone(),
action: GossipsubSubscriptionAction::Subscribe,
});
}
if !subscriptions.is_empty() {
// send our subscriptions to the peer
if self
.send_message(
peer_id,
GossipsubRpc {
messages: Vec::new(),
subscriptions,
control_msgs: Vec::new(),
}
.into_protobuf(),
)
.is_err()
{
error!("Failed to send subscriptions, message too large");
}
}
}
// Insert an empty set of the topics of this peer until known.
self.peer_topics.insert(peer_id, Default::default());
if let Some((peer_score, ..)) = &mut self.peer_score {
peer_score.add_peer(peer_id);
}
}
}
fn on_connection_closed(
&mut self,
ConnectionClosed {
peer_id,
connection_id,
endpoint,
remaining_established,
..
}: ConnectionClosed<<Self as NetworkBehaviour>::ConnectionHandler>,
) {
// Remove IP from peer scoring system
if let Some((peer_score, ..)) = &mut self.peer_score {
if let Some(ip) = get_ip_addr(endpoint.get_remote_address()) {
peer_score.remove_ip(&peer_id, &ip);
} else {
trace!(
"Couldn't extract ip from endpoint of peer {} with endpoint {:?}",
peer_id,
endpoint
)
}
}
if remaining_established != 0 {
// Remove the connection from the list
if let Some(connections) = self.connected_peers.get_mut(&peer_id) {
let index = connections
.connections
.iter()
.position(|v| v == &connection_id)
.expect("Previously established connection to peer must be present");
connections.connections.remove(index);
// If there are more connections and this peer is in a mesh, inform the first connection
// handler.
if !connections.connections.is_empty() {
if let Some(topics) = self.peer_topics.get(&peer_id) {
for topic in topics {
if let Some(mesh_peers) = self.mesh.get(topic) {
if mesh_peers.contains(&peer_id) {
self.events
.push_back(NetworkBehaviourAction::NotifyHandler {
peer_id,
event: Arc::new(GossipsubHandlerIn::JoinedMesh),
handler: NotifyHandler::One(connections.connections[0]),
});
break;
}
}
}
}
}
}
} else {
// remove from mesh, topic_peers, peer_topic and the fanout
debug!("Peer disconnected: {}", peer_id);
{
let topics = match self.peer_topics.get(&peer_id) {
Some(topics) => topics,
None => {
debug_assert!(
self.blacklisted_peers.contains(&peer_id),
"Disconnected node not in connected list"
);
return;
}
};
// remove peer from all mappings
for topic in topics {
// check the mesh for the topic
if let Some(mesh_peers) = self.mesh.get_mut(topic) {
// check if the peer is in the mesh and remove it
if mesh_peers.remove(&peer_id) {
if let Some(m) = self.metrics.as_mut() {
m.peers_removed(topic, Churn::Dc, 1);
m.set_mesh_peers(topic, mesh_peers.len());
}
};
}
// remove from topic_peers
if let Some(peer_list) = self.topic_peers.get_mut(topic) {
if !peer_list.remove(&peer_id) {
// debugging purposes
warn!(
"Disconnected node: {} not in topic_peers peer list",
peer_id
);
}
if let Some(m) = self.metrics.as_mut() {
m.set_topic_peers(topic, peer_list.len())
}
} else {
warn!(
"Disconnected node: {} with topic: {:?} not in topic_peers",
&peer_id, &topic
);
}
// remove from fanout
self.fanout
.get_mut(topic)
.map(|peers| peers.remove(&peer_id));
}
}
// Forget px and outbound status for this peer
self.px_peers.remove(&peer_id);
self.outbound_peers.remove(&peer_id);
// Remove peer from peer_topics and connected_peers
// NOTE: It is possible the peer has already been removed from all mappings if it does not
// support the protocol.
self.peer_topics.remove(&peer_id);
// If metrics are enabled, register the disconnection of a peer based on its protocol.
if let Some(metrics) = self.metrics.as_mut() {
let peer_kind = &self
.connected_peers
.get(&peer_id)
.expect("Connected peer must be registered")
.kind;
metrics.peer_protocol_disconnected(peer_kind.clone());
}
self.connected_peers.remove(&peer_id);
if let Some((peer_score, ..)) = &mut self.peer_score {
peer_score.remove_peer(&peer_id);
}
}
}
fn on_address_change(
&mut self,
AddressChange {
peer_id,
old: endpoint_old,
new: endpoint_new,
..
}: AddressChange,
) {
// Exchange IP in peer scoring system
if let Some((peer_score, ..)) = &mut self.peer_score {
if let Some(ip) = get_ip_addr(endpoint_old.get_remote_address()) {
peer_score.remove_ip(&peer_id, &ip);
} else {
trace!(
"Couldn't extract ip from endpoint of peer {} with endpoint {:?}",
&peer_id,
endpoint_old
)
}
if let Some(ip) = get_ip_addr(endpoint_new.get_remote_address()) {
peer_score.add_ip(&peer_id, ip);
} else {
trace!(
"Couldn't extract ip from endpoint of peer {} with endpoint {:?}",
peer_id,
endpoint_new
)
}
}
}
} }
fn get_ip_addr(addr: &Multiaddr) -> Option<IpAddr> { fn get_ip_addr(addr: &Multiaddr) -> Option<IpAddr> {
@ -3058,260 +3315,12 @@ where
GossipsubHandler::new(protocol_config, self.config.idle_timeout()) GossipsubHandler::new(protocol_config, self.config.idle_timeout())
} }
fn inject_connection_established( fn on_connection_handler_event(
&mut self,
peer_id: &PeerId,
connection_id: &ConnectionId,
endpoint: &ConnectedPoint,
_: Option<&Vec<Multiaddr>>,
other_established: usize,
) {
// Diverging from the go implementation we only want to consider a peer as outbound peer
// if its first connection is outbound.
if endpoint.is_dialer() && other_established == 0 && !self.px_peers.contains(peer_id) {
// The first connection is outbound and it is not a peer from peer exchange => mark
// it as outbound peer
self.outbound_peers.insert(*peer_id);
}
// Add the IP to the peer scoring system
if let Some((peer_score, ..)) = &mut self.peer_score {
if let Some(ip) = get_ip_addr(endpoint.get_remote_address()) {
peer_score.add_ip(peer_id, ip);
} else {
trace!(
"Couldn't extract ip from endpoint of peer {} with endpoint {:?}",
peer_id,
endpoint
)
}
}
// By default we assume a peer is only a floodsub peer.
//
// The protocol negotiation occurs once a message is sent/received. Once this happens we
// update the type of peer that this is in order to determine which kind of routing should
// occur.
self.connected_peers
.entry(*peer_id)
.or_insert(PeerConnections {
kind: PeerKind::Floodsub,
connections: vec![],
})
.connections
.push(*connection_id);
if other_established == 0 {
// Ignore connections from blacklisted peers.
if self.blacklisted_peers.contains(peer_id) {
debug!("Ignoring connection from blacklisted peer: {}", peer_id);
} else {
debug!("New peer connected: {}", peer_id);
// We need to send our subscriptions to the newly-connected node.
let mut subscriptions = vec![];
for topic_hash in self.mesh.keys() {
subscriptions.push(GossipsubSubscription {
topic_hash: topic_hash.clone(),
action: GossipsubSubscriptionAction::Subscribe,
});
}
if !subscriptions.is_empty() {
// send our subscriptions to the peer
if self
.send_message(
*peer_id,
GossipsubRpc {
messages: Vec::new(),
subscriptions,
control_msgs: Vec::new(),
}
.into_protobuf(),
)
.is_err()
{
error!("Failed to send subscriptions, message too large");
}
}
}
// Insert an empty set of the topics of this peer until known.
self.peer_topics.insert(*peer_id, Default::default());
if let Some((peer_score, ..)) = &mut self.peer_score {
peer_score.add_peer(*peer_id);
}
}
}
fn inject_connection_closed(
&mut self,
peer_id: &PeerId,
connection_id: &ConnectionId,
endpoint: &ConnectedPoint,
_: <Self::ConnectionHandler as IntoConnectionHandler>::Handler,
remaining_established: usize,
) {
// Remove IP from peer scoring system
if let Some((peer_score, ..)) = &mut self.peer_score {
if let Some(ip) = get_ip_addr(endpoint.get_remote_address()) {
peer_score.remove_ip(peer_id, &ip);
} else {
trace!(
"Couldn't extract ip from endpoint of peer {} with endpoint {:?}",
peer_id,
endpoint
)
}
}
if remaining_established != 0 {
// Remove the connection from the list
if let Some(connections) = self.connected_peers.get_mut(peer_id) {
let index = connections
.connections
.iter()
.position(|v| v == connection_id)
.expect("Previously established connection to peer must be present");
connections.connections.remove(index);
// If there are more connections and this peer is in a mesh, inform the first connection
// handler.
if !connections.connections.is_empty() {
if let Some(topics) = self.peer_topics.get(peer_id) {
for topic in topics {
if let Some(mesh_peers) = self.mesh.get(topic) {
if mesh_peers.contains(peer_id) {
self.events
.push_back(NetworkBehaviourAction::NotifyHandler {
peer_id: *peer_id,
event: Arc::new(GossipsubHandlerIn::JoinedMesh),
handler: NotifyHandler::One(connections.connections[0]),
});
break;
}
}
}
}
}
}
} else {
// remove from mesh, topic_peers, peer_topic and the fanout
debug!("Peer disconnected: {}", peer_id);
{
let topics = match self.peer_topics.get(peer_id) {
Some(topics) => topics,
None => {
debug_assert!(
self.blacklisted_peers.contains(peer_id),
"Disconnected node not in connected list"
);
return;
}
};
// remove peer from all mappings
for topic in topics {
// check the mesh for the topic
if let Some(mesh_peers) = self.mesh.get_mut(topic) {
// check if the peer is in the mesh and remove it
if mesh_peers.remove(peer_id) {
if let Some(m) = self.metrics.as_mut() {
m.peers_removed(topic, Churn::Dc, 1);
m.set_mesh_peers(topic, mesh_peers.len());
}
};
}
// remove from topic_peers
if let Some(peer_list) = self.topic_peers.get_mut(topic) {
if !peer_list.remove(peer_id) {
// debugging purposes
warn!(
"Disconnected node: {} not in topic_peers peer list",
peer_id
);
}
if let Some(m) = self.metrics.as_mut() {
m.set_topic_peers(topic, peer_list.len())
}
} else {
warn!(
"Disconnected node: {} with topic: {:?} not in topic_peers",
&peer_id, &topic
);
}
// remove from fanout
self.fanout
.get_mut(topic)
.map(|peers| peers.remove(peer_id));
}
}
// Forget px and outbound status for this peer
self.px_peers.remove(peer_id);
self.outbound_peers.remove(peer_id);
// Remove peer from peer_topics and connected_peers
// NOTE: It is possible the peer has already been removed from all mappings if it does not
// support the protocol.
self.peer_topics.remove(peer_id);
// If metrics are enabled, register the disconnection of a peer based on its protocol.
if let Some(metrics) = self.metrics.as_mut() {
let peer_kind = &self
.connected_peers
.get(peer_id)
.expect("Connected peer must be registered")
.kind;
metrics.peer_protocol_disconnected(peer_kind.clone());
}
self.connected_peers.remove(peer_id);
if let Some((peer_score, ..)) = &mut self.peer_score {
peer_score.remove_peer(peer_id);
}
}
}
fn inject_address_change(
&mut self,
peer: &PeerId,
_: &ConnectionId,
endpoint_old: &ConnectedPoint,
endpoint_new: &ConnectedPoint,
) {
// Exchange IP in peer scoring system
if let Some((peer_score, ..)) = &mut self.peer_score {
if let Some(ip) = get_ip_addr(endpoint_old.get_remote_address()) {
peer_score.remove_ip(peer, &ip);
} else {
trace!(
"Couldn't extract ip from endpoint of peer {} with endpoint {:?}",
peer,
endpoint_old
)
}
if let Some(ip) = get_ip_addr(endpoint_new.get_remote_address()) {
peer_score.add_ip(peer, ip);
} else {
trace!(
"Couldn't extract ip from endpoint of peer {} with endpoint {:?}",
peer,
endpoint_new
)
}
}
}
fn inject_event(
&mut self, &mut self,
propagation_source: PeerId, propagation_source: PeerId,
_: ConnectionId, _connection_id: ConnectionId,
handler_event: HandlerEvent, handler_event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as
ConnectionHandler>::OutEvent,
) { ) {
match handler_event { match handler_event {
HandlerEvent::PeerKind(kind) => { HandlerEvent::PeerKind(kind) => {
@ -3333,7 +3342,8 @@ where
)); ));
} else if let Some(conn) = self.connected_peers.get_mut(&propagation_source) { } else if let Some(conn) = self.connected_peers.get_mut(&propagation_source) {
// Only change the value if the old value is Floodsub (the default set in // Only change the value if the old value is Floodsub (the default set in
// inject_connection_established). All other PeerKind changes are ignored. // `NetworkBehaviour::on_event` with FromSwarm::ConnectionEstablished).
// All other PeerKind changes are ignored.
debug!( debug!(
"New peer type found: {} for peer: {}", "New peer type found: {} for peer: {}",
kind, propagation_source kind, propagation_source
@ -3458,6 +3468,27 @@ where
Poll::Pending Poll::Pending
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(connection_established) => {
self.on_connection_established(connection_established)
}
FromSwarm::ConnectionClosed(connection_closed) => {
self.on_connection_closed(connection_closed)
}
FromSwarm::AddressChange(address_change) => self.on_address_change(address_change),
FromSwarm::DialFailure(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }
/// This is called when peers are added to any mesh. It checks if the peer existed /// This is called when peers are added to any mesh. It checks if the peer existed

View File

@ -31,7 +31,7 @@ use crate::{
}; };
use async_std::net::Ipv4Addr; use async_std::net::Ipv4Addr;
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use libp2p_core::Endpoint; use libp2p_core::{ConnectedPoint, Endpoint};
use rand::Rng; use rand::Rng;
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@ -181,25 +181,27 @@ where
F: TopicSubscriptionFilter + Clone + Default + Send + 'static, F: TopicSubscriptionFilter + Clone + Default + Send + 'static,
{ {
let peer = PeerId::random(); let peer = PeerId::random();
gs.inject_connection_established( let endpoint = if outbound {
&peer, ConnectedPoint::Dialer {
&ConnectionId::new(0), address,
&if outbound { role_override: Endpoint::Dialer,
ConnectedPoint::Dialer { }
address, } else {
role_override: Endpoint::Dialer, ConnectedPoint::Listener {
} local_addr: Multiaddr::empty(),
} else { send_back_addr: address,
ConnectedPoint::Listener { }
local_addr: Multiaddr::empty(), };
send_back_addr: address,
} gs.on_swarm_event(FromSwarm::ConnectionEstablished(ConnectionEstablished {
}, peer_id: peer,
None, connection_id: ConnectionId::new(0),
0, // first connection endpoint: &endpoint,
); failed_addresses: &[],
other_established: 0, // first connection
}));
if let Some(kind) = kind { if let Some(kind) = kind {
gs.inject_event(peer, ConnectionId::new(1), HandlerEvent::PeerKind(kind)); gs.on_connection_handler_event(peer, ConnectionId::new(1), HandlerEvent::PeerKind(kind));
} }
if explicit { if explicit {
gs.add_explicit_peer(&peer); gs.add_explicit_peer(&peer);
@ -232,16 +234,16 @@ where
}; // this is not relevant }; // this is not relevant
// peer_connections.connections should never be empty. // peer_connections.connections should never be empty.
let mut active_connections = peer_connections.connections.len(); let mut active_connections = peer_connections.connections.len();
for conn_id in peer_connections.connections.clone() { for connection_id in peer_connections.connections.clone() {
let handler = gs.new_handler(); let handler = gs.new_handler();
active_connections = active_connections.checked_sub(1).unwrap(); active_connections = active_connections.checked_sub(1).unwrap();
gs.inject_connection_closed( gs.on_swarm_event(FromSwarm::ConnectionClosed(ConnectionClosed {
peer_id, peer_id: *peer_id,
&conn_id, connection_id,
&fake_endpoint, endpoint: &fake_endpoint,
handler, handler,
active_connections, remaining_established: active_connections,
); }));
} }
} }
} }
@ -545,16 +547,16 @@ fn test_join() {
for _ in 0..3 { for _ in 0..3 {
let random_peer = PeerId::random(); let random_peer = PeerId::random();
// inform the behaviour of a new peer // inform the behaviour of a new peer
gs.inject_connection_established( gs.on_swarm_event(FromSwarm::ConnectionEstablished(ConnectionEstablished {
&random_peer, peer_id: random_peer,
&ConnectionId::new(1), connection_id: ConnectionId::new(1),
&ConnectedPoint::Dialer { endpoint: &ConnectedPoint::Dialer {
address: "/ip4/127.0.0.1".parse::<Multiaddr>().unwrap(), address: "/ip4/127.0.0.1".parse::<Multiaddr>().unwrap(),
role_override: Endpoint::Dialer, role_override: Endpoint::Dialer,
}, },
None, failed_addresses: &[],
0, other_established: 0,
); }));
// add the new peer to the fanout // add the new peer to the fanout
let fanout_peers = gs.fanout.get_mut(&topic_hashes[1]).unwrap(); let fanout_peers = gs.fanout.get_mut(&topic_hashes[1]).unwrap();
@ -2349,12 +2351,6 @@ fn test_add_outbound_peers_if_min_is_not_satisfied() {
); );
} }
//TODO add a test that ensures that new outbound connections are recognized as such.
// This is at the moment done in behaviour with relying on the fact that the call to
// `inject_connection_established` for the first connection is done before `inject_connected`
// gets called. For all further connections `inject_connection_established` should get called
// after `inject_connected`.
#[test] #[test]
fn test_prune_negative_scored_peers() { fn test_prune_negative_scored_peers() {
let config = GossipsubConfig::default(); let config = GossipsubConfig::default();
@ -2983,7 +2979,7 @@ fn test_ignore_rpc_from_peers_below_graylist_threshold() {
gs.events.clear(); gs.events.clear();
//receive from p1 //receive from p1
gs.inject_event( gs.on_connection_handler_event(
p1, p1,
ConnectionId::new(0), ConnectionId::new(0),
HandlerEvent::Message { HandlerEvent::Message {
@ -3009,7 +3005,7 @@ fn test_ignore_rpc_from_peers_below_graylist_threshold() {
}; };
//receive from p2 //receive from p2
gs.inject_event( gs.on_connection_handler_event(
p2, p2,
ConnectionId::new(0), ConnectionId::new(0),
HandlerEvent::Message { HandlerEvent::Message {
@ -3621,7 +3617,7 @@ fn test_scoring_p4_invalid_signature() {
//peer 0 delivers message with invalid signature //peer 0 delivers message with invalid signature
let m = random_message(&mut seq, &topics); let m = random_message(&mut seq, &topics);
gs.inject_event( gs.on_connection_handler_event(
peers[0], peers[0],
ConnectionId::new(0), ConnectionId::new(0),
HandlerEvent::Message { HandlerEvent::Message {
@ -4105,16 +4101,16 @@ fn test_scoring_p6() {
//add additional connection for 3 others with addr //add additional connection for 3 others with addr
for id in others.iter().take(3) { for id in others.iter().take(3) {
gs.inject_connection_established( gs.on_swarm_event(FromSwarm::ConnectionEstablished(ConnectionEstablished {
id, peer_id: *id,
&ConnectionId::new(0), connection_id: ConnectionId::new(0),
&ConnectedPoint::Dialer { endpoint: &ConnectedPoint::Dialer {
address: addr.clone(), address: addr.clone(),
role_override: Endpoint::Dialer, role_override: Endpoint::Dialer,
}, },
None, failed_addresses: &[],
0, other_established: 0,
); }));
} }
//penalties apply squared //penalties apply squared
@ -4126,16 +4122,16 @@ fn test_scoring_p6() {
//add additional connection for 3 of the peers to addr2 //add additional connection for 3 of the peers to addr2
for peer in peers.iter().take(3) { for peer in peers.iter().take(3) {
gs.inject_connection_established( gs.on_swarm_event(FromSwarm::ConnectionEstablished(ConnectionEstablished {
peer, peer_id: *peer,
&ConnectionId::new(0), connection_id: ConnectionId::new(0),
&ConnectedPoint::Dialer { endpoint: &ConnectedPoint::Dialer {
address: addr2.clone(), address: addr2.clone(),
role_override: Endpoint::Dialer, role_override: Endpoint::Dialer,
}, },
None, failed_addresses: &[],
1, other_established: 1,
); }));
} }
//double penalties for the first three of each //double penalties for the first three of each
@ -4156,16 +4152,16 @@ fn test_scoring_p6() {
); );
//two times same ip doesn't count twice //two times same ip doesn't count twice
gs.inject_connection_established( gs.on_swarm_event(FromSwarm::ConnectionEstablished(ConnectionEstablished {
&peers[0], peer_id: peers[0],
&ConnectionId::new(0), connection_id: ConnectionId::new(0),
&ConnectedPoint::Dialer { endpoint: &ConnectedPoint::Dialer {
address: addr, address: addr,
role_override: Endpoint::Dialer, role_override: Endpoint::Dialer,
}, },
None, failed_addresses: &[],
2, other_established: 2,
); }));
//nothing changed //nothing changed
//double penalties for the first three of each //double penalties for the first three of each
@ -5203,7 +5199,7 @@ fn test_subscribe_and_graft_with_negative_score() {
_ => None, _ => None,
}); });
for message in messages_to_p1 { for message in messages_to_p1 {
gs1.inject_event( gs1.on_connection_handler_event(
p2, p2,
connection_id, connection_id,
HandlerEvent::Message { HandlerEvent::Message {

View File

@ -8,6 +8,10 @@
- Update to `libp2p-swarm` `v0.41.0`. - Update to `libp2p-swarm` `v0.41.0`.
- Replace `Behaviour`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
[PR 2995]: https://github.com/libp2p/rust-libp2p/pull/2995 [PR 2995]: https://github.com/libp2p/rust-libp2p/pull/2995
# 0.40.0 # 0.40.0

View File

@ -22,9 +22,9 @@ use crate::handler::{self, Proto, Push};
use crate::protocol::{Info, ReplySubstream, UpgradeError}; use crate::protocol::{Info, ReplySubstream, UpgradeError};
use futures::prelude::*; use futures::prelude::*;
use libp2p_core::{ use libp2p_core::{
connection::ConnectionId, multiaddr::Protocol, transport::ListenerId, ConnectedPoint, connection::ConnectionId, multiaddr::Protocol, ConnectedPoint, Multiaddr, PeerId, PublicKey,
Multiaddr, PeerId, PublicKey,
}; };
use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm};
use libp2p_swarm::{ use libp2p_swarm::{
dial_opts::DialOpts, AddressScore, ConnectionHandler, ConnectionHandlerUpgrErr, DialError, dial_opts::DialOpts, AddressScore, ConnectionHandler, ConnectionHandlerUpgrErr, DialError,
IntoConnectionHandler, NegotiatedSubstream, NetworkBehaviour, NetworkBehaviourAction, IntoConnectionHandler, NegotiatedSubstream, NetworkBehaviour, NetworkBehaviourAction,
@ -206,6 +206,33 @@ impl Behaviour {
} }
} }
} }
fn on_connection_established(
&mut self,
ConnectionEstablished {
peer_id,
connection_id: conn,
endpoint,
failed_addresses,
..
}: ConnectionEstablished,
) {
let addr = match endpoint {
ConnectedPoint::Dialer { address, .. } => address.clone(),
ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr.clone(),
};
self.connected
.entry(peer_id)
.or_default()
.insert(conn, addr);
if let Some(entry) = self.discovered_peers.get_mut(&peer_id) {
for addr in failed_addresses {
entry.remove(addr);
}
}
}
} }
impl NetworkBehaviour for Behaviour { impl NetworkBehaviour for Behaviour {
@ -216,84 +243,7 @@ impl NetworkBehaviour for Behaviour {
Proto::new(self.config.initial_delay, self.config.interval) Proto::new(self.config.initial_delay, self.config.interval)
} }
fn inject_connection_established( fn on_connection_handler_event(
&mut self,
peer_id: &PeerId,
conn: &ConnectionId,
endpoint: &ConnectedPoint,
failed_addresses: Option<&Vec<Multiaddr>>,
_other_established: usize,
) {
let addr = match endpoint {
ConnectedPoint::Dialer { address, .. } => address.clone(),
ConnectedPoint::Listener { send_back_addr, .. } => send_back_addr.clone(),
};
self.connected
.entry(*peer_id)
.or_default()
.insert(*conn, addr);
if let Some(entry) = self.discovered_peers.get_mut(peer_id) {
for addr in failed_addresses
.into_iter()
.flat_map(|addresses| addresses.iter())
{
entry.remove(addr);
}
}
}
fn inject_connection_closed(
&mut self,
peer_id: &PeerId,
conn: &ConnectionId,
_: &ConnectedPoint,
_: <Self::ConnectionHandler as IntoConnectionHandler>::Handler,
remaining_established: usize,
) {
if remaining_established == 0 {
self.connected.remove(peer_id);
self.pending_push.remove(peer_id);
} else if let Some(addrs) = self.connected.get_mut(peer_id) {
addrs.remove(conn);
}
}
fn inject_dial_failure(
&mut self,
peer_id: Option<PeerId>,
_: Self::ConnectionHandler,
error: &DialError,
) {
if let Some(peer_id) = peer_id {
if !self.connected.contains_key(&peer_id) {
self.pending_push.remove(&peer_id);
}
}
if let Some(entry) = peer_id.and_then(|id| self.discovered_peers.get_mut(&id)) {
if let DialError::Transport(errors) = error {
for (addr, _error) in errors {
entry.remove(addr);
}
}
}
}
fn inject_new_listen_addr(&mut self, _id: ListenerId, _addr: &Multiaddr) {
if self.config.push_listen_addr_updates {
self.pending_push.extend(self.connected.keys());
}
}
fn inject_expired_listen_addr(&mut self, _id: ListenerId, _addr: &Multiaddr) {
if self.config.push_listen_addr_updates {
self.pending_push.extend(self.connected.keys());
}
}
fn inject_event(
&mut self, &mut self,
peer_id: PeerId, peer_id: PeerId,
connection: ConnectionId, connection: ConnectionId,
@ -333,8 +283,9 @@ impl NetworkBehaviour for Behaviour {
.get(&peer_id) .get(&peer_id)
.and_then(|addrs| addrs.get(&connection)) .and_then(|addrs| addrs.get(&connection))
.expect( .expect(
"`inject_event` is only called with an established connection \ "`on_connection_handler_event` is only called \
and `inject_connection_established` ensures there is an entry; qed", with an established connection and calling `NetworkBehaviour::on_event` \
with `FromSwarm::ConnectionEstablished ensures there is an entry; qed",
); );
self.pending_replies.push_back(Reply::Queued { self.pending_replies.push_back(Reply::Queued {
peer: peer_id, peer: peer_id,
@ -452,6 +403,59 @@ impl NetworkBehaviour for Behaviour {
fn addresses_of_peer(&mut self, peer: &PeerId) -> Vec<Multiaddr> { fn addresses_of_peer(&mut self, peer: &PeerId) -> Vec<Multiaddr> {
self.discovered_peers.get(peer) self.discovered_peers.get(peer)
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(connection_established) => {
self.on_connection_established(connection_established)
}
FromSwarm::ConnectionClosed(ConnectionClosed {
peer_id,
connection_id,
remaining_established,
..
}) => {
if remaining_established == 0 {
self.connected.remove(&peer_id);
self.pending_push.remove(&peer_id);
} else if let Some(addrs) = self.connected.get_mut(&peer_id) {
addrs.remove(&connection_id);
}
}
FromSwarm::DialFailure(DialFailure { peer_id, error, .. }) => {
if let Some(peer_id) = peer_id {
if !self.connected.contains_key(&peer_id) {
self.pending_push.remove(&peer_id);
}
}
if let Some(entry) = peer_id.and_then(|id| self.discovered_peers.get_mut(&id)) {
if let DialError::Transport(errors) = error {
for (addr, _error) in errors {
entry.remove(addr);
}
}
}
}
FromSwarm::NewListenAddr(_) => {
if self.config.push_listen_addr_updates {
self.pending_push.extend(self.connected.keys());
}
}
FromSwarm::ExpiredListenAddr(_) => {
if self.config.push_listen_addr_updates {
self.pending_push.extend(self.connected.keys());
}
}
FromSwarm::AddressChange(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }
/// Event emitted by the `Identify` behaviour. /// Event emitted by the `Identify` behaviour.

View File

@ -4,6 +4,11 @@
- Update to `libp2p-swarm` `v0.41.0`. - Update to `libp2p-swarm` `v0.41.0`.
- Replace `Kademlia`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
# 0.41.0 # 0.41.0
- Remove deprecated `set_protocol_name()` from `KademliaConfig` & `KademliaProtocolConfig`. - Remove deprecated `set_protocol_name()` from `KademliaConfig` & `KademliaProtocolConfig`.

View File

@ -39,8 +39,10 @@ use crate::record::{
use crate::K_VALUE; use crate::K_VALUE;
use fnv::{FnvHashMap, FnvHashSet}; use fnv::{FnvHashMap, FnvHashSet};
use instant::Instant; use instant::Instant;
use libp2p_core::{ use libp2p_core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId};
connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId, use libp2p_swarm::behaviour::{
AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredListenAddr,
FromSwarm, NewExternalAddr, NewListenAddr,
}; };
use libp2p_swarm::{ use libp2p_swarm::{
dial_opts::{self, DialOpts}, dial_opts::{self, DialOpts},
@ -1771,6 +1773,166 @@ where
} }
} }
} }
fn on_connection_established(
&mut self,
ConnectionEstablished {
peer_id,
failed_addresses,
other_established,
..
}: ConnectionEstablished,
) {
for addr in failed_addresses {
self.address_failed(peer_id, addr);
}
// When a connection is established, we don't know yet whether the
// remote supports the configured protocol name. Only once a connection
// handler reports [`KademliaHandlerEvent::ProtocolConfirmed`] do we
// update the local routing table.
// Peer's first connection.
if other_established == 0 {
// Queue events for sending pending RPCs to the connected peer.
// There can be only one pending RPC for a particular peer and query per definition.
for (peer_id, event) in self.queries.iter_mut().filter_map(|q| {
q.inner
.pending_rpcs
.iter()
.position(|(p, _)| p == &peer_id)
.map(|p| q.inner.pending_rpcs.remove(p))
}) {
self.queued_events
.push_back(NetworkBehaviourAction::NotifyHandler {
peer_id,
event,
handler: NotifyHandler::Any,
});
}
self.connected_peers.insert(peer_id);
}
}
fn on_address_change(
&mut self,
AddressChange {
peer_id: peer,
old,
new,
..
}: AddressChange,
) {
let (old, new) = (old.get_remote_address(), new.get_remote_address());
// Update routing table.
if let Some(addrs) = self.kbuckets.entry(&kbucket::Key::from(peer)).value() {
if addrs.replace(old, new) {
debug!(
"Address '{}' replaced with '{}' for peer '{}'.",
old, new, peer
);
} else {
debug!(
"Address '{}' not replaced with '{}' for peer '{}' as old address wasn't \
present.",
old, new, peer
);
}
} else {
debug!(
"Address '{}' not replaced with '{}' for peer '{}' as peer is not present in the \
routing table.",
old, new, peer
);
}
// Update query address cache.
//
// Given two connected nodes: local node A and remote node B. Say node B
// is not in node A's routing table. Additionally node B is part of the
// `QueryInner::addresses` list of an ongoing query on node A. Say Node
// B triggers an address change and then disconnects. Later on the
// earlier mentioned query on node A would like to connect to node B.
// Without replacing the address in the `QueryInner::addresses` set node
// A would attempt to dial the old and not the new address.
//
// While upholding correctness, iterating through all discovered
// addresses of a peer in all currently ongoing queries might have a
// large performance impact. If so, the code below might be worth
// revisiting.
for query in self.queries.iter_mut() {
if let Some(addrs) = query.inner.addresses.get_mut(&peer) {
for addr in addrs.iter_mut() {
if addr == old {
*addr = new.clone();
}
}
}
}
}
fn on_dial_failure(
&mut self,
DialFailure { peer_id, error, .. }: DialFailure<
<Self as NetworkBehaviour>::ConnectionHandler,
>,
) {
let peer_id = match peer_id {
Some(id) => id,
// Not interested in dial failures to unknown peers.
None => return,
};
match error {
DialError::Banned
| DialError::ConnectionLimit(_)
| DialError::LocalPeerId
| DialError::InvalidPeerId { .. }
| DialError::WrongPeerId { .. }
| DialError::Aborted
| DialError::ConnectionIo(_)
| DialError::Transport(_)
| DialError::NoAddresses => {
if let DialError::Transport(addresses) = error {
for (addr, _) in addresses {
self.address_failed(peer_id, addr)
}
}
for query in self.queries.iter_mut() {
query.on_failure(&peer_id);
}
}
DialError::DialPeerConditionFalse(
dial_opts::PeerCondition::Disconnected | dial_opts::PeerCondition::NotDialing,
) => {
// We might (still) be connected, or about to be connected, thus do not report the
// failure to the queries.
}
DialError::DialPeerConditionFalse(dial_opts::PeerCondition::Always) => {
unreachable!("DialPeerCondition::Always can not trigger DialPeerConditionFalse.");
}
}
}
fn on_connection_closed(
&mut self,
ConnectionClosed {
peer_id,
remaining_established,
..
}: ConnectionClosed<<Self as NetworkBehaviour>::ConnectionHandler>,
) {
if remaining_established == 0 {
for query in self.queries.iter_mut() {
query.on_failure(&peer_id);
}
self.connection_updated(peer_id, None, NodeStatus::Disconnected);
self.connected_peers.remove(&peer_id);
}
}
} }
/// Exponentially decrease the given duration (base 2). /// Exponentially decrease the given duration (base 2).
@ -1817,164 +1979,7 @@ where
peer_addrs peer_addrs
} }
fn inject_connection_established( fn on_connection_handler_event(
&mut self,
peer_id: &PeerId,
_: &ConnectionId,
_: &ConnectedPoint,
errors: Option<&Vec<Multiaddr>>,
other_established: usize,
) {
for addr in errors.map(|a| a.iter()).into_iter().flatten() {
self.address_failed(*peer_id, addr);
}
// When a connection is established, we don't know yet whether the
// remote supports the configured protocol name. Only once a connection
// handler reports [`KademliaHandlerEvent::ProtocolConfirmed`] do we
// update the local routing table.
// Peer's first connection.
if other_established == 0 {
// Queue events for sending pending RPCs to the connected peer.
// There can be only one pending RPC for a particular peer and query per definition.
for (peer_id, event) in self.queries.iter_mut().filter_map(|q| {
q.inner
.pending_rpcs
.iter()
.position(|(p, _)| p == peer_id)
.map(|p| q.inner.pending_rpcs.remove(p))
}) {
self.queued_events
.push_back(NetworkBehaviourAction::NotifyHandler {
peer_id,
event,
handler: NotifyHandler::Any,
});
}
self.connected_peers.insert(*peer_id);
}
}
fn inject_address_change(
&mut self,
peer: &PeerId,
_: &ConnectionId,
old: &ConnectedPoint,
new: &ConnectedPoint,
) {
let (old, new) = (old.get_remote_address(), new.get_remote_address());
// Update routing table.
if let Some(addrs) = self.kbuckets.entry(&kbucket::Key::from(*peer)).value() {
if addrs.replace(old, new) {
debug!(
"Address '{}' replaced with '{}' for peer '{}'.",
old, new, peer
);
} else {
debug!(
"Address '{}' not replaced with '{}' for peer '{}' as old address wasn't \
present.",
old, new, peer,
);
}
} else {
debug!(
"Address '{}' not replaced with '{}' for peer '{}' as peer is not present in the \
routing table.",
old, new, peer,
);
}
// Update query address cache.
//
// Given two connected nodes: local node A and remote node B. Say node B
// is not in node A's routing table. Additionally node B is part of the
// `QueryInner::addresses` list of an ongoing query on node A. Say Node
// B triggers an address change and then disconnects. Later on the
// earlier mentioned query on node A would like to connect to node B.
// Without replacing the address in the `QueryInner::addresses` set node
// A would attempt to dial the old and not the new address.
//
// While upholding correctness, iterating through all discovered
// addresses of a peer in all currently ongoing queries might have a
// large performance impact. If so, the code below might be worth
// revisiting.
for query in self.queries.iter_mut() {
if let Some(addrs) = query.inner.addresses.get_mut(peer) {
for addr in addrs.iter_mut() {
if addr == old {
*addr = new.clone();
}
}
}
}
}
fn inject_dial_failure(
&mut self,
peer_id: Option<PeerId>,
_: Self::ConnectionHandler,
error: &DialError,
) {
let peer_id = match peer_id {
Some(id) => id,
// Not interested in dial failures to unknown peers.
None => return,
};
match error {
DialError::Banned
| DialError::ConnectionLimit(_)
| DialError::LocalPeerId
| DialError::InvalidPeerId { .. }
| DialError::WrongPeerId { .. }
| DialError::Aborted
| DialError::ConnectionIo(_)
| DialError::Transport(_)
| DialError::NoAddresses => {
if let DialError::Transport(addresses) = error {
for (addr, _) in addresses {
self.address_failed(peer_id, addr)
}
}
for query in self.queries.iter_mut() {
query.on_failure(&peer_id);
}
}
DialError::DialPeerConditionFalse(
dial_opts::PeerCondition::Disconnected | dial_opts::PeerCondition::NotDialing,
) => {
// We might (still) be connected, or about to be connected, thus do not report the
// failure to the queries.
}
DialError::DialPeerConditionFalse(dial_opts::PeerCondition::Always) => {
unreachable!("DialPeerCondition::Always can not trigger DialPeerConditionFalse.");
}
}
}
fn inject_connection_closed(
&mut self,
id: &PeerId,
_: &ConnectionId,
_: &ConnectedPoint,
_: <Self::ConnectionHandler as libp2p_swarm::IntoConnectionHandler>::Handler,
remaining_established: usize,
) {
if remaining_established == 0 {
for query in self.queries.iter_mut() {
query.on_failure(id);
}
self.connection_updated(*id, None, NodeStatus::Disconnected);
self.connected_peers.remove(id);
}
}
fn inject_event(
&mut self, &mut self,
source: PeerId, source: PeerId,
connection: ConnectionId, connection: ConnectionId,
@ -2225,20 +2230,6 @@ where
}; };
} }
fn inject_new_listen_addr(&mut self, _id: ListenerId, addr: &Multiaddr) {
self.local_addrs.insert(addr.clone());
}
fn inject_expired_listen_addr(&mut self, _id: ListenerId, addr: &Multiaddr) {
self.local_addrs.remove(addr);
}
fn inject_new_external_addr(&mut self, addr: &Multiaddr) {
if self.local_addrs.len() < MAX_LOCAL_EXTERNAL_ADDRS {
self.local_addrs.insert(addr.clone());
}
}
fn poll( fn poll(
&mut self, &mut self,
cx: &mut Context<'_>, cx: &mut Context<'_>,
@ -2360,6 +2351,35 @@ where
} }
} }
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(connection_established) => {
self.on_connection_established(connection_established)
}
FromSwarm::ConnectionClosed(connection_closed) => {
self.on_connection_closed(connection_closed)
}
FromSwarm::DialFailure(dial_failure) => self.on_dial_failure(dial_failure),
FromSwarm::AddressChange(address_change) => self.on_address_change(address_change),
FromSwarm::ExpiredListenAddr(ExpiredListenAddr { addr, .. }) => {
self.local_addrs.remove(addr);
}
FromSwarm::NewExternalAddr(NewExternalAddr { addr }) => {
if self.local_addrs.len() < MAX_LOCAL_EXTERNAL_ADDRS {
self.local_addrs.insert(addr.clone());
}
}
FromSwarm::NewListenAddr(NewListenAddr { addr, .. }) => {
self.local_addrs.insert(addr.clone());
}
FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }
/// A quorum w.r.t. the configured replication factor specifies the minimum /// A quorum w.r.t. the configured replication factor specifies the minimum

View File

@ -1277,7 +1277,7 @@ fn manual_bucket_inserts() {
} }
#[test] #[test]
fn network_behaviour_inject_address_change() { fn network_behaviour_on_address_change() {
let local_peer_id = PeerId::random(); let local_peer_id = PeerId::random();
let remote_peer_id = PeerId::random(); let remote_peer_id = PeerId::random();
@ -1293,7 +1293,13 @@ fn network_behaviour_inject_address_change() {
}; };
// Mimick a connection being established. // Mimick a connection being established.
kademlia.inject_connection_established(&remote_peer_id, &connection_id, &endpoint, None, 0); kademlia.on_swarm_event(FromSwarm::ConnectionEstablished(ConnectionEstablished {
peer_id: remote_peer_id,
connection_id,
endpoint: &endpoint,
failed_addresses: &[],
other_established: 0,
}));
// At this point the remote is not yet known to support the // At this point the remote is not yet known to support the
// configured protocol name, so the peer is not yet in the // configured protocol name, so the peer is not yet in the
@ -1302,7 +1308,7 @@ fn network_behaviour_inject_address_change() {
// Mimick the connection handler confirming the protocol for // Mimick the connection handler confirming the protocol for
// the test connection, so that the peer is added to the routing table. // the test connection, so that the peer is added to the routing table.
kademlia.inject_event( kademlia.on_connection_handler_event(
remote_peer_id, remote_peer_id,
connection_id, connection_id,
KademliaHandlerEvent::ProtocolConfirmed { endpoint }, KademliaHandlerEvent::ProtocolConfirmed { endpoint },
@ -1313,18 +1319,18 @@ fn network_behaviour_inject_address_change() {
kademlia.addresses_of_peer(&remote_peer_id), kademlia.addresses_of_peer(&remote_peer_id),
); );
kademlia.inject_address_change( kademlia.on_swarm_event(FromSwarm::AddressChange(AddressChange {
&remote_peer_id, peer_id: remote_peer_id,
&connection_id, connection_id,
&ConnectedPoint::Dialer { old: &ConnectedPoint::Dialer {
address: old_address, address: old_address,
role_override: Endpoint::Dialer, role_override: Endpoint::Dialer,
}, },
&ConnectedPoint::Dialer { new: &ConnectedPoint::Dialer {
address: new_address.clone(), address: new_address.clone(),
role_override: Endpoint::Dialer, role_override: Endpoint::Dialer,
}, },
); }));
assert_eq!( assert_eq!(
vec![new_address], vec![new_address],

View File

@ -4,8 +4,12 @@
- Update to `libp2p-swarm` `v0.41.0`. - Update to `libp2p-swarm` `v0.41.0`.
- Replace `GenMdns`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
- Use `trust-dns-proto` to parse DNS messages. See [PR 3102]. - Use `trust-dns-proto` to parse DNS messages. See [PR 3102].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
[PR 3102]: https://github.com/libp2p/rust-libp2p/pull/3102 [PR 3102]: https://github.com/libp2p/rust-libp2p/pull/3102
# 0.41.0 # 0.41.0

View File

@ -27,8 +27,8 @@ use crate::behaviour::{socket::AsyncSocket, timer::Builder};
use crate::MdnsConfig; use crate::MdnsConfig;
use futures::Stream; use futures::Stream;
use if_watch::{IfEvent, IfWatcher}; use if_watch::{IfEvent, IfWatcher};
use libp2p_core::transport::ListenerId;
use libp2p_core::{Multiaddr, PeerId}; use libp2p_core::{Multiaddr, PeerId};
use libp2p_swarm::behaviour::{ConnectionClosed, FromSwarm};
use libp2p_swarm::{ use libp2p_swarm::{
dummy, ConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters, dummy, ConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, PollParameters,
}; };
@ -133,7 +133,7 @@ where
.collect() .collect()
} }
fn inject_event( fn on_connection_handler_event(
&mut self, &mut self,
_: PeerId, _: PeerId,
_: libp2p_core::connection::ConnectionId, _: libp2p_core::connection::ConnectionId,
@ -142,23 +142,33 @@ where
void::unreachable(ev) void::unreachable(ev)
} }
fn inject_new_listen_addr(&mut self, _id: ListenerId, _addr: &Multiaddr) { fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
log::trace!("waking interface state because listening address changed"); match event {
for iface in self.iface_states.values_mut() { FromSwarm::ConnectionClosed(ConnectionClosed {
iface.fire_timer(); peer_id,
} remaining_established,
} ..
}) => {
fn inject_connection_closed( if remaining_established == 0 {
&mut self, self.expire_node(&peer_id);
peer: &PeerId, }
_: &libp2p_core::connection::ConnectionId, }
_: &libp2p_core::ConnectedPoint, FromSwarm::NewListener(_) => {
_: Self::ConnectionHandler, log::trace!("waking interface state because listening address changed");
remaining_established: usize, for iface in self.iface_states.values_mut() {
) { iface.fire_timer();
if remaining_established == 0 { }
self.expire_node(peer); }
FromSwarm::ConnectionEstablished(_)
| FromSwarm::DialFailure(_)
| FromSwarm::AddressChange(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
} }
} }

View File

@ -4,6 +4,11 @@
- Update to `libp2p-swarm` `v0.41.0`. - Update to `libp2p-swarm` `v0.41.0`.
- Replace `Behaviour`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
# 0.40.0 # 0.40.0
- Bump rand to 0.8 and quickcheck to 1. See [PR 2857]. - Bump rand to 0.8 and quickcheck to 1. See [PR 2857].

View File

@ -48,7 +48,9 @@ mod protocol;
use handler::Handler; use handler::Handler;
pub use handler::{Config, Failure, Success}; pub use handler::{Config, Failure, Success};
use libp2p_core::{connection::ConnectionId, PeerId}; use libp2p_core::{connection::ConnectionId, PeerId};
use libp2p_swarm::{NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use libp2p_swarm::{
behaviour::FromSwarm, NetworkBehaviour, NetworkBehaviourAction, PollParameters,
};
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
task::{Context, Poll}, task::{Context, Poll},
@ -121,7 +123,7 @@ impl NetworkBehaviour for Behaviour {
Handler::new(self.config.clone()) Handler::new(self.config.clone())
} }
fn inject_event(&mut self, peer: PeerId, _: ConnectionId, result: Result) { fn on_connection_handler_event(&mut self, peer: PeerId, _: ConnectionId, result: Result) {
self.events.push_front(Event { peer, result }) self.events.push_front(Event { peer, result })
} }
@ -144,4 +146,24 @@ impl NetworkBehaviour for Behaviour {
Poll::Pending Poll::Pending
} }
} }
fn on_swarm_event(
&mut self,
event: libp2p_swarm::behaviour::FromSwarm<Self::ConnectionHandler>,
) {
match event {
FromSwarm::ConnectionEstablished(_)
| FromSwarm::ConnectionClosed(_)
| FromSwarm::AddressChange(_)
| FromSwarm::DialFailure(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }

View File

@ -6,6 +6,11 @@
- Update to `libp2p-swarm` `v0.41.0`. - Update to `libp2p-swarm` `v0.41.0`.
- Replace `Client` and `Relay`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
# 0.13.0 # 0.13.0
- Update to `libp2p-core` `v0.37.0`. - Update to `libp2p-core` `v0.37.0`.

View File

@ -32,10 +32,10 @@ use futures::future::{BoxFuture, FutureExt};
use futures::io::{AsyncRead, AsyncWrite}; use futures::io::{AsyncRead, AsyncWrite};
use futures::ready; use futures::ready;
use futures::stream::StreamExt; use futures::stream::StreamExt;
use libp2p_core::connection::{ConnectedPoint, ConnectionId}; use libp2p_core::connection::ConnectionId;
use libp2p_core::{Multiaddr, PeerId}; use libp2p_core::PeerId;
use libp2p_swarm::behaviour::{ConnectionClosed, ConnectionEstablished, FromSwarm};
use libp2p_swarm::dial_opts::DialOpts; use libp2p_swarm::dial_opts::DialOpts;
use libp2p_swarm::dummy;
use libp2p_swarm::{ use libp2p_swarm::{
ConnectionHandlerUpgrErr, NegotiatedSubstream, NetworkBehaviour, NetworkBehaviourAction, ConnectionHandlerUpgrErr, NegotiatedSubstream, NetworkBehaviour, NetworkBehaviourAction,
NotifyHandler, PollParameters, NotifyHandler, PollParameters,
@ -113,47 +113,23 @@ impl Client {
}; };
(transport, behaviour) (transport, behaviour)
} }
}
impl NetworkBehaviour for Client { fn on_connection_closed(
type ConnectionHandler = handler::Prototype;
type OutEvent = Event;
fn new_handler(&mut self) -> Self::ConnectionHandler {
handler::Prototype::new(self.local_peer_id, None)
}
fn inject_connection_established(
&mut self, &mut self,
peer_id: &PeerId, ConnectionClosed {
connection_id: &ConnectionId, peer_id,
endpoint: &ConnectedPoint, connection_id,
_failed_addresses: Option<&Vec<Multiaddr>>, endpoint,
_other_established: usize, ..
}: ConnectionClosed<<Self as NetworkBehaviour>::ConnectionHandler>,
) { ) {
if !endpoint.is_relayed() { if !endpoint.is_relayed() {
self.directly_connected_peers match self.directly_connected_peers.entry(peer_id) {
.entry(*peer_id)
.or_default()
.push(*connection_id);
}
}
fn inject_connection_closed(
&mut self,
peer_id: &PeerId,
connection_id: &ConnectionId,
endpoint: &ConnectedPoint,
_handler: Either<handler::Handler, dummy::ConnectionHandler>,
_remaining_established: usize,
) {
if !endpoint.is_relayed() {
match self.directly_connected_peers.entry(*peer_id) {
hash_map::Entry::Occupied(mut connections) => { hash_map::Entry::Occupied(mut connections) => {
let position = connections let position = connections
.get() .get()
.iter() .iter()
.position(|c| c == connection_id) .position(|c| c == &connection_id)
.expect("Connection to be known."); .expect("Connection to be known.");
connections.get_mut().remove(position); connections.get_mut().remove(position);
@ -167,8 +143,48 @@ impl NetworkBehaviour for Client {
}; };
} }
} }
}
fn inject_event( impl NetworkBehaviour for Client {
type ConnectionHandler = handler::Prototype;
type OutEvent = Event;
fn new_handler(&mut self) -> Self::ConnectionHandler {
handler::Prototype::new(self.local_peer_id, None)
}
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(ConnectionEstablished {
peer_id,
connection_id,
endpoint,
..
}) => {
if !endpoint.is_relayed() {
self.directly_connected_peers
.entry(peer_id)
.or_default()
.push(connection_id);
}
}
FromSwarm::ConnectionClosed(connection_closed) => {
self.on_connection_closed(connection_closed)
}
FromSwarm::AddressChange(_)
| FromSwarm::DialFailure(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
fn on_connection_handler_event(
&mut self, &mut self,
event_source: PeerId, event_source: PeerId,
_connection: ConnectionId, _connection: ConnectionId,

View File

@ -27,11 +27,12 @@ use crate::v2::message_proto;
use crate::v2::protocol::inbound_hop; use crate::v2::protocol::inbound_hop;
use either::Either; use either::Either;
use instant::Instant; use instant::Instant;
use libp2p_core::connection::{ConnectedPoint, ConnectionId}; use libp2p_core::connection::ConnectionId;
use libp2p_core::multiaddr::Protocol; use libp2p_core::multiaddr::Protocol;
use libp2p_core::PeerId; use libp2p_core::PeerId;
use libp2p_swarm::behaviour::{ConnectionClosed, FromSwarm};
use libp2p_swarm::{ use libp2p_swarm::{
dummy, ConnectionHandlerUpgrErr, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, ConnectionHandlerUpgrErr, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler,
PollParameters, PollParameters,
}; };
use std::collections::{hash_map, HashMap, HashSet, VecDeque}; use std::collections::{hash_map, HashMap, HashSet, VecDeque};
@ -212,6 +213,39 @@ impl Relay {
queued_actions: Default::default(), queued_actions: Default::default(),
} }
} }
fn on_connection_closed(
&mut self,
ConnectionClosed {
peer_id,
connection_id,
..
}: ConnectionClosed<<Self as NetworkBehaviour>::ConnectionHandler>,
) {
if let hash_map::Entry::Occupied(mut peer) = self.reservations.entry(peer_id) {
peer.get_mut().remove(&connection_id);
if peer.get().is_empty() {
peer.remove();
}
}
for circuit in self
.circuits
.remove_by_connection(peer_id, connection_id)
.iter()
// Only emit [`CircuitClosed`] for accepted requests.
.filter(|c| matches!(c.status, CircuitStatus::Accepted))
{
self.queued_actions.push_back(
NetworkBehaviourAction::GenerateEvent(Event::CircuitClosed {
src_peer_id: circuit.src_peer_id,
dst_peer_id: circuit.dst_peer_id,
error: Some(std::io::ErrorKind::ConnectionAborted.into()),
})
.into(),
);
}
}
} }
impl NetworkBehaviour for Relay { impl NetworkBehaviour for Relay {
@ -228,40 +262,26 @@ impl NetworkBehaviour for Relay {
} }
} }
fn inject_connection_closed( fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
&mut self, match event {
peer: &PeerId, FromSwarm::ConnectionClosed(connection_closed) => {
connection: &ConnectionId, self.on_connection_closed(connection_closed)
_: &ConnectedPoint,
_handler: Either<handler::Handler, dummy::ConnectionHandler>,
_remaining_established: usize,
) {
if let hash_map::Entry::Occupied(mut peer) = self.reservations.entry(*peer) {
peer.get_mut().remove(connection);
if peer.get().is_empty() {
peer.remove();
} }
} FromSwarm::ConnectionEstablished(_)
| FromSwarm::DialFailure(_)
for circuit in self | FromSwarm::AddressChange(_)
.circuits | FromSwarm::ListenFailure(_)
.remove_by_connection(*peer, *connection) | FromSwarm::NewListener(_)
.iter() | FromSwarm::NewListenAddr(_)
// Only emit [`CircuitClosed`] for accepted requests. | FromSwarm::ExpiredListenAddr(_)
.filter(|c| matches!(c.status, CircuitStatus::Accepted)) | FromSwarm::ListenerError(_)
{ | FromSwarm::ListenerClosed(_)
self.queued_actions.push_back( | FromSwarm::NewExternalAddr(_)
NetworkBehaviourAction::GenerateEvent(Event::CircuitClosed { | FromSwarm::ExpiredExternalAddr(_) => {}
src_peer_id: circuit.src_peer_id,
dst_peer_id: circuit.dst_peer_id,
error: Some(std::io::ErrorKind::ConnectionAborted.into()),
})
.into(),
);
} }
} }
fn inject_event( fn on_connection_handler_event(
&mut self, &mut self,
event_source: PeerId, event_source: PeerId,
connection: ConnectionId, connection: ConnectionId,

View File

@ -1,11 +1,15 @@
# 0.11.0 [unreleased] # 0.11.0 [unreleased]
- De- and encode protobuf messages using `prost-codec`. See [PR 3058]. - De- and encode protobuf messages using `prost-codec`. See [PR 3058].
- Update to `libp2p-core` `v0.38.0`. - Update to `libp2p-core` `v0.38.0`.
- Update to `libp2p-swarm` `v0.41.0`. - Update to `libp2p-swarm` `v0.41.0`.
- Replace `Client` and `Server`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
[PR 3058]: https://github.com/libp2p/rust-libp2p/pull/3058 [PR 3058]: https://github.com/libp2p/rust-libp2p/pull/3058
# 0.10.0 # 0.10.0

View File

@ -32,6 +32,7 @@ use libp2p_core::connection::ConnectionId;
use libp2p_core::identity::error::SigningError; use libp2p_core::identity::error::SigningError;
use libp2p_core::identity::Keypair; use libp2p_core::identity::Keypair;
use libp2p_core::{Multiaddr, PeerId, PeerRecord}; use libp2p_core::{Multiaddr, PeerId, PeerRecord};
use libp2p_swarm::behaviour::FromSwarm;
use libp2p_swarm::{ use libp2p_swarm::{
CloseConnection, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, CloseConnection, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters,
}; };
@ -183,7 +184,7 @@ impl NetworkBehaviour for Behaviour {
.collect() .collect()
} }
fn inject_event( fn on_connection_handler_event(
&mut self, &mut self,
peer_id: PeerId, peer_id: PeerId,
connection_id: ConnectionId, connection_id: ConnectionId,
@ -265,6 +266,23 @@ impl NetworkBehaviour for Behaviour {
Poll::Pending Poll::Pending
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(_)
| FromSwarm::ConnectionClosed(_)
| FromSwarm::AddressChange(_)
| FromSwarm::DialFailure(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }
fn handle_outbound_event( fn handle_outbound_event(

View File

@ -29,6 +29,7 @@ use futures::stream::FuturesUnordered;
use futures::{FutureExt, StreamExt}; use futures::{FutureExt, StreamExt};
use libp2p_core::connection::ConnectionId; use libp2p_core::connection::ConnectionId;
use libp2p_core::PeerId; use libp2p_core::PeerId;
use libp2p_swarm::behaviour::FromSwarm;
use libp2p_swarm::{ use libp2p_swarm::{
CloseConnection, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters, CloseConnection, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters,
}; };
@ -118,7 +119,7 @@ impl NetworkBehaviour for Behaviour {
SubstreamConnectionHandler::new_inbound_only(initial_keep_alive) SubstreamConnectionHandler::new_inbound_only(initial_keep_alive)
} }
fn inject_event( fn on_connection_handler_event(
&mut self, &mut self,
peer_id: PeerId, peer_id: PeerId,
connection: ConnectionId, connection: ConnectionId,
@ -160,6 +161,23 @@ impl NetworkBehaviour for Behaviour {
Poll::Pending Poll::Pending
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(_)
| FromSwarm::ConnectionClosed(_)
| FromSwarm::AddressChange(_)
| FromSwarm::DialFailure(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }
fn handle_inbound_event( fn handle_inbound_event(

View File

@ -4,6 +4,11 @@
- Update to `libp2p-swarm` `v0.41.0`. - Update to `libp2p-swarm` `v0.41.0`.
- Replace `RequestResponse`'s `NetworkBehaviour` implemention `inject_*` methods with the new `on_*` methods.
See [PR 3011].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
# 0.22.0 # 0.22.0
- Bump rand to 0.8 and quickcheck to 1. See [PR 2857]. - Bump rand to 0.8 and quickcheck to 1. See [PR 2857].

View File

@ -68,8 +68,9 @@ use futures::channel::oneshot;
use handler::{RequestProtocol, RequestResponseHandler, RequestResponseHandlerEvent}; use handler::{RequestProtocol, RequestResponseHandler, RequestResponseHandlerEvent};
use libp2p_core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId}; use libp2p_core::{connection::ConnectionId, ConnectedPoint, Multiaddr, PeerId};
use libp2p_swarm::{ use libp2p_swarm::{
dial_opts::DialOpts, DialError, IntoConnectionHandler, NetworkBehaviour, behaviour::{AddressChange, ConnectionClosed, ConnectionEstablished, DialFailure, FromSwarm},
NetworkBehaviourAction, NotifyHandler, PollParameters, dial_opts::DialOpts,
IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, PollParameters,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
@ -560,6 +561,134 @@ where
.get_mut(peer) .get_mut(peer)
.and_then(|connections| connections.iter_mut().find(|c| c.id == connection)) .and_then(|connections| connections.iter_mut().find(|c| c.id == connection))
} }
fn on_address_change(
&mut self,
AddressChange {
peer_id,
connection_id,
new,
..
}: AddressChange,
) {
let new_address = match new {
ConnectedPoint::Dialer { address, .. } => Some(address.clone()),
ConnectedPoint::Listener { .. } => None,
};
let connections = self
.connected
.get_mut(&peer_id)
.expect("Address change can only happen on an established connection.");
let connection = connections
.iter_mut()
.find(|c| c.id == connection_id)
.expect("Address change can only happen on an established connection.");
connection.address = new_address;
}
fn on_connection_established(
&mut self,
ConnectionEstablished {
peer_id,
connection_id,
endpoint,
other_established,
..
}: ConnectionEstablished,
) {
let address = match endpoint {
ConnectedPoint::Dialer { address, .. } => Some(address.clone()),
ConnectedPoint::Listener { .. } => None,
};
self.connected
.entry(peer_id)
.or_default()
.push(Connection::new(connection_id, address));
if other_established == 0 {
if let Some(pending) = self.pending_outbound_requests.remove(&peer_id) {
for request in pending {
let request = self.try_send_request(&peer_id, request);
assert!(request.is_none());
}
}
}
}
fn on_connection_closed(
&mut self,
ConnectionClosed {
peer_id,
connection_id,
remaining_established,
..
}: ConnectionClosed<<Self as NetworkBehaviour>::ConnectionHandler>,
) {
let connections = self
.connected
.get_mut(&peer_id)
.expect("Expected some established connection to peer before closing.");
let connection = connections
.iter()
.position(|c| c.id == connection_id)
.map(|p: usize| connections.remove(p))
.expect("Expected connection to be established before closing.");
debug_assert_eq!(connections.is_empty(), remaining_established == 0);
if connections.is_empty() {
self.connected.remove(&peer_id);
}
for request_id in connection.pending_outbound_responses {
self.pending_events
.push_back(NetworkBehaviourAction::GenerateEvent(
RequestResponseEvent::InboundFailure {
peer: peer_id,
request_id,
error: InboundFailure::ConnectionClosed,
},
));
}
for request_id in connection.pending_inbound_responses {
self.pending_events
.push_back(NetworkBehaviourAction::GenerateEvent(
RequestResponseEvent::OutboundFailure {
peer: peer_id,
request_id,
error: OutboundFailure::ConnectionClosed,
},
));
}
}
fn on_dial_failure(
&mut self,
DialFailure { peer_id, .. }: DialFailure<<Self as NetworkBehaviour>::ConnectionHandler>,
) {
if let Some(peer) = peer_id {
// If there are pending outgoing requests when a dial failure occurs,
// it is implied that we are not connected to the peer, since pending
// outgoing requests are drained when a connection is established and
// only created when a peer is not connected when a request is made.
// Thus these requests must be considered failed, even if there is
// another, concurrent dialing attempt ongoing.
if let Some(pending) = self.pending_outbound_requests.remove(&peer) {
for request in pending {
self.pending_events
.push_back(NetworkBehaviourAction::GenerateEvent(
RequestResponseEvent::OutboundFailure {
peer,
request_id: request.request_id,
error: OutboundFailure::DialFailure,
},
));
}
}
}
}
} }
impl<TCodec> NetworkBehaviour for RequestResponse<TCodec> impl<TCodec> NetworkBehaviour for RequestResponse<TCodec>
@ -590,136 +719,33 @@ where
addresses addresses
} }
fn inject_address_change( fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
&mut self, match event {
peer: &PeerId, FromSwarm::ConnectionEstablished(connection_established) => {
conn: &ConnectionId, self.on_connection_established(connection_established)
_old: &ConnectedPoint,
new: &ConnectedPoint,
) {
let new_address = match new {
ConnectedPoint::Dialer { address, .. } => Some(address.clone()),
ConnectedPoint::Listener { .. } => None,
};
let connections = self
.connected
.get_mut(peer)
.expect("Address change can only happen on an established connection.");
let connection = connections
.iter_mut()
.find(|c| &c.id == conn)
.expect("Address change can only happen on an established connection.");
connection.address = new_address;
}
fn inject_connection_established(
&mut self,
peer: &PeerId,
conn: &ConnectionId,
endpoint: &ConnectedPoint,
_errors: Option<&Vec<Multiaddr>>,
other_established: usize,
) {
let address = match endpoint {
ConnectedPoint::Dialer { address, .. } => Some(address.clone()),
ConnectedPoint::Listener { .. } => None,
};
self.connected
.entry(*peer)
.or_default()
.push(Connection::new(*conn, address));
if other_established == 0 {
if let Some(pending) = self.pending_outbound_requests.remove(peer) {
for request in pending {
let request = self.try_send_request(peer, request);
assert!(request.is_none());
}
} }
} FromSwarm::ConnectionClosed(connection_closed) => {
} self.on_connection_closed(connection_closed)
fn inject_connection_closed(
&mut self,
peer_id: &PeerId,
conn: &ConnectionId,
_: &ConnectedPoint,
_: <Self::ConnectionHandler as IntoConnectionHandler>::Handler,
remaining_established: usize,
) {
let connections = self
.connected
.get_mut(peer_id)
.expect("Expected some established connection to peer before closing.");
let connection = connections
.iter()
.position(|c| &c.id == conn)
.map(|p: usize| connections.remove(p))
.expect("Expected connection to be established before closing.");
debug_assert_eq!(connections.is_empty(), remaining_established == 0);
if connections.is_empty() {
self.connected.remove(peer_id);
}
for request_id in connection.pending_outbound_responses {
self.pending_events
.push_back(NetworkBehaviourAction::GenerateEvent(
RequestResponseEvent::InboundFailure {
peer: *peer_id,
request_id,
error: InboundFailure::ConnectionClosed,
},
));
}
for request_id in connection.pending_inbound_responses {
self.pending_events
.push_back(NetworkBehaviourAction::GenerateEvent(
RequestResponseEvent::OutboundFailure {
peer: *peer_id,
request_id,
error: OutboundFailure::ConnectionClosed,
},
));
}
}
fn inject_dial_failure(
&mut self,
peer: Option<PeerId>,
_: Self::ConnectionHandler,
_: &DialError,
) {
if let Some(peer) = peer {
// If there are pending outgoing requests when a dial failure occurs,
// it is implied that we are not connected to the peer, since pending
// outgoing requests are drained when a connection is established and
// only created when a peer is not connected when a request is made.
// Thus these requests must be considered failed, even if there is
// another, concurrent dialing attempt ongoing.
if let Some(pending) = self.pending_outbound_requests.remove(&peer) {
for request in pending {
self.pending_events
.push_back(NetworkBehaviourAction::GenerateEvent(
RequestResponseEvent::OutboundFailure {
peer,
request_id: request.request_id,
error: OutboundFailure::DialFailure,
},
));
}
} }
FromSwarm::AddressChange(address_change) => self.on_address_change(address_change),
FromSwarm::DialFailure(dial_failure) => self.on_dial_failure(dial_failure),
FromSwarm::ListenFailure(_) => {}
FromSwarm::NewListener(_) => {}
FromSwarm::NewListenAddr(_) => {}
FromSwarm::ExpiredListenAddr(_) => {}
FromSwarm::ListenerError(_) => {}
FromSwarm::ListenerClosed(_) => {}
FromSwarm::NewExternalAddr(_) => {}
FromSwarm::ExpiredExternalAddr(_) => {}
} }
} }
fn inject_event( fn on_connection_handler_event(
&mut self, &mut self,
peer: PeerId, peer: PeerId,
connection: ConnectionId, connection: ConnectionId,
event: RequestResponseHandlerEvent<TCodec>, event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as
libp2p_swarm::ConnectionHandler>::OutEvent,
) { ) {
match event { match event {
RequestResponseHandlerEvent::Response { RequestResponseHandlerEvent::Response {

View File

@ -1,8 +1,13 @@
# 0.30.2 [unreleased] # 0.30.2 - [unreleased]
- Replace `NetworkBehaviour` Derive macro deprecated `inject_*` method implementations
with the new `on_swarm_event` and `on_connection_handler_event`.
See [PR 3011].
- Add `prelude` configuration option. - Add `prelude` configuration option.
The derive-macro generates code that needs to refer to various symbols. See [PR 3055]. The derive-macro generates code that needs to refer to various symbols. See [PR 3055].
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
[PR 3055]: https://github.com/libp2p/rust-libp2p/pull/3055 [PR 3055]: https://github.com/libp2p/rust-libp2p/pull/3055
# 0.30.1 # 0.30.1

View File

@ -48,7 +48,6 @@ fn build(ast: &DeriveInput) -> TokenStream {
fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
let name = &ast.ident; let name = &ast.ident;
let (_, ty_generics, where_clause) = ast.generics.split_for_impl(); let (_, ty_generics, where_clause) = ast.generics.split_for_impl();
let prelude_path = parse_attribute_value_by_key::<syn::Path>(ast, "prelude") let prelude_path = parse_attribute_value_by_key::<syn::Path>(ast, "prelude")
.unwrap_or_else(|| syn::parse_quote! { ::libp2p::swarm::derive_prelude }); .unwrap_or_else(|| syn::parse_quote! { ::libp2p::swarm::derive_prelude });
@ -61,11 +60,20 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
let into_proto_select_ident = quote! { #prelude_path::IntoConnectionHandlerSelect }; let into_proto_select_ident = quote! { #prelude_path::IntoConnectionHandlerSelect };
let peer_id = quote! { #prelude_path::PeerId }; let peer_id = quote! { #prelude_path::PeerId };
let connection_id = quote! { #prelude_path::ConnectionId }; let connection_id = quote! { #prelude_path::ConnectionId };
let dial_errors = quote! {Option<&Vec<#prelude_path::Multiaddr>> };
let connected_point = quote! { #prelude_path::ConnectedPoint };
let listener_id = quote! { #prelude_path::ListenerId };
let dial_error = quote! { #prelude_path::DialError };
let poll_parameters = quote! { #prelude_path::PollParameters }; let poll_parameters = quote! { #prelude_path::PollParameters };
let from_swarm = quote! { #prelude_path::FromSwarm };
let connection_established = quote! { #prelude_path::ConnectionEstablished };
let address_change = quote! { #prelude_path::AddressChange };
let connection_closed = quote! { #prelude_path::ConnectionClosed };
let dial_failure = quote! { #prelude_path::DialFailure };
let listen_failure = quote! { #prelude_path::ListenFailure };
let new_listener = quote! { #prelude_path::NewListener };
let new_listen_addr = quote! { #prelude_path::NewListenAddr };
let expired_listen_addr = quote! { #prelude_path::ExpiredListenAddr };
let new_external_addr = quote! { #prelude_path::NewExternalAddr };
let expired_external_addr = quote! { #prelude_path::ExpiredExternalAddr };
let listener_error = quote! { #prelude_path::ListenerError };
let listener_closed = quote! { #prelude_path::ListenerClosed };
// Build the generics. // Build the generics.
let impl_generics = { let impl_generics = {
@ -171,35 +179,50 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
}) })
}; };
// Build the list of statements to put in the body of `inject_connection_established()`. // Build the list of statements to put in the body of `on_swarm_event()`
let inject_connection_established_stmts = { // for the `FromSwarm::ConnectionEstablished` variant.
data_struct.fields.iter().enumerate().map(move |(field_n, field)| { let on_connection_established_stmts = {
match field.ident { data_struct
Some(ref i) => quote!{ self.#i.inject_connection_established(peer_id, connection_id, endpoint, errors, other_established); }, .fields
None => quote!{ self.#field_n.inject_connection_established(peer_id, connection_id, endpoint, errors, other_established); }, .iter()
} .enumerate()
}) .map(|(field_n, field)| match field.ident {
Some(ref i) => quote! {
#[allow(deprecated)]
self.#i.inject_connection_established(&peer_id, &connection_id, endpoint, Some(&failed_addresses.into()), other_established);},
None => quote! {
#[allow(deprecated)]
self.#field_n.inject_connection_established(&peer_id, &connection_id, endpoint, Some(&failed_addresses.into()), other_established);},
})
}; };
// Build the list of statements to put in the body of `inject_address_change()`. // Build the list of statements to put in the body of `on_swarm_event()`
let inject_address_change_stmts = { // for the `FromSwarm::AddressChange variant`.
data_struct.fields.iter().enumerate().map(move |(field_n, field)| { let on_address_change_stmts = {
match field.ident { data_struct
Some(ref i) => quote!{ self.#i.inject_address_change(peer_id, connection_id, old, new); }, .fields
None => quote!{ self.#field_n.inject_address_change(peer_id, connection_id, old, new); }, .iter()
} .enumerate()
}) .map(|(field_n, field)| match field.ident {
Some(ref i) => quote! {
#[allow(deprecated)]
self.#i.inject_address_change(&peer_id, &connection_id, old, new);},
None => quote! {
#[allow(deprecated)]
self.#field_n.inject_address_change(&peer_id, &connection_id, old, new);},
})
}; };
// Build the list of statements to put in the body of `inject_connection_closed()`. // Build the list of statements to put in the body of `on_swarm_event()`
let inject_connection_closed_stmts = { // for the `FromSwarm::ConnectionClosed` variant.
let on_connection_closed_stmts = {
data_struct.fields data_struct.fields
.iter() .iter()
.enumerate() .enumerate()
// The outmost handler belongs to the last behaviour. // The outmost handler belongs to the last behaviour.
.rev() .rev()
.enumerate() .enumerate()
.map(move |(enum_n, (field_n, field))| { .map(|(enum_n, (field_n, field))| {
let handler = if field_n == 0 { let handler = if field_n == 0 {
// Given that the iterator is reversed, this is the innermost handler only. // Given that the iterator is reversed, this is the innermost handler only.
quote! { let handler = handlers } quote! { let handler = handlers }
@ -209,8 +232,12 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
} }
}; };
let inject = match field.ident { let inject = match field.ident {
Some(ref i) => quote!{ self.#i.inject_connection_closed(peer_id, connection_id, endpoint, handler, remaining_established) }, Some(ref i) => quote! {
None => quote!{ self.#enum_n.inject_connection_closed(peer_id, connection_id, endpoint, handler, remaining_established) }, #[allow(deprecated)]
self.#i.inject_connection_closed(&peer_id, &connection_id, endpoint, handler, remaining_established);},
None => quote! {
#[allow(deprecated)]
self.#enum_n.inject_connection_closed(&peer_id, &connection_id, endpoint, handler, remaining_established);},
}; };
quote! { quote! {
@ -220,8 +247,9 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
}) })
}; };
// Build the list of statements to put in the body of `inject_dial_failure()`. // Build the list of statements to put in the body of `on_swarm_event()`
let inject_dial_failure_stmts = { // for the `FromSwarm::DialFailure` variant.
let on_dial_failure_stmts = {
data_struct data_struct
.fields .fields
.iter() .iter()
@ -229,7 +257,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
// The outmost handler belongs to the last behaviour. // The outmost handler belongs to the last behaviour.
.rev() .rev()
.enumerate() .enumerate()
.map(move |(enum_n, (field_n, field))| { .map(|(enum_n, (field_n, field))| {
let handler = if field_n == 0 { let handler = if field_n == 0 {
// Given that the iterator is reversed, this is the innermost handler only. // Given that the iterator is reversed, this is the innermost handler only.
quote! { let handler = handlers } quote! { let handler = handlers }
@ -240,12 +268,12 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
}; };
let inject = match field.ident { let inject = match field.ident {
Some(ref i) => { Some(ref i) => quote! {
quote! { self.#i.inject_dial_failure(peer_id, handler, error) } #[allow(deprecated)]
} self.#i.inject_dial_failure(peer_id, handler, error);},
None => { None => quote! {
quote! { self.#enum_n.inject_dial_failure(peer_id, handler, error) } #[allow(deprecated)]
} self.#enum_n.inject_dial_failure(peer_id, handler, error);},
}; };
quote! { quote! {
@ -255,138 +283,186 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
}) })
}; };
// Build the list of statements to put in the body of `inject_listen_failure()`. // Build the list of statements to put in the body of `on_swarm_event()`
let inject_listen_failure_stmts = { // for the `FromSwarm::ListenFailure` variant.
data_struct.fields let on_listen_failure_stmts =
.iter() {
.enumerate() data_struct.fields.iter().enumerate().rev().enumerate().map(
.rev() |(enum_n, (field_n, field))| {
.enumerate() let handler = if field_n == 0 {
.map(move |(enum_n, (field_n, field))| { quote! { let handler = handlers }
let handler = if field_n == 0 { } else {
quote! { let handler = handlers } quote! {
} else { let (handlers, handler) = handlers.into_inner()
}
};
let inject = match field.ident {
Some(ref i) => quote! {
#[allow(deprecated)]
self.#i.inject_listen_failure(local_addr, send_back_addr, handler);},
None => quote! {
#[allow(deprecated)]
self.#enum_n.inject_listen_failure(local_addr, send_back_addr, handler);},
};
quote! { quote! {
let (handlers, handler) = handlers.into_inner() #handler;
#inject;
} }
}; },
)
let inject = match field.ident {
Some(ref i) => quote! { self.#i.inject_listen_failure(local_addr, send_back_addr, handler) },
None => quote! { self.#enum_n.inject_listen_failure(local_addr, send_back_addr, handler) },
};
quote! {
#handler;
#inject;
}
})
};
// Build the list of statements to put in the body of `inject_new_listener()`.
let inject_new_listener_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(move |(field_n, field)| match field.ident {
Some(ref i) => quote! { self.#i.inject_new_listener(id); },
None => quote! { self.#field_n.inject_new_listener(id); },
})
};
// Build the list of statements to put in the body of `inject_new_listen_addr()`.
let inject_new_listen_addr_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(move |(field_n, field)| match field.ident {
Some(ref i) => quote! { self.#i.inject_new_listen_addr(id, addr); },
None => quote! { self.#field_n.inject_new_listen_addr(id, addr); },
})
};
// Build the list of statements to put in the body of `inject_expired_listen_addr()`.
let inject_expired_listen_addr_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(move |(field_n, field)| match field.ident {
Some(ref i) => quote! { self.#i.inject_expired_listen_addr(id, addr); },
None => quote! { self.#field_n.inject_expired_listen_addr(id, addr); },
})
};
// Build the list of statements to put in the body of `inject_new_external_addr()`.
let inject_new_external_addr_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(move |(field_n, field)| match field.ident {
Some(ref i) => quote! { self.#i.inject_new_external_addr(addr); },
None => quote! { self.#field_n.inject_new_external_addr(addr); },
})
};
// Build the list of statements to put in the body of `inject_expired_external_addr()`.
let inject_expired_external_addr_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(move |(field_n, field)| match field.ident {
Some(ref i) => quote! { self.#i.inject_expired_external_addr(addr); },
None => quote! { self.#field_n.inject_expired_external_addr(addr); },
})
};
// Build the list of statements to put in the body of `inject_listener_error()`.
let inject_listener_error_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(move |(field_n, field)| match field.ident {
Some(ref i) => quote!(self.#i.inject_listener_error(id, err);),
None => quote!(self.#field_n.inject_listener_error(id, err);),
})
};
// Build the list of statements to put in the body of `inject_listener_closed()`.
let inject_listener_closed_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(move |(field_n, field)| match field.ident {
Some(ref i) => quote!(self.#i.inject_listener_closed(id, reason);),
None => quote!(self.#field_n.inject_listener_closed(id, reason);),
})
};
// Build the list of variants to put in the body of `inject_event()`.
//
// The event type is a construction of nested `#either_ident`s of the events of the children.
// We call `inject_event` on the corresponding child.
let inject_node_event_stmts = data_struct.fields.iter().enumerate().enumerate().map(|(enum_n, (field_n, field))| {
let mut elem = if enum_n != 0 {
quote!{ #either_ident::Second(ev) }
} else {
quote!{ ev }
}; };
for _ in 0 .. data_struct.fields.len() - 1 - enum_n { // Build the list of statements to put in the body of `on_swarm_event()`
elem = quote!{ #either_ident::First(#elem) }; // for the `FromSwarm::NewListener` variant.
} let on_new_listener_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(|(field_n, field)| match field.ident {
Some(ref i) => quote! {
#[allow(deprecated)]
self.#i.inject_new_listener(listener_id);},
None => quote! {
#[allow(deprecated)]
self.#field_n.inject_new_listener(listener_id);},
})
};
Some(match field.ident { // Build the list of statements to put in the body of `on_swarm_event()`
Some(ref i) => quote!{ #elem => #trait_to_impl::inject_event(&mut self.#i, peer_id, connection_id, ev) }, // for the `FromSwarm::NewListenAddr` variant.
None => quote!{ #elem => #trait_to_impl::inject_event(&mut self.#field_n, peer_id, connection_id, ev) }, let on_new_listen_addr_stmts = {
}) data_struct
}); .fields
.iter()
.enumerate()
.map(|(field_n, field)| match field.ident {
Some(ref i) => quote! {
#[allow(deprecated)]
self.#i.inject_new_listen_addr(listener_id, addr);},
None => quote! {
#[allow(deprecated)]
self.#field_n.inject_new_listen_addr(listener_id, addr);},
})
};
// Build the list of statements to put in the body of `on_swarm_event()`
// for the `FromSwarm::ExpiredListenAddr` variant.
let on_expired_listen_addr_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(|(field_n, field)| match field.ident {
Some(ref i) => quote! {
#[allow(deprecated)]
self.#i.inject_expired_listen_addr(listener_id, addr);},
None => quote! {
#[allow(deprecated)]
self.#field_n.inject_expired_listen_addr(listener_id, addr);},
})
};
// Build the list of statements to put in the body of `on_swarm_event()`
// for the `FromSwarm::NewExternalAddr` variant.
let on_new_external_addr_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(|(field_n, field)| match field.ident {
Some(ref i) => quote! {
#[allow(deprecated)]
self.#i.inject_new_external_addr(addr);},
None => quote! {
#[allow(deprecated)]
self.#field_n.inject_new_external_addr(addr);},
})
};
// Build the list of statements to put in the body of `on_swarm_event()`
// for the `FromSwarm::ExpiredExternalAddr` variant.
let on_expired_external_addr_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(|(field_n, field)| match field.ident {
Some(ref i) => quote! {
#[allow(deprecated)]
self.#i.inject_expired_external_addr(addr);},
None => quote! {
#[allow(deprecated)]
self.#field_n.inject_expired_external_addr(addr);},
})
};
// Build the list of statements to put in the body of `on_swarm_event()`
// for the `FromSwarm::ListenerError` variant.
let on_listener_error_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(|(field_n, field)| match field.ident {
Some(ref i) => quote! {
#[allow(deprecated)]
self.#i.inject_listener_error(listener_id, err);},
None => quote! {
#[allow(deprecated)]
self.#field_n.inject_listener_error(listener_id, err);},
})
};
// Build the list of statements to put in the body of `on_swarm_event()`
// for the `FromSwarm::ListenerClosed` variant.
let on_listener_closed_stmts = {
data_struct
.fields
.iter()
.enumerate()
.map(|(field_n, field)| match field.ident {
Some(ref i) => quote! {
#[allow(deprecated)]
self.#i.inject_listener_closed(listener_id, reason);},
None => quote! {
#[allow(deprecated)]
self.#field_n.inject_listener_closed(listener_id, reason);},
})
};
// Build the list of variants to put in the body of `on_connection_handler_event()`.
//
// The event type is a construction of nested `#either_ident`s of the events of the children.
// We call `on_connection_handler_event` on the corresponding child.
let on_node_event_stmts =
data_struct
.fields
.iter()
.enumerate()
.enumerate()
.map(|(enum_n, (field_n, field))| {
let mut elem = if enum_n != 0 {
quote! { #either_ident::Second(ev) }
} else {
quote! { ev }
};
for _ in 0..data_struct.fields.len() - 1 - enum_n {
elem = quote! { #either_ident::First(#elem) };
}
Some(match field.ident {
Some(ref i) => quote! { #elem => {
#[allow(deprecated)]
#trait_to_impl::inject_event(&mut self.#i, peer_id, connection_id, ev) }},
None => quote! { #elem => {
#[allow(deprecated)]
#trait_to_impl::inject_event(&mut self.#field_n, peer_id, connection_id, ev) }},
})
});
// The [`ConnectionHandler`] associated type. // The [`ConnectionHandler`] associated type.
let connection_handler_ty = { let connection_handler_ty = {
@ -555,62 +631,14 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
out out
} }
fn inject_connection_established(&mut self, peer_id: &#peer_id, connection_id: &#connection_id, endpoint: &#connected_point, errors: #dial_errors, other_established: usize) { fn on_connection_handler_event(
#(#inject_connection_established_stmts);*
}
fn inject_address_change(&mut self, peer_id: &#peer_id, connection_id: &#connection_id, old: &#connected_point, new: &#connected_point) {
#(#inject_address_change_stmts);*
}
fn inject_connection_closed(&mut self, peer_id: &#peer_id, connection_id: &#connection_id, endpoint: &#connected_point, handlers: <Self::ConnectionHandler as #into_connection_handler>::Handler, remaining_established: usize) {
#(#inject_connection_closed_stmts);*
}
fn inject_dial_failure(&mut self, peer_id: Option<#peer_id>, handlers: Self::ConnectionHandler, error: &#dial_error) {
#(#inject_dial_failure_stmts);*
}
fn inject_listen_failure(&mut self, local_addr: &#multiaddr, send_back_addr: &#multiaddr, handlers: Self::ConnectionHandler) {
#(#inject_listen_failure_stmts);*
}
fn inject_new_listener(&mut self, id: #listener_id) {
#(#inject_new_listener_stmts);*
}
fn inject_new_listen_addr(&mut self, id: #listener_id, addr: &#multiaddr) {
#(#inject_new_listen_addr_stmts);*
}
fn inject_expired_listen_addr(&mut self, id: #listener_id, addr: &#multiaddr) {
#(#inject_expired_listen_addr_stmts);*
}
fn inject_new_external_addr(&mut self, addr: &#multiaddr) {
#(#inject_new_external_addr_stmts);*
}
fn inject_expired_external_addr(&mut self, addr: &#multiaddr) {
#(#inject_expired_external_addr_stmts);*
}
fn inject_listener_error(&mut self, id: #listener_id, err: &(dyn std::error::Error + 'static)) {
#(#inject_listener_error_stmts);*
}
fn inject_listener_closed(&mut self, id: #listener_id, reason: std::result::Result<(), &std::io::Error>) {
#(#inject_listener_closed_stmts);*
}
fn inject_event(
&mut self, &mut self,
peer_id: #peer_id, peer_id: #peer_id,
connection_id: #connection_id, connection_id: #connection_id,
event: <<Self::ConnectionHandler as #into_connection_handler>::Handler as #connection_handler>::OutEvent event: <<Self::ConnectionHandler as #into_connection_handler>::Handler as #connection_handler>::OutEvent
) { ) {
match event { match event {
#(#inject_node_event_stmts),* #(#on_node_event_stmts),*
} }
} }
@ -619,6 +647,48 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
#(#poll_stmts)* #(#poll_stmts)*
std::task::Poll::Pending std::task::Poll::Pending
} }
fn on_swarm_event(&mut self, event: #from_swarm<Self::ConnectionHandler>) {
match event {
#from_swarm::ConnectionEstablished(
#connection_established { peer_id, connection_id, endpoint, failed_addresses, other_established })
=> { #(#on_connection_established_stmts)* }
#from_swarm::AddressChange(
#address_change { peer_id, connection_id, old, new })
=> { #(#on_address_change_stmts)* }
#from_swarm::ConnectionClosed(
#connection_closed { peer_id, connection_id, endpoint, handler: handlers, remaining_established })
=> { #(#on_connection_closed_stmts)* }
#from_swarm::DialFailure(
#dial_failure { peer_id, handler: handlers, error })
=> { #(#on_dial_failure_stmts)* }
#from_swarm::ListenFailure(
#listen_failure { local_addr, send_back_addr, handler: handlers })
=> { #(#on_listen_failure_stmts)* }
#from_swarm::NewListener(
#new_listener { listener_id })
=> { #(#on_new_listener_stmts)* }
#from_swarm::NewListenAddr(
#new_listen_addr { listener_id, addr })
=> { #(#on_new_listen_addr_stmts)* }
#from_swarm::ExpiredListenAddr(
#expired_listen_addr { listener_id, addr })
=> { #(#on_expired_listen_addr_stmts)* }
#from_swarm::NewExternalAddr(
#new_external_addr { addr })
=> { #(#on_new_external_addr_stmts)* }
#from_swarm::ExpiredExternalAddr(
#expired_external_addr { addr })
=> { #(#on_expired_external_addr_stmts)* }
#from_swarm::ListenerError(
#listener_error { listener_id, err })
=> { #(#on_listener_error_stmts)* }
#from_swarm::ListenerClosed(
#listener_closed { listener_id, reason })
=> { #(#on_listener_closed_stmts)* }
_ => {}
}
}
} }
}; };

View File

@ -2,6 +2,20 @@
- Update to `libp2p-core` `v0.38.0`. - Update to `libp2p-core` `v0.38.0`.
- Add new `on_swarm_event` method to `NetworkBehaviour` that accepts a `FromSwarm` enum and update
`inject_*` methods to call `on_swarm_event` with the respective `FromSwarm` variant and deprecate
`inject_*`.
To migrate, users should replace the `NetworkBehaviour::inject_*` calls with a single
implementation of `NetworkBehaviour::on_swarm_event` treating each `FromSwarm` variant in
the same way its corresponding `inject_*` call was treated.
See [PR 3011].
- Add new `on_connection_handler_event` method with the same signature as `inject_event`, make the
default implementation of `inject_event` call `on_connection_handler_event` and deprecate it.
To migrate, users should replace the `NetworkBehaviour::inject_event` call
with `NetworkBehaviour::on_connection_handler_event`.
See [PR 3011].
- Export `NetworkBehaviour` derive as `libp2p_swarm::NetworkBehaviour`. - Export `NetworkBehaviour` derive as `libp2p_swarm::NetworkBehaviour`.
This follows the convention of other popular libraries. `serde` for example exports the `Serialize` trait and macro as This follows the convention of other popular libraries. `serde` for example exports the `Serialize` trait and macro as
`serde::Serialize`. See [PR 3055]. `serde::Serialize`. See [PR 3055].
@ -9,7 +23,7 @@
- Feature-gate `NetworkBehaviour` macro behind `macros` feature flag. See [PR 3055]. - Feature-gate `NetworkBehaviour` macro behind `macros` feature flag. See [PR 3055].
- Make executor in Swarm constructor explicit. See [PR 3097]. - Make executor in Swarm constructor explicit. See [PR 3097].
Supported executors: Supported executors:
- Tokio - Tokio
@ -26,7 +40,7 @@
let swarm = Swarm::with_tokio_executor(transport, behaviour, peer_id); let swarm = Swarm::with_tokio_executor(transport, behaviour, peer_id);
``` ```
- Async Std - Async Std
Previously Previously
```rust ```rust
let swarm = SwarmBuilder::new(transport, behaviour, peer_id) let swarm = SwarmBuilder::new(transport, behaviour, peer_id)
@ -40,7 +54,7 @@
let swarm = Swarm::with_async_std_executor(transport, behaviour, peer_id); let swarm = Swarm::with_async_std_executor(transport, behaviour, peer_id);
``` ```
- ThreadPool (see [Issue 3107]) - ThreadPool (see [Issue 3107])
In most cases ThreadPool can be replaced by executors or spawning on the local task. In most cases ThreadPool can be replaced by executors or spawning on the local task.
Previously Previously
@ -53,19 +67,20 @@
let swarm = Swarm::with_threadpool_executor(transport, behaviour, peer_id); let swarm = Swarm::with_threadpool_executor(transport, behaviour, peer_id);
``` ```
- Without - Without
Spawns the tasks on the current task, this may result in bad performance so try to use an executor where possible. Previously this was just a fallback when no executor was specified and constructing a `ThreadPool` failed. Spawns the tasks on the current task, this may result in bad performance so try to use an executor where possible. Previously this was just a fallback when no executor was specified and constructing a `ThreadPool` failed.
New New
```rust ```rust
let swarm = Swarm::without_executor(transport, behaviour, peer_id); let swarm = Swarm::without_executor(transport, behaviour, peer_id);
``` ```
Deprecated APIs: Deprecated APIs:
- `Swarm::new` - `Swarm::new`
- `SwarmBuilder::new` - `SwarmBuilder::new`
- `SwarmBuilder::executor` - `SwarmBuilder::executor`
[PR 3011]: https://github.com/libp2p/rust-libp2p/pull/3011
[PR 3055]: https://github.com/libp2p/rust-libp2p/pull/3055 [PR 3055]: https://github.com/libp2p/rust-libp2p/pull/3055
[PR 3097]: https://github.com/libp2p/rust-libp2p/pull/3097 [PR 3097]: https://github.com/libp2p/rust-libp2p/pull/3097
[Issue 3107]: https://github.com/libp2p/rust-libp2p/issues/3107 [Issue 3107]: https://github.com/libp2p/rust-libp2p/issues/3107

View File

@ -153,39 +153,90 @@ pub trait NetworkBehaviour: 'static {
vec![] vec![]
} }
/// Informs the behaviour about an event from the [`Swarm`](crate::Swarm).
fn on_swarm_event(&mut self, _event: FromSwarm<Self::ConnectionHandler>) {}
/// Informs the behaviour about an event generated by the [`ConnectionHandler`] dedicated to the
/// peer identified by `peer_id`. for the behaviour.
///
/// The [`PeerId`] is guaranteed to be in a connected state. In other words,
/// [`FromSwarm::ConnectionEstablished`] has previously been received with this [`PeerId`].
fn on_connection_handler_event(
&mut self,
_peer_id: PeerId,
_connection_id: ConnectionId,
_event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as
ConnectionHandler>::OutEvent,
) {
}
/// Informs the behaviour about a newly established connection to a peer. /// Informs the behaviour about a newly established connection to a peer.
#[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::ConnectionEstablished` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_connection_established( fn inject_connection_established(
&mut self, &mut self,
_peer_id: &PeerId, peer_id: &PeerId,
_connection_id: &ConnectionId, connection_id: &ConnectionId,
_endpoint: &ConnectedPoint, endpoint: &ConnectedPoint,
_failed_addresses: Option<&Vec<Multiaddr>>, failed_addresses: Option<&Vec<Multiaddr>>,
_other_established: usize, other_established: usize,
) { ) {
self.on_swarm_event(FromSwarm::ConnectionEstablished(ConnectionEstablished {
peer_id: *peer_id,
connection_id: *connection_id,
endpoint,
failed_addresses: failed_addresses
.map(|v| v.as_slice())
.unwrap_or_else(|| &[]),
other_established,
}));
} }
/// Informs the behaviour about a closed connection to a peer. /// Informs the behaviour about a closed connection to a peer.
/// ///
/// A call to this method is always paired with an earlier call to /// A call to this method is always paired with an earlier call to
/// [`NetworkBehaviour::inject_connection_established`] with the same peer ID, connection ID and endpoint. /// [`NetworkBehaviour::inject_connection_established`] with the same peer ID, connection ID and endpoint.
#[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::ConnectionClosed` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_connection_closed( fn inject_connection_closed(
&mut self, &mut self,
_: &PeerId, peer_id: &PeerId,
_: &ConnectionId, connection_id: &ConnectionId,
_: &ConnectedPoint, endpoint: &ConnectedPoint,
_: <Self::ConnectionHandler as IntoConnectionHandler>::Handler, handler: <Self::ConnectionHandler as IntoConnectionHandler>::Handler,
_remaining_established: usize, remaining_established: usize,
) { ) {
self.on_swarm_event(FromSwarm::ConnectionClosed(ConnectionClosed {
peer_id: *peer_id,
connection_id: *connection_id,
endpoint,
handler,
remaining_established,
}));
} }
/// Informs the behaviour that the [`ConnectedPoint`] of an existing connection has changed. /// Informs the behaviour that the [`ConnectedPoint`] of an existing connection has changed.
#[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::AddressChange` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_address_change( fn inject_address_change(
&mut self, &mut self,
_: &PeerId, peer_id: &PeerId,
_: &ConnectionId, connection_id: &ConnectionId,
_old: &ConnectedPoint, old: &ConnectedPoint,
_new: &ConnectedPoint, new: &ConnectedPoint,
) { ) {
self.on_swarm_event(FromSwarm::AddressChange(AddressChange {
peer_id: *peer_id,
connection_id: *connection_id,
old,
new,
}));
} }
/// Informs the behaviour about an event generated by the handler dedicated to the peer identified by `peer_id`. /// Informs the behaviour about an event generated by the handler dedicated to the peer identified by `peer_id`.
@ -193,20 +244,35 @@ pub trait NetworkBehaviour: 'static {
/// ///
/// The `peer_id` is guaranteed to be in a connected state. In other words, /// The `peer_id` is guaranteed to be in a connected state. In other words,
/// [`NetworkBehaviour::inject_connection_established`] has previously been called with this `PeerId`. /// [`NetworkBehaviour::inject_connection_established`] has previously been called with this `PeerId`.
#[deprecated(
since = "0.40.2",
note = "Implement `NetworkBehaviour::on_connection_handler_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_event( fn inject_event(
&mut self, &mut self,
peer_id: PeerId, peer_id: PeerId,
connection: ConnectionId, connection: ConnectionId,
event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent, event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent,
); ) {
self.on_connection_handler_event(peer_id, connection, event);
}
/// Indicates to the behaviour that the dial to a known or unknown node failed. /// Indicates to the behaviour that the dial to a known or unknown node failed.
#[deprecated(
since = "0.40.2",
note = "Handle `InEvent::DialFailure` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_dial_failure( fn inject_dial_failure(
&mut self, &mut self,
_peer_id: Option<PeerId>, peer_id: Option<PeerId>,
_handler: Self::ConnectionHandler, handler: Self::ConnectionHandler,
_error: &DialError, error: &DialError,
) { ) {
self.on_swarm_event(FromSwarm::DialFailure(DialFailure {
peer_id,
handler,
error,
}));
} }
/// Indicates to the behaviour that an error happened on an incoming connection during its /// Indicates to the behaviour that an error happened on an incoming connection during its
@ -214,36 +280,98 @@ pub trait NetworkBehaviour: 'static {
/// ///
/// This can include, for example, an error during the handshake of the encryption layer, or the /// This can include, for example, an error during the handshake of the encryption layer, or the
/// connection unexpectedly closed. /// connection unexpectedly closed.
#[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::ListenFailure` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_listen_failure( fn inject_listen_failure(
&mut self, &mut self,
_local_addr: &Multiaddr, local_addr: &Multiaddr,
_send_back_addr: &Multiaddr, send_back_addr: &Multiaddr,
_handler: Self::ConnectionHandler, handler: Self::ConnectionHandler,
) { ) {
self.on_swarm_event(FromSwarm::ListenFailure(ListenFailure {
local_addr,
send_back_addr,
handler,
}));
} }
/// Indicates to the behaviour that a new listener was created. /// Indicates to the behaviour that a new listener was created.
fn inject_new_listener(&mut self, _id: ListenerId) {} #[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::NewListener` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_new_listener(&mut self, id: ListenerId) {
self.on_swarm_event(FromSwarm::NewListener(NewListener { listener_id: id }));
}
/// Indicates to the behaviour that we have started listening on a new multiaddr. /// Indicates to the behaviour that we have started listening on a new multiaddr.
fn inject_new_listen_addr(&mut self, _id: ListenerId, _addr: &Multiaddr) {} #[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::NewListenAddr` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) {
self.on_swarm_event(FromSwarm::NewListenAddr(NewListenAddr {
listener_id: id,
addr,
}));
}
/// Indicates to the behaviour that a multiaddr we were listening on has expired, /// Indicates to the behaviour that a multiaddr we were listening on has expired,
/// which means that we are no longer listening in it. /// which means that we are no longer listening on it.
fn inject_expired_listen_addr(&mut self, _id: ListenerId, _addr: &Multiaddr) {} #[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::ExpiredListenAddr` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) {
self.on_swarm_event(FromSwarm::ExpiredListenAddr(ExpiredListenAddr {
listener_id: id,
addr,
}));
}
/// A listener experienced an error. /// A listener experienced an error.
fn inject_listener_error(&mut self, _id: ListenerId, _err: &(dyn std::error::Error + 'static)) { #[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::ListenerError` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) {
self.on_swarm_event(FromSwarm::ListenerError(ListenerError {
listener_id: id,
err,
}));
} }
/// A listener closed. /// A listener closed.
fn inject_listener_closed(&mut self, _id: ListenerId, _reason: Result<(), &std::io::Error>) {} #[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::ListenerClosed` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &std::io::Error>) {
self.on_swarm_event(FromSwarm::ListenerClosed(ListenerClosed {
listener_id: id,
reason,
}));
}
/// Indicates to the behaviour that we have discovered a new external address for us. /// Indicates to the behaviour that we have discovered a new external address for us.
fn inject_new_external_addr(&mut self, _addr: &Multiaddr) {} #[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::NewExternalAddr` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_new_external_addr(&mut self, addr: &Multiaddr) {
self.on_swarm_event(FromSwarm::NewExternalAddr(NewExternalAddr { addr }));
}
/// Indicates to the behaviour that an external address was removed. /// Indicates to the behaviour that an external address was removed.
fn inject_expired_external_addr(&mut self, _addr: &Multiaddr) {} #[deprecated(
since = "0.40.2",
note = "Handle `FromSwarm::ExpiredExternalAddr` in `NetworkBehaviour::on_swarm_event` instead. The default implementation of this `inject_*` method delegates to it."
)]
fn inject_expired_external_addr(&mut self, addr: &Multiaddr) {
self.on_swarm_event(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }));
}
/// Polls for things that swarm should do. /// Polls for things that swarm should do.
/// ///
@ -722,3 +850,364 @@ impl Default for CloseConnection {
CloseConnection::All CloseConnection::All
} }
} }
/// Enumeration with the list of the possible events
/// to pass to [`on_swarm_event`](NetworkBehaviour::on_swarm_event).
pub enum FromSwarm<'a, Handler: IntoConnectionHandler> {
/// Informs the behaviour about a newly established connection to a peer.
ConnectionEstablished(ConnectionEstablished<'a>),
/// Informs the behaviour about a closed connection to a peer.
///
/// This event is always paired with an earlier
/// [`FromSwarm::ConnectionEstablished`] with the same peer ID, connection ID
/// and endpoint.
ConnectionClosed(ConnectionClosed<'a, Handler>),
/// Informs the behaviour that the [`ConnectedPoint`] of an existing
/// connection has changed.
AddressChange(AddressChange<'a>),
/// Informs the behaviour that the dial to a known
/// or unknown node failed.
DialFailure(DialFailure<'a, Handler>),
/// Informs the behaviour that an error
/// happened on an incoming connection during its initial handshake.
///
/// This can include, for example, an error during the handshake of the encryption layer, or the
/// connection unexpectedly closed.
ListenFailure(ListenFailure<'a, Handler>),
/// Informs the behaviour that a new listener was created.
NewListener(NewListener),
/// Informs the behaviour that we have started listening on a new multiaddr.
NewListenAddr(NewListenAddr<'a>),
/// Informs the behaviour that a multiaddr
/// we were listening on has expired,
/// which means that we are no longer listening on it.
ExpiredListenAddr(ExpiredListenAddr<'a>),
/// Informs the behaviour that a listener experienced an error.
ListenerError(ListenerError<'a>),
/// Informs the behaviour that a listener closed.
ListenerClosed(ListenerClosed<'a>),
/// Informs the behaviour that we have discovered a new external address for us.
NewExternalAddr(NewExternalAddr<'a>),
/// Informs the behaviour that an external address was removed.
ExpiredExternalAddr(ExpiredExternalAddr<'a>),
}
/// [`FromSwarm`] variant that informs the behaviour about a newly established connection to a peer.
#[derive(Clone, Copy)]
pub struct ConnectionEstablished<'a> {
pub peer_id: PeerId,
pub connection_id: ConnectionId,
pub endpoint: &'a ConnectedPoint,
pub failed_addresses: &'a [Multiaddr],
pub other_established: usize,
}
/// [`FromSwarm`] variant that informs the behaviour about a closed connection to a peer.
///
/// This event is always paired with an earlier
/// [`FromSwarm::ConnectionEstablished`] with the same peer ID, connection ID
/// and endpoint.
pub struct ConnectionClosed<'a, Handler: IntoConnectionHandler> {
pub peer_id: PeerId,
pub connection_id: ConnectionId,
pub endpoint: &'a ConnectedPoint,
pub handler: <Handler as IntoConnectionHandler>::Handler,
pub remaining_established: usize,
}
/// [`FromSwarm`] variant that informs the behaviour that the [`ConnectedPoint`] of an existing
/// connection has changed.
#[derive(Clone, Copy)]
pub struct AddressChange<'a> {
pub peer_id: PeerId,
pub connection_id: ConnectionId,
pub old: &'a ConnectedPoint,
pub new: &'a ConnectedPoint,
}
/// [`FromSwarm`] variant that informs the behaviour that the dial to a known
/// or unknown node failed.
#[derive(Clone, Copy)]
pub struct DialFailure<'a, Handler> {
pub peer_id: Option<PeerId>,
pub handler: Handler,
pub error: &'a DialError,
}
/// [`FromSwarm`] variant that informs the behaviour that an error
/// happened on an incoming connection during its initial handshake.
///
/// This can include, for example, an error during the handshake of the encryption layer, or the
/// connection unexpectedly closed.
#[derive(Clone, Copy)]
pub struct ListenFailure<'a, Handler> {
pub local_addr: &'a Multiaddr,
pub send_back_addr: &'a Multiaddr,
pub handler: Handler,
}
/// [`FromSwarm`] variant that informs the behaviour that a new listener was created.
#[derive(Clone, Copy)]
pub struct NewListener {
pub listener_id: ListenerId,
}
/// [`FromSwarm`] variant that informs the behaviour
/// that we have started listening on a new multiaddr.
#[derive(Clone, Copy)]
pub struct NewListenAddr<'a> {
pub listener_id: ListenerId,
pub addr: &'a Multiaddr,
}
/// [`FromSwarm`] variant that informs the behaviour that a multiaddr
/// we were listening on has expired,
/// which means that we are no longer listening on it.
#[derive(Clone, Copy)]
pub struct ExpiredListenAddr<'a> {
pub listener_id: ListenerId,
pub addr: &'a Multiaddr,
}
/// [`FromSwarm`] variant that informs the behaviour that a listener experienced an error.
#[derive(Clone, Copy)]
pub struct ListenerError<'a> {
pub listener_id: ListenerId,
pub err: &'a (dyn std::error::Error + 'static),
}
/// [`FromSwarm`] variant that informs the behaviour that a listener closed.
#[derive(Clone, Copy)]
pub struct ListenerClosed<'a> {
pub listener_id: ListenerId,
pub reason: Result<(), &'a std::io::Error>,
}
/// [`FromSwarm`] variant that informs the behaviour
/// that we have discovered a new external address for us.
#[derive(Clone, Copy)]
pub struct NewExternalAddr<'a> {
pub addr: &'a Multiaddr,
}
/// [`FromSwarm`] variant that informs the behaviour that an external address was removed.
#[derive(Clone, Copy)]
pub struct ExpiredExternalAddr<'a> {
pub addr: &'a Multiaddr,
}
impl<'a, Handler: IntoConnectionHandler> FromSwarm<'a, Handler> {
fn map_handler<NewHandler>(
self,
map_into_handler: impl FnOnce(Handler) -> NewHandler,
map_handler: impl FnOnce(
<Handler as IntoConnectionHandler>::Handler,
) -> <NewHandler as IntoConnectionHandler>::Handler,
) -> FromSwarm<'a, NewHandler>
where
NewHandler: IntoConnectionHandler,
{
self.maybe_map_handler(|h| Some(map_into_handler(h)), |h| Some(map_handler(h)))
.expect("To return Some as all closures return Some.")
}
fn maybe_map_handler<NewHandler>(
self,
map_into_handler: impl FnOnce(Handler) -> Option<NewHandler>,
map_handler: impl FnOnce(
<Handler as IntoConnectionHandler>::Handler,
) -> Option<<NewHandler as IntoConnectionHandler>::Handler>,
) -> Option<FromSwarm<'a, NewHandler>>
where
NewHandler: IntoConnectionHandler,
{
match self {
FromSwarm::ConnectionClosed(ConnectionClosed {
peer_id,
connection_id,
endpoint,
handler,
remaining_established,
}) => Some(FromSwarm::ConnectionClosed(ConnectionClosed {
peer_id,
connection_id,
endpoint,
handler: map_handler(handler)?,
remaining_established,
})),
FromSwarm::ConnectionEstablished(ConnectionEstablished {
peer_id,
connection_id,
endpoint,
failed_addresses,
other_established,
}) => Some(FromSwarm::ConnectionEstablished(ConnectionEstablished {
peer_id,
connection_id,
endpoint,
failed_addresses,
other_established,
})),
FromSwarm::AddressChange(AddressChange {
peer_id,
connection_id,
old,
new,
}) => Some(FromSwarm::AddressChange(AddressChange {
peer_id,
connection_id,
old,
new,
})),
FromSwarm::DialFailure(DialFailure {
peer_id,
handler,
error,
}) => Some(FromSwarm::DialFailure(DialFailure {
peer_id,
handler: map_into_handler(handler)?,
error,
})),
FromSwarm::ListenFailure(ListenFailure {
local_addr,
send_back_addr,
handler,
}) => Some(FromSwarm::ListenFailure(ListenFailure {
local_addr,
send_back_addr,
handler: map_into_handler(handler)?,
})),
FromSwarm::NewListener(NewListener { listener_id }) => {
Some(FromSwarm::NewListener(NewListener { listener_id }))
}
FromSwarm::NewListenAddr(NewListenAddr { listener_id, addr }) => {
Some(FromSwarm::NewListenAddr(NewListenAddr {
listener_id,
addr,
}))
}
FromSwarm::ExpiredListenAddr(ExpiredListenAddr { listener_id, addr }) => {
Some(FromSwarm::ExpiredListenAddr(ExpiredListenAddr {
listener_id,
addr,
}))
}
FromSwarm::ListenerError(ListenerError { listener_id, err }) => {
Some(FromSwarm::ListenerError(ListenerError { listener_id, err }))
}
FromSwarm::ListenerClosed(ListenerClosed {
listener_id,
reason,
}) => Some(FromSwarm::ListenerClosed(ListenerClosed {
listener_id,
reason,
})),
FromSwarm::NewExternalAddr(NewExternalAddr { addr }) => {
Some(FromSwarm::NewExternalAddr(NewExternalAddr { addr }))
}
FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }) => {
Some(FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }))
}
}
}
}
/// Helper function to call [`NetworkBehaviour`]'s `inject_*` methods given a `FromSwarm.
/// TODO: Remove this function when we remove the remaining `inject_*` calls
/// from [`Either`] and [`Toggle`].
pub(crate) fn inject_from_swarm<T: NetworkBehaviour>(
behaviour: &mut T,
event: FromSwarm<T::ConnectionHandler>,
) {
match event {
FromSwarm::ConnectionEstablished(ConnectionEstablished {
peer_id,
connection_id,
endpoint,
failed_addresses,
other_established,
}) => {
#[allow(deprecated)]
behaviour.inject_connection_established(
&peer_id,
&connection_id,
endpoint,
Some(&failed_addresses.into()),
other_established,
);
}
FromSwarm::ConnectionClosed(ConnectionClosed {
peer_id,
connection_id,
endpoint,
handler,
remaining_established,
}) => {
#[allow(deprecated)]
behaviour.inject_connection_closed(
&peer_id,
&connection_id,
endpoint,
handler,
remaining_established,
);
}
FromSwarm::AddressChange(AddressChange {
peer_id,
connection_id,
old,
new,
}) => {
#[allow(deprecated)]
behaviour.inject_address_change(&peer_id, &connection_id, old, new);
}
FromSwarm::DialFailure(DialFailure {
peer_id,
handler,
error,
}) => {
#[allow(deprecated)]
behaviour.inject_dial_failure(peer_id, handler, error);
}
FromSwarm::ListenFailure(ListenFailure {
local_addr,
send_back_addr,
handler,
}) => {
#[allow(deprecated)]
behaviour.inject_listen_failure(local_addr, send_back_addr, handler);
}
FromSwarm::NewListener(NewListener { listener_id }) => {
#[allow(deprecated)]
behaviour.inject_new_listener(listener_id);
}
FromSwarm::NewListenAddr(NewListenAddr { listener_id, addr }) => {
#[allow(deprecated)]
behaviour.inject_new_listen_addr(listener_id, addr);
}
FromSwarm::ExpiredListenAddr(ExpiredListenAddr { listener_id, addr }) => {
#[allow(deprecated)]
behaviour.inject_expired_listen_addr(listener_id, addr);
}
FromSwarm::ListenerError(ListenerError { listener_id, err }) => {
#[allow(deprecated)]
behaviour.inject_listener_error(listener_id, err);
}
FromSwarm::ListenerClosed(ListenerClosed {
listener_id,
reason,
}) => {
#[allow(deprecated)]
behaviour.inject_listener_closed(listener_id, reason);
}
FromSwarm::NewExternalAddr(NewExternalAddr { addr }) => {
#[allow(deprecated)]
behaviour.inject_new_external_addr(addr);
}
FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }) =>
{
#[allow(deprecated)]
behaviour.inject_expired_external_addr(addr)
}
}
}

View File

@ -18,12 +18,12 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::handler::{either::IntoEitherHandler, ConnectionHandler, IntoConnectionHandler}; use crate::behaviour::{
use crate::{DialError, NetworkBehaviour, NetworkBehaviourAction, PollParameters}; self, inject_from_swarm, NetworkBehaviour, NetworkBehaviourAction, PollParameters,
use either::Either;
use libp2p_core::{
connection::ConnectionId, transport::ListenerId, ConnectedPoint, Multiaddr, PeerId,
}; };
use crate::handler::either::IntoEitherHandler;
use either::Either;
use libp2p_core::{Multiaddr, PeerId};
use std::{task::Context, task::Poll}; use std::{task::Context, task::Poll};
/// Implementation of [`NetworkBehaviour`] that can be either of two implementations. /// Implementation of [`NetworkBehaviour`] that can be either of two implementations.
@ -49,173 +49,50 @@ where
} }
} }
fn inject_connection_established( fn on_swarm_event(&mut self, event: behaviour::FromSwarm<Self::ConnectionHandler>) {
&mut self,
peer_id: &PeerId,
connection: &ConnectionId,
endpoint: &ConnectedPoint,
errors: Option<&Vec<Multiaddr>>,
other_established: usize,
) {
match self { match self {
Either::Left(a) => a.inject_connection_established( Either::Left(b) => inject_from_swarm(
peer_id, b,
connection, event.map_handler(
endpoint, |h| h.unwrap_left(),
errors, |h| match h {
other_established, Either::Left(h) => h,
), Either::Right(_) => unreachable!(),
Either::Right(b) => b.inject_connection_established( },
peer_id,
connection,
endpoint,
errors,
other_established,
),
}
}
fn inject_connection_closed(
&mut self,
peer_id: &PeerId,
connection: &ConnectionId,
endpoint: &ConnectedPoint,
handler: <Self::ConnectionHandler as IntoConnectionHandler>::Handler,
remaining_established: usize,
) {
match (self, handler) {
(Either::Left(behaviour), Either::Left(handler)) => behaviour.inject_connection_closed(
peer_id,
connection,
endpoint,
handler,
remaining_established,
),
(Either::Right(behaviour), Either::Right(handler)) => behaviour
.inject_connection_closed(
peer_id,
connection,
endpoint,
handler,
remaining_established,
), ),
_ => unreachable!(), ),
Either::Right(b) => inject_from_swarm(
b,
event.map_handler(
|h| h.unwrap_right(),
|h| match h {
Either::Right(h) => h,
Either::Left(_) => unreachable!(),
},
),
),
} }
} }
fn inject_address_change( fn on_connection_handler_event(
&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, &mut self,
peer_id: PeerId, peer_id: PeerId,
connection: ConnectionId, connection_id: libp2p_core::connection::ConnectionId,
event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent, event: crate::THandlerOutEvent<Self>,
) { ) {
match (self, event) { match (self, event) {
(Either::Left(behaviour), Either::Left(event)) => { (Either::Left(left), Either::Left(event)) => {
behaviour.inject_event(peer_id, connection, event) #[allow(deprecated)]
left.inject_event(peer_id, connection_id, event);
} }
(Either::Right(behaviour), Either::Right(event)) => { (Either::Right(right), Either::Right(event)) => {
behaviour.inject_event(peer_id, connection, event) #[allow(deprecated)]
right.inject_event(peer_id, connection_id, event);
} }
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn inject_dial_failure(
&mut self,
peer_id: Option<PeerId>,
handler: Self::ConnectionHandler,
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::ConnectionHandler,
) {
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( fn poll(
&mut self, &mut self,
cx: &mut Context<'_>, cx: &mut Context<'_>,

View File

@ -18,17 +18,16 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::behaviour::{inject_from_swarm, FromSwarm};
use crate::handler::{ use crate::handler::{
ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, IntoConnectionHandler, ConnectionHandler, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, IntoConnectionHandler,
KeepAlive, SubstreamProtocol, KeepAlive, SubstreamProtocol,
}; };
use crate::upgrade::{InboundUpgradeSend, OutboundUpgradeSend, SendWrapper}; use crate::upgrade::{InboundUpgradeSend, OutboundUpgradeSend, SendWrapper};
use crate::{DialError, NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use crate::{NetworkBehaviour, NetworkBehaviourAction, PollParameters};
use either::Either; use either::Either;
use libp2p_core::{ use libp2p_core::{
connection::ConnectionId,
either::{EitherError, EitherOutput}, either::{EitherError, EitherOutput},
transport::ListenerId,
upgrade::{DeniedUpgrade, EitherUpgrade}, upgrade::{DeniedUpgrade, EitherUpgrade},
ConnectedPoint, Multiaddr, PeerId, ConnectedPoint, Multiaddr, PeerId,
}; };
@ -84,134 +83,23 @@ where
.unwrap_or_else(Vec::new) .unwrap_or_else(Vec::new)
} }
fn inject_connection_established( fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
&mut self, if let Some(behaviour) = &mut self.inner {
peer_id: &PeerId, if let Some(event) = event.maybe_map_handler(|h| h.inner, |h| h.inner) {
connection: &ConnectionId, inject_from_swarm(behaviour, event);
endpoint: &ConnectedPoint,
errors: Option<&Vec<Multiaddr>>,
other_established: usize,
) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_connection_established(
peer_id,
connection,
endpoint,
errors,
other_established,
)
}
}
fn inject_connection_closed(
&mut self,
peer_id: &PeerId,
connection: &ConnectionId,
endpoint: &ConnectedPoint,
handler: <Self::ConnectionHandler as IntoConnectionHandler>::Handler,
remaining_established: usize,
) {
if let Some(inner) = self.inner.as_mut() {
if let Some(handler) = handler.inner {
inner.inject_connection_closed(
peer_id,
connection,
endpoint,
handler,
remaining_established,
)
} }
} }
} }
fn inject_address_change( fn on_connection_handler_event(
&mut self,
peer_id: &PeerId,
connection: &ConnectionId,
old: &ConnectedPoint,
new: &ConnectedPoint,
) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_address_change(peer_id, connection, old, new)
}
}
fn inject_event(
&mut self, &mut self,
peer_id: PeerId, peer_id: PeerId,
connection: ConnectionId, connection_id: libp2p_core::connection::ConnectionId,
event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent, event: crate::THandlerOutEvent<Self>,
) { ) {
if let Some(inner) = self.inner.as_mut() { if let Some(behaviour) = &mut self.inner {
inner.inject_event(peer_id, connection, event); #[allow(deprecated)]
} behaviour.inject_event(peer_id, connection_id, event)
}
fn inject_dial_failure(
&mut self,
peer_id: Option<PeerId>,
handler: Self::ConnectionHandler,
error: &DialError,
) {
if let Some(inner) = self.inner.as_mut() {
if let Some(handler) = handler.inner {
inner.inject_dial_failure(peer_id, handler, error)
}
}
}
fn inject_listen_failure(
&mut self,
local_addr: &Multiaddr,
send_back_addr: &Multiaddr,
handler: Self::ConnectionHandler,
) {
if let Some(inner) = self.inner.as_mut() {
if let Some(handler) = handler.inner {
inner.inject_listen_failure(local_addr, send_back_addr, handler)
}
}
}
fn inject_new_listener(&mut self, id: ListenerId) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_new_listener(id)
}
}
fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_new_listen_addr(id, addr)
}
}
fn inject_expired_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_expired_listen_addr(id, addr)
}
}
fn inject_new_external_addr(&mut self, addr: &Multiaddr) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_new_external_addr(addr)
}
}
fn inject_expired_external_addr(&mut self, addr: &Multiaddr) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_expired_external_addr(addr)
}
}
fn inject_listener_error(&mut self, id: ListenerId, err: &(dyn std::error::Error + 'static)) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_listener_error(id, err)
}
}
fn inject_listener_closed(&mut self, id: ListenerId, reason: Result<(), &std::io::Error>) {
if let Some(inner) = self.inner.as_mut() {
inner.inject_listener_closed(id, reason)
} }
} }

View File

@ -1,4 +1,4 @@
use crate::behaviour::{NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use crate::behaviour::{FromSwarm, NetworkBehaviour, NetworkBehaviourAction, PollParameters};
use crate::handler::{InboundUpgradeSend, OutboundUpgradeSend}; use crate::handler::{InboundUpgradeSend, OutboundUpgradeSend};
use crate::{ConnectionHandlerEvent, ConnectionHandlerUpgrErr, KeepAlive, SubstreamProtocol}; use crate::{ConnectionHandlerEvent, ConnectionHandlerUpgrErr, KeepAlive, SubstreamProtocol};
use libp2p_core::connection::ConnectionId; use libp2p_core::connection::ConnectionId;
@ -19,7 +19,7 @@ impl NetworkBehaviour for Behaviour {
ConnectionHandler ConnectionHandler
} }
fn inject_event(&mut self, _: PeerId, _: ConnectionId, event: Void) { fn on_connection_handler_event(&mut self, _: PeerId, _: ConnectionId, event: Void) {
void::unreachable(event) void::unreachable(event)
} }
@ -30,6 +30,23 @@ impl NetworkBehaviour for Behaviour {
) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ConnectionHandler>> { ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ConnectionHandler>> {
Poll::Pending Poll::Pending
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(_)
| FromSwarm::ConnectionClosed(_)
| FromSwarm::AddressChange(_)
| FromSwarm::DialFailure(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }
/// An implementation of [`ConnectionHandler`] that neither handles any protocols nor does it keep the connection alive. /// An implementation of [`ConnectionHandler`] that neither handles any protocols nor does it keep the connection alive.

View File

@ -29,6 +29,8 @@ use libp2p_core::upgrade::{EitherUpgrade, UpgradeError};
use libp2p_core::{ConnectedPoint, Multiaddr, PeerId}; use libp2p_core::{ConnectedPoint, Multiaddr, PeerId};
use std::task::{Context, Poll}; use std::task::{Context, Poll};
/// Auxiliary type to allow implementing [`IntoConnectionHandler`]. As [`IntoConnectionHandler`] is
/// already implemented for T, we cannot implement it for Either<A, B>.
pub enum IntoEitherHandler<L, R> { pub enum IntoEitherHandler<L, R> {
Left(L), Left(L),
Right(R), Right(R),
@ -64,6 +66,29 @@ where
} }
} }
// Taken from https://github.com/bluss/either.
impl<L, R> IntoEitherHandler<L, R> {
/// Returns the left value.
pub fn unwrap_left(self) -> L {
match self {
IntoEitherHandler::Left(l) => l,
IntoEitherHandler::Right(_) => {
panic!("called `IntoEitherHandler::unwrap_left()` on a `Right` value.",)
}
}
}
/// Returns the right value.
pub fn unwrap_right(self) -> R {
match self {
IntoEitherHandler::Right(r) => r,
IntoEitherHandler::Left(_) => {
panic!("called `IntoEitherHandler::unwrap_right()` on a `Left` value.",)
}
}
}
}
/// Implementation of a [`ConnectionHandler`] that represents either of two [`ConnectionHandler`] /// Implementation of a [`ConnectionHandler`] that represents either of two [`ConnectionHandler`]
/// implementations. /// implementations.
impl<L, R> ConnectionHandler for Either<L, R> impl<L, R> ConnectionHandler for Either<L, R>

View File

@ -1,4 +1,4 @@
use crate::behaviour::{NetworkBehaviour, NetworkBehaviourAction, PollParameters}; use crate::behaviour::{FromSwarm, NetworkBehaviour, NetworkBehaviourAction, PollParameters};
use crate::handler::{ use crate::handler::{
ConnectionHandlerEvent, ConnectionHandlerUpgrErr, KeepAlive, SubstreamProtocol, ConnectionHandlerEvent, ConnectionHandlerUpgrErr, KeepAlive, SubstreamProtocol,
}; };
@ -29,7 +29,7 @@ impl NetworkBehaviour for Behaviour {
ConnectionHandler ConnectionHandler
} }
fn inject_event(&mut self, _: PeerId, _: ConnectionId, event: Void) { fn on_connection_handler_event(&mut self, _: PeerId, _: ConnectionId, event: Void) {
void::unreachable(event) void::unreachable(event)
} }
@ -40,6 +40,23 @@ impl NetworkBehaviour for Behaviour {
) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ConnectionHandler>> { ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ConnectionHandler>> {
Poll::Pending Poll::Pending
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(_)
| FromSwarm::ConnectionClosed(_)
| FromSwarm::AddressChange(_)
| FromSwarm::DialFailure(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }
/// Implementation of [`ConnectionHandler`] that doesn't handle anything but keeps the connection alive. /// Implementation of [`ConnectionHandler`] that doesn't handle anything but keeps the connection alive.

View File

@ -71,6 +71,19 @@ pub mod keep_alive;
/// Bundles all symbols required for the [`libp2p_swarm_derive::NetworkBehaviour`] macro. /// Bundles all symbols required for the [`libp2p_swarm_derive::NetworkBehaviour`] macro.
#[doc(hidden)] #[doc(hidden)]
pub mod derive_prelude { pub mod derive_prelude {
pub use crate::behaviour::AddressChange;
pub use crate::behaviour::ConnectionClosed;
pub use crate::behaviour::ConnectionEstablished;
pub use crate::behaviour::DialFailure;
pub use crate::behaviour::ExpiredExternalAddr;
pub use crate::behaviour::ExpiredListenAddr;
pub use crate::behaviour::FromSwarm;
pub use crate::behaviour::ListenFailure;
pub use crate::behaviour::ListenerClosed;
pub use crate::behaviour::ListenerError;
pub use crate::behaviour::NewExternalAddr;
pub use crate::behaviour::NewListenAddr;
pub use crate::behaviour::NewListener;
pub use crate::ConnectionHandler; pub use crate::ConnectionHandler;
pub use crate::DialError; pub use crate::DialError;
pub use crate::IntoConnectionHandler; pub use crate::IntoConnectionHandler;
@ -432,6 +445,7 @@ where
/// Depending on the underlying transport, one listener may have multiple listening addresses. /// Depending on the underlying transport, one listener may have multiple listening addresses.
pub fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<io::Error>> { pub fn listen_on(&mut self, addr: Multiaddr) -> Result<ListenerId, TransportError<io::Error>> {
let id = self.transport.listen_on(addr)?; let id = self.transport.listen_on(addr)?;
#[allow(deprecated)]
self.behaviour.inject_new_listener(id); self.behaviour.inject_new_listener(id);
Ok(id) Ok(id)
} }
@ -500,6 +514,7 @@ where
PeerCondition::Always => true, PeerCondition::Always => true,
}; };
if !condition_matched { if !condition_matched {
#[allow(deprecated)]
self.behaviour.inject_dial_failure( self.behaviour.inject_dial_failure(
Some(peer_id), Some(peer_id),
handler, handler,
@ -512,6 +527,7 @@ where
// Check if peer is banned. // Check if peer is banned.
if self.banned_peers.contains(&peer_id) { if self.banned_peers.contains(&peer_id) {
let error = DialError::Banned; let error = DialError::Banned;
#[allow(deprecated)]
self.behaviour self.behaviour
.inject_dial_failure(Some(peer_id), handler, &error); .inject_dial_failure(Some(peer_id), handler, &error);
return Err(error); return Err(error);
@ -549,6 +565,7 @@ where
if addresses.is_empty() { if addresses.is_empty() {
let error = DialError::NoAddresses; let error = DialError::NoAddresses;
#[allow(deprecated)]
self.behaviour self.behaviour
.inject_dial_failure(Some(peer_id), handler, &error); .inject_dial_failure(Some(peer_id), handler, &error);
return Err(error); return Err(error);
@ -632,6 +649,7 @@ where
Ok(_connection_id) => Ok(()), Ok(_connection_id) => Ok(()),
Err((connection_limit, handler)) => { Err((connection_limit, handler)) => {
let error = DialError::ConnectionLimit(connection_limit); let error = DialError::ConnectionLimit(connection_limit);
#[allow(deprecated)]
self.behaviour.inject_dial_failure(peer_id, handler, &error); self.behaviour.inject_dial_failure(peer_id, handler, &error);
Err(error) Err(error)
} }
@ -673,12 +691,14 @@ where
let result = self.external_addrs.add(a.clone(), s); let result = self.external_addrs.add(a.clone(), s);
let expired = match &result { let expired = match &result {
AddAddressResult::Inserted { expired } => { AddAddressResult::Inserted { expired } => {
#[allow(deprecated)]
self.behaviour.inject_new_external_addr(&a); self.behaviour.inject_new_external_addr(&a);
expired expired
} }
AddAddressResult::Updated { expired } => expired, AddAddressResult::Updated { expired } => expired,
}; };
for a in expired { for a in expired {
#[allow(deprecated)]
self.behaviour.inject_expired_external_addr(&a.addr); self.behaviour.inject_expired_external_addr(&a.addr);
} }
result result
@ -692,6 +712,7 @@ where
/// otherwise. /// otherwise.
pub fn remove_external_address(&mut self, addr: &Multiaddr) -> bool { pub fn remove_external_address(&mut self, addr: &Multiaddr) -> bool {
if self.external_addrs.remove(addr) { if self.external_addrs.remove(addr) {
#[allow(deprecated)]
self.behaviour.inject_expired_external_addr(addr); self.behaviour.inject_expired_external_addr(addr);
true true
} else { } else {
@ -798,6 +819,7 @@ where
let failed_addresses = concurrent_dial_errors let failed_addresses = concurrent_dial_errors
.as_ref() .as_ref()
.map(|es| es.iter().map(|(a, _)| a).cloned().collect()); .map(|es| es.iter().map(|(a, _)| a).cloned().collect());
#[allow(deprecated)]
self.behaviour.inject_connection_established( self.behaviour.inject_connection_established(
&peer_id, &peer_id,
&id, &id,
@ -821,6 +843,7 @@ where
} => { } => {
let error = error.into(); let error = error.into();
#[allow(deprecated)]
self.behaviour.inject_dial_failure(peer, handler, &error); self.behaviour.inject_dial_failure(peer, handler, &error);
if let Some(peer) = peer { if let Some(peer) = peer {
@ -842,6 +865,7 @@ where
handler, handler,
} => { } => {
log::debug!("Incoming connection failed: {:?}", error); log::debug!("Incoming connection failed: {:?}", error);
#[allow(deprecated)]
self.behaviour self.behaviour
.inject_listen_failure(&local_addr, &send_back_addr, handler); .inject_listen_failure(&local_addr, &send_back_addr, handler);
return Some(SwarmEvent::IncomingConnectionError { return Some(SwarmEvent::IncomingConnectionError {
@ -882,6 +906,7 @@ where
.into_iter() .into_iter()
.filter(|conn_id| !self.banned_peer_connections.contains(conn_id)) .filter(|conn_id| !self.banned_peer_connections.contains(conn_id))
.count(); .count();
#[allow(deprecated)]
self.behaviour.inject_connection_closed( self.behaviour.inject_connection_closed(
&peer_id, &peer_id,
&id, &id,
@ -901,6 +926,7 @@ where
if self.banned_peer_connections.contains(&id) { if self.banned_peer_connections.contains(&id) {
log::debug!("Ignoring event from banned peer: {} {:?}.", peer_id, id); log::debug!("Ignoring event from banned peer: {} {:?}.", peer_id, id);
} else { } else {
#[allow(deprecated)]
self.behaviour.inject_event(peer_id, id, event); self.behaviour.inject_event(peer_id, id, event);
} }
} }
@ -911,6 +937,7 @@ where
old_endpoint, old_endpoint,
} => { } => {
if !self.banned_peer_connections.contains(&id) { if !self.banned_peer_connections.contains(&id) {
#[allow(deprecated)]
self.behaviour.inject_address_change( self.behaviour.inject_address_change(
&peer_id, &peer_id,
&id, &id,
@ -954,6 +981,7 @@ where
}); });
} }
Err((connection_limit, handler)) => { Err((connection_limit, handler)) => {
#[allow(deprecated)]
self.behaviour self.behaviour
.inject_listen_failure(&local_addr, &send_back_addr, handler); .inject_listen_failure(&local_addr, &send_back_addr, handler);
log::warn!("Incoming connection rejected: {:?}", connection_limit); log::warn!("Incoming connection rejected: {:?}", connection_limit);
@ -969,6 +997,7 @@ where
if !addrs.contains(&listen_addr) { if !addrs.contains(&listen_addr) {
addrs.push(listen_addr.clone()) addrs.push(listen_addr.clone())
} }
#[allow(deprecated)]
self.behaviour self.behaviour
.inject_new_listen_addr(listener_id, &listen_addr); .inject_new_listen_addr(listener_id, &listen_addr);
return Some(SwarmEvent::NewListenAddr { return Some(SwarmEvent::NewListenAddr {
@ -988,6 +1017,7 @@ where
if let Some(addrs) = self.listened_addrs.get_mut(&listener_id) { if let Some(addrs) = self.listened_addrs.get_mut(&listener_id) {
addrs.retain(|a| a != &listen_addr); addrs.retain(|a| a != &listen_addr);
} }
#[allow(deprecated)]
self.behaviour self.behaviour
.inject_expired_listen_addr(listener_id, &listen_addr); .inject_expired_listen_addr(listener_id, &listen_addr);
return Some(SwarmEvent::ExpiredListenAddr { return Some(SwarmEvent::ExpiredListenAddr {
@ -1002,8 +1032,10 @@ where
log::debug!("Listener {:?}; Closed by {:?}.", listener_id, reason); log::debug!("Listener {:?}; Closed by {:?}.", listener_id, reason);
let addrs = self.listened_addrs.remove(&listener_id).unwrap_or_default(); let addrs = self.listened_addrs.remove(&listener_id).unwrap_or_default();
for addr in addrs.iter() { for addr in addrs.iter() {
#[allow(deprecated)]
self.behaviour.inject_expired_listen_addr(listener_id, addr); self.behaviour.inject_expired_listen_addr(listener_id, addr);
} }
#[allow(deprecated)]
self.behaviour.inject_listener_closed( self.behaviour.inject_listener_closed(
listener_id, listener_id,
match &reason { match &reason {
@ -1018,6 +1050,7 @@ where
}); });
} }
TransportEvent::ListenerError { listener_id, error } => { TransportEvent::ListenerError { listener_id, error } => {
#[allow(deprecated)]
self.behaviour.inject_listener_error(listener_id, &error); self.behaviour.inject_listener_error(listener_id, &error);
return Some(SwarmEvent::ListenerError { listener_id, error }); return Some(SwarmEvent::ListenerError { listener_id, error });
} }
@ -1868,7 +1901,7 @@ mod tests {
// The banned connection was established. Check that it was not reported to // The banned connection was established. Check that it was not reported to
// the behaviour of the banning swarm. // the behaviour of the banning swarm.
assert_eq!( assert_eq!(
swarm2.behaviour.inject_connection_established.len(), s2_expected_conns, swarm2.behaviour.on_connection_established.len(), s2_expected_conns,
"No additional closed connections should be reported for the banned peer" "No additional closed connections should be reported for the banned peer"
); );
@ -1882,7 +1915,7 @@ mod tests {
if swarm2.network_info().num_peers() == 0 { if swarm2.network_info().num_peers() == 0 {
// The banned connection has closed. Check that it was not reported. // The banned connection has closed. Check that it was not reported.
assert_eq!( assert_eq!(
swarm2.behaviour.inject_connection_closed.len(), s2_expected_conns, swarm2.behaviour.on_connection_closed.len(), s2_expected_conns,
"No additional closed connections should be reported for the banned peer" "No additional closed connections should be reported for the banned peer"
); );
assert!(swarm2.banned_peer_connections.is_empty()); assert!(swarm2.banned_peer_connections.is_empty());
@ -1897,7 +1930,7 @@ mod tests {
} }
} }
Stage::Reconnecting => { Stage::Reconnecting => {
if swarm1.behaviour.inject_connection_established.len() == s1_expected_conns if swarm1.behaviour.on_connection_established.len() == s1_expected_conns
&& swarm2.behaviour.assert_connected(s2_expected_conns, 2) && swarm2.behaviour.assert_connected(s2_expected_conns, 2)
{ {
return Poll::Ready(()); return Poll::Ready(());
@ -2082,9 +2115,8 @@ mod tests {
State::Connecting => { State::Connecting => {
if swarms_connected(&swarm1, &swarm2, num_connections) { if swarms_connected(&swarm1, &swarm2, num_connections) {
disconnected_conn_id = { disconnected_conn_id = {
let conn_id = swarm2.behaviour.inject_connection_established let conn_id =
[num_connections / 2] swarm2.behaviour.on_connection_established[num_connections / 2].1;
.1;
swarm2.behaviour.inner().next_action.replace( swarm2.behaviour.inner().next_action.replace(
NetworkBehaviourAction::CloseConnection { NetworkBehaviourAction::CloseConnection {
peer_id: swarm1_id, peer_id: swarm1_id,
@ -2100,20 +2132,17 @@ mod tests {
for s in &[&swarm1, &swarm2] { for s in &[&swarm1, &swarm2] {
assert!(s assert!(s
.behaviour .behaviour
.inject_connection_closed .on_connection_closed
.iter() .iter()
.all(|(.., remaining_conns)| *remaining_conns > 0)); .all(|(.., remaining_conns)| *remaining_conns > 0));
assert_eq!( assert_eq!(s.behaviour.on_connection_established.len(), num_connections);
s.behaviour.inject_connection_established.len(),
num_connections
);
s.behaviour.assert_connected(num_connections, 1); s.behaviour.assert_connected(num_connections, 1);
} }
if [&swarm1, &swarm2] if [&swarm1, &swarm2]
.iter() .iter()
.all(|s| s.behaviour.inject_connection_closed.len() == 1) .all(|s| s.behaviour.on_connection_closed.len() == 1)
{ {
let conn_id = swarm2.behaviour.inject_connection_closed[0].1; let conn_id = swarm2.behaviour.on_connection_closed[0].1;
assert_eq!(Some(conn_id), disconnected_conn_id); assert_eq!(Some(conn_id), disconnected_conn_id);
return Poll::Ready(()); return Poll::Ready(());
} }

View File

@ -18,8 +18,12 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
use crate::behaviour::{
ConnectionClosed, ConnectionEstablished, DialFailure, ExpiredExternalAddr, ExpiredListenAddr,
FromSwarm, ListenerClosed, ListenerError, NewExternalAddr, NewListenAddr, NewListener,
};
use crate::{ use crate::{
ConnectionHandler, DialError, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction, ConnectionHandler, IntoConnectionHandler, NetworkBehaviour, NetworkBehaviourAction,
PollParameters, PollParameters,
}; };
use libp2p_core::{ use libp2p_core::{
@ -76,8 +80,6 @@ where
self.addresses.get(p).map_or(Vec::new(), |v| v.clone()) self.addresses.get(p).map_or(Vec::new(), |v| v.clone())
} }
fn inject_event(&mut self, _: PeerId, _: ConnectionId, _: THandler::OutEvent) {}
fn poll( fn poll(
&mut self, &mut self,
_: &mut Context, _: &mut Context,
@ -85,6 +87,32 @@ where
) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ConnectionHandler>> { ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ConnectionHandler>> {
self.next_action.take().map_or(Poll::Pending, Poll::Ready) self.next_action.take().map_or(Poll::Pending, Poll::Ready)
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(_)
| FromSwarm::ConnectionClosed(_)
| FromSwarm::AddressChange(_)
| FromSwarm::DialFailure(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
fn on_connection_handler_event(
&mut self,
_peer_id: PeerId,
_connection_id: ConnectionId,
_event: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as
ConnectionHandler>::OutEvent,
) {
}
} }
/// A `CallTraceBehaviour` is a `NetworkBehaviour` that tracks /// A `CallTraceBehaviour` is a `NetworkBehaviour` that tracks
@ -97,43 +125,45 @@ where
inner: TInner, inner: TInner,
pub addresses_of_peer: Vec<PeerId>, pub addresses_of_peer: Vec<PeerId>,
pub inject_connection_established: Vec<(PeerId, ConnectionId, ConnectedPoint, usize)>, pub on_connection_established: Vec<(PeerId, ConnectionId, ConnectedPoint, usize)>,
pub inject_connection_closed: Vec<(PeerId, ConnectionId, ConnectedPoint, usize)>, pub on_connection_closed: Vec<(PeerId, ConnectionId, ConnectedPoint, usize)>,
pub inject_event: Vec<( pub on_event: Vec<(
PeerId, PeerId,
ConnectionId, ConnectionId,
<<TInner::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent, <<TInner::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent,
)>, )>,
pub inject_dial_failure: Vec<Option<PeerId>>, pub on_dial_failure: Vec<Option<PeerId>>,
pub inject_new_listener: Vec<ListenerId>, pub on_new_listener: Vec<ListenerId>,
pub inject_new_listen_addr: Vec<(ListenerId, Multiaddr)>, pub on_new_listen_addr: Vec<(ListenerId, Multiaddr)>,
pub inject_new_external_addr: Vec<Multiaddr>, pub on_new_external_addr: Vec<Multiaddr>,
pub inject_expired_listen_addr: Vec<(ListenerId, Multiaddr)>, pub on_expired_listen_addr: Vec<(ListenerId, Multiaddr)>,
pub inject_expired_external_addr: Vec<Multiaddr>, pub on_expired_external_addr: Vec<Multiaddr>,
pub inject_listener_error: Vec<ListenerId>, pub on_listener_error: Vec<ListenerId>,
pub inject_listener_closed: Vec<(ListenerId, bool)>, pub on_listener_closed: Vec<(ListenerId, bool)>,
pub poll: usize, pub poll: usize,
} }
impl<TInner> CallTraceBehaviour<TInner> impl<TInner> CallTraceBehaviour<TInner>
where where
TInner: NetworkBehaviour, TInner: NetworkBehaviour,
<<TInner::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent:
Clone,
{ {
pub fn new(inner: TInner) -> Self { pub fn new(inner: TInner) -> Self {
Self { Self {
inner, inner,
addresses_of_peer: Vec::new(), addresses_of_peer: Vec::new(),
inject_connection_established: Vec::new(), on_connection_established: Vec::new(),
inject_connection_closed: Vec::new(), on_connection_closed: Vec::new(),
inject_event: Vec::new(), on_event: Vec::new(),
inject_dial_failure: Vec::new(), on_dial_failure: Vec::new(),
inject_new_listener: Vec::new(), on_new_listener: Vec::new(),
inject_new_listen_addr: Vec::new(), on_new_listen_addr: Vec::new(),
inject_new_external_addr: Vec::new(), on_new_external_addr: Vec::new(),
inject_expired_listen_addr: Vec::new(), on_expired_listen_addr: Vec::new(),
inject_expired_external_addr: Vec::new(), on_expired_external_addr: Vec::new(),
inject_listener_error: Vec::new(), on_listener_error: Vec::new(),
inject_listener_closed: Vec::new(), on_listener_closed: Vec::new(),
poll: 0, poll: 0,
} }
} }
@ -141,15 +171,15 @@ where
#[allow(dead_code)] #[allow(dead_code)]
pub fn reset(&mut self) { pub fn reset(&mut self) {
self.addresses_of_peer = Vec::new(); self.addresses_of_peer = Vec::new();
self.inject_connection_established = Vec::new(); self.on_connection_established = Vec::new();
self.inject_connection_closed = Vec::new(); self.on_connection_closed = Vec::new();
self.inject_event = Vec::new(); self.on_event = Vec::new();
self.inject_dial_failure = Vec::new(); self.on_dial_failure = Vec::new();
self.inject_new_listen_addr = Vec::new(); self.on_new_listen_addr = Vec::new();
self.inject_new_external_addr = Vec::new(); self.on_new_external_addr = Vec::new();
self.inject_expired_listen_addr = Vec::new(); self.on_expired_listen_addr = Vec::new();
self.inject_listener_error = Vec::new(); self.on_listener_error = Vec::new();
self.inject_listener_closed = Vec::new(); self.on_listener_closed = Vec::new();
self.poll = 0; self.poll = 0;
} }
@ -158,12 +188,12 @@ where
} }
pub fn num_connections_to_peer(&self, peer: PeerId) -> usize { pub fn num_connections_to_peer(&self, peer: PeerId) -> usize {
self.inject_connection_established self.on_connection_established
.iter() .iter()
.filter(|(peer_id, _, _, _)| *peer_id == peer) .filter(|(peer_id, _, _, _)| *peer_id == peer)
.count() .count()
- self - self
.inject_connection_closed .on_connection_closed
.iter() .iter()
.filter(|(peer_id, _, _, _)| *peer_id == peer) .filter(|(peer_id, _, _, _)| *peer_id == peer)
.count() .count()
@ -178,9 +208,9 @@ where
expected_closed_connections: usize, expected_closed_connections: usize,
expected_disconnections: usize, expected_disconnections: usize,
) -> bool { ) -> bool {
if self.inject_connection_closed.len() == expected_closed_connections { if self.on_connection_closed.len() == expected_closed_connections {
assert_eq!( assert_eq!(
self.inject_connection_closed self.on_connection_closed
.iter() .iter()
.filter(|(.., remaining_established)| { *remaining_established == 0 }) .filter(|(.., remaining_established)| { *remaining_established == 0 })
.count(), .count(),
@ -201,9 +231,9 @@ where
expected_established_connections: usize, expected_established_connections: usize,
expected_connections: usize, expected_connections: usize,
) -> bool { ) -> bool {
if self.inject_connection_established.len() == expected_established_connections { if self.on_connection_established.len() == expected_established_connections {
assert_eq!( assert_eq!(
self.inject_connection_established self.on_connection_established
.iter() .iter()
.filter(|(.., reported_aditional_connections)| { .filter(|(.., reported_aditional_connections)| {
*reported_aditional_connections == 0 *reported_aditional_connections == 0
@ -216,40 +246,23 @@ where
false false
} }
}
impl<TInner> NetworkBehaviour for CallTraceBehaviour<TInner> fn on_connection_established(
where
TInner: NetworkBehaviour,
<<TInner::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent:
Clone,
{
type ConnectionHandler = TInner::ConnectionHandler;
type OutEvent = TInner::OutEvent;
fn new_handler(&mut self) -> Self::ConnectionHandler {
self.inner.new_handler()
}
fn addresses_of_peer(&mut self, p: &PeerId) -> Vec<Multiaddr> {
self.addresses_of_peer.push(*p);
self.inner.addresses_of_peer(p)
}
fn inject_connection_established(
&mut self, &mut self,
p: &PeerId, ConnectionEstablished {
c: &ConnectionId, peer_id,
e: &ConnectedPoint, connection_id,
errors: Option<&Vec<Multiaddr>>, endpoint,
other_established: usize, failed_addresses,
other_established,
}: ConnectionEstablished,
) { ) {
let mut other_peer_connections = self let mut other_peer_connections = self
.inject_connection_established .on_connection_established
.iter() .iter()
.rev() // take last to first .rev() // take last to first
.filter_map(|(peer, .., other_established)| { .filter_map(|(peer, .., other_established)| {
if p == peer { if &peer_id == peer {
Some(other_established) Some(other_established)
} else { } else {
None None
@ -271,26 +284,39 @@ where
} else { } else {
assert_eq!(other_established, 0) assert_eq!(other_established, 0)
} }
self.inject_connection_established self.on_connection_established.push((
.push((*p, *c, e.clone(), other_established)); peer_id,
self.inner connection_id,
.inject_connection_established(p, c, e, errors, other_established); endpoint.clone(),
other_established,
));
let errors = Some(failed_addresses.to_vec());
#[allow(deprecated)]
self.inner.inject_connection_established(
&peer_id,
&connection_id,
endpoint,
errors.as_ref(),
other_established,
);
} }
fn inject_connection_closed( fn on_connection_closed(
&mut self, &mut self,
p: &PeerId, ConnectionClosed {
c: &ConnectionId, peer_id,
e: &ConnectedPoint, connection_id,
handler: <Self::ConnectionHandler as IntoConnectionHandler>::Handler, endpoint,
remaining_established: usize, handler,
remaining_established,
}: ConnectionClosed<<Self as NetworkBehaviour>::ConnectionHandler>,
) { ) {
let mut other_closed_connections = self let mut other_closed_connections = self
.inject_connection_established .on_connection_established
.iter() .iter()
.rev() // take last to first .rev() // take last to first
.filter_map(|(peer, .., remaining_established)| { .filter_map(|(peer, .., remaining_established)| {
if p == peer { if &peer_id == peer {
Some(remaining_established) Some(remaining_established)
} else { } else {
None None
@ -313,87 +339,133 @@ where
assert_eq!(remaining_established, 0) assert_eq!(remaining_established, 0)
} }
assert!( assert!(
self.inject_connection_established self.on_connection_established
.iter() .iter()
.any(|(peer, conn_id, endpoint, _)| (peer, conn_id, endpoint) == (p, c, e)), .any(|(peer, conn_id, endpoint, _)| (peer, conn_id, endpoint)
== (&peer_id, &connection_id, endpoint)),
"`inject_connection_closed` is called only for connections for \ "`inject_connection_closed` is called only for connections for \
which `inject_connection_established` was called first." which `inject_connection_established` was called first."
); );
self.inject_connection_closed self.on_connection_closed.push((
.push((*p, *c, e.clone(), remaining_established)); peer_id,
self.inner connection_id,
.inject_connection_closed(p, c, e, handler, remaining_established); endpoint.clone(),
remaining_established,
));
#[allow(deprecated)]
self.inner.inject_connection_closed(
&peer_id,
&connection_id,
endpoint,
handler,
remaining_established,
);
}
}
impl<TInner> NetworkBehaviour for CallTraceBehaviour<TInner>
where
TInner: NetworkBehaviour,
<<TInner::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent:
Clone,
{
type ConnectionHandler = TInner::ConnectionHandler;
type OutEvent = TInner::OutEvent;
fn new_handler(&mut self) -> Self::ConnectionHandler {
self.inner.new_handler()
} }
fn inject_event( fn addresses_of_peer(&mut self, p: &PeerId) -> Vec<Multiaddr> {
self.addresses_of_peer.push(*p);
self.inner.addresses_of_peer(p)
}
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(connection_established) => {
self.on_connection_established(connection_established)
}
FromSwarm::ConnectionClosed(connection_closed) => {
self.on_connection_closed(connection_closed)
}
FromSwarm::DialFailure(DialFailure {
peer_id,
handler,
error,
}) => {
self.on_dial_failure.push(peer_id);
#[allow(deprecated)]
self.inner.inject_dial_failure(peer_id, handler, error);
}
FromSwarm::NewListener(NewListener { listener_id }) => {
self.on_new_listener.push(listener_id);
#[allow(deprecated)]
self.inner.inject_new_listener(listener_id);
}
FromSwarm::NewListenAddr(NewListenAddr { listener_id, addr }) => {
self.on_new_listen_addr.push((listener_id, addr.clone()));
#[allow(deprecated)]
self.inner.inject_new_listen_addr(listener_id, addr);
}
FromSwarm::ExpiredListenAddr(ExpiredListenAddr { listener_id, addr }) => {
self.on_expired_listen_addr
.push((listener_id, addr.clone()));
#[allow(deprecated)]
self.inner.inject_expired_listen_addr(listener_id, addr);
}
FromSwarm::NewExternalAddr(NewExternalAddr { addr }) => {
self.on_new_external_addr.push(addr.clone());
#[allow(deprecated)]
self.inner.inject_new_external_addr(addr);
}
FromSwarm::ExpiredExternalAddr(ExpiredExternalAddr { addr }) => {
self.on_expired_external_addr.push(addr.clone());
#[allow(deprecated)]
self.inner.inject_expired_external_addr(addr);
}
FromSwarm::ListenerError(ListenerError { listener_id, err }) => {
self.on_listener_error.push(listener_id);
#[allow(deprecated)]
self.inner.inject_listener_error(listener_id, err);
}
FromSwarm::ListenerClosed(ListenerClosed {
listener_id,
reason,
}) => {
self.on_listener_closed.push((listener_id, reason.is_ok()));
#[allow(deprecated)]
self.inner.inject_listener_closed(listener_id, reason);
}
_ => {}
}
}
fn on_connection_handler_event(
&mut self, &mut self,
p: PeerId, p: PeerId,
c: ConnectionId, c: ConnectionId,
e: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent, e: <<Self::ConnectionHandler as IntoConnectionHandler>::Handler as ConnectionHandler>::OutEvent,
) { ) {
assert!( assert!(
self.inject_connection_established self.on_connection_established
.iter() .iter()
.any(|(peer_id, conn_id, ..)| *peer_id == p && c == *conn_id), .any(|(peer_id, conn_id, ..)| *peer_id == p && c == *conn_id),
"`inject_event` is called for reported connections." "`on_connection_handler_event` is called for reported connections."
); );
assert!( assert!(
!self !self
.inject_connection_closed .on_connection_closed
.iter() .iter()
.any(|(peer_id, conn_id, ..)| *peer_id == p && c == *conn_id), .any(|(peer_id, conn_id, ..)| *peer_id == p && c == *conn_id),
"`inject_event` is never called for closed connections." "`on_connection_handler_event` is never called for closed connections."
); );
self.inject_event.push((p, c, e.clone())); self.on_event.push((p, c, e.clone()));
#[allow(deprecated)]
self.inner.inject_event(p, c, e); self.inner.inject_event(p, c, e);
} }
fn inject_dial_failure(
&mut self,
p: Option<PeerId>,
handler: Self::ConnectionHandler,
error: &DialError,
) {
self.inject_dial_failure.push(p);
self.inner.inject_dial_failure(p, handler, error);
}
fn inject_new_listener(&mut self, id: ListenerId) {
self.inject_new_listener.push(id);
self.inner.inject_new_listener(id);
}
fn inject_new_listen_addr(&mut self, id: ListenerId, a: &Multiaddr) {
self.inject_new_listen_addr.push((id, a.clone()));
self.inner.inject_new_listen_addr(id, a);
}
fn inject_expired_listen_addr(&mut self, id: ListenerId, a: &Multiaddr) {
self.inject_expired_listen_addr.push((id, a.clone()));
self.inner.inject_expired_listen_addr(id, a);
}
fn inject_new_external_addr(&mut self, a: &Multiaddr) {
self.inject_new_external_addr.push(a.clone());
self.inner.inject_new_external_addr(a);
}
fn inject_expired_external_addr(&mut self, a: &Multiaddr) {
self.inject_expired_external_addr.push(a.clone());
self.inner.inject_expired_external_addr(a);
}
fn inject_listener_error(&mut self, l: ListenerId, e: &(dyn std::error::Error + 'static)) {
self.inject_listener_error.push(l);
self.inner.inject_listener_error(l, e);
}
fn inject_listener_closed(&mut self, l: ListenerId, r: Result<(), &std::io::Error>) {
self.inject_listener_closed.push((l, r.is_ok()));
self.inner.inject_listener_closed(l, r);
}
fn poll( fn poll(
&mut self, &mut self,
cx: &mut Context, cx: &mut Context,

View File

@ -21,7 +21,7 @@
use futures::StreamExt; use futures::StreamExt;
use libp2p_identify as identify; use libp2p_identify as identify;
use libp2p_ping as ping; use libp2p_ping as ping;
use libp2p_swarm::{dummy, NetworkBehaviour, SwarmEvent}; use libp2p_swarm::{behaviour::FromSwarm, dummy, NetworkBehaviour, SwarmEvent};
use std::fmt::Debug; use std::fmt::Debug;
/// Small utility to check that a type implements `NetworkBehaviour`. /// Small utility to check that a type implements `NetworkBehaviour`.
@ -390,7 +390,7 @@ fn custom_out_event_no_type_parameters() {
dummy::ConnectionHandler dummy::ConnectionHandler
} }
fn inject_event( fn on_connection_handler_event(
&mut self, &mut self,
_peer: PeerId, _peer: PeerId,
_connection: ConnectionId, _connection: ConnectionId,
@ -406,6 +406,23 @@ fn custom_out_event_no_type_parameters() {
) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ConnectionHandler>> { ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ConnectionHandler>> {
Poll::Pending Poll::Pending
} }
fn on_swarm_event(&mut self, event: FromSwarm<Self::ConnectionHandler>) {
match event {
FromSwarm::ConnectionEstablished(_)
| FromSwarm::ConnectionClosed(_)
| FromSwarm::AddressChange(_)
| FromSwarm::DialFailure(_)
| FromSwarm::ListenFailure(_)
| FromSwarm::NewListener(_)
| FromSwarm::NewListenAddr(_)
| FromSwarm::ExpiredListenAddr(_)
| FromSwarm::ListenerError(_)
| FromSwarm::ListenerClosed(_)
| FromSwarm::NewExternalAddr(_)
| FromSwarm::ExpiredExternalAddr(_) => {}
}
}
} }
#[derive(NetworkBehaviour)] #[derive(NetworkBehaviour)]