use qx_rs_err::err::*;
use std::{collections::HashMap, fmt::Debug};
use reqwest::{self, header::CONTENT_TYPE};
#[derive(Debug, Clone)]
pub enum Method {
Get,
Post,
Put,
Patch,
Delete,
Copy,
Head,
Options,
Link,
Unlink,
Purge,
Lock,
Unlock,
PropFind,
View,
Other(&'static str),
}
#[derive(Debug, Clone)]
pub enum Body<'a> {
ApplicationJson(&'a str),
XwwwFormUrlEncoded(HashMap<String, String>),
MultipartFormData(HashMap<String, MultipartFormValue<'a>>),
ApplicationXml(&'a str),
ApplicationJavascript(&'a str),
TextPlain(&'a str),
TextHtml(&'a str),
Other(&'a str, &'a str),
Raw(&'a str),
}
pub struct Request<'a> {
pub url: &'a str,
pub method: Method,
pub querys: Option<HashMap<String, String>>,
pub headers: Option<HashMap<String, String>>,
pub body: Option<Body<'a>>,
}
impl <'a> Request<'a> {
pub fn new(url: &'a str, method: Method) -> Self {
Request { url, method, headers: None, querys: None, body: None }
}
pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
self.headers = Some(headers);
self
}
pub fn querys(mut self, querys: HashMap<String, String>) -> Self {
self.querys = Some(querys);
self
}
pub fn body(mut self, body: Body<'a>) -> Self {
self.body = Some(body);
self
}
}
impl <'a> Request<'a> {
pub async fn fetch_bytes(&self) -> Result<bytes::Bytes> {
let resp = _fetch(self).await?;
let bytes = resp.bytes().await.map_err(|err| {
Error::error(Box::new(err))
})?;
Ok(bytes)
}
pub async fn fetch_text(&self) -> Result<String> {
let resp = _fetch(self).await?;
let text = resp.text().await.map_err(|err| {
Error::error(Box::new(err))
})?;
Ok(text)
}
}
pub fn request<'a>(url: &'a str, method: Method) -> Request<'a> {
Request::new(url, method)
}
#[derive(Debug, Clone)]
pub enum MultipartFormValue<'a> {
Text(&'a str),
File(MultipartFormFile<'a>)
}
#[derive(Debug, Clone)]
pub struct MultipartFormFile<'a> {
pub file_name: &'a str,
pub mine: &'a str,
pub file_path: &'a str,
}
impl <'a> MultipartFormFile<'a> {
pub fn new(file_name: &'a str, mine: &'a str, file_path: &'a str) -> Self {
Self {
file_name,
mine,
file_path
}
}
}
fn _method<'a>(method: Method) -> &'a str {
match method {
Method::Get => "GET",
Method::Post => "POST",
Method::Put => "PUT",
Method::Patch => "PATCH",
Method::Delete => "DELETE",
Method::Copy => "COPY",
Method::Head => "HEAD",
Method::Options => "OPTIONS",
Method::Link => "LINK",
Method::Unlink => "UNLINK",
Method::Purge => "PURGE",
Method::Lock => "LOCK",
Method::Unlock => "UNLOCK",
Method::PropFind => "PROPFIND",
Method::View => "VIEW",
Method::Other(m) => m,
}
}
async fn _fetch<'a>(request: &Request<'a>) -> Result<reqwest::Response> {
let client = reqwest::Client::builder().build().map_err(|err| {
Error::error(Box::new(err))
})?;
let url = reqwest::Url::parse(request.url).map_err(|err| {
Error::error(Box::new(err))
})?;
let method = reqwest::Method::from_bytes(_method(request.method.clone()).as_bytes()).map_err(|err| {
Error::error(Box::new(err))
})?;
let mut req = client.request(method, url);
if let Some(hs) = &request.headers {
for (k, v) in hs {
req = req.header(k, v);
}
}
if let Some(b) = &request.body {
match b {
Body::ApplicationJson(json) => {
req = req.header(CONTENT_TYPE, "application/json");
req = req.body(json.to_string());
},
Body::XwwwFormUrlEncoded(f) => {
req = req.form(&f);
},
Body::MultipartFormData(ms) => {
let form = _multipart_form(ms).await?;
req = req.multipart(form);
},
Body::ApplicationXml(xml) => {
req = req.header(CONTENT_TYPE, "application/xml");
req = req.body(xml.to_string());
},
Body::ApplicationJavascript(js) => {
req = req.header(CONTENT_TYPE, "application/javascript");
req = req.body(js.to_string());
},
Body::TextPlain(t) => {
req = req.header(CONTENT_TYPE, "text/plain");
req = req.body(t.to_string());
},
Body::TextHtml(h) => {
req = req.header(CONTENT_TYPE, "text/html");
req = req.body(h.to_string());
},
Body::Other(h, t) => {
req = req.header(CONTENT_TYPE, h.to_string());
req = req.body(t.to_string());
},
Body::Raw(t) => {
req = req.body(t.to_string());
},
}
}
let resp = req.send().await.map_err(|err| {
Error::error(Box::new(err))
})?;
Ok(resp)
}
async fn _multipart_form<'a>(multipart_form: &HashMap<String, MultipartFormValue<'a>>) -> Result<reqwest::multipart::Form> {
let mut form = reqwest::multipart::Form::new();
for (k, v) in multipart_form {
let k = k.clone();
match v {
MultipartFormValue::Text(t) => {
form = form.text(k, t.to_string());
},
MultipartFormValue::File(f) => {
let mut p = reqwest::multipart::Part::file(f.file_path.to_string()).await.map_err(|err| {
Error::error(Box::new(err))
})?;
p = p.file_name(f.file_name.to_string());
p = p.mime_str(f.mine).map_err(|err| {
Error::error(Box::new(err))
})?;
form = form.part(k, p);
},
}
}
Ok(form)
}