bybit_rust_api/rest/
client.rs

1use crate::consts::{
2    API_REQUEST_KEY, RECV_WINDOW_KEY, SIGNATURE_KEY, SIGN_TYPE_KEY, TIMESTAMP_KEY,
3};
4use crate::rest::api_key_pair::ApiKeyPair;
5use crate::utils::{millis, sign};
6use reqwest::RequestBuilder;
7use serde::de::DeserializeOwned;
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Copy, PartialEq)]
11pub enum SecType {
12    None = 0,
13    Signed = 1,
14}
15
16pub struct RestClient {
17    api_key_pair: ApiKeyPair,
18    base_url: String,
19
20    http_client: reqwest::Client,
21    //ws_client: tungstenite::client::AutoStream,
22}
23
24#[derive(Serialize, Deserialize, Debug)]
25pub struct ServerResponse<T> {
26    #[serde(rename = "retCode")]
27    pub ret_code: i32,
28    #[serde(rename = "retMsg")]
29    pub ret_msg: String,
30    #[serde(rename = "result")]
31    pub result: T,
32    #[serde(rename = "retExtInfo")]
33    pub ret_ext_info: serde_json::Value,
34    #[serde(rename = "time")]
35    pub time: i64,
36}
37
38impl RestClient {
39    pub fn new(api_key_pair: ApiKeyPair, base_url: String) -> RestClient {
40        RestClient {
41            api_key_pair,
42            base_url,
43            http_client: reqwest::Client::new(),
44        }
45    }
46
47    fn query_string(&self, query: serde_json::Value) -> String {
48        serde_urlencoded::to_string(query.as_object().unwrap()).unwrap()
49    }
50
51    fn sign_request(
52        &self,
53        request_builder: RequestBuilder,
54        query_or_body_param: String,
55    ) -> RequestBuilder {
56        let recv_window = "5000";
57        let timestamp_str = millis().to_string();
58        let signature = sign(
59            &self.api_key_pair.secret(),
60            &format!(
61                "{}{}{}{}",
62                timestamp_str,
63                self.api_key_pair.key(),
64                recv_window,
65                query_or_body_param
66            ),
67        );
68
69        request_builder
70            .header(SIGN_TYPE_KEY, "2")
71            .header(API_REQUEST_KEY, self.api_key_pair.key())
72            .header(TIMESTAMP_KEY, timestamp_str)
73            .header(RECV_WINDOW_KEY, recv_window)
74            .header(SIGNATURE_KEY, signature)
75    }
76
77    pub async fn get<A: DeserializeOwned>(
78        &self,
79        endpoint: &str,
80        query: serde_json::Value,
81        sec_type: SecType,
82    ) -> Result<A, reqwest::Error> {
83        let mut url = format!("{}/{}", self.base_url, endpoint);
84        let query_string = self.query_string(query);
85
86        if !query_string.is_empty() {
87            url.push_str(&format!("?{}", query_string));
88        }
89
90        let mut request_builder = self.http_client.get(&url);
91        if sec_type == SecType::Signed {
92            request_builder = self.sign_request(request_builder, query_string);
93        }
94
95        println!("url: {}", url);
96
97        let r = request_builder.send().await?;
98        let server_response: A = r.json().await?;
99        Ok(server_response)
100    }
101
102    pub async fn post<A: DeserializeOwned>(
103        &self,
104        endpoint: &str,
105        body: serde_json::Value,
106        sec_type: SecType,
107    ) -> Result<A, reqwest::Error> {
108        let url = format!("{}/{}", self.base_url, endpoint);
109        let mut request_builder = self.http_client.post(&url);
110        if sec_type == SecType::Signed {
111            request_builder = self.sign_request(
112                request_builder,
113                serde_urlencoded::to_string(body.as_object().unwrap()).unwrap(),
114            );
115        }
116
117        let server_response = request_builder.json(&body).send().await?.json().await?;
118        Ok(server_response)
119    }
120}