any_object_storage/async_impl/
object.rs

1use 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
11impl OSS {
12    /// 获取对象
13    ///
14    /// # 使用例子
15    ///
16    /// ```rust
17    /// use aliyun_oss_rust_sdk::oss::OSS;
18    /// use aliyun_oss_rust_sdk::request::RequestBuilder;
19    /// let oss = OSS::from_env();
20    /// let build = RequestBuilder::new();
21    /// let bytes = oss.get_object("/hello.txt", build).await.unwrap();
22    /// println!("file content: {}", String::from_utf8_lossy(bytes.as_slice()));
23    /// ```
24    pub async fn get_object<S: AsRef<str>>(
25        &self,
26        key: S,
27        build: RequestBuilder,
28    ) -> Result<Vec<u8>, OssError> {
29        let key = self.format_key(key);
30        let (url, headers) = self
31            .build_request(key.as_str(), build)
32            .map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
33        debug!("oss logget object url: {} headers: {:?}", url,headers);
34        let client = reqwest::Client::new();
35        let response = client.get(url).headers(headers).send().await?;
36        return if response.status().is_success() {
37            let result = response.bytes().await?;
38            Ok(result.to_vec())
39        } else {
40            let status = response.status();
41            let result = response.text().await?;
42            debug!("oss log: get object status: {} error: {}", status,result);
43            Err(OssError::Err(format!(
44                "get object status: {} error: {}",
45                status, result
46            )))
47        };
48    }
49
50    /// 获取上传对象的policy
51    /// # 使用例子
52    /// ```rust
53    /// use aliyun_oss_rust_sdk::entity::PolicyBuilder;
54    /// use aliyun_oss_rust_sdk::oss::OSS;
55    /// let oss = OSS::from_env();
56    /// let policy_builder = PolicyBuilder::new()
57    ///             .with_expire(60 * 60)//1个小时过期
58    ///             .with_upload_dir("upload/mydir/")//上传目录
59    ///             .with_content_type("text/plain")//只允许上传文本.txt
60    ///            .with_max_upload_size(100 * 1024 * 1024);//只允许文件上传大小1G以内
61    /// let policy = oss.get_upload_object_policy(policy_builder).unwrap();
62    /// println!("policy: {:?}", policy);
63    /// //使用postman测试上传
64    /// //form-data的参数为OSSAccessKeyId、policy、signature、success_action_status、key、file
65    /// //key为上传的文件名包含路径、例如:upload/mydir/test.txt
66    /// //file为上传的文件,类型跟with_content_type一致
67    /// ```
68    pub fn get_upload_object_policy(&self, build: PolicyBuilder) -> Result<PolicyResp, OssError> {
69        let date = chrono::Local::now().naive_local() + chrono::Duration::seconds(build.expire);
70        let date_str = date.format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string();
71        let mut json_data = r#"
72        {
73            "expiration": "{time}",
74            "conditions": [
75                {"bucket": "{bucket}" },
76                ["content-length-range", 1, {size}],
77                ["eq", "$success_action_status", "{success_action_status}"],
78                ["starts-with", "$key", "{prefix}"],
79                ["in", "$content-type", ["{content_type}"]]
80            ]
81        }
82        "#
83            .to_string();
84        let success_action_status = 200;
85        json_data = json_data.replacen("{time}", &date_str, 1);
86        json_data = json_data.replacen("{bucket}", &self.bucket(), 1);
87        //limit 1GB bytes
88        json_data = json_data.replacen("{size}", &build.max_upload_size.to_string(), 1); //允许上传的最大文件大小
89        //success status
90        json_data = json_data.replacen(
91            "{success_action_status}",
92            success_action_status.to_string().as_str(),
93            1,
94        );
95        json_data = json_data.replacen("{prefix}", &build.upload_dir, 1); //只允许上传到哪个目录上
96        //text file
97        json_data = json_data.replacen("{content_type}", &build.content_type, 1);
98        //只允许上传哪个类型文件
99        debug!("oss log: policy json: {}", json_data);
100        let base64_policy = util::base64_encode(json_data.as_bytes());
101        let mut hasher: Hmac<sha1::Sha1> = Hmac::new_from_slice(self.key_secret().as_bytes())
102            .map_err(|_| OssError::Err("Hmac new from slice error".to_string()))?;
103        hasher.update(base64_policy.as_bytes());
104        let signature = util::base64_encode(&hasher.finalize().into_bytes());
105        Ok(PolicyResp {
106            access_id: self.key_id().to_string(),
107            host: format!("https://{}.{}", self.bucket(), self.endpoint()),
108            policy: base64_policy,
109            signature,
110            success_action_status,
111        })
112    }
113
114    /// 上传文件(本地文件)
115    /// # 使用例子
116    /// ```rust
117    /// use aliyun_oss_rust_sdk::oss::OSS;
118    /// use aliyun_oss_rust_sdk::request::RequestBuilder;
119    /// let oss = OSS::from_env();
120    /// let builder = RequestBuilder::new()
121    ///     .with_expire(60);
122    /// let file_path = "./hello.txt";
123    /// oss.put_object_from_file("/hello.txt", file_path, builder).await.unwrap();
124    /// ```
125    pub async fn put_object_from_file<S: AsRef<str>>(
126        &self,
127        key: S,
128        file_path: S,
129        build: RequestBuilder,
130    ) -> Result<(), OssError> {
131        let buffer = read_file(file_path)?;
132        let mut build = build.clone();
133        build.method = RequestType::Put;
134        let key = self.format_key(key);
135        let (url, headers) = self
136            .build_request(key.as_str(), build)
137            .map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
138        debug!("oss log: put object from file: {} headers: {:?}", url,headers);
139        let client = reqwest::Client::new();
140        let response = client.put(url).headers(headers).body(buffer).send().await?;
141        return if response.status().is_success() {
142            Ok(())
143        } else {
144            let status = response.status();
145            let result = response.text().await?;
146            debug!("oss log: get object status: {} error: {}", status,result);
147            Err(OssError::Err(format!(
148                "get object status: {} error: {}",
149                status, result
150            )))
151        };
152    }
153
154    /// 上传文件(内存)
155    /// # 使用例子
156    /// ```rust
157    /// use aliyun_oss_rust_sdk::oss::OSS;
158    /// use aliyun_oss_rust_sdk::request::RequestBuilder;
159    /// let oss = OSS::from_env();
160    /// let builder = RequestBuilder::new()
161    ///     .with_expire(60);
162    /// let file_path = "./hello.txt";
163    /// let buffer = std::fs::read(file_path).unwrap();
164    /// oss.pub_object_from_buffer("/hello.txt", buffer.as_slice(), builder).await.unwrap();
165    /// ```
166    pub async fn pub_object_from_buffer<S: AsRef<str>>(
167        &self,
168        key: S,
169        buffer: &[u8],
170        build: RequestBuilder,
171    ) -> Result<(), OssError> {
172        let mut build = build.clone();
173        build.method = RequestType::Put;
174        let key = self.format_key(key);
175        let (url, headers) = self
176            .build_request(key.as_str(), build)
177            .map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
178        debug!("oss log: put object from file: {} headers: {:?}", url,headers);
179        let client = reqwest::Client::new();
180        let response = client
181            .put(url)
182            .headers(headers)
183            .body(buffer.to_owned())
184            .send()
185            .await?;
186        return if response.status().is_success() {
187            Ok(())
188        } else {
189            let status = response.status();
190            let result = response.text().await?;
191            debug!("oss log: get object status: {} error: {}", status,result);
192            Err(OssError::Err(format!(
193                "get object status: {} error: {}",
194                status, result
195            )))
196        };
197    }
198
199    /// 删除文件
200    /// # 使用例子
201    /// ```rust
202    /// use aliyun_oss_rust_sdk::oss::OSS;
203    /// use aliyun_oss_rust_sdk::request::RequestBuilder;
204    /// let oss = OSS::from_env();
205    /// let builder = RequestBuilder::new()
206    ///    .with_expire(60);
207    /// oss.delete_object("/hello.txt", builder).await.unwrap();
208    /// ```
209    pub async fn delete_object<S: AsRef<str>>(
210        &self,
211        key: S,
212        build: RequestBuilder,
213    ) -> Result<(), OssError> {
214        let mut build = build.clone();
215        build.method = RequestType::Delete;
216        let key = self.format_key(key);
217        let (url, headers) = self
218            .build_request(key.as_str(), build)
219            .map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
220        debug!("oss log: put object from file: {} headers: {:?}", url,headers);
221        let client = reqwest::Client::new();
222        let response = client.delete(url).headers(headers).send().await?;
223        return if response.status().is_success() {
224            Ok(())
225        } else {
226            let status = response.status();
227            let result = response.text().await?;
228            debug!("oss log: get object status: {} error: {}", status,result);
229            Err(OssError::Err(format!(
230                "get object status: {} error: {}",
231                status, result
232            )))
233        };
234    }
235
236    /// 获取对象元数据
237    /// # 使用例子
238    /// ```rust
239    /// use aliyun_oss_rust_sdk::oss::OSS;
240    /// use aliyun_oss_rust_sdk::request::RequestBuilder;
241    /// let oss = OSS::from_env();
242    /// let builder = RequestBuilder::new()
243    ///    .with_expire(60);
244    /// let metadata = oss.get_object_metadata("/hello.txt", builder).await.unwrap();
245    /// println!("{:?}", metadata);
246    /// ```
247    pub async fn get_object_metadata<S: AsRef<str>>(&self, key: S, build: RequestBuilder) -> Result<ObjectMetadata, OssError>{
248        let mut build = build.clone();
249        build.method = RequestType::Head;
250        let key = self.format_key(key);
251        let (url, headers) = self.build_request(key.as_str(), build)
252            .map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
253        debug!("put object from file: {} headers: {:?}", url,headers);
254        let client = reqwest::Client::new();
255        let response = client.head(url)
256            .headers(headers)
257            .send()
258            .await?;
259        return if response.status().is_success() {
260            let metadata = ObjectMetadata::new(response.headers());
261            Ok(metadata)
262        } else {
263            let status = response.status();
264            let result = response.text().await?;
265            debug!("get object status: {} error: {}", status,result);
266            Err(OssError::Err(format!("get object status: {} error: {}", status, result)))
267        };
268    }
269}