1use reqwest::blocking::{Body, Client, RequestBuilder, Response};
3use reqwest::header::HeaderMap;
4use std::collections::HashMap;
5use std::fmt;
6use std::str::FromStr;
7use std::time::Duration;
8
9pub use reqwest::Method;
10
11#[allow(rustdoc::bare_urls)]
12
13pub struct Request {
29 url: String,
30 method: Method,
31 inner: Option<Client>,
32 headers: HashMap<String, String>,
33 error: String,
34 timeout: f32,
35 gzip: bool,
36}
37
38pub struct Data {
39 status: u16,
40 data: String,
41 headers: HashMap<String, String>,
42}
43
44fn get_headers(input: &HeaderMap) -> HashMap<String, String> {
45 let mut headers: HashMap<String, String> = HashMap::new();
46 for (key, value) in input {
47 let k = String::from(key.as_str());
48 let v = String::from(value.to_str().unwrap_or(""));
49 headers.insert(k, v);
50 }
51
52 return headers;
53}
54
55impl fmt::Debug for Request {
56 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57 f.debug_struct("Request")
58 .field("method", &self.method)
59 .field("url", &self.url)
60 .field("headers", &self.headers)
61 .finish()
62 }
63}
64
65impl Request {
66 pub fn new<T: AsRef<str>>(method: Method, url: T) -> Self {
67 return Self {
68 url: url.as_ref().to_string(),
69 method: method,
70 inner: None,
71 headers: HashMap::new(),
72 error: "".into(),
73 timeout: 10.0,
74 gzip: false,
75 };
76 }
77
78 pub fn gzip(&mut self, zip: bool) -> &mut Self {
80 self.gzip = zip;
81 return self;
82 }
83
84 pub fn timeout(&mut self, seconds: f32) -> &mut Self {
86 self.timeout = seconds;
87 return self;
88 }
89
90 pub fn header<K: Into<String>>(&mut self, key: K, value: K) -> &mut Self {
92 self.headers.insert(key.into(), value.into());
93 return self;
94 }
95
96 fn build(&self) -> RequestBuilder {
97 let c = self.inner.as_ref().unwrap();
98 let mut x = c.request(self.method.clone(), self.url.clone());
99 for (key, value) in &self.headers {
100 x = x.header(key, value);
101 }
102 return x;
103 }
104
105 pub fn send<DATA: Into<Body>, F: FnMut(Data)>(&mut self, data: DATA, mut f: F) -> i32 {
107 let duration = Duration::from_millis((self.timeout * 1000.0) as u64);
108 if self.inner.is_none() {
110 let c = Client::builder()
111 .gzip(self.gzip)
112 .timeout(duration)
113 .build();
114 match c {
115 Ok(client) => {
116 self.inner = Some(client);
117 }
118 Err(e) => {
119 self.error = e.to_string();
120 return -1;
121 }
122 }
123 }
124
125 let mut x = self.build();
127 x = x.body(data);
128
129 let ret = x.send();
131 if let Err(e) = ret {
132 self.error = e.to_string();
133 return -1;
134 }
135
136 let response = ret.unwrap();
137 let status = response.status().as_u16();
138 let headers = get_headers(response.headers());
139
140 let t = response.text();
142 if let Err(e) = t {
143 self.error = e.to_string();
144 return -1;
145 }
146
147 let upcall = Data {
148 status: status,
149 data: t.unwrap(),
150 headers: headers,
151 };
152
153 f(upcall);
154
155 return 0;
156 }
157}
158
159impl Data {
160 pub fn status(&self) -> u16 {
162 return self.status;
163 }
164
165 pub fn text(&self) -> &String {
167 return &self.data;
168 }
169
170 pub fn json(&self) -> serde_json::Value {
172 let value = serde_json::Value::from_str(self.data.as_str());
173 return value.unwrap_or(serde_json::Value::Null);
174 }
175
176 pub fn headers(&self) -> &HashMap<String, String> {
178 return &self.headers;
179 }
180}
181
182pub fn get<URL, F>(url: URL, mut f: F)
192where
193 URL: AsRef<str>,
194 F: FnMut(Data),
195{
196 let g = || -> Result<Response, Box<dyn std::error::Error>> {
197 let client = Client::builder().gzip(true).build()?;
198 let ret = client.get(url.as_ref()).send()?;
199 return Ok(ret);
200 };
201
202 let mut data = Data {
204 status: 522,
205 data: "".to_string(),
206 headers: HashMap::new(),
207 };
208
209 if let Ok(response) = g() {
210 data.status = response.status().as_u16();
211 data.headers = get_headers(response.headers());
212 data.data = response.text().unwrap_or("".to_string());
213 }
214
215 f(data);
217}
218
219pub fn post<URL, BODY, F>(url: URL, body: BODY, mut f: F)
229where
230 URL: AsRef<str>,
231 BODY: Into<Body> + AsRef<[u8]>,
232 F: FnMut(Data),
233{
234 let g = |x: BODY| -> Result<Response, Box<dyn std::error::Error>> {
235 let zip = x.as_ref().len() > 1024;
237 let client = Client::builder().gzip(zip).build()?;
238 let ret = client.post(url.as_ref()).body(x).send()?;
239 return Ok(ret);
240 };
241
242 let mut data = Data {
244 status: 522,
245 data: "".to_string(),
246 headers: HashMap::new(),
247 };
248
249 if let Ok(response) = g(body) {
250 data.status = response.status().as_u16();
251 data.headers = get_headers(response.headers());
252 data.data = response.text().unwrap_or("".to_string());
253 }
254
255 f(data);
257}