Merge pull request #62 from tomaka/swarm-docs-pass2

More documentation for libp2p-swarm
This commit is contained in:
Fredrik Harrysson 2017-12-07 12:46:59 +01:00 committed by GitHub
commit c9e6a4d10b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 51 deletions

View File

@ -5,19 +5,20 @@ This crate contains all the core traits and mechanisms of the transport system o
# The `Transport` trait # The `Transport` trait
The main trait that this crate provides is `Transport`, which provides the `dial` and 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 `listen_on` methods and can be used to dial or listen on a multiaddress. The `swarm` crate
provide any concrete (non-dummy, non-adapter) implementation of this trait. It is implemented itself does not provide any concrete (ie. non-dummy, non-adapter) implementation of this trait.
on structs such as `TcpConfig`, `UdpConfig`, `WebsocketConfig` that are provided by external It is implemented on structs that are provided by external crates, such as `TcpConfig` from
crates. `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 Each implementation of `Transport` only supports *some* multiaddress protocols, for example
the `TcpConfig` struct only supports multiaddresses that look like `/ip*/*.*.*.*/tcp/*`. Two the `TcpConfig` struct only supports multiaddresses that look like `/ip*/*.*.*.*/tcp/*`. It is
implementations of `Transport` can be grouped together with the `or_transport` method, in order 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 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 // TODO: right now only tcp-transport exists, we need to add an example for chaining
// transports once that makes sense // multiple transports once that makes sense
# Connection upgrades # 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 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. 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 ## Middlewares
Examples of middleware protocol upgrades include `PlainTextConfig` (dummy upgrade), Examples of middleware connection upgrades include `PlainTextConfig` (dummy upgrade) or
`SecioConfig` (encyption layer), or `MultiplexConfig`. `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. traits, just like sockets do.
A middleware can be applied by using the `with_upgrade` method of the `Transport` trait. The A middleware can be applied on a transport by using the `with_upgrade` method of the
return value of this method also implements the `Transport` trait, which means that you can `Transport` trait. The return value of this method also implements the `Transport` trait, which
call `dial()` and `listen_on()` on it in order to directly obtain an upgraded connection. An means that you can call `dial()` and `listen_on()` on it in order to directly obtain an
error is produced if the remote doesn't support the protocol that you are trying to negotiate. 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_swarm;
extern crate libp2p_tcp_transport; extern crate libp2p_tcp_transport;
extern crate tokio_core; extern crate tokio_core;
@ -53,22 +55,37 @@ use libp2p_swarm::Transport;
let tokio_core = tokio_core::reactor::Core::new().unwrap(); let tokio_core = tokio_core::reactor::Core::new().unwrap();
let tcp_transport = libp2p_tcp_transport::TcpConfig::new(tokio_core.handle()); 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 // 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
*Actual protocols* work the same way as middlewares, except that their `Output` doesn't *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 implement the `AsyncRead` and `AsyncWrite` traits. This means that that the return value of
value of `with_upgrade` **cannot** doesn't implement the `Transport` trait and thus cannot be `with_upgrade` does **not** implement the `Transport` trait and thus cannot be used as a
used as a transport. transport.
However the value returned by `with_upgrade` still provides methods named `dial` and However the `UpgradedNode` struct returned by `with_upgrade` still provides methods named
`listen_on`, which will yield you respectively a `Future` or a `Stream`, which you can use to `dial` and `listen_on`, which will yield you respectively a `Future` or a `Stream`, which you
obtain the `Output`. This `Output` can then be used in a protocol-specific way to use the can use to obtain the `Output`. This `Output` can then be used in a protocol-specific way to
protocol. use the protocol.
```rust ```rust
extern crate futures; 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 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 also implements the `ConnectionUpgrade` trait and will choose one of the protocols amongst the
ones supported. ones supported.

View File

@ -28,19 +28,20 @@
//! # The `Transport` trait //! # The `Transport` trait
//! //!
//! The main trait that this crate provides is `Transport`, which provides the `dial` and //! 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 //! `listen_on` methods and can be used to dial or listen on a multiaddress. The `swarm` crate
//! provide any concrete (non-dummy, non-adapter) implementation of this trait. It is implemented //! itself does not provide any concrete (ie. non-dummy, non-adapter) implementation of this trait.
//! on structs such as `TcpConfig`, `UdpConfig`, `WebsocketConfig` that are provided by external //! It is implemented on structs that are provided by external crates, such as `TcpConfig` from
//! crates. //! `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 //! Each implementation of `Transport` only supports *some* multiaddress protocols, for example
//! the `TcpConfig` struct only supports multiaddresses that look like `/ip*/*.*.*.*/tcp/*`. Two //! the `TcpConfig` struct only supports multiaddresses that look like `/ip*/*.*.*.*/tcp/*`. It is
//! implementations of `Transport` can be grouped together with the `or_transport` method, in order //! 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 //! 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 //! // TODO: right now only tcp-transport exists, we need to add an example for chaining
//! // transports once that makes sense //! // multiple transports once that makes sense
//! //!
//! # Connection upgrades //! # Connection upgrades
//! //!
@ -52,20 +53,21 @@
//! consists in a protocol name plus a method that turns the socket into an `Output` object whose //! 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. //! 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 //! ## Middlewares
//! //!
//! Examples of middleware protocol upgrades include `PlainTextConfig` (dummy upgrade), //! Examples of middleware connection upgrades include `PlainTextConfig` (dummy upgrade) or
//! `SecioConfig` (encyption layer), or `MultiplexConfig`. //! `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. //! traits, just like sockets do.
//! //!
//! A middleware can be applied by using the `with_upgrade` method of the `Transport` trait. The //! A middleware can be applied on a transport by using the `with_upgrade` method of the
//! return value of this method also implements the `Transport` trait, which means that you can //! `Transport` trait. The return value of this method also implements the `Transport` trait, which
//! call `dial()` and `listen_on()` on it in order to directly obtain an upgraded connection. An //! means that you can call `dial()` and `listen_on()` on it in order to directly obtain an
//! error is produced if the remote doesn't support the protocol that you are trying to negotiate. //! 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; //! extern crate libp2p_swarm;
@ -82,18 +84,33 @@
//! // upgraded.dial(...) // automatically applies the plain text protocol on the socket //! // 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
//! //!
//! *Actual protocols* work the same way as middlewares, except that their `Output` doesn't //! *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 //! implement the `AsyncRead` and `AsyncWrite` traits. This means that that the return value of
//! value of `with_upgrade` **cannot** doesn't implement the `Transport` trait and thus cannot be //! `with_upgrade` does **not** implement the `Transport` trait and thus cannot be used as a
//! used as a transport. //! transport.
//! //!
//! However the value returned by `with_upgrade` still provides methods named `dial` and //! However the `UpgradedNode` struct returned by `with_upgrade` still provides methods named
//! `listen_on`, which will yield you respectively a `Future` or a `Stream`, which you can use to //! `dial` and `listen_on`, which will yield you respectively a `Future` or a `Stream`, which you
//! obtain the `Output`. This `Output` can then be used in a protocol-specific way to use the //! can use to obtain the `Output`. This `Output` can then be used in a protocol-specific way to
//! protocol. //! use the protocol.
//! //!
//! ```no_run //! ```no_run
//! extern crate futures; //! extern crate futures;