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
119
#![forbid(unsafe_code)]
#![deny(
    clippy::dbg_macro,
    missing_copy_implementations,
    rustdoc::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;
}