tencentcloud_sdk_rs/
client.rs

1use 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/// 通用基础响应
17#[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        // 计算临时认证
53        let authorization = self.make_post_authorization(timestamp, date, &payload)?;
54
55        // 配置请求头
56        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        /* first */
84        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 = encryption::sha256_hex(payload);
93        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        // println!("{}",canonical_request);
105
106        /* second */
107
108        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        // println!("{}", string_to_sign);
118        /* third */
119
120        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        /* forth */
130        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}