1use crate::acl::AclHeader;
3use crate::request::Response;
4use crate::signer::Signer;
5use chrono::Utc;
13use std::collections::HashMap;
14
15#[derive(Clone)]
16pub struct Client {
17 secrect_id: String,
18 secrect_key: String,
19 bucket: String,
20 region: String,
21}
22
23impl Client {
24 pub fn new(
25 secrect_id: impl Into<String>,
26 secrect_key: impl Into<String>,
27 bucket: impl Into<String>,
28 region: impl Into<String>,
29 ) -> Self {
30 Self {
31 secrect_id: secrect_id.into(),
32 secrect_key: secrect_key.into(),
33 bucket: bucket.into(),
34 region: region.into(),
35 }
36 }
37
38 pub fn get_host(&self) -> String {
39 format!("{}.cos.{}.myqcloud.com", self.bucket, self.region)
40 }
41
42 pub fn get_secrect_key(&self) -> &str {
43 &self.secrect_key
44 }
45 pub fn get_secrect_id(&self) -> &str {
46 &self.secrect_id
47 }
48
49 pub fn gen_common_headers(&self) -> HashMap<String, String> {
51 let mut headers = HashMap::new();
52 headers.insert("Host".to_string(), self.get_host());
53 let now_str = Utc::now().format("%a, %d %b %Y %T GMT").to_string();
54 headers.insert("Date".to_string(), now_str);
55 headers
56 }
57
58 pub fn get_full_url_from_path(&self, path: &str) -> String {
59 format!("https://{}{}", self.get_host(), path)
60 }
61
62 pub fn get_path_from_object_key(&self, key: &str) -> String {
63 let mut url_path = key.to_string();
64 if !url_path.starts_with('/') {
65 url_path = format!("/{}", url_path);
66 }
67 url_path
68 }
69 pub fn get_host_for_bucket_query(&self) -> String {
71 if self.region.is_empty() {
72 return "service.cos.myqcloud.com".to_string();
73 }
74 format!("cos.{}.myqcloud.com", self.region)
75 }
76
77 pub fn get_headers_with_auth(
80 &self,
81 method: &str,
82 url_path: &str,
83 acl_header: Option<&AclHeader>,
84 origin_headers: Option<HashMap<String, String>>,
85 query: Option<&HashMap<String, String>>,
86 ) -> HashMap<String, String> {
87 let mut headers;
88 if let Some(origin_headers) = origin_headers {
89 headers = origin_headers;
90 } else {
91 headers = self.gen_common_headers();
92 }
93 if let Some(acl_header) = acl_header {
94 for (k, v) in acl_header.get_headers() {
95 headers.insert(k.to_string(), v.to_string());
96 }
97 }
98 let signature = Signer::new(method, url_path, Some(&headers), query).get_signature(
99 self.get_secrect_key(),
100 self.get_secrect_id(),
101 7200,
102 );
103 headers.insert("Authorization".to_string(), signature);
104 headers
105 }
106
107 pub fn make_response(&self, resp: Result<Response, Response>) -> Response {
108 match resp {
109 Ok(e) => e,
110 Err(e) => e,
111 }
112 }
113
114 pub fn get_presigned_download_url(&self, object_key: &str, expire: u32) -> String {
117 let url_path = self.get_path_from_object_key(object_key);
118 let full_url = self.get_full_url_from_path(url_path.as_str());
119 let mut headers = HashMap::new();
120 headers.insert("host".to_string(), self.get_host());
121 let signature = Signer::new("get", &url_path, Some(&headers), None).get_signature(
122 self.get_secrect_key(),
123 self.get_secrect_id(),
124 expire,
125 );
126 format!("{url}?{signature}", url = full_url, signature = signature)
127 }
128}