mirror of
https://github.com/danbulant/despot
synced 2026-07-07 03:50:59 +00:00
user detail loading
This commit is contained in:
parent
a3d7ed83d7
commit
10e0877d51
3 changed files with 48 additions and 13 deletions
48
src/api.rs
48
src/api.rs
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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()))
|
||||||
|
|
|
||||||
11
src/main.rs
11
src/main.rs
|
|
@ -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()
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue