mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-08-01 01:11:58 +00:00
Merge remote-tracking branch 'upstream/master' into muxer-trait
This commit is contained in:
26
example/README.md
Normal file
26
example/README.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Examples
|
||||||
|
|
||||||
|
Running one of the examples:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo run --example <name-of-the-example>
|
||||||
|
```
|
||||||
|
|
||||||
|
The follow examples exist:
|
||||||
|
|
||||||
|
- `echo-dialer` will attempt to connect to `/ip4/127.0.0.1/tcp/10333`, negotiate the `/echo/1.0.0`
|
||||||
|
protocol, then send the `"hello world"` message. Compatible with the `echo-server` example.
|
||||||
|
- `echo-server` will listen on `/ip4/0.0.0.0/tcp/10333`, negotiate the `/echo/1.0.0` protocol with
|
||||||
|
each incoming connection, then send back any entering message. Compatible with the `echo-dialer`
|
||||||
|
example.
|
||||||
|
|
||||||
|
## How the keys were generated
|
||||||
|
|
||||||
|
The keys used in the examples were generated like this:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
openssl genrsa -out private.pem 2048
|
||||||
|
openssl rsa -in private.pem -outform DER -pubout -out public.der
|
||||||
|
openssl pkcs8 -in private.pem -topk8 -nocrypt -out private.pk8
|
||||||
|
rm private.pem # optional
|
||||||
|
```
|
@@ -65,7 +65,7 @@ fn main() {
|
|||||||
|
|
||||||
let future = with_echo.listen_on(swarm::multiaddr::Multiaddr::new("/ip4/0.0.0.0/tcp/10333").unwrap())
|
let future = with_echo.listen_on(swarm::multiaddr::Multiaddr::new("/ip4/0.0.0.0/tcp/10333").unwrap())
|
||||||
.map_err(|_| panic!())
|
.map_err(|_| panic!())
|
||||||
.unwrap()
|
.unwrap().0
|
||||||
.for_each(|(socket, _)| {
|
.for_each(|(socket, _)| {
|
||||||
loop_fn(socket, |socket| {
|
loop_fn(socket, |socket| {
|
||||||
socket.into_future()
|
socket.into_future()
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw3Dq8sdKZ/Lq0AkCFRB+ywQXpubvHgscR+WyVV4tdQE+0OcJSC5hx5W+XLR/y21PTe/30f0oYP7oJv8rH2Mov1Gvops2l6efVqPA8ZggDRrAkotjLXXJggDimIGichRS9+izNi/Lit77H2bFLmlkTfrFOjibWrPP+XvoYRFN3B1gyUT5P1hARePlbb86dcd1e5l/x/lBDH7DJ+TxsY7li6HjgvlxK4jAXa9yzdkDvJOpScs+la7gGawwesDKoQ5dWyqlgT93cbXhwOHTUvownl0hwtYjiK9UGWW8ptn9/3ehYAyi6Kx/SqLJsXiJFlPg16KNunGBHL7VAFyYZ51NEwIDAQAB
|
|
@@ -88,9 +88,9 @@ impl<T, C> Transport for ConnectionReuse<T, C>
|
|||||||
type Listener = ConnectionReuseListener<Box<Stream<Item = (C::Output, Multiaddr), Error = IoError>>, C::Output>;
|
type Listener = ConnectionReuseListener<Box<Stream<Item = (C::Output, Multiaddr), Error = IoError>>, C::Output>;
|
||||||
type Dial = Box<Future<Item = Self::RawConn, Error = IoError>>;
|
type Dial = Box<Future<Item = Self::RawConn, Error = IoError>>;
|
||||||
|
|
||||||
fn listen_on(self, addr: Multiaddr) -> Result<Self::Listener, (Self, Multiaddr)> {
|
fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> {
|
||||||
let listener = match self.inner.listen_on(addr.clone()) {
|
let (listener, new_addr) = match self.inner.listen_on(addr.clone()) {
|
||||||
Ok(l) => l,
|
Ok((l, a)) => (l, a),
|
||||||
Err((inner, addr)) => {
|
Err((inner, addr)) => {
|
||||||
return Err((ConnectionReuse {
|
return Err((ConnectionReuse {
|
||||||
inner: inner,
|
inner: inner,
|
||||||
@@ -98,10 +98,12 @@ impl<T, C> Transport for ConnectionReuse<T, C>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ConnectionReuseListener {
|
let listener = ConnectionReuseListener {
|
||||||
listener: listener.fuse(),
|
listener: listener.fuse(),
|
||||||
connections: Vec::new(),
|
connections: Vec::new(),
|
||||||
})
|
};
|
||||||
|
|
||||||
|
Ok((listener, new_addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dial(self, addr: Multiaddr) -> Result<Self::Dial, (Self, Multiaddr)> {
|
fn dial(self, addr: Multiaddr) -> Result<Self::Dial, (Self, Multiaddr)> {
|
||||||
|
@@ -58,10 +58,16 @@ pub trait Transport {
|
|||||||
/// A future which indicates that we are currently dialing to a peer.
|
/// A future which indicates that we are currently dialing to a peer.
|
||||||
type Dial: IntoFuture<Item = Self::RawConn, Error = IoError>;
|
type Dial: IntoFuture<Item = Self::RawConn, Error = IoError>;
|
||||||
|
|
||||||
/// Listen on the given multi-addr.
|
/// Listen on the given multiaddr. Returns a stream of incoming connections, plus a modified
|
||||||
|
/// version of the `Multiaddr`. This new `Multiaddr` is the one that that should be advertised
|
||||||
|
/// to other nodes, instead of the one passed as parameter.
|
||||||
///
|
///
|
||||||
/// Returns the address back if it isn't supported.
|
/// Returns the address back if it isn't supported.
|
||||||
fn listen_on(self, addr: Multiaddr) -> Result<Self::Listener, (Self, Multiaddr)>
|
///
|
||||||
|
/// > **Note**: The reason why we need to change the `Multiaddr` on success is to handle
|
||||||
|
/// > situations such as turning `/ip4/127.0.0.1/tcp/0` into
|
||||||
|
/// > `/ip4/127.0.0.1/tcp/<actual port>`.
|
||||||
|
fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)>
|
||||||
where Self: Sized;
|
where Self: Sized;
|
||||||
|
|
||||||
/// Dial to the given multi-addr.
|
/// Dial to the given multi-addr.
|
||||||
@@ -108,7 +114,7 @@ impl Transport for DeniedTransport {
|
|||||||
type Dial = Box<Future<Item = Self::RawConn, Error = IoError>>;
|
type Dial = Box<Future<Item = Self::RawConn, Error = IoError>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn listen_on(self, addr: Multiaddr) -> Result<Self::Listener, (Self, Multiaddr)> {
|
fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> {
|
||||||
Err((DeniedTransport, addr))
|
Err((DeniedTransport, addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,14 +139,14 @@ impl<A, B> Transport for OrTransport<A, B>
|
|||||||
<B::Dial as IntoFuture>::Future,
|
<B::Dial as IntoFuture>::Future,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
fn listen_on(self, addr: Multiaddr) -> Result<Self::Listener, (Self, Multiaddr)> {
|
fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> {
|
||||||
let (first, addr) = match self.0.listen_on(addr) {
|
let (first, addr) = match self.0.listen_on(addr) {
|
||||||
Ok(connec) => return Ok(EitherStream::First(connec)),
|
Ok((connec, addr)) => return Ok((EitherStream::First(connec), addr)),
|
||||||
Err(err) => err,
|
Err(err) => err,
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.1.listen_on(addr) {
|
match self.1.listen_on(addr) {
|
||||||
Ok(connec) => Ok(EitherStream::Second(connec)),
|
Ok((connec, addr)) => Ok((EitherStream::Second(connec), addr)),
|
||||||
Err((second, addr)) => Err((OrTransport(first, second), addr)),
|
Err((second, addr)) => Err((OrTransport(first, second), addr)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -543,14 +549,14 @@ impl<'a, T, C> UpgradedNode<T, C>
|
|||||||
pub fn listen_on(
|
pub fn listen_on(
|
||||||
self,
|
self,
|
||||||
addr: Multiaddr,
|
addr: Multiaddr,
|
||||||
) -> Result<Box<Stream<Item = (C::Output, Multiaddr), Error = IoError> + 'a>, (Self, Multiaddr)>
|
) -> Result<(Box<Stream<Item = (C::Output, Multiaddr), Error = IoError> + 'a>, Multiaddr), (Self, Multiaddr)>
|
||||||
where C::NamesIter: Clone, // TODO: not elegant
|
where C::NamesIter: Clone, // TODO: not elegant
|
||||||
C: Clone
|
C: Clone
|
||||||
{
|
{
|
||||||
let upgrade = self.upgrade;
|
let upgrade = self.upgrade;
|
||||||
|
|
||||||
let listening_stream = match self.transports.listen_on(addr) {
|
let (listening_stream, new_addr) = match self.transports.listen_on(addr) {
|
||||||
Ok(l) => l,
|
Ok((l, new_addr)) => (l, new_addr),
|
||||||
Err((trans, addr)) => {
|
Err((trans, addr)) => {
|
||||||
let builder = UpgradedNode {
|
let builder = UpgradedNode {
|
||||||
transports: trans,
|
transports: trans,
|
||||||
@@ -580,7 +586,7 @@ impl<'a, T, C> UpgradedNode<T, C>
|
|||||||
upgrade.upgrade(connection, upgrade_id).map(|c| (c, client_addr))
|
upgrade.upgrade(connection, upgrade_id).map(|c| (c, client_addr))
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(Box::new(stream))
|
Ok((Box::new(stream), new_addr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,7 +602,7 @@ impl<T, C> Transport for UpgradedNode<T, C>
|
|||||||
type Dial = Box<Future<Item = C::Output, Error = IoError>>;
|
type Dial = Box<Future<Item = C::Output, Error = IoError>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn listen_on(self, addr: Multiaddr) -> Result<Self::Listener, (Self, Multiaddr)>
|
fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)>
|
||||||
where Self: Sized
|
where Self: Sized
|
||||||
{
|
{
|
||||||
self.listen_on(addr)
|
self.listen_on(addr)
|
||||||
|
@@ -62,12 +62,21 @@ impl Transport for Tcp {
|
|||||||
|
|
||||||
/// Listen on the given multi-addr.
|
/// Listen on the given multi-addr.
|
||||||
/// Returns the address back if it isn't supported.
|
/// Returns the address back if it isn't supported.
|
||||||
fn listen_on(self, addr: Multiaddr) -> Result<Self::Listener, (Self, Multiaddr)> {
|
fn listen_on(self, addr: Multiaddr) -> Result<(Self::Listener, Multiaddr), (Self, Multiaddr)> {
|
||||||
if let Ok(socket_addr) = multiaddr_to_socketaddr(&addr) {
|
if let Ok(socket_addr) = multiaddr_to_socketaddr(&addr) {
|
||||||
Ok(Box::new(
|
let listener = TcpListener::bind(&socket_addr, &self.event_loop);
|
||||||
futures::future::result(
|
// We need to build the `Multiaddr` to return from this function. If an error happened,
|
||||||
TcpListener::bind(&socket_addr, &self.event_loop),
|
// just return the original multiaddr.
|
||||||
).map(|listener| {
|
let new_addr = match listener {
|
||||||
|
Ok(ref l) => if let Ok(new_s_addr) = l.local_addr() {
|
||||||
|
new_s_addr.to_multiaddr().expect("multiaddr generated from socket addr is \
|
||||||
|
always valid")
|
||||||
|
} else {
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
Err(_) => addr,
|
||||||
|
};
|
||||||
|
let future = futures::future::result(listener).map(|listener| {
|
||||||
// Pull out a stream of sockets for incoming connections
|
// Pull out a stream of sockets for incoming connections
|
||||||
listener.incoming().map(|(sock, addr)| {
|
listener.incoming().map(|(sock, addr)| {
|
||||||
let addr = addr.to_multiaddr()
|
let addr = addr.to_multiaddr()
|
||||||
@@ -75,8 +84,8 @@ impl Transport for Tcp {
|
|||||||
(sock, addr)
|
(sock, addr)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.flatten_stream(),
|
.flatten_stream();
|
||||||
))
|
Ok((Box::new(future), new_addr))
|
||||||
} else {
|
} else {
|
||||||
Err((self, addr))
|
Err((self, addr))
|
||||||
}
|
}
|
||||||
@@ -95,7 +104,7 @@ impl Transport for Tcp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This type of logic should probably be moved into the multiaddr package
|
// This type of logic should probably be moved into the multiaddr package
|
||||||
fn multiaddr_to_socketaddr(addr: &Multiaddr) -> Result<SocketAddr, &Multiaddr> {
|
fn multiaddr_to_socketaddr(addr: &Multiaddr) -> Result<SocketAddr, ()> {
|
||||||
let protocols = addr.protocol();
|
let protocols = addr.protocol();
|
||||||
|
|
||||||
// TODO: This is nonconforming (since a multiaddr could specify TCP first) but we can't fix that
|
// TODO: This is nonconforming (since a multiaddr could specify TCP first) but we can't fix that
|
||||||
@@ -118,9 +127,9 @@ fn multiaddr_to_socketaddr(addr: &Multiaddr) -> Result<SocketAddr, &Multiaddr> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(addr)
|
Err(())
|
||||||
}
|
}
|
||||||
_ => Err(addr),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +201,7 @@ mod tests {
|
|||||||
let addr = Multiaddr::new("/ip4/127.0.0.1/tcp/12345").unwrap();
|
let addr = Multiaddr::new("/ip4/127.0.0.1/tcp/12345").unwrap();
|
||||||
let tcp = Tcp::new(core.handle()).unwrap();
|
let tcp = Tcp::new(core.handle()).unwrap();
|
||||||
let handle = core.handle();
|
let handle = core.handle();
|
||||||
let listener = tcp.listen_on(addr).unwrap().for_each(|(sock, _)| {
|
let listener = tcp.listen_on(addr).unwrap().0.for_each(|(sock, _)| {
|
||||||
// Define what to do with the socket that just connected to us
|
// Define what to do with the socket that just connected to us
|
||||||
// Which in this case is read 3 bytes
|
// Which in this case is read 3 bytes
|
||||||
let handle_conn = tokio_io::io::read_exact(sock, [0; 3])
|
let handle_conn = tokio_io::io::read_exact(sock, [0; 3])
|
||||||
@@ -225,4 +234,16 @@ mod tests {
|
|||||||
core.run(action).unwrap();
|
core.run(action).unwrap();
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn replace_port_0_in_returned_multiaddr() {
|
||||||
|
let core = Core::new().unwrap();
|
||||||
|
let tcp = Tcp::new(core.handle()).unwrap();
|
||||||
|
|
||||||
|
let addr = Multiaddr::new("/ip4/127.0.0.1/tcp/0").unwrap();
|
||||||
|
assert!(addr.to_string().contains("tcp/0"));
|
||||||
|
|
||||||
|
let (_, new_addr) = tcp.listen_on(addr).unwrap();
|
||||||
|
assert!(!new_addr.to_string().contains("tcp/0"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
92
multistream-select/README.md
Normal file
92
multistream-select/README.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
# Multistream-select
|
||||||
|
|
||||||
|
This crate implements the `multistream-select` protocol, which is the protocol used by libp2p
|
||||||
|
to negotiate which protocol to use with the remote.
|
||||||
|
|
||||||
|
> **Note**: This crate is used by the internals of *libp2p*, and it is not required to
|
||||||
|
> understand it in order to use *libp2p*.
|
||||||
|
|
||||||
|
Whenever a new connection or a new multiplexed substream is opened, libp2p uses
|
||||||
|
`multistream-select` to negotiate with the remote which protocol to use. After a protocol has
|
||||||
|
been successfully negotiated, the stream (ie. the connection or the multiplexed substream)
|
||||||
|
immediately stops using `multistream-select` and starts using the negotiated protocol.
|
||||||
|
|
||||||
|
## Protocol explanation
|
||||||
|
|
||||||
|
The dialer has two options available: either request the list of protocols that the listener
|
||||||
|
supports, or suggest a protocol. If a protocol is suggested, the listener can either accept (by
|
||||||
|
answering with the same protocol name) or refuse the choice (by answering "not available").
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
For a dialer:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
extern crate bytes;
|
||||||
|
extern crate futures;
|
||||||
|
extern crate multistream_select;
|
||||||
|
extern crate tokio_core;
|
||||||
|
|
||||||
|
use bytes::Bytes;
|
||||||
|
use multistream_select::dialer_select_proto;
|
||||||
|
use futures::{Future, Sink, Stream};
|
||||||
|
use tokio_core::net::TcpStream;
|
||||||
|
use tokio_core::reactor::Core;
|
||||||
|
|
||||||
|
let mut core = Core::new().unwrap();
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum MyProto { Echo, Hello }
|
||||||
|
|
||||||
|
let client = TcpStream::connect(&"127.0.0.1:10333".parse().unwrap(), &core.handle())
|
||||||
|
.from_err()
|
||||||
|
.and_then(move |connec| {
|
||||||
|
let protos = vec![
|
||||||
|
(Bytes::from("/echo/1.0.0"), <Bytes as PartialEq>::eq, MyProto::Echo),
|
||||||
|
(Bytes::from("/hello/2.5.0"), <Bytes as PartialEq>::eq, MyProto::Hello),
|
||||||
|
]
|
||||||
|
.into_iter();
|
||||||
|
dialer_select_proto(connec, protos).map(|r| r.0)
|
||||||
|
});
|
||||||
|
|
||||||
|
let negotiated_protocol: MyProto = core.run(client).expect("failed to find a protocol");
|
||||||
|
println!("negotiated: {:?}", negotiated_protocol);
|
||||||
|
```
|
||||||
|
|
||||||
|
For a listener:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
extern crate bytes;
|
||||||
|
extern crate futures;
|
||||||
|
extern crate multistream_select;
|
||||||
|
extern crate tokio_core;
|
||||||
|
|
||||||
|
use bytes::Bytes;
|
||||||
|
use multistream_select::listener_select_proto;
|
||||||
|
use futures::{Future, Sink, Stream};
|
||||||
|
use tokio_core::net::TcpListener;
|
||||||
|
use tokio_core::reactor::Core;
|
||||||
|
|
||||||
|
let mut core = Core::new().unwrap();
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
enum MyProto { Echo, Hello }
|
||||||
|
|
||||||
|
let server = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap()
|
||||||
|
.incoming()
|
||||||
|
.from_err()
|
||||||
|
.and_then(move |(connec, _)| {
|
||||||
|
let protos = vec![
|
||||||
|
(Bytes::from("/echo/1.0.0"), <Bytes as PartialEq>::eq, MyProto::Echo),
|
||||||
|
(Bytes::from("/hello/2.5.0"), <Bytes as PartialEq>::eq, MyProto::Hello),
|
||||||
|
]
|
||||||
|
.into_iter();
|
||||||
|
listener_select_proto(connec, protos)
|
||||||
|
})
|
||||||
|
.for_each(|(proto, _connec)| {
|
||||||
|
println!("new remote with {:?} negotiated", proto);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
core.run(server).expect("failed to run server");
|
||||||
|
```
|
@@ -18,20 +18,105 @@
|
|||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
// DEALINGS IN THE SOFTWARE.
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
// TODO: use this once stable ; for now we just copy-paste the content of the README.md
|
||||||
|
//#![doc(include = "../README.md")]
|
||||||
|
|
||||||
//! # Multistream-select
|
//! # Multistream-select
|
||||||
//!
|
//!
|
||||||
//! Multistream-select is the "main" protocol of libp2p.
|
//! This crate implements the `multistream-select` protocol, which is the protocol used by libp2p
|
||||||
//! Whenever a connection opens between two peers, it starts talking in `multistream-select`.
|
//! to negotiate which protocol to use with the remote.
|
||||||
//!
|
//!
|
||||||
//! The purpose of `multistream-select` is to choose which protocol we are going to use. As soon as
|
//! > **Note**: This crate is used by the internals of *libp2p*, and it is not required to
|
||||||
//! both sides agree on a given protocol, the socket immediately starts using it and multistream is
|
//! > understand it in order to use *libp2p*.
|
||||||
//! no longer relevant.
|
|
||||||
//!
|
//!
|
||||||
//! However note that `multistream-select` is also sometimes used on top of another protocol such
|
//! Whenever a new connection or a new multiplexed substream is opened, libp2p uses
|
||||||
//! as secio or multiplex. For example, two hosts can use `multistream-select` to decide to use
|
//! `multistream-select` to negotiate with the remote which protocol to use. After a protocol has
|
||||||
//! secio, then use `multistream-select` again (wrapped inside `secio`) to decide to use
|
//! been successfully negotiated, the stream (ie. the connection or the multiplexed substream)
|
||||||
//! `multiplex`, then use `multistream-select` one more time (wrapped inside `secio` and
|
//! immediately stops using `multistream-select` and starts using the negotiated protocol.
|
||||||
//! `multiplex`) to decide to use the final actual protocol.
|
//!
|
||||||
|
//! ## Protocol explanation
|
||||||
|
//!
|
||||||
|
//! The dialer has two options available: either request the list of protocols that the listener
|
||||||
|
//! supports, or suggest a protocol. If a protocol is suggested, the listener can either accept (by
|
||||||
|
//! answering with the same protocol name) or refuse the choice (by answering "not available").
|
||||||
|
//!
|
||||||
|
//! ## Examples
|
||||||
|
//!
|
||||||
|
//! For a dialer:
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! extern crate bytes;
|
||||||
|
//! extern crate futures;
|
||||||
|
//! extern crate multistream_select;
|
||||||
|
//! extern crate tokio_core;
|
||||||
|
//!
|
||||||
|
//! # fn main() {
|
||||||
|
//! use bytes::Bytes;
|
||||||
|
//! use multistream_select::dialer_select_proto;
|
||||||
|
//! use futures::{Future, Sink, Stream};
|
||||||
|
//! use tokio_core::net::TcpStream;
|
||||||
|
//! use tokio_core::reactor::Core;
|
||||||
|
//!
|
||||||
|
//! let mut core = Core::new().unwrap();
|
||||||
|
//!
|
||||||
|
//! #[derive(Debug, Copy, Clone)]
|
||||||
|
//! enum MyProto { Echo, Hello }
|
||||||
|
//!
|
||||||
|
//! let client = TcpStream::connect(&"127.0.0.1:10333".parse().unwrap(), &core.handle())
|
||||||
|
//! .from_err()
|
||||||
|
//! .and_then(move |connec| {
|
||||||
|
//! let protos = vec![
|
||||||
|
//! (Bytes::from("/echo/1.0.0"), <Bytes as PartialEq>::eq, MyProto::Echo),
|
||||||
|
//! (Bytes::from("/hello/2.5.0"), <Bytes as PartialEq>::eq, MyProto::Hello),
|
||||||
|
//! ]
|
||||||
|
//! .into_iter();
|
||||||
|
//! dialer_select_proto(connec, protos).map(|r| r.0)
|
||||||
|
//! });
|
||||||
|
//!
|
||||||
|
//! let negotiated_protocol: MyProto = core.run(client).expect("failed to find a protocol");
|
||||||
|
//! println!("negotiated: {:?}", negotiated_protocol);
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! For a listener:
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! extern crate bytes;
|
||||||
|
//! extern crate futures;
|
||||||
|
//! extern crate multistream_select;
|
||||||
|
//! extern crate tokio_core;
|
||||||
|
//!
|
||||||
|
//! # fn main() {
|
||||||
|
//! use bytes::Bytes;
|
||||||
|
//! use multistream_select::listener_select_proto;
|
||||||
|
//! use futures::{Future, Sink, Stream};
|
||||||
|
//! use tokio_core::net::TcpListener;
|
||||||
|
//! use tokio_core::reactor::Core;
|
||||||
|
//!
|
||||||
|
//! let mut core = Core::new().unwrap();
|
||||||
|
//!
|
||||||
|
//! #[derive(Debug, Copy, Clone)]
|
||||||
|
//! enum MyProto { Echo, Hello }
|
||||||
|
//!
|
||||||
|
//! let server = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap()
|
||||||
|
//! .incoming()
|
||||||
|
//! .from_err()
|
||||||
|
//! .and_then(move |(connec, _)| {
|
||||||
|
//! let protos = vec![
|
||||||
|
//! (Bytes::from("/echo/1.0.0"), <Bytes as PartialEq>::eq, MyProto::Echo),
|
||||||
|
//! (Bytes::from("/hello/2.5.0"), <Bytes as PartialEq>::eq, MyProto::Hello),
|
||||||
|
//! ]
|
||||||
|
//! .into_iter();
|
||||||
|
//! listener_select_proto(connec, protos)
|
||||||
|
//! })
|
||||||
|
//! .for_each(|(proto, _connec)| {
|
||||||
|
//! println!("new remote with {:?} negotiated", proto);
|
||||||
|
//! Ok(())
|
||||||
|
//! });
|
||||||
|
//!
|
||||||
|
//! core.run(server).expect("failed to run server");
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
|
||||||
extern crate bytes;
|
extern crate bytes;
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
|
Reference in New Issue
Block a user