Skip to main content

mise_client/
mise.rs

1use http::Request;
2use http_by_chunks::{ConverterTo, HttpByChunks};
3use serde_json::Value;
4use std::{
5    io::{Read, Write},
6    net::{SocketAddr, TcpStream},
7};
8
9#[derive(Debug)]
10pub enum ClientError {
11    StatusCode(u16),
12    Io(std::io::Error),
13    Http(http::Error),
14    Serde(serde_json::Error),
15}
16
17impl From<std::io::Error> for ClientError {
18    fn from(value: std::io::Error) -> Self {
19        Self::Io(value)
20    }
21}
22
23impl From<http::Error> for ClientError {
24    fn from(value: http::Error) -> Self {
25        Self::Http(value)
26    }
27}
28
29impl From<serde_json::Error> for ClientError {
30    fn from(value: serde_json::Error) -> Self {
31        Self::Serde(value)
32    }
33}
34
35pub type Result<T> = std::result::Result<T, ClientError>;
36
37/// The client for mise
38/// One instance of this will keep one connection open to the server and it
39/// will be closed once this instance is deallocated.
40///
41/// It is possible to batch requests with the plural methods (ex gets instead
42/// of get).
43pub struct Client {
44    _addr: SocketAddr,
45    socket: TcpStream,
46    static_read_buf: [u8; 4096],
47    read_buf: Vec<u8>,
48}
49
50struct JsonConverter;
51impl ConverterTo<Value> for JsonConverter {
52    fn convert(&self, buf: &[u8]) -> Value {
53        serde_json::from_slice(buf).unwrap_or(Value::Null)
54    }
55}
56
57static JSON_CONVERTER: JsonConverter = JsonConverter;
58
59impl Client {
60    /// Creates a new client by connecting to a server.
61    /// Every client instance is one connection.
62    ///
63    /// # Errors
64    ///
65    /// Errors if connection cannot be established.
66    pub fn connect(addr: SocketAddr) -> Result<Self> {
67        let socket = TcpStream::connect(addr)?;
68        Ok(Self {
69            _addr: addr,
70            socket,
71            static_read_buf: [0; 4096],
72            read_buf: Vec::new(),
73        })
74    }
75
76    /// Sends a normal GET request.
77    ///
78    /// # Errors
79    ///
80    /// Errors if request fails
81    pub fn get(&mut self, uri: &str) -> Result<Value> {
82        self.do_no_body("GET", uri)
83    }
84
85    /// Sends a batch of GET requests sent all at once.
86    ///
87    /// First writes all the requests in the pipe before starting to read back
88    /// the first response. Effectively this is a batching mode since there is
89    /// no waiting between sends.
90    ///
91    /// When batching, consider that if the send buffer is full this may block
92    /// undefinetly as it won't read the first response until all requests are
93    /// sent first. This means that the batch number cannot be arbitrarly high
94    /// but there is a virtual limit that will trigger this behavior and then
95    /// rend this method stuck in wait mode while trying to write to a full
96    /// buffer.
97    ///
98    /// # Errors
99    ///
100    /// Errors if request fails
101    pub fn gets<const X: usize>(&mut self, uris: &[&str; X]) -> Result<[Option<Result<Value>>; X]> {
102        self.do_no_bodys("GET", uris)
103    }
104
105    /// Sends a DELETE request.
106    ///
107    /// # Errors
108    ///
109    /// Errors if request fails
110    pub fn delete(&mut self, uri: &str) -> Result<Value> {
111        self.do_no_body("DELETE", uri)
112    }
113
114    /// Batches a DELETE set of requests. For batching, see [`Self::gets`]
115    ///
116    /// # Errors
117    ///
118    /// Errors if request fails
119    pub fn deletes<const X: usize>(
120        &mut self,
121        uris: &[&str; X],
122    ) -> Result<[Option<Result<Value>>; X]> {
123        self.do_no_bodys("DELETE", uris)
124    }
125
126    /// Sends a POST request.
127    ///
128    /// # Errors
129    ///
130    /// Errors if request fails
131    pub fn post(&mut self, uri: &str, value: Value) -> Result<Value> {
132        self.do_body("POST", uri, value)
133    }
134
135    /// Batches a POST set of requests. For batching, see [`Self::gets`]
136    ///
137    /// # Errors
138    ///
139    /// Errors if request fails
140    pub fn posts<const X: usize>(
141        &mut self,
142        uris: &[&str; X],
143        values: &[Value; X],
144    ) -> Result<[Option<Result<Value>>; X]> {
145        self.do_bodys("POST", uris, values)
146    }
147
148    /// Sends a PUT request.
149    ///
150    /// # Errors
151    ///
152    /// Errors if request fails
153    pub fn put(&mut self, uri: &str, value: Value) -> Result<Value> {
154        self.do_body("PUT", uri, value)
155    }
156
157    /// Batches a PUT set of requests. For batching, see [`Self::gets`]
158    ///
159    /// # Errors
160    ///
161    /// Errors if request fails
162    pub fn puts<const X: usize>(
163        &mut self,
164        uris: &[&str; X],
165        values: &[Value; X],
166    ) -> Result<[Option<Result<Value>>; X]> {
167        self.do_bodys("PUT", uris, values)
168    }
169
170    /// Sends a PATCH request.
171    ///
172    /// # Errors
173    ///
174    /// Errors if request fails
175    pub fn patch(&mut self, uri: &str, value: Value) -> Result<Value> {
176        self.do_body("PATCH", uri, value)
177    }
178
179    /// Batches a PATCH set of requests. For batching, see [`Self::gets`]
180    ///
181    /// # Errors
182    ///
183    /// Errors if request fails
184    pub fn patches<const X: usize>(
185        &mut self,
186        uris: &[&str; X],
187        values: &[Value; X],
188    ) -> Result<[Option<Result<Value>>; X]> {
189        self.do_bodys("PATCH", uris, values)
190    }
191
192    fn do_no_body(&mut self, method: &str, uri: &str) -> Result<Value> {
193        let req = Request::builder()
194            .method(method)
195            .uri(uri)
196            .body(Value::Null)?;
197        self.send_request(&req)?;
198        self.read_response()
199    }
200
201    fn do_no_bodys<const X: usize>(
202        &mut self,
203        method: &str,
204        uris: &[&str; X],
205    ) -> Result<[Option<Result<Value>>; X]> {
206        let mut res = [const { None }; X];
207        for uri in uris {
208            let req = Request::builder()
209                .method(method)
210                .uri(*uri)
211                .body(Value::Null)?;
212            self.send_request(&req)?;
213        }
214        (0..uris.len()).for_each(|x| {
215            res[x] = Some(self.read_response());
216        });
217        Ok(res)
218    }
219
220    fn do_body(&mut self, method: &str, uri: &str, value: Value) -> Result<Value> {
221        let req = Request::builder().method(method).uri(uri).body(value)?;
222        self.send_request(&req)?;
223        self.read_response()
224    }
225
226    fn do_bodys<const X: usize>(
227        &mut self,
228        method: &str,
229        uris: &[&str; X],
230        values: &[Value; X],
231    ) -> Result<[Option<Result<Value>>; X]> {
232        let mut res = [const { None }; X];
233        for i in 0..uris.len() {
234            let req = Request::builder()
235                .method(method)
236                .uri(uris[i])
237                .body(values[i].clone())?;
238            self.send_request(&req)?;
239        }
240        (0..uris.len()).for_each(|x| {
241            res[x] = Some(self.read_response());
242        });
243        Ok(res)
244    }
245
246    fn send_request(&mut self, req: &Request<Value>) -> Result<()> {
247        self.socket.write_all(&req_to_bytes(req))?;
248        Ok(())
249    }
250
251    fn read_response(&mut self) -> Result<Value> {
252        let mut c = HttpByChunks::<Value>::new(&JSON_CONVERTER);
253        loop {
254            let n = self.socket.read(&mut self.static_read_buf)?;
255            self.read_buf.extend_from_slice(&self.static_read_buf[..n]);
256            self.read_buf = c.append(&self.read_buf).to_vec();
257            if let Some(resp) = c.build_response() {
258                let mut resp = resp?;
259                if !resp.status().is_success() {
260                    return Err(ClientError::StatusCode(resp.status().as_u16()));
261                }
262                return Ok(resp.body_mut().take());
263            }
264        }
265    }
266}
267
268fn req_to_bytes(req: &Request<Value>) -> Vec<u8> {
269    let mut res = vec![];
270    res.extend_from_slice(format!("{} {} HTTP/1.1\r\n", req.method(), req.uri()).as_bytes());
271    if *req.body() == Value::Null {
272        res.extend_from_slice("\r\n".to_string().as_bytes());
273    } else if let Ok(b) = serde_json::to_vec(req.body()) {
274        res.extend_from_slice(format!("Content-Length: {}\r\n\r\n", b.len()).as_bytes());
275        res.extend_from_slice(&b);
276    }
277    res
278}