sui_storage/object_store/http/
s3.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::object_store::ObjectStoreGetExt;
5use crate::object_store::http::{DEFAULT_USER_AGENT, STRICT_PATH_ENCODE_SET, get};
6use anyhow::Result;
7use async_trait::async_trait;
8use bytes::Bytes;
9use object_store::GetResult;
10use object_store::path::Path;
11use percent_encoding::{PercentEncode, utf8_percent_encode};
12use reqwest::Client;
13use reqwest::ClientBuilder;
14use std::fmt;
15use std::sync::Arc;
16
17#[derive(Debug)]
18pub(crate) struct S3Client {
19    endpoint: String,
20    client: Client,
21}
22
23impl S3Client {
24    pub fn new(endpoint: &str) -> Result<Self> {
25        let mut builder = ClientBuilder::new();
26        builder = builder
27            .user_agent(DEFAULT_USER_AGENT)
28            .pool_idle_timeout(None);
29        let client = builder.https_only(false).build()?;
30
31        Ok(Self {
32            endpoint: endpoint.to_string(),
33            client,
34        })
35    }
36    async fn get(&self, location: &Path) -> Result<GetResult> {
37        let url = self.path_url(location);
38        get(&url, "s3", location, &self.client).await
39    }
40    fn path_url(&self, path: &Path) -> String {
41        format!("{}/{}", self.endpoint, Self::encode_path(path))
42    }
43    fn encode_path(path: &Path) -> PercentEncode<'_> {
44        utf8_percent_encode(path.as_ref(), &STRICT_PATH_ENCODE_SET)
45    }
46}
47
48/// Interface for [Amazon S3](https://aws.amazon.com/s3/).
49#[derive(Debug)]
50pub struct AmazonS3 {
51    client: Arc<S3Client>,
52}
53
54impl AmazonS3 {
55    pub fn new(endpoint: &str) -> Result<Self> {
56        let s3_client = S3Client::new(endpoint)?;
57        Ok(AmazonS3 {
58            client: Arc::new(s3_client),
59        })
60    }
61}
62
63impl fmt::Display for AmazonS3 {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        write!(f, "s3:{}", self.client.endpoint)
66    }
67}
68
69#[async_trait]
70impl ObjectStoreGetExt for AmazonS3 {
71    async fn get_bytes(&self, location: &Path) -> Result<Bytes> {
72        let result = self.client.get(location).await?;
73        let bytes = result.bytes().await?;
74        Ok(bytes)
75    }
76}