palpo_core/
sending.rs

1use std::future::Future;
2use std::ops::{Deref, DerefMut};
3
4use reqwest::{Client as ReqwestClient, ClientBuilder, Request as ReqwestRequest};
5use salvo::http::header::CONTENT_TYPE;
6use salvo::http::{HeaderName, HeaderValue, Method};
7use serde::Deserialize;
8use thiserror::Error;
9use url::{ParseError, Url};
10
11pub fn client() -> ReqwestClient {
12    ClientBuilder::new().build().unwrap()
13}
14
15#[derive(Debug)]
16pub struct SendRequest {
17    inner: ReqwestRequest,
18}
19
20#[macro_export]
21macro_rules! json_body_modifier {
22    ($name:ident) => {
23        impl crate::sending::SendModifier for $name {
24            fn modify(self, request: &mut crate::sending::SendRequest) -> Result<(), crate::sending::SendError> {
25                let bytes = serde_json::to_vec(&self)?;
26                *request.body_mut() = Some(bytes.into());
27                Ok(())
28            }
29        }
30    };
31}
32macro_rules! method {
33    ($name:ident, $method:ident) => {
34        pub fn $name(url: Url) -> SendRequest {
35            SendRequest {
36                inner: ReqwestRequest::new(Method::$method, url),
37            }
38        }
39    };
40}
41method!(get, GET);
42method!(patch, PATCH);
43method!(put, PUT);
44method!(post, POST);
45method!(delete, DELETE);
46
47#[derive(Error, Debug)]
48pub enum SendError {
49    #[error("parse url: `{0}`")]
50    Url(#[from] ParseError),
51    #[error("reqwest: `{0}`")]
52    Reqwest(#[from] reqwest::Error),
53    #[error("json: `{0}`")]
54    Json(#[from] serde_json::Error),
55    #[error("other: `{0}`")]
56    Other(String),
57}
58
59impl SendError {
60    pub fn other(msg: impl Into<String>) -> Self {
61        Self::Other(msg.into())
62    }
63}
64
65pub type SendResult<T> = Result<T, SendError>;
66
67impl SendRequest {
68    method!(get, GET);
69    method!(patch, PATCH);
70    method!(put, PUT);
71    method!(post, POST);
72    method!(delete, DELETE);
73
74    pub fn into_inner(self) -> reqwest::Request {
75        self.inner
76    }
77    pub fn stuff(mut self, modifier: impl SendModifier) -> Result<Self, SendError> {
78        modifier.modify(&mut self)?;
79        if !self.headers().contains_key(CONTENT_TYPE) {
80            self.headers_mut()
81                .insert(CONTENT_TYPE, "application/json".parse().unwrap());
82        }
83        Ok(self)
84    }
85
86    pub async fn load<R>(self) -> Result<R, SendError>
87    where
88        R: for<'de> Deserialize<'de>,
89    {
90        let res = client().execute(self.inner).await?;
91        res.json().await.map_err(SendError::Reqwest)
92    }
93
94    pub async fn load_by_client<R>(self, client: ReqwestClient) -> Result<R, SendError>
95    where
96        R: for<'de> Deserialize<'de>,
97    {
98        let res = client.execute(self.inner).await?;
99        res.json().await.map_err(SendError::Reqwest)
100    }
101
102    pub async fn send<R>(self) -> Result<R, SendError>
103    where
104        R: for<'de> Deserialize<'de>,
105    {
106        let res = client().execute(self.inner).await?;
107        res.json().await.map_err(SendError::Reqwest)
108    }
109
110    pub async fn send_by_client<R>(self, client: ReqwestClient) -> Result<R, SendError>
111    where
112        R: for<'de> Deserialize<'de>,
113    {
114        let res = client.execute(self.inner).await?;
115        res.json().await.map_err(SendError::Reqwest)
116    }
117
118    pub fn exec(self) -> impl Future<Output = Result<reqwest::Response, reqwest::Error>> {
119        client().execute(self.inner)
120    }
121}
122
123impl Deref for SendRequest {
124    type Target = ReqwestRequest;
125    fn deref(&self) -> &Self::Target {
126        &self.inner
127    }
128}
129impl DerefMut for SendRequest {
130    fn deref_mut(&mut self) -> &mut Self::Target {
131        &mut self.inner
132    }
133}
134
135pub trait SendModifier {
136    fn modify(self, request: &mut SendRequest) -> Result<(), SendError>;
137}
138
139impl SendModifier for (HeaderName, HeaderValue) {
140    fn modify(self, request: &mut SendRequest) -> Result<(), SendError> {
141        request.headers_mut().append(self.0, self.1);
142        Ok(())
143    }
144}