use crate::credentials::Credentials;
use anyhow::Result;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Debug, Clone)]
pub(crate) struct TokenValue {
access_token: String,
expires_in: i64,
scope: Option<String>,
token_type: String,
id_token: Option<String>,
}
#[derive(Clone, Debug)]
pub(crate) struct Token {
token_value: TokenValue,
expiry: DateTime<Utc>,
}
impl Token {
pub fn new(token_value: TokenValue) -> Self {
let expiry = Self::get_expiry(token_value.expires_in);
Self {
token_value,
expiry,
}
}
fn is_expired(&self) -> bool {
let now = Utc::now();
self.expiry <= now
}
fn get_expiry(expires_in: i64) -> DateTime<Utc> {
let duration = chrono::Duration::seconds((expires_in as f64 * 0.75) as i64);
Utc::now() + duration
}
fn get_access_token(&self) -> String {
format!("Bearer {}", self.token_value.access_token)
}
}
#[derive(Deserialize, Serialize, Debug)]
struct VerifyResponse {
azp: String,
aud: String,
sub: Option<String>,
scope: String,
exp: String,
expires_in: String,
email: Option<String>,
email_verified: Option<String>,
access_type: String,
}
#[derive(Clone, Debug)]
pub struct TokenManager {
credentials: Credentials,
current_token: Token,
}
impl TokenManager {
pub async fn new(scopes: &[&str]) -> Result<Self> {
let cred = Credentials::new(scopes).await?;
let token = cred.token().await?;
Ok(Self {
credentials: cred,
current_token: token,
})
}
pub async fn token(&mut self) -> Result<String> {
if self.current_token.is_expired() {
self.current_token = self.credentials.token().await?;
}
Ok(self.current_token.get_access_token())
}
}