diff --git a/README.md b/README.md index ebb98d8..8b0771d 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,8 @@ The authentication type is designated by implementing a marker trait in addition to the base `HttpClient` trait: one of `NoauthClient`, `UserAuthClient`, `TeamAuthClient`, or `AppAuthClient`. -The default client has implementations of all of these (except for -`AppAuthClient` currently). They all share a common implementation and differ -only in which HTTP headers they add to the request. +The default client has implementations of all of these. They all share a common +implementation and differ only in which HTTP headers they add to the request. [authentication types]: https://www.dropbox.com/developers/reference/auth-types diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 726255b..29551a9 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,7 @@ +# v0.19.0-beta3 +xxxx-yy-zz +* added implementations of AppAuthClient to default HTTP clients + # v0.19.0-beta2 2024-11-05 * renamed sync_routes_default feature to sync_routes_in_root diff --git a/src/async_client_trait.rs b/src/async_client_trait.rs index 4443a2c..e9d8419 100644 --- a/src/async_client_trait.rs +++ b/src/async_client_trait.rs @@ -4,7 +4,7 @@ use std::future::{Future, ready}; use std::sync::Arc; use bytes::Bytes; use futures::AsyncRead; -use crate::client_trait_common::{HttpRequest, TeamSelect}; +pub use crate::client_trait_common::{HttpRequest, TeamSelect}; use crate::Error; /// The base HTTP asynchronous client trait. diff --git a/src/client_trait.rs b/src/client_trait.rs index 7c977e6..3485b62 100644 --- a/src/client_trait.rs +++ b/src/client_trait.rs @@ -4,7 +4,7 @@ use std::io::Read; use std::sync::Arc; -use crate::client_trait_common::{HttpRequest, TeamSelect}; +pub use crate::client_trait_common::{HttpRequest, TeamSelect}; use crate::Error; /// The base HTTP synchronous client trait. diff --git a/src/default_async_client.rs b/src/default_async_client.rs index 10f069c..2a0a0fa 100644 --- a/src/default_async_client.rs +++ b/src/default_async_client.rs @@ -15,8 +15,8 @@ use std::str::FromStr; use std::sync::Arc; use bytes::Bytes; use futures::{FutureExt, TryFutureExt, TryStreamExt}; -use crate::async_client_trait::{HttpClient, HttpRequestResultRaw, NoauthClient, TeamAuthClient, UserAuthClient}; -use crate::client_trait_common::{HttpRequest, TeamSelect}; +use crate::async_client_trait::{AppAuthClient, HttpClient, HttpRequest, HttpRequestResultRaw, + NoauthClient, TeamAuthClient, TeamSelect, UserAuthClient}; use crate::default_client_common::impl_set_path_root; use crate::Error; use crate::oauth2::{Authorization, TokenCache}; @@ -156,6 +156,44 @@ impl HttpClient for TeamAuthDefaultClient { impl TeamAuthClient for TeamAuthDefaultClient {} +/// Default HTTP client using App authorization. +#[derive(Debug)] +pub struct AppAuthDefaultClient { + inner: ReqwestClient, + path_root: Option, + auth: String, +} + +impl AppAuthDefaultClient { + /// Create a new App auth client using the given app key and secret, which can be found in the Dropbox app console. + pub fn new(app_key: &str, app_secret: &str) -> Self { + use base64::prelude::*; + let encoded = BASE64_STANDARD.encode(format!("{app_key}:{app_secret}")); + Self { + inner: ReqwestClient::default(), + path_root: None, + auth: format!("Basic {encoded}"), + } + } + + impl_set_path_root!(self); +} + +impl HttpClient for AppAuthDefaultClient { + type Request = ReqwestRequest; + + fn execute(&self, request: Self::Request, body: Bytes) -> impl Future> + Send { + self.inner.execute(request, body) + } + + fn new_request(&self, url: &str) -> Self::Request { + self.inner.new_request(url) + .set_header("Authorization", &self.auth) + } +} + +impl AppAuthClient for AppAuthDefaultClient {} + /// Default HTTP client for unauthenticated API calls. #[derive(Debug, Default)] pub struct NoauthDefaultClient { diff --git a/src/default_client.rs b/src/default_client.rs index 0a6c51c..8ecfc8e 100644 --- a/src/default_client.rs +++ b/src/default_client.rs @@ -18,8 +18,8 @@ use std::fmt::Write; use std::str::FromStr; use std::sync::Arc; use futures::FutureExt; -use crate::client_trait::{HttpClient, HttpRequestResultRaw, NoauthClient, TeamAuthClient, UserAuthClient}; -use crate::client_trait_common::{HttpRequest, TeamSelect}; +use crate::client_trait::{AppAuthClient, HttpClient, HttpRequest, HttpRequestResultRaw, + NoauthClient, TeamAuthClient, TeamSelect, UserAuthClient}; use crate::default_client_common::impl_set_path_root; macro_rules! impl_update_token { @@ -145,6 +145,44 @@ impl HttpClient for TeamAuthDefaultClient { impl TeamAuthClient for TeamAuthDefaultClient {} +/// Default HTTP client using App authorization. +#[derive(Debug)] +pub struct AppAuthDefaultClient { + inner: UreqClient, + path_root: Option, + auth: String, +} + +impl AppAuthDefaultClient { + /// Create a new App auth client using the given app key and secret, which can be found in the Dropbox app console. + pub fn new(app_key: &str, app_secret: &str) -> Self { + use base64::prelude::*; + let encoded = BASE64_STANDARD.encode(format!("{app_key}:{app_secret}")); + Self { + inner: UreqClient::default(), + path_root: None, + auth: format!("Basic {encoded}"), + } + } + + impl_set_path_root!(self); +} + +impl HttpClient for AppAuthDefaultClient { + type Request = UreqRequest; + + fn execute(&self, request: Self::Request, body: &[u8]) -> Result { + self.inner.execute(request, body) + } + + fn new_request(&self, url: &str) -> Self::Request { + self.inner.new_request(url) + .set_header("Authorization", &self.auth) + } +} + +impl AppAuthClient for AppAuthDefaultClient {} + /// Default HTTP client for unauthenticated API calls. #[derive(Debug, Default)] pub struct NoauthDefaultClient { diff --git a/src/lib.rs b/src/lib.rs index 30ee32e..e99ab1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,30 +44,29 @@ if_feature! { "default_client", if_feature! { "default_async_client", pub mod default_async_client; } #[cfg(any(feature = "default_client", feature = "default_async_client"))] -pub(crate) mod default_client_common; +mod default_client_common; -pub mod client_trait_common; +mod client_trait_common; pub mod client_trait; pub mod async_client_trait; -pub(crate) mod client_helpers; +mod client_helpers; pub mod oauth2; -mod generated; - // You need to run the Stone generator to create this module. +mod generated; pub use generated::*; #[cfg(feature = "async_routes")] #[cfg(not(feature = "sync_routes_in_root"))] -pub use generated::async_routes::*; +pub use async_routes::*; #[cfg(feature = "sync_routes")] #[cfg(feature = "sync_routes_in_root")] -pub use generated::sync_routes::*; +pub use sync_routes::*; mod error; pub use error::{BoxedError, Error, NoError}; diff --git a/tests/async_client_test.rs b/tests/async_client_test.rs index 922c9fd..682681b 100644 --- a/tests/async_client_test.rs +++ b/tests/async_client_test.rs @@ -1,9 +1,7 @@ -use std::sync::Arc; use bytes::Bytes; use futures::io::Cursor; use dropbox_sdk::async_routes::check; use dropbox_sdk::async_client_trait::*; -use dropbox_sdk::client_trait_common::{HttpRequest, TeamSelect}; use dropbox_sdk::Error; struct TestAsyncClient; @@ -36,22 +34,6 @@ impl HttpClient for TestAsyncClient { fn new_request(&self, url: &str) -> Self::Request { TestRequest{ url: url.to_owned() } } - - async fn update_token(&self, _old_token: Arc) -> Result { - Ok(true) - } - - fn token(&self) -> Option> { - Some(Arc::new(String::new())) - } - - fn path_root(&self) -> Option<&str> { - None - } - - fn team_select(&self) -> Option<&TeamSelect> { - None - } } impl UserAuthClient for TestAsyncClient {} diff --git a/tests/noop_client.rs b/tests/noop_client.rs index 46c24ee..df114a5 100644 --- a/tests/noop_client.rs +++ b/tests/noop_client.rs @@ -1,6 +1,5 @@ use std::fmt::{Debug, Display, Formatter}; use dropbox_sdk::client_trait::*; -use dropbox_sdk::client_trait_common::HttpRequest; macro_rules! noop_client { ($name:ident) => { diff --git a/tests/sync_client_test.rs b/tests/sync_client_test.rs index 88f008d..476a236 100644 --- a/tests/sync_client_test.rs +++ b/tests/sync_client_test.rs @@ -1,8 +1,6 @@ use std::io::Cursor; -use std::sync::Arc; use dropbox_sdk::sync_routes::check; use dropbox_sdk::client_trait::*; -use dropbox_sdk::client_trait_common::{HttpRequest, TeamSelect}; use dropbox_sdk::Error; struct TestSyncClient; @@ -31,22 +29,6 @@ impl HttpClient for TestSyncClient { fn new_request(&self, url: &str) -> Self::Request { TestRequest{ url: url.to_owned() } } - - fn update_token(&self, _old_token: Arc) -> Result { - Ok(true) - } - - fn token(&self) -> Option> { - Some(Arc::new(String::new())) - } - - fn path_root(&self) -> Option<&str> { - None - } - - fn team_select(&self) -> Option<&TeamSelect> { - None - } } impl UserAuthClient for TestSyncClient {}