Return TCP listener errors. (#1218)

* Add listener ID and error event.

Report listener errors to client code so they are aware that an error
occurred within a listener. By default we continue to poll listeners
which produced an error, but clients can remove listeners by ID.

* tcp: Report errors.

Instead of silently waiting after errors we return all errors, but pause
after each error, before continuing.

* Add a test.

To ease testing, `Listener` is made generic and we test that no values
and errors are lost. Elapsed time between item generation is not
measured.

* Support the new methods in core-derive.

* Address review concerns.

* Remove `Display` impl of `ListenerId`.

* Add 'static bound to `on_listener_error` error.
This commit is contained in:
Toralf Wittner
2019-08-13 15:41:12 +02:00
committed by Pierre Krieger
parent ec22688f96
commit 2c4b52a545
8 changed files with 294 additions and 94 deletions

View File

@ -56,6 +56,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
let into_proto_select_ident = quote!{::libp2p::swarm::IntoProtocolsHandlerSelect};
let peer_id = quote!{::libp2p::core::PeerId};
let connected_point = quote!{::libp2p::core::ConnectedPoint};
let listener_id = quote!{::libp2p::core::nodes::ListenerId};
// Name of the type parameter that represents the substream.
let substream_generic = {
@ -284,6 +285,32 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
})
};
// Build the list of statements to put in the body of `inject_listener_error()`.
let inject_listener_error_stmts = {
data_struct.fields.iter().enumerate().filter_map(move |(field_n, field)| {
if is_ignored(&field) {
return None
}
Some(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().filter_map(move |(field_n, field)| {
if is_ignored(&field) {
return None
}
Some(match field.ident {
Some(ref i) => quote!(self.#i.inject_listener_closed(id);),
None => quote!(self.#field_n.inject_listener_closed(id);)
})
})
};
// Build the list of variants to put in the body of `inject_node_event()`.
//
// The event type is a construction of nested `#either_ident`s of the events of the children.
@ -467,6 +494,14 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
#(#inject_new_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) {
#(#inject_listener_closed_stmts);*
}
fn inject_node_event(
&mut self,
peer_id: #peer_id,