xt_oss/oss/api/objects/
symlink.rs

1use crate::oss;
2
3use self::builders::{GetSymlinkBuilder, PutSymlinkBuilder};
4
5pub mod builders {
6
7    use std::collections::HashMap;
8
9    use reqwest::header::{
10        CACHE_CONTROL, CONTENT_DISPOSITION, CONTENT_ENCODING, CONTENT_LANGUAGE, CONTENT_TYPE,
11        EXPIRES,
12    };
13
14    use crate::oss::{
15        self,
16        api::{self, insert_custom_header, insert_header, ApiResponseFrom},
17        entities::{ObjectACL, StorageClass},
18        http,
19    };
20
21    #[derive(Debug, Default, Clone)]
22    struct PutSymlinkBuilderHeaders<'a> {
23        cache_control: Option<http::CacheControl>,
24        content_disposition: Option<http::ContentDisposition>,
25        content_language: Option<&'a str>,
26        content_encoding: Option<http::ContentEncoding>,
27        content_type: Option<&'a str>,
28        expires: Option<&'a str>,
29    }
30
31    #[derive(Debug)]
32    pub struct PutSymlinkBuilder<'a> {
33        client: &'a oss::Client<'a>,
34        object: &'a str,
35        version_id: Option<&'a str>,
36        symlink_target: &'a str,
37        forbid_overwrite: Option<bool>,
38        object_acl: Option<ObjectACL>,
39        storage_class: Option<StorageClass>,
40        oss_meta: HashMap<&'a str, &'a str>,
41        headers: PutSymlinkBuilderHeaders<'a>,
42    }
43
44    impl<'a> PutSymlinkBuilder<'a> {
45        pub(crate) fn new(client: &'a oss::Client, object: &'a str) -> Self {
46            Self {
47                client,
48                object,
49                version_id: None,
50                symlink_target: Default::default(),
51                forbid_overwrite: None,
52                object_acl: None,
53                storage_class: None,
54                oss_meta: HashMap::new(),
55                headers: PutSymlinkBuilderHeaders::default(),
56            }
57        }
58
59        pub fn with_symlink_target(mut self, value: &'a str) -> Self {
60            self.symlink_target = value;
61            self
62        }
63
64        pub fn with_forbid_overwrite(mut self, value: bool) -> Self {
65            self.forbid_overwrite = Some(value);
66            self
67        }
68
69        pub fn with_object_acl(mut self, value: ObjectACL) -> Self {
70            self.object_acl = Some(value);
71            self
72        }
73
74        pub fn with_storage_class(mut self, value: StorageClass) -> Self {
75            self.storage_class = Some(value);
76            self
77        }
78
79        pub fn with_oss_meta(mut self, key: &'a str, value: &'a str) -> Self {
80            self.oss_meta.insert(key, value);
81            self
82        }
83        pub fn with_content_type(mut self, value: &'a str) -> Self {
84            self.headers.content_type = Some(value);
85            self
86        }
87
88        pub fn with_content_language(mut self, value: &'a str) -> Self {
89            self.headers.content_language = Some(value);
90            self
91        }
92
93        pub fn with_cache_control(mut self, value: http::CacheControl) -> Self {
94            self.headers.cache_control = Some(value);
95            self
96        }
97
98        pub fn with_content_disposition(mut self, value: http::ContentDisposition) -> Self {
99            self.headers.content_disposition = Some(value);
100            self
101        }
102
103        pub fn with_content_encoding(mut self, value: http::ContentEncoding) -> Self {
104            self.headers.content_encoding = Some(value);
105            self
106        }
107
108        pub fn with_expires(mut self, value: &'a str) -> Self {
109            self.headers.expires = Some(value);
110            self
111        }
112
113        fn headers(&self) -> http::HeaderMap {
114            let mut headers = http::HeaderMap::new();
115            insert_custom_header(&mut headers, "x-oss-symlink-target", self.symlink_target);
116            if let Some(forbid_overwrite) = self.forbid_overwrite {
117                insert_custom_header(&mut headers, "x-oss-forbid-overwrite", forbid_overwrite);
118            }
119            if let Some(object_acl) = &self.object_acl {
120                insert_custom_header(&mut headers, "x-oss-object-acl", object_acl.to_string());
121            }
122            if let Some(storage_class) = &self.storage_class {
123                insert_custom_header(
124                    &mut headers,
125                    "x-oss-storage-class",
126                    storage_class.to_string(),
127                );
128            }
129            if let Some(content_type) = &self.headers.content_type {
130                insert_header(&mut headers, CONTENT_TYPE, content_type);
131            }
132
133            if let Some(content_language) = &self.headers.content_language {
134                insert_header(&mut headers, CONTENT_LANGUAGE, content_language);
135            }
136
137            if let Some(cache_control) = &self.headers.cache_control {
138                insert_header(&mut headers, CACHE_CONTROL, cache_control);
139            }
140
141            if let Some(content_disposition) = &self.headers.content_disposition {
142                insert_header(&mut headers, CONTENT_DISPOSITION, content_disposition);
143            }
144
145            if let Some(content_encoding) = &self.headers.content_encoding {
146                insert_header(&mut headers, CONTENT_ENCODING, content_encoding);
147            }
148
149            if let Some(expires) = &self.headers.expires {
150                insert_header(&mut headers, EXPIRES, expires);
151            }
152
153            if !self.oss_meta.is_empty() {
154                for (key, value) in &self.oss_meta {
155                    insert_custom_header(&mut headers, &format!("x-oss-meta-{}", key), value);
156                }
157            }
158            headers
159        }
160
161        pub async fn execute(&self) -> api::ApiResult {
162            let mut res = format!("/{}/{}?{}", self.client.bucket(), self.object, "symlink");
163            let mut url = format!("{}?{}", self.client.object_url(self.object), "symlink");
164            if let Some(version_id) = self.version_id {
165                res = format!("{}&versionId={}", res, version_id);
166                url = format!("{}&versionId={}", url, version_id);
167            }
168
169            let headers = self.headers();
170
171            let resp = self
172                .client
173                .request
174                .task()
175                .with_url(&url)
176                .with_headers(headers)
177                .with_method(http::Method::PUT)
178                .with_resource(&res)
179                .execute()
180                .await?;
181
182            Ok(ApiResponseFrom(resp).to_empty().await)
183        }
184    }
185
186    pub struct GetSymlinkBuilder<'a> {
187        client: &'a oss::Client<'a>,
188        object: &'a str,
189        version_id: Option<&'a str>,
190    }
191
192    impl<'a> GetSymlinkBuilder<'a> {
193        pub(crate) fn new(client: &'a oss::Client, object: &'a str) -> Self {
194            Self {
195                client,
196                object,
197                version_id: None,
198            }
199        }
200
201        pub fn with_version_id(mut self, value: &'a str) -> Self {
202            self.version_id = Some(value);
203            self
204        }
205
206        pub async fn execute(&self) -> api::ApiResult {
207            let mut res = format!("/{}/{}?{}", self.client.bucket(), self.object, "symlink");
208            let mut url = { format!("{}?{}", self.client.object_url(self.object), "symlink") };
209            if let Some(version_id) = self.version_id {
210                res = format!("{}&versionId={}", res, version_id);
211                url = format!("{}&versionId={}", url, version_id);
212            }
213
214            let resp = self
215                .client
216                .request
217                .task()
218                .with_url(&url)
219                .with_resource(&res)
220                .execute()
221                .await?;
222
223            Ok(ApiResponseFrom(resp).to_empty().await)
224        }
225    }
226}
227
228/// # 软链接`Symlink``
229#[allow(non_snake_case)]
230impl<'a> oss::Client<'a> {
231    /// 调用PutSymlink接口用于为OSS的目标文件`TargetObject`创建软链接
232    /// `Symlink`,您可以通过该软链接访问TargetObject。
233    ///
234    /// - [official docs](https://help.aliyun.com/zh/oss/developer-reference/putsymlink)
235    /// - [xtoss example](https://github.com/isme-sun/xt_oss/blob/main/examples/api_object_symlink_put.rs)
236    pub fn PutSymlink(&self, object: &'a str) -> PutSymlinkBuilder<'_> {
237        PutSymlinkBuilder::new(self, object)
238    }
239
240    /// 调用GetSymlink接口获取软链接。此操作需要您对该软链接有读权限。
241    ///
242    /// - [official docs](https://help.aliyun.com/zh/oss/developer-reference/getsymlink)
243    /// - [xtoss example](https://github.com/isme-sun/xt_oss/blob/main/examples/api_object_symlink_get.rs)
244    pub fn GetSymlink(&self, object: &'a str) -> GetSymlinkBuilder<'_> {
245        GetSymlinkBuilder::new(self, object)
246    }
247}