1use crate::FeignContext;
2#[cfg(feature = "multipart")]
3use crate::multipart::MultipartForm;
4use crate::{ClientConfig, ClientWrapper, RequestConfig, RequestWrapper, error::Result};
5use async_trait::async_trait;
6use http::StatusCode;
7use once_cell::sync::Lazy;
8use std::collections::HashMap;
9
10pub trait FeignClientBuilder: Sized {
12 type Target;
13
14 fn new() -> Self;
15
16 fn config(self, config: ClientConfig) -> Self;
17
18 fn context<C>(self, context: C) -> Self
19 where
20 C: FeignContext + 'static;
21
22 fn build(self) -> Result<Self::Target>;
23}
24
25pub trait Client: Sized + Clone {
27 type Inner;
28
29 fn new() -> Result<Self>;
30
31 fn with_config(config: ClientConfig) -> Result<Self>;
32
33 fn with_client(client: Self::Inner) -> Result<Self>;
34
35 fn get_client(&self) -> &Self::Inner;
36}
37
38#[async_trait]
40pub trait HttpRequest {
41 type Response: HttpResponse;
42
43 fn headers(self, headers: HashMap<&str, String>) -> Self;
44
45 fn query(self, query: Vec<(&str, String)>) -> Self;
46
47 async fn send(self) -> Result<Self::Response>;
48
49 async fn send_text(self, text: String) -> Result<Self::Response>;
50
51 async fn send_form<T>(self, form: &T) -> Result<Self::Response>
52 where
53 T: serde::ser::Serialize + Sync;
54
55 #[cfg(feature = "json")]
56 async fn send_json<T>(self, json: &T) -> Result<Self::Response>
57 where
58 T: serde::ser::Serialize + Sync;
59
60 #[cfg(feature = "multipart")]
61 async fn send_multipart(self, form: MultipartForm) -> Result<Self::Response>;
62
63 async fn send_vec(self, vec: Vec<u8>) -> Result<Self::Response>;
64}
65
66#[async_trait]
68pub trait HttpResponse {
69 fn status(&self) -> StatusCode;
70
71 async fn none(self) -> Result<()>;
72
73 async fn text(self) -> Result<String>;
74
75 async fn vec(self) -> Result<Vec<u8>>;
76
77 #[cfg(feature = "json")]
78 async fn json<T>(self) -> Result<T>
79 where
80 T: serde::de::DeserializeOwned;
81}
82
83pub struct HttpClient;
85
86impl HttpClient {
87 pub fn new() -> Result<ClientWrapper> {
88 ClientWrapper::with_config(ClientConfig {
89 connect_timeout: Some(10000),
90 timeout: Some(10000),
91 read_timeout: None,
92 })
93 }
94
95 pub fn with_config(config: ClientConfig) -> Result<ClientWrapper> {
96 ClientWrapper::with_config(config)
97 }
98
99 pub fn shared() -> &'static ClientWrapper {
100 static SHARED: Lazy<ClientWrapper> =
101 Lazy::new(|| HttpClient::new().expect("shared http client failed to initialize"));
102
103 &SHARED
104 }
105}
106
107pub struct RequestBuilder<'a> {
109 client: ClientWrapper,
110 url: &'a str,
111 method: &'a str,
112 headers: Option<HashMap<&'a str, String>>,
113 query: Option<Vec<(&'a str, String)>>,
114 config: Option<RequestConfig>,
115}
116
117impl<'a> RequestBuilder<'a> {
118 pub fn new(client: ClientWrapper) -> Self {
119 Self {
120 client,
121 url: "",
122 method: "",
123 headers: None,
124 query: None,
125 config: None,
126 }
127 }
128 pub fn url(mut self, url: &'a str) -> Self {
129 self.url = url;
130 self
131 }
132
133 pub fn method(mut self, method: &'a str) -> Self {
134 self.method = method;
135 self
136 }
137
138 pub fn config(mut self, config: RequestConfig) -> Self {
139 self.config = Some(config);
140 self
141 }
142
143 pub fn headers(mut self, headers: HashMap<&'a str, String>) -> Self {
144 self.headers = Some(headers);
145 self
146 }
147
148 pub fn query(mut self, query: Vec<(&'a str, String)>) -> Self {
149 self.query = Some(query);
150 self
151 }
152
153 pub fn build(self) -> Result<RequestWrapper> {
154 let mut request = match self.config {
155 Some(config) => {
156 RequestWrapper::with_config(self.client, self.url, self.method, config)?
157 }
158 None => RequestWrapper::new(self.client, self.url, self.method)?,
159 };
160 if let Some(header_map) = self.headers {
161 request = request.headers(header_map);
162 }
163 if let Some(query_vec) = self.query {
164 request = request.query(query_vec);
165 }
166 Ok(request)
167 }
168}