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:
Pierre Krieger
2018-09-04 14:53:27 +02:00
committed by GitHub
parent ee9be6f0c9
commit 75ceba7809
11 changed files with 146 additions and 70 deletions

View File

@ -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};

View File

@ -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();
} }

View File

@ -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);

View File

@ -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();
} }

View File

@ -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();

View File

@ -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);

View File

@ -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();
} }

View File

@ -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)

View File

@ -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();

View File

@ -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();

View File

@ -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 ///////////////////////////////////////////////////////////