cloud_storage_lite/client/
mod.rs1pub(crate) mod bucket;
4
5use std::sync::Arc;
6
7use futures::Future;
8use reqwest::{Method, RequestBuilder, Response, StatusCode, Url};
9
10use crate::{errors::Error, token_provider::TokenProvider};
11
12pub use bucket::{BucketClient, GcsBucketClient};
13
14const GCS_API_URL: &str = "https://www.googleapis.com/storage/v1/";
15
16#[derive(Clone)]
20pub struct Client {
21 token_provider: Arc<dyn TokenProvider>,
22 client: reqwest::Client,
23 api_url: Arc<Url>,
24}
25
26impl Client {
27 pub fn new(token_provider: impl TokenProvider + 'static) -> Self {
29 Self::new_with_client(token_provider, Default::default())
30 }
31
32 pub fn new_with_client(
34 token_provider: impl TokenProvider + 'static,
35 client: reqwest::Client,
36 ) -> Self {
37 Self {
38 token_provider: Arc::new(token_provider),
39 client,
40 api_url: Arc::new(Url::parse(GCS_API_URL).unwrap()),
41 }
42 }
43
44 pub fn into_bucket_client(self, bucket_name: String) -> bucket::GcsBucketClient {
46 bucket::GcsBucketClient::new(self, bucket_name)
47 }
48
49 async fn make_request<B, F>(
50 &self,
51 method: &Method,
52 path: &str,
53 make_request: B,
54 ) -> Result<Response, Error>
55 where
56 B: FnOnce(RequestBuilder) -> F,
57 F: Future<Output = Result<Response, reqwest::Error>>,
58 {
59 self.make_request_to_url(
60 method,
61 &self.api_url.join(path).expect("malformed url"),
62 make_request,
63 )
64 .await
65 }
66
67 async fn make_request_to_url<B, F>(
68 &self,
69 method: &Method,
70 url: &Url,
71 make_request: B,
72 ) -> Result<Response, Error>
73 where
74 B: FnOnce(RequestBuilder) -> F,
75 F: Future<Output = Result<Response, reqwest::Error>>,
76 {
77 let auth_token = self
78 .token_provider
79 .get_token()
80 .await
81 .map_err(Error::TokenFetch)?;
82 let builder = self
83 .client
84 .request(method.clone(), url.clone())
85 .bearer_auth(&auth_token.token);
86 let res = make_request(builder).await?;
87 if res.status() == StatusCode::UNAUTHORIZED {
88 self.token_provider.invalidate_token().await;
89 }
90 Ok(res)
91 }
92}