jh_s3/
lib.rs

1mod aws_sig_v4;
2// mod aws_sig_v4_surf;
3pub mod bucket;
4pub mod object;
5pub extern crate zjhttpc;
6
7use std::collections::HashMap;
8use std::fs;
9use std::path::PathBuf;
10
11use anyhow_ext::Context;
12use anyhow_ext::Result;
13use anyhow_ext::anyhow;
14use derive_builder::Builder;
15use serde::Deserialize;
16use serde::Serialize;
17use std::path::Path;
18use zjhttpc::client::ZJHttpClient;
19use zjhttpc::requestx::Request;
20use zjhttpc::response::Response;
21use zjhttpc::url::Url;
22
23#[derive(Default, Debug)]
24pub struct S3Client {
25	pub endpoint: String,
26	pub bucket: String,
27	pub access_key: String,
28	pub secret_key: String,
29	pub httpc: ZJHttpClient,
30}
31
32#[derive(Serialize, Deserialize, Debug)]
33pub struct S3Config {
34	pub endpoint: String,
35	pub bucket: String,
36	pub access_key: String,
37	pub secret_key: String,
38	pub trust_cert_path: Option<String>,
39}
40
41impl S3Client {
42	pub fn new(
43		endpoint: String,
44		bucket: String,
45		access_key: String,
46		secret_key: String,
47		trust_cert_path: Option<String>,
48	) -> Self {
49		// let http_client: surf::Client = match trust_cert_path {
50		// 	Some(path) => {
51		// 		todo!()
52		// 	}
53		// 	None => {
54		// 		let surf_config = surf::Config::new();
55		// 		surf_config.try_into().unwrap()
56		// 	}
57		// };
58		let mut httpc = ZJHttpClient::new();
59		if let Some(cert_path) = trust_cert_path {
60			httpc.global_trust_store_pem =
61				Some(zjhttpc::misc::TrustStorePem::Path(PathBuf::from(cert_path)));
62		}
63		return S3Client {
64			endpoint,
65			bucket,
66			access_key,
67			secret_key,
68			// http_client,
69			httpc,
70		};
71	}
72	pub fn from_toml_config<P>(path: P) -> Result<Self>
73	where
74		P: AsRef<Path>,
75	{
76		let txt = fs::read_to_string(path)?;
77		let c: S3Config = toml::from_str(&txt)?;
78		return Ok(Self::new(
79			c.endpoint,
80			c.bucket,
81			c.access_key,
82			c.secret_key,
83			c.trust_cert_path,
84		));
85	}
86	pub async fn send(
87		&self,
88		path: Option<&str>,
89		method: &'static str,
90		queries: Option<&impl Serialize>,
91		headers: Option<HashMap<String, String>>,
92		body: Option<S3Body>,
93	) -> Result<Response> {
94		let mut url = format!("{}/{}", self.endpoint, self.bucket);
95		if let Some(p) = path {
96			url.push_str("/");
97			url.push_str(p);
98		}
99		let url = Url::parse(&url)?;
100		let mut req = Request::new(method, url).dot()?;
101		if let Some(headers) = headers {
102			req = req.set_headers_nondup(headers);
103		}
104		if let Some(queries) = queries {
105			req = req.set_queries_serde(queries).dot()?;
106		}
107		req = crate::aws_sig_v4::auth(&self.access_key, &self.secret_key, req, None, body).await.dot()?;
108		let resp = self
109			.httpc
110			.send(&mut req)
111			.await
112			.map_err(|err| anyhow!(err.to_string()))?;
113		Ok(resp)
114	}
115
116	// pub async fn send_via_surf(
117	// 	&self,
118	// 	path: Option<&str>,
119	// 	method: surf::http::Method,
120	// 	queries: Option<&impl Serialize>,
121	// 	headers: Option<HashMap<String, String>>,
122	// 	body: Option<impl Into<surf::Body>>,
123	// ) -> Result<surf::Response> {
124	// 	let mut url = format!("{}/{}", self.endpoint, self.bucket);
125	// 	if let Some(p) = path {
126	// 		url.push_str("/");
127	// 		url.push_str(p);
128	// 	}
129	// 	let url = Url::parse(&url)?;
130	// 	let mut builder = surf::RequestBuilder::new(method, url)
131	// 		.query(&queries)
132	// 		.map_err(|err| anyhow!(err.to_string()))?;
133	// 	if let Some(map) = headers {
134	// 		for (key, value) in map.into_iter() {
135	// 			let key = surf::http::headers::HeaderName::from_bytes(key.into_bytes()).unwrap();
136	// 			builder = builder.header(&key, value);
137	// 		}
138	// 	}
139	// 	if let Some(body) = body {
140	// 		builder = builder.body(body);
141	// 	}
142	// 	let req = builder.build();
143	// 	let req = crate::aws_sig_v4_surf::auth(&self.access_key, &self.secret_key, req, None)?;
144	// 	let surf_config = surf::Config::new();
145	// 	let http_client: surf::Client = surf_config.try_into().dot()?;
146	// 	let resp = http_client
147	// 		.send(req)
148	// 		.await
149	// 		.map_err(|err| anyhow!(err.to_string()))?;
150	// 	Ok(resp)
151	// }
152}
153
154pub enum S3Body {
155	Bytes(Vec<u8>),
156	Path(PathBuf)
157}
158
159#[derive(Deserialize, Debug)]
160#[serde(rename_all = "PascalCase")]
161pub struct S3Error {
162	code: String,
163	message: String,
164	resource: Option<String>,
165	request_id: Option<String>,
166}
167
168#[cfg(test)]
169mod test {
170	use crate::{
171		bucket::{ListBucketParams, ListBucketParamsBuilder}, S3Client
172	};
173	use anyhow_ext::Result;
174	use async_std::task;
175	use tracing::info;
176
177	#[test]
178	fn test_s3_client() {
179		// let s3client = S3Client::new(endpoint, bucket, access_key, secret_key, trust_cert_path)
180		
181	}
182}