#[cfg(feature = "proxy")]
use crate::component::proxy::{Auth, AuthBasic, AuthBearer, AuthCustom, Proxy};
use crate::plugin::deser::*;
use crate::utils;
use crate::{
component::{Body, Info, Parsed},
Response,
};
use http::{
header::HeaderName, method::Method, version::Version, Extensions, HeaderMap, HeaderValue, Uri,
};
use serde::{Deserialize, Serialize};
use std::collections::{hash_map::DefaultHasher, BinaryHeap};
use std::hash::{Hash, Hasher};
use std::convert::TryFrom;
use std::{fmt, mem};
#[derive(Deserialize, Default, Serialize)]
pub struct Task {
pub(crate) inner: InnerTask,
pub(crate) body: Body,
pub(crate) metat: MetaTask,
#[cfg(feature = "proxy")]
pub(crate) proxy: Option<Proxy>,
}
impl fmt::Debug for Task {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut fmter = f.debug_struct("Task");
fmter
.field("uri", self.uri())
.field("method", self.method())
.field("version", &self.version())
.field("headers", &self.headers())
.field("body", &self.body())
.field("metat", &self.metat);
#[cfg(feature = "proxy")]
fmter.field("proxy", &self.proxy);
fmter.finish()
}
}
#[derive(Deserialize, Default, fmt::Debug, Serialize)]
pub struct InnerTask {
#[serde(with = "serde_uri")]
pub uri: Uri,
#[serde(with = "serde_version")]
pub version: Version,
#[serde(with = "serde_method")]
pub method: Method,
#[serde(with = "serde_headermap")]
pub headers: HeaderMap<HeaderValue>,
#[serde(skip)]
pub extensions: Extensions,
}
impl Hash for InnerTask {
fn hash<H: Hasher>(&self, state: &mut H) {
let mut heap: BinaryHeap<(&str, &str)> = BinaryHeap::new();
self.uri.hash(state);
self.method.hash(state);
self.headers.iter().for_each(|(k, v)| {
heap.push((k.as_str(), v.to_str().unwrap()));
});
while let Some((k, v)) = heap.pop() {
k.hash(state);
v.hash(state);
}
}
}
unsafe impl Send for Task {}
unsafe impl Sync for Task {}
impl InnerTask {
pub fn new() -> Self {
Self {
uri: Uri::default(),
method: Method::default(),
version: Version::default(),
headers: HeaderMap::default(),
extensions: Extensions::default(),
}
}
}
#[derive(Deserialize, Serialize)]
pub struct MetaTask {
pub info: Info,
#[serde(serialize_with = "serde_fn::serfn")]
#[serde(deserialize_with = "serde_fn::defn")]
pub(crate) parser: *const (),
#[serde(serialize_with = "serde_fn::serfn_op")]
#[serde(deserialize_with = "serde_fn::defn_op")]
pub(crate) err_parser: Option<*const ()>,
#[serde(skip)]
pub exts: Extensions,
}
impl Hash for MetaTask {
fn hash<H: Hasher>(&self, state: &mut H) {
self.info.used.hash(state);
self.info.marker.hash(state);
self.parser.hash(state);
self.err_parser.hash(state);
}
}
impl MetaTask {
pub fn new() -> Self {
Self {
info: Info::default(),
parser: 0 as *const (),
err_parser: None,
exts: Extensions::new(),
}
}
}
impl fmt::Debug for MetaTask {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut parser = "Unknow_or_KnownButUnset";
let mut err_parser = None;
if let Some((n, _)) = serde_fn::query(None, Some(self.parser)) {
parser = n;
}
if self.err_parser.is_some() {
if let Some((n, _)) = serde_fn::query(None, self.err_parser) {
err_parser = Some(n);
}
}
f.debug_struct("MetaTask")
.field("info", &self.info)
.field("parser", &parser)
.field("err_parser", &err_parser)
.field("exts", &self.exts)
.finish()
}
}
impl Default for MetaTask {
fn default() -> Self {
Self {
info: Info::default(),
parser: 0 as *const (),
err_parser: None,
exts: Extensions::new(),
}
}
}
impl Task {
pub fn builder() -> TaskBuilder {
TaskBuilder::new()
}
}
impl Task {
pub fn get<'a, S>(uri: S) -> TaskBuilder
where
Uri: TryFrom<S>,
<Uri as TryFrom<S>>::Error: Into<http::Error>,
{
TaskBuilder::new().method(Method::GET).uri(uri)
}
pub fn post<'a, S>(uri: S) -> TaskBuilder
where
Uri: TryFrom<S>,
<Uri as TryFrom<S>>::Error: Into<http::Error>,
{
TaskBuilder::new().method(Method::POST).uri(uri)
}
pub fn put<'a, S>(uri: S) -> TaskBuilder
where
Uri: TryFrom<S>,
<Uri as TryFrom<S>>::Error: Into<http::Error>,
{
TaskBuilder::new().method(Method::PUT).uri(uri)
}
pub fn connect<'a, S>(uri: S) -> TaskBuilder
where
Uri: TryFrom<S>,
<Uri as TryFrom<S>>::Error: Into<http::Error>,
{
TaskBuilder::new().method(Method::CONNECT).uri(uri)
}
pub fn delete<'a, S>(uri: S) -> TaskBuilder
where
Uri: TryFrom<S>,
<Uri as TryFrom<S>>::Error: Into<http::Error>,
{
TaskBuilder::new().method(Method::DELETE).uri(uri)
}
pub fn head<'a, S>(uri: S) -> TaskBuilder
where
Uri: TryFrom<S>,
<Uri as TryFrom<S>>::Error: Into<http::Error>,
{
TaskBuilder::new().method(Method::HEAD).uri(uri)
}
pub fn options<'a, S>(uri: S) -> TaskBuilder
where
Uri: TryFrom<S>,
<Uri as TryFrom<S>>::Error: Into<http::Error>,
{
TaskBuilder::new().method(Method::OPTIONS).uri(uri)
}
pub fn patch<S>(uri: S) -> TaskBuilder
where
Uri: TryFrom<S>,
<Uri as TryFrom<S>>::Error: Into<http::Error>,
{
TaskBuilder::new().method(Method::PATCH).uri(uri)
}
pub fn trace<'a, S>(uri: S) -> TaskBuilder
where
Uri: TryFrom<S>,
<Uri as TryFrom<S>>::Error: Into<http::Error>,
{
TaskBuilder::new().method(Method::TRACE).uri(uri)
}
#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
#[cfg(feature = "proxy")]
pub fn proxy_mut(&mut self) -> Option<&mut Proxy> {
self.proxy.as_mut()
}
#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
#[cfg(feature = "proxy")]
pub fn proxy(&self) -> Option<&Proxy> {
self.proxy.as_ref()
}
}
impl Task {
pub fn uri(&self) -> &Uri {
&self.inner.uri
}
pub fn method(&self) -> &Method {
&self.inner.method
}
pub fn headers(&self) -> &HeaderMap<HeaderValue> {
&self.inner.headers
}
pub fn version(&self) -> Version {
self.inner.version
}
pub fn exts(&self) -> &Extensions {
&self.metat.exts
}
pub fn extensions(&self) -> &Extensions {
&self.inner.extensions
}
pub fn parser<E>(&self) -> fn(Response) -> Parsed<E>
where
E: Serialize + Clone,
{
let f =
unsafe { mem::transmute::<*const (), fn(Response) -> Parsed<E>>(self.metat.parser) };
f
}
pub fn err_parser<E>(&self) -> fn(Response) -> Parsed<E>
where
E: Serialize + Clone,
{
let f =
unsafe { mem::transmute::<*const (), fn(Response) -> Parsed<E>>(self.metat.parser) };
f
}
pub fn rank(&self) -> i16 {
self.metat.info.rank
}
pub fn rank_mut(&mut self) -> &mut i16 {
&mut self.metat.info.rank
}
pub fn info(&self) -> &Info {
&self.metat.info
}
pub fn body(&self) -> &Body {
&self.body
}
pub fn uri_mut(&mut self) -> &mut Uri {
&mut self.inner.uri
}
pub fn method_mut(&mut self) -> &mut Method {
&mut self.inner.method
}
pub fn headers_mut(&mut self) -> &mut HeaderMap<HeaderValue> {
&mut self.inner.headers
}
pub fn version_mut(&mut self) -> &mut Version {
&mut self.inner.version
}
pub fn exts_mut(&mut self) -> &mut Extensions {
&mut self.metat.exts
}
pub fn extension_mut(&mut self) -> &mut Extensions {
&mut self.inner.extensions
}
pub fn parser_mut<E>(&mut self, parser: fn(Response) -> Parsed<E>)
where
E: Serialize + Clone,
{
let parser = parser as *const ();
assert_ne!(0 as *const (), parser, "the parser cannot be NULL!");
self.metat.parser = parser;
}
pub fn err_parser_mut<E>(&mut self, parser: fn(Response) -> Parsed<E>)
where
E: Serialize + Clone,
{
let parser = parser as *const ();
assert_ne!(0 as *const (), parser, "the error parser cannot be NULL!");
self.metat.err_parser = Some(parser);
}
pub fn info_mut(&mut self) -> &mut Info {
&mut self.metat.info
}
pub fn body_mut(&mut self) -> &mut Body {
&mut self.body
}
pub fn into_body(self) -> Body {
self.body
}
pub fn map<F>(self, f: F) -> Task
where
F: FnOnce(Body) -> Body,
{
Task {
body: f(self.body),
metat: self.metat,
inner: self.inner,
#[cfg(feature = "proxy")]
proxy: self.proxy,
}
}
#[cfg(not(feature = "proxy"))]
pub fn from_parts(inner: InnerTask, body: Body, metat: MetaTask) -> Self {
Self { inner, body, metat }
}
#[cfg(feature = "proxy")]
pub fn from_parts(inner: InnerTask, body: Body, metat: MetaTask, proxy: Option<Proxy>) -> Self {
Self {
inner,
body,
metat,
proxy,
}
}
#[cfg(not(feature = "proxy"))]
pub fn into_parts(self) -> (InnerTask, Body, MetaTask) {
(self.inner, self.body, self.metat)
}
#[cfg(feature = "proxy")]
pub fn into_parts(self) -> (InnerTask, Body, MetaTask, Option<Proxy>) {
(self.inner, self.body, self.metat, self.proxy)
}
}
impl Hash for Task {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner.hash(state);
self.metat.hash(state);
self.body.hash(state);
}
}
pub struct TaskBuilder {
inner: InnerTask,
meta: MetaTask,
parser_set: bool,
#[cfg(feature = "proxy")]
proxy: Option<Proxy>,
}
impl TaskBuilder {
pub fn new() -> Self {
Self {
inner: InnerTask::new(),
meta: MetaTask::new(),
parser_set: false,
#[cfg(feature = "proxy")]
proxy: None,
}
}
pub fn uri<S>(mut self, uri: S) -> Self
where
Uri: TryFrom<S>,
<Uri as TryFrom<S>>::Error: Into<http::Error>,
{
self.inner.uri = TryFrom::try_from(uri)
.map_err(Into::into)
.expect("Set Uri Failed");
self
}
pub fn uri_ref(&self) -> &Uri {
&self.inner.uri
}
pub fn method<S>(mut self, method: S) -> Self
where
Method: TryFrom<S>,
<Method as TryFrom<S>>::Error: Into<http::Error>,
{
self.inner.method = TryFrom::try_from(method)
.map_err(Into::into)
.expect("Set Method Failed");
self
}
pub fn method_ref(&self) -> &Method {
&self.inner.method
}
pub fn header_ref(&self) -> &HeaderMap<HeaderValue> {
&self.inner.headers
}
pub fn header_mut(&mut self) -> &mut HeaderMap<HeaderValue> {
&mut self.inner.headers
}
pub fn header<K, V>(mut self, key: K, value: V) -> Self
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<http::Error>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
{
let k: HeaderName = TryFrom::try_from(key)
.map_err(Into::into)
.expect("Invalid Key When Setting Header");
let v: HeaderValue = TryFrom::try_from(value)
.map_err(Into::into)
.expect("Invalid Value When Setting Header");
self.inner.headers.append(k, v);
self
}
pub fn version(mut self, version: Version) -> Self {
self.inner.version = version;
self
}
pub fn version_ref(&self) -> &Version {
&self.inner.version
}
pub fn exts_ref(&self) -> &Extensions {
&self.meta.exts
}
pub fn exts_mut(&mut self) -> &mut Extensions {
&mut self.meta.exts
}
pub fn exts<S>(mut self, exts: S) -> Self
where
S: std::any::Any + Send + Sync + 'static,
{
self.meta.exts.insert(exts);
self
}
pub fn extensions_ref(&self) -> &Extensions {
&self.inner.extensions
}
pub fn extensions<S>(mut self, extension: S) -> Self
where
S: std::any::Any + Send + Sync + 'static,
{
self.inner.extensions.insert(extension);
self
}
pub fn parser_ref<E>(&self) -> fn(Response) -> Parsed<E>
where
E: Serialize + Clone,
{
let f = unsafe { mem::transmute::<*const (), fn(Response) -> Parsed<E>>(self.meta.parser) };
f
}
pub fn parser<E>(mut self, parser: fn(Response) -> Parsed<E>) -> Self {
let parser = parser as *const ();
assert_ne!(0 as *const (), parser, "the parser cannot be NULL!");
self.meta.parser = parser;
self.parser_set = true;
self
}
pub fn err_parser_ref<E>(&self) -> Option<fn(Response) -> Parsed<E>> {
if self.meta.err_parser.is_none() {
return None;
}
let f = unsafe { mem::transmute::<*const (), fn(Response) -> Parsed<E>>(self.meta.parser) };
Some(f)
}
pub fn err_parser<E>(mut self, parser: fn(Response) -> Parsed<E>) -> Self {
let parser = parser as *const ();
assert_ne!(0 as *const (), parser, "the parser cannot be NULL!");
self.meta.err_parser = Some(parser);
self
}
pub fn info_ref(&self) -> &Info {
&self.meta.info
}
pub fn info_mut(&mut self) -> &mut Info {
&mut self.meta.info
}
pub fn info(mut self, info: Info) -> Self {
self.meta.info = info;
self
}
pub fn body<R: Into<String>>(mut self, body: Body, marker: R) -> http::Result<Task> {
assert!(
self.parser_set,
"set parser is required before building the Task"
);
if self.meta.info.id == 0 {
let mut hasher = DefaultHasher::new();
self.inner.hash(&mut hasher);
self.meta.hash(&mut hasher);
body.hash(&mut hasher);
self.meta.info.id = hasher.finish();
}
if self.meta.info.from.path() == "/" {
self.meta.info.from = self.inner.uri.clone();
}
if self.meta.info.created == 0.0 {
self.meta.info.created = utils::now();
}
self.meta.info.marker = marker.into();
Ok(Task {
inner: self.inner,
metat: self.meta,
body,
#[cfg(feature = "proxy")]
proxy: self.proxy,
})
}
pub fn meta_ref(&self) -> &MetaTask {
&self.meta
}
pub fn meta(mut self, meta: MetaTask) -> Self {
self.meta = meta;
self
}
#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
#[cfg(feature = "proxy")]
pub fn proxy_mut(&mut self) -> Option<&mut Proxy> {
self.proxy.as_mut()
}
#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
#[cfg(feature = "proxy")]
pub fn proxy<T: Into<String>>(mut self, addr: T) -> Self {
self.proxy = Some(Proxy {
addr: addr.into(),
auth: None,
});
self
}
#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
#[cfg(feature = "proxy")]
pub fn proxy_auth_basic<T: Into<String>>(mut self, addr: T, username: T, password: T) {
self.proxy = Some(Proxy {
addr: addr.into(),
auth: Some(Auth::Basic(AuthBasic {
username: username.into(),
password: password.into(),
})),
});
}
#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
#[cfg(feature = "proxy")]
pub fn proxy_auth_bearer<T: Into<String>>(mut self, addr: T, bearer: T) {
self.proxy = Some(Proxy {
addr: addr.into(),
auth: Some(Auth::Bearer(AuthBearer {
bearer: bearer.into(),
})),
});
}
#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
#[cfg(feature = "proxy")]
pub fn proxy_auth_custom<T: Into<String>>(mut self, addr: T, token: T) {
self.proxy = Some(Proxy {
addr: addr.into(),
auth: Some(Auth::Custom(AuthCustom {
token: token.into(),
})),
});
}
#[cfg_attr(docsrs, doc(cfg(feature = "proxy")))]
#[cfg(feature = "proxy")]
pub fn proxy_ref(&self) -> Option<&Proxy> {
self.proxy.as_ref()
}
}