mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-12 01:21:21 +00:00
Multiple connections per peer (#1440)
* Allow multiple connections per peer in libp2p-core. Instead of trying to enforce a single connection per peer, which involves quite a bit of additional complexity e.g. to prioritise simultaneously opened connections and can have other undesirable consequences [1], we now make multiple connections per peer a feature. The gist of these changes is as follows: The concept of a "node" with an implicit 1-1 correspondence to a connection has been replaced with the "first-class" concept of a "connection". The code from `src/nodes` has moved (with varying degrees of modification) to `src/connection`. A `HandledNode` has become a `Connection`, a `NodeHandler` a `ConnectionHandler`, the `CollectionStream` was the basis for the new `connection::Pool`, and so forth. Conceptually, a `Network` contains a `connection::Pool` which in turn internally employs the `connection::Manager` for handling the background `connection::manager::Task`s, one per connection, as before. These are all considered implementation details. On the public API, `Peer`s are managed as before through the `Network`, except now the API has changed with the shift of focus to (potentially multiple) connections per peer. The `NetworkEvent`s have accordingly also undergone changes. The Swarm APIs remain largely unchanged, except for the fact that `inject_replaced` is no longer called. It may now practically happen that multiple `ProtocolsHandler`s are associated with a single `NetworkBehaviour`, one per connection. If implementations of `NetworkBehaviour` rely somehow on communicating with exactly one `ProtocolsHandler`, this may cause issues, but it is unlikely. [1]: https://github.com/paritytech/substrate/issues/4272 * Fix intra-rustdoc links. * Update core/src/connection/pool.rs Co-Authored-By: Max Inden <mail@max-inden.de> * Address some review feedback and fix doc links. * Allow responses to be sent on the same connection. * Remove unnecessary remainders of inject_replaced. * Update swarm/src/behaviour.rs Co-Authored-By: Pierre Krieger <pierre.krieger1708@gmail.com> * Update swarm/src/lib.rs Co-Authored-By: Pierre Krieger <pierre.krieger1708@gmail.com> * Update core/src/connection/manager.rs Co-Authored-By: Pierre Krieger <pierre.krieger1708@gmail.com> * Update core/src/connection/manager.rs Co-Authored-By: Pierre Krieger <pierre.krieger1708@gmail.com> * Update core/src/connection/pool.rs Co-Authored-By: Pierre Krieger <pierre.krieger1708@gmail.com> * Incorporate more review feedback. * Move module declaration below imports. * Update core/src/connection/manager.rs Co-Authored-By: Toralf Wittner <tw@dtex.org> * Update core/src/connection/manager.rs Co-Authored-By: Toralf Wittner <tw@dtex.org> * Simplify as per review. * Fix rustoc link. * Add try_notify_handler and simplify. * Relocate DialingConnection and DialingAttempt. For better visibility constraints. * Small cleanup. * Small cleanup. More robust EstablishedConnectionIter. * Clarify semantics of `DialingPeer::connect`. * Don't call inject_disconnected on InvalidPeerId. To preserve the previous behavior and ensure calls to `inject_disconnected` are always paired with calls to `inject_connected`. * Provide public ConnectionId constructor. Mainly needed for testing purposes, e.g. in substrate. * Move the established connection limit check to the right place. * Clean up connection error handling. Separate connection errors into those occuring during connection setup or upon rejecting a newly established connection (the `PendingConnectionError`) and those errors occurring on previously established connections, i.e. for which a `ConnectionEstablished` event has been emitted by the connection pool earlier. * Revert change in log level and clarify an invariant. * Remove inject_replaced entirely. * Allow notifying all connection handlers. Thereby simplify by introducing a new enum `NotifyHandler`, used with a single constructor `NetworkBehaviourAction::NotifyHandler`. * Finishing touches. Small API simplifications and code deduplication. Some more useful debug logging. Co-authored-by: Max Inden <mail@max-inden.de> Co-authored-by: Pierre Krieger <pierre.krieger1708@gmail.com> Co-authored-by: Toralf Wittner <tw@dtex.org>
This commit is contained in:
@ -56,8 +56,9 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
||||
let protocols_handler = quote!{::libp2p::swarm::ProtocolsHandler};
|
||||
let into_proto_select_ident = quote!{::libp2p::swarm::IntoProtocolsHandlerSelect};
|
||||
let peer_id = quote!{::libp2p::core::PeerId};
|
||||
let connection_id = quote!{::libp2p::core::connection::ConnectionId};
|
||||
let connected_point = quote!{::libp2p::core::ConnectedPoint};
|
||||
let listener_id = quote!{::libp2p::core::nodes::ListenerId};
|
||||
let listener_id = quote!{::libp2p::core::connection::ListenerId};
|
||||
|
||||
let poll_parameters = quote!{::libp2p::swarm::PollParameters};
|
||||
|
||||
@ -172,32 +173,6 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
||||
})
|
||||
};
|
||||
|
||||
// Build the list of statements to put in the body of `inject_replaced()`.
|
||||
let inject_replaced_stmts = {
|
||||
let num_fields = data_struct.fields.iter().filter(|f| !is_ignored(f)).count();
|
||||
data_struct.fields.iter().enumerate().filter_map(move |(field_n, field)| {
|
||||
if is_ignored(&field) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(if field_n == num_fields - 1 {
|
||||
match field.ident {
|
||||
Some(ref i) => quote!{ self.#i.inject_replaced(peer_id, closed_endpoint, new_endpoint); },
|
||||
None => quote!{ self.#field_n.inject_replaced(peer_id, closed_endpoint, new_endpoint); },
|
||||
}
|
||||
} else {
|
||||
match field.ident {
|
||||
Some(ref i) => quote!{
|
||||
self.#i.inject_replaced(peer_id.clone(), closed_endpoint.clone(), new_endpoint.clone());
|
||||
},
|
||||
None => quote!{
|
||||
self.#field_n.inject_replaced(peer_id.clone(), closed_endpoint.clone(), new_endpoint.clone());
|
||||
},
|
||||
}
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
// Build the list of statements to put in the body of `inject_addr_reach_failure()`.
|
||||
let inject_addr_reach_failure_stmts = {
|
||||
data_struct.fields.iter().enumerate().filter_map(move |(field_n, field)| {
|
||||
@ -294,10 +269,10 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
||||
})
|
||||
};
|
||||
|
||||
// Build the list of variants to put in the body of `inject_node_event()`.
|
||||
// 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_node_event` on the corresponding child.
|
||||
// We call `inject_event` on the corresponding child.
|
||||
let inject_node_event_stmts = data_struct.fields.iter().enumerate().filter(|f| !is_ignored(&f.1)).enumerate().map(|(enum_n, (field_n, field))| {
|
||||
let mut elem = if enum_n != 0 {
|
||||
quote!{ #either_ident::Second(ev) }
|
||||
@ -310,8 +285,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
||||
}
|
||||
|
||||
Some(match field.ident {
|
||||
Some(ref i) => quote!{ #elem => self.#i.inject_node_event(peer_id, ev) },
|
||||
None => quote!{ #elem => self.#field_n.inject_node_event(peer_id, ev) },
|
||||
Some(ref i) => quote!{ #elem => self.#i.inject_event(peer_id, connection_id, ev) },
|
||||
None => quote!{ #elem => self.#field_n.inject_event(peer_id, connection_id, ev) },
|
||||
})
|
||||
});
|
||||
|
||||
@ -411,9 +386,10 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
||||
std::task::Poll::Ready(#network_behaviour_action::DialPeer { peer_id }) => {
|
||||
return std::task::Poll::Ready(#network_behaviour_action::DialPeer { peer_id });
|
||||
}
|
||||
std::task::Poll::Ready(#network_behaviour_action::SendEvent { peer_id, event }) => {
|
||||
return std::task::Poll::Ready(#network_behaviour_action::SendEvent {
|
||||
std::task::Poll::Ready(#network_behaviour_action::NotifyHandler { peer_id, handler, event }) => {
|
||||
return std::task::Poll::Ready(#network_behaviour_action::NotifyHandler {
|
||||
peer_id,
|
||||
handler,
|
||||
event: #wrapped_event,
|
||||
});
|
||||
}
|
||||
@ -453,10 +429,6 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
||||
#(#inject_disconnected_stmts);*
|
||||
}
|
||||
|
||||
fn inject_replaced(&mut self, peer_id: #peer_id, closed_endpoint: #connected_point, new_endpoint: #connected_point) {
|
||||
#(#inject_replaced_stmts);*
|
||||
}
|
||||
|
||||
fn inject_addr_reach_failure(&mut self, peer_id: Option<&#peer_id>, addr: &#multiaddr, error: &dyn std::error::Error) {
|
||||
#(#inject_addr_reach_failure_stmts);*
|
||||
}
|
||||
@ -485,9 +457,10 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
||||
#(#inject_listener_closed_stmts);*
|
||||
}
|
||||
|
||||
fn inject_node_event(
|
||||
fn inject_event(
|
||||
&mut self,
|
||||
peer_id: #peer_id,
|
||||
connection_id: #connection_id,
|
||||
event: <<Self::ProtocolsHandler as #into_protocols_handler>::Handler as #protocols_handler>::OutEvent
|
||||
) {
|
||||
match event {
|
||||
|
Reference in New Issue
Block a user