rusticity-core 0.1.5

Core AWS SDK integration for Rusticity
Documentation
use crate::config::AwsConfig;
use anyhow::Result;

pub struct S3Client {
    config: AwsConfig,
}

impl S3Client {
    pub fn new(config: AwsConfig) -> Self {
        Self { config }
    }

    pub async fn list_buckets(&self) -> Result<Vec<(String, String, String)>> {
        let client = self.config.s3_client();
        let resp = client.list_buckets().send().await?;

        let buckets: Vec<(String, String, String)> = resp
            .buckets()
            .iter()
            .filter_map(|b| {
                let name = b.name()?.to_string();
                let date = b.creation_date().map(|d| d.to_string()).unwrap_or_default();
                Some((name, String::new(), date))
            })
            .collect();

        Ok(buckets)
    }

    pub async fn get_bucket_location(&self, bucket: &str) -> Result<String> {
        let client = self.config.s3_client();
        let region = match client.get_bucket_location().bucket(bucket).send().await {
            Ok(resp) => match resp.location_constraint() {
                Some(loc) => {
                    let loc_str = loc.as_str();
                    if loc_str.is_empty() || loc_str == "null" {
                        "us-east-1".to_string()
                    } else {
                        loc_str.to_string()
                    }
                }
                None => "us-east-1".to_string(),
            },
            Err(_) => "us-east-1".to_string(),
        };

        Ok(region)
    }

    pub async fn list_objects(
        &self,
        bucket: &str,
        bucket_region: &str,
        prefix: &str,
    ) -> Result<Vec<(String, i64, String, bool, String)>> {
        let client = self.config.s3_client_with_region(bucket_region).await;
        let mut req = client.list_objects_v2().bucket(bucket).delimiter("/");

        if !prefix.is_empty() {
            req = req.prefix(prefix);
        }

        let resp = req.send().await?;

        let mut objects = Vec::new();

        for prefix in resp.common_prefixes() {
            if let Some(p) = prefix.prefix() {
                objects.push((p.to_string(), 0, String::new(), true, String::new()));
            }
        }

        for obj in resp.contents() {
            if let Some(key) = obj.key() {
                let size = obj.size().unwrap_or(0);
                let modified = obj
                    .last_modified()
                    .map(|d| d.to_string())
                    .unwrap_or_default();
                let storage_class = obj
                    .storage_class()
                    .map(|s| s.as_str().to_string())
                    .unwrap_or_else(|| "STANDARD".to_string());
                objects.push((key.to_string(), size, modified, false, storage_class));
            }
        }

        Ok(objects)
    }
}