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
use rama_core::{error::BoxError, Context, Service};
use std::{fmt, future::Future, net::SocketAddr};

/// The established connection to a server returned for the http client to be used.
pub struct EstablishedClientConnection<S, State, Request> {
    /// The [`Context`] of the `Request` for which a connection was established.
    pub ctx: Context<State>,
    /// The `Request` for which a connection was established.
    pub req: Request,
    /// The established connection stream/service/... to the server.
    pub conn: S,
    /// The target address connected to.
    pub addr: SocketAddr,
}

impl<S: fmt::Debug, State: fmt::Debug, Request: fmt::Debug> fmt::Debug
    for EstablishedClientConnection<S, State, Request>
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("EstablishedClientConnection")
            .field("ctx", &self.ctx)
            .field("req", &self.req)
            .field("conn", &self.conn)
            .field("addr", &self.addr)
            .finish()
    }
}

impl<S: Clone, State, Request: Clone> Clone for EstablishedClientConnection<S, State, Request> {
    fn clone(&self) -> Self {
        Self {
            ctx: self.ctx.clone(),
            req: self.req.clone(),
            conn: self.conn.clone(),
            addr: self.addr,
        }
    }
}

/// Glue trait that is used as the Connector trait bound for
/// clients establishing a connection on one layer or another.
///
/// Can also be manually implemented as an alternative [`Service`] trait,
/// but from a Rama POV it is mostly used for UX trait bounds.
pub trait ConnectorService<State, Request>: Send + Sync + 'static {
    /// Connection returned by the [`ConnectorService`]
    type Connection;
    /// Error returned in case of connection / setup failure
    type Error: Into<BoxError>;

    /// Establish a connection, which often involves some kind of handshake,
    /// or connection revival.
    fn connect(
        &self,
        ctx: Context<State>,
        req: Request,
    ) -> impl Future<
        Output = Result<EstablishedClientConnection<Self::Connection, State, Request>, Self::Error>,
    > + Send
           + '_;
}

impl<S, State, Request, Connection> ConnectorService<State, Request> for S
where
    S: Service<
        State,
        Request,
        Response = EstablishedClientConnection<Connection, State, Request>,
        Error: Into<BoxError>,
    >,
{
    type Connection = Connection;
    type Error = S::Error;

    fn connect(
        &self,
        ctx: Context<State>,
        req: Request,
    ) -> impl Future<
        Output = Result<EstablishedClientConnection<Self::Connection, State, Request>, Self::Error>,
    > + Send
           + '_ {
        self.serve(ctx, req)
    }
}