Skip to content

Commit 319a7c5

Browse files
[Storage] get_blob_properties for BlobClient (Azure#2014)
1 parent 4e0ba1e commit 319a7c5

File tree

12 files changed

+309
-9
lines changed

12 files changed

+309
-9
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
# AzureSDKOwners: @heaths
5555
# ServiceLabel: %Storage
5656
# PRLabel: %Storage
57-
/sdk/storage/ @heaths @RickWinter @JeffreyRichter @LarryOsterman
57+
/sdk/storage/ @heaths @RickWinter @JeffreyRichter @LarryOsterman @vincenttran-msft @jalauzon-msft
5858

5959
# AzureSDKOwners: @heaths
6060
# ServiceOwner: @Pilchie

Cargo.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sdk/storage/.dict.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,7 @@ copyid
77
deletetype
88
incrementalcopy
99
legalhold
10+
missingcontainer
1011
RAGRS
1112
restype
13+
testcontainer

sdk/storage/azure_storage_blob/Cargo.toml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,20 @@ rust-version.workspace = true
1010
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1111

1212
[dependencies]
13+
async-trait.workspace = true
1314
azure_storage_common.workspace = true
1415
azure_core = { workspace = true, features = ["xml"] }
15-
serde = { workspace = true }
16-
time = { workspace = true }
16+
azure_identity = { workspace = true }
17+
serde.workspace = true
18+
time.workspace = true
1719
typespec_client_core = { workspace = true, features = ["derive"] }
20+
uuid.workspace = true
21+
url.workspace = true
1822

1923
[lints]
2024
workspace = true
25+
26+
[dev-dependencies]
27+
tokio = { workspace = true, features = ["macros"] }
28+
azure_identity.workspace = true
29+
azure_core_test.path = "../../core/azure_core_test"
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,69 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
3+
4+
use crate::{
5+
models::BlobProperties, pipeline::StorageHeadersPolicy, BlobBlobClientGetPropertiesOptions,
6+
BlobClientOptions, GeneratedBlobClient,
7+
};
8+
use azure_core::{credentials::TokenCredential, BearerTokenCredentialPolicy, Policy, Result, Url};
9+
use std::sync::Arc;
10+
11+
pub struct BlobClient {
12+
endpoint: Url,
13+
container_name: String,
14+
blob_name: String,
15+
client: GeneratedBlobClient,
16+
}
17+
18+
impl BlobClient {
19+
pub fn new(
20+
endpoint: &str,
21+
container_name: String,
22+
blob_name: String,
23+
credential: Arc<dyn TokenCredential>,
24+
options: Option<BlobClientOptions>,
25+
) -> Result<Self> {
26+
let mut options = options.unwrap_or_default();
27+
28+
let storage_headers_policy = Arc::new(StorageHeadersPolicy);
29+
options
30+
.client_options
31+
.per_call_policies
32+
.push(storage_headers_policy);
33+
34+
let oauth_token_policy = BearerTokenCredentialPolicy::new(
35+
credential.clone(),
36+
["https://storage.azure.com/.default"],
37+
);
38+
options
39+
.client_options
40+
.per_try_policies
41+
.push(Arc::new(oauth_token_policy) as Arc<dyn Policy>);
42+
43+
let client = GeneratedBlobClient::new(endpoint, credential, Some(options))?;
44+
Ok(Self {
45+
endpoint: endpoint.parse()?,
46+
container_name,
47+
blob_name,
48+
client,
49+
})
50+
}
51+
52+
pub fn endpoint(&self) -> &Url {
53+
&self.endpoint
54+
}
55+
56+
pub async fn get_blob_properties(
57+
&self,
58+
options: Option<BlobBlobClientGetPropertiesOptions<'_>>,
59+
) -> Result<BlobProperties> {
60+
let response = self
61+
.client
62+
.get_blob_blob_client(self.container_name.clone(), self.blob_name.clone())
63+
.get_properties(options)
64+
.await?;
65+
66+
let blob_properties: BlobProperties = response.headers().get()?;
67+
Ok(blob_properties)
68+
}
69+
}

sdk/storage/azure_storage_blob/src/clients/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
mod blob_client;
55
mod blob_container_client;
66
mod blob_service_client;
7+
8+
pub use blob_client::BlobClient;

sdk/storage/azure_storage_blob/src/lib.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
// Licensed under the MIT License. See License.txt in the project root for license information.
44
// Code generated by Microsoft (R) Rust Code Generator. DO NOT EDIT.
55

6+
mod clients;
67
mod generated;
78

8-
pub use crate::generated::clients::*;
9+
pub(crate) mod pipeline;
10+
11+
pub use clients::*;
912

10-
pub mod models {
11-
pub use crate::generated::enums::*;
12-
pub use crate::generated::models::*;
13-
}
13+
pub mod models;
14+
15+
pub use crate::generated::clients::*;
16+
pub(crate) use blob_client::BlobClient as GeneratedBlobClient;
1417

15-
pub use blob_client::BlobClient;
18+
pub use crate::generated::clients::blob_blob_client::BlobBlobClientGetPropertiesOptions;
19+
pub use crate::generated::clients::blob_client::BlobClientOptions;
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
use azure_core::{
5+
headers::{
6+
FromHeaders, HeaderName, Headers, BLOB_ACCESS_TIER, BLOB_TYPE, CREATION_TIME, LEASE_STATE,
7+
LEASE_STATUS, SERVER_ENCRYPTED,
8+
},
9+
Error, Etag, LeaseStatus,
10+
};
11+
use typespec_client_core::fmt::SafeDebug;
12+
13+
use crate::models::{AccessTier, BlobType, LeaseState};
14+
15+
pub const CONTENT_LENGTH: HeaderName = HeaderName::from_static("content-length");
16+
pub const CONTENT_MD5: HeaderName = HeaderName::from_static("content-md5");
17+
pub const CONTENT_TYPE: HeaderName = HeaderName::from_static("content-type");
18+
pub const ETAG: HeaderName = HeaderName::from_static("etag");
19+
pub const LAST_MODIFIED: HeaderName = HeaderName::from_static("last-modified");
20+
pub const BLOB_ACCESS_TIER_INFERRED: HeaderName =
21+
HeaderName::from_static("x-ms-access-tier-inferred");
22+
23+
/// Properties of an Azure Storage blob.
24+
///
25+
#[derive(Clone, Default, SafeDebug)]
26+
pub struct BlobProperties {
27+
pub access_tier_inferred: Option<bool>,
28+
pub access_tier: Option<AccessTier>,
29+
pub blob_type: Option<BlobType>,
30+
pub content_length: Option<i64>,
31+
pub content_md5: Option<String>,
32+
pub content_type: Option<String>,
33+
pub creation_time: Option<String>,
34+
pub etag: Option<Etag>,
35+
pub last_modified: Option<String>,
36+
pub lease_state: Option<LeaseState>,
37+
pub lease_status: Option<LeaseStatus>,
38+
pub server_encrypted: Option<bool>,
39+
}
40+
41+
impl FromHeaders for BlobProperties {
42+
type Error = Error;
43+
fn header_names() -> &'static [&'static str] {
44+
&[
45+
"content-length",
46+
"content-md5",
47+
"content-type",
48+
"etag",
49+
"last-modified",
50+
"x-ms-access-tier-inferred",
51+
"x-ms-access-tier",
52+
"x-ms-blob-type",
53+
"x-ms-creation-time",
54+
"x-ms-lease-state",
55+
"x-ms-lease-status",
56+
"x-ms-server-encrypted",
57+
]
58+
}
59+
60+
fn from_headers(headers: &Headers) -> Result<Option<Self>, Error> {
61+
let mut properties = BlobProperties {
62+
..Default::default()
63+
};
64+
65+
let access_tier_inferred: Option<bool> =
66+
headers.get_optional_as(&BLOB_ACCESS_TIER_INFERRED)?;
67+
properties.access_tier_inferred = access_tier_inferred;
68+
69+
let access_tier: Option<AccessTier> = headers.get_optional_as(&BLOB_ACCESS_TIER)?;
70+
properties.access_tier = access_tier;
71+
72+
let blob_type: Option<BlobType> = headers.get_optional_as(&BLOB_TYPE)?;
73+
properties.blob_type = blob_type;
74+
75+
let content_length: Option<i64> = headers.get_optional_as(&CONTENT_LENGTH)?;
76+
properties.content_length = content_length;
77+
78+
let content_md5 = headers.get_optional_str(&CONTENT_MD5);
79+
properties.content_md5 = content_md5.map(|s| s.to_string());
80+
81+
let content_type = headers.get_optional_str(&CONTENT_TYPE);
82+
properties.content_type = content_type.map(|s| s.to_string());
83+
84+
let creation_time = headers.get_optional_str(&CREATION_TIME);
85+
properties.creation_time = creation_time.map(|s| s.to_string());
86+
87+
let etag: Option<Etag> = headers.get_optional_as(&ETAG)?;
88+
properties.etag = etag;
89+
90+
let last_modified = headers.get_optional_str(&LAST_MODIFIED);
91+
properties.last_modified = last_modified.map(|s| s.to_string());
92+
93+
let lease_state: Option<LeaseState> = headers.get_optional_as(&LEASE_STATE)?;
94+
properties.lease_state = lease_state;
95+
96+
let lease_status: Option<LeaseStatus> = headers.get_optional_as(&LEASE_STATUS)?;
97+
properties.lease_status = lease_status;
98+
99+
let server_encrypted: Option<bool> = headers.get_optional_as(&SERVER_ENCRYPTED)?;
100+
properties.server_encrypted = server_encrypted;
101+
102+
Ok(Some(properties))
103+
}
104+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
mod blob_properties;
5+
6+
pub use crate::generated::enums::*;
7+
pub use crate::generated::models::*;
8+
9+
pub use blob_properties::BlobProperties;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
mod storage_headers_policy;
5+
6+
pub use storage_headers_policy::StorageHeadersPolicy;

0 commit comments

Comments
 (0)