user detail loading

This commit is contained in:
Daniel Bulant 2024-10-14 22:54:44 +02:00
parent a3d7ed83d7
commit 10e0877d51
No known key found for this signature in database
3 changed files with 48 additions and 13 deletions

View file

@ -1,24 +1,27 @@
use std::future::Future; use std::future::Future;
use std::time::Duration; use std::time::{Duration, Instant};
use chrono::TimeDelta; use chrono::TimeDelta;
use futures_util::lock::Mutex;
use librespot_core::Session; use librespot_core::Session;
use librespot_oauth::OAuthToken; use librespot_oauth::OAuthToken;
use reqwest::StatusCode; use reqwest::StatusCode;
use rspotify::model::PrivateUser;
use rspotify::prelude::*;
use rspotify::{AuthCodeSpotify, ClientError, ClientResult, Config, Token}; use rspotify::{AuthCodeSpotify, ClientError, ClientResult, Config, Token};
use rspotify::http::HttpError; use rspotify::http::HttpError;
use crate::auth::{rspotify_scopes, SPOTIFY_REDIRECT_URI}; use crate::auth::{get_access_token_from_refresh_token, rspotify_scopes, SPOTIFY_REDIRECT_URI};
struct SpotifyContext { pub struct SpotifyContext {
session: Session, session: Session,
api: AuthCodeSpotify, api: AuthCodeSpotify,
token: OAuthToken token: Mutex<OAuthToken>
} }
impl SpotifyContext { impl SpotifyContext {
fn new(session: Session, token: OAuthToken) -> SpotifyContext { pub fn new(session: Session, token: OAuthToken) -> SpotifyContext {
let config = Config { let config = Config {
token_refreshing: false, token_refreshing: false,
..Default::default() ..Default::default()
@ -34,13 +37,28 @@ impl SpotifyContext {
}, },
config, config,
); );
SpotifyContext { session, api, token } SpotifyContext { session, api, token: Mutex::new(token) }
}
pub async fn update_token(&self) -> bool {
let expires_soon = Instant::now() + Duration::from_secs(10);
let token = self.token.lock().await;
if token.expires_at < expires_soon {
let refresh_token = token.refresh_token.clone();
drop(token);
let token = get_access_token_from_refresh_token(&refresh_token).unwrap();;
*self.api.token.lock().await.unwrap() = Some(librespot_token_to_rspotify(&token));
*self.token.lock().await = token;
true
} else {
false
}
} }
/// Execute `api_call` and retry once if a rate limit occurs. /// Execute `api_call` and retry once if a rate limit occurs.
async fn api_with_retry<F, T: Future<Output = ClientResult<R>>, R>(&self, api_call: F) -> Option<R> async fn api_with_retry<'a, F, T: Future<Output = ClientResult<R>>, R>(&'a self, api_call: F) -> Option<R>
where where
F: Fn(&AuthCodeSpotify) -> T, F: Fn(&'a AuthCodeSpotify) -> T,
{ {
let result = { api_call(&self.api).await }; let result = { api_call(&self.api).await };
match result { match result {
@ -63,9 +81,12 @@ impl SpotifyContext {
} }
StatusCode::UNAUTHORIZED => { StatusCode::UNAUTHORIZED => {
dbg!("token unauthorized. trying refresh.."); dbg!("token unauthorized. trying refresh..");
// self.update_token() let updated = self.update_token().await;
// .and_then(move |_| api_call(&self.api).await.ok()) if updated {
None api_call(&self.api).await.ok()
} else {
None
}
} }
_ => { _ => {
eprintln!("unhandled api error: {:?}", response); eprintln!("unhandled api error: {:?}", response);
@ -82,6 +103,11 @@ impl SpotifyContext {
} }
} }
} }
pub async fn current_user(&self) -> Result<PrivateUser, ()> {
self.api_with_retry(|api| api.current_user()).await.ok_or(())
}
} }
fn librespot_token_to_rspotify(token: &OAuthToken) -> Token { fn librespot_token_to_rspotify(token: &OAuthToken) -> Token {

View file

@ -69,7 +69,7 @@ fn oauth2_client() -> Result<BasicClient, OAuthError> {
Ok(client) Ok(client)
} }
fn get_access_token_from_refresh_token(refresh_token: &str) -> Result<OAuthToken, OAuthError> { pub fn get_access_token_from_refresh_token(refresh_token: &str) -> Result<OAuthToken, OAuthError> {
let client = oauth2_client()?; let client = oauth2_client()?;
let token = client let token = client
.exchange_refresh_token(&RefreshToken::new(refresh_token.to_string())) .exchange_refresh_token(&RefreshToken::new(refresh_token.to_string()))

View file

@ -1,5 +1,6 @@
use std::thread; use std::thread;
use api::SpotifyContext;
use auth::get_token; use auth::get_token;
use clap::Parser; use clap::Parser;
use cli::Args; use cli::Args;
@ -53,9 +54,17 @@ fn main() -> cushy::Result {
} }
}); });
dbg!(session.user_data());
let context = SpotifyContext::new(session, token);
tokio::spawn(async move {
let user = context.current_user().await.unwrap();
dbg!(user);
});
drop(guard); drop(guard);
} }
dbg!(session.user_data());
app.run() app.run()
} }