diff --git a/google-apis-common/src/auth.rs b/google-apis-common/src/auth.rs index 7576e56079..4574a27e4b 100644 --- a/google-apis-common/src/auth.rs +++ b/google-apis-common/src/auth.rs @@ -27,17 +27,17 @@ //! use core::future::Future; //! use core::pin::Pin; //! -//! use google_apis_common::GetToken; +//! use google_apis_common::{GetToken, oauth2}; //! //! use http::Uri; //! use hyper::client::connect::Connection; //! use tokio::io::{AsyncRead, AsyncWrite}; //! use tower_service::Service; -//! use yup_oauth2::authenticator::Authenticator; +//! use oauth2::authenticator::Authenticator; //! //! #[derive(Clone)] //! struct AuthenticatorWithRetry { -//! auth: yup_oauth2::authenticator::Authenticator, +//! auth: Authenticator, //! retries: usize, //! } //! @@ -51,13 +51,16 @@ //! fn get_token<'a>( //! &'a self, //! scopes: &'a [&str], -//! ) -> Pin> + Send + 'a>> { +//! ) -> Pin, Box>> + Send + 'a>> { //! Box::pin(async move { -//! let mut auth_token = None; +//! let mut auth_token = Ok(None); //! for _ in 0..self.retries { -//! if let Ok(token) = self.auth.token(scopes).await { -//! auth_token.insert(token.as_str().to_owned()); -//! break; +//! match self.auth.token(scopes).await { +//! Ok(token) => { +//! auth_token = Ok(Some(token.as_str().to_owned())); +//! break; +//! }, +//! Err(e) => auth_token = Err(e.into()), //! } //! } //! auth_token @@ -71,7 +74,7 @@ use std::future::Future; use std::pin::Pin; -type TokenResult = Option; +type TokenResult = Result, Box>; pub trait GetToken: GetTokenClone + Send + Sync { /// Called whenever an API call require authentication via an oauth2 token. @@ -79,9 +82,7 @@ pub trait GetToken: GetTokenClone + Send + Sync { fn get_token<'a>( &'a self, _scopes: &'a [&str], - ) -> Pin + Send + 'a>> { - Box::pin(async move { None }) - } + ) -> Pin + Send + 'a>>; } pub trait GetTokenClone { @@ -108,7 +109,7 @@ impl GetToken for String { &'a self, _scopes: &'a [&str], ) -> Pin + Send + 'a>> { - Box::pin(async move { Some(self.clone()) }) + Box::pin(async move { Ok(Some(self.clone())) }) } } @@ -117,7 +118,14 @@ impl GetToken for String { #[derive(Default, Clone)] pub struct NoToken; -impl GetToken for NoToken {} +impl GetToken for NoToken { + fn get_token<'a>( + &'a self, + _scopes: &'a [&str], + ) -> Pin + Send + 'a>> { + Box::pin(async move { Ok(None) }) + } +} #[cfg(feature = "yup-oauth2")] mod yup_oauth2_impl { @@ -143,7 +151,12 @@ mod yup_oauth2_impl { &'a self, scopes: &'a [&str], ) -> Pin + Send + 'a>> { - Box::pin(async move { self.token(scopes).await.ok().map(|t| t.as_str().to_owned()) }) + Box::pin(async move { + self.token(scopes) + .await + .map(|t| Some(t.as_str().to_owned())) + .map_err(|e| e.into()) + }) } } } diff --git a/google-apis-common/src/lib.rs b/google-apis-common/src/lib.rs index 758cc0e09c..e66f011465 100644 --- a/google-apis-common/src/lib.rs +++ b/google-apis-common/src/lib.rs @@ -114,14 +114,16 @@ pub trait Delegate: Send { None } - // TODO: Remove oauth2::Error /// Called whenever the Authenticator didn't yield a token. The delegate /// may attempt to provide one, or just take it as a general information about the /// impending failure. /// The given Error provides information about why the token couldn't be acquired in the /// first place - fn token(&mut self) -> Option { - None + fn token( + &mut self, + e: Box, + ) -> std::result::Result, Box> { + Err(e) } /// Called during resumable uploads to provide a URL for the impending upload. @@ -237,7 +239,7 @@ pub enum Error { MissingAPIKey, /// We required a Token, but didn't get one from the Authenticator - MissingToken, + MissingToken(Box), /// The delgate instructed to cancel the operation Cancelled, @@ -258,10 +260,10 @@ pub enum Error { impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Io(ref err) => err.fmt(f), - Error::HttpError(ref err) => err.fmt(f), - Error::UploadSizeLimitExceeded(ref resource_size, ref max_size) => writeln!( + match self { + Error::Io(err) => err.fmt(f), + Error::HttpError(err) => err.fmt(f), + Error::UploadSizeLimitExceeded(resource_size, max_size) => writeln!( f, "The media size {} exceeds the maximum allowed upload size of {}", resource_size, max_size @@ -276,16 +278,16 @@ impl Display for Error { "It is used as there are no Scopes defined for this method." ) } - Error::BadRequest(ref message) => writeln!(f, "Bad Request: {}", message), - Error::MissingToken => writeln!(f, "Token retrieval failed"), + Error::BadRequest(message) => writeln!(f, "Bad Request: {}", message), + Error::MissingToken(e) => writeln!(f, "Token retrieval failed: {}", e), Error::Cancelled => writeln!(f, "Operation cancelled by delegate"), Error::FieldClash(field) => writeln!( f, "The custom parameter '{}' is already provided natively by the CallBuilder.", field ), - Error::JsonDecodeError(ref json_str, ref err) => writeln!(f, "{}: {}", err, json_str), - Error::Failure(ref response) => { + Error::JsonDecodeError(json_str, err) => writeln!(f, "{}: {}", err, json_str), + Error::Failure(response) => { writeln!(f, "Http status indicates failure: {:?}", response) } } @@ -577,14 +579,12 @@ impl RangeResponseHeader { pub struct ResumableUploadHelper<'a, A: 'a, S> where S: tower_service::Service + Clone + Send + Sync + 'static, - S::Response: hyper::client::connect::Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static, + S::Response: + hyper::client::connect::Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static, S::Future: Send + Unpin + 'static, S::Error: Into>, { - pub client: &'a hyper::client::Client< - S, - hyper::body::Body, - >, + pub client: &'a hyper::client::Client, pub delegate: &'a mut dyn Delegate, pub start_at: Option, pub auth: &'a A, @@ -598,7 +598,8 @@ where impl<'a, A, S> ResumableUploadHelper<'a, A, S> where S: tower_service::Service + Clone + Send + Sync + 'static, - S::Response: hyper::client::connect::Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static, + S::Response: + hyper::client::connect::Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static, S::Future: Send + Unpin + 'static, S::Error: Into>, { diff --git a/src/generator/templates/api/lib/mbuild.mako b/src/generator/templates/api/lib/mbuild.mako index 857ea2e03f..d224dc08bc 100644 --- a/src/generator/templates/api/lib/mbuild.mako +++ b/src/generator/templates/api/lib/mbuild.mako @@ -399,7 +399,7 @@ match result { Error::HttpError(_) |Error::Io(_) |Error::MissingAPIKey - |Error::MissingToken + |Error::MissingToken(_) |Error::Cancelled |Error::UploadSizeLimitExceeded(_, _) |Error::Failure(_) @@ -711,13 +711,13 @@ else { loop { % if default_scope: let token = match ${auth_call}.get_token(&self.${api.properties.scopes}.iter().map(String::as_str).collect::>()[..]).await { - Some(token) => token.clone(), - None => { - match dlg.token() { - Some(token) => token, - None => { + Ok(token) => token, + Err(e) => { + match dlg.token(e) { + Ok(token) => token, + Err(e) => { ${delegate_finish}(false); - return Err(client::Error::MissingToken); + return Err(client::Error::MissingToken(e)); } } } @@ -756,11 +756,13 @@ else { let client = &self.hub.client; dlg.pre_request(); let mut req_builder = hyper::Request::builder().method(${method_name_to_variant(m.httpMethod)}).uri(url.clone().into_string()) - .header(USER_AGENT, self.hub._user_agent.clone())\ - % if default_scope: - .header(AUTHORIZATION, format!("Bearer {}", token.as_str()))\ - % endif -; + .header(USER_AGENT, self.hub._user_agent.clone()); + + % if default_scope: + if let Some(token) = token.as_ref() { + req_builder = req_builder.header(AUTHORIZATION, format!("Bearer {}", token)); + } + % endif % if resumable_media_param: upload_url_from_server = true; @@ -854,7 +856,7 @@ else { start_at: if upload_url_from_server { Some(0) } else { None }, auth: &${auth_call}, user_agent: &self.hub._user_agent, - auth_header: format!("Bearer {}", token.as_str()), + auth_header: format!("Bearer {}", token.expect("resumable upload requires token").as_str()), url: url_str, reader: &mut reader, media_type: reader_mime_type.clone(),