use std::sync::Arc;
use ferrohealth_smart::client::TokenError;
use ferrohealth_smart::client::cache::TokenSource;
use http::HeaderValue;
use secrecy::ExposeSecret;
use secrecy::SecretString;
use crate::config::TokenFailure;
use crate::config::TokenProvider;
const BEARER: &str = "Bearer ";
#[derive(Debug, Clone)]
pub struct SmartToken(TokenSource);
impl From<TokenSource> for SmartToken {
fn from(source: TokenSource) -> Self {
Self(source)
}
}
#[async_trait::async_trait]
impl TokenProvider for SmartToken {
async fn token(&self) -> Result<SecretString, TokenFailure> {
let token = self
.0
.token()
.await
.map_err(|error| TokenFailure::new(error))?;
token
.header()
.to_str()
.ok()
.and_then(|value| value.strip_prefix(BEARER))
.map(SecretString::from)
.ok_or_else(|| TokenFailure::new(Arc::new(TokenError::Unusable)))
}
fn invalidate(&self, stale: &SecretString) {
if let Ok(header) = HeaderValue::from_str(&format!("{BEARER}{}", stale.expose_secret())) {
self.0.invalidate(&header);
}
}
}