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;