nethsm_sdk_rs/apis/
mod.rs

1use std::collections::HashMap;
2use std::error;
3use std::fmt;
4
5use base64::{engine::general_purpose, Engine};
6use serde::de::DeserializeOwned;
7
8macro_rules! create_request {
9    ($agent:expr, GET, $uri:expr) => {
10        $agent.get($uri).force_send_body()
11    };
12    ($agent:expr, POST, $uri:expr) => {
13        $agent.post($uri)
14    };
15    ($agent:expr, PUT, $uri:expr) => {
16        $agent.put($uri)
17    };
18    ($agent:expr, DELETE, $uri:expr) => {
19        $agent.delete($uri).force_send_body()
20    };
21}
22
23fn get_header_map<B>(response: &http::Response<B>) -> HashMap<String, String> {
24    let mut headers = HashMap::new();
25
26    let names = response.headers();
27    for (name, value) in names {
28        if let Ok(value) = value.to_str() {
29            headers.insert(name.as_str().into(), value.into());
30        }
31    }
32
33    headers
34}
35
36#[derive(Debug, Clone)]
37pub struct ResponseContent<T> {
38    pub status: u16,
39    pub content: Vec<u8>,
40    pub entity: T,
41    pub headers: HashMap<String, String>,
42}
43
44impl<T> ResponseContent<T> {
45    fn new<F, E>(response: http::Response<ureq::Body>, f: F) -> Result<Self, Error<E>>
46    where
47        F: FnOnce(&[u8]) -> Result<T, Error<E>>,
48    {
49        use std::io::Read;
50        let status = response.status().as_u16();
51        let headers = get_header_map(&response);
52        let mut content = Vec::new();
53        response
54            .into_body()
55            .into_reader()
56            .read_to_end(&mut content)?;
57        let entity = f(&content)?;
58        Ok(Self {
59            status,
60            content,
61            entity,
62            headers,
63        })
64    }
65}
66
67impl ResponseContent<()> {
68    fn unit<E>(response: http::Response<ureq::Body>) -> Result<Self, Error<E>> {
69        Self::new(response, |_| Ok(()))
70    }
71}
72
73impl ResponseContent<Vec<u8>> {
74    fn bytes<E>(response: http::Response<ureq::Body>) -> Result<Self, Error<E>> {
75        Self::new(response, |content| Ok(content.into()))
76    }
77}
78
79impl ResponseContent<String> {
80    fn string<E>(response: http::Response<ureq::Body>) -> Result<Self, Error<E>> {
81        Self::new(response, |content| {
82            String::from_utf8(content.into()).map_err(From::from)
83        })
84    }
85}
86
87impl<T: DeserializeOwned> ResponseContent<T> {
88    fn deserialized<E>(response: http::Response<ureq::Body>) -> Result<Self, Error<E>> {
89        Self::new(response, |content| {
90            serde_json::from_slice(content).map_err(From::from)
91        })
92    }
93}
94
95#[derive(Debug)]
96pub enum Error<T> {
97    Multipart {
98        field: Option<String>,
99        error: std::io::Error,
100    },
101    Ureq(ureq::Error),
102    Serde(serde_json::Error),
103    Io(std::io::Error),
104    ResponseError(ResponseContent<T>),
105    StringParse(std::string::FromUtf8Error),
106}
107
108impl<T> fmt::Display for Error<T> {
109    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110        let (module, e) = match self {
111            Error::Multipart { field, error } => {
112                let error = match field {
113                    Some(field) => format!("failed to encode {field}: {error}"),
114                    None => error.to_string(),
115                };
116                ("multipart", error)
117            }
118            Error::Ureq(e) => ("ureq", e.to_string()),
119            Error::Serde(e) => ("serde", e.to_string()),
120            Error::Io(e) => ("IO", e.to_string()),
121            Error::ResponseError(e) => ("response", format!("status code {}", e.status)),
122            Error::StringParse(e) => ("string", e.to_string()),
123        };
124        write!(f, "error in {}: {}", module, e)
125    }
126}
127
128impl<T: fmt::Debug> error::Error for Error<T> {
129    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
130        Some(match self {
131            Error::Multipart { error, .. } => error,
132            Error::Ureq(e) => e,
133            Error::Serde(e) => e,
134            Error::Io(e) => e,
135            Error::ResponseError(_) => return None,
136            Error::StringParse(e) => e,
137        })
138    }
139}
140
141impl<T> From<multipart::client::lazy::LazyError<'_, std::io::Error>> for Error<T> {
142    fn from(e: multipart::client::lazy::LazyError<'_, std::io::Error>) -> Self {
143        Self::Multipart {
144            field: e.field_name.map(|s| s.into_owned()),
145            error: e.error,
146        }
147    }
148}
149
150impl<T> From<ureq::Error> for Error<T> {
151    fn from(e: ureq::Error) -> Self {
152        Error::Ureq(e)
153    }
154}
155
156impl<T> From<serde_json::Error> for Error<T> {
157    fn from(e: serde_json::Error) -> Self {
158        Error::Serde(e)
159    }
160}
161
162impl<T> From<std::io::Error> for Error<T> {
163    fn from(e: std::io::Error) -> Self {
164        Error::Io(e)
165    }
166}
167
168impl<T> From<std::string::FromUtf8Error> for Error<T> {
169    fn from(e: std::string::FromUtf8Error) -> Self {
170        Error::StringParse(e)
171    }
172}
173
174pub fn urlencode<T: AsRef<str>>(s: T) -> String {
175    ::url::form_urlencoded::byte_serialize(s.as_ref().as_bytes()).collect()
176}
177
178pub fn parse_deep_object(prefix: &str, value: &serde_json::Value) -> Vec<(String, String)> {
179    if let serde_json::Value::Object(object) = value {
180        let mut params = vec![];
181
182        for (key, value) in object {
183            match value {
184                serde_json::Value::Object(_) => params.append(&mut parse_deep_object(
185                    &format!("{}[{}]", prefix, key),
186                    value,
187                )),
188                serde_json::Value::Array(array) => {
189                    for (i, value) in array.iter().enumerate() {
190                        params.append(&mut parse_deep_object(
191                            &format!("{}[{}][{}]", prefix, key, i),
192                            value,
193                        ));
194                    }
195                }
196                serde_json::Value::String(s) => {
197                    params.push((format!("{}[{}]", prefix, key), s.clone()))
198                }
199                _ => params.push((format!("{}[{}]", prefix, key), value.to_string())),
200            }
201        }
202
203        return params;
204    }
205
206    unimplemented!("Only objects are supported with style=deepObject")
207}
208
209pub(crate) fn basic_auth(auth: &configuration::BasicAuth) -> String {
210    let string = format!("{}:{}", auth.0, auth.1.as_ref().unwrap_or(&"".to_string()));
211    format!("Basic {}", general_purpose::STANDARD.encode(string)).to_string()
212}
213
214pub mod default_api;
215
216pub mod configuration;