1use std::collections::HashMap;
3use std::fmt::Display;
4
5use bytes::Bytes;
6
7use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
8use reqwest::Body;
9use serde_json::value::Value;
10use std::convert::From;
11use std::str::FromStr;
12use std::time::Duration;
13
14use reqwest;
15
16pub struct Request;
17use serde;
18
19#[derive(Debug, serde::Serialize, serde::Deserialize, PartialEq)]
20pub struct InitiateMultipartUploadResult {
21 #[serde(rename(deserialize = "Bucket"))]
22 bucket: String,
23 #[serde(rename(deserialize = "Key"))]
24 key: String,
25 #[serde(rename(deserialize = "UploadId"))]
26 pub upload_id: String,
27}
28
29#[derive(Debug, serde::Serialize, serde::Deserialize)]
37pub struct CompleteMultipartUpload {
38 #[serde(rename(serialize = "Part"))]
39 pub part: Vec<Part>,
40}
41
42#[derive(Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone)]
43pub struct Part {
44 #[serde(rename = "$unflatten=PartNumber")]
45 pub part_number: u64,
46 #[serde(rename = "$unflatten=ETag")]
47 pub etag: String,
48}
49
50#[derive(Debug, PartialEq)]
52pub enum ErrNo {
53 SUCCESS = 0,
55 OTHER = 10000,
57 STATUS = 10001,
59 DECODE = 10002,
61 CONNECT = 10003,
63 ENCODE = 20001,
65 IO = 20002,
67}
68
69#[derive(Debug, Eq, PartialEq)]
71pub enum Method {
72 Get,
73 Post,
74 Delete,
75 Put,
76 Head,
77}
78
79impl std::fmt::Display for ErrNo {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 write!(f, "{:#?}", self)
87 }
88}
89
90#[derive(Debug)]
92pub struct Response {
93 pub error_no: ErrNo,
95 pub error_message: String,
97 pub result: Bytes,
99 pub headers: HashMap<String, String>,
101}
102
103impl From<reqwest::Error> for Response {
104 fn from(value: reqwest::Error) -> Self {
105 let mut e = ErrNo::OTHER;
106 if value.is_status() {
107 e = ErrNo::STATUS;
108 } else if value.is_connect() {
109 e = ErrNo::CONNECT;
110 } else if value.is_decode() {
111 e = ErrNo::DECODE;
112 }
113 Response {
114 error_no: e,
115 error_message: value.to_string(),
116 result: Bytes::from(""),
117 headers: HashMap::new(),
118 }
119 }
120}
121
122impl Display for Response {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 write!(
125 f,
126 r#"{{"error_no": "{}","error_message": "{}","result": "{}"}}"#,
127 self.error_no,
128 self.error_message,
129 String::from_utf8_lossy(&self.result[..])
130 )
131 }
132}
133
134impl Response {
135 pub fn new(error_no: ErrNo, error_message: String, result: String) -> Self {
136 Self {
137 error_no,
138 error_message,
139 result: Bytes::from(result),
140 headers: HashMap::new(),
141 }
142 }
143 pub fn blank_success() -> Self {
145 Self::new(ErrNo::SUCCESS, "".to_string(), "".to_string())
146 }
147}
148
149type Data = Value;
150
151impl Request {
153 fn get_builder_with_headers(
155 headers: Option<&HashMap<String, String>>,
156 ) -> reqwest::ClientBuilder {
157 let mut builder = reqwest::ClientBuilder::new();
158 if let Some(headers) = headers {
159 let mut header = HeaderMap::new();
160 for (k, v) in headers {
161 header.insert(
162 HeaderName::from_str(k).unwrap(),
163 HeaderValue::from_str(v).unwrap(),
164 );
165 }
166 builder = builder.default_headers(header);
167 }
168 builder
169 }
170 pub async fn head(
182 url: &str,
183 query: Option<&HashMap<String, String>>,
184 headers: Option<&HashMap<String, String>>,
185 ) -> Result<Response, Response> {
186 Request::do_req(
187 Method::Head,
188 url,
189 query,
190 headers,
191 None,
192 None,
193 None as Option<Body>,
194 )
195 .await
196 }
197 pub async fn get(
209 url: &str,
210 query: Option<&HashMap<String, String>>,
211 headers: Option<&HashMap<String, String>>,
212 ) -> Result<Response, Response> {
213 Request::do_req(
214 Method::Get,
215 url,
216 query,
217 headers,
218 None,
219 None,
220 None as Option<Body>,
221 )
222 .await
223 }
224 pub async fn post<T: Into<Body>>(
250 url: &str,
251 query: Option<&HashMap<String, String>>,
252 headers: Option<&HashMap<String, String>>,
253 form: Option<&HashMap<&str, Data>>,
254 json: Option<&HashMap<&str, Data>>,
255 body_data: Option<T>,
256 ) -> Result<Response, Response> {
257 Request::do_req(Method::Post, url, query, headers, form, json, body_data).await
258 }
259
260 pub async fn put<T: Into<Body>>(
262 url: &str,
263 query: Option<&HashMap<String, String>>,
264 headers: Option<&HashMap<String, String>>,
265 form: Option<&HashMap<&str, Data>>,
266 json: Option<&HashMap<&str, Data>>,
267 body_data: Option<T>,
268 ) -> Result<Response, Response> {
269 Request::do_req(Method::Put, url, query, headers, form, json, body_data).await
270 }
271
272 pub async fn delete(
274 url: &str,
275 query: Option<&HashMap<String, String>>,
276 headers: Option<&HashMap<String, String>>,
277 form: Option<&HashMap<&str, Data>>,
278 json: Option<&HashMap<&str, Data>>,
279 ) -> Result<Response, Response> {
280 Request::do_req(
281 Method::Delete,
282 url,
283 query,
284 headers,
285 form,
286 json,
287 None as Option<Body>,
288 )
289 .await
290 }
291
292 async fn do_req<T: Into<Body>>(
293 method: Method,
294 url: &str,
295 query: Option<&HashMap<String, String>>,
296 headers: Option<&HashMap<String, String>>,
297 form: Option<&HashMap<&str, Data>>,
298 json: Option<&HashMap<&str, Data>>,
299 body_data: Option<T>,
300 ) -> Result<Response, Response> {
301 let builder = Self::get_builder_with_headers(headers);
302 let client = builder.timeout(Duration::from_secs(24 * 3600)).build()?;
303 let mut req = match method {
304 Method::Get => client.get(url),
305 Method::Delete => client.delete(url),
306 Method::Post => client.post(url),
307 Method::Put => client.put(url),
308 Method::Head => client.head(url),
309 };
310 if let Some(v) = query {
311 req = req.query(v);
312 }
313 if let Some(v) = form {
314 req = req.form(v);
315 }
316 if let Some(v) = json {
317 req = req.json(v);
318 }
319 if let Some(v) = body_data {
320 req = req.body(v.into());
321 }
322 let resp = req.send().await?;
323 let status_code = resp.status();
324 let mut error_no = ErrNo::SUCCESS;
325 let mut message = "".to_string();
326 if status_code.is_client_error() || status_code.is_server_error() {
327 error_no = ErrNo::STATUS;
328 message = format!("{}", status_code);
329 }
330 let mut headers = HashMap::new();
331 for (k, v) in resp.headers() {
332 headers.insert(k.to_string(), String::from_utf8_lossy(v.as_bytes()).into());
333 }
334 Ok(Response {
335 error_no,
336 error_message: message,
337 result: resp.bytes().await?,
338 headers,
339 })
340 }
341}
342
343#[cfg(test)]
344mod tests {
345 use crate::request::{ErrNo, Request};
346 use reqwest::Body;
347 use serde_json::json;
348 use std::collections::HashMap;
349
350 #[tokio::test]
351 async fn test_get() {
352 let mut header = HashMap::new();
353 header.insert("user-agent".to_string(), "test-user-agent".to_string());
354 let mut query = HashMap::new();
355 query.insert("a".to_string(), "a".to_string());
356 query.insert("b".to_string(), "b".to_string());
357 query.insert("c".to_string(), "c".to_string());
358 let response = Request::get("https://www.baidu.com", Some(&query), Some(&header)).await;
359 match response {
360 Ok(e) => {
361 println!("{:#?}", e);
362 }
363 Err(e) => println!("{}", e),
364 }
365 }
366
367 #[tokio::test]
368 async fn test_post_form() {
369 let mut form = HashMap::new();
370 form.insert("hello", json!(1i16));
371 form.insert("hello1", json!("world"));
372 let mut json = HashMap::new();
373 json.insert("hello", json!(1i64));
374 json.insert("hello_json", json!("world"));
375 json.insert("data", json!(vec![1u8, 2u8, 3u8] as Vec<u8>));
376 let resp = Request::post(
377 "https://www.baidu.com",
378 None,
379 None,
380 Some(&form),
381 Some(&json),
382 None as Option<Body>,
383 )
384 .await;
385 if let Ok(e) = &resp {
386 println!("{:#?}", e);
387 }
388 if let Err(e) = resp {
389 assert_eq!(e.error_no, ErrNo::DECODE)
390 }
391 }
392}