Skip to main content

aliyun_oss/operations/
bucket_access_monitor.rs

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