use reqwest::blocking::{Body, Client, RequestBuilder, Response};
use reqwest::header::HeaderMap;
use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
use std::time::Duration;
pub use reqwest::Method;
#[allow(rustdoc::bare_urls)]
pub struct Request {
url: String,
method: Method,
inner: Option<Client>,
headers: HashMap<String, String>,
error: String,
timeout: f32,
gzip: bool,
}
pub struct Data {
status: u16,
data: String,
headers: HashMap<String, String>,
}
fn get_headers(input: &HeaderMap) -> HashMap<String, String> {
let mut headers: HashMap<String, String> = HashMap::new();
for (key, value) in input {
let k = String::from(key.as_str());
let v = String::from(value.to_str().unwrap_or(""));
headers.insert(k, v);
}
return headers;
}
impl fmt::Debug for Request {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Request")
.field("method", &self.method)
.field("url", &self.url)
.field("headers", &self.headers)
.finish()
}
}
impl Request {
pub fn new<T: AsRef<str>>(method: Method, url: T) -> Self {
return Self {
url: url.as_ref().to_string(),
method: method,
inner: None,
headers: HashMap::new(),
error: "".into(),
timeout: 10.0,
gzip: false,
};
}
pub fn gzip(&mut self, zip: bool) -> &mut Self {
self.gzip = zip;
return self;
}
pub fn timeout(&mut self, seconds: f32) -> &mut Self {
self.timeout = seconds;
return self;
}
pub fn header<K: Into<String>>(&mut self, key: K, value: K) -> &mut Self {
self.headers.insert(key.into(), value.into());
return self;
}
fn build(&self) -> RequestBuilder {
let c = self.inner.as_ref().unwrap();
let mut x = c.request(self.method.clone(), self.url.clone());
for (key, value) in &self.headers {
x = x.header(key, value);
}
return x;
}
pub fn send<DATA: Into<Body>, F: FnMut(Data)>(&mut self, data: DATA, mut f: F) -> i32 {
let duration = Duration::from_millis((self.timeout * 1000.0) as u64);
if self.inner.is_none() {
let c = Client::builder()
.gzip(self.gzip)
.timeout(duration)
.build();
match c {
Ok(client) => {
self.inner = Some(client);
}
Err(e) => {
self.error = e.to_string();
return -1;
}
}
}
let mut x = self.build();
x = x.body(data);
let ret = x.send();
if let Err(e) = ret {
self.error = e.to_string();
return -1;
}
let response = ret.unwrap();
let status = response.status().as_u16();
let headers = get_headers(response.headers());
let t = response.text();
if let Err(e) = t {
self.error = e.to_string();
return -1;
}
let upcall = Data {
status: status,
data: t.unwrap(),
headers: headers,
};
f(upcall);
return 0;
}
}
impl Data {
pub fn status(&self) -> u16 {
return self.status;
}
pub fn text(&self) -> &String {
return &self.data;
}
pub fn json(&self) -> serde_json::Value {
let value = serde_json::Value::from_str(self.data.as_str());
return value.unwrap_or(serde_json::Value::Null);
}
pub fn headers(&self) -> &HashMap<String, String> {
return &self.headers;
}
}
pub fn get<URL, F>(url: URL, mut f: F)
where
URL: AsRef<str>,
F: FnMut(Data),
{
let g = || -> Result<Response, Box<dyn std::error::Error>> {
let client = Client::builder().gzip(true).build()?;
let ret = client.get(url.as_ref()).send()?;
return Ok(ret);
};
let mut data = Data {
status: 522,
data: "".to_string(),
headers: HashMap::new(),
};
if let Ok(response) = g() {
data.status = response.status().as_u16();
data.headers = get_headers(response.headers());
data.data = response.text().unwrap_or("".to_string());
}
f(data);
}
pub fn post<URL, BODY, F>(url: URL, body: BODY, mut f: F)
where
URL: AsRef<str>,
BODY: Into<Body> + AsRef<[u8]>,
F: FnMut(Data),
{
let g = |x: BODY| -> Result<Response, Box<dyn std::error::Error>> {
let zip = x.as_ref().len() > 1024;
let client = Client::builder().gzip(zip).build()?;
let ret = client.post(url.as_ref()).body(x).send()?;
return Ok(ret);
};
let mut data = Data {
status: 522,
data: "".to_string(),
headers: HashMap::new(),
};
if let Ok(response) = g(body) {
data.status = response.status().as_u16();
data.headers = get_headers(response.headers());
data.data = response.text().unwrap_or("".to_string());
}
f(data);
}