use crate::AccessTokenExpired;
use std::fmt::{Debug, Display};
pub trait ClientIdProvider {
fn client_id(&self) -> &str;
}
#[derive(Debug, Clone)]
pub struct ClientId(pub String);
impl ClientId {
pub fn new(client_id: impl Into<String>) -> Self {
Self(client_id.into())
}
}
impl ClientIdProvider for ClientId {
fn client_id(&self) -> &str {
&self.0
}
}
#[derive(Debug, Clone)]
pub enum AccessToken {
Token(String),
NeedsRefresh,
}
impl From<String> for AccessToken {
fn from(token: String) -> Self {
Self::Token(token)
}
}
#[async_trait::async_trait]
pub trait AccessTokenProvider: ClientIdProvider {
type Error: Display + Debug;
fn access_token(&self) -> AccessToken;
async fn refresh_token(&self) -> Result<String, Self::Error>;
}
#[derive(Debug)]
pub struct AccessTokenOnly {
client_id: String,
token: String,
}
impl AccessTokenOnly {
pub fn new(client_id: impl Into<String>, access_token: impl Into<String>) -> Self {
Self {
client_id: client_id.into(),
token: access_token.into(),
}
}
}
impl ClientIdProvider for AccessTokenOnly {
fn client_id(&self) -> &str {
&self.client_id
}
}
#[async_trait::async_trait]
impl AccessTokenProvider for AccessTokenOnly {
type Error = AccessTokenExpired;
fn access_token(&self) -> AccessToken {
AccessToken::Token(self.token.clone())
}
async fn refresh_token(&self) -> Result<String, Self::Error> {
Err(AccessTokenExpired)
}
}
#[macro_export]
#[doc(hidden)]
macro_rules! access_token {
($auth: expr, $error_type: ident) => {
match $auth.access_token() {
$crate::auth::AccessToken::Token(token) => token,
$crate::auth::AccessToken::NeedsRefresh => $auth
.refresh_token()
.await
.map_err($error_type::RefreshToken)?,
}
};
}