mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-15 02:51:25 +00:00
The SwarmFuture is now a Stream (#442)
* The SwarmFuture is now a Stream * Return the produced future in the message * Remove IncomingConnection event * Pass error when failing to dial * Fix loop break mistake * Fix concern * Rename SwarmFuture to SwarmEvents * Increase type length limit * Remove todo
This commit is contained in:
@ -177,7 +177,7 @@
|
|||||||
//! extern crate libp2p_tcp_transport;
|
//! extern crate libp2p_tcp_transport;
|
||||||
//! extern crate tokio_current_thread;
|
//! extern crate tokio_current_thread;
|
||||||
//!
|
//!
|
||||||
//! use futures::Future;
|
//! use futures::{Future, Stream};
|
||||||
//! use libp2p_ping::{Ping, PingOutput};
|
//! use libp2p_ping::{Ping, PingOutput};
|
||||||
//! use libp2p_core::Transport;
|
//! use libp2p_core::Transport;
|
||||||
//!
|
//!
|
||||||
@ -200,7 +200,7 @@
|
|||||||
//! swarm_controller.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap());
|
//! swarm_controller.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap());
|
||||||
//!
|
//!
|
||||||
//! // Runs until everything is finished.
|
//! // Runs until everything is finished.
|
||||||
//! tokio_current_thread::block_on_all(swarm_future).unwrap();
|
//! tokio_current_thread::block_on_all(swarm_future.for_each(|_| Ok(()))).unwrap();
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ pub use self::multiaddr::{AddrComponent, Multiaddr};
|
|||||||
pub use self::muxing::StreamMuxer;
|
pub use self::muxing::StreamMuxer;
|
||||||
pub use self::peer_id::PeerId;
|
pub use self::peer_id::PeerId;
|
||||||
pub use self::public_key::PublicKey;
|
pub use self::public_key::PublicKey;
|
||||||
pub use self::swarm::{swarm, SwarmController, SwarmFuture};
|
pub use self::swarm::{swarm, SwarmController, SwarmEvents};
|
||||||
pub use self::transport::{MuxedTransport, Transport};
|
pub use self::transport::{MuxedTransport, Transport};
|
||||||
pub use self::unique::{UniqueConnec, UniqueConnecFuture, UniqueConnecState};
|
pub use self::unique::{UniqueConnec, UniqueConnecFuture, UniqueConnecState};
|
||||||
pub use self::upgrade::{ConnectionUpgrade, Endpoint};
|
pub use self::upgrade::{ConnectionUpgrade, Endpoint};
|
||||||
|
@ -38,7 +38,7 @@ use {Multiaddr, MuxedTransport, Transport};
|
|||||||
pub fn swarm<T, H, F>(
|
pub fn swarm<T, H, F>(
|
||||||
transport: T,
|
transport: T,
|
||||||
handler: H,
|
handler: H,
|
||||||
) -> (SwarmController<T>, SwarmFuture<T, H>)
|
) -> (SwarmController<T, F::Future>, SwarmEvents<T, F::Future, H>)
|
||||||
where
|
where
|
||||||
T: MuxedTransport + Clone + 'static, // TODO: 'static :-/
|
T: MuxedTransport + Clone + 'static, // TODO: 'static :-/
|
||||||
H: FnMut(T::Output, Box<Future<Item = Multiaddr, Error = IoError>>) -> F,
|
H: FnMut(T::Output, Box<Future<Item = Multiaddr, Error = IoError>>) -> F,
|
||||||
@ -53,7 +53,7 @@ where
|
|||||||
task_to_notify: None,
|
task_to_notify: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let future = SwarmFuture {
|
let future = SwarmEvents {
|
||||||
transport: transport.clone(),
|
transport: transport.clone(),
|
||||||
shared: shared.clone(),
|
shared: shared.clone(),
|
||||||
handler: handler,
|
handler: handler,
|
||||||
@ -68,18 +68,18 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Allows control of what the swarm is doing.
|
/// Allows control of what the swarm is doing.
|
||||||
pub struct SwarmController<T>
|
pub struct SwarmController<T, F>
|
||||||
where
|
where
|
||||||
T: MuxedTransport + 'static, // TODO: 'static :-/
|
T: MuxedTransport + 'static, // TODO: 'static :-/
|
||||||
{
|
{
|
||||||
/// Shared between the swarm infrastructure.
|
/// Shared between the swarm infrastructure.
|
||||||
shared: Arc<Mutex<Shared<T>>>,
|
shared: Arc<Mutex<Shared<T, F>>>,
|
||||||
|
|
||||||
/// Transport used to dial or listen.
|
/// Transport used to dial or listen.
|
||||||
transport: T,
|
transport: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for SwarmController<T>
|
impl<T, F> fmt::Debug for SwarmController<T, F>
|
||||||
where
|
where
|
||||||
T: fmt::Debug + MuxedTransport + 'static, // TODO: 'static :-/
|
T: fmt::Debug + MuxedTransport + 'static, // TODO: 'static :-/
|
||||||
{
|
{
|
||||||
@ -90,11 +90,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Clone for SwarmController<T>
|
impl<T, F> Clone for SwarmController<T, F>
|
||||||
where
|
where
|
||||||
T: MuxedTransport + Clone + 'static, // TODO: 'static :-/
|
T: MuxedTransport + Clone + 'static, // TODO: 'static :-/
|
||||||
{
|
{
|
||||||
fn clone(&self) -> SwarmController<T> {
|
fn clone(&self) -> Self {
|
||||||
SwarmController {
|
SwarmController {
|
||||||
transport: self.transport.clone(),
|
transport: self.transport.clone(),
|
||||||
shared: self.shared.clone(),
|
shared: self.shared.clone(),
|
||||||
@ -102,9 +102,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SwarmController<T>
|
impl<T, F> SwarmController<T, F>
|
||||||
where
|
where
|
||||||
T: MuxedTransport + Clone + 'static, // TODO: 'static :-/
|
T: MuxedTransport + Clone + 'static, // TODO: 'static :-/
|
||||||
|
F: 'static,
|
||||||
{
|
{
|
||||||
/// Asks the swarm to dial the node with the given multiaddress. The connection is then
|
/// Asks the swarm to dial the node with the given multiaddress. The connection is then
|
||||||
/// upgraded using the `upgrade`, and the output is sent to the handler that was passed when
|
/// upgraded using the `upgrade`, and the output is sent to the handler that was passed when
|
||||||
@ -127,12 +128,12 @@ where
|
|||||||
/// dialing fails or the handler has been called with the resulting future.
|
/// dialing fails or the handler has been called with the resulting future.
|
||||||
///
|
///
|
||||||
/// The returned future is filled with the output of `then`.
|
/// The returned future is filled with the output of `then`.
|
||||||
pub(crate) fn dial_then<Du, F>(&self, multiaddr: Multiaddr, transport: Du, then: F)
|
pub(crate) fn dial_then<Du, TThen>(&self, multiaddr: Multiaddr, transport: Du, then: TThen)
|
||||||
-> Result<impl Future<Item = (), Error = IoError>, Multiaddr>
|
-> Result<impl Future<Item = (), Error = IoError>, Multiaddr>
|
||||||
where
|
where
|
||||||
Du: Transport + 'static, // TODO: 'static :-/
|
Du: Transport + 'static, // TODO: 'static :-/
|
||||||
Du::Output: Into<T::Output>,
|
Du::Output: Into<T::Output>,
|
||||||
F: FnOnce(Result<(), IoError>) -> Result<(), IoError> + 'static,
|
TThen: FnOnce(Result<(), IoError>) -> Result<(), IoError> + 'static,
|
||||||
{
|
{
|
||||||
trace!("Swarm dialing {}", multiaddr);
|
trace!("Swarm dialing {}", multiaddr);
|
||||||
|
|
||||||
@ -157,8 +158,9 @@ where
|
|||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("Error in dialer upgrade: {:?}", err);
|
debug!("Error in dialer upgrade: {:?}", err);
|
||||||
|
let err_clone = IoError::new(err.kind(), err.to_string());
|
||||||
then(Err(err));
|
then(Err(err));
|
||||||
Err(())
|
Err(err_clone)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -210,7 +212,7 @@ where
|
|||||||
Box::new(f) as Box<Future<Item = _, Error = _>>
|
Box::new(f) as Box<Future<Item = _, Error = _>>
|
||||||
}),
|
}),
|
||||||
) as Box<Stream<Item = _, Error = _>>;
|
) as Box<Stream<Item = _, Error = _>>;
|
||||||
shared.listeners.push(listener.into_future());
|
shared.listeners.push((new_addr.clone(), listener.into_future()));
|
||||||
if let Some(task) = shared.task_to_notify.take() {
|
if let Some(task) = shared.task_to_notify.take() {
|
||||||
task.notify();
|
task.notify();
|
||||||
}
|
}
|
||||||
@ -223,12 +225,12 @@ where
|
|||||||
|
|
||||||
/// Future that must be driven to completion in order for the swarm to work.
|
/// Future that must be driven to completion in order for the swarm to work.
|
||||||
#[must_use = "futures do nothing unless polled"]
|
#[must_use = "futures do nothing unless polled"]
|
||||||
pub struct SwarmFuture<T, H>
|
pub struct SwarmEvents<T, F, H>
|
||||||
where
|
where
|
||||||
T: MuxedTransport + 'static, // TODO: 'static :-/
|
T: MuxedTransport + 'static, // TODO: 'static :-/
|
||||||
{
|
{
|
||||||
/// Shared between the swarm infrastructure.
|
/// Shared between the swarm infrastructure.
|
||||||
shared: Arc<Mutex<Shared<T>>>,
|
shared: Arc<Mutex<Shared<T, F>>>,
|
||||||
|
|
||||||
/// The transport used to dial.
|
/// The transport used to dial.
|
||||||
transport: T,
|
transport: T,
|
||||||
@ -237,17 +239,17 @@ where
|
|||||||
handler: H,
|
handler: H,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, H, If, F> Future for SwarmFuture<T, H>
|
impl<T, H, If, F> Stream for SwarmEvents<T, F, H>
|
||||||
where
|
where
|
||||||
T: MuxedTransport + Clone + 'static, // TODO: 'static :-/,
|
T: MuxedTransport + Clone + 'static, // TODO: 'static :-/,
|
||||||
H: FnMut(T::Output, Box<Future<Item = Multiaddr, Error = IoError>>) -> If,
|
H: FnMut(T::Output, Box<Future<Item = Multiaddr, Error = IoError>>) -> If,
|
||||||
If: IntoFuture<Future = F, Item = (), Error = IoError>,
|
If: IntoFuture<Future = F, Item = (), Error = IoError>,
|
||||||
F: Future<Item = (), Error = IoError> + 'static, // TODO: 'static :-/
|
F: Future<Item = (), Error = IoError> + 'static, // TODO: 'static :-/
|
||||||
{
|
{
|
||||||
type Item = ();
|
type Item = SwarmEvent<F>;
|
||||||
type Error = IoError;
|
type Error = IoError;
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
|
||||||
let mut shared = self.shared.lock();
|
let mut shared = self.shared.lock();
|
||||||
let handler = &mut self.handler;
|
let handler = &mut self.handler;
|
||||||
|
|
||||||
@ -266,7 +268,7 @@ where
|
|||||||
// TODO: should that stop everything?
|
// TODO: should that stop everything?
|
||||||
debug!("Error in multiplexed incoming connection: {:?}", err);
|
debug!("Error in multiplexed incoming connection: {:?}", err);
|
||||||
shared.next_incoming = self.transport.clone().next_incoming();
|
shared.next_incoming = self.transport.clone().next_incoming();
|
||||||
break;
|
return Ok(Async::Ready(Some(SwarmEvent::IncomingError(err))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,7 +276,7 @@ where
|
|||||||
// We remove each element from `shared.listeners` one by one and add them back only
|
// We remove each element from `shared.listeners` one by one and add them back only
|
||||||
// if relevant.
|
// if relevant.
|
||||||
for n in (0 .. shared.listeners.len()).rev() {
|
for n in (0 .. shared.listeners.len()).rev() {
|
||||||
let mut listener = shared.listeners.swap_remove(n);
|
let (listen_addr, mut listener) = shared.listeners.swap_remove(n);
|
||||||
loop {
|
loop {
|
||||||
match listener.poll() {
|
match listener.poll() {
|
||||||
Ok(Async::Ready((Some(upgrade), remaining))) => {
|
Ok(Async::Ready((Some(upgrade), remaining))) => {
|
||||||
@ -284,14 +286,19 @@ where
|
|||||||
}
|
}
|
||||||
Ok(Async::Ready((None, _))) => {
|
Ok(Async::Ready((None, _))) => {
|
||||||
debug!("Listener closed gracefully");
|
debug!("Listener closed gracefully");
|
||||||
break;
|
return Ok(Async::Ready(Some(SwarmEvent::ListenerClosed {
|
||||||
|
listen_addr
|
||||||
|
})));
|
||||||
},
|
},
|
||||||
Err((err, _)) => {
|
Err((error, _)) => {
|
||||||
debug!("Error in listener: {:?}", err);
|
debug!("Error in listener: {:?}", error);
|
||||||
break;
|
return Ok(Async::Ready(Some(SwarmEvent::ListenerError {
|
||||||
|
listen_addr,
|
||||||
|
error,
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
Ok(Async::NotReady) => {
|
Ok(Async::NotReady) => {
|
||||||
shared.listeners.push(listener);
|
shared.listeners.push((listen_addr, listener));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,10 +314,11 @@ where
|
|||||||
debug!("Successfully upgraded incoming connection");
|
debug!("Successfully upgraded incoming connection");
|
||||||
// TODO: unlock mutex before calling handler, in order to avoid deadlocks if
|
// TODO: unlock mutex before calling handler, in order to avoid deadlocks if
|
||||||
// the user does something stupid
|
// the user does something stupid
|
||||||
shared.to_process.push(Box::new(handler(output, client_addr).into_future()));
|
shared.to_process.push(handler(output, client_addr).into_future());
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("Error in listener upgrade: {:?}", err);
|
debug!("Error in listener upgrade: {:?}", err);
|
||||||
|
return Ok(Async::Ready(Some(SwarmEvent::ListenerUpgradeError(err))));
|
||||||
}
|
}
|
||||||
Ok(Async::NotReady) => {
|
Ok(Async::NotReady) => {
|
||||||
shared.listeners_upgrade.push(listener_upgrade);
|
shared.listeners_upgrade.push(listener_upgrade);
|
||||||
@ -327,10 +335,15 @@ where
|
|||||||
trace!("Successfully upgraded dialed connection");
|
trace!("Successfully upgraded dialed connection");
|
||||||
// TODO: unlock mutex before calling handler, in order to avoid deadlocks if
|
// TODO: unlock mutex before calling handler, in order to avoid deadlocks if
|
||||||
// the user does something stupid
|
// the user does something stupid
|
||||||
shared.to_process.push(Box::new(handler(output, addr).into_future()));
|
shared.to_process.push(handler(output, addr).into_future());
|
||||||
notifier(Ok(()));
|
notifier(Ok(()));
|
||||||
}
|
}
|
||||||
Err(()) => {},
|
Err(error) => {
|
||||||
|
return Ok(Async::Ready(Some(SwarmEvent::DialFailed {
|
||||||
|
client_addr,
|
||||||
|
error,
|
||||||
|
})));
|
||||||
|
},
|
||||||
Ok(Async::NotReady) => {
|
Ok(Async::NotReady) => {
|
||||||
shared.dialers.push((client_addr, dialer));
|
shared.dialers.push((client_addr, dialer));
|
||||||
},
|
},
|
||||||
@ -344,9 +357,16 @@ where
|
|||||||
match to_process.poll() {
|
match to_process.poll() {
|
||||||
Ok(Async::Ready(())) => {
|
Ok(Async::Ready(())) => {
|
||||||
trace!("Future returned by swarm handler driven to completion");
|
trace!("Future returned by swarm handler driven to completion");
|
||||||
|
return Ok(Async::Ready(Some(SwarmEvent::HandlerFinished {
|
||||||
|
handler_future: to_process,
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(error) => {
|
||||||
debug!("Error in processing: {:?}", err);
|
debug!("Error in processing: {:?}", error);
|
||||||
|
return Ok(Async::Ready(Some(SwarmEvent::HandlerError {
|
||||||
|
handler_future: to_process,
|
||||||
|
error,
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
Ok(Async::NotReady) => {
|
Ok(Async::NotReady) => {
|
||||||
shared.to_process.push(to_process);
|
shared.to_process.push(to_process);
|
||||||
@ -363,12 +383,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: stronger typing
|
// TODO: stronger typing
|
||||||
struct Shared<T> where T: MuxedTransport + 'static {
|
struct Shared<T, F> where T: MuxedTransport + 'static {
|
||||||
/// Next incoming substream on the transport.
|
/// Next incoming substream on the transport.
|
||||||
next_incoming: T::Incoming,
|
next_incoming: T::Incoming,
|
||||||
|
|
||||||
/// All the active listeners.
|
/// All the active listeners.
|
||||||
listeners: Vec<
|
listeners: Vec<(
|
||||||
|
Multiaddr,
|
||||||
StreamFuture<
|
StreamFuture<
|
||||||
Box<
|
Box<
|
||||||
Stream<
|
Stream<
|
||||||
@ -377,7 +398,7 @@ struct Shared<T> where T: MuxedTransport + 'static {
|
|||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
>,
|
)>,
|
||||||
|
|
||||||
/// Futures that upgrade an incoming listening connection to a full connection.
|
/// Futures that upgrade an incoming listening connection to a full connection.
|
||||||
listeners_upgrade:
|
listeners_upgrade:
|
||||||
@ -386,19 +407,65 @@ struct Shared<T> where T: MuxedTransport + 'static {
|
|||||||
/// Futures that dial a remote address.
|
/// Futures that dial a remote address.
|
||||||
///
|
///
|
||||||
/// Contains the address we dial, so that we can cancel it if necessary.
|
/// Contains the address we dial, so that we can cancel it if necessary.
|
||||||
dialers: Vec<(Multiaddr, Box<Future<Item = (T::Output, Box<FnMut(Result<(), IoError>)>, Box<Future<Item = Multiaddr, Error = IoError>>), Error = ()>>)>,
|
dialers: Vec<(Multiaddr, Box<Future<Item = (T::Output, Box<FnMut(Result<(), IoError>)>, Box<Future<Item = Multiaddr, Error = IoError>>), Error = IoError>>)>,
|
||||||
|
|
||||||
/// List of futures produced by the swarm closure. Must be processed to the end.
|
/// List of futures produced by the swarm closure. Must be processed to the end.
|
||||||
to_process: Vec<Box<Future<Item = (), Error = IoError>>>,
|
to_process: Vec<F>,
|
||||||
|
|
||||||
/// The task to notify whenever we add a new element in one of the lists.
|
/// The task to notify whenever we add a new element in one of the lists.
|
||||||
/// Necessary so that the task wakes up and the element gets polled.
|
/// Necessary so that the task wakes up and the element gets polled.
|
||||||
task_to_notify: Option<task::Task>,
|
task_to_notify: Option<task::Task>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Event that happens in the swarm.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SwarmEvent<F> {
|
||||||
|
/// An error has happened while polling the muxed transport for incoming connections.
|
||||||
|
IncomingError(IoError),
|
||||||
|
|
||||||
|
/// A listener has gracefully closed.
|
||||||
|
ListenerClosed {
|
||||||
|
/// Address the listener was listening on.
|
||||||
|
listen_addr: Multiaddr,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// A listener has stopped because it produced an error.
|
||||||
|
ListenerError {
|
||||||
|
/// Address the listener was listening on.
|
||||||
|
listen_addr: Multiaddr,
|
||||||
|
/// The error that happened.
|
||||||
|
error: IoError,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// An error happened while upgrading an incoming connection.
|
||||||
|
ListenerUpgradeError(IoError),
|
||||||
|
|
||||||
|
/// Failed to dial a remote address.
|
||||||
|
DialFailed {
|
||||||
|
/// Address we were trying to dial.
|
||||||
|
client_addr: Multiaddr,
|
||||||
|
/// Error that happened.
|
||||||
|
error: IoError,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// A future returned by the handler has finished.
|
||||||
|
HandlerFinished {
|
||||||
|
/// The future originally returned by the handler.
|
||||||
|
handler_future: F,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// A future returned by the handler has produced an error.
|
||||||
|
HandlerError {
|
||||||
|
/// The future originally returned by the handler.
|
||||||
|
handler_future: F,
|
||||||
|
/// The error that happened.
|
||||||
|
error: IoError,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use futures::{Future, future};
|
use futures::{Future, Stream, future};
|
||||||
use rand;
|
use rand;
|
||||||
use transport::{self, DeniedTransport, Transport};
|
use transport::{self, DeniedTransport, Transport};
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
@ -441,8 +508,8 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let dial_success = swarm_ctrl2.dial("/memory".parse().unwrap(), tx).unwrap();
|
let dial_success = swarm_ctrl2.dial("/memory".parse().unwrap(), tx).unwrap();
|
||||||
let future = swarm_future2
|
let future = swarm_future2.for_each(|_| Ok(()))
|
||||||
.select(swarm_future1).map(|_| ()).map_err(|(err, _)| err)
|
.select(swarm_future1.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err)
|
||||||
.select(dial_success).map(|_| ()).map_err(|(err, _)| err);
|
.select(dial_success).map(|_| ()).map_err(|(err, _)| err);
|
||||||
|
|
||||||
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
||||||
@ -468,7 +535,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
let future = future::join_all(dials)
|
let future = future::join_all(dials)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.select(swarm_future)
|
.select(swarm_future.for_each(|_| Ok(())))
|
||||||
.map_err(|(err, _)| err);
|
.map_err(|(err, _)| err);
|
||||||
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
||||||
assert_eq!(reached.load(atomic::Ordering::SeqCst), num_dials);
|
assert_eq!(reached.load(atomic::Ordering::SeqCst), num_dials);
|
||||||
@ -484,7 +551,7 @@ mod tests {
|
|||||||
});
|
});
|
||||||
swarm_ctrl.listen_on("/memory".parse().unwrap()).unwrap();
|
swarm_ctrl.listen_on("/memory".parse().unwrap()).unwrap();
|
||||||
let dial_success = swarm_ctrl.dial("/memory".parse().unwrap(), tx).unwrap();
|
let dial_success = swarm_ctrl.dial("/memory".parse().unwrap(), tx).unwrap();
|
||||||
let future = dial_success.select(swarm_future)
|
let future = dial_success.select(swarm_future.for_each(|_| Ok(())))
|
||||||
.map_err(|(err, _)| err);
|
.map_err(|(err, _)| err);
|
||||||
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,9 @@ mod tests {
|
|||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(|((), _)| io::Error::new(io::ErrorKind::Other, "receive error"));
|
.map_err(|((), _)| io::Error::new(io::ErrorKind::Other, "receive error"));
|
||||||
|
|
||||||
let future = future.select(finish_rx)
|
let future = future
|
||||||
|
.for_each(|_| Ok(()))
|
||||||
|
.select(finish_rx)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(|(e, _)| e);
|
.map_err(|(e, _)| e);
|
||||||
|
|
||||||
|
@ -99,12 +99,13 @@ impl<T> UniqueConnec<T> {
|
|||||||
/// One critical property of this method, is that if a connection incomes and `tie_*` is
|
/// One critical property of this method, is that if a connection incomes and `tie_*` is
|
||||||
/// called, then it will be returned by the returned future.
|
/// called, then it will be returned by the returned future.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dial<S, Du>(&self, swarm: &SwarmController<S>, multiaddr: &Multiaddr,
|
pub fn dial<S, F, Du>(&self, swarm: &SwarmController<S, F>, multiaddr: &Multiaddr,
|
||||||
transport: Du) -> UniqueConnecFuture<T>
|
transport: Du) -> UniqueConnecFuture<T>
|
||||||
where T: Clone + 'static, // TODO: 'static :-/
|
where T: Clone + 'static, // TODO: 'static :-/
|
||||||
Du: Transport + 'static, // TODO: 'static :-/
|
Du: Transport + 'static, // TODO: 'static :-/
|
||||||
Du::Output: Into<S::Output>,
|
Du::Output: Into<S::Output>,
|
||||||
S: Clone + MuxedTransport,
|
S: Clone + MuxedTransport,
|
||||||
|
F: 'static,
|
||||||
{
|
{
|
||||||
self.dial_inner(swarm, multiaddr, transport, true)
|
self.dial_inner(swarm, multiaddr, transport, true)
|
||||||
}
|
}
|
||||||
@ -112,23 +113,25 @@ impl<T> UniqueConnec<T> {
|
|||||||
/// Same as `dial`, except that the future will produce an error if an earlier attempt to dial
|
/// Same as `dial`, except that the future will produce an error if an earlier attempt to dial
|
||||||
/// has errored.
|
/// has errored.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dial_if_empty<S, Du>(&self, swarm: &SwarmController<S>, multiaddr: &Multiaddr,
|
pub fn dial_if_empty<S, F, Du>(&self, swarm: &SwarmController<S, F>, multiaddr: &Multiaddr,
|
||||||
transport: Du) -> UniqueConnecFuture<T>
|
transport: Du) -> UniqueConnecFuture<T>
|
||||||
where T: Clone + 'static, // TODO: 'static :-/
|
where T: Clone + 'static, // TODO: 'static :-/
|
||||||
Du: Transport + 'static, // TODO: 'static :-/
|
Du: Transport + 'static, // TODO: 'static :-/
|
||||||
Du::Output: Into<S::Output>,
|
Du::Output: Into<S::Output>,
|
||||||
S: Clone + MuxedTransport,
|
S: Clone + MuxedTransport,
|
||||||
|
F: 'static,
|
||||||
{
|
{
|
||||||
self.dial_inner(swarm, multiaddr, transport, false)
|
self.dial_inner(swarm, multiaddr, transport, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inner implementation of `dial_*`.
|
/// Inner implementation of `dial_*`.
|
||||||
fn dial_inner<S, Du>(&self, swarm: &SwarmController<S>, multiaddr: &Multiaddr,
|
fn dial_inner<S, F, Du>(&self, swarm: &SwarmController<S, F>, multiaddr: &Multiaddr,
|
||||||
transport: Du, dial_if_err: bool) -> UniqueConnecFuture<T>
|
transport: Du, dial_if_err: bool) -> UniqueConnecFuture<T>
|
||||||
where T: Clone + 'static, // TODO: 'static :-/
|
where T: Clone + 'static, // TODO: 'static :-/
|
||||||
Du: Transport + 'static, // TODO: 'static :-/
|
Du: Transport + 'static, // TODO: 'static :-/
|
||||||
Du::Output: Into<S::Output>,
|
Du::Output: Into<S::Output>,
|
||||||
S: Clone + MuxedTransport,
|
S: Clone + MuxedTransport,
|
||||||
|
F: 'static,
|
||||||
{
|
{
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
match &*inner {
|
match &*inner {
|
||||||
@ -426,7 +429,7 @@ pub enum UniqueConnecState {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use futures::{future, sync::oneshot, Future};
|
use futures::{future, sync::oneshot, Future, Stream};
|
||||||
use transport::DeniedTransport;
|
use transport::DeniedTransport;
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use std::sync::{Arc, atomic};
|
use std::sync::{Arc, atomic};
|
||||||
@ -456,7 +459,7 @@ mod tests {
|
|||||||
.map(|val| { assert_eq!(val, 12); });
|
.map(|val| { assert_eq!(val, 12); });
|
||||||
assert_eq!(unique_connec.state(), UniqueConnecState::Pending);
|
assert_eq!(unique_connec.state(), UniqueConnecState::Pending);
|
||||||
|
|
||||||
let future = dial_success.select(swarm_future).map_err(|(err, _)| err);
|
let future = dial_success.select(swarm_future.for_each(|_| Ok(()))).map_err(|(err, _)| err);
|
||||||
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
||||||
assert_eq!(unique_connec.state(), UniqueConnecState::Full);
|
assert_eq!(unique_connec.state(), UniqueConnecState::Full);
|
||||||
}
|
}
|
||||||
@ -526,8 +529,8 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let future = dial_success
|
let future = dial_success
|
||||||
.select(swarm_future2).map(|_| ()).map_err(|(err, _)| err)
|
.select(swarm_future2.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err)
|
||||||
.select(swarm_future1).map(|_| ()).map_err(|(err, _)| err);
|
.select(swarm_future1.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err);
|
||||||
|
|
||||||
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
||||||
assert!(unique_connec.is_alive());
|
assert!(unique_connec.is_alive());
|
||||||
@ -557,7 +560,7 @@ mod tests {
|
|||||||
swarm_ctrl.dial("/memory".parse().unwrap(), tx)
|
swarm_ctrl.dial("/memory".parse().unwrap(), tx)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let future = dial_success.select(swarm_future).map_err(|(err, _)| err);
|
let future = dial_success.select(swarm_future.for_each(|_| Ok(()))).map_err(|(err, _)| err);
|
||||||
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
||||||
assert_eq!(unique_connec.poll(), Some(13));
|
assert_eq!(unique_connec.poll(), Some(13));
|
||||||
}
|
}
|
||||||
@ -601,8 +604,8 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let future = dial_success
|
let future = dial_success
|
||||||
.select(swarm_future1).map(|_| ()).map_err(|(err, _)| err)
|
.select(swarm_future1.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err)
|
||||||
.select(swarm_future2).map(|_| ()).map_err(|(err, _)| err);
|
.select(swarm_future2.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err);
|
||||||
|
|
||||||
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
||||||
assert!(!unique_connec.is_alive());
|
assert!(!unique_connec.is_alive());
|
||||||
@ -654,8 +657,8 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let future = dial_success
|
let future = dial_success
|
||||||
.select(swarm_future1).map(|_| ()).map_err(|(err, _)| err)
|
.select(swarm_future1.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err)
|
||||||
.select(swarm_future2).map(|_| ()).map_err(|(err, _)| err);
|
.select(swarm_future2.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err);
|
||||||
|
|
||||||
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
||||||
assert!(!unique_connec.is_alive());
|
assert!(!unique_connec.is_alive());
|
||||||
@ -699,8 +702,8 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let future = dial_success
|
let future = dial_success
|
||||||
.select(swarm_future1).map(|_| ()).map_err(|(err, _)| err)
|
.select(swarm_future1.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err)
|
||||||
.select(swarm_future2).map(|_| ()).map_err(|(err, _)| err);
|
.select(swarm_future2.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err);
|
||||||
|
|
||||||
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
||||||
}
|
}
|
||||||
@ -726,7 +729,7 @@ mod tests {
|
|||||||
drop(unique_connec);
|
drop(unique_connec);
|
||||||
|
|
||||||
let future = dial_success
|
let future = dial_success
|
||||||
.select(swarm_future).map(|_| ()).map_err(|(err, _)| err);
|
.select(swarm_future.for_each(|_| Ok(()))).map(|_| ()).map_err(|(err, _)| err);
|
||||||
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
current_thread::Runtime::new().unwrap().block_on(future).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ extern crate rand;
|
|||||||
extern crate tokio_current_thread;
|
extern crate tokio_current_thread;
|
||||||
extern crate tokio_io;
|
extern crate tokio_io;
|
||||||
|
|
||||||
use futures::{future, future::Future};
|
use futures::{future, future::Future, Stream};
|
||||||
use libp2p_core::Transport;
|
use libp2p_core::Transport;
|
||||||
use libp2p_tcp_transport::TcpConfig;
|
use libp2p_tcp_transport::TcpConfig;
|
||||||
use std::sync::{atomic, Arc};
|
use std::sync::{atomic, Arc};
|
||||||
@ -52,7 +52,7 @@ fn lots_of_swarms() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
swarm_controllers.push(ctrl);
|
swarm_controllers.push(ctrl);
|
||||||
swarm_futures.push(fut);
|
swarm_futures.push(fut.for_each(|_| Ok(())));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut addresses = Vec::new();
|
let mut addresses = Vec::new();
|
||||||
|
@ -133,6 +133,7 @@ fn main() {
|
|||||||
// actually started yet. Because we created the `TcpConfig` with tokio, we need to run the
|
// actually started yet. Because we created the `TcpConfig` with tokio, we need to run the
|
||||||
// future through the tokio core.
|
// future through the tokio core.
|
||||||
let final_future = swarm_future
|
let final_future = swarm_future
|
||||||
|
.for_each(|_| Ok(()))
|
||||||
.select(finished_rx.map_err(|_| unreachable!()))
|
.select(finished_rx.map_err(|_| unreachable!()))
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(|(err, _)| err);
|
.map_err(|(err, _)| err);
|
||||||
|
@ -141,5 +141,5 @@ fn main() {
|
|||||||
// `swarm_future` is a future that contains all the behaviour that we want, but nothing has
|
// `swarm_future` is a future that contains all the behaviour that we want, but nothing has
|
||||||
// actually started yet. Because we created the `TcpConfig` with tokio, we need to run the
|
// actually started yet. Because we created the `TcpConfig` with tokio, we need to run the
|
||||||
// future through the tokio core.
|
// future through the tokio core.
|
||||||
tokio_current_thread::block_on_all(swarm_future).unwrap();
|
tokio_current_thread::block_on_all(swarm_future.for_each(|_| Ok(()))).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -149,6 +149,7 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let final_fut = swarm_future
|
let final_fut = swarm_future
|
||||||
|
.for_each(|_| Ok(()))
|
||||||
.select(floodsub_rx)
|
.select(floodsub_rx)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(|e| e.0)
|
.map_err(|e| e.0)
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
#![type_length_limit = "2097152"]
|
// Libp2p's code unfortunately produces very large types. Rust's default length limit for type
|
||||||
|
// names is not large enough, therefore we need this attribute.
|
||||||
|
#![type_length_limit = "4194304"]
|
||||||
|
|
||||||
extern crate bigint;
|
extern crate bigint;
|
||||||
extern crate bytes;
|
extern crate bytes;
|
||||||
@ -231,7 +233,7 @@ fn main() {
|
|||||||
// future through the tokio core.
|
// future through the tokio core.
|
||||||
tokio_current_thread::block_on_all(
|
tokio_current_thread::block_on_all(
|
||||||
finish_enum
|
finish_enum
|
||||||
.select(swarm_future)
|
.select(swarm_future.for_each(|_| Ok(())))
|
||||||
.map(|(n, _)| n)
|
.map(|(n, _)| n)
|
||||||
.map_err(|(err, _)| err),
|
.map_err(|(err, _)| err),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
@ -25,7 +25,7 @@ extern crate libp2p;
|
|||||||
extern crate tokio_current_thread;
|
extern crate tokio_current_thread;
|
||||||
extern crate tokio_io;
|
extern crate tokio_io;
|
||||||
|
|
||||||
use futures::Future;
|
use futures::{Future, Stream};
|
||||||
use futures::sync::oneshot;
|
use futures::sync::oneshot;
|
||||||
use std::env;
|
use std::env;
|
||||||
use libp2p::core::Transport;
|
use libp2p::core::Transport;
|
||||||
@ -112,7 +112,7 @@ fn main() {
|
|||||||
// actually started yet. Because we created the `TcpConfig` with tokio, we need to run the
|
// actually started yet. Because we created the `TcpConfig` with tokio, we need to run the
|
||||||
// future through the tokio core.
|
// future through the tokio core.
|
||||||
tokio_current_thread::block_on_all(
|
tokio_current_thread::block_on_all(
|
||||||
rx.select(swarm_future.map_err(|_| unreachable!()))
|
rx.select(swarm_future.for_each(|_| Ok(())).map_err(|_| unreachable!()))
|
||||||
.map_err(|(e, _)| e)
|
.map_err(|(e, _)| e)
|
||||||
.map(|_| ()),
|
.map(|_| ()),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
@ -152,7 +152,7 @@ fn run_dialer(opts: DialerOpts) -> Result<(), Box<Error>> {
|
|||||||
|
|
||||||
control.dial(address, transport.with_upgrade(echo)).map_err(|_| "failed to dial")?;
|
control.dial(address, transport.with_upgrade(echo)).map_err(|_| "failed to dial")?;
|
||||||
|
|
||||||
tokio_current_thread::block_on_all(future).map_err(From::from)
|
tokio_current_thread::block_on_all(future.for_each(|_| Ok(()))).map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_listener(opts: ListenerOpts) -> Result<(), Box<Error>> {
|
fn run_listener(opts: ListenerOpts) -> Result<(), Box<Error>> {
|
||||||
@ -206,7 +206,7 @@ fn run_listener(opts: ListenerOpts) -> Result<(), Box<Error>> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
control.listen_on(opts.listen).map_err(|_| "failed to listen")?;
|
control.listen_on(opts.listen).map_err(|_| "failed to listen")?;
|
||||||
tokio_current_thread::block_on_all(future).map_err(From::from)
|
tokio_current_thread::block_on_all(future.for_each(|_| Ok(()))).map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom parsers ///////////////////////////////////////////////////////////
|
// Custom parsers ///////////////////////////////////////////////////////////
|
||||||
|
Reference in New Issue
Block a user