arche 3.0.0

An opinionated backend foundation for Axum applications, providing batteries-included integrations for cloud services, databases, authentication, middleware, and logging.
Documentation
use aws_config::{BehaviorVersion, Region};
use aws_sdk_s3::{Client, config::Credentials};

use crate::config::{resolve_required_string, resolve_with_default};
use crate::error::AppError;

pub use crate::config::s3::{S3Config, S3ConfigBuilder};

const DEFAULT_REGION: &str = "ap-south-1";

pub async fn get_s3_client(config: impl Into<Option<S3Config>>) -> Result<Client, AppError> {
    let config = config.into().unwrap_or_default();

    let region_str = resolve_with_default(config.region, "S3_REGION", DEFAULT_REGION.to_string());
    let region = Region::new(region_str);

    let cred_source = resolve_with_default(
        config.credential_source,
        "S3_CRED_SOURCE",
        "IAM".to_string(),
    );

    if cred_source.to_lowercase() == "env" {
        let credentials = load_s3_cred_from_config(config.access_key_id, config.secret_access_key)?;
        Ok(Client::new(
            &aws_config::defaults(BehaviorVersion::latest())
                .region(region)
                .credentials_provider(credentials)
                .load()
                .await,
        ))
    } else {
        Ok(Client::new(
            &aws_config::defaults(BehaviorVersion::latest())
                .region(region)
                .load()
                .await,
        ))
    }
}

fn load_s3_cred_from_config(
    access_key_id: Option<String>,
    secret_access_key: Option<String>,
) -> Result<Credentials, AppError> {
    let access_key_id =
        resolve_required_string(access_key_id, "S3_ACCESS_KEY_ID", "access_key_id")?;
    let secret_access_key = resolve_required_string(
        secret_access_key,
        "S3_SECRET_ACCESS_KEY",
        "secret_access_key",
    )?;

    Ok(Credentials::new(
        access_key_id,
        secret_access_key,
        None,
        None,
        "",
    ))
}