Skip to main content

rusticity_core/
s3.rs

1use crate::config::AwsConfig;
2use anyhow::Result;
3
4pub struct S3Client {
5    config: AwsConfig,
6}
7
8impl S3Client {
9    pub fn new(config: AwsConfig) -> Self {
10        Self { config }
11    }
12
13    pub async fn list_buckets(&self) -> Result<Vec<(String, String, String)>> {
14        let client = self.config.s3_client().await;
15        let resp = client.list_buckets().send().await?;
16
17        let buckets: Vec<(String, String, String)> = resp
18            .buckets()
19            .iter()
20            .filter_map(|b| {
21                let name = b.name()?.to_string();
22                let date = b.creation_date().map(|d| d.to_string()).unwrap_or_default();
23                Some((name, String::new(), date))
24            })
25            .collect();
26
27        Ok(buckets)
28    }
29
30    pub async fn get_bucket_location(&self, bucket: &str) -> Result<String> {
31        let client = self.config.s3_client().await;
32        let region = match client.get_bucket_location().bucket(bucket).send().await {
33            Ok(resp) => match resp.location_constraint() {
34                Some(loc) => {
35                    let loc_str = loc.as_str();
36                    if loc_str.is_empty() || loc_str == "null" {
37                        "us-east-1".to_string()
38                    } else {
39                        loc_str.to_string()
40                    }
41                }
42                None => "us-east-1".to_string(),
43            },
44            Err(_) => "us-east-1".to_string(),
45        };
46
47        Ok(region)
48    }
49
50    pub async fn list_objects(
51        &self,
52        bucket: &str,
53        bucket_region: &str,
54        prefix: &str,
55    ) -> Result<Vec<(String, i64, String, bool, String)>> {
56        let client = self.config.s3_client_with_region(bucket_region).await;
57        let mut req = client.list_objects_v2().bucket(bucket).delimiter("/");
58
59        if !prefix.is_empty() {
60            req = req.prefix(prefix);
61        }
62
63        let resp = req.send().await?;
64
65        let mut objects = Vec::new();
66
67        for prefix in resp.common_prefixes() {
68            if let Some(p) = prefix.prefix() {
69                objects.push((p.to_string(), 0, String::new(), true, String::new()));
70            }
71        }
72
73        for obj in resp.contents() {
74            if let Some(key) = obj.key() {
75                let size = obj.size().unwrap_or(0);
76                let modified = obj
77                    .last_modified()
78                    .map(|d| d.to_string())
79                    .unwrap_or_default();
80                let storage_class = obj
81                    .storage_class()
82                    .map(|s| s.as_str().to_string())
83                    .unwrap_or_else(|| "STANDARD".to_string());
84                objects.push((key.to_string(), size, modified, false, storage_class));
85            }
86        }
87
88        Ok(objects)
89    }
90}