Use Result<Option<_>, _>

This commit is contained in:
philippeitis
2022-10-16 21:04:43 -07:00
parent 1132b542d2
commit a375b710b1
3 changed files with 62 additions and 46 deletions

View File

@@ -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<S> {
//! auth: yup_oauth2::authenticator::Authenticator<S>,
//! auth: Authenticator<S>,
//! retries: usize,
//! }
//!
@@ -51,13 +51,16 @@
//! fn get_token<'a>(
//! &'a self,
//! scopes: &'a [&str],
//! ) -> Pin<Box<dyn Future<Output = Option<String>> + Send + 'a>> {
//! ) -> Pin<Box<dyn Future<Output = Result<Option<String>, Box<dyn std::error::Error + Send + Sync>>> + 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<String>;
type TokenResult = Result<Option<String>, Box<dyn std::error::Error + Send + Sync>>;
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<Box<dyn Future<Output = TokenResult> + Send + 'a>> {
Box::pin(async move { None })
}
) -> Pin<Box<dyn Future<Output = TokenResult> + Send + 'a>>;
}
pub trait GetTokenClone {
@@ -108,7 +109,7 @@ impl GetToken for String {
&'a self,
_scopes: &'a [&str],
) -> Pin<Box<dyn Future<Output = TokenResult> + 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<Box<dyn Future<Output = TokenResult> + 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<Box<dyn Future<Output = TokenResult> + 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())
})
}
}
}

View File

@@ -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<String> {
None
fn token(
&mut self,
e: Box<dyn StdError + Send + Sync>,
) -> std::result::Result<Option<String>, Box<dyn StdError + Send + Sync>> {
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<dyn StdError + Send + Sync>),
/// 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<Uri> + 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<Box<dyn StdError + Send + Sync>>,
{
pub client: &'a hyper::client::Client<
S,
hyper::body::Body,
>,
pub client: &'a hyper::client::Client<S, hyper::body::Body>,
pub delegate: &'a mut dyn Delegate,
pub start_at: Option<u64>,
pub auth: &'a A,
@@ -598,7 +598,8 @@ where
impl<'a, A, S> ResumableUploadHelper<'a, A, S>
where
S: tower_service::Service<Uri> + 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<Box<dyn StdError + Send + Sync>>,
{

View File

@@ -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::<Vec<_>>()[..]).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(),