df_hyperliquid_core/client/native/
mod.rs1pub mod socket;
18
19use crate::client::{Client, Http, Method, Request, Response, TransportError};
20use std::sync::Arc;
21use std::time::{Duration, SystemTime, UNIX_EPOCH};
22
23pub use socket::Feed;
24
25pub const TIMEOUT: Duration = Duration::from_secs(30);
28
29#[derive(Debug, Clone)]
31pub struct Native {
32 client: reqwest::Client,
33}
34
35impl Native {
36 #[must_use]
38 pub fn new() -> Self {
39 Native::with_timeout(TIMEOUT)
40 }
41
42 #[must_use]
46 pub fn with_timeout(timeout: Duration) -> Self {
47 let client = reqwest::Client::builder().timeout(timeout).build().unwrap_or_else(|_| reqwest::Client::new());
48 Native { client }
49 }
50
51 #[must_use]
53 pub const fn with_client(client: reqwest::Client) -> Self {
54 Native { client }
55 }
56}
57
58impl Default for Native {
59 fn default() -> Self {
60 Native::new()
61 }
62}
63
64impl Http for Native {
65 async fn send(&self, request: Request) -> Result<Response, TransportError> {
66 request.refuse_if_offline()?;
67 let unreachable = |error: reqwest::Error| TransportError::Unreachable(error.without_url().to_string());
68 let mut outgoing = self.client.request(method(request.method), &request.url);
69 for (name, value) in &request.headers {
70 outgoing = outgoing.header(name, value);
71 }
72 if !request.body.is_empty() {
73 outgoing = outgoing.body(request.body);
74 }
75 let answer = outgoing.send().await.map_err(unreachable)?;
76 let status = answer.status().as_u16();
77 let headers = answer
78 .headers()
79 .iter()
80 .map(|(name, value)| (name.as_str().to_owned(), String::from_utf8_lossy(value.as_bytes()).into_owned()))
81 .collect();
82 let body = answer.bytes().await.map_err(unreachable)?.to_vec();
83 Ok(Response { status, headers, body })
84 }
85}
86
87fn method(method: Method) -> reqwest::Method {
88 match method {
89 Method::Get => reqwest::Method::GET,
90 Method::Post => reqwest::Method::POST,
91 }
92}
93
94pub const KEEP_WARM: Duration = Duration::from_secs(30);
96
97pub fn keep_warm<S: Send + Sync + 'static>(
100 client: &Arc<Client<Native, S>>,
101 every: Duration,
102) -> tokio::task::JoinHandle<()> {
103 let held = Arc::downgrade(client);
104 tokio::spawn(async move {
105 let mut ticks = tokio::time::interval(every);
106 loop {
107 ticks.tick().await;
108 let Some(client) = held.upgrade() else {
109 return;
110 };
111 client.warm().await;
112 }
113 })
114}
115
116#[must_use]
119pub fn clock() -> u64 {
120 SystemTime::now().duration_since(UNIX_EPOCH).map_or(0, |since| u64::try_from(since.as_millis()).unwrap_or(u64::MAX))
121}
122
123#[cfg(test)]
124#[path = "tests/http.rs"]
125mod tests;