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::rest::errors::{BybitResult, ErrorCodes};
6use crate::utils::{millis, sign, RateLimiter};
7use reqwest::RequestBuilder;
8use serde::de::DeserializeOwned;
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub enum SecType {
13 None = 0,
14 Signed = 1,
15}
16
17#[derive(Clone)]
18pub struct RestClient {
19 api_key_pair: ApiKeyPair,
20 base_url: String,
21
22 http_client: reqwest::Client,
23 recv_window: String,
24 rate_limiter: Option<RateLimiter>,
25}
26
27#[derive(Serialize, Deserialize, Debug, Clone)]
28pub struct ServerResponse<T> {
29 #[serde(rename = "retCode")]
30 pub ret_code: i32,
31 #[serde(rename = "retMsg")]
32 pub ret_msg: String,
33 #[serde(rename = "result")]
34 pub result: T,
35 #[serde(rename = "retExtInfo")]
36 pub ret_ext_info: serde_json::Value,
37 #[serde(rename = "time")]
38 pub time: i64,
39}
40
41#[derive(Serialize, Deserialize, Debug, Clone)]
42struct RawServerResponse {
43 #[serde(rename = "retCode")]
44 pub ret_code: i32,
45 #[serde(rename = "retMsg")]
46 pub ret_msg: String,
47 #[serde(rename = "result")]
48 pub result: serde_json::Value,
49 #[serde(rename = "retExtInfo")]
50 pub ret_ext_info: serde_json::Value,
51 #[serde(rename = "time")]
52 pub time: i64,
53}
54
55impl RestClient {
56 pub fn new(api_key_pair: ApiKeyPair, base_url: String) -> RestClient {
57 RestClient {
58 api_key_pair,
59 base_url,
60 http_client: reqwest::Client::new(),
61 recv_window: "5000".to_string(),
62 rate_limiter: None,
63 }
64 }
65
66 pub fn with_rate_limiter(mut self, limiter: RateLimiter) -> Self {
71 self.rate_limiter = Some(limiter);
72 self
73 }
74
75 pub fn with_recv_window(mut self, recv_window: impl Into<String>) -> Self {
76 self.recv_window = recv_window.into();
77 self
78 }
79
80 fn query_string(&self, query: serde_json::Value) -> BybitResult<String> {
81 let object = query.as_object().ok_or_else(|| {
82 crate::rest::errors::BybitError::Internal(
83 "Query params must be a JSON object".to_string(),
84 )
85 })?;
86 Ok(serde_urlencoded::to_string(object)?)
87 }
88
89 fn sign_request(
90 &self,
91 request_builder: RequestBuilder,
92 query_or_body_param: String,
93 ) -> RequestBuilder {
94 let recv_window = &self.recv_window;
95 let timestamp_str = millis().to_string();
96 let signature = sign(
97 self.api_key_pair.secret(),
98 &format!(
99 "{}{}{}{}",
100 timestamp_str,
101 self.api_key_pair.key(),
102 recv_window,
103 query_or_body_param
104 ),
105 );
106
107 request_builder
108 .header(SIGN_TYPE_KEY, "2")
109 .header(API_REQUEST_KEY, self.api_key_pair.key())
110 .header(TIMESTAMP_KEY, timestamp_str)
111 .header(RECV_WINDOW_KEY, recv_window)
112 .header(SIGNATURE_KEY, signature)
113 }
114
115 pub async fn get<A: DeserializeOwned>(
116 &self,
117 endpoint: &str,
118 query: serde_json::Value,
119 sec_type: SecType,
120 ) -> BybitResult<ServerResponse<A>> {
121 if let Some(ref limiter) = self.rate_limiter {
122 limiter.acquire().await;
123 }
124 let mut url = format!("{}/{}", self.base_url, endpoint);
125 let query_string = self.query_string(query)?;
126
127 if !query_string.is_empty() {
128 url.push_str(&format!("?{}", query_string));
129 }
130
131 let mut request_builder = self.http_client.get(&url);
132 if sec_type == SecType::Signed {
133 request_builder = self.sign_request(request_builder, query_string);
134 }
135
136 log::debug!("url: {}", url);
137
138 let r = request_builder.send().await?;
139 let raw_response: RawServerResponse = r.json().await?;
140
141 if raw_response.ret_code != 0 {
142 let code_str = raw_response.ret_code.to_string();
143 if let Ok(error_code) = serde_json::from_value(serde_json::json!(code_str)) {
145 return Err(crate::rest::errors::BybitError::Api(error_code));
146 } else {
147 return Err(crate::rest::errors::BybitError::Api(
148 crate::rest::errors::ErrorCodes::E10001,
149 )); }
151 }
152
153 let result: A = serde_json::from_value(raw_response.result)?;
154 Ok(ServerResponse {
155 ret_code: raw_response.ret_code,
156 ret_msg: raw_response.ret_msg,
157 result,
158 ret_ext_info: raw_response.ret_ext_info,
159 time: raw_response.time,
160 })
161 }
162
163 pub async fn post<A: DeserializeOwned>(
164 &self,
165 endpoint: &str,
166 body: serde_json::Value,
167 sec_type: SecType,
168 ) -> BybitResult<ServerResponse<A>> {
169 if let Some(ref limiter) = self.rate_limiter {
170 limiter.acquire().await;
171 }
172 let url = format!("{}/{}", self.base_url, endpoint);
173 let mut request_builder = self.http_client.post(&url);
174 if sec_type == SecType::Signed {
175 let body_str =
176 serde_json::to_string(&body).map_err(crate::rest::errors::BybitError::Json)?;
177 request_builder = self.sign_request(request_builder, body_str);
178 }
179
180 let r = request_builder.json(&body).send().await?;
181 let raw_response: RawServerResponse = r.json().await?;
182
183 if raw_response.ret_code != 0 {
184 let code_str = raw_response.ret_code.to_string();
185 if let Ok(error_code) = serde_json::from_value(serde_json::json!(code_str)) {
186 return Err(crate::rest::errors::BybitError::Api(error_code));
187 } else {
188 return Err(crate::rest::errors::BybitError::Api(ErrorCodes::E10001));
189 }
190 }
191
192 let result: A = serde_json::from_value(raw_response.result)?;
193 Ok(ServerResponse {
194 ret_code: raw_response.ret_code,
195 ret_msg: raw_response.ret_msg,
196 result,
197 ret_ext_info: raw_response.ret_ext_info,
198 time: raw_response.time,
199 })
200 }
201}