2018-05-16 12:59:36 +02:00
|
|
|
# libp2p-core
|
2017-12-07 15:10:46 +01:00
|
|
|
|
2018-01-03 14:19:24 +01:00
|
|
|
Transport, protocol upgrade and swarm systems of *libp2p*.
|
2017-12-04 18:49:47 +01:00
|
|
|
|
2018-01-03 14:19:24 +01:00
|
|
|
This crate contains all the core traits and mechanisms of the transport and swarm systems
|
|
|
|
of *libp2p*.
|
2017-12-04 18:49:47 +01:00
|
|
|
|
|
|
|
# The `Transport` trait
|
|
|
|
|
|
|
|
The main trait that this crate provides is `Transport`, which provides the `dial` and
|
2017-12-05 13:03:55 +01:00
|
|
|
`listen_on` methods and can be used to dial or listen on a multiaddress. The `swarm` crate
|
2018-07-27 18:10:14 +10:00
|
|
|
itself does not provide any concrete (i.e. non-dummy, non-adapter) implementation of this trait.
|
2017-12-05 13:03:55 +01:00
|
|
|
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).
|
2017-12-04 18:49:47 +01:00
|
|
|
|
|
|
|
Each implementation of `Transport` only supports *some* multiaddress protocols, for example
|
2017-12-05 13:03:55 +01:00
|
|
|
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
|
2017-12-04 18:49:47 +01:00
|
|
|
to obtain a single object that supports the protocols of both objects at once. This can be done
|
2017-12-05 13:03:55 +01:00
|
|
|
multiple times in a row in order to chain as many implementations as you want.
|
2017-12-04 18:49:47 +01:00
|
|
|
|
2018-07-27 18:10:14 +10:00
|
|
|
```
|
2017-12-05 13:03:55 +01:00
|
|
|
// TODO: right now only tcp-transport exists, we need to add an example for chaining
|
|
|
|
// multiple transports once that makes sense
|
2018-07-27 18:10:14 +10:00
|
|
|
```
|
2017-12-04 18:49:47 +01:00
|
|
|
|
2017-12-07 15:10:46 +01:00
|
|
|
## The `MuxedTransport` trait
|
|
|
|
|
|
|
|
The `MuxedTransport` trait is an extension to the `Transport` trait, and is implemented on
|
|
|
|
transports that can receive incoming connections on streams that have been opened with `dial()`.
|
|
|
|
|
2018-01-03 14:19:24 +01:00
|
|
|
The trait provides the `next_incoming()` method, which returns a future that will resolve to
|
|
|
|
the next substream that arrives from a dialed node.
|
2017-12-07 15:10:46 +01:00
|
|
|
|
|
|
|
> **Note**: This trait is mainly implemented for transports that provide stream muxing
|
2018-01-03 14:19:24 +01:00
|
|
|
> capabilities, but it can also be implemented in a dummy way by returning an empty
|
|
|
|
> iterator.
|
2017-12-07 15:10:46 +01:00
|
|
|
|
2017-12-04 18:49:47 +01:00
|
|
|
# Connection upgrades
|
|
|
|
|
|
|
|
Once a socket has been opened with a remote through a `Transport`, it can be *upgraded*. This
|
|
|
|
consists in negotiating a protocol with the remote (through `multistream-select`), and applying
|
|
|
|
that protocol on the socket.
|
|
|
|
|
|
|
|
A potential connection upgrade is represented with the `ConnectionUpgrade` trait. The 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.
|
|
|
|
|
2017-12-05 13:03:55 +01:00
|
|
|
There exists three kinds of connection upgrades: middlewares, muxers, and actual protocols.
|
2017-12-04 18:49:47 +01:00
|
|
|
|
|
|
|
## Middlewares
|
|
|
|
|
2017-12-05 13:03:55 +01:00
|
|
|
Examples of middleware connection upgrades include `PlainTextConfig` (dummy upgrade) or
|
|
|
|
`SecioConfig` (encyption layer, provided by the `secio` crate).
|
2017-12-04 18:49:47 +01:00
|
|
|
|
2017-12-07 15:10:46 +01:00
|
|
|
The output of a middleware connection upgrade implements the `AsyncRead` and `AsyncWrite`
|
2017-12-04 18:49:47 +01:00
|
|
|
traits, just like sockets do.
|
|
|
|
|
2017-12-05 13:03:55 +01:00
|
|
|
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
|
2017-12-07 15:10:46 +01:00
|
|
|
upgraded connection or a listener that will yield upgraded connections. Similarly, the
|
2018-01-03 14:19:24 +01:00
|
|
|
`next_incoming()` method will automatically apply the upgrade on both the dialer and the
|
2017-12-07 15:10:46 +01:00
|
|
|
listener. An error is produced if the remote doesn't support the protocol corresponding to the
|
|
|
|
connection upgrade.
|
2017-12-04 18:49:47 +01:00
|
|
|
|
2017-12-05 13:03:55 +01:00
|
|
|
```rust
|
2018-05-16 12:59:36 +02:00
|
|
|
extern crate libp2p_core;
|
2017-12-04 18:49:47 +01:00
|
|
|
extern crate libp2p_tcp_transport;
|
2018-07-16 12:15:27 +02:00
|
|
|
extern crate tokio_current_thread;
|
2017-12-04 18:49:47 +01:00
|
|
|
|
2018-05-16 12:59:36 +02:00
|
|
|
use libp2p_core::Transport;
|
2017-12-04 18:49:47 +01:00
|
|
|
|
|
|
|
let tokio_core = tokio_core::reactor::Core::new().unwrap();
|
2017-12-05 10:17:24 +01:00
|
|
|
let tcp_transport = libp2p_tcp_transport::TcpConfig::new(tokio_core.handle());
|
2018-05-16 12:59:36 +02:00
|
|
|
let upgraded = tcp_transport.with_upgrade(libp2p_core::PlainTextConfig);
|
2017-12-04 18:49:47 +01:00
|
|
|
|
|
|
|
// upgraded.dial(...) // automatically applies the plain text protocol on the socket
|
|
|
|
```
|
|
|
|
|
2017-12-05 13:03:55 +01:00
|
|
|
## 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)`.
|
|
|
|
|
2017-12-07 15:10:46 +01:00
|
|
|
The `ConnectionReuse` struct then implements the `Transport` and `MuxedTransport` traits, 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.
|
|
|
|
|
|
|
|
> **Note**: Right now the `ConnectionReuse` struct is not fully implemented.
|
2017-12-05 13:03:55 +01:00
|
|
|
|
2018-07-27 18:10:14 +10:00
|
|
|
`TODO: add an example once the multiplex pull request is merged`
|
2017-12-05 13:03:55 +01:00
|
|
|
|
2017-12-04 18:49:47 +01:00
|
|
|
## Actual protocols
|
|
|
|
|
|
|
|
*Actual protocols* work the same way as middlewares, except that their `Output` doesn't
|
2017-12-05 13:03:55 +01:00
|
|
|
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.
|
2017-12-04 18:49:47 +01:00
|
|
|
|
2017-12-05 13:03:55 +01:00
|
|
|
However the `UpgradedNode` struct returned by `with_upgrade` still provides methods named
|
2018-01-03 14:19:24 +01:00
|
|
|
`dial`, `listen_on`, and `next_incoming`, which will yield you a `Future` or a `Stream`,
|
2017-12-07 15:10:46 +01:00
|
|
|
which you can use to obtain the `Output`. This `Output` can then be used in a protocol-specific
|
|
|
|
way to use the protocol.
|
2017-12-04 18:49:47 +01:00
|
|
|
|
2018-01-03 14:19:24 +01:00
|
|
|
```rust
|
2017-12-04 18:49:47 +01:00
|
|
|
extern crate futures;
|
|
|
|
extern crate libp2p_ping;
|
2018-05-16 12:59:36 +02:00
|
|
|
extern crate libp2p_core;
|
2017-12-04 18:49:47 +01:00
|
|
|
extern crate libp2p_tcp_transport;
|
2018-07-16 12:15:27 +02:00
|
|
|
extern crate tokio_current_thread;
|
2017-12-04 18:49:47 +01:00
|
|
|
|
|
|
|
use futures::Future;
|
|
|
|
use libp2p_ping::Ping;
|
2018-05-16 12:59:36 +02:00
|
|
|
use libp2p_core::Transport;
|
2017-12-04 18:49:47 +01:00
|
|
|
|
|
|
|
let mut core = tokio_core::reactor::Core::new().unwrap();
|
|
|
|
|
2018-07-16 12:15:27 +02:00
|
|
|
let ping_finished_future = libp2p_tcp_transport::TcpConfig::new()
|
2017-12-05 10:17:24 +01:00
|
|
|
// We have a `TcpConfig` struct that implements `Transport`, and apply a `Ping` upgrade on it.
|
2017-12-04 18:49:47 +01:00
|
|
|
.with_upgrade(Ping)
|
|
|
|
// TODO: right now the only available protocol is ping, but we want to replace it with
|
|
|
|
// something that is more simple to use
|
2018-05-16 12:59:36 +02:00
|
|
|
.dial("127.0.0.1:12345".parse::<libp2p_core::Multiaddr>().unwrap()).unwrap_or_else(|_| panic!())
|
2018-03-07 10:49:11 +01:00
|
|
|
.and_then(|((mut pinger, service), _)| {
|
2017-12-04 18:49:47 +01:00
|
|
|
pinger.ping().map_err(|_| panic!()).select(service).map_err(|_| panic!())
|
|
|
|
});
|
|
|
|
|
|
|
|
// Runs until the ping arrives.
|
2018-07-16 12:15:27 +02:00
|
|
|
tokio_current_thread::block_on_all(ping_finished_future).unwrap();
|
2017-12-04 18:49:47 +01:00
|
|
|
```
|
|
|
|
|
|
|
|
## Grouping protocols
|
|
|
|
|
|
|
|
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.
|
2018-01-03 14:19:24 +01:00
|
|
|
|
|
|
|
# Swarm
|
|
|
|
|
|
|
|
Once you have created an object that implements the `Transport` trait, you can put it in a
|
|
|
|
*swarm*. This is done by calling the `swarm()` freestanding function with the transport
|
|
|
|
alongside with a function or a closure that will turn the output of the upgrade (usually an
|
|
|
|
actual protocol, as explained above) into a `Future` producing `()`.
|
|
|
|
|
|
|
|
```rust
|
|
|
|
extern crate futures;
|
|
|
|
extern crate libp2p_ping;
|
2018-05-16 12:59:36 +02:00
|
|
|
extern crate libp2p_core;
|
2018-01-03 14:19:24 +01:00
|
|
|
extern crate libp2p_tcp_transport;
|
2018-07-16 12:15:27 +02:00
|
|
|
extern crate tokio_current_thread;
|
2018-01-03 14:19:24 +01:00
|
|
|
|
|
|
|
use futures::Future;
|
|
|
|
use libp2p_ping::Ping;
|
2018-05-16 12:59:36 +02:00
|
|
|
use libp2p_core::Transport;
|
2018-01-03 14:19:24 +01:00
|
|
|
|
|
|
|
let mut core = tokio_core::reactor::Core::new().unwrap();
|
|
|
|
|
2018-07-16 12:15:27 +02:00
|
|
|
let transport = libp2p_tcp_transport::TcpConfig::new()
|
2018-01-03 15:46:45 +01:00
|
|
|
.with_dummy_muxing();
|
2018-01-03 14:19:24 +01:00
|
|
|
|
2018-05-16 12:59:36 +02:00
|
|
|
let (swarm_controller, swarm_future) = libp2p_core::swarm(transport, Ping, |(mut pinger, service), client_addr| {
|
2018-01-03 14:19:24 +01:00
|
|
|
pinger.ping().map_err(|_| panic!())
|
|
|
|
.select(service).map_err(|_| panic!())
|
|
|
|
.map(|_| ())
|
|
|
|
});
|
|
|
|
|
|
|
|
// The `swarm_controller` can then be used to do some operations.
|
|
|
|
swarm_controller.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap());
|
|
|
|
|
|
|
|
// Runs until everything is finished.
|
2018-07-16 12:15:27 +02:00
|
|
|
tokio_current_thread::block_on_all(swarm_future).unwrap();
|
2018-01-03 14:19:24 +01:00
|
|
|
```
|