1use core::fmt;
2
3use rama_core::{Service, extensions::ExtensionsRef, service::BoxService};
4
5use super::ConnectionError;
6
7#[derive(Clone)]
8pub struct EstablishedClientConnection<S, Input> {
10 pub input: Input,
12 pub conn: S,
14}
15
16impl<S: fmt::Debug, Input: fmt::Debug> fmt::Debug for EstablishedClientConnection<S, Input> {
17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 f.debug_struct("EstablishedClientConnection")
19 .field("input", &self.input)
20 .field("conn", &self.conn)
21 .finish()
22 }
23}
24
25pub trait ConnectorService<Input>: Send + Sync + 'static {
31 type Connection: Send + ExtensionsRef;
33
34 fn connect(
41 &self,
42 input: Input,
43 ) -> impl Future<
44 Output = Result<EstablishedClientConnection<Self::Connection, Input>, ConnectionError>,
45 > + Send
46 + '_;
47}
48
49impl<S, Input, Connection> ConnectorService<Input> for S
50where
51 S: Service<
52 Input,
53 Output = EstablishedClientConnection<Connection, Input>,
54 Error: Into<ConnectionError>,
55 >,
56 Connection: Send + ExtensionsRef,
57{
58 type Connection = Connection;
59
60 fn connect(
61 &self,
62 input: Input,
63 ) -> impl Future<
64 Output = Result<EstablishedClientConnection<Self::Connection, Input>, ConnectionError>,
65 > + Send
66 + '_ {
67 let future = self.serve(input);
68 async move { future.await.map_err(Into::into) }
69 }
70}
71
72#[derive(Debug, Clone)]
75pub struct BoxedConnectorService<S>(S);
76
77impl<S> BoxedConnectorService<S> {
78 pub fn new(connector: S) -> Self {
80 Self(connector)
81 }
82}
83
84impl<S, Input, Svc> Service<Input> for BoxedConnectorService<S>
85where
86 S: ConnectorService<Input, Connection = Svc>,
87 Svc: Service<Input>,
88 Input: Send + 'static,
89{
90 type Output = EstablishedClientConnection<BoxService<Input, Svc::Output, Svc::Error>, Input>;
91 type Error = ConnectionError;
92
93 async fn serve(&self, input: Input) -> Result<Self::Output, Self::Error> {
94 let EstablishedClientConnection { input, conn: svc } = self.0.connect(input).await?;
95 Ok(EstablishedClientConnection {
96 input,
97 conn: svc.boxed(),
98 })
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use core::{convert::Infallible, fmt};
105
106 use rama_core::ServiceInput;
107
108 use super::*;
109 use crate::client::{ConnectionErrorDomain, ConnectionErrorKind};
110
111 #[derive(Debug)]
112 struct LegacyError;
113
114 impl fmt::Display for LegacyError {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 f.write_str("legacy connector error")
117 }
118 }
119
120 impl core::error::Error for LegacyError {}
121
122 #[derive(Debug)]
123 struct LegacyFailingConnector;
124
125 impl Service<()> for LegacyFailingConnector {
126 type Output = EstablishedClientConnection<ServiceInput<()>, ()>;
127 type Error = rama_core::error::BoxError;
128
129 async fn serve(&self, _input: ()) -> Result<Self::Output, Self::Error> {
130 Err(Box::new(LegacyError))
131 }
132 }
133
134 #[derive(Debug)]
135 struct ClassifiedFailingConnector;
136
137 impl Service<()> for ClassifiedFailingConnector {
138 type Output = EstablishedClientConnection<ServiceInput<()>, ()>;
139 type Error = ConnectionError;
140
141 async fn serve(&self, _input: ()) -> Result<Self::Output, Self::Error> {
142 Err(ConnectionError::transport(
143 LegacyError,
144 ConnectionErrorKind::Unavailable,
145 ))
146 }
147 }
148
149 #[derive(Debug)]
150 struct SuccessfulConnector;
151
152 impl Service<usize> for SuccessfulConnector {
153 type Output = EstablishedClientConnection<ServiceInput<()>, usize>;
154 type Error = Infallible;
155
156 async fn serve(&self, input: usize) -> Result<Self::Output, Self::Error> {
157 Ok(EstablishedClientConnection {
158 input,
159 conn: ServiceInput::new(()),
160 })
161 }
162 }
163
164 #[tokio::test]
165 async fn connector_service_normalizes_legacy_errors() {
166 let error = LegacyFailingConnector.connect(()).await.unwrap_err();
167
168 assert_eq!(error.domain(), ConnectionErrorDomain::Unknown);
169 assert_eq!(error.kind(), ConnectionErrorKind::Other);
170 assert_eq!(error.to_string(), "legacy connector error");
171 }
172
173 #[tokio::test]
174 async fn connector_service_preserves_classified_errors() {
175 let error = ClassifiedFailingConnector.connect(()).await.unwrap_err();
176
177 assert_eq!(error.domain(), ConnectionErrorDomain::Transport);
178 assert_eq!(error.kind(), ConnectionErrorKind::Unavailable);
179 assert_eq!(error.to_string(), "legacy connector error");
180 }
181
182 #[tokio::test]
183 async fn connector_service_preserves_successful_input() {
184 let established = SuccessfulConnector.connect(42).await.unwrap();
185
186 assert_eq!(established.input, 42);
187 }
188}