huaweicloud_sdk_rust_obs/
client.rs1use std::{collections::HashMap, time::Duration};
2
3use reqwest::{header::HeaderMap, Body, Method, Response};
4
5use crate::{
6 auth::Authorization,
7 bucket::Bucket,
8 config::{Config, SecurityHolder, SignatureType},
9 error::ObsError,
10};
11
12#[derive(Debug)]
13pub struct Client {
14 config: Config,
15 http_client: reqwest::Client,
16}
17
18impl Client {
19 pub fn new<S: ToString>(
21 access_key_id: S,
22 secret_access_key: S,
23 endpoint: &str,
24 ) -> Result<Client, ObsError> {
25 ClientBuilder::new()
26 .security_provider(access_key_id, secret_access_key)
27 .endpoint(endpoint)
28 .build()
29 }
30
31 pub fn security(&self) -> Option<SecurityHolder> {
32 if !self.config().security_providers().is_empty() {
33 for sh in self.config().security_providers() {
34 if !sh.sk().is_empty() && !sh.ak().is_empty() {
35 return Some(sh.clone());
36 }
37 }
38 None
39 } else {
40 None
41 }
42 }
43 pub fn bucket<'a>(&'a self, name: &'a str) -> Bucket {
44 Bucket::new(name, self)
45 }
46
47 pub fn builder() -> ClientBuilder {
48 ClientBuilder::new()
49 }
50
51 pub fn config(&self) -> &Config {
52 &self.config
53 }
54
55 pub async fn do_action<T, S1, S2>(
56 &self,
57 method: Method,
58 bucket_name: S1,
59 uri: S2,
60 with_headers: Option<HeaderMap>,
61 params: Option<HashMap<String, String>>,
62 body: Option<T>,
63 ) -> Result<Response, ObsError>
64 where
65 T: Into<Body> + Send,
66 S1: AsRef<str> + Send,
67 S2: AsRef<str> + Send,
68 {
69 let mut auth_headers = HashMap::new();
70 let mut headers = if let Some(wh) = with_headers {
71 for (k, v) in &wh {
72 if let Ok(v) = v.to_str() {
73 auth_headers.insert(k.as_str().to_string(), vec![v.to_string()]);
74 }
75 }
76 wh
77 } else {
78 HeaderMap::new()
79 };
80
81 let (request_uri, canonicalized_url) =
82 self.config()
83 .format_urls(bucket_name.as_ref(), uri.as_ref(), params);
84
85 let url = format!(
86 "https://{}.{}/{}",
87 bucket_name.as_ref(),
88 self.config().endpoint(),
89 &request_uri
90 );
91
92 let auth_headers = self.auth(
93 method.as_str(),
94 bucket_name.as_ref(),
95 HashMap::new(),
96 auth_headers,
97 canonicalized_url,
98 )?;
99 headers.extend(auth_headers);
100
101 let mut req = self.http_client.request(method, url).headers(headers);
102
103 if let Some(body) = body {
104 req = req.body(body);
105 }
106 let res = req.send().await?;
107 Ok(res)
108 }
109
110 pub async fn do_action_without_bucket_name<T, S1>(
111 &self,
112 method: Method,
113 uri: S1,
114 with_headers: Option<HeaderMap>,
115 params: Option<HashMap<String, String>>,
116 body: Option<T>,
117 ) -> Result<Response, ObsError>
118 where
119 T: Into<Body> + Send,
120 S1: AsRef<str> + Send,
121 {
122 let (request_uri, canonicalized_url) = self.config().format_urls("", uri.as_ref(), params);
123 let mut headers = self.auth(
124 method.as_str(),
125 "",
126 HashMap::new(),
127 HashMap::new(),
128 canonicalized_url,
129 )?;
130 let url = format!("https://{}/{}", self.config().endpoint(), &request_uri);
131
132 if let Some(wh) = with_headers {
133 headers.extend(wh);
134 }
135
136 let mut req = self.http_client.request(method, url).headers(headers);
137
138 if let Some(body) = body {
139 req = req.body(body);
140 }
141 let res = req.send().await?;
142 Ok(res)
143 }
144}
145
146#[derive(Debug)]
147pub struct ClientBuilder {
148 config: Config,
149}
150
151impl Default for ClientBuilder {
152 fn default() -> Self {
153 Self::new()
154 }
155}
156
157impl ClientBuilder {
158 fn new() -> ClientBuilder {
159 ClientBuilder {
160 config: Config {
161 security_providers: vec![],
162 endpoint: "".into(),
163 is_secure: false,
164 region: "".into(),
165 timeout: Duration::from_secs(3),
166 signature_type: SignatureType::V2,
167 },
168 }
169 }
170 pub fn signature_type(mut self, st: SignatureType) -> ClientBuilder {
171 self.config.set_signature_type(st);
172 self
173 }
174
175 pub fn security_providers(mut self, sps: Vec<SecurityHolder>) -> ClientBuilder {
176 self.config.set_security_providers(sps);
177 self
178 }
179
180 pub fn endpoint<S: ToString>(mut self, value: S) -> ClientBuilder {
186 let mut value = value.to_string();
187 if value.starts_with("https://") {
188 value = value.replace("https://", "");
189 } else if value.starts_with("http://") {
190 value = value.replace("http://", "");
191 }
192 self.config.set_endpoint(value);
193 self
194 }
195
196 pub fn security_provider<S: ToString>(mut self, ak: S, sk: S) -> ClientBuilder {
197 self.config.security_providers.push(SecurityHolder::new(
198 ak.to_string(),
199 sk.to_string(),
200 "".to_string(),
201 ));
202 self
203 }
204
205 pub fn timeout(mut self, duration: Duration) -> ClientBuilder {
206 self.config.set_timeout(duration);
207 self
208 }
209
210 pub fn region<S: ToString>(mut self, value: S) -> ClientBuilder {
211 self.config.set_region(value.to_string());
212 self
213 }
214
215 pub fn is_secure(mut self, value: bool) -> ClientBuilder {
216 self.config.set_is_secure(value);
217 self
218 }
219
220 pub fn build(self) -> Result<Client, ObsError> {
221 let req_client = reqwest::ClientBuilder::new()
222 .timeout(self.config.timeout())
223 .build();
224 Ok(Client {
225 config: self.config,
226 http_client: req_client?,
227 })
228 }
229}