galata_vault/client/
transport.rs1use std::sync::Arc;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum Method {
9 Get,
11 Put,
13 Post,
15 Delete,
17}
18
19impl Method {
20 pub fn as_str(self) -> &'static str {
22 match self {
23 Method::Get => "GET",
24 Method::Put => "PUT",
25 Method::Post => "POST",
26 Method::Delete => "DELETE",
27 }
28 }
29}
30
31impl std::fmt::Display for Method {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 f.write_str(self.as_str())
34 }
35}
36
37#[derive(Clone, Copy)]
45#[non_exhaustive]
46pub struct Request<'a> {
47 pub method: Method,
49 pub path_and_query: &'a str,
52 pub if_match: Option<&'a str>,
54 pub if_none_match: Option<&'a str>,
56 pub authorization: Option<&'a str>,
59 pub body: Option<&'a [u8]>,
61}
62
63impl<'a> Request<'a> {
64 pub fn new(method: Method, path_and_query: &'a str) -> Request<'a> {
68 Request {
69 method,
70 path_and_query,
71 if_match: None,
72 if_none_match: None,
73 authorization: None,
74 body: None,
75 }
76 }
77
78 pub fn with_authorization(mut self, authorization: Option<&'a str>) -> Request<'a> {
80 self.authorization = authorization;
81 self
82 }
83
84 pub fn with_body(mut self, body: Option<&'a [u8]>) -> Request<'a> {
86 self.body = body;
87 self
88 }
89
90 pub fn with_if_match(mut self, if_match: Option<&'a str>) -> Request<'a> {
92 self.if_match = if_match;
93 self
94 }
95
96 pub fn with_if_none_match(mut self, if_none_match: Option<&'a str>) -> Request<'a> {
98 self.if_none_match = if_none_match;
99 self
100 }
101}
102
103impl std::fmt::Debug for Request<'_> {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 f.debug_struct("Request")
106 .field("method", &self.method)
107 .field("path_and_query", &self.path_and_query)
108 .field("if_match", &self.if_match)
109 .field("if_none_match", &self.if_none_match)
110 .field("authorized", &self.authorization.is_some())
111 .field("body_len", &self.body.map(<[u8]>::len))
112 .finish()
113 }
114}
115
116#[derive(Clone, PartialEq, Eq)]
119#[non_exhaustive]
120pub struct Response {
121 pub status: u16,
123 pub etag: Option<String>,
125 pub expires_at: Option<String>,
127 pub body: Vec<u8>,
129}
130
131impl Response {
132 pub fn new(status: u16, body: impl Into<Vec<u8>>) -> Response {
134 Response {
135 status,
136 etag: None,
137 expires_at: None,
138 body: body.into(),
139 }
140 }
141
142 pub fn with_etag(mut self, etag: impl Into<String>) -> Response {
144 self.etag = Some(etag.into());
145 self
146 }
147
148 pub fn with_expires_at(mut self, expires_at: impl Into<String>) -> Response {
150 self.expires_at = Some(expires_at.into());
151 self
152 }
153}
154
155impl std::fmt::Debug for Response {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 f.debug_struct("Response")
158 .field("status", &self.status)
159 .field("etag", &self.etag)
160 .field("expires_at", &self.expires_at)
161 .field("body_len", &self.body.len())
162 .finish()
163 }
164}
165
166#[derive(Debug, Clone)]
170pub struct TransportError {
171 server: String,
172 message: String,
173 source: Option<Arc<dyn std::error::Error + Send + Sync>>,
174}
175
176impl TransportError {
177 pub fn new(server: impl Into<String>, message: impl Into<String>) -> TransportError {
179 TransportError {
180 server: server.into(),
181 message: message.into(),
182 source: None,
183 }
184 }
185
186 pub fn with_source(
189 server: impl Into<String>,
190 source: impl std::error::Error + Send + Sync + 'static,
191 ) -> TransportError {
192 TransportError {
193 server: server.into(),
194 message: source.to_string(),
195 source: Some(Arc::new(source)),
196 }
197 }
198
199 pub fn server(&self) -> &str {
201 &self.server
202 }
203
204 pub fn message(&self) -> &str {
206 &self.message
207 }
208
209 pub fn cause(&self) -> Option<Arc<dyn std::error::Error + Send + Sync>> {
211 self.source.clone()
212 }
213}
214
215impl std::fmt::Display for TransportError {
216 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
217 write!(f, "could not reach {}: {}", self.server, self.message)
218 }
219}
220
221impl std::error::Error for TransportError {
222 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
223 self.source
224 .as_deref()
225 .map(|e| e as &(dyn std::error::Error + 'static))
226 }
227}
228
229pub trait Transport: Send + Sync {
234 fn send(&self, request: Request<'_>) -> Result<Response, TransportError>;
237}
238
239impl<T: Transport + ?Sized> Transport for Arc<T> {
240 fn send(&self, request: Request<'_>) -> Result<Response, TransportError> {
241 (**self).send(request)
242 }
243}
244
245impl<T: Transport + ?Sized> Transport for Box<T> {
246 fn send(&self, request: Request<'_>) -> Result<Response, TransportError> {
247 (**self).send(request)
248 }
249}