mod aws_sig_v4;
pub mod bucket;
pub mod object;
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use anyhow_ext::Context;
use anyhow_ext::Result;
use anyhow_ext::anyhow;
use derive_builder::Builder;
use serde::Deserialize;
use serde::Serialize;
use std::path::Path;
use zjhttpc::client::ZJHttpClient;
use zjhttpc::requestx::Request;
use zjhttpc::response::Response;
use zjhttpc::url::Url;
#[derive(Default, Debug)]
pub struct S3Client {
pub endpoint: String,
pub bucket: String,
pub access_key: String,
pub secret_key: String,
pub httpc: ZJHttpClient,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct S3Config {
pub endpoint: String,
pub bucket: String,
pub access_key: String,
pub secret_key: String,
pub trust_cert_path: Option<String>,
}
impl S3Client {
pub fn new(
endpoint: String,
bucket: String,
access_key: String,
secret_key: String,
trust_cert_path: Option<String>,
) -> Self {
let mut httpc = ZJHttpClient::new();
if let Some(cert_path) = trust_cert_path {
httpc.global_trust_store_pem =
Some(zjhttpc::misc::TrustStorePem::Path(PathBuf::from(cert_path)));
}
return S3Client {
endpoint,
bucket,
access_key,
secret_key,
httpc,
};
}
pub fn from_toml_config<P>(path: P) -> Result<Self>
where
P: AsRef<Path>,
{
let txt = fs::read_to_string(path)?;
let c: S3Config = toml::from_str(&txt)?;
return Ok(Self::new(
c.endpoint,
c.bucket,
c.access_key,
c.secret_key,
c.trust_cert_path,
));
}
pub async fn send(
&self,
path: Option<&str>,
method: &'static str,
queries: Option<&impl Serialize>,
headers: Option<HashMap<String, String>>,
body: Option<S3Body>,
) -> Result<Response> {
let mut url = format!("{}/{}", self.endpoint, self.bucket);
if let Some(p) = path {
url.push_str("/");
url.push_str(p);
}
let url = Url::parse(&url)?;
let mut req = Request::new(method, url).dot()?;
if let Some(headers) = headers {
req = req.set_headers_nondup(headers);
}
if let Some(queries) = queries {
req = req.set_queries_serde(queries).dot()?;
}
req = crate::aws_sig_v4::auth(&self.access_key, &self.secret_key, req, None, body).await.dot()?;
let resp = self
.httpc
.send(&mut req)
.await
.map_err(|err| anyhow!(err.to_string()))?;
Ok(resp)
}
}
pub enum S3Body {
Bytes(Vec<u8>),
Path(PathBuf)
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct S3Error {
code: String,
message: String,
resource: Option<String>,
request_id: Option<String>,
}
#[cfg(test)]
mod test {
use crate::{
bucket::{ListBucketParams, ListBucketParamsBuilder}, S3Client
};
use anyhow_ext::Result;
use async_std::task;
use tracing::info;
#[test]
fn test_s3_client() {
}
}