rama_net/client/
conn.rs

1use rama_core::{Context, Service, error::BoxError, service::BoxService};
2use std::fmt;
3
4/// The established connection to a server returned for the http client to be used.
5pub struct EstablishedClientConnection<S, State, Request> {
6    /// The [`Context`] of the `Request` for which a connection was established.
7    pub ctx: Context<State>,
8    /// The `Request` for which a connection was established.
9    pub req: Request,
10    /// The established connection stream/service/... to the server.
11    pub conn: S,
12}
13
14impl<S: fmt::Debug, State: fmt::Debug, Request: fmt::Debug> fmt::Debug
15    for EstablishedClientConnection<S, State, Request>
16{
17    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18        f.debug_struct("EstablishedClientConnection")
19            .field("ctx", &self.ctx)
20            .field("req", &self.req)
21            .field("conn", &self.conn)
22            .finish()
23    }
24}
25
26impl<S: Clone, State: Clone, Request: Clone> Clone
27    for EstablishedClientConnection<S, State, Request>
28{
29    fn clone(&self) -> Self {
30        Self {
31            ctx: self.ctx.clone(),
32            req: self.req.clone(),
33            conn: self.conn.clone(),
34        }
35    }
36}
37
38/// Glue trait that is used as the Connector trait bound for
39/// clients establishing a connection on one layer or another.
40///
41/// Can also be manually implemented as an alternative [`Service`] trait,
42/// but from a Rama POV it is mostly used for UX trait bounds.
43pub trait ConnectorService<State, Request>: Send + Sync + 'static {
44    /// Connection returned by the [`ConnectorService`]
45    type Connection;
46    /// Error returned in case of connection / setup failure
47    type Error: Into<BoxError>;
48
49    /// Establish a connection, which often involves some kind of handshake,
50    /// or connection revival.
51    fn connect(
52        &self,
53        ctx: Context<State>,
54        req: Request,
55    ) -> impl Future<
56        Output = Result<EstablishedClientConnection<Self::Connection, State, Request>, Self::Error>,
57    > + Send
58    + '_;
59}
60
61impl<S, State, Request, Connection> ConnectorService<State, Request> for S
62where
63    S: Service<
64            State,
65            Request,
66            Response = EstablishedClientConnection<Connection, State, Request>,
67            Error: Into<BoxError>,
68        >,
69{
70    type Connection = Connection;
71    type Error = S::Error;
72
73    fn connect(
74        &self,
75        ctx: Context<State>,
76        req: Request,
77    ) -> impl Future<
78        Output = Result<EstablishedClientConnection<Self::Connection, State, Request>, Self::Error>,
79    > + Send
80    + '_ {
81        self.serve(ctx, req)
82    }
83}
84
85/// A [`ConnectorService`] which only job is to [`Box`]
86/// the created [`Service`] by the inner [`ConnectorService`].
87pub struct BoxedConnectorService<S>(S);
88
89impl<S> BoxedConnectorService<S> {
90    /// Create a new [`BoxedConnector`].
91    pub fn new(connector: S) -> Self {
92        Self(connector)
93    }
94}
95
96impl<S: fmt::Debug> fmt::Debug for BoxedConnectorService<S> {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        f.debug_tuple("BoxedConnectorService")
99            .field(&self.0)
100            .finish()
101    }
102}
103
104impl<S: Clone> Clone for BoxedConnectorService<S> {
105    fn clone(&self) -> Self {
106        Self(self.0.clone())
107    }
108}
109
110impl<S, State, Request, Svc> Service<State, Request> for BoxedConnectorService<S>
111where
112    S: Service<
113            State,
114            Request,
115            Response = EstablishedClientConnection<Svc, State, Request>,
116            Error: Into<BoxError>,
117        >,
118    Svc: Service<State, Request>,
119    State: Send + 'static,
120    Request: Send + 'static,
121{
122    type Response = EstablishedClientConnection<
123        BoxService<State, Request, Svc::Response, Svc::Error>,
124        State,
125        Request,
126    >;
127    type Error = S::Error;
128
129    async fn serve(
130        &self,
131        ctx: Context<State>,
132        req: Request,
133    ) -> Result<Self::Response, Self::Error> {
134        let EstablishedClientConnection {
135            ctx,
136            req,
137            conn: svc,
138        } = self.0.serve(ctx, req).await?;
139        Ok(EstablishedClientConnection {
140            ctx,
141            req,
142            conn: svc.boxed(),
143        })
144    }
145}