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