aliyun_oss_rust_sdk/async_impl/
object.rs1use hmac::Hmac;
2use sha1::digest::Mac;
3use crate::entity::{PolicyBuilder, PolicyResp};
4use crate::error::OssError;
5use crate::oss::{OSSInfo, API, OSS};
6use crate::request::{RequestBuilder, RequestType};
7use crate::{debug, util};
8use crate::metadata::ObjectMetadata;
9use crate::util::read_file;
10
11#[cfg(not(feature = "async"))]
12use reqwest::blocking::Client;
13#[cfg(feature = "async")]
14use reqwest::Client;
15
16#[cfg(feature = "async")]
17use maybe_async::maybe_async as maybe_async_attr;
18#[cfg(not(feature = "async"))]
19use maybe_async::must_be_sync as maybe_async_attr;
20
21impl OSS {
22 #[maybe_async_attr]
35 pub async fn get_object<S: AsRef<str>>(
36 &self,
37 key: S,
38 build: RequestBuilder,
39 ) -> Result<Vec<u8>, OssError> {
40 let key = self.format_key(key);
41 let (url, headers) = self
42 .build_request(key.as_str(), build)
43 .map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
44 debug!("oss logget object url: {} headers: {:?}", url,headers);
45 let client = Client::new();
46 let response = client.get(url).headers(headers).send().await?;
47 return if response.status().is_success() {
48 let result = response.bytes().await?;
49 Ok(result.to_vec())
50 } else {
51 let status = response.status();
52 let result = response.text().await?;
53 debug!("oss log: get object status: {} error: {}", status,result);
54 Err(OssError::Err(format!(
55 "get object status: {} error: {}",
56 status, result
57 )))
58 };
59 }
60
61 pub fn get_upload_object_policy(&self, build: PolicyBuilder) -> Result<PolicyResp, OssError> {
80 let date = chrono::Local::now().naive_local() + chrono::Duration::seconds(build.expire);
81 let date_str = date.format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string();
82 let mut json_data = r#"
83 {
84 "expiration": "{time}",
85 "conditions": [
86 {"bucket": "{bucket}" },
87 ["content-length-range", 1, {size}],
88 ["eq", "$success_action_status", "{success_action_status}"],
89 ["starts-with", "$key", "{prefix}"],
90 ["in", "$content-type", ["{content_type}"]]
91 ]
92 }
93 "#
94 .to_string();
95 let success_action_status = 200;
96 json_data = json_data.replacen("{time}", &date_str, 1);
97 json_data = json_data.replacen("{bucket}", &self.bucket(), 1);
98 json_data = json_data.replacen("{size}", &build.max_upload_size.to_string(), 1); json_data = json_data.replacen(
102 "{success_action_status}",
103 success_action_status.to_string().as_str(),
104 1,
105 );
106 json_data = json_data.replacen("{prefix}", &build.upload_dir, 1); json_data = json_data.replacen("{content_type}", &build.content_type, 1);
109 debug!("oss log: policy json: {}", json_data);
111 let base64_policy = util::base64_encode(json_data.as_bytes());
112 let mut hasher: Hmac<sha1::Sha1> = Hmac::new_from_slice(self.key_secret().as_bytes())
113 .map_err(|_| OssError::Err("Hmac new from slice error".to_string()))?;
114 hasher.update(base64_policy.as_bytes());
115 let signature = util::base64_encode(&hasher.finalize().into_bytes());
116 Ok(PolicyResp {
117 access_id: self.key_id().to_string(),
118 host: format!("https://{}.{}", self.bucket(), self.endpoint()),
119 policy: base64_policy,
120 signature,
121 success_action_status,
122 })
123 }
124
125 #[maybe_async_attr]
137 pub async fn put_object_from_file<S: AsRef<str>>(
138 &self,
139 key: S,
140 file_path: S,
141 build: RequestBuilder,
142 ) -> Result<(), OssError> {
143 let buffer = read_file(file_path)?;
144 let mut build = build.clone();
145 build.method = RequestType::Put;
146 let key = self.format_key(key);
147 let (url, headers) = self
148 .build_request(key.as_str(), build)
149 .map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
150 debug!("oss log: put object from file: {} headers: {:?}", url,headers);
151 let client = Client::new();
152 let response = client.put(url).headers(headers).body(buffer).send().await?;
153 if response.status().is_success() {
154 Ok(())
155 } else {
156 let status = response.status();
157 let result = response.text().await?;
158 debug!("oss log: get object status: {} error: {}", status,result);
159 Err(OssError::Err(format!(
160 "get object status: {} error: {}",
161 status, result
162 )))
163 }
164 }
165
166 #[maybe_async_attr]
179 pub async fn pub_object_from_buffer<S: AsRef<str>>(
180 &self,
181 key: S,
182 buffer: &[u8],
183 build: RequestBuilder,
184 ) -> Result<(), OssError> {
185 let mut build = build.clone();
186 build.method = RequestType::Put;
187 let key = self.format_key(key);
188 let (url, headers) = self
189 .build_request(key.as_str(), build)
190 .map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
191 debug!("oss log: put object from file: {} headers: {:?}", url,headers);
192 let client = Client::new();
193 let response = client
194 .put(url)
195 .headers(headers)
196 .body(buffer.to_owned())
197 .send()
198 .await?;
199 if response.status().is_success() {
200 Ok(())
201 } else {
202 let status = response.status();
203 let result = response.text().await?;
204 debug!("oss log: get object status: {} error: {}", status,result);
205 Err(OssError::Err(format!(
206 "get object status: {} error: {}",
207 status, result
208 )))
209 }
210 }
211
212 #[maybe_async_attr]
223 pub async fn delete_object<S: AsRef<str>>(
224 &self,
225 key: S,
226 build: RequestBuilder,
227 ) -> Result<(), OssError> {
228 let mut build = build.clone();
229 build.method = RequestType::Delete;
230 let key = self.format_key(key);
231 let (url, headers) = self
232 .build_request(key.as_str(), build)
233 .map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
234 debug!("oss log: put object from file: {} headers: {:?}", url,headers);
235 let client = Client::new();
236 let response = client.delete(url).headers(headers).send().await?;
237 if response.status().is_success() {
238 Ok(())
239 } else {
240 let status = response.status();
241 let result = response.text().await?;
242 debug!("oss log: get object status: {} error: {}", status,result);
243 Err(OssError::Err(format!(
244 "get object status: {} error: {}",
245 status, result
246 )))
247 }
248 }
249
250 #[maybe_async_attr]
262 pub async fn get_object_metadata<S: AsRef<str>>(&self, key: S, build: RequestBuilder) -> Result<ObjectMetadata, OssError>{
263 let mut build = build.clone();
264 build.method = RequestType::Head;
265 let key = self.format_key(key);
266 let (url, headers) = self.build_request(key.as_str(), build)
267 .map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
268 debug!("put object from file: {} headers: {:?}", url,headers);
269 let client = Client::new();
270 let response = client.head(url)
271 .headers(headers)
272 .send()
273 .await?;
274 if response.status().is_success() {
275 let metadata = ObjectMetadata::new(response.headers());
276 Ok(metadata)
277 } else {
278 let status = response.status();
279 let result = response.text().await?;
280 debug!("get object status: {} error: {}", status,result);
281 Err(OssError::Err(format!("get object status: {} error: {}", status, result)))
282 }
283 }
284}
285#[cfg(test)]
286mod tests {
287 use crate::entity::PolicyBuilder;
288 use crate::oss::OSS;
289 use crate::request::RequestBuilder;
290
291 #[inline]
292 fn init_log() {
293 tracing_subscriber::fmt()
294 .with_max_level(tracing::Level::DEBUG)
295 .with_line_number(true)
296 .init();
297 }
298
299 #[test]
300 fn test_get_upload_object_policy() {
301 init_log();
302 let oss = OSS::from_env();
303 let policy_builder = PolicyBuilder::new()
304 .with_expire(60 * 60).with_upload_dir("upload/mydir/").with_content_type("text/plain").with_max_upload_size(100 * 1024 * 1024);let policy = oss.get_upload_object_policy(policy_builder).unwrap();
309 println!("policy: {:?}", policy);
310 }
315
316 #[test]
317 fn test_put_object_from_file() {
318 init_log();
319 let oss = OSS::from_env();
320 let builder = RequestBuilder::new()
321 .with_expire(60);
322 let file_path = "./Cargo.toml";
323 oss.put_object_from_file("/cargo.toml", file_path, builder).unwrap();
324 }
325
326 #[test]
327 fn test_put_object_from_buffer() {
328 init_log();
329 let oss = OSS::from_env();
330 let builder = RequestBuilder::new()
331 .with_expire(60);
332 let file_path = "./Cargo.toml";
333 let buffer = std::fs::read(file_path).unwrap();
334 oss.pub_object_from_buffer("/cargo.toml", buffer.as_slice(), builder).unwrap();
335 }
336
337 #[test]
338 fn test_delete_object() {
339 init_log();
340 let oss = OSS::from_env();
341 let builder = RequestBuilder::new()
342 .with_expire(60);
343 oss.delete_object("/cargo.toml", builder).unwrap();
344 }
345
346 #[test]
347 fn test_get_object() {
348 init_log();
349 dotenvy::dotenv().ok();
350 let oss = OSS::from_env();
351 let build = RequestBuilder::new()
352 .with_cdn("http://cdn.ipadump.com");
353 let bytes = oss.get_object("/hello.txt", build).unwrap();
354 println!("file content: {}", String::from_utf8_lossy(bytes.as_slice()));
355 }
356
357 #[test]
358 fn test_get_object_metadata() {
359 init_log();
360 dotenvy::dotenv().ok();
361 let oss = OSS::from_env();
362 let build = RequestBuilder::new();
363 let metadata = oss.get_object_metadata("/hello.txt", build).unwrap();
364 println!("file metadata: {:?}", metadata);
365 }
366}