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}