@@ -3,38 +3,35 @@ use std::fmt::{Display, Formatter};
3
3
/// Trait that refreshes a token when it is expired
4
4
#[ async_trait:: async_trait]
5
5
pub trait TokenCache : Sync {
6
- type TokenData : Sync + Send + Clone + Display ;
7
- /// Getter for the token
8
- async fn get_token ( & self ) -> Option < Self :: TokenData > ;
6
+ /// Returns the token that is currently held within the instance of `TokenCache`, together with
7
+ /// the expiry of that token as a u64 in seconds sine the Unix Epoch (1 Jan 1970).
8
+ async fn token_and_exp ( & self ) -> Option < ( String , u64 ) > ;
9
9
10
- /// Updates the token
11
- async fn set_token ( & self , token : Self :: TokenData ) -> crate :: Result < ( ) > ;
10
+ /// Updates the token to the value `token`.
11
+ async fn set_token ( & self , token : String , exp : u64 ) -> crate :: Result < ( ) > ;
12
12
13
- /// Getter for the scope
14
- fn get_scope ( & self ) -> & str ;
13
+ /// Returns the intended scope for the current token.
14
+ async fn scope ( & self ) -> String ;
15
15
16
- /// Returns whether the token is expired
17
- fn is_expired ( token : & Self :: TokenData ) -> bool ;
18
-
19
- /// Returns a valid, unexpired token
20
- /// Otherwise updates and returns the token
21
- async fn get ( & self , client : & reqwest:: Client ) -> crate :: Result < Self :: TokenData > {
22
- match self . get_token ( ) . await {
23
- Some ( token) if !Self :: is_expired ( & token) => Ok ( token) ,
16
+ /// Returns a valid, unexpired token. If the contained token is expired, it updates and returns
17
+ /// the token.
18
+ async fn get ( & self , client : & reqwest:: Client ) -> crate :: Result < String > {
19
+ match self . token_and_exp ( ) . await {
20
+ Some ( ( token, exp) ) if now ( ) > exp => Ok ( token) ,
24
21
_ => {
25
- let scope = self . get_scope ( ) ;
26
- let token = Self :: fetch_token ( client, scope) . await ?;
27
- self . set_token ( token) . await ?;
22
+ let ( token, exp) = self . fetch_token ( client) . await ?;
23
+ self . set_token ( token, exp) . await ?;
28
24
29
- self . get_token ( )
25
+ self . token_and_exp ( )
30
26
. await
27
+ . map ( |( t, _) | t)
31
28
. ok_or ( crate :: Error :: Other ( "Token is not set" . to_string ( ) ) )
32
29
}
33
30
}
34
31
}
35
32
36
33
/// Fetches and returns the token using the service account
37
- async fn fetch_token ( client : & reqwest:: Client , scope : & str ) -> crate :: Result < Self :: TokenData > ;
34
+ async fn fetch_token ( & self , client : & reqwest:: Client ) -> crate :: Result < ( String , u64 ) > ;
38
35
}
39
36
40
37
#[ derive( serde:: Serialize ) ]
@@ -47,10 +44,11 @@ struct Claims {
47
44
}
48
45
49
46
#[ derive( serde:: Deserialize , Debug ) ]
47
+ // #[allow(dead_code)]
50
48
struct TokenResponse {
51
49
access_token : String ,
52
- expires_in : usize ,
53
- token_type : String ,
50
+ expires_in : u64 ,
51
+ // token_type: String,
54
52
}
55
53
56
54
/// This struct contains a token, an expiry, and an access scope.
@@ -63,7 +61,7 @@ pub struct Token {
63
61
}
64
62
65
63
#[ derive( Debug , Clone ) ]
66
- pub struct DefaultTokenData ( pub String , u64 ) ;
64
+ pub struct DefaultTokenData ( String , u64 ) ;
67
65
68
66
impl Display for DefaultTokenData {
69
67
fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
@@ -78,40 +76,36 @@ impl Default for Token {
78
76
}
79
77
80
78
impl Token {
81
- pub fn new ( scope : & str ) -> Self {
79
+ pub ( crate ) fn new ( scope : & str ) -> Self {
82
80
Self {
83
81
token : tokio:: sync:: RwLock :: new ( None ) ,
84
82
access_scope : scope. to_string ( ) ,
85
83
}
86
84
}
87
85
}
86
+
88
87
#[ async_trait:: async_trait]
89
88
impl TokenCache for Token {
90
- type TokenData = DefaultTokenData ;
91
-
92
- fn get_scope ( & self ) -> & str {
93
- self . access_scope . as_ref ( )
89
+ async fn scope ( & self ) -> String {
90
+ self . access_scope . clone ( )
94
91
}
95
92
96
- fn is_expired ( token : & Self :: TokenData ) -> bool {
97
- token. 1 > now ( )
93
+ async fn token_and_exp ( & self ) -> Option < ( String , u64 ) > {
94
+ self . token . read ( ) . await . as_ref ( ) . map ( |d| ( d . 0 . clone ( ) , d . 1 ) )
98
95
}
99
96
100
- async fn get_token ( & self ) -> Option < Self :: TokenData > {
101
- self . token . read ( ) . await . clone ( )
102
- }
103
- async fn set_token ( & self , token : Self :: TokenData ) -> crate :: Result < ( ) > {
104
- * self . token . write ( ) . await = Some ( token) ;
97
+ async fn set_token ( & self , token : String , exp : u64 ) -> crate :: Result < ( ) > {
98
+ * self . token . write ( ) . await = Some ( DefaultTokenData ( token, exp) ) ;
105
99
Ok ( ( ) )
106
100
}
107
101
108
- async fn fetch_token ( client : & reqwest:: Client , scope : & str ) -> crate :: Result < Self :: TokenData > {
102
+ async fn fetch_token ( & self , client : & reqwest:: Client ) -> crate :: Result < ( String , u64 ) > {
109
103
let now = now ( ) ;
110
104
let exp = now + 3600 ;
111
105
112
106
let claims = Claims {
113
107
iss : crate :: SERVICE_ACCOUNT . client_email . clone ( ) ,
114
- scope : scope. into ( ) ,
108
+ scope : self . scope ( ) . await . into ( ) ,
115
109
aud : "https://www.googleapis.com/oauth2/v4/token" . to_string ( ) ,
116
110
exp,
117
111
iat : now,
@@ -134,7 +128,7 @@ impl TokenCache for Token {
134
128
. await ?
135
129
. json ( )
136
130
. await ?;
137
- Ok ( DefaultTokenData ( response. access_token , exp ) )
131
+ Ok ( ( response. access_token , now + response . expires_in ) )
138
132
}
139
133
}
140
134
0 commit comments