prefixload 0.7.0

S3 cli backuper
Documentation
use crate::error::Result;
use aws_sdk_s3 as s3;
use aws_sdk_s3::error::ProvideErrorMetadata;
use aws_types::region::Region;

pub struct S3Client {
    client: s3::Client,
}

impl S3Client {
    /// Creates a new S3Client
    pub async fn new(
        access_key: &str,
        secret_key: &str,
        region: Option<&str>,
        endpoint: Option<&str>,
    ) -> Result<Self> {
        let credentials = s3::config::Credentials::new(
            access_key, // access-key-id
            secret_key, // secret-access-key
            None,       // session-token
            None,       // expires_at
            "custom",   // provider-name
        );

        let cred_provider = s3::config::SharedCredentialsProvider::new(credentials);

        let mut defaults = aws_config::defaults(aws_config::BehaviorVersion::latest())
            .credentials_provider(cred_provider);

        let used_region = region.unwrap_or("us-east-1"); // default

        defaults = defaults.region(Region::new(used_region.to_owned()));

        let sdk_config = defaults.load().await;

        let mut s3_config_builder = aws_sdk_s3::config::Builder::from(&sdk_config);
        if let Some(url) = endpoint {
            s3_config_builder = s3_config_builder.endpoint_url(url);
        }
        let s3_config = s3_config_builder.build();

        let client = s3::Client::from_conf(s3_config);

        Ok(S3Client { client })
    }

    /// Checks the availability of the bucket
    /// Result:
    /// - `Ok(true)`  – the bucket is available
    /// - `Ok(false)` – the key is valid, but there are no rights (401/403)
    /// - `Err(e)`    – other errors (network, DNS, incorrect region, etc.)
    pub async fn check_bucket_access(&self, bucket: &str) -> Result<bool> {
        match self.client.head_bucket().bucket(bucket).send().await {
            // 200 OK – the bucket exists and the credentials are valid
            Ok(_) => Ok(true),

            Err(sdk_err) => {
                // 403 Forbidden or 401 Unauthorized ⇢ the bucket is there, but there are no rights
                if matches!(sdk_err.code(), Some("AccessDenied") | Some("Forbidden")) {
                    return Ok(false);
                }

                // Everything else (404 NotFound, PermanentRedirect, network failures, etc.)
                // wrap it in our Error tree and throw it up.
                let aws_err: aws_sdk_s3::Error = sdk_err.into();
                Err(aws_err.into())
            }
        }
    }
}