Skip to content

Commit 023dc58

Browse files
committedOct 18, 2021
0.11.0-rc.1: added the TokenCache trait to make authentication configurable
1 parent bca0937 commit 023dc58

23 files changed

+173
-192
lines changed
 

‎CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ shepmaster. Big thanks!
88
Small fix to the public interface of `sync::ObjectClient` that was not properly sync.
99
Fix urlencoding url paths correctly in several places.
1010
Update cloud storage to use the new url, `www.googleapis.com` => `storage.googleapis.com`
11+
12+
# 0.11
13+
@pseguin2011: Implemented a configurable authentication layer through the `TokenCache` trait.

‎Cargo.toml

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cloud-storage"
3-
version = "0.10.3"
3+
version = "0.11.0-rc.1"
44
authors = ["Luuk Wester <luuk.wester@gmail.com>"]
55
edition = "2018"
66
description = "A crate for uploading files to Google cloud storage, and for generating download urls."
@@ -10,6 +10,7 @@ documentation = "https://docs.rs/cloud-storage"
1010
keywords = ["google", "cloud", "storage"]
1111
readme = "README.md"
1212
categories = ["api-bindings", "web-programming"]
13+
resolver = "2"
1314
# maintenance = { status = "actively-developed" }
1415

1516
[features]
@@ -38,7 +39,10 @@ hex = { version = "0.4", default-features = false, features = ["al
3839
tokio = { version = "1.0", default-features = false, features = ["macros", "rt"] }
3940
futures = { version = "0.3", default_features = false, features = ["alloc"] }
4041
bytes = { version = "1.0", default-features = false }
41-
async-trait = { version = "0.1.48", default_features = false }
42+
async-trait = { version = "0.1.48", default-features = false }
43+
44+
[dev-dependencies]
45+
tokio = { version = "1.0", default-features = false, features = ["full"] }
4246

4347
[package.metadata.docs.rs]
4448
features = ["global-client", "sync"]

‎src/client.rs

+22-24
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,13 @@ pub use object::ObjectClient;
1919
pub use object_access_control::ObjectAccessControlClient;
2020

2121
/// The primary entrypoint to perform operations with Google Cloud Storage.
22-
pub struct Client<R: TokenCache> {
22+
pub struct Client {
2323
client: reqwest::Client,
24-
2524
/// Static `Token` struct that caches
26-
token_cache: R,
25+
token_cache: Box<dyn crate::TokenCache>,
2726
}
2827

29-
impl<R> fmt::Debug for Client<R>
30-
where
31-
R: TokenCache,
32-
{
28+
impl fmt::Debug for Client {
3329
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3430
f.debug_struct("Client")
3531
.field("client", &self.client)
@@ -38,61 +34,63 @@ where
3834
}
3935
}
4036

41-
impl<T: TokenCache + Default> Default for Client<T> {
37+
impl Default for Client {
4238
fn default() -> Self {
4339
Self {
4440
client: Default::default(),
45-
token_cache: T::default(),
41+
token_cache: Box::new(crate::Token::default()),
4642
}
4743
}
4844
}
4945

50-
impl<T: TokenCache + Default> Client<T> {
51-
/// Constructs a client
46+
impl Client {
47+
/// Constructs a client with the default token provider, where it attemps to obtain the
48+
/// credentials from the following locations:
49+
///
50+
/// 1. Checks for the environment variable `SERVICE_ACCOUNT`, and if it exists, reads the file
51+
/// at the path specified there as a credentials json file.
52+
/// 2. It attemps to do the same with the `GOOGLE_APPLICATION_CREDENTIALS` var.
53+
/// 3. It reads the `SERVICE_ACCOUNT_JSON` environment variable directly as json and uses that
54+
/// 4.It attemps to do the same with the `GOOGLE_APPLICATION_CREDENTIALS_JSON` var.
5255
pub fn new() -> Self {
5356
Default::default()
5457
}
55-
}
5658

57-
impl<R> Client<R>
58-
where
59-
R: TokenCache,
60-
{
6159
/// Initializer with a provided refreshable token
62-
pub fn with_token_cache(token_cache: R) -> Self {
60+
pub fn with_cache(token: impl TokenCache + 'static) -> Self {
6361
Self {
6462
client: Default::default(),
65-
token_cache,
63+
token_cache: Box::new(token),
6664
}
6765
}
6866

6967
/// Operations on [`Bucket`](crate::bucket::Bucket)s.
70-
pub fn bucket(&self) -> BucketClient<'_, R> {
68+
pub fn bucket(&self) -> BucketClient<'_> {
7169
BucketClient(self)
7270
}
7371

7472
/// Operations on [`BucketAccessControl`](crate::bucket_access_control::BucketAccessControl)s.
75-
pub fn bucket_access_control(&self) -> BucketAccessControlClient<'_, R> {
73+
pub fn bucket_access_control(&self) -> BucketAccessControlClient<'_> {
7674
BucketAccessControlClient(self)
7775
}
7876

7977
/// Operations on [`DefaultObjectAccessControl`](crate::default_object_access_control::DefaultObjectAccessControl)s.
80-
pub fn default_object_access_control(&self) -> DefaultObjectAccessControlClient<'_, R> {
78+
pub fn default_object_access_control(&self) -> DefaultObjectAccessControlClient<'_> {
8179
DefaultObjectAccessControlClient(self)
8280
}
8381

8482
/// Operations on [`HmacKey`](crate::hmac_key::HmacKey)s.
85-
pub fn hmac_key(&self) -> HmacKeyClient<'_, R> {
83+
pub fn hmac_key(&self) -> HmacKeyClient<'_> {
8684
HmacKeyClient(self)
8785
}
8886

8987
/// Operations on [`Object`](crate::object::Object)s.
90-
pub fn object(&self) -> ObjectClient<'_, R> {
88+
pub fn object(&self) -> ObjectClient<'_> {
9189
ObjectClient(self)
9290
}
9391

9492
/// Operations on [`ObjectAccessControl`](crate::object_access_control::ObjectAccessControl)s.
95-
pub fn object_access_control(&self) -> ObjectAccessControlClient<'_, R> {
93+
pub fn object_access_control(&self) -> ObjectAccessControlClient<'_> {
9694
ObjectAccessControlClient(self)
9795
}
9896

‎src/client/bucket.rs

+10-18
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
use crate::{
22
bucket::{IamPolicy, TestIamPermission},
3-
object::percent_encode,
43
error::GoogleResponse,
4+
object::percent_encode,
55
resources::common::ListResponse,
6-
token::TokenCache,
76
Bucket, NewBucket,
87
};
98

109
/// Operations on [`Bucket`]()s.
1110
#[derive(Debug)]
12-
pub struct BucketClient<'a, T: TokenCache>(pub(super) &'a super::Client<T>);
11+
pub struct BucketClient<'a>(pub(super) &'a super::Client);
1312

14-
impl<'a, T> BucketClient<'a, T>
15-
where
16-
T: TokenCache,
17-
{
13+
impl<'a> BucketClient<'a> {
1814
/// Creates a new `Bucket`. There are many options that you can provide for creating a new
1915
/// bucket, so the `NewBucket` resource contains all of them. Note that `NewBucket` implements
2016
/// `Default`, so you don't have to specify the fields you're not using. And error is returned
@@ -118,11 +114,7 @@ where
118114
/// # }
119115
/// ```
120116
pub async fn read(&self, name: &str) -> crate::Result<Bucket> {
121-
let url = format!(
122-
"{}/b/{}",
123-
crate::BASE_URL,
124-
percent_encode(name),
125-
);
117+
let url = format!("{}/b/{}", crate::BASE_URL, percent_encode(name),);
126118
let result: GoogleResponse<Bucket> = self
127119
.0
128120
.client
@@ -167,11 +159,7 @@ where
167159
/// # }
168160
/// ```
169161
pub async fn update(&self, bucket: &Bucket) -> crate::Result<Bucket> {
170-
let url = format!(
171-
"{}/b/{}",
172-
crate::BASE_URL,
173-
percent_encode(&bucket.name),
174-
);
162+
let url = format!("{}/b/{}", crate::BASE_URL, percent_encode(&bucket.name),);
175163
let result: GoogleResponse<Bucket> = self
176164
.0
177165
.client
@@ -346,7 +334,11 @@ where
346334
"tested permission must not be `storage.buckets.list` or `storage.buckets.create`",
347335
));
348336
}
349-
let url = format!("{}/b/{}/iam/testPermissions", crate::BASE_URL, percent_encode(&bucket.name));
337+
let url = format!(
338+
"{}/b/{}/iam/testPermissions",
339+
crate::BASE_URL,
340+
percent_encode(&bucket.name)
341+
);
350342
let result: GoogleResponse<TestIamPermission> = self
351343
.0
352344
.client

‎src/client/bucket_access_control.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
use crate::{
22
bucket_access_control::{BucketAccessControl, Entity, NewBucketAccessControl},
3-
object::percent_encode,
43
error::GoogleResponse,
4+
object::percent_encode,
55
resources::common::ListResponse,
6-
token::TokenCache,
76
};
87

98
/// Operations on [`BucketAccessControl`](BucketAccessControl)s.
10-
pub struct BucketAccessControlClient<'a, R: TokenCache>(pub(super) &'a super::Client<R>);
9+
pub struct BucketAccessControlClient<'a>(pub(super) &'a super::Client);
1110

12-
impl<'a, R> BucketAccessControlClient<'a, R>
13-
where
14-
R: TokenCache,
15-
{
11+
impl<'a> BucketAccessControlClient<'a> {
1612
/// Create a new `BucketAccessControl` using the provided `NewBucketAccessControl`, related to
1713
/// the `Bucket` provided by the `bucket_name` argument.
1814
///
@@ -117,7 +113,12 @@ where
117113
/// # }
118114
/// ```
119115
pub async fn read(&self, bucket: &str, entity: &Entity) -> crate::Result<BucketAccessControl> {
120-
let url = format!("{}/b/{}/acl/{}", crate::BASE_URL, percent_encode(bucket), percent_encode(&entity.to_string()));
116+
let url = format!(
117+
"{}/b/{}/acl/{}",
118+
crate::BASE_URL,
119+
percent_encode(bucket),
120+
percent_encode(&entity.to_string())
121+
);
121122
let result: GoogleResponse<BucketAccessControl> = self
122123
.0
123124
.client

‎src/client/default_object_access_control.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
use crate::{
22
bucket_access_control::Entity,
3-
object::percent_encode,
43
default_object_access_control::{DefaultObjectAccessControl, NewDefaultObjectAccessControl},
54
error::GoogleResponse,
5+
object::percent_encode,
66
resources::common::ListResponse,
7-
token::TokenCache,
87
};
98

109
/// Operations on [`DefaultObjectAccessControl`](DefaultObjectAccessControl)s.
1110
#[derive(Debug)]
12-
pub struct DefaultObjectAccessControlClient<'a, T: TokenCache>(pub(super) &'a super::Client<T>);
11+
pub struct DefaultObjectAccessControlClient<'a>(pub(super) &'a super::Client);
1312

14-
impl<'a, R> DefaultObjectAccessControlClient<'a, R>
15-
where
16-
R: TokenCache,
17-
{
13+
impl<'a> DefaultObjectAccessControlClient<'a> {
1814
/// Create a new `DefaultObjectAccessControl` entry on the specified bucket.
1915
/// ### Important
2016
/// Important: This method fails with a `400 Bad Request` response for buckets with uniform
@@ -44,7 +40,11 @@ where
4440
bucket: &str,
4541
new_acl: &NewDefaultObjectAccessControl,
4642
) -> crate::Result<DefaultObjectAccessControl> {
47-
let url = format!("{}/b/{}/defaultObjectAcl", crate::BASE_URL, percent_encode(bucket));
43+
let url = format!(
44+
"{}/b/{}/defaultObjectAcl",
45+
crate::BASE_URL,
46+
percent_encode(bucket)
47+
);
4848
let result: GoogleResponse<DefaultObjectAccessControl> = self
4949
.0
5050
.client
@@ -82,7 +82,11 @@ where
8282
/// # }
8383
/// ```
8484
pub async fn list(&self, bucket: &str) -> crate::Result<Vec<DefaultObjectAccessControl>> {
85-
let url = format!("{}/b/{}/defaultObjectAcl", crate::BASE_URL, percent_encode(bucket));
85+
let url = format!(
86+
"{}/b/{}/defaultObjectAcl",
87+
crate::BASE_URL,
88+
percent_encode(bucket)
89+
);
8690
let result: GoogleResponse<ListResponse<DefaultObjectAccessControl>> = self
8791
.0
8892
.client

‎src/client/hmac_key.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
use crate::{
22
error::GoogleResponse,
33
hmac_key::{HmacKey, HmacMeta, HmacState},
4-
token::TokenCache,
54
};
65

76
/// Operations on [`HmacKey`](HmacKey)s.
87
#[derive(Debug)]
9-
pub struct HmacKeyClient<'a, R: TokenCache>(pub(super) &'a super::Client<R>);
8+
pub struct HmacKeyClient<'a>(pub(super) &'a super::Client);
109

11-
impl<'a, R> HmacKeyClient<'a, R>
12-
where
13-
R: TokenCache,
14-
{
10+
impl<'a> HmacKeyClient<'a> {
1511
/// Creates a new HMAC key for the specified service account.
1612
///
1713
/// The authenticated user must have `storage.hmacKeys.create` permission for the project in

‎src/client/object.rs

+11-12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use reqwest::StatusCode;
44
use crate::{
55
error::GoogleResponse,
66
object::{percent_encode, ComposeRequest, ObjectList, RewriteResponse, SizedByteStream},
7-
token::TokenCache,
87
ListRequest, Object,
98
};
109

@@ -13,12 +12,9 @@ const BASE_URL: &str = "https://storage.googleapis.com/upload/storage/v1/b";
1312

1413
/// Operations on [`Object`](Object)s.
1514
#[derive(Debug)]
16-
pub struct ObjectClient<'a, R: TokenCache>(pub(super) &'a super::Client<R>);
15+
pub struct ObjectClient<'a>(pub(super) &'a super::Client);
1716

18-
impl<'a, R> ObjectClient<'a, R>
19-
where
20-
R: TokenCache,
21-
{
17+
impl<'a> ObjectClient<'a> {
2218
/// Create a new object.
2319
/// Upload a file as that is loaded in memory to google cloud storage, where it will be
2420
/// interpreted according to the mime type you specified.
@@ -569,18 +565,21 @@ where
569565
);
570566
let mut headers = self.0.get_headers().await?;
571567
headers.insert(CONTENT_LENGTH, "0".parse()?);
572-
let result: GoogleResponse<RewriteResponse> = self
568+
let s = self
573569
.0
574570
.client
575571
.post(&url)
576572
.headers(headers)
577573
.send()
578574
.await?
579-
.json()
575+
.text()
580576
.await?;
581-
match result {
582-
GoogleResponse::Success(s) => Ok(s.resource),
583-
GoogleResponse::Error(e) => Err(e.into()),
584-
}
577+
578+
let result: RewriteResponse = serde_json::from_str(dbg!(&s)).unwrap();
579+
Ok(result.resource)
580+
// match result {
581+
// GoogleResponse::Success(s) => Ok(s.resource),
582+
// GoogleResponse::Error(e) => Err(e.into()),
583+
// }
585584
}
586585
}

‎src/client/object_access_control.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
use crate::{
22
bucket_access_control::Entity,
3-
object::percent_encode,
43
error::GoogleResponse,
4+
object::percent_encode,
55
object_access_control::{NewObjectAccessControl, ObjectAccessControl},
66
resources::common::ListResponse,
7-
token::TokenCache,
87
};
98

109
/// Operations on [`ObjectAccessControl`](ObjectAccessControl)s.
1110
#[derive(Debug)]
12-
pub struct ObjectAccessControlClient<'a, R: TokenCache>(pub(super) &'a super::Client<R>);
11+
pub struct ObjectAccessControlClient<'a>(pub(super) &'a super::Client);
1312

14-
impl<'a, R> ObjectAccessControlClient<'a, R>
15-
where
16-
R: TokenCache,
17-
{
13+
impl<'a> ObjectAccessControlClient<'a> {
1814
/// Creates a new ACL entry on the specified `object`.
1915
///
2016
/// ### Important

‎src/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ mod error;
9898
mod resources;
9999
mod token;
100100

101+
use crate::resources::service_account::ServiceAccount;
101102
pub use crate::{
102103
client::Client,
103104
error::*,
@@ -106,8 +107,8 @@ pub use crate::{
106107
object::{ListRequest, Object},
107108
*,
108109
},
110+
token::{Token, TokenCache},
109111
};
110-
use crate::{resources::service_account::ServiceAccount, token::Token};
111112
pub use download_options::DownloadOptions;
112113
use tokio::sync::Mutex;
113114

@@ -124,7 +125,7 @@ lazy_static::lazy_static! {
124125

125126
#[cfg(feature = "global-client")]
126127
lazy_static::lazy_static! {
127-
static ref CLOUD_CLIENT: client::Client<Token> = client::Client::default();
128+
static ref CLOUD_CLIENT: client::Client = client::Client::default();
128129
}
129130

130131
/// A type alias where the error is set to be `cloud_storage::Error`.

‎src/resources/bucket_access_control.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,9 @@ mod tests {
280280
entity: Entity::AllUsers,
281281
role: Role::Reader,
282282
};
283-
BucketAccessControl::create(&bucket.name, &new_bucket_access_control).await.unwrap();
283+
BucketAccessControl::create(&bucket.name, &new_bucket_access_control)
284+
.await
285+
.unwrap();
284286
Ok(())
285287
}
286288

‎src/resources/common.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub enum Role {
6363
pub(crate) struct ListResponse<T> {
6464
#[serde(default = "Vec::new")]
6565
pub items: Vec<T>,
66-
pub next_page_token: Option<String>,
66+
// pub next_page_token: Option<String>,
6767
}
6868

6969
/// An entity is used to represent a user or group of users that often have some kind of permission.

‎src/resources/object.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -227,11 +227,12 @@ pub struct ObjectList {
227227

228228
#[derive(Debug, serde::Deserialize)]
229229
#[serde(rename_all = "camelCase")]
230+
#[allow(dead_code)]
230231
pub(crate) struct RewriteResponse {
231-
pub(crate) kind: String,
232-
pub(crate) total_bytes_rewritten: String,
233-
pub(crate) object_size: String,
234-
pub(crate) done: bool,
232+
kind: String,
233+
total_bytes_rewritten: String,
234+
object_size: String,
235+
done: bool,
235236
pub(crate) resource: Object,
236237
}
237238

@@ -920,8 +921,10 @@ mod ring {
920921
#[cfg_attr(all(feature = "ring", feature = "openssl"), allow(dead_code))]
921922
#[inline(always)]
922923
pub fn rsa_pkcs1_sha256(message: &str) -> crate::Result<Vec<u8>> {
923-
use ring::rand::SystemRandom;
924-
use ring::signature::{RsaKeyPair, RSA_PKCS1_SHA256};
924+
use ring::{
925+
rand::SystemRandom,
926+
signature::{RsaKeyPair, RSA_PKCS1_SHA256},
927+
};
925928

926929
let key_pem = pem::parse(crate::SERVICE_ACCOUNT.private_key.as_bytes())?;
927930
let key = RsaKeyPair::from_pkcs8(&key_pem.contents)?;

‎src/sync.rs

+21-20
Original file line numberDiff line numberDiff line change
@@ -16,63 +16,64 @@ pub use hmac_key::HmacKeyClient;
1616
pub use object::ObjectClient;
1717
pub use object_access_control::ObjectAccessControlClient;
1818

19-
use crate::token::{Token, TokenCache};
20-
2119
/// The primary synchronous entrypoint to perform operations with Google Cloud Storage.
2220
#[derive(Debug)]
23-
pub struct Client<R: TokenCache> {
21+
pub struct Client {
2422
runtime: tokio::runtime::Runtime,
25-
client: crate::client::Client<R>,
23+
client: crate::client::Client,
2624
}
2725

28-
impl Client<Token> {
29-
/// Constructs a synchronous client
26+
impl Client {
27+
/// Constructs a client with the default token provider, where it attemps to obtain the
28+
/// credentials from the following locations:
29+
///
30+
/// 1. Checks for the environment variable `SERVICE_ACCOUNT`, and if it exists, reads the file
31+
/// at the path specified there as a credentials json file.
32+
/// 2. It attemps to do the same with the `GOOGLE_APPLICATION_CREDENTIALS` var.
33+
/// 3. It reads the `SERVICE_ACCOUNT_JSON` environment variable directly as json and uses that
34+
/// 4.It attemps to do the same with the `GOOGLE_APPLICATION_CREDENTIALS_JSON` var.
3035
pub fn new() -> crate::Result<Self> {
3136
Ok(Self {
3237
runtime: crate::runtime()?,
33-
client: Default::default(),
38+
client: crate::Client::default(),
3439
})
3540
}
36-
}
3741

38-
impl<R> Client<R>
39-
where
40-
R: TokenCache,
41-
{
4242
/// Initializer with a provided refreshable token
43-
pub fn with_token_cache(token_cache: R) -> crate::Result<Self> {
43+
pub fn with_cache(token_cache: impl crate::TokenCache + 'static) -> crate::Result<Self> {
4444
Ok(Self {
4545
runtime: crate::runtime()?,
46-
client: crate::Client::with_token_cache(token_cache),
46+
client: crate::Client::with_cache(token_cache),
4747
})
4848
}
49+
4950
/// Synchronous operations on [`Bucket`](crate::bucket::Bucket)s.
50-
pub fn bucket(&self) -> BucketClient<'_, R> {
51+
pub fn bucket(&self) -> BucketClient {
5152
BucketClient(self)
5253
}
5354

5455
/// Synchronous operations on [`BucketAccessControl`](crate::bucket_access_control::BucketAccessControl)s.
55-
pub fn bucket_access_control(&self) -> BucketAccessControlClient<'_, R> {
56+
pub fn bucket_access_control(&self) -> BucketAccessControlClient {
5657
BucketAccessControlClient(self)
5758
}
5859

5960
/// Synchronous operations on [`DefaultObjectAccessControl`](crate::default_object_access_control::DefaultObjectAccessControl)s.
60-
pub fn default_object_access_control(&self) -> DefaultObjectAccessControlClient<'_, R> {
61+
pub fn default_object_access_control(&self) -> DefaultObjectAccessControlClient {
6162
DefaultObjectAccessControlClient(self)
6263
}
6364

6465
/// Synchronous operations on [`HmacKey`](crate::hmac_key::HmacKey)s.
65-
pub fn hmac_key(&self) -> HmacKeyClient<'_, R> {
66+
pub fn hmac_key(&self) -> HmacKeyClient {
6667
HmacKeyClient(self)
6768
}
6869

6970
/// Synchronous operations on [`Object`](crate::object::Object)s.
70-
pub fn object(&self) -> ObjectClient<'_, R> {
71+
pub fn object(&self) -> ObjectClient {
7172
ObjectClient(self)
7273
}
7374

7475
/// Synchronous operations on [`ObjectAccessControl`](crate::object_access_control::ObjectAccessControl)s.
75-
pub fn object_access_control(&self) -> ObjectAccessControlClient<'_, R> {
76+
pub fn object_access_control(&self) -> ObjectAccessControlClient {
7677
ObjectAccessControlClient(self)
7778
}
7879
}

‎src/sync/bucket.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
use crate::{
22
bucket::{IamPolicy, TestIamPermission},
3-
token::TokenCache,
43
Bucket, NewBucket,
54
};
65

76
/// Operations on [`Bucket`]()s.
87
#[derive(Debug)]
9-
pub struct BucketClient<'a, R: TokenCache>(pub(super) &'a super::Client<R>);
8+
pub struct BucketClient<'a>(pub(super) &'a super::Client);
109

11-
impl<'a, R> BucketClient<'a, R>
12-
where
13-
R: TokenCache,
14-
{
10+
impl<'a> BucketClient<'a> {
1511
/// Creates a new `Bucket`. There are many options that you can provide for creating a new
1612
/// bucket, so the `NewBucket` resource contains all of them. Note that `NewBucket` implements
1713
/// `Default`, so you don't have to specify the fields you're not using. And error is returned

‎src/sync/bucket_access_control.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
use crate::{
22
bucket_access_control::{BucketAccessControl, Entity, NewBucketAccessControl},
3-
token::TokenCache,
43
};
54

65
/// Operations on [`BucketAccessControl`](BucketAccessControl)s.
76
#[derive(Debug)]
8-
pub struct BucketAccessControlClient<'a, R: TokenCache>(pub(super) &'a super::Client<R>);
7+
pub struct BucketAccessControlClient<'a>(pub(super) &'a super::Client);
98

10-
impl<'a, R> BucketAccessControlClient<'a, R>
11-
where
12-
R: TokenCache,
13-
{
9+
impl<'a> BucketAccessControlClient<'a> {
1410
/// Create a new `BucketAccessControl` using the provided `NewBucketAccessControl`, related to
1511
/// the `Bucket` provided by the `bucket_name` argument.
1612
///

‎src/sync/default_object_access_control.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
use crate::{
22
bucket_access_control::Entity,
33
default_object_access_control::{DefaultObjectAccessControl, NewDefaultObjectAccessControl},
4-
token::TokenCache,
54
};
65

76
/// Operations on [`DefaultObjectAccessControl`](DefaultObjectAccessControl)s.
87
#[derive(Debug)]
9-
pub struct DefaultObjectAccessControlClient<'a, R: TokenCache>(pub(super) &'a super::Client<R>);
8+
pub struct DefaultObjectAccessControlClient<'a>(pub(super) &'a super::Client);
109

11-
impl<'a, R> DefaultObjectAccessControlClient<'a, R>
12-
where
13-
R: TokenCache,
14-
{
10+
impl<'a> DefaultObjectAccessControlClient<'a> {
1511
/// Create a new `DefaultObjectAccessControl` entry on the specified bucket.
1612
/// ### Important
1713
/// Important: This method fails with a `400 Bad Request` response for buckets with uniform

‎src/sync/helpers/reader_stream.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
use std::{io::{BufReader, Read}, pin::Pin, task::{Context, Poll}};
21
use futures::Stream;
2+
use std::{
3+
io::{BufReader, Read},
4+
pin::Pin,
5+
task::{Context, Poll},
6+
};
37

48
const BUF_CAP: usize = 8 * 1024;
59

@@ -22,7 +26,7 @@ impl<R: std::io::Read + Send + Sync + Unpin + 'static> Stream for ReaderStream<R
2226
Ok(n) => {
2327
buf.truncate(n);
2428
Poll::Ready(Some(Ok(buf)))
25-
},
29+
}
2630
Err(e) => Poll::Ready(Some(Err(e.into()))),
2731
}
2832
}

‎src/sync/hmac_key.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
use crate::{
22
hmac_key::{HmacKey, HmacMeta, HmacState},
3-
token::TokenCache,
43
};
54

65
/// Operations on [`HmacKey`](HmacKey)s.
76
#[derive(Debug)]
8-
pub struct HmacKeyClient<'a, R: TokenCache>(pub(super) &'a super::Client<R>);
7+
pub struct HmacKeyClient<'a>(pub(super) &'a super::Client);
98

10-
impl<'a, R> HmacKeyClient<'a, R>
11-
where
12-
R: TokenCache,
13-
{
9+
impl<'a> HmacKeyClient<'a> {
1410
/// Creates a new HMAC key for the specified service account.
1511
///
1612
/// The authenticated user must have `storage.hmacKeys.create` permission for the project in

‎src/sync/object.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
use crate::{
22
object::{ComposeRequest, ObjectList},
3-
token::TokenCache,
43
ListRequest, Object,
54
};
65
use futures::TryStreamExt;
76

87
/// Operations on [`Object`](Object)s.
98
#[derive(Debug)]
10-
pub struct ObjectClient<'a, T: TokenCache>(pub(super) &'a super::Client<T>);
9+
pub struct ObjectClient<'a>(pub(super) &'a super::Client);
1110

12-
impl<'a, T> ObjectClient<'a, T>
13-
where
14-
T: TokenCache,
15-
{
11+
impl<'a> ObjectClient<'a> {
1612
/// Create a new object.
1713
/// Upload a file as that is loaded in memory to google cloud storage, where it will be
1814
/// interpreted according to the mime type you specified.

‎src/sync/object_access_control.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
use crate::{
22
bucket_access_control::Entity,
33
object_access_control::{NewObjectAccessControl, ObjectAccessControl},
4-
token::TokenCache,
54
};
65

76
/// Operations on [`ObjectAccessControl`](ObjectAccessControl)s.
87
#[derive(Debug)]
9-
pub struct ObjectAccessControlClient<'a, R: TokenCache>(pub(super) &'a super::Client<R>);
8+
pub struct ObjectAccessControlClient<'a>(pub(super) &'a super::Client);
109

11-
impl<'a, R> ObjectAccessControlClient<'a, R>
12-
where
13-
R: TokenCache,
14-
{
10+
impl<'a> ObjectAccessControlClient<'a> {
1511
/// Creates a new ACL entry on the specified `object`.
1612
///
1713
/// ### Important

‎src/token.rs

+32-38
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,35 @@ use std::fmt::{Display, Formatter};
33
/// Trait that refreshes a token when it is expired
44
#[async_trait::async_trait]
55
pub trait TokenCache: Sync {
6-
type TokenData: Sync + Send + Clone + Display;
7-
/// Getter for the token
8-
async fn get_token(&self) -> Option<Self::TokenData>;
6+
/// Returns the token that is currently held within the instance of `TokenCache`, together with
7+
/// the expiry of that token as a u64 in seconds sine the Unix Epoch (1 Jan 1970).
8+
async fn token_and_exp(&self) -> Option<(String, u64)>;
99

10-
/// Updates the token
11-
async fn set_token(&self, token: Self::TokenData) -> crate::Result<()>;
10+
/// Updates the token to the value `token`.
11+
async fn set_token(&self, token: String, exp: u64) -> crate::Result<()>;
1212

13-
/// Getter for the scope
14-
fn get_scope(&self) -> &str;
13+
/// Returns the intended scope for the current token.
14+
async fn scope(&self) -> String;
1515

16-
/// Returns whether the token is expired
17-
fn is_expired(token: &Self::TokenData) -> bool;
18-
19-
/// Returns a valid, unexpired token
20-
/// Otherwise updates and returns the token
21-
async fn get(&self, client: &reqwest::Client) -> crate::Result<Self::TokenData> {
22-
match self.get_token().await {
23-
Some(token) if !Self::is_expired(&token) => Ok(token),
16+
/// Returns a valid, unexpired token. If the contained token is expired, it updates and returns
17+
/// the token.
18+
async fn get(&self, client: &reqwest::Client) -> crate::Result<String> {
19+
match self.token_and_exp().await {
20+
Some((token, exp)) if now() > exp => Ok(token),
2421
_ => {
25-
let scope = self.get_scope();
26-
let token = Self::fetch_token(client, scope).await?;
27-
self.set_token(token).await?;
22+
let (token, exp) = self.fetch_token(client).await?;
23+
self.set_token(token, exp).await?;
2824

29-
self.get_token()
25+
self.token_and_exp()
3026
.await
27+
.map(|(t, _)| t)
3128
.ok_or(crate::Error::Other("Token is not set".to_string()))
3229
}
3330
}
3431
}
3532

3633
/// Fetches and returns the token using the service account
37-
async fn fetch_token(client: &reqwest::Client, scope: &str) -> crate::Result<Self::TokenData>;
34+
async fn fetch_token(&self, client: &reqwest::Client) -> crate::Result<(String, u64)>;
3835
}
3936

4037
#[derive(serde::Serialize)]
@@ -47,10 +44,11 @@ struct Claims {
4744
}
4845

4946
#[derive(serde::Deserialize, Debug)]
47+
// #[allow(dead_code)]
5048
struct TokenResponse {
5149
access_token: String,
52-
expires_in: usize,
53-
token_type: String,
50+
expires_in: u64,
51+
// token_type: String,
5452
}
5553

5654
/// This struct contains a token, an expiry, and an access scope.
@@ -63,7 +61,7 @@ pub struct Token {
6361
}
6462

6563
#[derive(Debug, Clone)]
66-
pub struct DefaultTokenData(pub String, u64);
64+
pub struct DefaultTokenData(String, u64);
6765

6866
impl Display for DefaultTokenData {
6967
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
@@ -78,40 +76,36 @@ impl Default for Token {
7876
}
7977

8078
impl Token {
81-
pub fn new(scope: &str) -> Self {
79+
pub(crate) fn new(scope: &str) -> Self {
8280
Self {
8381
token: tokio::sync::RwLock::new(None),
8482
access_scope: scope.to_string(),
8583
}
8684
}
8785
}
86+
8887
#[async_trait::async_trait]
8988
impl TokenCache for Token {
90-
type TokenData = DefaultTokenData;
91-
92-
fn get_scope(&self) -> &str {
93-
self.access_scope.as_ref()
89+
async fn scope(&self) -> String {
90+
self.access_scope.clone()
9491
}
9592

96-
fn is_expired(token: &Self::TokenData) -> bool {
97-
token.1 > now()
93+
async fn token_and_exp(&self) -> Option<(String, u64)> {
94+
self.token.read().await.as_ref().map(|d| (d.0.clone(), d.1))
9895
}
9996

100-
async fn get_token(&self) -> Option<Self::TokenData> {
101-
self.token.read().await.clone()
102-
}
103-
async fn set_token(&self, token: Self::TokenData) -> crate::Result<()> {
104-
*self.token.write().await = Some(token);
97+
async fn set_token(&self, token: String, exp: u64) -> crate::Result<()> {
98+
*self.token.write().await = Some(DefaultTokenData(token, exp));
10599
Ok(())
106100
}
107101

108-
async fn fetch_token(client: &reqwest::Client, scope: &str) -> crate::Result<Self::TokenData> {
102+
async fn fetch_token(&self, client: &reqwest::Client) -> crate::Result<(String, u64)> {
109103
let now = now();
110104
let exp = now + 3600;
111105

112106
let claims = Claims {
113107
iss: crate::SERVICE_ACCOUNT.client_email.clone(),
114-
scope: scope.into(),
108+
scope: self.scope().await.into(),
115109
aud: "https://www.googleapis.com/oauth2/v4/token".to_string(),
116110
exp,
117111
iat: now,
@@ -134,7 +128,7 @@ impl TokenCache for Token {
134128
.await?
135129
.json()
136130
.await?;
137-
Ok(DefaultTokenData(response.access_token, exp))
131+
Ok((response.access_token, now + response.expires_in))
138132
}
139133
}
140134

‎test.sh

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
set -e
2+
echo && echo '--------------------------------' && echo 'Runing sync tests'
3+
cargo test --features sync,global-client -- --test-threads=1
4+
echo && echo '--------------------------------' && echo 'Runing sync tests with rustls'
5+
cargo test --no-default-features --features sync,rustls-tls,global-client -- --test-threads=1
6+
echo && echo '--------------------------------' && echo 'Runing sync tests with all features'
7+
cargo test --all-features -- --test-threads=1

0 commit comments

Comments
 (0)
Please sign in to comment.