Use generic Authy trait in place of yup_oauth2

This commit is contained in:
philippeitis
2022-09-23 00:21:27 -07:00
parent f279d821e1
commit 7078038857
4 changed files with 93 additions and 17 deletions

View File

@@ -32,7 +32,7 @@ mime = "^ 0.2.0"
serde = "^ 1.0"
serde_json = "^ 1.0"
serde_derive = "^ 1.0"
yup-oauth2 = "^ 7.0"
yup-oauth2 = { version = "^ 7.0", optional = true }
itertools = "^ 0.10"
% for dep in cargo.get('dependencies', list()):
${dep}
@@ -41,7 +41,7 @@ ${dep}
<%
api_name = util.library_name()
crate_name_we_depend_on = None
if make.depends_on_suffix is not None:
crate_name_we_depend_on = library_to_crate_name(api_name, suffix=make.depends_on_suffix)
%>\
@@ -53,3 +53,6 @@ ${dep}
path = "../${api_name}"
version = "${util.crate_version()}"
% endif
[features]
default = ["yup-oauth2"]

View File

@@ -30,7 +30,7 @@ use http::Uri;
use hyper::client::connect;
use tokio::io::{AsyncRead, AsyncWrite};
use tower_service;
use crate::client;
use crate::{client, client::Authy};
// ##############
// UTILITIES ###
@@ -55,7 +55,7 @@ ${lib.hub_usage_example(c)}\
#[derive(Clone)]
pub struct ${hub_type}${ht_params} {
pub client: hyper::Client<S, hyper::body::Body>,
pub auth: oauth2::authenticator::Authenticator<S>,
pub auth: Box<dyn client::Authy>,
_user_agent: String,
_base_url: String,
_root_url: String,
@@ -65,10 +65,10 @@ impl<'a, ${', '.join(HUB_TYPE_PARAMETERS)}> client::Hub for ${hub_type}${ht_para
impl<'a, ${', '.join(HUB_TYPE_PARAMETERS)}> ${hub_type}${ht_params} {
pub fn new(client: hyper::Client<S, hyper::body::Body>, authenticator: oauth2::authenticator::Authenticator<S>) -> ${hub_type}${ht_params} {
pub fn new<A: 'static + client::Authy>(client: hyper::Client<S, hyper::body::Body>, auth: A) -> ${hub_type}${ht_params} {
${hub_type} {
client,
auth: authenticator,
auth: Box::new(auth),
_user_agent: "${default_user_agent}".to_string(),
_base_url: "${baseUrl}".to_string(),
_root_url: "${rootUrl}".to_string(),

View File

@@ -387,7 +387,7 @@ match result {
Error::HttpError(_)
|Error::Io(_)
|Error::MissingAPIKey
|Error::MissingToken(_)
|Error::MissingToken
|Error::Cancelled
|Error::UploadSizeLimitExceeded(_, _)
|Error::Failure(_)
@@ -706,14 +706,14 @@ else {
loop {
% if default_scope:
let token = match ${auth_call}.token(&self.${api.properties.scopes}.keys().collect::<Vec<_>>()[..]).await {
Ok(token) => token.clone(),
Err(err) => {
match dlg.token(&err) {
let token = match ${auth_call}.get_token(&self.${api.properties.scopes}.keys().map(String::as_str).collect::<Vec<_>>()[..]).await {
Some(token) => token.clone(),
None => {
match dlg.token() {
Some(token) => token,
None => {
${delegate_finish}(false);
return Err(client::Error::MissingToken(err))
return Err(client::Error::MissingToken)
}
}
}

View File

@@ -1,7 +1,9 @@
use std::error;
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::future::Future;
use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};
use std::pin::Pin;
use std::str::FromStr;
use std::thread::sleep;
use std::time::Duration;
@@ -110,8 +112,7 @@ pub trait Delegate: Send {
/// impending failure.
/// The given Error provides information about why the token couldn't be acquired in the
/// first place
fn token(&mut self, err: &oauth2::Error) -> Option<oauth2::AccessToken> {
let _ = err;
fn token(&mut self) -> Option<String> {
None
}
@@ -228,7 +229,7 @@ pub enum Error {
MissingAPIKey,
/// We required a Token, but didn't get one from the Authenticator
MissingToken(oauth2::Error),
MissingToken,
/// The delgate instructed to cancel the operation
Cancelled,
@@ -272,8 +273,8 @@ impl Display for Error {
writeln!(f, "Bad Request: {}", message)?;
Ok(())
}
Error::MissingToken(ref err) => {
writeln!(f, "Token retrieval failed with error: {}", err)
Error::MissingToken => {
writeln!(f, "Token retrieval failed.")
}
Error::Cancelled => writeln!(f, "Operation cancelled by delegate"),
Error::FieldClash(field) => writeln!(
@@ -785,3 +786,75 @@ pub async fn get_body_as_string(res_body: &mut hyper::Body) -> String {
let res_body_string = String::from_utf8_lossy(&res_body_buf);
res_body_string.to_string()
}
pub trait Authy: AuthyClone {
fn get_token<'a>(&'a self, _scopes: &'a [&str]) -> Pin<Box<dyn Future<Output=Option<String>> + 'a>> {
async fn x() -> Option<String> {
None
}
Box::pin(x())
}
}
pub trait AuthyClone {
fn clone_box(&self) -> Box<dyn Authy>;
}
impl<T> AuthyClone for T
where
T: 'static + Authy + Clone,
{
fn clone_box(&self) -> Box<dyn Authy> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn Authy> {
fn clone(&self) -> Box<dyn Authy> {
self.clone_box()
}
}
impl Authy for String {
fn get_token<'a>(&'a self, _scopes: &'a [&str]) -> Pin<Box<dyn Future<Output=Option<String>> + 'a>> {
async fn ident(s: &str) -> Option<String> {
Some(s.to_string())
}
Box::pin(ident(self))
}
}
impl Authy for () {}
#[cfg(feature = "yup-oauth2")]
mod yup_oauth2_impl {
use core::future::Future;
use core::pin::Pin;
use super::Authy;
use tower_service::Service;
use yup_oauth2::authenticator::Authenticator;
use tokio::io::{AsyncRead, AsyncWrite};
use http::Uri;
use hyper::client::connect::Connection;
async fn helper<S>(auth: &Authenticator<S>, scopes: &[&str]) -> Option<String> where
S: Service<Uri> + Clone + Send + Sync + 'static,
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
S::Future: Send + Unpin + 'static,
S::Error: Into<Box<dyn std::error::Error + Send + Sync>> {
auth.token(scopes).await.ok().map(|t| t.as_str().to_string())
}
impl<S> Authy for Authenticator<S> where
S: Service<Uri> + Clone + Send + Sync + 'static,
S::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
S::Future: Send + Unpin + 'static,
S::Error: Into<Box<dyn std::error::Error + Send + Sync>> {
fn get_token<'a>(&'a self, scopes: &'a [&str]) -> Pin<Box<dyn Future<Output=Option<String>> + 'a>> {
Box::pin(helper(self, scopes))
}
}
}