use std::sync::Arc;
use ferrohealth_smart::client::TokenError;
use ferrohealth_smart::client::cache::TokenSource;
use http::HeaderValue;
use secrecy::{ExposeSecret, SecretString};
use super::feed::{Credentials, CredentialsError};
#[derive(Debug, Clone)]
pub struct Bearer(TokenSource);
impl From<TokenSource> for Bearer {
fn from(source: TokenSource) -> Self {
Self(source)
}
}
#[async_trait::async_trait]
impl Credentials for Bearer {
async fn authorization(&self) -> Result<SecretString, CredentialsError> {
let token = self
.0
.token()
.await
.map_err(|error| CredentialsError(Box::new(SharedError(error))))?;
let value = token
.header()
.to_str()
.map_err(|error| CredentialsError(Box::new(error)))?;
Ok(SecretString::from(value.to_owned()))
}
async fn refused(&self, refused: &SecretString) {
if let Ok(stale) = HeaderValue::from_str(refused.expose_secret()) {
self.0.invalidate(&stale);
}
}
}
#[derive(Debug)]
struct SharedError(Arc<TokenError>);
impl std::fmt::Display for SharedError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
impl std::error::Error for SharedError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(self.0.as_ref())
}
}