use crate::Config;
use crate::common::types::{Body, Timeout};
use http::header::{AsHeaderName, IntoHeaderName};
use http::{Extensions, HeaderMap, HeaderValue};
use reqwest::{Method, RequestBuilder as ReqwestRequestBuilder};
use serde_json::Value;
use std::time::Duration;
pub(crate) struct RequestSpec<U, F>
where
U: FnOnce(&Config) -> String,
F: FnOnce(&Config, &mut RequestBuilder),
{
pub url_fn: U,
pub builder_fn: F,
}
impl<U, F> RequestSpec<U, F>
where
U: FnOnce(&Config) -> String,
F: FnOnce(&Config, &mut RequestBuilder),
{
pub fn new(url_fn: U, builder_fn: F) -> Self {
Self { url_fn, builder_fn }
}
}
#[derive(Debug, Clone)]
pub(crate) struct Request {
method: Method,
url: String,
headers: HeaderMap,
body: Option<Body>,
extensions: Extensions,
}
impl Request {
pub fn to_reqwest(&self, client: &reqwest::Client) -> ReqwestRequestBuilder {
let mut builder = client.request(self.method.clone(), &self.url);
for (k, v) in &self.headers {
builder = builder.header(k, v);
}
if let Some(body) = &self.body {
builder = builder.json(body);
}
if let Some(timeout) = self.extensions.get::<Timeout>() {
builder = builder.timeout(timeout.0);
}
builder
}
}
pub(crate) struct RequestBuilder {
request: Request,
}
impl RequestBuilder {
pub fn new(method: Method, url: &str) -> RequestBuilder {
RequestBuilder {
request: Request {
method,
url: url.to_string(),
headers: HeaderMap::new(),
body: None,
extensions: Extensions::new(),
},
}
}
#[inline]
pub fn extensions(&self) -> &Extensions {
&self.request.extensions
}
#[inline]
pub fn extensions_mut(&mut self) -> &mut Extensions {
&mut self.request.extensions
}
#[inline]
pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.request.headers
}
#[inline]
pub fn header<K: IntoHeaderName>(&mut self, key: K, value: HeaderValue) -> &mut Self {
self.request.headers.insert(key, value);
self
}
pub fn bearer_auth(&mut self, token: &str) -> &mut Self {
let val = format!("Bearer {token}");
self.request.headers.insert(
"Authorization",
HeaderValue::from_str(&val).unwrap_or_else(|_| {
panic!("不能将 `api_key` 转换为 HeaderValue, 请检查其值是否合法")
}),
);
self
}
pub fn body_field<K: Into<String>, V: Into<Value>>(&mut self, key: K, value: V) -> &mut Self {
self.request
.body
.get_or_insert_with(Body::new)
.insert(key.into(), value.into());
self
}
pub fn body_fields(&mut self, fields: Body) -> &mut Self {
self.request
.body
.get_or_insert_with(Body::new)
.extend(fields);
self
}
#[inline]
pub fn timeout(&mut self, timeout: Duration) -> &mut Self {
self.request.extensions.insert(Timeout(timeout));
self
}
#[inline]
pub fn has_header<K: AsHeaderName>(&self, key: K) -> bool {
self.request.headers.contains_key(key)
}
#[inline]
pub fn has_body_field(&self, key: &str) -> bool {
match self.request.body.as_ref() {
Some(body_fields) => body_fields.contains_key(key),
None => false,
}
}
pub fn build(self) -> Request {
self.request
}
}