Skip to content

Commit

Permalink
Mostly working, issue with generated get_block_list
Browse files Browse the repository at this point in the history
  • Loading branch information
vincenttran-msft committed Mar 4, 2025
1 parent f1fe84f commit 386879b
Show file tree
Hide file tree
Showing 13 changed files with 670 additions and 75 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ path = "sdk/identity/azure_identity"
version = "0.1.0"
path = "sdk/storage"

[workspace.dependencies.azure_storage_blob]
version = "0.1.0"
path = "sdk/storage/azure_storage_blob"

[workspace.dependencies]
async-lock = "3.0"
async-process = "2.0"
Expand Down
9 changes: 5 additions & 4 deletions sdk/storage/azure_storage_blob/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ rust-version.workspace = true

[dependencies]
async-trait.workspace = true
azure_storage_common.workspace = true
azure_core = { workspace = true, features = ["xml"] }
azure_identity = { workspace = true }
azure_storage_common.workspace = true
serde.workspace = true
time.workspace = true
typespec_client_core = { workspace = true, features = ["derive"] }
uuid.workspace = true
url.workspace = true
uuid.workspace = true

[lints]
workspace = true

[dev-dependencies]
tokio = { workspace = true, features = ["macros"] }
azure_identity.workspace = true
azure_core_test.path = "../../core/azure_core_test"
azure_identity.workspace = true
azure_storage_blob_test.path = "../azure_storage_blob_test"
tokio = { workspace = true, features = ["macros"] }
50 changes: 47 additions & 3 deletions sdk/storage/azure_storage_blob/src/clients/blob_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ use crate::{
clients::GeneratedBlobClient,
models::{
BlobBlobClientDownloadOptions, BlobBlobClientGetPropertiesOptions,
BlobBlockBlobClientUploadOptions, BlobProperties,
BlobBlockBlobClientCommitBlockListOptions, BlobBlockBlobClientGetBlockListOptions,
BlobBlockBlobClientStageBlockOptions, BlobBlockBlobClientUploadOptions, BlobProperties,
BlockListType, BlockLookupList,
},
pipeline::StorageHeadersPolicy,
BlobClientOptions,
};
use azure_core::{
credentials::TokenCredential, BearerTokenCredentialPolicy, Bytes, Policy, RequestContent,
Response, Result, Url,
base64, credentials::TokenCredential, BearerTokenCredentialPolicy, Bytes, Policy,
RequestContent, Response, Result, Url,
};
use std::sync::Arc;

Expand Down Expand Up @@ -117,4 +119,46 @@ impl BlobClient {
.await?;
Ok(response)
}

pub async fn commit_block_list(
&self,
blocks: RequestContent<BlockLookupList>,
options: Option<BlobBlockBlobClientCommitBlockListOptions<'_>>,
) -> Result<Response<()>> {
let response = self
.client
.get_blob_block_blob_client(self.container_name.clone(), self.blob_name.clone())
.commit_block_list(blocks, options)
.await?;
Ok(response)
}

pub async fn get_block_list(
&self,
list_type: BlockListType,
options: Option<BlobBlockBlobClientGetBlockListOptions<'_>>,
) -> Result<Response<BlockLookupList>> {
let response = self
.client
.get_blob_block_blob_client(self.container_name.clone(), self.blob_name.clone())
.get_block_list(list_type, options)
.await?;
Ok(response)
}

pub async fn stage_block(
&self,
block_id: &str,
content_length: i64,
body: RequestContent<Bytes>,
options: Option<BlobBlockBlobClientStageBlockOptions<'_>>,
) -> Result<Response<()>> {
let block_id = base64::encode(block_id);
let response = self
.client
.get_blob_block_blob_client(self.container_name.clone(), self.blob_name.clone())
.stage_block(&block_id, content_length, body, options)
.await?;
Ok(response)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
// Licensed under the MIT License.

use crate::clients::GeneratedBlobClient;
use crate::models::{BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions};
use crate::models::{
BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions,
BlobContainerClientGetPropertiesOptions, ContainerProperties,
};
use crate::pipeline::StorageHeadersPolicy;
use crate::BlobClientOptions;
use azure_core::{
Expand Down Expand Up @@ -80,4 +83,18 @@ impl BlobContainerClient {
.await?;
Ok(response)
}

pub async fn get_container_properties(
&self,
options: Option<BlobContainerClientGetPropertiesOptions<'_>>,
) -> Result<ContainerProperties> {
let response = self
.client
.get_blob_container_client(self.container_name.clone())
.get_properties(options)
.await?;

let container_properties: ContainerProperties = response.headers().get()?;
Ok(container_properties)
}
}
64 changes: 64 additions & 0 deletions sdk/storage/azure_storage_blob/src/clients/blob_service_client.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,66 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

use crate::{
clients::GeneratedBlobClient,
models::{BlobServiceClientGetPropertiesOptions, StorageServiceProperties},
pipeline::StorageHeadersPolicy,
BlobClientOptions,
};
use azure_core::{
credentials::TokenCredential, BearerTokenCredentialPolicy, Policy, Response, Result, Url,
};
use std::sync::Arc;

pub struct BlobServiceClient {
endpoint: Url,
client: GeneratedBlobClient,
}

impl BlobServiceClient {
pub fn new(
endpoint: &str,
credential: Arc<dyn TokenCredential>,
options: Option<BlobClientOptions>,
) -> Result<Self> {
let mut options = options.unwrap_or_default();

let storage_headers_policy = Arc::new(StorageHeadersPolicy);
options
.client_options
.per_call_policies
.push(storage_headers_policy);

let oauth_token_policy = BearerTokenCredentialPolicy::new(
credential.clone(),
["https://storage.azure.com/.default"],
);
options
.client_options
.per_try_policies
.push(Arc::new(oauth_token_policy) as Arc<dyn Policy>);

let client = GeneratedBlobClient::new(endpoint, credential, Some(options))?;

Ok(Self {
endpoint: endpoint.parse()?,
client,
})
}

pub fn endpoint(&self) -> &Url {
&self.endpoint
}

pub async fn get_service_properties(
&self,
options: Option<BlobServiceClientGetPropertiesOptions<'_>>,
) -> Result<Response<StorageServiceProperties>> {
let response = self
.client
.get_blob_service_client()
.get_properties(options)
.await?;
Ok(response)
}
}
5 changes: 5 additions & 0 deletions sdk/storage/azure_storage_blob/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ mod generated;
pub mod clients {
pub mod blob_client;
pub mod blob_container_client;
pub mod blob_service_client;

pub use blob_client::BlobClient;
pub use blob_container_client::BlobContainerClient as ContainerClient;
pub use blob_service_client::BlobServiceClient as ServiceClient;

pub use crate::generated::clients::{
BlobAppendBlobClient, BlobBlobClient, BlobBlockBlobClient,
Expand Down Expand Up @@ -60,6 +62,9 @@ pub mod models {

mod blob_properties;
pub use blob_properties::BlobProperties;

mod container_properties;
pub use container_properties::ContainerProperties;
}

pub use crate::generated::clients::{BlobClient, BlobClientOptions};
Expand Down
91 changes: 91 additions & 0 deletions sdk/storage/azure_storage_blob/src/models/container_properties.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

use azure_core::{
headers::{
FromHeaders, HeaderName, Headers, ETAG, HAS_IMMUTABILITY_POLICY, HAS_LEGAL_HOLD,
LEASE_STATE, LEASE_STATUS, VERSION,
},
Error, Etag, LeaseStatus,
};
use typespec_client_core::fmt::SafeDebug;

use crate::models::LeaseState;

pub const LAST_MODIFIED: HeaderName = HeaderName::from_static("last-modified");
pub const IMMUTABLE_STORAGE_WITH_VERSIONING_ENABLED: HeaderName =
HeaderName::from_static("x-ms-immutable-storage-with-versioning-enabled");

/// Properties of an Azure Storage container.
///
#[derive(Clone, Default, SafeDebug)]
pub struct ContainerProperties {
pub last_modified: Option<String>,
pub lease_state: Option<LeaseState>,
pub lease_status: Option<LeaseStatus>,
pub has_immutability_policy: Option<bool>,
pub has_legal_hold: Option<bool>,
pub immutable_storage_with_versioning_enabled: Option<String>,
pub etag: Option<Etag>,
pub version: Option<String>,
}

impl FromHeaders for ContainerProperties {
type Error = Error;
fn header_names() -> &'static [&'static str] {
&[
"etag",
"last-modified",
"x-ms-lease-state",
"x-ms-lease-status",
"x-ms-immutable-storage-with-versioning-enabled",
"x-ms-has-immutability-policy",
"x-ms-version",
"x-ms-has-legal-hold",
]
}

fn from_headers(headers: &Headers) -> Result<Option<Self>, Error> {
let mut properties = ContainerProperties {
..Default::default()
};

let last_modified = headers.get_optional_str(&LAST_MODIFIED);
properties.last_modified = last_modified.map(|s| s.to_string());

let lease_state: Option<LeaseState> = headers.get_optional_as(&LEASE_STATE)?;
properties.lease_state = lease_state;

let lease_status: Option<LeaseStatus> = headers.get_optional_as(&LEASE_STATUS)?;
properties.lease_status = lease_status;

let has_immutability_policy: Option<bool> =
headers.get_optional_as(&HAS_IMMUTABILITY_POLICY)?;
properties.has_immutability_policy = has_immutability_policy;

let has_legal_hold: Option<bool> = headers.get_optional_as(&HAS_LEGAL_HOLD)?;
properties.has_legal_hold = has_legal_hold;

let immutable_storage_with_versioning_enabled =
headers.get_optional_str(&IMMUTABLE_STORAGE_WITH_VERSIONING_ENABLED);
properties.immutable_storage_with_versioning_enabled =
immutable_storage_with_versioning_enabled.map(|s| s.to_string());

let version = headers.get_optional_str(&VERSION);
properties.version = version.map(|s| s.to_string());

let etag: Option<Etag> = headers.get_optional_as(&ETAG)?;
properties.etag = etag;

let last_modified = headers.get_optional_str(&LAST_MODIFIED);
properties.last_modified = last_modified.map(|s| s.to_string());

let lease_state: Option<LeaseState> = headers.get_optional_as(&LEASE_STATE)?;
properties.lease_state = lease_state;

let lease_status: Option<LeaseStatus> = headers.get_optional_as(&LEASE_STATUS)?;
properties.lease_status = lease_status;

Ok(Some(properties))
}
}
Loading

0 comments on commit 386879b

Please sign in to comment.