diff --git a/src/authenticator.rs b/src/authenticator.rs index 2ea89d8..6ad3086 100644 --- a/src/authenticator.rs +++ b/src/authenticator.rs @@ -14,15 +14,21 @@ use std::borrow::Cow; use std::fmt; use std::io; use std::path::PathBuf; +use std::sync::Arc; -/// Authenticator is responsible for fetching tokens, handling refreshing tokens, -/// and optionally persisting tokens to disk. -pub struct Authenticator { +struct InnerAuthenticator { hyper_client: hyper::Client, storage: Storage, auth_flow: AuthFlow, } +/// Authenticator is responsible for fetching tokens, handling refreshing tokens, +/// and optionally persisting tokens to disk. +#[derive(Clone)] +pub struct Authenticator { + inner: Arc>, +} + struct DisplayScopes<'a, T>(&'a [T]); impl<'a, T> fmt::Display for DisplayScopes<'a, T> where @@ -81,8 +87,8 @@ where ); let hashed_scopes = storage::ScopeSet::from(scopes); match ( - self.storage.get(hashed_scopes).await, - self.auth_flow.app_secret(), + self.inner.storage.get(hashed_scopes).await, + self.inner.auth_flow.app_secret(), ) { (Some(t), _) if !t.is_expired() && !force_refresh => { // unexpired token found @@ -97,16 +103,29 @@ where Some(app_secret), ) => { // token is expired but has a refresh token. - let token_info = - RefreshFlow::refresh_token(&self.hyper_client, app_secret, &refresh_token) - .await?; - self.storage.set(hashed_scopes, token_info.clone()).await?; + let token_info = RefreshFlow::refresh_token( + &self.inner.hyper_client, + app_secret, + &refresh_token, + ) + .await?; + self.inner + .storage + .set(hashed_scopes, token_info.clone()) + .await?; Ok(token_info.into()) } _ => { // no token in the cache or the token returned can't be refreshed. - let token_info = self.auth_flow.token(&self.hyper_client, scopes).await?; - self.storage.set(hashed_scopes, token_info.clone()).await?; + let token_info = self + .inner + .auth_flow + .token(&self.inner.hyper_client, scopes) + .await?; + self.inner + .storage + .set(hashed_scopes, token_info.clone()) + .await?; Ok(token_info.into()) } } @@ -222,9 +241,11 @@ impl AuthenticatorBuilder { }; Ok(Authenticator { - hyper_client, - storage, - auth_flow, + inner: Arc::new(InnerAuthenticator { + hyper_client, + storage, + auth_flow, + }), }) } diff --git a/tests/tests.rs b/tests/tests.rs index 548d9c7..183ed77 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -118,6 +118,7 @@ async fn test_device_no_code() { }))), ); let auth = create_device_flow_auth(&server).await; + let auth = auth.clone(); let res = auth.token(&["https://www.googleapis.com/scope/1"]).await; assert!(res.is_err()); assert!(format!("{}", res.unwrap_err()).contains("invalid_client_id"));