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#[allow(non_snake_case)]
230impl<'a> oss::Client<'a> {
231 pub fn PutSymlink(&self, object: &'a str) -> PutSymlinkBuilder<'_> {
237 PutSymlinkBuilder::new(self, object)
238 }
239
240 pub fn GetSymlink(&self, object: &'a str) -> GetSymlinkBuilder<'_> {
245 GetSymlinkBuilder::new(self, object)
246 }
247}