tencentcloud_sdk_rs/
client.rs1use reqwest::{header::HeaderMap, Client};
2use serde::{de::DeserializeOwned, Deserialize};
3
4use crate::encryption;
5
6pub struct ReqClient {
7 secret_id: String,
8 secret_key: String,
9 host: String,
10 service: String,
11 region: String,
12 version: String,
13 client: Client,
14}
15
16#[derive(Deserialize, Debug)]
18#[serde(rename_all = "PascalCase")]
19pub struct TcResponse<T> {
20 pub response: T,
21}
22
23impl ReqClient {
24 pub fn new(secret_id: String, secret_key: String, host: String, service: String) -> Self {
25 let client = reqwest::Client::new();
26 return Self {
27 secret_id,
28 secret_key,
29 client,
30 host,
31 service,
32 region: "".to_string(),
33 version: "2021-03-23".to_string(),
34 };
35 }
36
37 pub async fn send<T, R>(
38 &self,
39 action: String,
40 payload: T,
41 ) -> Result<TcResponse<R>, Box<dyn std::error::Error>>
42 where
43 T: serde::ser::Serialize,
44 R: DeserializeOwned,
45 {
46 let now = chrono::Utc::now();
47
48 let payload = serde_json::to_string(&payload)?;
49 let timestamp = now.timestamp();
50 let date = now.format("%Y-%m-%d").to_string();
51
52 let authorization = self.make_post_authorization(timestamp, date, &payload)?;
54
55 let mut headers = HeaderMap::new();
57 headers.insert("Authorization", authorization.parse()?);
58 headers.insert("Content-Type", "application/json; charset=utf-8".parse()?);
59 headers.insert("Host", self.host.parse()?);
60 headers.insert("X-TC-Action", action.parse()?);
61 headers.insert("X-TC-Timestamp", timestamp.to_string().parse()?);
62 headers.insert("X-TC-Version", self.version.parse()?);
63 headers.insert("X-TC-Region", self.region.parse()?);
64
65 let url = format!("https://{}", self.host);
66 let res = self
67 .client
68 .post(&url)
69 .headers(headers)
70 .body(payload)
71 .send()
72 .await?;
73 let json_resp = res.json::<TcResponse<R>>().await?;
74 Ok(json_resp)
75 }
76
77 fn make_post_authorization(
78 &self,
79 timestamp: i64,
80 date: String,
81 payload: &str,
82 ) -> Result<String, Box<dyn std::error::Error>> {
83 let httprequest_method = "POST";
85 let canonical_uri = "/";
86 let canonical_query_string = "";
87 let canonical_headers = format!(
88 "content-type:application/json; charset=utf-8\nhost:{}\n",
89 self.host
90 );
91 let signed_headers = "content-type;host";
92 let hashed_request_payload = sha256::digest(payload);
94
95 let canonical_request = format!(
96 "{}\n{}\n{}\n{}\n{}\n{}",
97 httprequest_method,
98 canonical_uri,
99 canonical_query_string,
100 canonical_headers,
101 signed_headers,
102 hashed_request_payload
103 );
104 let algorithm = "TC3-HMAC-SHA256";
109
110 let credential_scope = format!("{}/{}/tc3_request", date, self.service);
111 let hashed_canonical_request = sha256::digest(canonical_request);
112
113 let string_to_sign = format!(
114 "{}\n{}\n{}\n{}",
115 algorithm, timestamp, credential_scope, hashed_canonical_request
116 );
117 let secret_date = encryption::hmac_sha256(
121 &date.as_bytes(),
122 format!("TC3{}", self.secret_key).as_str().as_bytes(),
123 );
124 let secret_service = encryption::hmac_sha256(&self.service.as_bytes(), &secret_date);
125 let secret_signing = encryption::hmac_sha256("tc3_request".as_bytes(), &secret_service);
126
127 let signature = encryption::hmac_sha256_hex(&string_to_sign.as_bytes(), &secret_signing);
128
129 let authorization = format!(
131 "TC3-HMAC-SHA256 Credential={}/{},SignedHeaders={},Signature={}",
132 self.secret_id, credential_scope, signed_headers, signature
133 );
134 Ok(authorization)
135 }
136}