use crate::{
Multiaddr,
Transport,
StreamMuxer,
connection::{
Connected,
ConnectedPoint,
ConnectionHandler,
ConnectionInfo,
Connection,
ConnectionId,
ConnectionLimit,
EstablishedConnection,
EstablishedConnectionIter,
IntoConnectionHandler,
PendingConnection,
Substream,
},
};
use std::{
collections::hash_map,
error,
fmt,
hash::Hash,
};
use super::{Network, DialingOpts};
pub enum Peer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>
{
Connected(ConnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>),
Dialing(DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>),
Disconnected(DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>),
Local,
}
impl<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> fmt::Debug for
Peer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>,
TConnInfo: fmt::Debug + ConnectionInfo<PeerId = TPeerId>,
TPeerId: fmt::Debug + Eq + Hash,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match *self {
Peer::Connected(ConnectedPeer { ref peer_id, .. }) => {
f.debug_struct("Connected")
.field("peer_id", peer_id)
.finish()
}
Peer::Dialing(DialingPeer { ref peer_id, .. } ) => {
f.debug_struct("DialingPeer")
.field("peer_id", peer_id)
.finish()
}
Peer::Disconnected(DisconnectedPeer { ref peer_id, .. }) => {
f.debug_struct("Disconnected")
.field("peer_id", peer_id)
.finish()
}
Peer::Local => {
f.debug_struct("Local")
.finish()
}
}
}
}
impl<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
Peer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>,
TPeerId: Eq + Hash,
TConnInfo: ConnectionInfo<PeerId = TPeerId>
{
pub(super) fn new(
network: &'a mut Network<TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,
peer_id: TPeerId
) -> Self {
if peer_id == network.local_peer_id {
return Peer::Local;
}
if network.pool.is_connected(&peer_id) {
return Self::connected(network, peer_id)
}
if network.dialing.get_mut(&peer_id).is_some() {
return Self::dialing(network, peer_id);
}
Self::disconnected(network, peer_id)
}
fn disconnected(
network: &'a mut Network<TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,
peer_id: TPeerId
) -> Self {
Peer::Disconnected(DisconnectedPeer { network, peer_id })
}
fn connected(
network: &'a mut Network<TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,
peer_id: TPeerId
) -> Self {
Peer::Connected(ConnectedPeer { network, peer_id })
}
fn dialing(
network: &'a mut Network<TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,
peer_id: TPeerId
) -> Self {
Peer::Dialing(DialingPeer { network, peer_id })
}
}
impl<'a, TTrans, TMuxer, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
Peer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport<Output = (TConnInfo, TMuxer)> + Clone,
TTrans::Error: Send + 'static,
TTrans::Dial: Send + 'static,
TMuxer: StreamMuxer + Send + Sync + 'static,
TMuxer::OutboundSubstream: Send,
TMuxer::Substream: Send,
TInEvent: Send + 'static,
TOutEvent: Send + 'static,
THandler: IntoConnectionHandler<TConnInfo> + Send + 'static,
THandler::Handler: ConnectionHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent> + Send + 'static,
<THandler::Handler as ConnectionHandler>::OutboundOpenInfo: Send + 'static,
<THandler::Handler as ConnectionHandler>::Error: error::Error + Send + 'static,
TConnInfo: fmt::Debug + ConnectionInfo<PeerId = TPeerId> + Send + 'static,
TPeerId: Eq + Hash + Clone + Send + 'static,
{
pub fn is_connected(&self) -> bool {
match self {
Peer::Connected(..) => true,
Peer::Dialing(peer) => peer.is_connected(),
Peer::Disconnected(..) => false,
Peer::Local => false
}
}
pub fn is_dialing(&self) -> bool {
match self {
Peer::Dialing(_) => true,
Peer::Connected(peer) => peer.is_dialing(),
Peer::Disconnected(..) => false,
Peer::Local => false
}
}
pub fn is_disconnected(&self) -> bool {
match self {
Peer::Disconnected(..) => true,
_ => false
}
}
pub fn into_connected(self) -> Option<
ConnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
> {
match self {
Peer::Connected(peer) => Some(peer),
Peer::Dialing(peer) => peer.into_connected(),
Peer::Disconnected(..) => None,
Peer::Local => None,
}
}
pub fn into_dialing(self) -> Option<
DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
> {
match self {
Peer::Dialing(peer) => Some(peer),
Peer::Connected(peer) => peer.into_dialing(),
Peer::Disconnected(..) => None,
Peer::Local => None
}
}
pub fn into_disconnected(self) -> Option<
DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
> {
match self {
Peer::Disconnected(peer) => Some(peer),
_ => None,
}
}
}
pub struct ConnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>,
{
network: &'a mut Network<TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,
peer_id: TPeerId,
}
impl<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
ConnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>,
TConnInfo: ConnectionInfo<PeerId = TPeerId>,
TPeerId: Eq + Hash + Clone,
{
pub fn id(&self) -> &TPeerId {
&self.peer_id
}
pub fn connect<I, TMuxer>(self, address: Multiaddr, remaining: I, handler: THandler)
-> Result<DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,
ConnectionLimit>
where
I: IntoIterator<Item = Multiaddr>,
THandler: Send + 'static,
THandler::Handler: Send,
<THandler::Handler as ConnectionHandler>::Error: error::Error + Send,
<THandler::Handler as ConnectionHandler>::OutboundOpenInfo: Send,
THandler::Handler: ConnectionHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent> + Send,
TTrans: Transport<Output = (TConnInfo, TMuxer)> + Clone,
TTrans::Error: Send + 'static,
TTrans::Dial: Send + 'static,
TMuxer: StreamMuxer + Send + Sync + 'static,
TMuxer::OutboundSubstream: Send,
TMuxer::Substream: Send,
TConnInfo: fmt::Debug + Send + 'static,
TPeerId: Eq + Hash + Clone + Send + 'static,
TInEvent: Send + 'static,
TOutEvent: Send + 'static,
{
if self.network.dialing.contains_key(&self.peer_id) {
let peer = DialingPeer {
network: self.network,
peer_id: self.peer_id
};
Ok(peer)
} else {
self.network.dial_peer(DialingOpts {
peer: self.peer_id.clone(),
handler,
address,
remaining: remaining.into_iter().collect(),
})?;
Ok(DialingPeer {
network: self.network,
peer_id: self.peer_id,
})
}
}
pub fn connection<'b>(&'b mut self, id: ConnectionId)
-> Option<EstablishedConnection<'b, TInEvent, TConnInfo, TPeerId>>
{
self.network.pool.get_established(id)
}
pub fn num_connections(&self) -> usize {
self.network.pool.num_peer_established(&self.peer_id)
}
pub fn is_dialing(&self) -> bool {
self.network.dialing.contains_key(&self.peer_id)
}
pub fn into_dialing(self) -> Option<
DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
> {
if self.network.dialing.contains_key(&self.peer_id) {
Some(DialingPeer { network: self.network, peer_id: self.peer_id })
} else {
None
}
}
pub fn connections<'b>(&'b mut self) ->
EstablishedConnectionIter<'b,
impl Iterator<Item = ConnectionId>,
TInEvent,
TOutEvent,
THandler,
TTrans::Error,
<THandler::Handler as ConnectionHandler>::Error,
TConnInfo,
TPeerId>
{
self.network.pool.iter_peer_established(&self.peer_id)
}
pub fn some_connection<'b>(&'b mut self)
-> EstablishedConnection<'b, TInEvent, TConnInfo, TPeerId>
{
self.connections()
.into_first()
.expect("By `Peer::new` and the definition of `ConnectedPeer`.")
}
pub fn disconnect(self)
-> DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
{
self.network.disconnect(&self.peer_id);
DisconnectedPeer { network: self.network, peer_id: self.peer_id }
}
}
impl<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> fmt::Debug for
ConnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>,
TPeerId: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("ConnectedPeer")
.field("peer_id", &self.peer_id)
.finish()
}
}
pub struct DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>,
{
network: &'a mut Network<TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,
peer_id: TPeerId,
}
impl<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>,
TConnInfo: ConnectionInfo<PeerId = TPeerId>,
TPeerId: Eq + Hash + Clone,
{
pub fn id(&self) -> &TPeerId {
&self.peer_id
}
pub fn disconnect(self) -> DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> {
self.network.disconnect(&self.peer_id);
DisconnectedPeer { network: self.network, peer_id: self.peer_id }
}
pub fn is_connected(&self) -> bool {
self.network.pool.is_connected(&self.peer_id)
}
pub fn into_connected(self)
-> Option<ConnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>>
{
if self.is_connected() {
Some(ConnectedPeer { peer_id: self.peer_id, network: self.network })
} else {
None
}
}
pub fn connection<'b>(&'b mut self) -> DialingConnection<'b, TInEvent, TConnInfo, TPeerId> {
let attempt = match self.network.dialing.entry(self.peer_id.clone()) {
hash_map::Entry::Occupied(e) => e,
_ => unreachable!("By `Peer::new` and the definition of `DialingPeer`.")
};
let inner = self.network.pool
.get_outgoing(attempt.get().id)
.expect("By consistency of `network.pool` with `network.dialing`.");
DialingConnection {
inner, dialing: attempt, peer_id: &self.peer_id
}
}
}
impl<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> fmt::Debug for
DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>,
TPeerId: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("DialingPeer")
.field("peer_id", &self.peer_id)
.finish()
}
}
pub struct DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>,
{
peer_id: TPeerId,
network: &'a mut Network<TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,
}
impl<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId> fmt::Debug for
DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport,
THandler: IntoConnectionHandler<TConnInfo>,
TPeerId: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("DisconnectedPeer")
.field("peer_id", &self.peer_id)
.finish()
}
}
impl<'a, TTrans, TInEvent, TOutEvent, TMuxer, THandler, TConnInfo, TPeerId>
DisconnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>
where
TTrans: Transport<Output = (TConnInfo, TMuxer)> + Clone,
TTrans::Error: Send + 'static,
TTrans::Dial: Send + 'static,
TMuxer: StreamMuxer + Send + Sync + 'static,
TMuxer::OutboundSubstream: Send,
TMuxer::Substream: Send,
THandler: IntoConnectionHandler<TConnInfo> + Send + 'static,
THandler::Handler: ConnectionHandler<Substream = Substream<TMuxer>, InEvent = TInEvent, OutEvent = TOutEvent> + Send,
<THandler::Handler as ConnectionHandler>::OutboundOpenInfo: Send,
<THandler::Handler as ConnectionHandler>::Error: error::Error + Send,
TInEvent: Send + 'static,
TOutEvent: Send + 'static,
{
pub fn id(&self) -> &TPeerId {
&self.peer_id
}
pub fn connect<TIter>(self, first: Multiaddr, rest: TIter, handler: THandler)
-> Result<DialingPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,
ConnectionLimit>
where
TIter: IntoIterator<Item = Multiaddr>,
TConnInfo: fmt::Debug + ConnectionInfo<PeerId = TPeerId> + Send + 'static,
TPeerId: Eq + Hash + Clone + Send + 'static,
{
self.network.dial_peer(DialingOpts {
peer: self.peer_id.clone(),
handler,
address: first,
remaining: rest.into_iter().collect(),
})?;
Ok(DialingPeer {
network: self.network,
peer_id: self.peer_id,
})
}
pub fn set_connected(
self,
connected: Connected<TConnInfo>,
connection: Connection<TMuxer, THandler::Handler>,
) -> Result<
ConnectedPeer<'a, TTrans, TInEvent, TOutEvent, THandler, TConnInfo, TPeerId>,
ConnectionLimit
> where
TConnInfo: fmt::Debug + ConnectionInfo<PeerId = TPeerId> + Clone + Send + 'static,
TPeerId: Eq + Hash + Clone + fmt::Debug,
{
if connected.peer_id() != &self.peer_id {
panic!("Invalid peer ID given: {:?}. Expected: {:?}", connected.peer_id(), self.peer_id)
}
self.network.pool.add(connection, connected)
.map(|_id| ConnectedPeer {
network: self.network,
peer_id: self.peer_id,
})
}
}
#[derive(Debug, Clone)]
pub(super) struct DialingAttempt {
pub(super) id: ConnectionId,
pub(super) current: Multiaddr,
pub(super) next: Vec<Multiaddr>,
}
pub struct DialingConnection<'a, TInEvent, TConnInfo, TPeerId> {
peer_id: &'a TPeerId,
inner: PendingConnection<'a, TInEvent, TConnInfo, TPeerId>,
dialing: hash_map::OccupiedEntry<'a, TPeerId, DialingAttempt>,
}
impl<'a, TInEvent, TConnInfo, TPeerId>
DialingConnection<'a, TInEvent, TConnInfo, TPeerId>
{
pub fn id(&self) -> ConnectionId {
self.inner.id()
}
pub fn peer_id(&self) -> &TPeerId {
self.peer_id
}
pub fn endpoint(&self) -> &ConnectedPoint {
self.inner.endpoint()
}
pub fn abort(self)
where
TPeerId: Eq + Hash + Clone,
{
self.dialing.remove();
self.inner.abort();
}
pub fn add_addresses(&mut self, addrs: impl IntoIterator<Item = Multiaddr>) {
for addr in addrs {
self.add_address(addr);
}
}
pub fn add_address(&mut self, addr: Multiaddr) {
if self.dialing.get().next.iter().all(|a| a != &addr) {
self.dialing.get_mut().next.push(addr);
}
}
}