use async_trait::async_trait;
use futures::prelude::*;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use std::{error::Error, fmt};
use libp2prs_multiaddr::Multiaddr;
use crate::multistream::NegotiationError;
use libp2p_pnet::PnetError;
pub mod dummy;
pub mod memory;
pub mod protector;
pub mod timeout;
pub mod upgrade;
#[async_trait]
pub trait Transport: Send {
type Output;
fn listen_on(&mut self, addr: Multiaddr) -> Result<IListener<Self::Output>, TransportError>;
async fn dial(&mut self, addr: Multiaddr) -> Result<Self::Output, TransportError>;
fn box_clone(&self) -> ITransport<Self::Output>;
fn protocols(&self) -> Vec<u32>;
fn timeout(self, timeout: Duration) -> timeout::TransportTimeout<Self>
where
Self: Sized,
{
timeout::TransportTimeout::new(self, timeout)
}
fn outbound_timeout(self, timeout: Duration) -> timeout::TransportTimeout<Self>
where
Self: Sized,
{
timeout::TransportTimeout::with_outgoing_timeout(self, timeout)
}
fn inbound_timeout(self, timeout: Duration) -> timeout::TransportTimeout<Self>
where
Self: Sized,
{
timeout::TransportTimeout::with_ingoing_timeout(self, timeout)
}
}
#[derive(Clone, Debug)]
pub enum ListenerEvent<TOutput> {
AddressAdded(Multiaddr),
AddressDeleted(Multiaddr),
Accepted(TOutput),
}
impl<TOutput> ListenerEvent<TOutput> {
pub fn map<U>(self, f: impl FnOnce(TOutput) -> Result<U, TransportError>) -> Result<ListenerEvent<U>, TransportError> {
match self {
ListenerEvent::Accepted(o) => f(o).map(ListenerEvent::Accepted),
ListenerEvent::AddressAdded(a) => Ok(ListenerEvent::AddressAdded(a)),
ListenerEvent::AddressDeleted(a) => Ok(ListenerEvent::AddressDeleted(a)),
}
}
pub fn is_address_added(&self) -> bool {
matches!(self, ListenerEvent::AddressAdded(_))
}
pub fn into_new_address(self) -> Option<Multiaddr> {
if let ListenerEvent::AddressAdded(a) = self {
Some(a)
} else {
None
}
}
pub fn is_address_deleted(&self) -> bool {
matches!(self, ListenerEvent::AddressDeleted(_))
}
pub fn into_address_deleted(self) -> Option<Multiaddr> {
if let ListenerEvent::AddressDeleted(a) = self {
Some(a)
} else {
None
}
}
}
#[async_trait]
pub trait TransportListener: Send {
type Output: Send;
async fn accept(&mut self) -> Result<ListenerEvent<Self::Output>, TransportError>;
fn multi_addr(&self) -> Option<&Multiaddr>;
fn incoming(&mut self) -> Incoming<Self>
where
Self: Sized,
{
Incoming(self)
}
async fn accept_output(&mut self) -> Result<Self::Output, TransportError> {
loop {
if let ListenerEvent::Accepted(o) = self.accept().await? {
break Ok(o);
}
}
}
}
pub type IListener<TOutput> = Box<dyn TransportListener<Output = TOutput> + Send>;
pub type ITransport<TOutput> = Box<dyn Transport<Output = TOutput> + Send>;
impl<TOutput: ConnectionInfo> Clone for ITransport<TOutput> {
fn clone(&self) -> Self {
self.box_clone()
}
}
pub struct Incoming<'a, T>(&'a mut T);
impl<'a, T> Stream for Incoming<'a, T>
where
T: TransportListener,
{
type Item = Result<ListenerEvent<T::Output>, TransportError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let future = self.0.accept();
futures::pin_mut!(future);
let evt = futures::ready!(future.poll(cx))?;
Poll::Ready(Some(Ok(evt)))
}
}
pub trait ConnectionInfo: Send {
fn local_multiaddr(&self) -> Multiaddr;
fn remote_multiaddr(&self) -> Multiaddr;
}
#[derive(Debug)]
pub enum TransportError {
MultiaddrNotSupported(Multiaddr),
Timeout,
Unreachable,
Internal,
Routing(Box<dyn Error + Send + Sync>),
IoError(std::io::Error),
ResolveFail(String),
NegotiationError(NegotiationError),
ProtectorError(PnetError),
SecurityError(Box<dyn Error + Send + Sync>),
StreamMuxerError(Box<dyn Error + Send + Sync>),
WsError(Box<dyn Error + Send + Sync>),
}
impl From<std::io::Error> for TransportError {
fn from(e: std::io::Error) -> Self {
TransportError::IoError(e)
}
}
impl From<NegotiationError> for TransportError {
fn from(e: NegotiationError) -> Self {
TransportError::NegotiationError(e)
}
}
impl From<PnetError> for TransportError {
fn from(e: PnetError) -> Self {
TransportError::ProtectorError(e)
}
}
impl fmt::Display for TransportError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TransportError::MultiaddrNotSupported(addr) => write!(f, "Multiaddr is not supported: {}", addr),
TransportError::Timeout => write!(f, "Operation timeout"),
TransportError::Unreachable => write!(f, "Memory transport unreachable"),
TransportError::Internal => write!(f, "Internal error"),
TransportError::Routing(err) => write!(f, "Routing layer error {:?}", err),
TransportError::IoError(err) => write!(f, "IO error {}", err),
TransportError::ResolveFail(name) => write!(f, "resolve dns {} failed", name),
TransportError::NegotiationError(err) => write!(f, "Negotiation error {:?}", err),
TransportError::ProtectorError(err) => write!(f, "Protector error {:?}", err),
TransportError::SecurityError(err) => write!(f, "SecurityError layer error {:?}", err),
TransportError::StreamMuxerError(err) => write!(f, "StreamMuxerError layer error {:?}", err),
TransportError::WsError(err) => write!(f, "Websocket transport error: {}", err),
}
}
}
impl Error for TransportError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
TransportError::MultiaddrNotSupported(_) => None,
TransportError::Timeout => None,
TransportError::Unreachable => None,
TransportError::Internal => None,
TransportError::Routing(err) => Some(&**err),
TransportError::IoError(err) => Some(err),
TransportError::ResolveFail(_) => None,
TransportError::NegotiationError(err) => Some(err),
TransportError::ProtectorError(err) => Some(err),
TransportError::SecurityError(err) => Some(&**err),
TransportError::StreamMuxerError(err) => Some(&**err),
TransportError::WsError(err) => Some(&**err),
}
}
}