ufile_rus3/api/
put_file.rs1use reqwest::header::{HeaderMap, HeaderName};
2use std::str::FromStr;
3
4use crate::api::{object::PutObjectResultResponse, traits::ApiOperation};
5
6use anyhow::Error;
7use chrono::Local;
8use reqwest::Method;
9
10use crate::api::object::ObjectOptAuthParamBuilder;
11
12use crate::{AuthorizationService, define_api_request, define_operation_struct};
13
14define_operation_struct!(PutFileOperation);
15
16define_api_request!(
17 PutFileRequest,
18 PutFileOperationBuilder,
19 PutObjectResultResponse,
20 {
21 #[builder(setter(into))]
23 pub bucket_name: String,
24
25 #[builder(setter(into))]
27 pub key_name: String,
28
29 #[builder(setter(into))]
31 pub mime_type: String,
32
33 pub stream: crate::api::ByteStream,
35
36 pub content_length: usize,
38
39 #[builder(setter(into, strip_option), default)]
41 pub content_md5: ::std::option::Option<String>,
42
43 #[builder(setter(strip_option), default)]
45 pub metadatas: ::std::option::Option<::std::collections::HashMap<String, String>>,
46
47 #[builder(setter(into, strip_option), default)]
49 pub storage_type: ::std::option::Option<String>,
50
51 #[builder(setter(into, strip_option), default)]
53 pub iop_cmd: ::std::option::Option<String>,
54
55 #[builder(setter(into, strip_option), default)]
57 pub security_token: ::std::option::Option<String>,
58 }
59);
60
61#[async_trait::async_trait]
62impl ApiOperation for PutFileOperation {
63 type Request = PutFileRequest;
64 type Response = PutObjectResultResponse;
65 type Error = Error;
66
67 async fn execute(&self, req: Self::Request) -> Result<Self::Response, Self::Error> {
68 let PutFileRequest {
69 bucket_name,
70 key_name,
71 stream,
72 mime_type,
73 metadatas,
74 content_length,
75 content_md5,
76 storage_type,
77 iop_cmd,
78 security_token,
79 ..
80 } = req;
81 let date = Local::now().format("%Y%m%d%H%M%S").to_string();
82 let content_type = mime_type.clone();
83 let mut auth_object_builder = ObjectOptAuthParamBuilder::default();
84 auth_object_builder
85 .method(Method::PUT)
86 .bucket(bucket_name.as_str())
87 .key_name(key_name.as_str())
88 .content_type(content_type.as_str())
89 .date(date.as_str());
90
91 let mut headers = HeaderMap::new();
92 if let Some(content_md5) = content_md5 {
94 auth_object_builder.content_md5(content_md5.as_str());
95 headers.insert("Content-MD5", content_md5.parse().unwrap());
96 }
97 let auth_object = auth_object_builder.build()?;
98 headers.insert(
99 "Content-Length",
100 content_length.to_string().parse().unwrap(),
101 );
102
103 let authorization =
104 AuthorizationService.authorization(auth_object, self.object_config.clone())?;
105 headers.insert("Authorization", authorization.parse().unwrap());
106 headers.insert("Content-Type", content_type.parse().unwrap());
107 headers.insert("Accept", "*/*".parse().unwrap());
108 headers.insert("Date", date.parse().unwrap());
109
110 if let Some(storage_type) = storage_type {
111 headers.insert("X-Ufile-Storage-Class", storage_type.parse().unwrap());
112 }
113
114 if let Some(security_token) = security_token {
115 headers.insert("SecurityToken", security_token.parse().unwrap());
116 }
117
118 if let Some(metadatas) = metadatas
119 && !metadatas.is_empty()
120 {
121 metadatas.iter().for_each(|(key, value)| {
122 let key = format!("X-Ufile-Meta-{key}");
123 headers.insert(
124 HeaderName::from_str(key.as_str()).unwrap(),
125 value.to_string().parse().unwrap(),
126 );
127 });
128 }
129
130 let mut url = self
131 .object_config
132 .generate_final_host(bucket_name.as_str(), key_name.as_str());
133 if let Some(iop_cmd) = iop_cmd {
134 url = format!("{url}?{iop_cmd}");
135 }
136
137 let response = self
138 .client
139 .send_file(url.as_str(), Method::PUT, headers, stream)
140 .await?;
141 tracing::debug!("put file response: {:?}", response);
142 let mut put_file_response = PutObjectResultResponse::from(response);
143 if let Some(e_tag) = put_file_response.resp.headers.get("etag") {
144 put_file_response.etag = e_tag.to_string();
145 }
146
147 Ok(put_file_response)
148 }
149}