refactor(swarm)!: remove handler from NetworkBehaviourAction::Dial (#3328)

We create the `ConnectionId` for the new connection as part of `DialOpts`. This allows `NetworkBehaviour`s to accurately track state regarding their own dial attempts.

This patch is the main enabler of https://github.com/libp2p/rust-libp2p/pull/3254. Removing the `handler` field will allow us to deprecate the `NetworkBehaviour::new_handler` function in favor of four new ones that give more control over the connection lifecycle.
This commit is contained in:
Thomas Eizinger
2023-02-14 14:09:29 +13:00
committed by GitHub
parent 9247cfa878
commit caed1fe2c7
31 changed files with 584 additions and 967 deletions

View File

@ -74,6 +74,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
let expired_external_addr = quote! { #prelude_path::ExpiredExternalAddr };
let listener_error = quote! { #prelude_path::ListenerError };
let listener_closed = quote! { #prelude_path::ListenerClosed };
let t_handler_in_event = quote! { #prelude_path::THandlerInEvent };
// Build the generics.
let impl_generics = {
@ -325,87 +326,51 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
// Build the list of statements to put in the body of `on_swarm_event()`
// for the `FromSwarm::DialFailure` variant.
let on_dial_failure_stmts = {
data_struct
.fields
.iter()
.enumerate()
// The outmost handler belongs to the last behaviour.
.rev()
.enumerate()
.map(|(enum_n, (field_n, field))| {
let handler = if field_n == 0 {
// Given that the iterator is reversed, this is the innermost handler only.
quote! { let handler = handlers }
} else {
quote! {
let (handlers, handler) = handlers.into_inner()
}
};
let inject = match field.ident {
Some(ref i) => quote! {
self.#i.on_swarm_event(#from_swarm::DialFailure(#dial_failure {
peer_id,
handler,
error,
}));
},
None => quote! {
self.#enum_n.on_swarm_event(#from_swarm::DialFailure(#dial_failure {
peer_id,
handler,
error,
}));
},
};
quote! {
#handler;
#inject;
}
})
};
let on_dial_failure_stmts = data_struct
.fields
.iter()
.enumerate()
.map(|(enum_n, field)| match field.ident {
Some(ref i) => quote! {
self.#i.on_swarm_event(#from_swarm::DialFailure(#dial_failure {
peer_id,
connection_id,
error,
}));
},
None => quote! {
self.#enum_n.on_swarm_event(#from_swarm::DialFailure(#dial_failure {
peer_id,
connection_id,
error,
}));
},
});
// Build the list of statements to put in the body of `on_swarm_event()`
// for the `FromSwarm::ListenFailure` variant.
let on_listen_failure_stmts =
{
data_struct.fields.iter().enumerate().rev().enumerate().map(
|(enum_n, (field_n, field))| {
let handler = if field_n == 0 {
quote! { let handler = handlers }
} else {
quote! {
let (handlers, handler) = handlers.into_inner()
}
};
let inject = match field.ident {
Some(ref i) => quote! {
self.#i.on_swarm_event(#from_swarm::ListenFailure(#listen_failure {
local_addr,
send_back_addr,
error,
handler,
}));
},
None => quote! {
self.#enum_n.on_swarm_event(#from_swarm::ListenFailure(#listen_failure {
local_addr,
send_back_addr,
error,
handler,
}));
},
};
quote! {
#handler;
#inject;
}
},
)
};
let on_listen_failure_stmts = data_struct
.fields
.iter()
.enumerate()
.map(|(enum_n, field)| match field.ident {
Some(ref i) => quote! {
self.#i.on_swarm_event(#from_swarm::ListenFailure(#listen_failure {
local_addr,
send_back_addr,
connection_id,
error
}));
},
None => quote! {
self.#enum_n.on_swarm_event(#from_swarm::ListenFailure(#listen_failure {
local_addr,
send_back_addr,
connection_id,
error
}));
},
});
// Build the list of statements to put in the body of `on_swarm_event()`
// for the `FromSwarm::NewListener` variant.
@ -650,38 +615,6 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
wrapped_event = quote!{ #either_ident::Left(#wrapped_event) };
}
// `Dial` provides a handler of the specific behaviour triggering the
// event. Though in order for the final handler to be able to handle
// protocols of all behaviours, the provided handler needs to be
// combined with handlers of all other behaviours.
let provided_handler_and_new_handlers = {
let mut out_handler = None;
for (f_n, f) in data_struct.fields.iter().enumerate() {
let f_name = match f.ident {
Some(ref i) => quote! { self.#i },
None => quote! { self.#f_n },
};
let builder = if field_n == f_n {
// The behaviour that triggered the event. Thus, instead of
// creating a new handler, use the provided handler.
quote! { provided_handler }
} else {
quote! { #f_name.new_handler() }
};
match out_handler {
Some(h) => {
out_handler = Some(quote! { #into_connection_handler::select(#h, #builder) })
}
ref mut h @ None => *h = Some(builder),
}
}
out_handler.unwrap_or(quote! {()}) // TODO: See test `empty`.
};
let generate_event_match_arm = {
// If the `NetworkBehaviour`'s `OutEvent` is generated by the derive macro, wrap the sub
// `NetworkBehaviour` `OutEvent` in the variant of the generated `OutEvent`. If the
@ -708,8 +641,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
quote!{
match #trait_to_impl::poll(&mut self.#field, cx, poll_params) {
#generate_event_match_arm
std::task::Poll::Ready(#network_behaviour_action::Dial { opts, handler: provided_handler }) => {
return std::task::Poll::Ready(#network_behaviour_action::Dial { opts, handler: #provided_handler_and_new_handlers });
std::task::Poll::Ready(#network_behaviour_action::Dial { opts }) => {
return std::task::Poll::Ready(#network_behaviour_action::Dial { opts });
}
std::task::Poll::Ready(#network_behaviour_action::NotifyHandler { peer_id, handler, event }) => {
return std::task::Poll::Ready(#network_behaviour_action::NotifyHandler {
@ -767,7 +700,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
}
}
fn poll(&mut self, cx: &mut std::task::Context, poll_params: &mut impl #poll_parameters) -> std::task::Poll<#network_behaviour_action<Self::OutEvent, Self::ConnectionHandler>> {
fn poll(&mut self, cx: &mut std::task::Context, poll_params: &mut impl #poll_parameters) -> std::task::Poll<#network_behaviour_action<Self::OutEvent, #t_handler_in_event<Self>>> {
use #prelude_path::futures::*;
#(#poll_stmts)*
std::task::Poll::Pending
@ -785,10 +718,10 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
#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 })
#dial_failure { peer_id, connection_id, error })
=> { #(#on_dial_failure_stmts)* }
#from_swarm::ListenFailure(
#listen_failure { local_addr, send_back_addr, handler: handlers, error })
#listen_failure { local_addr, send_back_addr, connection_id, error })
=> { #(#on_listen_failure_stmts)* }
#from_swarm::NewListener(
#new_listener { listener_id })