iota_storage/object_store/http/
gcs.rs1use std::{fmt, sync::Arc};
6
7use anyhow::Result;
8use async_trait::async_trait;
9use bytes::Bytes;
10use object_store::{GetResult, path::Path};
11use percent_encoding::{NON_ALPHANUMERIC, percent_encode, utf8_percent_encode};
12use reqwest::{Client, ClientBuilder};
13
14use crate::object_store::{
15 ObjectStoreGetExt,
16 http::{DEFAULT_USER_AGENT, get},
17};
18
19#[derive(Debug)]
20struct GoogleCloudStorageClient {
21 client: Client,
22 bucket_name_encoded: String,
23}
24
25impl GoogleCloudStorageClient {
26 pub fn new(bucket: &str) -> Result<Self> {
27 let mut builder = ClientBuilder::new().pool_idle_timeout(None);
28 builder = builder.user_agent(DEFAULT_USER_AGENT);
29 let client = builder.https_only(false).build()?;
30 let bucket_name_encoded = percent_encode(bucket.as_bytes(), NON_ALPHANUMERIC).to_string();
31
32 Ok(Self {
33 client,
34 bucket_name_encoded,
35 })
36 }
37
38 async fn get(&self, path: &Path) -> Result<GetResult> {
39 let url = self.object_url(path);
40 get(&url, "gcs", path, &self.client).await
41 }
42
43 fn object_url(&self, path: &Path) -> String {
44 let encoded = utf8_percent_encode(path.as_ref(), NON_ALPHANUMERIC);
45 format!(
46 "https://storage.googleapis.com/{}/{}",
47 self.bucket_name_encoded, encoded
48 )
49 }
50}
51
52#[derive(Debug)]
54pub struct GoogleCloudStorage {
55 client: Arc<GoogleCloudStorageClient>,
56}
57
58impl GoogleCloudStorage {
59 pub fn new(bucket: &str) -> Result<Self> {
60 let gcs_client = GoogleCloudStorageClient::new(bucket)?;
61 Ok(GoogleCloudStorage {
62 client: Arc::new(gcs_client),
63 })
64 }
65}
66
67impl fmt::Display for GoogleCloudStorage {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 write!(f, "gcs:{}", self.client.bucket_name_encoded)
70 }
71}
72
73#[async_trait]
74impl ObjectStoreGetExt for GoogleCloudStorage {
75 async fn get_bytes(&self, location: &Path) -> Result<Bytes> {
76 let result = self.client.get(location).await?;
77 let bytes = result.bytes().await?;
78 Ok(bytes)
79 }
80}