sui_storage/object_store/http/
s3.rs1use 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#[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}