-
Notifications
You must be signed in to change notification settings - Fork 124
/
Copy pathwith_auto_reauth.rs
128 lines (109 loc) · 4.84 KB
/
with_auto_reauth.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! Automatically re-authentication means you only need to authenticate the
//! usual way at most once to get token. Then everytime you send a request to
//! Spotify server, it will check whether the token is expired and automatically
//! re-authenticate by refresh_token if set `Token.token_refreshing` to true.
#![allow(clippy::assigning_clones)]
use chrono::offset::Utc;
use chrono::Duration;
use rspotify::{
model::AlbumId, model::ArtistId, prelude::*, scopes, AuthCodeSpotify, ClientCredsSpotify,
Config, Credentials, OAuth,
};
// Sample request that will follow some artists, print the user's
// followed artists, and then unfollow the artists.
async fn auth_code_do_things(spotify: &AuthCodeSpotify) {
let artists = [
ArtistId::from_id("3RGLhK1IP9jnYFH4BRFJBS").unwrap(), // The Clash
ArtistId::from_id("0yNLKJebCb8Aueb54LYya3").unwrap(), // New Order
ArtistId::from_id("2jzc5TC5TVFLXQlBNiIUzE").unwrap(), // a-ha
];
let num_artists = artists.len();
spotify
.user_follow_artists(artists.iter().map(|a| a.as_ref()))
.await
.expect("couldn't follow artists");
println!("Followed {num_artists} artists successfully.");
// Printing the followed artists
let followed = spotify
.current_user_followed_artists(None, None)
.await
.expect("couldn't get user followed artists");
println!(
"User currently follows at least {} artists.",
followed.items.len()
);
spotify
.user_unfollow_artists(artists)
.await
.expect("couldn't unfollow artists");
println!("Unfollowed {num_artists} artists successfully.");
}
async fn client_creds_do_things(spotify: &ClientCredsSpotify) {
// Running the requests
let birdy_uri = AlbumId::from_uri("spotify:album:0sNOF9WDwhWunNAHPD3Baj").unwrap();
let albums = spotify.album(birdy_uri, None).await;
println!("Get albums: {}", albums.unwrap().id);
}
async fn expire_token<S: BaseClient>(spotify: &S) {
let token_mutex = spotify.get_token();
let mut token = token_mutex.lock().await.unwrap();
let token = token.as_mut().expect("Token can't be empty as this point");
// In a regular case, the token would expire with time. Here we just do
// it manually.
let now = Utc::now().checked_sub_signed(Duration::try_seconds(10).unwrap());
token.expires_at = now;
token.expires_in = Duration::try_seconds(0).unwrap();
// We also use a garbage access token to make sure it's actually
// refreshed.
token.access_token = "garbage".to_owned();
}
async fn with_auth(creds: Credentials, oauth: OAuth, config: Config) {
// In the first session of the application we authenticate and obtain the
// refresh token.
println!(">>> Session one, obtaining refresh token and running some requests:");
let spotify = AuthCodeSpotify::with_config(creds.clone(), oauth, config.clone());
let url = spotify.get_authorize_url(false).unwrap();
// This function requires the `cli` feature enabled.
spotify
.prompt_for_token(&url)
.await
.expect("couldn't authenticate successfully");
// We can now perform requests
auth_code_do_things(&spotify).await;
// Manually expiring the token.
expire_token(&spotify).await;
// Without automatically refreshing tokens, this would cause an
// authentication error when making a request, because the auth token is
// invalid. However, since it will be refreshed automatically, this will
// work.
println!(">>> Session two, the token should expire, then re-auth automatically");
auth_code_do_things(&spotify).await;
}
async fn with_client_credentials(creds: Credentials, config: Config) {
// Same with client-credential based spotify client
println!(">>> New Session one from ClientCredsSpotify, obtaining token and doing things");
let spotify = ClientCredsSpotify::with_config(creds, config);
spotify.request_token().await.unwrap();
// We can now perform requests
client_creds_do_things(&spotify).await;
// Manually expiring the token.
expire_token(&spotify).await;
// Same as before, this should work just fine.
println!(">>> New Session two from ClientCredsSpotify, expiring the token and then re-auth automatically");
client_creds_do_things(&spotify).await;
}
#[tokio::main]
async fn main() {
// You can use any logger for debugging.
env_logger::init();
// Enabling automatic token refreshing in the config
let config = Config {
..Default::default()
};
// May require the `env-file` feature enabled if the environment variables
// aren't configured manually.
let creds = Credentials::from_env().unwrap();
let oauth = OAuth::from_env(scopes!("user-follow-read user-follow-modify")).unwrap();
with_auth(creds.clone(), oauth, config.clone()).await;
with_client_credentials(creds, config).await;
}