use crate::{
clients::BaseClient,
http::{Form, HttpClient},
params,
sync::Mutex,
ClientResult, Config, Credentials, Token,
};
use maybe_async::maybe_async;
use std::sync::Arc;
#[derive(Clone, Debug, Default)]
pub struct ClientCredsSpotify {
pub config: Config,
pub creds: Credentials,
pub token: Arc<Mutex<Option<Token>>>,
pub(crate) http: HttpClient,
}
#[cfg_attr(target_arch = "wasm32", maybe_async(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), maybe_async)]
impl BaseClient for ClientCredsSpotify {
fn get_http(&self) -> &HttpClient {
&self.http
}
fn get_token(&self) -> Arc<Mutex<Option<Token>>> {
Arc::clone(&self.token)
}
fn get_creds(&self) -> &Credentials {
&self.creds
}
fn get_config(&self) -> &Config {
&self.config
}
async fn refetch_token(&self) -> ClientResult<Option<Token>> {
let token = self.fetch_token().await?;
Ok(Some(token))
}
}
impl ClientCredsSpotify {
#[must_use]
pub fn new(creds: Credentials) -> Self {
Self {
creds,
..Default::default()
}
}
#[must_use]
pub fn from_token(token: Token) -> Self {
Self {
token: Arc::new(Mutex::new(Some(token))),
..Default::default()
}
}
#[must_use]
pub fn with_config(creds: Credentials, config: Config) -> Self {
Self {
config,
creds,
..Default::default()
}
}
#[maybe_async]
pub async fn read_token_cache(&self) -> ClientResult<Option<Token>> {
if !self.get_config().token_cached {
log::info!("Token cache read ignored (not configured)");
return Ok(None);
}
log::info!("Reading token cache");
let token = Token::from_cache(&self.get_config().cache_path)?;
if token.is_expired() {
Ok(None)
} else {
Ok(Some(token))
}
}
#[maybe_async]
async fn fetch_token(&self) -> ClientResult<Token> {
let mut data = Form::new();
data.insert(params::GRANT_TYPE, params::GRANT_TYPE_CLIENT_CREDS);
let headers = self
.creds
.auth_headers()
.expect("No client secret set in the credentials.");
let token = self.fetch_access_token(&data, Some(&headers)).await?;
if let Some(callback_fn) = &*self.get_config().token_callback_fn.clone() {
callback_fn.0(token.clone())?;
}
Ok(token)
}
#[maybe_async]
pub async fn request_token(&self) -> ClientResult<()> {
log::info!("Requesting Client Credentials token");
*self.token.lock().await.unwrap() = Some(self.fetch_token().await?);
self.write_token_cache().await
}
}