azure_storage_blobs/clients/
blob_service_client.rs1use crate::{
2 clients::{BlobClient, BlobLeaseClient, ContainerClient, ContainerLeaseClient},
3 service::operations::*,
4};
5use azure_core::{
6 headers::Headers, request_options::LeaseId, Body, ClientOptions, Context, Method, Pipeline,
7 Request, Response, Url,
8};
9use azure_storage::{
10 clients::{new_pipeline_from_options, shared_access_signature, ServiceType},
11 prelude::{AccountSasPermissions, AccountSasResource, AccountSasResourceType},
12 shared_access_signature::account_sas::AccountSharedAccessSignature,
13 CloudLocation, StorageCredentials,
14};
15use time::OffsetDateTime;
16
17#[derive(Debug, Clone)]
19pub struct ClientBuilder {
20 cloud_location: CloudLocation,
21 options: ClientOptions,
22 credentials: StorageCredentials,
23}
24
25impl ClientBuilder {
26 #[must_use]
28 pub fn new<A, C>(account: A, credentials: C) -> Self
29 where
30 A: Into<String>,
31 C: Into<StorageCredentials>,
32 {
33 Self::with_location(
34 CloudLocation::Public {
35 account: account.into(),
36 },
37 credentials,
38 )
39 }
40
41 #[must_use]
43 pub fn with_location<C>(cloud_location: CloudLocation, credentials: C) -> Self
44 where
45 C: Into<StorageCredentials>,
46 {
47 Self {
48 options: ClientOptions::default(),
49 cloud_location,
50 credentials: credentials.into(),
51 }
52 }
53
54 #[must_use]
56 pub fn emulator() -> Self {
57 Self::with_location(
58 CloudLocation::Emulator {
59 address: "127.0.0.1".to_owned(),
60 port: 10000,
61 },
62 StorageCredentials::emulator(),
63 )
64 }
65
66 #[must_use]
68 pub fn blob_service_client(self) -> BlobServiceClient {
69 let Self {
70 cloud_location,
71 options,
72 credentials,
73 } = self;
74
75 BlobServiceClient {
76 pipeline: new_pipeline_from_options(options, credentials.clone()),
77 cloud_location,
78 credentials,
79 }
80 }
81
82 #[must_use]
84 pub fn container_client(self, container_name: impl Into<String>) -> ContainerClient {
85 self.blob_service_client().container_client(container_name)
86 }
87
88 #[must_use]
90 pub fn blob_client(
91 self,
92 container_name: impl Into<String>,
93 blob_name: impl Into<String>,
94 ) -> BlobClient {
95 self.blob_service_client()
96 .container_client(container_name)
97 .blob_client(blob_name)
98 }
99
100 #[must_use]
102 pub fn container_lease_client(
103 self,
104 container_name: impl Into<String>,
105 lease_id: LeaseId,
106 ) -> ContainerLeaseClient {
107 self.blob_service_client()
108 .container_client(container_name)
109 .container_lease_client(lease_id)
110 }
111
112 #[must_use]
114 pub fn blob_lease_client(
115 self,
116 container_name: impl Into<String>,
117 blob_name: impl Into<String>,
118 lease_id: LeaseId,
119 ) -> BlobLeaseClient {
120 self.blob_service_client()
121 .container_client(container_name)
122 .blob_client(blob_name)
123 .blob_lease_client(lease_id)
124 }
125
126 #[must_use]
128 pub fn cloud_location(mut self, cloud_location: CloudLocation) -> Self {
129 self.cloud_location = cloud_location;
130 self
131 }
132
133 #[must_use]
135 pub fn retry(mut self, retry: impl Into<azure_core::RetryOptions>) -> Self {
136 self.options = self.options.retry(retry);
137 self
138 }
139
140 #[must_use]
142 pub fn transport(mut self, transport: impl Into<azure_core::TransportOptions>) -> Self {
143 self.options = self.options.transport(transport);
144 self
145 }
146
147 #[must_use]
151 pub fn client_options(mut self, options: impl Into<azure_core::ClientOptions>) -> Self {
152 self.options = options.into();
153 self
154 }
155}
156
157#[derive(Debug, Clone)]
159pub struct BlobServiceClient {
160 pipeline: Pipeline,
161 cloud_location: CloudLocation,
162 credentials: StorageCredentials,
163}
164
165impl BlobServiceClient {
166 #[must_use]
168 pub fn new(account: impl Into<String>, credentials: impl Into<StorageCredentials>) -> Self {
169 ClientBuilder::new(account, credentials).blob_service_client()
170 }
171
172 #[must_use]
174 pub fn builder(
175 account: impl Into<String>,
176 credentials: impl Into<StorageCredentials>,
177 ) -> ClientBuilder {
178 ClientBuilder::new(account, credentials)
179 }
180
181 pub fn account(&self) -> &str {
182 self.cloud_location.account()
183 }
184
185 pub fn get_account_information(&self) -> GetAccountInformationBuilder {
187 GetAccountInformationBuilder::new(self.clone())
188 }
189
190 pub fn find_blobs_by_tags(&self, expression: String) -> FindBlobsByTagsBuilder {
192 FindBlobsByTagsBuilder::new(self.clone(), expression)
193 }
194
195 pub fn list_containers(&self) -> ListContainersBuilder {
197 ListContainersBuilder::new(self.clone())
198 }
199
200 pub fn get_properties(&self) -> GetBlobServicePropertiesBuilder {
201 GetBlobServicePropertiesBuilder::new(self.clone())
202 }
203
204 pub fn url(&self) -> azure_core::Result<Url> {
205 self.cloud_location.url(ServiceType::Blob)
206 }
207
208 pub fn container_client<S: Into<String>>(&self, container_name: S) -> ContainerClient {
209 ContainerClient::new(self.clone(), container_name.into())
210 }
211
212 pub fn get_user_deligation_key(
213 &self,
214 start: OffsetDateTime,
215 expiry: OffsetDateTime,
216 ) -> GetUserDelegationKeyBuilder {
217 GetUserDelegationKeyBuilder::new(self.clone(), start, expiry)
218 }
219
220 pub async fn shared_access_signature(
221 &self,
222 resource_type: AccountSasResourceType,
223 expiry: OffsetDateTime,
224 permissions: AccountSasPermissions,
225 ) -> azure_core::Result<AccountSharedAccessSignature> {
226 shared_access_signature(
227 self.credentials(),
228 AccountSasResource::Blob,
229 resource_type,
230 expiry,
231 permissions,
232 )
233 .await
234 }
235
236 pub async fn update_credentials(
237 &self,
238 new_credentials: StorageCredentials,
239 ) -> azure_core::Result<()> {
240 self.credentials.replace(new_credentials).await
241 }
242
243 pub(crate) fn credentials(&self) -> &StorageCredentials {
244 &self.credentials
245 }
246
247 pub(crate) fn finalize_request(
248 url: Url,
249 method: Method,
250 headers: Headers,
251 request_body: Option<Body>,
252 ) -> azure_core::Result<Request> {
253 azure_storage::clients::finalize_request(url, method, headers, request_body)
254 }
255
256 pub(crate) async fn send(
257 &self,
258 context: &mut Context,
259 request: &mut Request,
260 ) -> azure_core::Result<Response> {
261 self.pipeline
262 .send(context.insert(ServiceType::Blob), request)
263 .await
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270 use azure_storage::StorageCredentialsInner;
271 use std::ops::Deref;
272
273 #[tokio::test]
274 async fn update_credentials() -> azure_core::Result<()> {
275 let account = "test";
276
277 let keyed = StorageCredentials::access_key(account, "test");
278 let anonymous = StorageCredentials::anonymous();
279
280 let service_client = BlobServiceClient::new(account, keyed);
281 let container_client = service_client.container_client("test");
282 let blob_client = container_client.blob_client("test");
283
284 service_client.update_credentials(anonymous).await?;
285
286 let credentials = blob_client.container_client().credentials();
288 let locked = credentials.0.read().await;
289 assert!(matches!(
290 locked.deref(),
291 &StorageCredentialsInner::Anonymous
292 ));
293
294 Ok(())
295 }
296}