1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
pub use crate::generated::clients::{BlobServiceClient, BlobServiceClientOptions};
use crate::{BlobClient, BlobContainerClient};
use azure_core::{
credentials::TokenCredential,
http::{
policies::{auth::BearerTokenAuthorizationPolicy, Policy},
Pipeline, Url,
},
tracing, Result,
};
use std::sync::Arc;
impl BlobServiceClient {
/// Creates a new BlobServiceClient, using Entra ID authentication.
///
/// # Arguments
///
/// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/`
/// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating.
/// * `options` - Optional configuration for the client.
#[tracing::new("Storage.Blob.Service")]
pub fn new(
endpoint: &str,
credential: Option<Arc<dyn TokenCredential>>,
options: Option<BlobServiceClientOptions>,
) -> Result<Self> {
let endpoint = Url::parse(endpoint)?;
let mut options = options.unwrap_or_default();
super::apply_client_defaults(&mut options.client_options);
if let Some(token_credential) = credential {
if !endpoint.scheme().starts_with("https") {
return Err(azure_core::Error::with_message(
azure_core::error::ErrorKind::Other,
format!("{endpoint} must use https"),
));
}
let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(
token_credential,
vec!["https://storage.azure.com/.default"],
));
options.client_options.per_try_policies.push(auth_policy);
}
let pipeline = Pipeline::new(
option_env!("CARGO_PKG_NAME"),
option_env!("CARGO_PKG_VERSION"),
options.client_options.clone(),
Vec::default(),
Vec::default(),
None,
);
Ok(Self {
endpoint,
version: options.version,
pipeline,
})
}
/// Returns a new instance of BlobContainerClient.
///
/// # Arguments
///
/// * `container_name` - The name of the container.
pub fn blob_container_client(&self, container_name: &str) -> BlobContainerClient {
let mut container_url = self.url().clone();
container_url
.path_segments_mut()
// This should not fail as service URL has already been validated on client construction.
.expect("Cannot be a base URL.")
.push(container_name);
BlobContainerClient {
endpoint: container_url,
pipeline: self.pipeline.clone(),
version: self.version.clone(),
tracer: self.tracer.clone(),
}
}
/// Returns a new instance of BlobClient.
///
/// # Arguments
///
/// * `container_name` - The name of the container.
/// * `blob_name` - The name of the blob.
pub fn blob_client(&self, container_name: &str, blob_name: &str) -> BlobClient {
let mut blob_url = self.url().clone();
blob_url
.path_segments_mut()
// This should not fail as service URL has already been validated on client construction.
.expect("Cannot be a base URL.")
.extend([container_name, blob_name]);
BlobClient {
endpoint: blob_url,
pipeline: self.pipeline.clone(),
version: self.version.clone(),
tracer: self.tracer.clone(),
}
}
/// Gets the URL of the resource this client is configured for.
pub fn url(&self) -> &Url {
&self.endpoint
}
}