1use crate::auth::AuthManager;
4use crate::config::HttpConfig;
5use crate::error::HttpError;
6use crate::model::types::AuthToken;
7use crate::rate_limit::{RateLimiter, categorize_endpoint};
8use reqwest::Client;
9use std::sync::Arc;
10use tokio::sync::Mutex;
11
12#[derive(Debug, Clone)]
14pub struct DeribitHttpClient {
15 client: Client,
17 config: Arc<HttpConfig>,
19 rate_limiter: RateLimiter,
21 auth_manager: Arc<Mutex<AuthManager>>,
23}
24
25impl DeribitHttpClient {
26 pub fn new() -> Self {
28 let config = HttpConfig::default();
29 Self::with_config(config)
30 }
31
32 pub fn with_config(config: HttpConfig) -> Self {
34 let opt_client = Client::builder()
35 .timeout(config.timeout)
36 .user_agent(&config.user_agent)
37 .build()
38 .map_err(|e| HttpError::NetworkError(e.to_string()))
39 .ok();
40
41 let client = if let Some(opt_client) = &opt_client {
42 opt_client.clone()
43 } else {
44 panic!("Failed to create HTTP client");
45 };
46
47 let auth_manager = AuthManager::new(client.clone(), config.clone());
48
49 Self {
50 client,
51 config: Arc::new(config),
52 rate_limiter: RateLimiter::new(),
53 auth_manager: Arc::new(Mutex::new(auth_manager)),
54 }
55 }
56
57 pub fn config(&self) -> &HttpConfig {
59 &self.config
60 }
61
62 pub fn base_url(&self) -> &str {
64 self.config.base_url.as_str()
65 }
66
67 pub fn http_client(&self) -> &Client {
69 &self.client
70 }
71
72 pub async fn make_request(&self, url: &str) -> Result<reqwest::Response, HttpError> {
74 let category = categorize_endpoint(url);
76
77 self.rate_limiter.wait_for_permission(category).await;
79
80 self.client
82 .get(url)
83 .send()
84 .await
85 .map_err(|e| HttpError::NetworkError(e.to_string()))
86 }
87
88 pub async fn make_authenticated_request(
90 &self,
91 url: &str,
92 ) -> Result<reqwest::Response, HttpError> {
93 let category = categorize_endpoint(url);
95
96 self.rate_limiter.wait_for_permission(category).await;
98
99 let mut auth_manager = self.auth_manager.lock().await;
101 let auth_header = auth_manager
102 .get_authorization_header()
103 .await
104 .ok_or_else(|| {
105 HttpError::AuthenticationFailed(
106 "No valid authentication token available.".to_string(),
107 )
108 })?;
109
110 tracing::debug!("Using authorization header: {}", auth_header);
112 drop(auth_manager);
113
114 self.client
116 .get(url)
117 .header("Authorization", auth_header)
118 .send()
119 .await
120 .map_err(|e| HttpError::NetworkError(e.to_string()))
121 }
122
123 pub async fn make_authenticated_post_request<T: serde::Serialize>(
125 &self,
126 url: &str,
127 body: &T,
128 ) -> Result<reqwest::Response, HttpError> {
129 let category = categorize_endpoint(url);
131
132 self.rate_limiter.wait_for_permission(category).await;
134
135 let mut auth_manager = self.auth_manager.lock().await;
137 let auth_header = auth_manager
138 .get_authorization_header()
139 .await
140 .ok_or_else(|| {
141 HttpError::AuthenticationFailed(
142 "No valid authentication token available.".to_string(),
143 )
144 })?;
145
146 tracing::debug!("Using authorization header: {}", auth_header);
148 drop(auth_manager);
149
150 self.client
152 .post(url)
153 .header("Authorization", auth_header)
154 .json(body)
155 .send()
156 .await
157 .map_err(|e| HttpError::NetworkError(e.to_string()))
158 }
159
160 pub fn rate_limiter(&self) -> &RateLimiter {
162 &self.rate_limiter
163 }
164
165 pub async fn exchange_token(
167 &self,
168 refresh_token: &str,
169 subject_id: u64,
170 scope: Option<&str>,
171 ) -> Result<AuthToken, HttpError> {
172 let mut url = format!(
173 "{}/public/exchange_token?refresh_token={}&subject_id={}",
174 self.config.base_url,
175 urlencoding::encode(refresh_token),
176 subject_id
177 );
178
179 if let Some(scope) = scope {
180 url.push_str(&format!("&scope={}", urlencoding::encode(scope)));
181 }
182
183 let response = self
184 .client
185 .get(&url)
186 .header("Content-Type", "application/json")
187 .send()
188 .await
189 .map_err(|e| HttpError::NetworkError(e.to_string()))?;
190
191 if !response.status().is_success() {
192 let error_text = response
193 .text()
194 .await
195 .unwrap_or_else(|_| "Unknown error".to_string());
196 return Err(HttpError::AuthenticationFailed(format!(
197 "Token exchange failed: {}",
198 error_text
199 )));
200 }
201
202 let json_response: serde_json::Value = response
204 .json()
205 .await
206 .map_err(|e| HttpError::InvalidResponse(e.to_string()))?;
207
208 if let Some(_error) = json_response.get("error") {
210 return Err(HttpError::AuthenticationFailed(format!(
211 "Token exchange failed: {}",
212 json_response
213 )));
214 }
215
216 let result = json_response
218 .get("result")
219 .ok_or_else(|| HttpError::InvalidResponse("No result in response".to_string()))?;
220
221 let token: AuthToken = serde_json::from_value(result.clone())
222 .map_err(|e| HttpError::InvalidResponse(format!("Failed to parse token: {}", e)))?;
223
224 let _auth_manager = self.auth_manager.lock().await;
226 let _expires_at =
227 std::time::SystemTime::now() + std::time::Duration::from_secs(token.expires_in);
228
229 self.auth_manager.lock().await.update_token(token.clone());
230
231 Ok(token)
232 }
233
234 pub async fn fork_token(
236 &self,
237 refresh_token: &str,
238 session_name: &str,
239 scope: Option<&str>,
240 ) -> Result<AuthToken, HttpError> {
241 let mut url = format!(
242 "{}/public/fork_token?refresh_token={}&session_name={}",
243 self.config.base_url,
244 urlencoding::encode(refresh_token),
245 urlencoding::encode(session_name)
246 );
247
248 if let Some(scope) = scope {
249 url.push_str(&format!("&scope={}", urlencoding::encode(scope)));
250 }
251
252 let response = self
253 .client
254 .get(&url)
255 .header("Content-Type", "application/json")
256 .send()
257 .await
258 .map_err(|e| HttpError::NetworkError(e.to_string()))?;
259
260 if !response.status().is_success() {
261 let error_text = response
262 .text()
263 .await
264 .unwrap_or_else(|_| "Unknown error".to_string());
265 return Err(HttpError::AuthenticationFailed(format!(
266 "Token fork failed: {}",
267 error_text
268 )));
269 }
270
271 let json_response: serde_json::Value = response
273 .json()
274 .await
275 .map_err(|e| HttpError::InvalidResponse(e.to_string()))?;
276
277 if let Some(_error) = json_response.get("error") {
279 return Err(HttpError::AuthenticationFailed(format!(
280 "Token fork failed: {}",
281 json_response
282 )));
283 }
284
285 let result = json_response
287 .get("result")
288 .ok_or_else(|| HttpError::InvalidResponse("No result in response".to_string()))?;
289
290 let token: AuthToken = serde_json::from_value(result.clone())
291 .map_err(|e| HttpError::InvalidResponse(format!("Failed to parse token: {}", e)))?;
292
293 self.auth_manager.lock().await.update_token(token.clone());
294
295 Ok(token)
296 }
297}
298
299impl Default for DeribitHttpClient {
300 fn default() -> Self {
301 Self::new()
302 }
303}