More precise errors in the nodes module (#765)

* More precise errors in the nodes module

* Typo

* Prove the panics
This commit is contained in:
Pierre Krieger
2018-12-11 15:36:41 +01:00
committed by GitHub
parent a152e18821
commit 69684a97b2
7 changed files with 298 additions and 159 deletions

View File

@ -23,21 +23,21 @@ use crate::{
muxing::StreamMuxer, muxing::StreamMuxer,
nodes::{ nodes::{
node::Substream, node::Substream,
handled_node_tasks::{HandledNodesEvent, HandledNodesTasks}, handled_node_tasks::{HandledNodesEvent, HandledNodesTasks, TaskClosedEvent},
handled_node_tasks::{Task as HandledNodesTask, TaskId}, handled_node_tasks::{Task as HandledNodesTask, TaskId},
handled_node::NodeHandler handled_node::{HandledNodeError, NodeHandler}
} }
}; };
use fnv::FnvHashMap; use fnv::FnvHashMap;
use futures::prelude::*; use futures::prelude::*;
use std::{collections::hash_map::Entry, error, fmt, io, mem}; use std::{collections::hash_map::Entry, error, fmt, mem};
// TODO: make generic over PeerId // TODO: make generic over PeerId
/// Implementation of `Stream` that handles a collection of nodes. /// Implementation of `Stream` that handles a collection of nodes.
pub struct CollectionStream<TInEvent, TOutEvent, THandler> { pub struct CollectionStream<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> {
/// Object that handles the tasks. /// Object that handles the tasks.
inner: HandledNodesTasks<TInEvent, TOutEvent, THandler>, inner: HandledNodesTasks<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr>,
/// List of nodes, with the task id that handles this node. The corresponding entry in `tasks` /// List of nodes, with the task id that handles this node. The corresponding entry in `tasks`
/// must always be in the `Connected` state. /// must always be in the `Connected` state.
nodes: FnvHashMap<PeerId, TaskId>, nodes: FnvHashMap<PeerId, TaskId>,
@ -46,7 +46,7 @@ pub struct CollectionStream<TInEvent, TOutEvent, THandler> {
tasks: FnvHashMap<TaskId, TaskState>, tasks: FnvHashMap<TaskId, TaskState>,
} }
impl<TInEvent, TOutEvent, THandler> fmt::Debug for CollectionStream<TInEvent, TOutEvent, THandler> { impl<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> fmt::Debug for CollectionStream<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let mut list = f.debug_list(); let mut list = f.debug_list();
for (id, task) in &self.tasks { for (id, task) in &self.tasks {
@ -73,10 +73,10 @@ enum TaskState {
} }
/// Event that can happen on the `CollectionStream`. /// Event that can happen on the `CollectionStream`.
pub enum CollectionEvent<'a, TInEvent:'a , TOutEvent: 'a, THandler: 'a> { pub enum CollectionEvent<'a, TInEvent:'a , TOutEvent: 'a, THandler: 'a, TReachErr, THandlerErr> {
/// A connection to a node has succeeded. You must use the provided event in order to accept /// A connection to a node has succeeded. You must use the provided event in order to accept
/// the connection. /// the connection.
NodeReached(CollectionReachEvent<'a, TInEvent, TOutEvent, THandler>), NodeReached(CollectionReachEvent<'a, TInEvent, TOutEvent, THandler, TReachErr, THandlerErr>),
/// A connection to a node has been closed. /// A connection to a node has been closed.
/// ///
@ -94,7 +94,7 @@ pub enum CollectionEvent<'a, TInEvent:'a , TOutEvent: 'a, THandler: 'a> {
/// Identifier of the node. /// Identifier of the node.
peer_id: PeerId, peer_id: PeerId,
/// The error that happened. /// The error that happened.
error: io::Error, error: HandledNodeError<THandlerErr>,
}, },
/// An error happened on the future that was trying to reach a node. /// An error happened on the future that was trying to reach a node.
@ -102,7 +102,7 @@ pub enum CollectionEvent<'a, TInEvent:'a , TOutEvent: 'a, THandler: 'a> {
/// Identifier of the reach attempt that failed. /// Identifier of the reach attempt that failed.
id: ReachAttemptId, id: ReachAttemptId,
/// Error that happened on the future. /// Error that happened on the future.
error: io::Error, error: TReachErr,
/// The handler that was passed to `add_reach_attempt`. /// The handler that was passed to `add_reach_attempt`.
handler: THandler, handler: THandler,
}, },
@ -116,8 +116,10 @@ pub enum CollectionEvent<'a, TInEvent:'a , TOutEvent: 'a, THandler: 'a> {
}, },
} }
impl<'a, TInEvent, TOutEvent, THandler> fmt::Debug for CollectionEvent<'a, TInEvent, TOutEvent, THandler> impl<'a, TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> fmt::Debug for CollectionEvent<'a, TInEvent, TOutEvent, THandler, TReachErr, THandlerErr>
where TOutEvent: fmt::Debug where TOutEvent: fmt::Debug,
TReachErr: fmt::Debug,
THandlerErr: fmt::Debug,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self { match *self {
@ -155,16 +157,16 @@ where TOutEvent: fmt::Debug
/// Event that happens when we reach a node. /// Event that happens when we reach a node.
#[must_use = "The node reached event is used to accept the newly-opened connection"] #[must_use = "The node reached event is used to accept the newly-opened connection"]
pub struct CollectionReachEvent<'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> { pub struct CollectionReachEvent<'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a, TReachErr, THandlerErr: 'a> {
/// Peer id we connected to. /// Peer id we connected to.
peer_id: PeerId, peer_id: PeerId,
/// The task id that reached the node. /// The task id that reached the node.
id: TaskId, id: TaskId,
/// The `CollectionStream` we are referencing. /// The `CollectionStream` we are referencing.
parent: &'a mut CollectionStream<TInEvent, TOutEvent, THandler>, parent: &'a mut CollectionStream<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr>,
} }
impl<'a, TInEvent, TOutEvent, THandler> CollectionReachEvent<'a, TInEvent, TOutEvent, THandler> { impl<'a, TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> CollectionReachEvent<'a, TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> {
/// Returns the peer id of the node that has been reached. /// Returns the peer id of the node that has been reached.
#[inline] #[inline]
pub fn peer_id(&self) -> &PeerId { pub fn peer_id(&self) -> &PeerId {
@ -227,7 +229,7 @@ impl<'a, TInEvent, TOutEvent, THandler> CollectionReachEvent<'a, TInEvent, TOutE
} }
} }
impl<'a, TInEvent, TOutEvent, THandler> fmt::Debug for CollectionReachEvent<'a, TInEvent, TOutEvent, THandler> { impl<'a, TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> fmt::Debug for CollectionReachEvent<'a, TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_struct("CollectionReachEvent") f.debug_struct("CollectionReachEvent")
.field("peer_id", &self.peer_id) .field("peer_id", &self.peer_id)
@ -236,7 +238,7 @@ impl<'a, TInEvent, TOutEvent, THandler> fmt::Debug for CollectionReachEvent<'a,
} }
} }
impl<'a, TInEvent, TOutEvent, THandler> Drop for CollectionReachEvent<'a, TInEvent, TOutEvent, THandler> { impl<'a, TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> Drop for CollectionReachEvent<'a, TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> {
fn drop(&mut self) { fn drop(&mut self) {
let task_state = self.parent.tasks.remove(&self.id); let task_state = self.parent.tasks.remove(&self.id);
debug_assert!(if let Some(TaskState::Pending) = task_state { true } else { false }); debug_assert!(if let Some(TaskState::Pending) = task_state { true } else { false });
@ -262,7 +264,7 @@ pub enum CollectionNodeAccept {
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ReachAttemptId(TaskId); pub struct ReachAttemptId(TaskId);
impl<TInEvent, TOutEvent, THandler> CollectionStream<TInEvent, TOutEvent, THandler> { impl<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> CollectionStream<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> {
/// Creates a new empty collection. /// Creates a new empty collection.
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Self {
@ -280,9 +282,10 @@ impl<TInEvent, TOutEvent, THandler> CollectionStream<TInEvent, TOutEvent, THandl
pub fn add_reach_attempt<TFut, TMuxer>(&mut self, future: TFut, handler: THandler) pub fn add_reach_attempt<TFut, TMuxer>(&mut self, future: TFut, handler: THandler)
-> ReachAttemptId -> ReachAttemptId
where where
TFut: Future<Item = (PeerId, TMuxer)> + Send + 'static, TFut: Future<Item = (PeerId, TMuxer), Error = TReachErr> + Send + 'static,
TFut::Error: std::error::Error + Send + Sync + 'static, THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent, Error = THandlerErr> + Send + 'static,
THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, TReachErr: error::Error + Send + 'static,
THandlerErr: error::Error + Send + 'static,
TInEvent: Send + 'static, TInEvent: Send + 'static,
TOutEvent: Send + 'static, TOutEvent: Send + 'static,
THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be required? THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be required?
@ -369,7 +372,7 @@ impl<TInEvent, TOutEvent, THandler> CollectionStream<TInEvent, TOutEvent, THandl
/// > **Note**: we use a regular `poll` method instead of implementing `Stream` in order to /// > **Note**: we use a regular `poll` method instead of implementing `Stream` in order to
/// > remove the `Err` variant, but also because we want the `CollectionStream` to stay /// > remove the `Err` variant, but also because we want the `CollectionStream` to stay
/// > borrowed if necessary. /// > borrowed if necessary.
pub fn poll(&mut self) -> Async<CollectionEvent<TInEvent, TOutEvent, THandler>> { pub fn poll(&mut self) -> Async<CollectionEvent<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr>> {
let item = match self.inner.poll() { let item = match self.inner.poll() {
Async::Ready(item) => item, Async::Ready(item) => item,
Async::NotReady => return Async::NotReady, Async::NotReady => return Async::NotReady,
@ -378,16 +381,27 @@ impl<TInEvent, TOutEvent, THandler> CollectionStream<TInEvent, TOutEvent, THandl
match item { match item {
HandledNodesEvent::TaskClosed { id, result, handler } => { HandledNodesEvent::TaskClosed { id, result, handler } => {
match (self.tasks.remove(&id), result, handler) { match (self.tasks.remove(&id), result, handler) {
(Some(TaskState::Pending), Err(err), Some(handler)) => { (Some(TaskState::Pending), Err(TaskClosedEvent::Reach(err)), Some(handler)) => {
Async::Ready(CollectionEvent::ReachError { Async::Ready(CollectionEvent::ReachError {
id: ReachAttemptId(id), id: ReachAttemptId(id),
error: err, error: err,
handler, handler,
}) })
}, },
(Some(TaskState::Pending), _, _) => { (Some(TaskState::Pending), Ok(()), _) => {
// TODO: this variant shouldn't happen; prove this panic!("The API of HandledNodesTasks guarantees that a task cannot \
panic!() gracefully closed before being connected to a node, in which case \
its state should be Connected and not Pending; QED");
},
(Some(TaskState::Pending), Err(TaskClosedEvent::Node(_)), _) => {
panic!("We switch the task state to Connected once we're connected, and \
a TaskClosedEvent::Node can only happen after we're \
connected; QED");
},
(Some(TaskState::Pending), Err(TaskClosedEvent::Reach(_)), None) => {
// TODO: this could be improved in the API of HandledNodesTasks
panic!("The HandledNodesTasks is guaranteed to always return the handler \
when producing a TaskClosedEvent::Reach error");
}, },
(Some(TaskState::Connected(peer_id)), Ok(()), _handler) => { (Some(TaskState::Connected(peer_id)), Ok(()), _handler) => {
debug_assert!(_handler.is_none()); debug_assert!(_handler.is_none());
@ -397,7 +411,7 @@ impl<TInEvent, TOutEvent, THandler> CollectionStream<TInEvent, TOutEvent, THandl
peer_id, peer_id,
}) })
}, },
(Some(TaskState::Connected(peer_id)), Err(err), _handler) => { (Some(TaskState::Connected(peer_id)), Err(TaskClosedEvent::Node(err)), _handler) => {
debug_assert!(_handler.is_none()); debug_assert!(_handler.is_none());
let _node_task_id = self.nodes.remove(&peer_id); let _node_task_id = self.nodes.remove(&peer_id);
debug_assert_eq!(_node_task_id, Some(id)); debug_assert_eq!(_node_task_id, Some(id));
@ -406,6 +420,10 @@ impl<TInEvent, TOutEvent, THandler> CollectionStream<TInEvent, TOutEvent, THandl
error: err, error: err,
}) })
}, },
(Some(TaskState::Connected(_)), Err(TaskClosedEvent::Reach(_)), _) => {
panic!("A TaskClosedEvent::Reach can only happen before we are connected \
to a node; therefore the TaskState won't be Connected; QED");
},
(None, _, _) => { (None, _, _) => {
panic!("self.tasks is always kept in sync with the tasks in self.inner; \ panic!("self.tasks is always kept in sync with the tasks in self.inner; \
when we add a task in self.inner we add a corresponding entry in \ when we add a task in self.inner we add a corresponding entry in \
@ -506,11 +524,10 @@ mod tests {
use tokio::runtime::current_thread::Runtime; use tokio::runtime::current_thread::Runtime;
use tokio::runtime::Builder; use tokio::runtime::Builder;
use nodes::NodeHandlerEvent; use nodes::NodeHandlerEvent;
use std::sync::Arc; use std::{io, sync::Arc};
use parking_lot::Mutex; use parking_lot::Mutex;
use void::Void;
type TestCollectionStream = CollectionStream<InEvent, OutEvent, Handler>; type TestCollectionStream = CollectionStream<InEvent, OutEvent, Handler, io::Error, io::Error>;
#[test] #[test]
fn has_connection_is_false_before_a_connection_has_been_made() { fn has_connection_is_false_before_a_connection_has_been_made() {
@ -532,7 +549,7 @@ mod tests {
assert!(cs.peer_mut(&peer_id).is_none()); assert!(cs.peer_mut(&peer_id).is_none());
let handler = Handler::default(); let handler = Handler::default();
let fut = future::ok::<_, Void>((peer_id.clone(), DummyMuxer::new())); let fut = future::ok((peer_id.clone(), DummyMuxer::new()));
cs.add_reach_attempt(fut, handler); cs.add_reach_attempt(fut, handler);
assert!(cs.peer_mut(&peer_id).is_none()); // task is pending assert!(cs.peer_mut(&peer_id).is_none()); // task is pending
} }
@ -546,7 +563,7 @@ mod tests {
muxer.set_inbound_connection_state(DummyConnectionState::Pending); muxer.set_inbound_connection_state(DummyConnectionState::Pending);
muxer.set_outbound_connection_state(DummyConnectionState::Opened); muxer.set_outbound_connection_state(DummyConnectionState::Opened);
let fut = future::ok::<_, Void>((peer_id, muxer)); let fut = future::ok((peer_id, muxer));
cs.add_reach_attempt(fut, Handler::default()); cs.add_reach_attempt(fut, Handler::default());
let mut rt = Runtime::new().unwrap(); let mut rt = Runtime::new().unwrap();
let mut poll_count = 0; let mut poll_count = 0;
@ -570,7 +587,7 @@ mod tests {
fn accepting_a_node_yields_new_entry() { fn accepting_a_node_yields_new_entry() {
let mut cs = TestCollectionStream::new(); let mut cs = TestCollectionStream::new();
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let fut = future::ok::<_, Void>((peer_id.clone(), DummyMuxer::new())); let fut = future::ok((peer_id.clone(), DummyMuxer::new()));
cs.add_reach_attempt(fut, Handler::default()); cs.add_reach_attempt(fut, Handler::default());
let mut rt = Runtime::new().unwrap(); let mut rt = Runtime::new().unwrap();
@ -622,7 +639,7 @@ mod tests {
muxer.set_inbound_connection_state(DummyConnectionState::Pending); muxer.set_inbound_connection_state(DummyConnectionState::Pending);
muxer.set_outbound_connection_state(DummyConnectionState::Opened); muxer.set_outbound_connection_state(DummyConnectionState::Opened);
let fut = future::ok::<_, Void>((task_peer_id.clone(), muxer)); let fut = future::ok((task_peer_id.clone(), muxer));
cs.lock().add_reach_attempt(fut, handler); cs.lock().add_reach_attempt(fut, handler);
let mut rt = Builder::new().core_threads(1).build().unwrap(); let mut rt = Builder::new().core_threads(1).build().unwrap();
@ -710,7 +727,7 @@ mod tests {
let cs = Arc::new(Mutex::new(TestCollectionStream::new())); let cs = Arc::new(Mutex::new(TestCollectionStream::new()));
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let muxer = DummyMuxer::new(); let muxer = DummyMuxer::new();
let task_inner_fut = future::ok::<_, Void>((peer_id.clone(), muxer)); let task_inner_fut = future::ok((peer_id.clone(), muxer));
let mut handler = Handler::default(); let mut handler = Handler::default();
handler.next_states = vec![HandlerState::Err]; // triggered when sending a NextState event handler.next_states = vec![HandlerState::Err]; // triggered when sending a NextState event
@ -756,7 +773,7 @@ mod tests {
let cs = Arc::new(Mutex::new(TestCollectionStream::new())); let cs = Arc::new(Mutex::new(TestCollectionStream::new()));
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let muxer = DummyMuxer::new(); let muxer = DummyMuxer::new();
let task_inner_fut = future::ok::<_, Void>((peer_id.clone(), muxer)); let task_inner_fut = future::ok((peer_id.clone(), muxer));
let mut handler = Handler::default(); let mut handler = Handler::default();
handler.next_states = vec![HandlerState::Ready(None)]; // triggered when sending a NextState event handler.next_states = vec![HandlerState::Ready(None)]; // triggered when sending a NextState event
@ -802,7 +819,7 @@ mod tests {
#[test] #[test]
fn interrupting_a_pending_connection_attempt_is_ok() { fn interrupting_a_pending_connection_attempt_is_ok() {
let mut cs = TestCollectionStream::new(); let mut cs = TestCollectionStream::new();
let fut = future::empty::<_, Void>(); let fut = future::empty();
let reach_id = cs.add_reach_attempt(fut, Handler::default()); let reach_id = cs.add_reach_attempt(fut, Handler::default());
let interrupt = cs.interrupt(reach_id); let interrupt = cs.interrupt(reach_id);
assert!(interrupt.is_ok()); assert!(interrupt.is_ok());
@ -811,7 +828,7 @@ mod tests {
#[test] #[test]
fn interrupting_a_connection_attempt_twice_is_err() { fn interrupting_a_connection_attempt_twice_is_err() {
let mut cs = TestCollectionStream::new(); let mut cs = TestCollectionStream::new();
let fut = future::empty::<_, Void>(); let fut = future::empty();
let reach_id = cs.add_reach_attempt(fut, Handler::default()); let reach_id = cs.add_reach_attempt(fut, Handler::default());
assert!(cs.interrupt(reach_id).is_ok()); assert!(cs.interrupt(reach_id).is_ok());
assert_matches!(cs.interrupt(reach_id), Err(InterruptError::ReachAttemptNotFound)) assert_matches!(cs.interrupt(reach_id), Err(InterruptError::ReachAttemptNotFound))
@ -822,7 +839,7 @@ mod tests {
let cs = Arc::new(Mutex::new(TestCollectionStream::new())); let cs = Arc::new(Mutex::new(TestCollectionStream::new()));
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let muxer = DummyMuxer::new(); let muxer = DummyMuxer::new();
let task_inner_fut = future::ok::<_, Void>((peer_id.clone(), muxer)); let task_inner_fut = future::ok((peer_id.clone(), muxer));
let handler = Handler::default(); let handler = Handler::default();
let reach_id = cs.lock().add_reach_attempt(task_inner_fut, handler); let reach_id = cs.lock().add_reach_attempt(task_inner_fut, handler);

View File

@ -21,7 +21,7 @@
use muxing::StreamMuxer; use muxing::StreamMuxer;
use nodes::node::{NodeEvent, NodeStream, Substream}; use nodes::node::{NodeEvent, NodeStream, Substream};
use futures::{prelude::*, stream::Fuse}; use futures::{prelude::*, stream::Fuse};
use std::{io::Error as IoError, fmt}; use std::{error, fmt, io};
/// Handler for the substreams of a node. /// Handler for the substreams of a node.
// TODO: right now it is possible for a node handler to be built, then shut down right after if we // TODO: right now it is possible for a node handler to be built, then shut down right after if we
@ -32,6 +32,8 @@ pub trait NodeHandler {
type InEvent; type InEvent;
/// Custom event that can be produced by the handler and that will be returned by the swarm. /// Custom event that can be produced by the handler and that will be returned by the swarm.
type OutEvent; type OutEvent;
/// Error that can happen during the processing of the node.
type Error;
/// The type of the substream containing the data. /// The type of the substream containing the data.
type Substream; type Substream;
/// Information about a substream. Can be sent to the handler through a `NodeHandlerEndpoint`, /// Information about a substream. Can be sent to the handler through a `NodeHandlerEndpoint`,
@ -74,7 +76,7 @@ pub trait NodeHandler {
/// Should behave like `Stream::poll()`. Should close if no more event can be produced and the /// Should behave like `Stream::poll()`. Should close if no more event can be produced and the
/// node should be closed. /// node should be closed.
fn poll(&mut self) -> Poll<Option<NodeHandlerEvent<Self::OutboundOpenInfo, Self::OutEvent>>, IoError>; fn poll(&mut self) -> Poll<Option<NodeHandlerEvent<Self::OutboundOpenInfo, Self::OutEvent>>, Self::Error>;
} }
/// Endpoint for a received substream. /// Endpoint for a received substream.
@ -248,7 +250,7 @@ where
THandler: NodeHandler<Substream = Substream<TMuxer>>, THandler: NodeHandler<Substream = Substream<TMuxer>>,
{ {
type Item = THandler::OutEvent; type Item = THandler::OutEvent;
type Error = IoError; type Error = HandledNodeError<THandler::Error>;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
loop { loop {
@ -258,7 +260,7 @@ where
let mut node_not_ready = false; let mut node_not_ready = false;
match self.node.poll()? { match self.node.poll().map_err(HandledNodeError::Node)? {
Async::NotReady => node_not_ready = true, Async::NotReady => node_not_ready = true,
Async::Ready(Some(NodeEvent::InboundSubstream { substream })) => { Async::Ready(Some(NodeEvent::InboundSubstream { substream })) => {
self.handler.inject_substream(substream, NodeHandlerEndpoint::Listener) self.handler.inject_substream(substream, NodeHandlerEndpoint::Listener)
@ -281,7 +283,7 @@ where
} }
} }
match if self.handler_is_done { Async::Ready(None) } else { self.handler.poll()? } { match if self.handler_is_done { Async::Ready(None) } else { self.handler.poll().map_err(HandledNodeError::Handler)? } {
Async::NotReady => { Async::NotReady => {
if node_not_ready { if node_not_ready {
break break
@ -316,13 +318,45 @@ where
} }
} }
/// Error that can happen when polling a `HandledNode`.
#[derive(Debug)]
pub enum HandledNodeError<THandlerErr> {
/// An error happend in the stream muxer.
// TODO: eventually this should also be a custom error
Node(io::Error),
/// An error happened in the handler of the connection to the node.
Handler(THandlerErr),
}
impl<THandlerErr> fmt::Display for HandledNodeError<THandlerErr>
where THandlerErr: fmt::Display
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
HandledNodeError::Node(err) => write!(f, "{}", err),
HandledNodeError::Handler(err) => write!(f, "{}", err),
}
}
}
impl<THandlerErr> error::Error for HandledNodeError<THandlerErr>
where THandlerErr: error::Error + 'static
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
HandledNodeError::Node(err) => Some(err),
HandledNodeError::Handler(err) => Some(err),
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use tokio::runtime::current_thread; use tokio::runtime::current_thread;
use tests::dummy_muxer::{DummyMuxer, DummyConnectionState}; use tests::dummy_muxer::{DummyMuxer, DummyConnectionState};
use tests::dummy_handler::{Handler, HandlerState, InEvent, OutEvent, TestHandledNode}; use tests::dummy_handler::{Handler, HandlerState, InEvent, OutEvent, TestHandledNode};
use std::marker::PhantomData; use std::{io, marker::PhantomData};
struct TestBuilder { struct TestBuilder {
muxer: DummyMuxer, muxer: DummyMuxer,
@ -389,6 +423,7 @@ mod tests {
type InEvent = (); type InEvent = ();
type OutEvent = (); type OutEvent = ();
type Substream = T; type Substream = T;
type Error = io::Error;
type OutboundOpenInfo = (); type OutboundOpenInfo = ();
fn inject_substream(&mut self, _: Self::Substream, _: NodeHandlerEndpoint<Self::OutboundOpenInfo>) { panic!() } fn inject_substream(&mut self, _: Self::Substream, _: NodeHandlerEndpoint<Self::OutboundOpenInfo>) { panic!() }
fn inject_inbound_closed(&mut self) { fn inject_inbound_closed(&mut self) {
@ -405,7 +440,7 @@ mod tests {
assert!(self.substream_attempt_cancelled); assert!(self.substream_attempt_cancelled);
self.shutdown_called = true; self.shutdown_called = true;
} }
fn poll(&mut self) -> Poll<Option<NodeHandlerEvent<(), ()>>, IoError> { fn poll(&mut self) -> Poll<Option<NodeHandlerEvent<(), ()>>, io::Error> {
if self.shutdown_called { if self.shutdown_called {
Ok(Async::Ready(None)) Ok(Async::Ready(None))
} else if !self.did_substream_attempt { } else if !self.did_substream_attempt {

View File

@ -22,7 +22,7 @@ use crate::{
PeerId, PeerId,
muxing::StreamMuxer, muxing::StreamMuxer,
nodes::{ nodes::{
handled_node::{HandledNode, NodeHandler}, handled_node::{HandledNode, HandledNodeError, NodeHandler},
node::Substream node::Substream
} }
}; };
@ -31,8 +31,8 @@ use futures::{prelude::*, stream, sync::mpsc};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
collections::hash_map::{Entry, OccupiedEntry}, collections::hash_map::{Entry, OccupiedEntry},
error,
fmt, fmt,
io::{self, Error as IoError},
mem mem
}; };
use tokio_executor; use tokio_executor;
@ -57,7 +57,7 @@ use void::Void;
// conditions in the user's code. See similar comments in the documentation of `NodeStream`. // conditions in the user's code. See similar comments in the documentation of `NodeStream`.
/// Implementation of `Stream` that handles a collection of nodes. /// Implementation of `Stream` that handles a collection of nodes.
pub struct HandledNodesTasks<TInEvent, TOutEvent, THandler> { pub struct HandledNodesTasks<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> {
/// A map between active tasks to an unbounded sender, used to control the task. Closing the sender interrupts /// A map between active tasks to an unbounded sender, used to control the task. Closing the sender interrupts
/// the task. It is possible that we receive messages from tasks that used to be in this list /// the task. It is possible that we receive messages from tasks that used to be in this list
/// but no longer are, in which case we should ignore them. /// but no longer are, in which case we should ignore them.
@ -71,12 +71,12 @@ pub struct HandledNodesTasks<TInEvent, TOutEvent, THandler> {
to_spawn: SmallVec<[Box<Future<Item = (), Error = ()> + Send>; 8]>, to_spawn: SmallVec<[Box<Future<Item = (), Error = ()> + Send>; 8]>,
/// Sender to emit events to the outside. Meant to be cloned and sent to tasks. /// Sender to emit events to the outside. Meant to be cloned and sent to tasks.
events_tx: mpsc::UnboundedSender<(InToExtMessage<TOutEvent, THandler>, TaskId)>, events_tx: mpsc::UnboundedSender<(InToExtMessage<TOutEvent, THandler, TReachErr, THandlerErr>, TaskId)>,
/// Receiver side for the events. /// Receiver side for the events.
events_rx: mpsc::UnboundedReceiver<(InToExtMessage<TOutEvent, THandler>, TaskId)>, events_rx: mpsc::UnboundedReceiver<(InToExtMessage<TOutEvent, THandler, TReachErr, THandlerErr>, TaskId)>,
} }
impl<TInEvent, TOutEvent, THandler> fmt::Debug for HandledNodesTasks<TInEvent, TOutEvent, THandler> { impl<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> fmt::Debug for HandledNodesTasks<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_list() f.debug_list()
.entries(self.tasks.keys().cloned()) .entries(self.tasks.keys().cloned())
@ -84,9 +84,44 @@ impl<TInEvent, TOutEvent, THandler> fmt::Debug for HandledNodesTasks<TInEvent, T
} }
} }
/// Error that can happen in a task.
#[derive(Debug)]
pub enum TaskClosedEvent<TReachErr, THandlerErr> {
/// An error happend while we were trying to reach the node.
Reach(TReachErr),
/// An error happened after the node has been reached.
Node(HandledNodeError<THandlerErr>),
}
impl<TReachErr, THandlerErr> fmt::Display for TaskClosedEvent<TReachErr, THandlerErr>
where
TReachErr: fmt::Display,
THandlerErr: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TaskClosedEvent::Reach(err) => write!(f, "{}", err),
TaskClosedEvent::Node(err) => write!(f, "{}", err),
}
}
}
impl<TReachErr, THandlerErr> error::Error for TaskClosedEvent<TReachErr, THandlerErr>
where
TReachErr: error::Error + 'static,
THandlerErr: error::Error + 'static
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
TaskClosedEvent::Reach(err) => Some(err),
TaskClosedEvent::Node(err) => Some(err),
}
}
}
/// Event that can happen on the `HandledNodesTasks`. /// Event that can happen on the `HandledNodesTasks`.
#[derive(Debug)] #[derive(Debug)]
pub enum HandledNodesEvent<TOutEvent, THandler> { pub enum HandledNodesEvent<TOutEvent, THandler, TReachErr, THandlerErr> {
/// A task has been closed. /// A task has been closed.
/// ///
/// This happens once the node handler closes or an error happens. /// This happens once the node handler closes or an error happens.
@ -95,7 +130,7 @@ pub enum HandledNodesEvent<TOutEvent, THandler> {
/// Identifier of the task that closed. /// Identifier of the task that closed.
id: TaskId, id: TaskId,
/// What happened. /// What happened.
result: Result<(), IoError>, result: Result<(), TaskClosedEvent<TReachErr, THandlerErr>>,
/// If the task closed before reaching the node, this contains the handler that was passed /// If the task closed before reaching the node, this contains the handler that was passed
/// to `add_reach_attempt`. /// to `add_reach_attempt`.
handler: Option<THandler>, handler: Option<THandler>,
@ -122,7 +157,7 @@ pub enum HandledNodesEvent<TOutEvent, THandler> {
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct TaskId(usize); pub struct TaskId(usize);
impl<TInEvent, TOutEvent, THandler> HandledNodesTasks<TInEvent, TOutEvent, THandler> { impl<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> HandledNodesTasks<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> {
/// Creates a new empty collection. /// Creates a new empty collection.
#[inline] #[inline]
pub fn new() -> Self { pub fn new() -> Self {
@ -143,9 +178,10 @@ impl<TInEvent, TOutEvent, THandler> HandledNodesTasks<TInEvent, TOutEvent, THand
/// events. /// events.
pub fn add_reach_attempt<TFut, TMuxer>(&mut self, future: TFut, handler: THandler) -> TaskId pub fn add_reach_attempt<TFut, TMuxer>(&mut self, future: TFut, handler: THandler) -> TaskId
where where
TFut: Future<Item = (PeerId, TMuxer)> + Send + 'static, TFut: Future<Item = (PeerId, TMuxer), Error = TReachErr> + Send + 'static,
TFut::Error: std::error::Error + Send + Sync + 'static, THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent, Error = THandlerErr> + Send + 'static,
THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, TReachErr: error::Error + Send + 'static,
THandlerErr: error::Error + Send + 'static,
TInEvent: Send + 'static, TInEvent: Send + 'static,
TOutEvent: Send + 'static, TOutEvent: Send + 'static,
THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be required? THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be required?
@ -203,7 +239,7 @@ impl<TInEvent, TOutEvent, THandler> HandledNodesTasks<TInEvent, TOutEvent, THand
} }
/// Provides an API similar to `Stream`, except that it cannot produce an error. /// Provides an API similar to `Stream`, except that it cannot produce an error.
pub fn poll(&mut self) -> Async<HandledNodesEvent<TOutEvent, THandler>> { pub fn poll(&mut self) -> Async<HandledNodesEvent<TOutEvent, THandler, TReachErr, THandlerErr>> {
for to_spawn in self.to_spawn.drain() { for to_spawn in self.to_spawn.drain() {
tokio_executor::spawn(to_spawn); tokio_executor::spawn(to_spawn);
} }
@ -289,8 +325,8 @@ impl<'a, TInEvent> fmt::Debug for Task<'a, TInEvent> {
} }
} }
impl<TInEvent, TOutEvent, THandler> Stream for HandledNodesTasks<TInEvent, TOutEvent, THandler> { impl<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> Stream for HandledNodesTasks<TInEvent, TOutEvent, THandler, TReachErr, THandlerErr> {
type Item = HandledNodesEvent<TOutEvent, THandler>; type Item = HandledNodesEvent<TOutEvent, THandler, TReachErr, THandlerErr>;
type Error = Void; // TODO: use ! once stable type Error = Void; // TODO: use ! once stable
#[inline] #[inline]
@ -301,24 +337,24 @@ impl<TInEvent, TOutEvent, THandler> Stream for HandledNodesTasks<TInEvent, TOutE
/// Message to transmit from a task to the public API. /// Message to transmit from a task to the public API.
#[derive(Debug)] #[derive(Debug)]
enum InToExtMessage<TOutEvent, THandler> { enum InToExtMessage<TOutEvent, THandler, TReachErr, THandlerErr> {
/// A connection to a node has succeeded. /// A connection to a node has succeeded.
NodeReached(PeerId), NodeReached(PeerId),
/// The task closed. /// The task closed.
TaskClosed(Result<(), IoError>, Option<THandler>), TaskClosed(Result<(), TaskClosedEvent<TReachErr, THandlerErr>>, Option<THandler>),
/// An event from the node. /// An event from the node.
NodeEvent(TOutEvent), NodeEvent(TOutEvent),
} }
/// Implementation of `Future` that handles a single node, and all the communications between /// Implementation of `Future` that handles a single node, and all the communications between
/// the various components of the `HandledNodesTasks`. /// the various components of the `HandledNodesTasks`.
struct NodeTask<TFut, TMuxer, THandler, TInEvent, TOutEvent> struct NodeTask<TFut, TMuxer, THandler, TInEvent, TOutEvent, TReachErr>
where where
TMuxer: StreamMuxer, TMuxer: StreamMuxer,
THandler: NodeHandler<Substream = Substream<TMuxer>>, THandler: NodeHandler<Substream = Substream<TMuxer>>,
{ {
/// Sender to transmit events to the outside. /// Sender to transmit events to the outside.
events_tx: mpsc::UnboundedSender<(InToExtMessage<TOutEvent, THandler>, TaskId)>, events_tx: mpsc::UnboundedSender<(InToExtMessage<TOutEvent, THandler, TReachErr, THandler::Error>, TaskId)>,
/// Receiving end for events sent from the main `HandledNodesTasks`. /// Receiving end for events sent from the main `HandledNodesTasks`.
in_events_rx: stream::Fuse<mpsc::UnboundedReceiver<TInEvent>>, in_events_rx: stream::Fuse<mpsc::UnboundedReceiver<TInEvent>>,
/// Inner state of the `NodeTask`. /// Inner state of the `NodeTask`.
@ -351,12 +387,11 @@ where
Poisoned, Poisoned,
} }
impl<TFut, TMuxer, THandler, TInEvent, TOutEvent> Future for impl<TFut, TMuxer, THandler, TInEvent, TOutEvent, TReachErr> Future for
NodeTask<TFut, TMuxer, THandler, TInEvent, TOutEvent> NodeTask<TFut, TMuxer, THandler, TInEvent, TOutEvent, TReachErr>
where where
TMuxer: StreamMuxer, TMuxer: StreamMuxer,
TFut: Future<Item = (PeerId, TMuxer)>, TFut: Future<Item = (PeerId, TMuxer), Error = TReachErr>,
TFut::Error: std::error::Error + Send + Sync + 'static,
THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent>, THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent>,
{ {
type Item = (); type Item = ();
@ -395,8 +430,7 @@ where
}, },
Err(err) => { Err(err) => {
// End the task // End the task
let ioerr = IoError::new(io::ErrorKind::Other, err); let event = InToExtMessage::TaskClosed(Err(TaskClosedEvent::Reach(err)), Some(handler));
let event = InToExtMessage::TaskClosed(Err(ioerr), Some(handler));
let _ = self.events_tx.unbounded_send((event, self.id)); let _ = self.events_tx.unbounded_send((event, self.id));
return Ok(Async::Ready(())); return Ok(Async::Ready(()));
} }
@ -442,7 +476,7 @@ where
return Ok(Async::Ready(())); // End the task. return Ok(Async::Ready(())); // End the task.
} }
Err(err) => { Err(err) => {
let event = InToExtMessage::TaskClosed(Err(err), None); let event = InToExtMessage::TaskClosed(Err(TaskClosedEvent::Node(err)), None);
let _ = self.events_tx.unbounded_send((event, self.id)); let _ = self.events_tx.unbounded_send((event, self.id));
return Ok(Async::Ready(())); // End the task. return Ok(Async::Ready(())); // End the task.
} }
@ -475,17 +509,18 @@ mod tests {
use PeerId; use PeerId;
type TestNodeTask = NodeTask< type TestNodeTask = NodeTask<
FutureResult<(PeerId, DummyMuxer), IoError>, FutureResult<(PeerId, DummyMuxer), io::Error>,
DummyMuxer, DummyMuxer,
Handler, Handler,
InEvent, InEvent,
OutEvent, OutEvent,
io::Error,
>; >;
struct NodeTaskTestBuilder { struct NodeTaskTestBuilder {
task_id: TaskId, task_id: TaskId,
inner_node: Option<TestHandledNode>, inner_node: Option<TestHandledNode>,
inner_fut: Option<FutureResult<(PeerId, DummyMuxer), IoError>>, inner_fut: Option<FutureResult<(PeerId, DummyMuxer), io::Error>>,
} }
impl NodeTaskTestBuilder { impl NodeTaskTestBuilder {
@ -500,7 +535,7 @@ mod tests {
} }
} }
fn with_inner_fut(&mut self, fut: FutureResult<(PeerId, DummyMuxer), IoError>) -> &mut Self{ fn with_inner_fut(&mut self, fut: FutureResult<(PeerId, DummyMuxer), io::Error>) -> &mut Self{
self.inner_fut = Some(fut); self.inner_fut = Some(fut);
self self
} }
@ -513,9 +548,9 @@ mod tests {
fn node_task(&mut self) -> ( fn node_task(&mut self) -> (
TestNodeTask, TestNodeTask,
UnboundedSender<InEvent>, UnboundedSender<InEvent>,
UnboundedReceiver<(InToExtMessage<OutEvent, Handler>, TaskId)>, UnboundedReceiver<(InToExtMessage<OutEvent, Handler, io::Error, io::Error>, TaskId)>,
) { ) {
let (events_from_node_task_tx, events_from_node_task_rx) = mpsc::unbounded::<(InToExtMessage<OutEvent, Handler>, TaskId)>(); let (events_from_node_task_tx, events_from_node_task_rx) = mpsc::unbounded::<(InToExtMessage<OutEvent, Handler, _, _>, TaskId)>();
let (events_to_node_task_tx, events_to_node_task_rx) = mpsc::unbounded::<InEvent>(); let (events_to_node_task_tx, events_to_node_task_rx) = mpsc::unbounded::<InEvent>();
let inner = if self.inner_node.is_some() { let inner = if self.inner_node.is_some() {
NodeTaskInner::Node(self.inner_node.take().unwrap()) NodeTaskInner::Node(self.inner_node.take().unwrap())
@ -536,7 +571,7 @@ mod tests {
} }
} }
type TestHandledNodesTasks = HandledNodesTasks<InEvent, OutEvent, Handler>; type TestHandledNodesTasks = HandledNodesTasks<InEvent, OutEvent, Handler, io::Error, io::Error>;
struct HandledNodeTaskTestBuilder { struct HandledNodeTaskTestBuilder {
muxer: DummyMuxer, muxer: DummyMuxer,
@ -578,7 +613,7 @@ mod tests {
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let mut task_ids = Vec::new(); let mut task_ids = Vec::new();
for _i in 0..self.task_count { for _i in 0..self.task_count {
let fut = future::ok::<_, Void>((peer_id.clone(), self.muxer.clone())); let fut = future::ok((peer_id.clone(), self.muxer.clone()));
task_ids.push( task_ids.push(
handled_nodes.add_reach_attempt(fut, self.handler.clone()) handled_nodes.add_reach_attempt(fut, self.handler.clone())
); );
@ -743,7 +778,7 @@ mod tests {
.handled_nodes_tasks(); .handled_nodes_tasks();
let mut rt = Runtime::new().unwrap(); let mut rt = Runtime::new().unwrap();
let mut events: (Option<HandledNodesEvent<_,_>>, TestHandledNodesTasks); let mut events: (Option<HandledNodesEvent<_, _, _, _>>, TestHandledNodesTasks);
// we're running on a single thread so events are sequential: first // we're running on a single thread so events are sequential: first
// we get a NodeReached, then a TaskClosed // we get a NodeReached, then a TaskClosed
for i in 0..5 { for i in 0..5 {

View File

@ -30,7 +30,10 @@ use crate::{
PeerMut as CollecPeerMut, PeerMut as CollecPeerMut,
ReachAttemptId ReachAttemptId
}, },
handled_node::NodeHandler, handled_node::{
HandledNodeError,
NodeHandler
},
node::Substream node::Substream
}, },
nodes::listeners::{ListenersEvent, ListenersStream}, nodes::listeners::{ListenersEvent, ListenersStream},
@ -39,14 +42,15 @@ use crate::{
use fnv::FnvHashMap; use fnv::FnvHashMap;
use futures::{prelude::*, future}; use futures::{prelude::*, future};
use std::{ use std::{
fmt,
collections::hash_map::{Entry, OccupiedEntry}, collections::hash_map::{Entry, OccupiedEntry},
error,
fmt,
io::{Error as IoError, ErrorKind as IoErrorKind} io::{Error as IoError, ErrorKind as IoErrorKind}
}; };
/// Implementation of `Stream` that handles the nodes. /// Implementation of `Stream` that handles the nodes.
#[derive(Debug)] #[derive(Debug)]
pub struct RawSwarm<TTrans, TInEvent, TOutEvent, THandler> pub struct RawSwarm<TTrans, TInEvent, TOutEvent, THandler, THandlerErr>
where where
TTrans: Transport, TTrans: Transport,
{ {
@ -54,7 +58,7 @@ where
listeners: ListenersStream<TTrans>, listeners: ListenersStream<TTrans>,
/// The nodes currently active. /// The nodes currently active.
active_nodes: CollectionStream<TInEvent, TOutEvent, THandler>, active_nodes: CollectionStream<TInEvent, TOutEvent, THandler, RawSwarmReachError, THandlerErr>,
/// The reach attempts of the swarm. /// The reach attempts of the swarm.
/// This needs to be a separate struct in order to handle multiple mutable borrows issues. /// This needs to be a separate struct in order to handle multiple mutable borrows issues.
@ -89,7 +93,7 @@ struct OutReachAttempt {
} }
/// Event that can happen on the `RawSwarm`. /// Event that can happen on the `RawSwarm`.
pub enum RawSwarmEvent<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> pub enum RawSwarmEvent<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a, THandlerErr: 'a>
where where
TTrans: Transport, TTrans: Transport,
{ {
@ -104,7 +108,7 @@ where
}, },
/// A new connection arrived on a listener. /// A new connection arrived on a listener.
IncomingConnection(IncomingConnectionEvent<'a, TTrans, TInEvent, TOutEvent, THandler>), IncomingConnection(IncomingConnectionEvent<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>),
/// A new connection was arriving on a listener, but an error happened when negotiating it. /// A new connection was arriving on a listener, but an error happened when negotiating it.
/// ///
@ -150,14 +154,14 @@ where
endpoint: ConnectedPoint, endpoint: ConnectedPoint,
}, },
/// The muxer of a node has produced an error. /// The handler of a node has produced an error.
NodeError { NodeError {
/// Identifier of the node. /// Identifier of the node.
peer_id: PeerId, peer_id: PeerId,
/// Endpoint we were connected to. /// Endpoint we were connected to.
endpoint: ConnectedPoint, endpoint: ConnectedPoint,
/// The error that happened. /// The error that happened.
error: IoError, error: HandledNodeError<THandlerErr>,
}, },
/// Failed to reach a peer that we were trying to dial. /// Failed to reach a peer that we were trying to dial.
@ -174,7 +178,7 @@ where
multiaddr: Multiaddr, multiaddr: Multiaddr,
/// The error that happened. /// The error that happened.
error: IoError, error: RawSwarmReachError,
}, },
/// Failed to reach a peer that we were trying to dial. /// Failed to reach a peer that we were trying to dial.
@ -198,10 +202,11 @@ where
}, },
} }
impl<'a, TTrans, TInEvent, TOutEvent, THandler> fmt::Debug for RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler> impl<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr> fmt::Debug for RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>
where where
TOutEvent: fmt::Debug, TOutEvent: fmt::Debug,
TTrans: Transport, TTrans: Transport,
THandlerErr: fmt::Debug,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self { match *self {
@ -274,9 +279,42 @@ where
} }
} }
/// Error that can happen when trying to reach a node.
#[derive(Debug)]
pub enum RawSwarmReachError {
/// Error in the transport layer.
// TODO: better error type
Transport(IoError),
/// We successfully reached the peer, but there was a mismatch between the expected id and the
/// actual id of the peer.
PeerIdMismatch {
/// The peer id that the node reports.
obtained: PeerId,
}
}
impl fmt::Display for RawSwarmReachError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RawSwarmReachError::Transport(err) => write!(f, "{}", err),
RawSwarmReachError::PeerIdMismatch { obtained } => {
write!(f, "Peer ID mismatch, obtained: {}", obtained.to_base58())
},
}
}
}
impl error::Error for RawSwarmReachError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
RawSwarmReachError::Transport(err) => Some(err),
RawSwarmReachError::PeerIdMismatch { .. } => None,
}
}
}
/// A new connection arrived on a listener. /// A new connection arrived on a listener.
pub struct IncomingConnectionEvent<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> pub struct IncomingConnectionEvent<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a, THandlerErr: 'a>
where TTrans: Transport where TTrans: Transport
{ {
/// The produced upgrade. /// The produced upgrade.
@ -286,17 +324,19 @@ where TTrans: Transport
/// Address used to send back data to the remote. /// Address used to send back data to the remote.
send_back_addr: Multiaddr, send_back_addr: Multiaddr,
/// Reference to the `active_nodes` field of the swarm. /// Reference to the `active_nodes` field of the swarm.
active_nodes: &'a mut CollectionStream<TInEvent, TOutEvent, THandler>, active_nodes: &'a mut CollectionStream<TInEvent, TOutEvent, THandler, RawSwarmReachError, THandlerErr>,
/// Reference to the `other_reach_attempts` field of the swarm. /// Reference to the `other_reach_attempts` field of the swarm.
other_reach_attempts: &'a mut Vec<(ReachAttemptId, ConnectedPoint)>, other_reach_attempts: &'a mut Vec<(ReachAttemptId, ConnectedPoint)>,
} }
impl<'a, TTrans, TInEvent, TOutEvent, TMuxer, THandler> IncomingConnectionEvent<'a, TTrans, TInEvent, TOutEvent, THandler> impl<'a, TTrans, TInEvent, TOutEvent, TMuxer, THandler, THandlerErr>
IncomingConnectionEvent<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>
where where
TTrans: Transport<Output = (PeerId, TMuxer)>, TTrans: Transport<Output = (PeerId, TMuxer)>,
TTrans::ListenerUpgrade: Send + 'static, TTrans::ListenerUpgrade: Send + 'static,
THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent, Error = THandlerErr> + Send + 'static,
THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary
THandlerErr: error::Error + Send + 'static,
TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer: StreamMuxer + Send + Sync + 'static,
TMuxer::OutboundSubstream: Send, TMuxer::OutboundSubstream: Send,
TMuxer::Substream: Send, TMuxer::Substream: Send,
@ -315,7 +355,7 @@ where
{ {
let connected_point = self.to_connected_point(); let connected_point = self.to_connected_point();
let handler = builder(&connected_point); let handler = builder(&connected_point);
let id = self.active_nodes.add_reach_attempt(self.upgrade, handler); let id = self.active_nodes.add_reach_attempt(self.upgrade.map_err(RawSwarmReachError::Transport), handler);
self.other_reach_attempts.push(( self.other_reach_attempts.push((
id, id,
connected_point, connected_point,
@ -323,7 +363,7 @@ where
} }
} }
impl<'a, TTrans, TInEvent, TOutEvent, THandler> IncomingConnectionEvent<'a, TTrans, TInEvent, TOutEvent, THandler> impl<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr> IncomingConnectionEvent<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>
where TTrans: Transport where TTrans: Transport
{ {
/// Address of the listener that received the connection. /// Address of the listener that received the connection.
@ -409,13 +449,14 @@ impl ConnectedPoint {
} }
} }
impl<TTrans, TInEvent, TOutEvent, TMuxer, THandler> impl<TTrans, TInEvent, TOutEvent, TMuxer, THandler, THandlerErr>
RawSwarm<TTrans, TInEvent, TOutEvent, THandler> RawSwarm<TTrans, TInEvent, TOutEvent, THandler, THandlerErr>
where where
TTrans: Transport + Clone, TTrans: Transport + Clone,
TMuxer: StreamMuxer, TMuxer: StreamMuxer,
THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent, Error = THandlerErr> + Send + 'static,
THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary
THandlerErr: error::Error + Send + 'static,
{ {
/// Creates a new node events stream. /// Creates a new node events stream.
#[inline] #[inline]
@ -497,7 +538,7 @@ where
}; };
let connected_point = ConnectedPoint::Dialer { address: addr }; let connected_point = ConnectedPoint::Dialer { address: addr };
let reach_id = self.active_nodes.add_reach_attempt(future, handler); let reach_id = self.active_nodes.add_reach_attempt(future.map_err(RawSwarmReachError::Transport), handler);
self.reach_attempts.other_reach_attempts.push((reach_id, connected_point)); self.reach_attempts.other_reach_attempts.push((reach_id, connected_point));
Ok(()) Ok(())
} }
@ -527,7 +568,7 @@ where
/// Grants access to a struct that represents a peer. /// Grants access to a struct that represents a peer.
#[inline] #[inline]
pub fn peer(&mut self, peer_id: PeerId) -> Peer<TTrans, TInEvent, TOutEvent, THandler> { pub fn peer(&mut self, peer_id: PeerId) -> Peer<TTrans, TInEvent, TOutEvent, THandler, THandlerErr> {
// TODO: we do `peer_mut(...).is_some()` followed with `peer_mut(...).unwrap()`, otherwise // TODO: we do `peer_mut(...).is_some()` followed with `peer_mut(...).unwrap()`, otherwise
// the borrow checker yells at us. // the borrow checker yells at us.
@ -579,20 +620,21 @@ where
let reach_id = match self.transport().clone().dial(first.clone()) { let reach_id = match self.transport().clone().dial(first.clone()) {
Ok(fut) => { Ok(fut) => {
let expected_peer_id = peer_id.clone(); let expected_peer_id = peer_id.clone();
let fut = fut.and_then(move |(actual_peer_id, muxer)| { let fut = fut
.map_err(RawSwarmReachError::Transport)
.and_then(move |(actual_peer_id, muxer)| {
if actual_peer_id == expected_peer_id { if actual_peer_id == expected_peer_id {
Ok((actual_peer_id, muxer)) Ok((actual_peer_id, muxer))
} else { } else {
let msg = format!("public key mismatch; expected = {:?}; obtained = {:?}", Err(RawSwarmReachError::PeerIdMismatch { obtained: actual_peer_id })
expected_peer_id, actual_peer_id);
Err(IoError::new(IoErrorKind::Other, msg))
} }
}); });
self.active_nodes.add_reach_attempt(fut, handler) self.active_nodes.add_reach_attempt(fut, handler)
}, },
Err((_, addr)) => { Err((_, addr)) => {
// TODO: better error reporting
let msg = format!("unsupported multiaddr {}", addr); let msg = format!("unsupported multiaddr {}", addr);
let fut = future::err(IoError::new(IoErrorKind::Other, msg)); let fut = future::err(RawSwarmReachError::Transport(IoError::new(IoErrorKind::Other, msg)));
self.active_nodes.add_reach_attempt(fut, handler) self.active_nodes.add_reach_attempt(fut, handler)
}, },
}; };
@ -610,7 +652,7 @@ where
} }
/// Provides an API similar to `Stream`, except that it cannot error. /// Provides an API similar to `Stream`, except that it cannot error.
pub fn poll(&mut self) -> Async<RawSwarmEvent<TTrans, TInEvent, TOutEvent, THandler>> pub fn poll(&mut self) -> Async<RawSwarmEvent<TTrans, TInEvent, TOutEvent, THandler, THandlerErr>>
where where
TTrans: Transport<Output = (PeerId, TMuxer)>, TTrans: Transport<Output = (PeerId, TMuxer)>,
TTrans::Dial: Send + 'static, TTrans::Dial: Send + 'static,
@ -620,8 +662,9 @@ where
TMuxer::Substream: Send, TMuxer::Substream: Send,
TInEvent: Send + 'static, TInEvent: Send + 'static,
TOutEvent: Send + 'static, TOutEvent: Send + 'static,
THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent, Error = THandlerErr> + Send + 'static,
THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary
THandlerErr: error::Error + Send + 'static,
{ {
// Start by polling the listeners for events. // Start by polling the listeners for events.
match self.listeners.poll() { match self.listeners.poll() {
@ -737,10 +780,10 @@ impl<THandler> Default for ActionItem<THandler> {
/// ///
/// > **Note**: The event **must** have been produced by the collection of nodes, otherwise /// > **Note**: The event **must** have been produced by the collection of nodes, otherwise
/// > panics will likely happen. /// > panics will likely happen.
fn handle_node_reached<'a, TTrans, TMuxer, TInEvent, TOutEvent, THandler>( fn handle_node_reached<'a, TTrans, TMuxer, TInEvent, TOutEvent, THandler, THandlerErr>(
reach_attempts: &mut ReachAttempts, reach_attempts: &mut ReachAttempts,
event: CollectionReachEvent<TInEvent, TOutEvent, THandler> event: CollectionReachEvent<TInEvent, TOutEvent, THandler, RawSwarmReachError, THandlerErr>
) -> (ActionItem<THandler>, RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler>) ) -> (ActionItem<THandler>, RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>)
where where
TTrans: Transport<Output = (PeerId, TMuxer)> + Clone, TTrans: Transport<Output = (PeerId, TMuxer)> + Clone,
TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer: StreamMuxer + Send + Sync + 'static,
@ -866,12 +909,12 @@ fn has_dial_prio(local: &PeerId, other: &PeerId) -> bool {
/// ///
/// > **Note**: The event **must** have been produced by the collection of nodes, otherwise /// > **Note**: The event **must** have been produced by the collection of nodes, otherwise
/// > panics will likely happen. /// > panics will likely happen.
fn handle_reach_error<'a, TTrans, TInEvent, TOutEvent, THandler>( fn handle_reach_error<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>(
reach_attempts: &mut ReachAttempts, reach_attempts: &mut ReachAttempts,
reach_id: ReachAttemptId, reach_id: ReachAttemptId,
error: IoError, error: RawSwarmReachError,
handler: THandler, handler: THandler,
) -> (ActionItem<THandler>, RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler>) ) -> (ActionItem<THandler>, RawSwarmEvent<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>)
where TTrans: Transport where TTrans: Transport
{ {
// Search for the attempt in `out_reach_attempts`. // Search for the attempt in `out_reach_attempts`.
@ -914,6 +957,10 @@ where TTrans: Transport
.position(|i| i.0 == reach_id) .position(|i| i.0 == reach_id)
{ {
let (_, endpoint) = reach_attempts.other_reach_attempts.swap_remove(in_pos); let (_, endpoint) = reach_attempts.other_reach_attempts.swap_remove(in_pos);
let error = match error {
RawSwarmReachError::Transport(err) => err,
RawSwarmReachError::PeerIdMismatch { .. } => unreachable!(), // TODO: prove
};
match endpoint { match endpoint {
ConnectedPoint::Dialer { address } => { ConnectedPoint::Dialer { address } => {
return (Default::default(), RawSwarmEvent::UnknownPeerDialError { return (Default::default(), RawSwarmEvent::UnknownPeerDialError {
@ -939,7 +986,7 @@ where TTrans: Transport
} }
/// State of a peer in the system. /// State of a peer in the system.
pub enum Peer<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> pub enum Peer<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a, THandlerErr: 'a>
where where
TTrans: Transport, TTrans: Transport,
{ {
@ -947,16 +994,16 @@ where
Connected(PeerConnected<'a, TInEvent>), Connected(PeerConnected<'a, TInEvent>),
/// We are currently attempting to connect to this peer. /// We are currently attempting to connect to this peer.
PendingConnect(PeerPendingConnect<'a, TInEvent, TOutEvent, THandler>), PendingConnect(PeerPendingConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr>),
/// We are not connected to this peer at all. /// We are not connected to this peer at all.
/// ///
/// > **Note**: It is however possible that a pending incoming connection is being negotiated /// > **Note**: It is however possible that a pending incoming connection is being negotiated
/// > and will connect to this peer, but we don't know it yet. /// > and will connect to this peer, but we don't know it yet.
NotConnected(PeerNotConnected<'a, TTrans, TInEvent, TOutEvent, THandler>), NotConnected(PeerNotConnected<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>),
} }
impl<'a, TTrans, TInEvent, TOutEvent, THandler> fmt::Debug for Peer<'a, TTrans, TInEvent, TOutEvent, THandler> impl<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr> fmt::Debug for Peer<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>
where where
TTrans: Transport, TTrans: Transport,
{ {
@ -983,8 +1030,8 @@ where
} }
// TODO: add other similar methods that wrap to the ones of `PeerNotConnected` // TODO: add other similar methods that wrap to the ones of `PeerNotConnected`
impl<'a, TTrans, TMuxer, TInEvent, TOutEvent, THandler> impl<'a, TTrans, TMuxer, TInEvent, TOutEvent, THandler, THandlerErr>
Peer<'a, TTrans, TInEvent, TOutEvent, THandler> Peer<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>
where where
TTrans: Transport<Output = (PeerId, TMuxer)> + Clone, TTrans: Transport<Output = (PeerId, TMuxer)> + Clone,
TTrans::Dial: Send + 'static, TTrans::Dial: Send + 'static,
@ -993,8 +1040,9 @@ where
TMuxer::Substream: Send, TMuxer::Substream: Send,
TInEvent: Send + 'static, TInEvent: Send + 'static,
TOutEvent: Send + 'static, TOutEvent: Send + 'static,
THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent, Error = THandlerErr> + Send + 'static,
THandler::OutboundOpenInfo: Send + 'static, THandler::OutboundOpenInfo: Send + 'static,
THandlerErr: error::Error + Send + 'static,
{ {
/// If we are connected, returns the `PeerConnected`. /// If we are connected, returns the `PeerConnected`.
#[inline] #[inline]
@ -1007,7 +1055,7 @@ where
/// If a connection is pending, returns the `PeerPendingConnect`. /// If a connection is pending, returns the `PeerPendingConnect`.
#[inline] #[inline]
pub fn as_pending_connect(self) -> Option<PeerPendingConnect<'a, TInEvent, TOutEvent, THandler>> { pub fn as_pending_connect(self) -> Option<PeerPendingConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr>> {
match self { match self {
Peer::PendingConnect(peer) => Some(peer), Peer::PendingConnect(peer) => Some(peer),
_ => None, _ => None,
@ -1016,7 +1064,7 @@ where
/// If we are not connected, returns the `PeerNotConnected`. /// If we are not connected, returns the `PeerNotConnected`.
#[inline] #[inline]
pub fn as_not_connected(self) -> Option<PeerNotConnected<'a, TTrans, TInEvent, TOutEvent, THandler>> { pub fn as_not_connected(self) -> Option<PeerNotConnected<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>> {
match self { match self {
Peer::NotConnected(peer) => Some(peer), Peer::NotConnected(peer) => Some(peer),
_ => None, _ => None,
@ -1033,7 +1081,7 @@ where
/// > node. /// > node.
#[inline] #[inline]
pub fn or_connect(self, addr: Multiaddr, handler: THandler) pub fn or_connect(self, addr: Multiaddr, handler: THandler)
-> Result<PeerPotentialConnect<'a, TInEvent, TOutEvent, THandler>, Self> -> Result<PeerPotentialConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr>, Self>
{ {
self.or_connect_with(move |_| addr, handler) self.or_connect_with(move |_| addr, handler)
} }
@ -1049,7 +1097,7 @@ where
/// > node. /// > node.
#[inline] #[inline]
pub fn or_connect_with<TFn>(self, addr: TFn, handler: THandler) pub fn or_connect_with<TFn>(self, addr: TFn, handler: THandler)
-> Result<PeerPotentialConnect<'a, TInEvent, TOutEvent, THandler>, Self> -> Result<PeerPotentialConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr>, Self>
where where
TFn: FnOnce(&PeerId) -> Multiaddr, TFn: FnOnce(&PeerId) -> Multiaddr,
{ {
@ -1068,15 +1116,15 @@ where
} }
/// Peer we are potentially going to connect to. /// Peer we are potentially going to connect to.
pub enum PeerPotentialConnect<'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> { pub enum PeerPotentialConnect<'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a, THandlerErr: 'a> {
/// We are connected to this peer. /// We are connected to this peer.
Connected(PeerConnected<'a, TInEvent>), Connected(PeerConnected<'a, TInEvent>),
/// We are currently attempting to connect to this peer. /// We are currently attempting to connect to this peer.
PendingConnect(PeerPendingConnect<'a, TInEvent, TOutEvent, THandler>), PendingConnect(PeerPendingConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr>),
} }
impl<'a, TInEvent, TOutEvent, THandler> PeerPotentialConnect<'a, TInEvent, TOutEvent, THandler> { impl<'a, TInEvent, TOutEvent, THandler, THandlerErr> PeerPotentialConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr> {
/// Closes the connection or the connection attempt. /// Closes the connection or the connection attempt.
/// ///
/// If the connection was active, returns the list of outbound substream openings that were /// If the connection was active, returns the list of outbound substream openings that were
@ -1101,7 +1149,7 @@ impl<'a, TInEvent, TOutEvent, THandler> PeerPotentialConnect<'a, TInEvent, TOutE
/// If a connection is pending, returns the `PeerPendingConnect`. /// If a connection is pending, returns the `PeerPendingConnect`.
#[inline] #[inline]
pub fn as_pending_connect(self) -> Option<PeerPendingConnect<'a, TInEvent, TOutEvent, THandler>> { pub fn as_pending_connect(self) -> Option<PeerPendingConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr>> {
match self { match self {
PeerPotentialConnect::PendingConnect(peer) => Some(peer), PeerPotentialConnect::PendingConnect(peer) => Some(peer),
_ => None, _ => None,
@ -1147,12 +1195,12 @@ impl<'a, TInEvent> PeerConnected<'a, TInEvent> {
/// Access to a peer we are attempting to connect to. /// Access to a peer we are attempting to connect to.
#[derive(Debug)] #[derive(Debug)]
pub struct PeerPendingConnect<'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> { pub struct PeerPendingConnect<'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a, THandlerErr: 'a> {
attempt: OccupiedEntry<'a, PeerId, OutReachAttempt>, attempt: OccupiedEntry<'a, PeerId, OutReachAttempt>,
active_nodes: &'a mut CollectionStream<TInEvent, TOutEvent, THandler>, active_nodes: &'a mut CollectionStream<TInEvent, TOutEvent, THandler, RawSwarmReachError, THandlerErr>,
} }
impl<'a, TInEvent, TOutEvent, THandler> PeerPendingConnect<'a, TInEvent, TOutEvent, THandler> { impl<'a, TInEvent, TOutEvent, THandler, THandlerErr> PeerPendingConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr> {
/// Interrupt this connection attempt. /// Interrupt this connection attempt.
// TODO: consider returning a PeerNotConnected; however that is really pain in terms of // TODO: consider returning a PeerNotConnected; however that is really pain in terms of
// borrows // borrows
@ -1195,24 +1243,25 @@ impl<'a, TInEvent, TOutEvent, THandler> PeerPendingConnect<'a, TInEvent, TOutEve
/// Access to a peer we're not connected to. /// Access to a peer we're not connected to.
#[derive(Debug)] #[derive(Debug)]
pub struct PeerNotConnected<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a> pub struct PeerNotConnected<'a, TTrans: 'a, TInEvent: 'a, TOutEvent: 'a, THandler: 'a, THandlerErr: 'a>
where where
TTrans: Transport, TTrans: Transport,
{ {
peer_id: PeerId, peer_id: PeerId,
nodes: &'a mut RawSwarm<TTrans, TInEvent, TOutEvent, THandler>, nodes: &'a mut RawSwarm<TTrans, TInEvent, TOutEvent, THandler, THandlerErr>,
} }
impl<'a, TTrans, TInEvent, TOutEvent, TMuxer, THandler> impl<'a, TTrans, TInEvent, TOutEvent, TMuxer, THandler, THandlerErr>
PeerNotConnected<'a, TTrans, TInEvent, TOutEvent, THandler> PeerNotConnected<'a, TTrans, TInEvent, TOutEvent, THandler, THandlerErr>
where where
TTrans: Transport<Output = (PeerId, TMuxer)> + Clone, TTrans: Transport<Output = (PeerId, TMuxer)> + Clone,
TTrans::Dial: Send + 'static, TTrans::Dial: Send + 'static,
TMuxer: StreamMuxer + Send + Sync + 'static, TMuxer: StreamMuxer + Send + Sync + 'static,
TMuxer::OutboundSubstream: Send, TMuxer::OutboundSubstream: Send,
TMuxer::Substream: Send, TMuxer::Substream: Send,
THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static, THandler: NodeHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent, Error = THandlerErr> + Send + 'static,
THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary THandler::OutboundOpenInfo: Send + 'static, // TODO: shouldn't be necessary
THandlerErr: error::Error + Send + 'static,
TInEvent: Send + 'static, TInEvent: Send + 'static,
TOutEvent: Send + 'static, TOutEvent: Send + 'static,
{ {
@ -1221,7 +1270,7 @@ where
/// If we reach a peer but the `PeerId` doesn't correspond to the one we're expecting, then /// If we reach a peer but the `PeerId` doesn't correspond to the one we're expecting, then
/// the whole connection is immediately closed. /// the whole connection is immediately closed.
#[inline] #[inline]
pub fn connect(self, addr: Multiaddr, handler: THandler) -> Result<PeerPendingConnect<'a, TInEvent, TOutEvent, THandler>, Self> { pub fn connect(self, addr: Multiaddr, handler: THandler) -> Result<PeerPendingConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr>, Self> {
self.connect_inner(handler, addr, Vec::new()) self.connect_inner(handler, addr, Vec::new())
} }
@ -1235,7 +1284,7 @@ where
/// the whole connection is immediately closed. /// the whole connection is immediately closed.
#[inline] #[inline]
pub fn connect_iter<TIter>(self, addrs: TIter, handler: THandler) pub fn connect_iter<TIter>(self, addrs: TIter, handler: THandler)
-> Result<PeerPendingConnect<'a, TInEvent, TOutEvent, THandler>, Self> -> Result<PeerPendingConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr>, Self>
where where
TIter: IntoIterator<Item = Multiaddr>, TIter: IntoIterator<Item = Multiaddr>,
{ {
@ -1250,7 +1299,7 @@ where
/// Inner implementation of `connect`. /// Inner implementation of `connect`.
fn connect_inner(self, handler: THandler, first: Multiaddr, rest: Vec<Multiaddr>) fn connect_inner(self, handler: THandler, first: Multiaddr, rest: Vec<Multiaddr>)
-> Result<PeerPendingConnect<'a, TInEvent, TOutEvent, THandler>, Self> -> Result<PeerPendingConnect<'a, TInEvent, TOutEvent, THandler, THandlerErr>, Self>
{ {
self.nodes.start_dial_out(self.peer_id.clone(), handler, first, rest); self.nodes.start_dial_out(self.peer_id.clone(), handler, first, rest);
Ok(PeerPendingConnect { Ok(PeerPendingConnect {
@ -1281,13 +1330,13 @@ mod tests {
fn query_transport() { fn query_transport() {
let transport = DummyTransport::new(); let transport = DummyTransport::new();
let transport2 = transport.clone(); let transport2 = transport.clone();
let raw_swarm = RawSwarm::<_, _, _, Handler>::new(transport, PeerId::random()); let raw_swarm = RawSwarm::<_, _, _, Handler, _>::new(transport, PeerId::random());
assert_eq!(raw_swarm.transport(), &transport2); assert_eq!(raw_swarm.transport(), &transport2);
} }
#[test] #[test]
fn starts_listening() { fn starts_listening() {
let mut raw_swarm = RawSwarm::<_, _, _, Handler>::new(DummyTransport::new(), PeerId::random()); let mut raw_swarm = RawSwarm::<_, _, _, Handler, _>::new(DummyTransport::new(), PeerId::random());
let addr = "/ip4/127.0.0.1/tcp/1234".parse::<Multiaddr>().expect("bad multiaddr"); let addr = "/ip4/127.0.0.1/tcp/1234".parse::<Multiaddr>().expect("bad multiaddr");
let addr2 = addr.clone(); let addr2 = addr.clone();
assert!(raw_swarm.listen_on(addr).is_ok()); assert!(raw_swarm.listen_on(addr).is_ok());
@ -1300,7 +1349,7 @@ mod tests {
fn nat_traversal_transforms_the_observed_address_according_to_the_transport_used() { fn nat_traversal_transforms_the_observed_address_according_to_the_transport_used() {
// the DummyTransport nat_traversal increments the port number by one for Ip4 addresses // the DummyTransport nat_traversal increments the port number by one for Ip4 addresses
let transport = DummyTransport::new(); let transport = DummyTransport::new();
let mut raw_swarm = RawSwarm::<_, _, _, Handler>::new(transport, PeerId::random()); let mut raw_swarm = RawSwarm::<_, _, _, Handler, _>::new(transport, PeerId::random());
let addr1 = "/ip4/127.0.0.1/tcp/1234".parse::<Multiaddr>().expect("bad multiaddr"); let addr1 = "/ip4/127.0.0.1/tcp/1234".parse::<Multiaddr>().expect("bad multiaddr");
// An unrelated outside address is returned as-is, no transform // An unrelated outside address is returned as-is, no transform
let outside_addr1 = "/memory".parse::<Multiaddr>().expect("bad multiaddr"); let outside_addr1 = "/memory".parse::<Multiaddr>().expect("bad multiaddr");
@ -1328,7 +1377,7 @@ mod tests {
#[test] #[test]
fn successful_dial_reaches_a_node() { fn successful_dial_reaches_a_node() {
let mut swarm = RawSwarm::<_, _, _, Handler>::new(DummyTransport::new(), PeerId::random()); let mut swarm = RawSwarm::<_, _, _, Handler, _>::new(DummyTransport::new(), PeerId::random());
let addr = "/ip4/127.0.0.1/tcp/1234".parse::<Multiaddr>().expect("bad multiaddr"); let addr = "/ip4/127.0.0.1/tcp/1234".parse::<Multiaddr>().expect("bad multiaddr");
let dial_res = swarm.dial(addr, Handler::default()); let dial_res = swarm.dial(addr, Handler::default());
assert!(dial_res.is_ok()); assert!(dial_res.is_ok());
@ -1366,7 +1415,7 @@ mod tests {
// Set up listener to see an incoming connection // Set up listener to see an incoming connection
transport.set_initial_listener_state(ListenerState::Ok(Async::Ready(Some((peer_id, muxer))))); transport.set_initial_listener_state(ListenerState::Ok(Async::Ready(Some((peer_id, muxer)))));
let mut swarm = RawSwarm::<_, _, _, Handler>::new(transport, PeerId::random()); let mut swarm = RawSwarm::<_, _, _, Handler, _>::new(transport, PeerId::random());
swarm.listen_on("/memory".parse().unwrap()).unwrap(); swarm.listen_on("/memory".parse().unwrap()).unwrap();
// no incoming yet // no incoming yet
@ -1391,7 +1440,7 @@ mod tests {
#[test] #[test]
fn broadcasted_events_reach_active_nodes() { fn broadcasted_events_reach_active_nodes() {
let mut swarm = RawSwarm::<_, _, _, Handler>::new(DummyTransport::new(), PeerId::random()); let mut swarm = RawSwarm::<_, _, _, Handler, _>::new(DummyTransport::new(), PeerId::random());
let mut muxer = DummyMuxer::new(); let mut muxer = DummyMuxer::new();
muxer.set_inbound_connection_state(DummyConnectionState::Pending); muxer.set_inbound_connection_state(DummyConnectionState::Pending);
muxer.set_outbound_connection_state(DummyConnectionState::Opened); muxer.set_outbound_connection_state(DummyConnectionState::Opened);
@ -1438,7 +1487,7 @@ mod tests {
#[test] #[test]
fn querying_for_pending_peer() { fn querying_for_pending_peer() {
let mut swarm = RawSwarm::<_, _, _, Handler>::new(DummyTransport::new(), PeerId::random()); let mut swarm = RawSwarm::<_, _, _, Handler, _>::new(DummyTransport::new(), PeerId::random());
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let peer = swarm.peer(peer_id.clone()); let peer = swarm.peer(peer_id.clone());
assert_matches!(peer, Peer::NotConnected(PeerNotConnected{ .. })); assert_matches!(peer, Peer::NotConnected(PeerNotConnected{ .. }));
@ -1450,7 +1499,7 @@ mod tests {
#[test] #[test]
fn querying_for_unknown_peer() { fn querying_for_unknown_peer() {
let mut swarm = RawSwarm::<_, _, _, Handler>::new(DummyTransport::new(), PeerId::random()); let mut swarm = RawSwarm::<_, _, _, Handler, _>::new(DummyTransport::new(), PeerId::random());
let peer_id = PeerId::random(); let peer_id = PeerId::random();
let peer = swarm.peer(peer_id.clone()); let peer = swarm.peer(peer_id.clone());
assert_matches!(peer, Peer::NotConnected( PeerNotConnected { nodes: _, peer_id: node_peer_id }) => { assert_matches!(peer, Peer::NotConnected( PeerNotConnected { nodes: _, peer_id: node_peer_id }) => {
@ -1460,7 +1509,7 @@ mod tests {
#[test] #[test]
fn querying_for_connected_peer() { fn querying_for_connected_peer() {
let mut swarm = RawSwarm::<_, _, _, Handler>::new(DummyTransport::new(), PeerId::random()); let mut swarm = RawSwarm::<_, _, _, Handler, _>::new(DummyTransport::new(), PeerId::random());
// Dial a node // Dial a node
let addr = "/ip4/127.0.0.1/tcp/1234".parse().expect("bad multiaddr"); let addr = "/ip4/127.0.0.1/tcp/1234".parse().expect("bad multiaddr");
@ -1494,7 +1543,7 @@ mod tests {
// Set up listener to be closed // Set up listener to be closed
transport.set_initial_listener_state(ListenerState::Ok(Async::Ready(None))); transport.set_initial_listener_state(ListenerState::Ok(Async::Ready(None)));
let mut swarm = RawSwarm::<_, _, _, Handler>::new(transport, PeerId::random()); let mut swarm = RawSwarm::<_, _, _, Handler, _>::new(transport, PeerId::random());
swarm.listen_on("/memory".parse().unwrap()).unwrap(); swarm.listen_on("/memory".parse().unwrap()).unwrap();
let mut rt = Runtime::new().unwrap(); let mut rt = Runtime::new().unwrap();
@ -1513,7 +1562,7 @@ mod tests {
fn unknown_peer_that_is_unreachable_yields_unknown_peer_dial_error() { fn unknown_peer_that_is_unreachable_yields_unknown_peer_dial_error() {
let mut transport = DummyTransport::new(); let mut transport = DummyTransport::new();
transport.make_dial_fail(); transport.make_dial_fail();
let mut swarm = RawSwarm::<_, _, _, Handler>::new(transport, PeerId::random()); let mut swarm = RawSwarm::<_, _, _, Handler, _>::new(transport, PeerId::random());
let addr = "/memory".parse::<Multiaddr>().expect("bad multiaddr"); let addr = "/memory".parse::<Multiaddr>().expect("bad multiaddr");
let handler = Handler::default(); let handler = Handler::default();
let dial_result = swarm.dial(addr, handler); let dial_result = swarm.dial(addr, handler);
@ -1544,7 +1593,7 @@ mod tests {
let peer_id = PeerId::random(); let peer_id = PeerId::random();
transport.set_next_peer_id(&peer_id); transport.set_next_peer_id(&peer_id);
transport.make_dial_fail(); transport.make_dial_fail();
let swarm = Arc::new(Mutex::new(RawSwarm::<_, _, _, Handler>::new(transport, PeerId::random()))); let swarm = Arc::new(Mutex::new(RawSwarm::<_, _, _, Handler, _>::new(transport, PeerId::random())));
{ {
let swarm1 = swarm.clone(); let swarm1 = swarm.clone();
@ -1584,7 +1633,7 @@ mod tests {
let mut transport = DummyTransport::new(); let mut transport = DummyTransport::new();
let peer_id = PeerId::random(); let peer_id = PeerId::random();
transport.set_next_peer_id(&peer_id); transport.set_next_peer_id(&peer_id);
let swarm = Arc::new(Mutex::new(RawSwarm::<_, _, _, Handler>::new(transport, PeerId::random()))); let swarm = Arc::new(Mutex::new(RawSwarm::<_, _, _, Handler, _>::new(transport, PeerId::random())));
{ {
// Set up an outgoing connection with a PeerId we know // Set up an outgoing connection with a PeerId we know
@ -1638,7 +1687,7 @@ mod tests {
let mut transport = DummyTransport::new(); let mut transport = DummyTransport::new();
let peer_id = PeerId::random(); let peer_id = PeerId::random();
transport.set_next_peer_id(&peer_id); transport.set_next_peer_id(&peer_id);
let swarm = Arc::new(Mutex::new(RawSwarm::<_, _, _, Handler>::new(transport, PeerId::random()))); let swarm = Arc::new(Mutex::new(RawSwarm::<_, _, _, Handler, _>::new(transport, PeerId::random())));
{ {
// Set up an outgoing connection with a PeerId we know // Set up an outgoing connection with a PeerId we know

View File

@ -123,6 +123,7 @@ where
{ {
type InEvent = TProtoHandler::InEvent; type InEvent = TProtoHandler::InEvent;
type OutEvent = TProtoHandler::OutEvent; type OutEvent = TProtoHandler::OutEvent;
type Error = io::Error; // TODO: better error type
type Substream = TProtoHandler::Substream; type Substream = TProtoHandler::Substream;
// The first element of the tuple is the unique upgrade identifier // The first element of the tuple is the unique upgrade identifier
// (see `unique_dial_upgrade_id`). // (see `unique_dial_upgrade_id`).

View File

@ -45,6 +45,7 @@ where TTransport: Transport,
<<TBehaviour as NetworkBehaviour<TTopology>>::ProtocolsHandler as ProtocolsHandler>::InEvent, <<TBehaviour as NetworkBehaviour<TTopology>>::ProtocolsHandler as ProtocolsHandler>::InEvent,
<<TBehaviour as NetworkBehaviour<TTopology>>::ProtocolsHandler as ProtocolsHandler>::OutEvent, <<TBehaviour as NetworkBehaviour<TTopology>>::ProtocolsHandler as ProtocolsHandler>::OutEvent,
NodeHandlerWrapper<TBehaviour::ProtocolsHandler>, NodeHandlerWrapper<TBehaviour::ProtocolsHandler>,
io::Error,
>, >,
/// Handles which nodes to connect to and how to handle the events sent back by the protocol /// Handles which nodes to connect to and how to handle the events sent back by the protocol

View File

@ -84,6 +84,7 @@ pub(crate) type TestHandledNode = HandledNode<DummyMuxer, Handler>;
impl NodeHandler for Handler { impl NodeHandler for Handler {
type InEvent = InEvent; type InEvent = InEvent;
type OutEvent = OutEvent; type OutEvent = OutEvent;
type Error = IoError;
type OutboundOpenInfo = usize; type OutboundOpenInfo = usize;
type Substream = SubstreamRef<Arc<DummyMuxer>>; type Substream = SubstreamRef<Arc<DummyMuxer>>;
fn inject_substream( fn inject_substream(