alibabacloud-imm 0.1.0

A modern, easy-to-use, and reqwest-powered Rust SDK for Alibaba Cloud Intelligent Media Management (IMM)
Documentation
use tracing::debug;

use crate::Result;
use crate::credentials::env::EnvironmentCredentialsProvider;
use crate::credentials::rrsa::RrsaCredentialsProvider;
use crate::credentials::{Credentials, CredentialsProvider, DynCredentialsProvider};

pub struct CredentialsChain {
    providers: Vec<(String, DynCredentialsProvider)>,
}

impl std::fmt::Debug for CredentialsChain {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let names: Vec<_> = self.providers.iter().map(|(n, _)| n.as_str()).collect();
        f.debug_struct("CredentialsChain")
            .field("providers", &names)
            .finish()
    }
}

impl CredentialsChain {
    pub fn new() -> Self {
        Self {
            providers: Vec::new(),
        }
    }

    pub fn push<P>(mut self, name: impl Into<String>, provider: P) -> Self
    where
        P: CredentialsProvider + 'static,
    {
        self.providers
            .push((name.into(), DynCredentialsProvider::new(provider)));
        self
    }
}

impl Default for CredentialsChain {
    fn default() -> Self {
        Self::new()
    }
}

impl CredentialsProvider for CredentialsChain {
    async fn get_credentials(&self) -> Result<Credentials> {
        let mut last_error = None;
        for (name, provider) in &self.providers {
            match provider.get_credentials().await {
                Ok(c) => return Ok(c),
                Err(e) => {
                    debug!(target: "alibabacloud_imm::credentials", "provider `{name}` failed: {e}");
                    last_error = Some(e);
                },
            }
        }
        Err(last_error.unwrap_or(crate::Error::InvalidCredentials))
    }
}

#[derive(Debug)]
pub struct DefaultCredentialsChain {
    inner: CredentialsChain,
}

#[derive(Default)]
pub struct DefaultCredentialsChainBuilder {
    http_client: Option<reqwest::Client>,
}

impl DefaultCredentialsChainBuilder {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn http_client(mut self, client: reqwest::Client) -> Self {
        self.http_client = Some(client);
        self
    }

    pub fn build(self) -> DefaultCredentialsChain {
        let http_client = self.http_client.unwrap_or_default();
        let mut chain = CredentialsChain::new().push("environment", EnvironmentCredentialsProvider);

        if let Some(rrsa) = RrsaCredentialsProvider::from_env(http_client) {
            chain = chain.push("rrsa", rrsa);
        }

        DefaultCredentialsChain { inner: chain }
    }
}

impl DefaultCredentialsChain {
    pub fn new() -> Self {
        Self::builder().build()
    }

    pub fn with_http_client(http_client: reqwest::Client) -> Self {
        Self::builder().http_client(http_client).build()
    }

    pub fn builder() -> DefaultCredentialsChainBuilder {
        DefaultCredentialsChainBuilder::new()
    }
}

impl Default for DefaultCredentialsChain {
    fn default() -> Self {
        Self::new()
    }
}

impl CredentialsProvider for DefaultCredentialsChain {
    async fn get_credentials(&self) -> Result<Credentials> {
        self.inner.get_credentials().await
    }
}