mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-05-21 15:11:20 +00:00
Make deriving the NetworkBehaviour more ergonomic (#782)
This commit is contained in:
parent
6be3aca768
commit
d10cafa804
@ -48,6 +48,7 @@ env_logger = "0.6.0"
|
|||||||
rand = "0.6"
|
rand = "0.6"
|
||||||
tokio = "0.1"
|
tokio = "0.1"
|
||||||
tokio-stdin-stdout = "0.1"
|
tokio-stdin-stdout = "0.1"
|
||||||
|
void = "1.0"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
|
@ -336,6 +336,15 @@ pub trait NetworkBehaviour<TTopology> {
|
|||||||
fn poll(&mut self, topology: &mut PollParameters<TTopology>) -> Async<NetworkBehaviourAction<<Self::ProtocolsHandler as ProtocolsHandler>::InEvent, Self::OutEvent>>;
|
fn poll(&mut self, topology: &mut PollParameters<TTopology>) -> Async<NetworkBehaviourAction<<Self::ProtocolsHandler as ProtocolsHandler>::InEvent, Self::OutEvent>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used when deriving `NetworkBehaviour`. When deriving `NetworkBehaviour`, must be implemented
|
||||||
|
/// for all the possible event types generated by the various fields.
|
||||||
|
// TODO: document how the custom behaviour works and link this here
|
||||||
|
pub trait NetworkBehaviourEventProcess<TEvent> {
|
||||||
|
/// Called when one of the fields of the type you're deriving `NetworkBehaviour` on generates
|
||||||
|
/// an event.
|
||||||
|
fn inject_event(&mut self, event: TEvent);
|
||||||
|
}
|
||||||
|
|
||||||
/// Parameters passed to `poll()` that the `NetworkBehaviour` has access to.
|
/// Parameters passed to `poll()` that the `NetworkBehaviour` has access to.
|
||||||
// TODO: #[derive(Debug)]
|
// TODO: #[derive(Debug)]
|
||||||
pub struct PollParameters<'a, TTopology: 'a> {
|
pub struct PollParameters<'a, TTopology: 'a> {
|
||||||
|
@ -53,6 +53,7 @@ extern crate env_logger;
|
|||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate libp2p;
|
extern crate libp2p;
|
||||||
extern crate tokio;
|
extern crate tokio;
|
||||||
|
extern crate void;
|
||||||
|
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use libp2p::{
|
use libp2p::{
|
||||||
@ -79,16 +80,19 @@ fn main() {
|
|||||||
// In the future, we want to improve libp2p to make this easier to do.
|
// In the future, we want to improve libp2p to make this easier to do.
|
||||||
#[derive(NetworkBehaviour)]
|
#[derive(NetworkBehaviour)]
|
||||||
struct MyBehaviour<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite> {
|
struct MyBehaviour<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite> {
|
||||||
#[behaviour(handler = "on_floodsub")]
|
|
||||||
floodsub: libp2p::floodsub::Floodsub<TSubstream>,
|
floodsub: libp2p::floodsub::Floodsub<TSubstream>,
|
||||||
mdns: libp2p::mdns::Mdns<TSubstream>,
|
mdns: libp2p::mdns::Mdns<TSubstream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite> MyBehaviour<TSubstream> {
|
impl<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite> libp2p::core::swarm::NetworkBehaviourEventProcess<void::Void> for MyBehaviour<TSubstream> {
|
||||||
|
fn inject_event(&mut self, _ev: void::Void) {
|
||||||
|
void::unreachable(_ev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite> libp2p::core::swarm::NetworkBehaviourEventProcess<libp2p::floodsub::FloodsubMessage> for MyBehaviour<TSubstream> {
|
||||||
// Called when `floodsub` produces an event.
|
// Called when `floodsub` produces an event.
|
||||||
fn on_floodsub<TTopology>(&mut self, message: <libp2p::floodsub::Floodsub<TSubstream> as libp2p::core::swarm::NetworkBehaviour<TTopology>>::OutEvent)
|
fn inject_event(&mut self, message: libp2p::floodsub::FloodsubMessage) {
|
||||||
where TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite
|
|
||||||
{
|
|
||||||
println!("Received: '{:?}' from {:?}", String::from_utf8_lossy(&message.data), message.source);
|
println!("Received: '{:?}' from {:?}", String::from_utf8_lossy(&message.data), message.source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,3 +17,4 @@ quote = "0.6"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
libp2p = { version = "0.1.0", path = "../.." }
|
libp2p = { version = "0.1.0", path = "../.." }
|
||||||
|
void = "1.0"
|
||||||
|
@ -50,6 +50,7 @@ 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 trait_to_impl = quote!{::libp2p::core::swarm::NetworkBehaviour};
|
let trait_to_impl = quote!{::libp2p::core::swarm::NetworkBehaviour};
|
||||||
|
let net_behv_event_proc = quote!{::libp2p::core::swarm::NetworkBehaviourEventProcess};
|
||||||
let either_ident = quote!{::libp2p::core::either::EitherOutput};
|
let either_ident = quote!{::libp2p::core::either::EitherOutput};
|
||||||
let network_behaviour_action = quote!{::libp2p::core::swarm::NetworkBehaviourAction};
|
let network_behaviour_action = quote!{::libp2p::core::swarm::NetworkBehaviourAction};
|
||||||
let protocols_handler = quote!{::libp2p::core::protocols_handler::ProtocolsHandler};
|
let protocols_handler = quote!{::libp2p::core::protocols_handler::ProtocolsHandler};
|
||||||
@ -97,6 +98,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
|||||||
let ty = &field.ty;
|
let ty = &field.ty;
|
||||||
vec![
|
vec![
|
||||||
quote!{#ty: #trait_to_impl<#topology_generic>},
|
quote!{#ty: #trait_to_impl<#topology_generic>},
|
||||||
|
quote!{Self: #net_behv_event_proc<<#ty as #trait_to_impl<#topology_generic>>::OutEvent>},
|
||||||
quote!{<#ty as #trait_to_impl<#topology_generic>>::ProtocolsHandler: #protocols_handler<Substream = #substream_generic>},
|
quote!{<#ty as #trait_to_impl<#topology_generic>>::ProtocolsHandler: #protocols_handler<Substream = #substream_generic>},
|
||||||
// Note: this bound is required because of https://github.com/rust-lang/rust/issues/55697
|
// Note: this bound is required because of https://github.com/rust-lang/rust/issues/55697
|
||||||
quote!{<<#ty as #trait_to_impl<#topology_generic>>::ProtocolsHandler as #protocols_handler>::InboundProtocol: ::libp2p::core::InboundUpgrade<#substream_generic>},
|
quote!{<<#ty as #trait_to_impl<#topology_generic>>::ProtocolsHandler as #protocols_handler>::InboundProtocol: ::libp2p::core::InboundUpgrade<#substream_generic>},
|
||||||
@ -276,27 +278,6 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
|||||||
None => quote!{ self.#field_n },
|
None => quote!{ self.#field_n },
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut handler_fn: Option<Ident> = None;
|
|
||||||
for meta_items in field.attrs.iter().filter_map(get_meta_items) {
|
|
||||||
for meta_item in meta_items {
|
|
||||||
match meta_item {
|
|
||||||
// Parse `#[behaviour(handler = "foo")]`
|
|
||||||
syn::NestedMeta::Meta(syn::Meta::NameValue(ref m)) if m.ident == "handler" => {
|
|
||||||
if let syn::Lit::Str(ref s) = m.lit {
|
|
||||||
handler_fn = Some(syn::parse_str(&s.value()).unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let handling = if let Some(handler_fn) = handler_fn {
|
|
||||||
quote!{self.#handler_fn(event)}
|
|
||||||
} else {
|
|
||||||
quote!{}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut wrapped_event = if enum_n != 0 {
|
let mut wrapped_event = if enum_n != 0 {
|
||||||
quote!{ #either_ident::Second(event) }
|
quote!{ #either_ident::Second(event) }
|
||||||
} else {
|
} else {
|
||||||
@ -310,7 +291,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
|
|||||||
loop {
|
loop {
|
||||||
match #field_name.poll(poll_params) {
|
match #field_name.poll(poll_params) {
|
||||||
Async::Ready(#network_behaviour_action::GenerateEvent(event)) => {
|
Async::Ready(#network_behaviour_action::GenerateEvent(event)) => {
|
||||||
#handling
|
#net_behv_event_proc::inject_event(self, event)
|
||||||
}
|
}
|
||||||
Async::Ready(#network_behaviour_action::DialAddress { address }) => {
|
Async::Ready(#network_behaviour_action::DialAddress { address }) => {
|
||||||
return Async::Ready(#network_behaviour_action::DialAddress { address });
|
return Async::Ready(#network_behaviour_action::DialAddress { address });
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate libp2p;
|
extern crate libp2p;
|
||||||
|
extern crate void;
|
||||||
|
|
||||||
|
use void::Void;
|
||||||
|
|
||||||
/// Small utility to check that a type implements `NetworkBehaviour`.
|
/// Small utility to check that a type implements `NetworkBehaviour`.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -41,6 +44,12 @@ fn one_field() {
|
|||||||
ping: libp2p::ping::PeriodicPing<TSubstream>,
|
ping: libp2p::ping::PeriodicPing<TSubstream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<TSubstream> libp2p::core::swarm::NetworkBehaviourEventProcess<Void> for Foo<TSubstream> {
|
||||||
|
fn inject_event(&mut self, event: Void) {
|
||||||
|
void::unreachable(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
|
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
|
||||||
require_net_behaviour::<Foo<TSubstream>>();
|
require_net_behaviour::<Foo<TSubstream>>();
|
||||||
}
|
}
|
||||||
@ -54,6 +63,16 @@ fn two_fields() {
|
|||||||
ping_dialer: libp2p::ping::PeriodicPing<TSubstream>,
|
ping_dialer: libp2p::ping::PeriodicPing<TSubstream>,
|
||||||
ping_listener: libp2p::ping::PingListen<TSubstream>,
|
ping_listener: libp2p::ping::PingListen<TSubstream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<TSubstream> libp2p::core::swarm::NetworkBehaviourEventProcess<Void> for Foo<TSubstream> {
|
||||||
|
fn inject_event(&mut self, event: Void) {
|
||||||
|
void::unreachable(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
|
||||||
|
require_net_behaviour::<Foo<TSubstream>>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -68,24 +87,14 @@ fn three_fields() {
|
|||||||
foo: String,
|
foo: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
|
impl<TSubstream> libp2p::core::swarm::NetworkBehaviourEventProcess<Void> for Foo<TSubstream> {
|
||||||
require_net_behaviour::<Foo<TSubstream>>();
|
fn inject_event(&mut self, event: Void) {
|
||||||
}
|
void::unreachable(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn event_handler() {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(NetworkBehaviour)]
|
|
||||||
struct Foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite> {
|
|
||||||
#[behaviour(handler = "foo")]
|
|
||||||
ping: libp2p::ping::PingListen<TSubstream>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite> Foo<TSubstream> {
|
impl<TSubstream> libp2p::core::swarm::NetworkBehaviourEventProcess<libp2p::identify::IdentifyEvent> for Foo<TSubstream> {
|
||||||
// TODO: for some reason, the parameter cannot be the event type or we
|
fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {
|
||||||
// get a compilation error; figure out why or open an issue to Rust
|
|
||||||
fn foo<TTopology>(&mut self, ev: <libp2p::ping::PingListen<TSubstream> as libp2p::core::swarm::NetworkBehaviour<TTopology>>::OutEvent) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,6 +113,17 @@ fn custom_polling() {
|
|||||||
identify: libp2p::identify::Identify<TSubstream>,
|
identify: libp2p::identify::Identify<TSubstream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<TSubstream> libp2p::core::swarm::NetworkBehaviourEventProcess<Void> for Foo<TSubstream> {
|
||||||
|
fn inject_event(&mut self, event: Void) {
|
||||||
|
void::unreachable(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TSubstream> libp2p::core::swarm::NetworkBehaviourEventProcess<libp2p::identify::IdentifyEvent> for Foo<TSubstream> {
|
||||||
|
fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<TSubstream> Foo<TSubstream> {
|
impl<TSubstream> Foo<TSubstream> {
|
||||||
fn foo<T>(&mut self) -> libp2p::futures::Async<libp2p::core::swarm::NetworkBehaviourAction<T, ()>> { libp2p::futures::Async::NotReady }
|
fn foo<T>(&mut self) -> libp2p::futures::Async<libp2p::core::swarm::NetworkBehaviourAction<T, ()>> { libp2p::futures::Async::NotReady }
|
||||||
}
|
}
|
||||||
@ -123,6 +143,17 @@ fn custom_event_no_polling() {
|
|||||||
identify: libp2p::identify::Identify<TSubstream>,
|
identify: libp2p::identify::Identify<TSubstream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<TSubstream> libp2p::core::swarm::NetworkBehaviourEventProcess<Void> for Foo<TSubstream> {
|
||||||
|
fn inject_event(&mut self, event: Void) {
|
||||||
|
void::unreachable(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TSubstream> libp2p::core::swarm::NetworkBehaviourEventProcess<libp2p::identify::IdentifyEvent> for Foo<TSubstream> {
|
||||||
|
fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
|
fn foo<TSubstream: libp2p::tokio_io::AsyncRead + libp2p::tokio_io::AsyncWrite>() {
|
||||||
require_net_behaviour::<Foo<TSubstream>>();
|
require_net_behaviour::<Foo<TSubstream>>();
|
||||||
}
|
}
|
||||||
@ -138,6 +169,17 @@ fn custom_event_and_polling() {
|
|||||||
identify: libp2p::identify::Identify<TSubstream>,
|
identify: libp2p::identify::Identify<TSubstream>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<TSubstream> libp2p::core::swarm::NetworkBehaviourEventProcess<Void> for Foo<TSubstream> {
|
||||||
|
fn inject_event(&mut self, event: Void) {
|
||||||
|
void::unreachable(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<TSubstream> libp2p::core::swarm::NetworkBehaviourEventProcess<libp2p::identify::IdentifyEvent> for Foo<TSubstream> {
|
||||||
|
fn inject_event(&mut self, _: libp2p::identify::IdentifyEvent) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<TSubstream> Foo<TSubstream> {
|
impl<TSubstream> Foo<TSubstream> {
|
||||||
fn foo<T>(&mut self) -> libp2p::futures::Async<libp2p::core::swarm::NetworkBehaviourAction<T, String>> { libp2p::futures::Async::NotReady }
|
fn foo<T>(&mut self) -> libp2p::futures::Async<libp2p::core::swarm::NetworkBehaviourAction<T, String>> { libp2p::futures::Async::NotReady }
|
||||||
}
|
}
|
||||||
|
@ -42,4 +42,5 @@ mod rpc_proto;
|
|||||||
mod topic;
|
mod topic;
|
||||||
|
|
||||||
pub use self::layer::Floodsub;
|
pub use self::layer::Floodsub;
|
||||||
|
pub use self::protocol::{FloodsubMessage, FloodsubRpc};
|
||||||
pub use self::topic::{Topic, TopicBuilder, TopicHash};
|
pub use self::topic::{Topic, TopicBuilder, TopicHash};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user