From 7aacb081d2e7db05b17c932370c926bb5e0d6230 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 5 Dec 2017 13:03:55 +0100 Subject: [PATCH] More documentation for libp2p-swarm --- libp2p-swarm/README.md | 70 +++++++++++++++++++++++++---------------- libp2p-swarm/src/lib.rs | 65 ++++++++++++++++++++++++-------------- 2 files changed, 84 insertions(+), 51 deletions(-) diff --git a/libp2p-swarm/README.md b/libp2p-swarm/README.md index 9d14cc9e..136b47cf 100644 --- a/libp2p-swarm/README.md +++ b/libp2p-swarm/README.md @@ -5,19 +5,20 @@ This crate contains all the core traits and mechanisms of the transport system o # The `Transport` trait The main trait that this crate provides is `Transport`, which provides the `dial` and -`listen_on` methods and can be used to dial or listen on a multiaddress. This crate does not -provide any concrete (non-dummy, non-adapter) implementation of this trait. It is implemented -on structs such as `TcpConfig`, `UdpConfig`, `WebsocketConfig` that are provided by external -crates. +`listen_on` methods and can be used to dial or listen on a multiaddress. The `swarm` crate +itself does not provide any concrete (ie. non-dummy, non-adapter) implementation of this trait. +It is implemented on structs that are provided by external crates, such as `TcpConfig` from +`tcp-transport`, `UdpConfig`, or `WebsocketConfig` (note: as of the writing of this +documentation, the last two structs don't exist yet). Each implementation of `Transport` only supports *some* multiaddress protocols, for example -the `TcpConfig` struct only supports multiaddresses that look like `/ip*/*.*.*.*/tcp/*`. Two -implementations of `Transport` can be grouped together with the `or_transport` method, in order +the `TcpConfig` struct only supports multiaddresses that look like `/ip*/*.*.*.*/tcp/*`. It is +possible to group two implementations of `Transport` with the `or_transport` method, in order to obtain a single object that supports the protocols of both objects at once. This can be done -multiple times in order to chain as many implementations as you want. +multiple times in a row in order to chain as many implementations as you want. -// TODO: right now only tcp-transport exists, but we need to add an example for chaining multiple -// transports once that makes sense +// TODO: right now only tcp-transport exists, we need to add an example for chaining +// multiple transports once that makes sense # Connection upgrades @@ -29,22 +30,23 @@ A potential connection upgrade is represented with the `ConnectionUpgrade` trait consists in a protocol name plus a method that turns the socket into an `Output` object whose nature and type is specific to each upgrade. -There exists two kinds of connection upgrades: middlewares, and actual protocols. +There exists three kinds of connection upgrades: middlewares, muxers, and actual protocols. ## Middlewares -Examples of middleware protocol upgrades include `PlainTextConfig` (dummy upgrade), -`SecioConfig` (encyption layer), or `MultiplexConfig`. +Examples of middleware connection upgrades include `PlainTextConfig` (dummy upgrade) or +`SecioConfig` (encyption layer, provided by the `secio` crate). -The output of a middleware protocol upgrade must implement the `AsyncRead` and `AsyncWrite` +The output of a middleware connection upgrade must implement the `AsyncRead` and `AsyncWrite` traits, just like sockets do. -A middleware can be applied by using the `with_upgrade` method of the `Transport` trait. The -return value of this method also implements the `Transport` trait, which means that you can -call `dial()` and `listen_on()` on it in order to directly obtain an upgraded connection. An -error is produced if the remote doesn't support the protocol that you are trying to negotiate. +A middleware can be applied on a transport by using the `with_upgrade` method of the +`Transport` trait. The return value of this method also implements the `Transport` trait, which +means that you can call `dial()` and `listen_on()` on it in order to directly obtain an +upgraded connection or a listener that will yield upgraded connections. An error is produced if +the remote doesn't support the protocol corresponding to the connection upgrade. -``` +```rust extern crate libp2p_swarm; extern crate libp2p_tcp_transport; extern crate tokio_core; @@ -53,22 +55,37 @@ use libp2p_swarm::Transport; let tokio_core = tokio_core::reactor::Core::new().unwrap(); let tcp_transport = libp2p_tcp_transport::TcpConfig::new(tokio_core.handle()); -let upgraded = tcp_transport.with_upgrade(libp2p_swarm::PlainText); +let upgraded = tcp_transport.with_upgrade(libp2p_swarm::PlainTextConfig); // upgraded.dial(...) // automatically applies the plain text protocol on the socket ``` +## Muxers + +The concept of *muxing* consists in using a single stream as if it was multiple substreams. + +If the output of the connection upgrade instead implements the `StreamMuxer` and `Clone` +traits, then you can turn the `UpgradedNode` struct into a `ConnectionReuse` struct by calling +`ConnectionReuse::from(upgraded_node)`. + +The `ConnectionReuse` struct then implements the `Transport` trait, and can be used to dial or +listen to multiaddresses, just like any other transport. The only difference is that dialing +a node will try to open a new substream on an existing connection instead of opening a new +one every time. + +TODO: add an example once the multiplex pull request is merged + ## Actual protocols *Actual protocols* work the same way as middlewares, except that their `Output` doesn't -implement the `AsyncRead` and `AsyncWrite` traits. The consequence of this is that the return -value of `with_upgrade` **cannot** doesn't implement the `Transport` trait and thus cannot be -used as a transport. +implement the `AsyncRead` and `AsyncWrite` traits. This means that that the return value of +`with_upgrade` does **not** implement the `Transport` trait and thus cannot be used as a +transport. -However the value returned by `with_upgrade` still provides methods named `dial` and -`listen_on`, which will yield you respectively a `Future` or a `Stream`, which you can use to -obtain the `Output`. This `Output` can then be used in a protocol-specific way to use the -protocol. +However the `UpgradedNode` struct returned by `with_upgrade` still provides methods named +`dial` and `listen_on`, which will yield you respectively a `Future` or a `Stream`, which you +can use to obtain the `Output`. This `Output` can then be used in a protocol-specific way to +use the protocol. ```rust extern crate futures; @@ -102,4 +119,3 @@ core.run(ping_finished_future).unwrap(); You can use the `.or_upgrade()` method to group multiple upgrades together. The return value also implements the `ConnectionUpgrade` trait and will choose one of the protocols amongst the ones supported. - diff --git a/libp2p-swarm/src/lib.rs b/libp2p-swarm/src/lib.rs index 3dce1f3d..e0eddea4 100644 --- a/libp2p-swarm/src/lib.rs +++ b/libp2p-swarm/src/lib.rs @@ -28,19 +28,20 @@ //! # The `Transport` trait //! //! The main trait that this crate provides is `Transport`, which provides the `dial` and -//! `listen_on` methods and can be used to dial or listen on a multiaddress. This crate does not -//! provide any concrete (non-dummy, non-adapter) implementation of this trait. It is implemented -//! on structs such as `TcpConfig`, `UdpConfig`, `WebsocketConfig` that are provided by external -//! crates. +//! `listen_on` methods and can be used to dial or listen on a multiaddress. The `swarm` crate +//! itself does not provide any concrete (ie. non-dummy, non-adapter) implementation of this trait. +//! It is implemented on structs that are provided by external crates, such as `TcpConfig` from +//! `tcp-transport`, `UdpConfig`, or `WebsocketConfig` (note: as of the writing of this +//! documentation, the last two structs don't exist yet). //! //! Each implementation of `Transport` only supports *some* multiaddress protocols, for example -//! the `TcpConfig` struct only supports multiaddresses that look like `/ip*/*.*.*.*/tcp/*`. Two -//! implementations of `Transport` can be grouped together with the `or_transport` method, in order +//! the `TcpConfig` struct only supports multiaddresses that look like `/ip*/*.*.*.*/tcp/*`. It is +//! possible to group two implementations of `Transport` with the `or_transport` method, in order //! to obtain a single object that supports the protocols of both objects at once. This can be done -//! multiple times in order to chain as many implementations as you want. +//! multiple times in a row in order to chain as many implementations as you want. //! -//! // TODO: right now only tcp-transport exists, but we need to add an example for chaining multiple -//! // transports once that makes sense +//! // TODO: right now only tcp-transport exists, we need to add an example for chaining +//! // multiple transports once that makes sense //! //! # Connection upgrades //! @@ -52,20 +53,21 @@ //! consists in a protocol name plus a method that turns the socket into an `Output` object whose //! nature and type is specific to each upgrade. //! -//! There exists two kinds of connection upgrades: middlewares, and actual protocols. +//! There exists three kinds of connection upgrades: middlewares, muxers, and actual protocols. //! //! ## Middlewares //! -//! Examples of middleware protocol upgrades include `PlainTextConfig` (dummy upgrade), -//! `SecioConfig` (encyption layer), or `MultiplexConfig`. +//! Examples of middleware connection upgrades include `PlainTextConfig` (dummy upgrade) or +//! `SecioConfig` (encyption layer, provided by the `secio` crate). //! -//! The output of a middleware protocol upgrade must implement the `AsyncRead` and `AsyncWrite` +//! The output of a middleware connection upgrade must implement the `AsyncRead` and `AsyncWrite` //! traits, just like sockets do. //! -//! A middleware can be applied by using the `with_upgrade` method of the `Transport` trait. The -//! return value of this method also implements the `Transport` trait, which means that you can -//! call `dial()` and `listen_on()` on it in order to directly obtain an upgraded connection. An -//! error is produced if the remote doesn't support the protocol that you are trying to negotiate. +//! A middleware can be applied on a transport by using the `with_upgrade` method of the +//! `Transport` trait. The return value of this method also implements the `Transport` trait, which +//! means that you can call `dial()` and `listen_on()` on it in order to directly obtain an +//! upgraded connection or a listener that will yield upgraded connections. An error is produced if +//! the remote doesn't support the protocol corresponding to the connection upgrade. //! //! ``` //! extern crate libp2p_swarm; @@ -82,18 +84,33 @@ //! // upgraded.dial(...) // automatically applies the plain text protocol on the socket //! # } //! ``` +//! +//! ## Muxers +//! +//! The concept of *muxing* consists in using a single stream as if it was multiple substreams. +//! +//! If the output of the connection upgrade instead implements the `StreamMuxer` and `Clone` +//! traits, then you can turn the `UpgradedNode` struct into a `ConnectionReuse` struct by calling +//! `ConnectionReuse::from(upgraded_node)`. +//! +//! The `ConnectionReuse` struct then implements the `Transport` trait, and can be used to dial or +//! listen to multiaddresses, just like any other transport. The only difference is that dialing +//! a node will try to open a new substream on an existing connection instead of opening a new +//! one every time. +//! +//! TODO: add an example once the multiplex pull request is merged //! //! ## Actual protocols //! //! *Actual protocols* work the same way as middlewares, except that their `Output` doesn't -//! implement the `AsyncRead` and `AsyncWrite` traits. The consequence of this is that the return -//! value of `with_upgrade` **cannot** doesn't implement the `Transport` trait and thus cannot be -//! used as a transport. +//! implement the `AsyncRead` and `AsyncWrite` traits. This means that that the return value of +//! `with_upgrade` does **not** implement the `Transport` trait and thus cannot be used as a +//! transport. //! -//! However the value returned by `with_upgrade` still provides methods named `dial` and -//! `listen_on`, which will yield you respectively a `Future` or a `Stream`, which you can use to -//! obtain the `Output`. This `Output` can then be used in a protocol-specific way to use the -//! protocol. +//! However the `UpgradedNode` struct returned by `with_upgrade` still provides methods named +//! `dial` and `listen_on`, which will yield you respectively a `Future` or a `Stream`, which you +//! can use to obtain the `Output`. This `Output` can then be used in a protocol-specific way to +//! use the protocol. //! //! ```no_run //! extern crate futures;