azure_storage_blobs/clients/
blob_service_client.rsuse crate::{
clients::{BlobClient, BlobLeaseClient, ContainerClient, ContainerLeaseClient},
service::operations::*,
};
use azure_core::{
headers::Headers, request_options::LeaseId, Body, ClientOptions, Context, Method, Pipeline,
Request, Response, Url,
};
use azure_storage::{
clients::{new_pipeline_from_options, shared_access_signature, ServiceType},
prelude::{AccountSasPermissions, AccountSasResource, AccountSasResourceType},
shared_access_signature::account_sas::AccountSharedAccessSignature,
CloudLocation, StorageCredentials,
};
use time::OffsetDateTime;
#[derive(Debug, Clone)]
pub struct ClientBuilder {
cloud_location: CloudLocation,
options: ClientOptions,
credentials: StorageCredentials,
}
impl ClientBuilder {
#[must_use]
pub fn new<A, C>(account: A, credentials: C) -> Self
where
A: Into<String>,
C: Into<StorageCredentials>,
{
Self::with_location(
CloudLocation::Public {
account: account.into(),
},
credentials,
)
}
#[must_use]
pub fn with_location<C>(cloud_location: CloudLocation, credentials: C) -> Self
where
C: Into<StorageCredentials>,
{
Self {
options: ClientOptions::default(),
cloud_location,
credentials: credentials.into(),
}
}
#[must_use]
pub fn emulator() -> Self {
Self::with_location(
CloudLocation::Emulator {
address: "127.0.0.1".to_owned(),
port: 10000,
},
StorageCredentials::emulator(),
)
}
#[must_use]
pub fn blob_service_client(self) -> BlobServiceClient {
let Self {
cloud_location,
options,
credentials,
} = self;
BlobServiceClient {
pipeline: new_pipeline_from_options(options, credentials.clone()),
cloud_location,
credentials,
}
}
#[must_use]
pub fn container_client(self, container_name: impl Into<String>) -> ContainerClient {
self.blob_service_client().container_client(container_name)
}
#[must_use]
pub fn blob_client(
self,
container_name: impl Into<String>,
blob_name: impl Into<String>,
) -> BlobClient {
self.blob_service_client()
.container_client(container_name)
.blob_client(blob_name)
}
#[must_use]
pub fn container_lease_client(
self,
container_name: impl Into<String>,
lease_id: LeaseId,
) -> ContainerLeaseClient {
self.blob_service_client()
.container_client(container_name)
.container_lease_client(lease_id)
}
#[must_use]
pub fn blob_lease_client(
self,
container_name: impl Into<String>,
blob_name: impl Into<String>,
lease_id: LeaseId,
) -> BlobLeaseClient {
self.blob_service_client()
.container_client(container_name)
.blob_client(blob_name)
.blob_lease_client(lease_id)
}
#[must_use]
pub fn cloud_location(mut self, cloud_location: CloudLocation) -> Self {
self.cloud_location = cloud_location;
self
}
#[must_use]
pub fn retry(mut self, retry: impl Into<azure_core::RetryOptions>) -> Self {
self.options = self.options.retry(retry);
self
}
#[must_use]
pub fn transport(mut self, transport: impl Into<azure_core::TransportOptions>) -> Self {
self.options = self.options.transport(transport);
self
}
#[must_use]
pub fn client_options(mut self, options: impl Into<azure_core::ClientOptions>) -> Self {
self.options = options.into();
self
}
}
#[derive(Debug, Clone)]
pub struct BlobServiceClient {
pipeline: Pipeline,
cloud_location: CloudLocation,
credentials: StorageCredentials,
}
impl BlobServiceClient {
#[must_use]
pub fn new(account: impl Into<String>, credentials: impl Into<StorageCredentials>) -> Self {
ClientBuilder::new(account, credentials).blob_service_client()
}
#[must_use]
pub fn builder(
account: impl Into<String>,
credentials: impl Into<StorageCredentials>,
) -> ClientBuilder {
ClientBuilder::new(account, credentials)
}
pub fn account(&self) -> &str {
self.cloud_location.account()
}
pub fn get_account_information(&self) -> GetAccountInformationBuilder {
GetAccountInformationBuilder::new(self.clone())
}
pub fn find_blobs_by_tags(&self, expression: String) -> FindBlobsByTagsBuilder {
FindBlobsByTagsBuilder::new(self.clone(), expression)
}
pub fn list_containers(&self) -> ListContainersBuilder {
ListContainersBuilder::new(self.clone())
}
pub fn get_properties(&self) -> GetBlobServicePropertiesBuilder {
GetBlobServicePropertiesBuilder::new(self.clone())
}
pub fn url(&self) -> azure_core::Result<Url> {
self.cloud_location.url(ServiceType::Blob)
}
pub fn container_client<S: Into<String>>(&self, container_name: S) -> ContainerClient {
ContainerClient::new(self.clone(), container_name.into())
}
pub fn get_user_deligation_key(
&self,
start: OffsetDateTime,
expiry: OffsetDateTime,
) -> GetUserDelegationKeyBuilder {
GetUserDelegationKeyBuilder::new(self.clone(), start, expiry)
}
pub async fn shared_access_signature(
&self,
resource_type: AccountSasResourceType,
expiry: OffsetDateTime,
permissions: AccountSasPermissions,
) -> azure_core::Result<AccountSharedAccessSignature> {
shared_access_signature(
self.credentials(),
AccountSasResource::Blob,
resource_type,
expiry,
permissions,
)
.await
}
pub async fn update_credentials(
&self,
new_credentials: StorageCredentials,
) -> azure_core::Result<()> {
self.credentials.replace(new_credentials).await
}
pub(crate) fn credentials(&self) -> &StorageCredentials {
&self.credentials
}
pub(crate) fn finalize_request(
url: Url,
method: Method,
headers: Headers,
request_body: Option<Body>,
) -> azure_core::Result<Request> {
azure_storage::clients::finalize_request(url, method, headers, request_body)
}
pub(crate) async fn send(
&self,
context: &mut Context,
request: &mut Request,
) -> azure_core::Result<Response> {
self.pipeline
.send(context.insert(ServiceType::Blob), request)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use azure_storage::StorageCredentialsInner;
use std::ops::Deref;
#[tokio::test]
async fn update_credentials() -> azure_core::Result<()> {
let account = "test";
let keyed = StorageCredentials::access_key(account, "test");
let anonymous = StorageCredentials::anonymous();
let service_client = BlobServiceClient::new(account, keyed);
let container_client = service_client.container_client("test");
let blob_client = container_client.blob_client("test");
service_client.update_credentials(anonymous).await?;
let credentials = blob_client.container_client().credentials();
let locked = credentials.0.read().await;
assert!(matches!(
locked.deref(),
&StorageCredentialsInner::Anonymous
));
Ok(())
}
}