Skip to main content

aliyun_oss/operations/
bucket_resource_group.rs

1//! Resource group binding operations.
2
3use crate::client::{BucketOperations, OSSClientInner};
4use crate::error::{ErrorContext, OssError, OssErrorKind, Result};
5use crate::http::client::HttpRequest;
6use crate::types::bucket::BucketName;
7use serde::{Deserialize, Serialize};
8use std::sync::Arc;
9
10#[derive(Debug, Clone, Serialize)]
11#[serde(rename = "ResourceGroupConfiguration")]
12struct ResourceGroupConfig {
13    #[serde(rename = "ResourceGroupId")]
14    resource_group_id: String,
15}
16
17#[derive(Debug, Clone, Deserialize)]
18#[serde(rename = "ResourceGroupConfiguration")]
19struct ResourceGroupConfigResp {
20    #[serde(rename = "ResourceGroupId")]
21    resource_group_id: String,
22}
23
24pub struct PutBucketResourceGroupBuilder {
25    client: Arc<OSSClientInner>,
26    bucket: BucketName,
27    group_id: String,
28}
29impl PutBucketResourceGroupBuilder {
30    pub(crate) fn new(
31        client: Arc<OSSClientInner>,
32        bucket: BucketName,
33        group_id: impl Into<String>,
34    ) -> Self {
35        Self {
36            client,
37            bucket,
38            group_id: group_id.into(),
39        }
40    }
41    pub async fn send(self) -> Result<PutBucketResourceGroupOutput> {
42        let ep = self.client.endpoint.clone();
43        let uri = format!("https://{}.{}?resourceGroup", self.bucket.as_str(), ep);
44        let qp = vec![("resourceGroup".into(), String::new())];
45        let cfg = ResourceGroupConfig {
46            resource_group_id: self.group_id,
47        };
48        let xml = crate::util::xml::to_xml(&cfg)?;
49        let req = HttpRequest::builder()
50            .method(http::Method::PUT)
51            .uri(&uri)
52            .body(bytes::Bytes::from(xml))
53            .build();
54        let r = self
55            .client
56            .send_signed(req, Some(&self.bucket), qp)
57            .await
58            .map_err(|e| OssError {
59                kind: OssErrorKind::TransportError,
60                context: Box::new(ErrorContext {
61                    operation: Some("PutBucketResourceGroup".into()),
62                    bucket: Some(self.bucket.to_string()),
63                    endpoint: Some(ep),
64                    ..Default::default()
65                }),
66                source: Some(Box::new(e)),
67            })?;
68        if r.status().is_success() {
69            Ok(PutBucketResourceGroupOutput {
70                request_id: r
71                    .headers
72                    .get("x-oss-request-id")
73                    .and_then(|v| v.to_str().ok())
74                    .unwrap_or("")
75                    .to_string(),
76            })
77        } else {
78            Err(OssError {
79                kind: OssErrorKind::ServiceError(Box::new(crate::error::OssServiceError {
80                    status_code: r.status().as_u16(),
81                    code: String::new(),
82                    message: String::new(),
83                    request_id: String::new(),
84                    host_id: String::new(),
85                    resource: Some(self.bucket.to_string()),
86                    string_to_sign: None,
87                })),
88                context: Box::new(ErrorContext {
89                    operation: Some("PutBucketResourceGroup".into()),
90                    bucket: Some(self.bucket.to_string()),
91                    ..Default::default()
92                }),
93                source: None,
94            })
95        }
96    }
97}
98#[derive(Debug, Clone)]
99pub struct PutBucketResourceGroupOutput {
100    pub request_id: String,
101}
102
103pub struct GetBucketResourceGroupBuilder {
104    client: Arc<OSSClientInner>,
105    bucket: BucketName,
106}
107impl GetBucketResourceGroupBuilder {
108    pub(crate) fn new(client: Arc<OSSClientInner>, bucket: BucketName) -> Self {
109        Self { client, bucket }
110    }
111    pub async fn send(self) -> Result<GetBucketResourceGroupOutput> {
112        let ep = self.client.endpoint.clone();
113        let uri = format!("https://{}.{}?resourceGroup", self.bucket.as_str(), ep);
114        let qp = vec![("resourceGroup".into(), String::new())];
115        let req = HttpRequest::builder()
116            .method(http::Method::GET)
117            .uri(&uri)
118            .build();
119        let r = self
120            .client
121            .send_signed(req, Some(&self.bucket), qp)
122            .await
123            .map_err(|e| OssError {
124                kind: OssErrorKind::TransportError,
125                context: Box::new(ErrorContext {
126                    operation: Some("GetBucketResourceGroup".into()),
127                    bucket: Some(self.bucket.to_string()),
128                    endpoint: Some(ep),
129                    ..Default::default()
130                }),
131                source: Some(Box::new(e)),
132            })?;
133        if r.is_success() {
134            let c: ResourceGroupConfigResp =
135                crate::util::xml::from_xml(r.body_as_str().unwrap_or("")).map_err(|e| {
136                    OssError {
137                        kind: OssErrorKind::DeserializationError,
138                        context: Box::new(ErrorContext {
139                            operation: Some("parse XML".into()),
140                            bucket: Some(self.bucket.to_string()),
141                            ..Default::default()
142                        }),
143                        source: Some(Box::new(e)),
144                    }
145                })?;
146            Ok(GetBucketResourceGroupOutput {
147                resource_group_id: c.resource_group_id,
148            })
149        } else {
150            Err(OssError {
151                kind: OssErrorKind::ServiceError(Box::new(crate::error::OssServiceError {
152                    status_code: r.status().as_u16(),
153                    code: String::new(),
154                    message: String::new(),
155                    request_id: String::new(),
156                    host_id: String::new(),
157                    resource: Some(self.bucket.to_string()),
158                    string_to_sign: None,
159                })),
160                context: Box::new(ErrorContext {
161                    operation: Some("GetBucketResourceGroup".into()),
162                    bucket: Some(self.bucket.to_string()),
163                    ..Default::default()
164                }),
165                source: None,
166            })
167        }
168    }
169}
170#[derive(Debug, Clone)]
171pub struct GetBucketResourceGroupOutput {
172    pub resource_group_id: String,
173}
174
175impl BucketOperations {
176    pub fn put_resource_group(&self, group_id: impl Into<String>) -> PutBucketResourceGroupBuilder {
177        PutBucketResourceGroupBuilder::new(
178            self.client_inner().clone(),
179            self.bucket_name().clone(),
180            group_id,
181        )
182    }
183    pub fn get_resource_group(&self) -> GetBucketResourceGroupBuilder {
184        GetBucketResourceGroupBuilder::new(self.client_inner().clone(), self.bucket_name().clone())
185    }
186}
187
188#[cfg(test)]
189mod tests {
190    use super::*;
191    use crate::client::OSSClientInner;
192    use crate::config::credentials::Credentials;
193    use crate::http::client::{HttpClient, HttpRequest, HttpResponse};
194    use crate::types::region::Region;
195    use std::sync::Mutex;
196
197    struct Rc {
198        r: Arc<Mutex<Vec<HttpRequest>>>,
199    }
200    #[async_trait::async_trait]
201    impl HttpClient for Rc {
202        async fn send(&self, req: HttpRequest) -> crate::error::Result<HttpResponse> {
203            self.r.lock().unwrap().push(req);
204            let mut h = http::HeaderMap::new();
205            h.insert("x-oss-request-id", http::HeaderValue::from_static("rid"));
206            Ok(HttpResponse {
207                status: http::StatusCode::OK,
208                headers: h,
209                body: bytes::Bytes::new(),
210            })
211        }
212    }
213    fn ci() -> (Arc<OSSClientInner>, Arc<Mutex<Vec<HttpRequest>>>) {
214        let rq = Arc::new(Mutex::new(Vec::new()));
215        let h = Arc::new(Rc { r: rq.clone() });
216        let cr = Arc::new(crate::config::credentials::StaticCredentialsProvider::new(
217            Credentials::builder()
218                .access_key_id("ak")
219                .access_key_secret("sk")
220                .build()
221                .unwrap(),
222        ));
223        (
224            Arc::new(OSSClientInner {
225                http: h,
226                credentials: cr,
227                signer: Arc::from(crate::signer::create_signer(crate::signer::SignVersion::V4)),
228                region: Region::CnHangzhou,
229                endpoint: "oss-cn-hangzhou.aliyuncs.com".into(),
230            }),
231            rq,
232        )
233    }
234
235    #[test]
236    fn resource_group_xml() {
237        let c = ResourceGroupConfig {
238            resource_group_id: "rg-xxx".into(),
239        };
240        let x = crate::util::xml::to_xml(&c).unwrap();
241        assert!(x.contains("<ResourceGroupId>rg-xxx</ResourceGroupId>"));
242    }
243    #[tokio::test]
244    async fn put_sends_request() {
245        let (i, r) = ci();
246        PutBucketResourceGroupBuilder::new(i, BucketName::new("test-bucket").unwrap(), "rg-1")
247            .send()
248            .await
249            .unwrap();
250        assert_eq!(r.lock().unwrap()[0].method, http::Method::PUT);
251    }
252}