1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#![forbid(unsafe_code)]
#![deny(
    missing_copy_implementations,
    missing_crate_level_docs,
    missing_debug_implementations,
    missing_docs,
    nonstandard_style,
    unused_qualifications
)]

/*!
This crate provides the common interface for server-side tls
[`Acceptor`]s and client-side [`Connector`]s, abstracting over various
implementations.
*/

pub use async_trait::async_trait;
pub use futures_lite::{AsyncRead, AsyncWrite};
use std::{convert::Infallible, fmt::Debug, future::Future};
pub use url::Url;

/**
This trait provides the common interface for server-side tls
acceptors, abstracting over various implementations

The only implementation provided by this crate is `()`, which is
a noop acceptor, and passes through the `Input` type.

Implementing this trait looks like:
```rust,ignore
use trillium_tls_common::{AsyncRead, AsyncWrite, async_trait};
#[async_trait]
impl<Input> Acceptor<Input> for my_tls_impl::Acceptor
where
    Input: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
{
    type Output = my_tls_impl::TlsStream<Input>;
    type Error = my_tls_impl::Error;
    async fn accept(&self, input: Input) -> Result<Self::Output, Self::Error> {
        self.accept(input).await
    }
}
```
*/
#[async_trait]
pub trait Acceptor<Input>: Clone + Send + Sync + 'static
where
    Input: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
{
    /// The stream type. For example, TlsStream<Input>
    type Output: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static;

    /// An error type that [`Acceptor::accept`] may return
    type Error: Debug + Send + Sync;

    /**
    Transform an Input (`AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static`) into Self::Output

    Async trait signature:
    ```rust,ignore
    async fn accept(&self, input: Input) -> Result<Self::Output, Self::Error>;
    ```
    */
    async fn accept(&self, input: Input) -> Result<Self::Output, Self::Error>;
}

#[async_trait]
impl<Input> Acceptor<Input> for ()
where
    Input: AsyncRead + AsyncWrite + Send + Sync + Unpin + 'static,
{
    type Output = Input;
    type Error = Infallible;
    async fn accept(&self, input: Input) -> Result<Self::Output, Self::Error> {
        Ok(input)
    }
}

/**
Interface for runtime and tls adapters for the trillium client

See
[`trillium_client`](https://docs.trillium.rs/trillium_client) for more
information on usage.
*/
#[async_trait]
pub trait Connector: Clone + Send + Sync + 'static {
    /// The async read + write type for this connector, often a TcpStream or TlSStream
    type Transport: AsyncRead + AsyncWrite + Unpin + Send + Sync + 'static;

    /// A type that can be used to configure this Connector. It will be passed into [`Connector::connect`].
    type Config: Debug + Default + Send + Sync + Clone;

    /// A SocketAddr representation of the other side of this connection
    fn peer_addr(transport: &Self::Transport) -> std::io::Result<std::net::SocketAddr>;

    /**
    Initiate a connection to the provided url, using the configuration.

    Async trait signature:
    ```rust,ignore
    async fn connect(url: &Url, config: &Self::Config) -> std::io::Result<Self::Transport>;
    ```
     */
    async fn connect(url: &Url, config: &Self::Config) -> std::io::Result<Self::Transport>;

    /**
    Spawn and detach a task on the runtime. Although this may seem
    unrelated to the purpose of a tcp connector, it is required as a
    workaround for the absence of async drop in order to enable
    keepalive connection pooling. TLS implementations that wrap a
    runtime implementation should call through to the inner spawn.
    */
    fn spawn<Fut>(future: Fut)
    where
        Fut: Future + Send + 'static,
        <Fut as Future>::Output: Send;
}