use std::{collections::HashMap, env, sync::Arc};
use azure_core::credentials::TokenCredential;
use azure_identity::DeveloperToolsCredential;
use azure_storage_queue::{
models::{
CorsRule, ListQueuesIncludeType, QueueServiceClientListQueuesOptions,
QueueServiceProperties,
},
QueueServiceClient,
};
use futures::StreamExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let account = env::var("AZURE_QUEUE_STORAGE_ACCOUNT_NAME")
.expect("Set AZURE_QUEUE_STORAGE_ACCOUNT_NAME environment variable");
let endpoint = format!("https://{}.queue.core.windows.net/", account);
let queue_name = random_queue_name();
let credential = DeveloperToolsCredential::new(None)?;
let service_client = QueueServiceClient::new(&endpoint, Some(credential.clone()), None)?;
let queue_client = service_client.queue_client(&queue_name)?;
println!("Creating queue '{queue_name}'...");
queue_client.create(None).await?;
queue_client
.set_metadata(
&HashMap::from([("sample".to_string(), "service-client".to_string())]),
None,
)
.await?;
set_and_get_service_properties(&service_client).await?;
list_queues(&service_client, &queue_name).await?;
get_service_statistics(&account, credential).await?;
queue_client.delete(None).await?;
println!("Deleted queue '{queue_name}'");
Ok(())
}
async fn set_and_get_service_properties(
service_client: &QueueServiceClient,
) -> Result<(), Box<dyn std::error::Error>> {
let properties = QueueServiceProperties {
cors: Some(vec![CorsRule {
allowed_origins: Some("https://example.com".to_string()),
allowed_methods: Some("GET,POST".to_string()),
max_age_in_seconds: Some(3600),
exposed_headers: Some("x-ms-meta-data".to_string()),
allowed_headers: Some("x-ms-meta-target".to_string()),
}]),
..Default::default()
};
service_client
.set_properties(properties.try_into()?, None)
.await?;
println!("Updated queue service properties");
let retrieved = service_client.get_properties(None).await?.into_model()?;
println!(
"Service properties loaded. CORS rules configured: {}",
retrieved.cors.as_ref().map(Vec::len).unwrap_or(0)
);
Ok(())
}
async fn list_queues(
service_client: &QueueServiceClient,
prefix: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let options = QueueServiceClientListQueuesOptions {
prefix: Some(prefix.to_string()),
include: Some(vec![ListQueuesIncludeType::Metadata]),
..Default::default()
};
let mut pages = service_client.list_queues(Some(options))?.into_pages();
println!("Listing queues with prefix '{prefix}'...");
while let Some(page) = pages.next().await {
let queue_list = page?.into_model()?;
for queue in queue_list.queue_items {
println!(" Queue: {}", queue.name.unwrap_or_default());
for (key, value) in queue.metadata.unwrap_or_default() {
println!(" {key}: {value}");
}
}
}
Ok(())
}
async fn get_service_statistics(
account: &str,
credential: Arc<dyn TokenCredential>,
) -> Result<(), Box<dyn std::error::Error>> {
let secondary_endpoint = format!("https://{account}-secondary.queue.core.windows.net/");
let secondary_client = QueueServiceClient::new(&secondary_endpoint, Some(credential), None)?;
match secondary_client.get_statistics(None).await {
Ok(response) => {
let stats = response.into_model()?;
if let Some(geo_replication) = stats.geo_replication {
println!(
"Geo-replication status: {:?}, last sync time: {:?}",
geo_replication.status, geo_replication.last_sync_time
);
}
}
Err(err) => {
eprintln!(
"Skipping statistics example because the secondary endpoint is unavailable: {err}"
);
}
}
Ok(())
}
fn random_queue_name() -> String {
use rand::RngExt;
let mut rng = rand::rng();
let random_suffix: u32 = rng.random_range(1000..9999);
format!("sdk-test-queue-{random_suffix}")
}