1use crate::generated::models::{
7 BlobServiceClientFindBlobsByTagsOptions, BlobServiceClientGetAccountInfoOptions,
8 BlobServiceClientGetAccountInfoResult, BlobServiceClientGetPropertiesOptions,
9 BlobServiceClientGetStatisticsOptions, BlobServiceClientGetUserDelegationKeyOptions,
10 BlobServiceClientListContainersOptions, BlobServiceClientSetPropertiesOptions,
11 BlobServiceProperties, FilteredBlobResponse, KeyInfo, ListContainersResponse,
12 StorageServiceStats,
13};
14use azure_core::{
15 error::CheckSuccessOptions,
16 fmt::SafeDebug,
17 http::{
18 pager::{PagerContinuation, PagerResult, PagerState},
19 ClientOptions, Method, NoFormat, Pager, Pipeline, PipelineSendOptions, RawResponse,
20 Request, RequestContent, Response, Url, UrlExt, XmlFormat,
21 },
22 tracing, xml, Result,
23};
24use azure_storage_common::models::UserDelegationKey;
25
26#[tracing::client]
27pub struct BlobServiceClient {
28 pub(crate) endpoint: Url,
29 pub(crate) pipeline: Pipeline,
30 pub(crate) version: String,
31}
32
33#[derive(Clone, SafeDebug)]
35pub struct BlobServiceClientOptions {
36 pub client_options: ClientOptions,
38 pub version: String,
40}
41
42impl BlobServiceClient {
43 #[tracing::function("Storage.Blob.BlobServiceClient.findBlobsByTags")]
50 pub fn find_blobs_by_tags(
51 &self,
52 filter_expression: &str,
53 options: Option<BlobServiceClientFindBlobsByTagsOptions<'_>>,
54 ) -> Result<Pager<FilteredBlobResponse, XmlFormat>> {
55 let options = options.unwrap_or_default().into_owned();
56 let pipeline = self.pipeline.clone();
57 let mut first_url = self.endpoint.clone();
58 let mut query_builder = first_url.query_builder();
59 query_builder.append_pair("comp", "blobs");
60 if let Some(include) = options.include.as_ref() {
61 query_builder.set_pair(
62 "include",
63 include
64 .iter()
65 .map(|i| i.to_string())
66 .collect::<Vec<String>>()
67 .join(","),
68 );
69 }
70 if let Some(marker) = options.marker.as_ref() {
71 query_builder.set_pair("marker", marker);
72 }
73 if let Some(maxresults) = options.maxresults {
74 query_builder.set_pair("maxresults", maxresults.to_string());
75 }
76 if let Some(timeout) = options.timeout {
77 query_builder.set_pair("timeout", timeout.to_string());
78 }
79 query_builder.set_pair("where", filter_expression);
80 query_builder.build();
81 #[derive(serde::Deserialize)]
82 struct BlobServiceClientFindBlobsByTagsPage {
83 #[serde(rename = "NextMarker")]
84 next_marker: Option<String>,
85 }
86
87 let version = self.version.clone();
88 Ok(Pager::new(
89 move |marker: PagerState, pager_options| {
90 let mut url = first_url.clone();
91 if let PagerState::More(marker) = marker {
92 let mut query_builder = url.query_builder();
93 query_builder.set_pair("marker", marker.as_ref());
94 query_builder.build();
95 }
96 let mut request = Request::new(url, Method::Get);
97 request.insert_header("accept", "application/xml");
98 request.insert_header("x-ms-version", &version);
99 let pipeline = pipeline.clone();
100 Box::pin(async move {
101 let rsp = pipeline
102 .send(
103 &pager_options.context,
104 &mut request,
105 Some(PipelineSendOptions {
106 check_success: CheckSuccessOptions {
107 success_codes: &[200],
108 },
109 ..Default::default()
110 }),
111 )
112 .await?;
113 let (status, headers, body) = rsp.deconstruct();
114 let res: BlobServiceClientFindBlobsByTagsPage = xml::from_xml(&body)?;
115 let rsp = RawResponse::from_bytes(status, headers, body).into();
116 Ok(match res.next_marker {
117 Some(next_marker) if !next_marker.is_empty() => PagerResult::More {
118 response: rsp,
119 continuation: PagerContinuation::Token(next_marker),
120 },
121 _ => PagerResult::Done { response: rsp },
122 })
123 })
124 },
125 Some(options.method_options),
126 ))
127 }
128
129 #[tracing::function("Storage.Blob.BlobServiceClient.getAccountInfo")]
166 pub async fn get_account_info(
167 &self,
168 options: Option<BlobServiceClientGetAccountInfoOptions<'_>>,
169 ) -> Result<Response<BlobServiceClientGetAccountInfoResult, NoFormat>> {
170 let options = options.unwrap_or_default();
171 let ctx = options.method_options.context.to_borrowed();
172 let mut url = self.endpoint.clone();
173 let mut query_builder = url.query_builder();
174 query_builder
175 .append_pair("comp", "properties")
176 .append_pair("restype", "account");
177 if let Some(timeout) = options.timeout {
178 query_builder.set_pair("timeout", timeout.to_string());
179 }
180 query_builder.build();
181 let mut request = Request::new(url, Method::Get);
182 request.insert_header("x-ms-version", &self.version);
183 let rsp = self
184 .pipeline
185 .send(
186 &ctx,
187 &mut request,
188 Some(PipelineSendOptions {
189 check_success: CheckSuccessOptions {
190 success_codes: &[200],
191 },
192 ..Default::default()
193 }),
194 )
195 .await?;
196 Ok(rsp.into())
197 }
198
199 #[tracing::function("Storage.Blob.BlobServiceClient.getProperties")]
206 pub async fn get_properties(
207 &self,
208 options: Option<BlobServiceClientGetPropertiesOptions<'_>>,
209 ) -> Result<Response<BlobServiceProperties, XmlFormat>> {
210 let options = options.unwrap_or_default();
211 let ctx = options.method_options.context.to_borrowed();
212 let mut url = self.endpoint.clone();
213 let mut query_builder = url.query_builder();
214 query_builder
215 .append_pair("comp", "properties")
216 .append_pair("restype", "service");
217 if let Some(timeout) = options.timeout {
218 query_builder.set_pair("timeout", timeout.to_string());
219 }
220 query_builder.build();
221 let mut request = Request::new(url, Method::Get);
222 request.insert_header("accept", "application/xml");
223 request.insert_header("x-ms-version", &self.version);
224 let rsp = self
225 .pipeline
226 .send(
227 &ctx,
228 &mut request,
229 Some(PipelineSendOptions {
230 check_success: CheckSuccessOptions {
231 success_codes: &[200],
232 },
233 ..Default::default()
234 }),
235 )
236 .await?;
237 Ok(rsp.into())
238 }
239
240 #[tracing::function("Storage.Blob.BlobServiceClient.getStatistics")]
247 pub async fn get_statistics(
248 &self,
249 options: Option<BlobServiceClientGetStatisticsOptions<'_>>,
250 ) -> Result<Response<StorageServiceStats, XmlFormat>> {
251 let options = options.unwrap_or_default();
252 let ctx = options.method_options.context.to_borrowed();
253 let mut url = self.endpoint.clone();
254 let mut query_builder = url.query_builder();
255 query_builder
256 .append_pair("comp", "stats")
257 .append_pair("restype", "service");
258 if let Some(timeout) = options.timeout {
259 query_builder.set_pair("timeout", timeout.to_string());
260 }
261 query_builder.build();
262 let mut request = Request::new(url, Method::Get);
263 request.insert_header("accept", "application/xml");
264 request.insert_header("x-ms-version", &self.version);
265 let rsp = self
266 .pipeline
267 .send(
268 &ctx,
269 &mut request,
270 Some(PipelineSendOptions {
271 check_success: CheckSuccessOptions {
272 success_codes: &[200],
273 },
274 ..Default::default()
275 }),
276 )
277 .await?;
278 Ok(rsp.into())
279 }
280
281 #[tracing::function("Storage.Blob.BlobServiceClient.getUserDelegationKey")]
288 pub async fn get_user_delegation_key(
289 &self,
290 key_info: RequestContent<KeyInfo, XmlFormat>,
291 options: Option<BlobServiceClientGetUserDelegationKeyOptions<'_>>,
292 ) -> Result<Response<UserDelegationKey, XmlFormat>> {
293 let options = options.unwrap_or_default();
294 let ctx = options.method_options.context.to_borrowed();
295 let mut url = self.endpoint.clone();
296 let mut query_builder = url.query_builder();
297 query_builder
298 .append_pair("comp", "userdelegationkey")
299 .append_pair("restype", "service");
300 if let Some(timeout) = options.timeout {
301 query_builder.set_pair("timeout", timeout.to_string());
302 }
303 query_builder.build();
304 let mut request = Request::new(url, Method::Post);
305 request.insert_header("accept", "application/xml");
306 request.insert_header("content-type", "application/xml");
307 request.insert_header("x-ms-version", &self.version);
308 request.set_body(key_info);
309 let rsp = self
310 .pipeline
311 .send(
312 &ctx,
313 &mut request,
314 Some(PipelineSendOptions {
315 check_success: CheckSuccessOptions {
316 success_codes: &[200],
317 },
318 ..Default::default()
319 }),
320 )
321 .await?;
322 Ok(rsp.into())
323 }
324
325 #[tracing::function("Storage.Blob.BlobServiceClient.listContainers")]
331 pub fn list_containers(
332 &self,
333 options: Option<BlobServiceClientListContainersOptions<'_>>,
334 ) -> Result<Pager<ListContainersResponse, XmlFormat>> {
335 let options = options.unwrap_or_default().into_owned();
336 let pipeline = self.pipeline.clone();
337 let mut first_url = self.endpoint.clone();
338 let mut query_builder = first_url.query_builder();
339 query_builder.append_pair("comp", "list");
340 if let Some(include) = options.include.as_ref() {
341 query_builder.set_pair(
342 "include",
343 include
344 .iter()
345 .map(|i| i.to_string())
346 .collect::<Vec<String>>()
347 .join(","),
348 );
349 }
350 if let Some(marker) = options.marker.as_ref() {
351 query_builder.set_pair("marker", marker);
352 }
353 if let Some(maxresults) = options.maxresults {
354 query_builder.set_pair("maxresults", maxresults.to_string());
355 }
356 if let Some(prefix) = options.prefix.as_ref() {
357 query_builder.set_pair("prefix", prefix);
358 }
359 if let Some(timeout) = options.timeout {
360 query_builder.set_pair("timeout", timeout.to_string());
361 }
362 query_builder.build();
363 #[derive(serde::Deserialize)]
364 struct BlobServiceClientListContainersPage {
365 #[serde(rename = "NextMarker")]
366 next_marker: Option<String>,
367 }
368
369 let version = self.version.clone();
370 Ok(Pager::new(
371 move |marker: PagerState, pager_options| {
372 let mut url = first_url.clone();
373 if let PagerState::More(marker) = marker {
374 let mut query_builder = url.query_builder();
375 query_builder.set_pair("marker", marker.as_ref());
376 query_builder.build();
377 }
378 let mut request = Request::new(url, Method::Get);
379 request.insert_header("accept", "application/xml");
380 request.insert_header("x-ms-version", &version);
381 let pipeline = pipeline.clone();
382 Box::pin(async move {
383 let rsp = pipeline
384 .send(
385 &pager_options.context,
386 &mut request,
387 Some(PipelineSendOptions {
388 check_success: CheckSuccessOptions {
389 success_codes: &[200],
390 },
391 ..Default::default()
392 }),
393 )
394 .await?;
395 let (status, headers, body) = rsp.deconstruct();
396 let res: BlobServiceClientListContainersPage = xml::from_xml(&body)?;
397 let rsp = RawResponse::from_bytes(status, headers, body).into();
398 Ok(match res.next_marker {
399 Some(next_marker) if !next_marker.is_empty() => PagerResult::More {
400 response: rsp,
401 continuation: PagerContinuation::Token(next_marker),
402 },
403 _ => PagerResult::Done { response: rsp },
404 })
405 })
406 },
407 Some(options.method_options),
408 ))
409 }
410
411 #[tracing::function("Storage.Blob.BlobServiceClient.setProperties")]
419 pub async fn set_properties(
420 &self,
421 storage_service_properties: RequestContent<BlobServiceProperties, XmlFormat>,
422 options: Option<BlobServiceClientSetPropertiesOptions<'_>>,
423 ) -> Result<Response<(), NoFormat>> {
424 let options = options.unwrap_or_default();
425 let ctx = options.method_options.context.to_borrowed();
426 let mut url = self.endpoint.clone();
427 let mut query_builder = url.query_builder();
428 query_builder
429 .append_pair("comp", "properties")
430 .append_pair("restype", "service");
431 if let Some(timeout) = options.timeout {
432 query_builder.set_pair("timeout", timeout.to_string());
433 }
434 query_builder.build();
435 let mut request = Request::new(url, Method::Put);
436 request.insert_header("content-type", "application/xml");
437 request.insert_header("x-ms-version", &self.version);
438 request.set_body(storage_service_properties);
439 let rsp = self
440 .pipeline
441 .send(
442 &ctx,
443 &mut request,
444 Some(PipelineSendOptions {
445 check_success: CheckSuccessOptions {
446 success_codes: &[202],
447 },
448 ..Default::default()
449 }),
450 )
451 .await?;
452 Ok(rsp.into())
453 }
454}
455
456pub(crate) const DEFAULT_VERSION: &str = "2026-04-06";
458
459impl Default for BlobServiceClientOptions {
460 fn default() -> Self {
461 Self {
462 client_options: ClientOptions::default(),
463 version: String::from(DEFAULT_VERSION),
464 }
465 }
466}