aggligator 0.12.1

Aggregates multiple links (TCP, WebSocket, USB or similar) into one connection having their combined bandwidth and provides resiliency against failure of individual links, allowing failover and roaming between networks in user space.
Documentation
//! Connection and link management for various transports.
//!
//! This module provides automatic link management for an Aggligator connection.
//!
//! Crates that provide Aggligator support for common transports, such as TCP or WebSocket,
//! can be found under the
//! [`aggligator-transport` keyword on crates.io](https://crates.io/keywords/aggligator-transport).
//!
//! # Establishing outgoing connections
//!
//! The following example shows how to use a [`Connector`] to establish outgoing connections
//! using the TCP transport to connect to `server` on port 5900.
//!
//! You must depend on the `aggligator_transport_tcp` crate for this example to work.
//!
//! ```ignore
//! use aggligator::Connector;
//! use aggligator_transport_tcp::TcpConnector;
//!
//! #[tokio::main]
//! async fn main() -> std::io::Result<()> {
//!     let mut connector = Connector::new();
//!     connector.add(TcpConnector::new(["server"], 5900).await?);
//!     let ch = connector.channel().unwrap().await?;
//!     let stream = ch.into_stream();
//!
//!     // use the connection
//!
//!     Ok(())
//! }
//! ```
//!
//! # Accepting incoming connections
//!
//! The following example shows how to use an [`Acceptor`] to listen for incoming connections
//! using the TCP transport on port 5900.
//!
//! You must depend on the `aggligator_transport_tcp` crate for this example to work.
//!
//! ```ignore
//! use std::net::{Ipv6Addr, SocketAddr};
//! use aggligator::Acceptor;
//! use aggligator_transport_tcp::TcpAcceptor;
//!
//! #[tokio::main]
//! async fn main() -> std::io::Result<()> {
//!     let acceptor = Acceptor::new();
//!     acceptor.add(
//!         TcpAcceptor::new([SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 5900)]).await?
//!     );
//!
//!     loop {
//!         let (ch, _control) = acceptor.accept().await?;
//!         let stream = ch.into_stream();
//!
//!         // use the connection
//!     }
//!
//!     Ok(())
//! }
//!

use std::{
    any::Any,
    cmp::Ordering,
    error::Error,
    fmt,
    fmt::{Debug, Display},
    hash::{Hash, Hasher},
    sync::Arc,
};

use crate::{
    Control, Link, Listener, Server, Task,
    cfg::LinkCfg,
    control::Direction,
    id::ConnId,
    io::{RxBox, TxBox},
};

mod acceptor;
mod connector;

pub use acceptor::*;
pub use connector::*;

/// Link error information.
#[derive(Clone, Debug)]
pub struct LinkError<TAG> {
    /// Connection id for outgoing links.
    pub id: Option<ConnId>,
    /// Link tag.
    pub tag: TAG,
    /// Error.
    pub error: Arc<std::io::Error>,
}

impl<TAG> LinkError<TAG>
where
    TAG: Clone,
{
    /// Creates new link tag error information for outgoing links.
    pub fn outgoing(id: ConnId, tag: &TAG, error: std::io::Error) -> Self {
        Self { id: Some(id), tag: tag.clone(), error: Arc::new(error) }
    }

    /// Creates new link tag error information for incoming links.
    pub fn incoming(tag: &TAG, error: std::io::Error) -> Self {
        Self { id: None, tag: tag.clone(), error: Arc::new(error) }
    }

    /// Direction of link on which the error occured.
    pub fn direction(&self) -> Direction {
        if self.id.is_some() { Direction::Outgoing } else { Direction::Incoming }
    }
}

impl<TAG> fmt::Display for LinkError<TAG>
where
    TAG: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}: {}", self.tag, self.error)
    }
}

impl<TAG> Error for LinkError<TAG> where TAG: fmt::Display + fmt::Debug {}

/// A tag for a link to a remote endpoint.
pub trait LinkTag: Debug + Display + Send + Sync + 'static {
    /// The name of the transport.
    fn transport_name(&self) -> &str;

    /// The direction of the link.
    fn direction(&self) -> Direction;

    /// User data to send to the remote endpoint when connecting.
    fn user_data(&self) -> Vec<u8>;

    /// Allows the transport to apply link-specific configuration.
    ///
    /// This is called before establishing a new link and may modify the
    /// link-specific configuration.
    fn link_cfg(&self, link_cfg: &mut LinkCfg) {
        let _ = link_cfg;
    }

    /// Cast this type as [`Any`].
    fn as_any(&self) -> &dyn Any;

    /// Return a clone of this type in a [`Box`].
    fn box_clone(&self) -> LinkTagBox;

    /// Compare to another link tag of the same type.
    fn dyn_cmp(&self, other: &dyn LinkTag) -> Ordering;

    /// Hash this link tag.
    fn dyn_hash(&self, state: &mut dyn Hasher);
}

impl PartialEq for dyn LinkTag {
    fn eq(&self, other: &Self) -> bool {
        self.cmp(other).is_eq()
    }
}

impl Eq for dyn LinkTag {}

impl PartialOrd for dyn LinkTag {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(Ord::cmp(self, other))
    }
}

impl Ord for dyn LinkTag {
    fn cmp(&self, other: &Self) -> Ordering {
        let id = self.as_any().type_id();
        let other_id = other.as_any().type_id();
        self.transport_name()
            .cmp(other.transport_name())
            .then(id.cmp(&other_id).then_with(|| self.dyn_cmp(other)))
    }
}

impl Hash for dyn LinkTag {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let id = self.as_any().type_id();
        id.hash(state);
        self.dyn_hash(state);
    }
}

/// A boxed [`LinkTag`].
pub type LinkTagBox = Box<dyn LinkTag>;

impl Clone for LinkTagBox {
    fn clone(&self) -> Self {
        self.box_clone()
    }
}

/// Control handle for boxed transports.
pub type BoxControl = Control<TxBox, RxBox, LinkTagBox>;

/// Server for boxed transports.
pub type BoxServer = Server<TxBox, RxBox, LinkTagBox>;

/// Listener for boxed transports.
pub type BoxListener = Listener<TxBox, RxBox, LinkTagBox>;

/// Connection management task for boxed transports.
pub type BoxTask = Task<TxBox, RxBox, LinkTagBox>;

/// Link handle for boxed link tag.
pub type BoxLink = Link<LinkTagBox>;

/// Link error information for boxed link tag.
pub type BoxLinkError = LinkError<LinkTagBox>;

/// Link configuration function.
type LinkCfgFn = Arc<dyn Fn(&dyn LinkTag, &mut LinkCfg) + Send + Sync>;