diff --git a/src/authenticator.rs b/src/authenticator.rs index 2ea89d8..39d062b 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 @@ -98,15 +104,15 @@ where ) => { // token is expired but has a refresh token. let token_info = - RefreshFlow::refresh_token(&self.hyper_client, app_secret, &refresh_token) + RefreshFlow::refresh_token(&self.inner.hyper_client, app_secret, &refresh_token) .await?; - self.storage.set(hashed_scopes, token_info.clone()).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()) } } @@ -221,11 +227,11 @@ impl AuthenticatorBuilder { StorageType::Disk(path) => Storage::Disk(storage::DiskStorage::new(path).await?), }; - Ok(Authenticator { + Ok(Authenticator{ inner: Arc::new(InnerAuthenticator { hyper_client, storage, auth_flow, - }) + })}) } fn with_auth_flow(auth_flow: F) -> AuthenticatorBuilder { 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"));