use crate::app_config::AppConfig; use s3::error::S3Error; use s3::{Bucket, BucketConfiguration}; #[derive(thiserror::Error, Debug)] enum BucketServiceError { #[error("Failed to fetch bucket information!")] FailedFetchBucketInfo, } /// Create S3 bucket if required pub async fn create_bucket_if_required() -> anyhow::Result<()> { if AppConfig::get().s3_skip_auto_create_bucket { log::debug!("Skipping bucket existence check"); return Ok(()); } let bucket = AppConfig::get().s3_bucket()?; match bucket.location().await { Ok(_) => { log::debug!("The bucket already exists."); return Ok(()); } Err(S3Error::Http(404, s)) if s.contains("NoSuchKey") => { log::warn!("Failed to fetch bucket location, but it seems that bucket exists."); return Ok(()); } Err(S3Error::Http(404, s)) if s.contains("NoSuchBucket") => { log::warn!("The bucket does not seem to exists, trying to create it!") } Err(e) => { log::error!("Got unexpected error when querying bucket info: {}", e); return Err(BucketServiceError::FailedFetchBucketInfo.into()); } } Bucket::create_with_path_style( &bucket.name, bucket.region, AppConfig::get().s3_credentials()?, BucketConfiguration::private(), ) .await?; Ok(()) } /// Upload a new file to the bucket pub async fn upload_file(path: &str, content: &[u8]) -> anyhow::Result<()> { let bucket = AppConfig::get().s3_bucket()?; bucket.put_object(path, content).await?; Ok(()) } /// Get a file pub async fn get_file(path: &str) -> anyhow::Result> { let bucket = AppConfig::get().s3_bucket()?; Ok(bucket.get_object(path).await?.to_vec()) } /// Delete a file, if it exists pub async fn delete_file_if_exists(path: &str) -> anyhow::Result<()> { let bucket = AppConfig::get().s3_bucket()?; bucket.delete_object(path).await?; Ok(()) }