use async_trait::async_trait;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
#[async_trait]
pub trait CredentialVault: Send + Sync {
async fn get(&self, key: &str) -> Option<String>;
}
pub struct EnvCredentialVault;
#[async_trait]
impl CredentialVault for EnvCredentialVault {
async fn get(&self, key: &str) -> Option<String> {
std::env::var(key).ok()
}
}
pub struct InMemoryCredentialVault {
store: Arc<RwLock<HashMap<String, String>>>,
}
impl Default for InMemoryCredentialVault {
fn default() -> Self {
Self {
store: Arc::new(RwLock::new(HashMap::new())),
}
}
}
impl InMemoryCredentialVault {
pub fn new() -> Self {
Self::default()
}
pub async fn set(&self, key: impl Into<String>, value: impl Into<String>) {
self.store.write().await.insert(key.into(), value.into());
}
}
#[async_trait]
impl CredentialVault for InMemoryCredentialVault {
async fn get(&self, key: &str) -> Option<String> {
self.store.read().await.get(key).cloned()
}
}
pub struct ChainedCredentialVault {
vaults: Vec<Box<dyn CredentialVault>>,
}
impl ChainedCredentialVault {
pub fn new(vaults: Vec<Box<dyn CredentialVault>>) -> Self {
Self { vaults }
}
}
#[async_trait]
impl CredentialVault for ChainedCredentialVault {
async fn get(&self, key: &str) -> Option<String> {
for vault in &self.vaults {
if let Some(v) = vault.get(key).await {
return Some(v);
}
}
None
}
}