polyoxide_clob/api/
health.rs1use polyoxide_core::HttpClient;
2use serde::{Deserialize, Serialize};
3use std::time::{Duration, Instant};
4
5use crate::{
6 error::ClobError,
7 request::{AuthMode, Request},
8};
9
10#[derive(Clone)]
12pub struct Health {
13 pub(crate) http_client: HttpClient,
14 pub(crate) chain_id: u64,
15}
16
17impl Health {
18 pub async fn ping(&self) -> Result<Duration, ClobError> {
35 let start = Instant::now();
36 let response = self
37 .http_client
38 .client
39 .get(self.http_client.base_url.clone())
40 .send()
41 .await?;
42 let latency = start.elapsed();
43
44 if !response.status().is_success() {
45 return Err(ClobError::from_response(response).await);
46 }
47
48 Ok(latency)
49 }
50
51 pub fn server_time(&self) -> Request<ServerTimeResponse> {
53 Request::get(
54 self.http_client.clone(),
55 "/time",
56 AuthMode::None,
57 self.chain_id,
58 )
59 }
60}
61
62#[derive(Debug, Clone, Serialize)]
67pub struct ServerTimeResponse {
68 pub time: i64,
69}
70
71impl<'de> Deserialize<'de> for ServerTimeResponse {
72 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
73 where
74 D: serde::Deserializer<'de>,
75 {
76 let time = i64::deserialize(deserializer)?;
77 Ok(ServerTimeResponse { time })
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn server_time_response_deserializes() {
87 let json = "1700000000";
88 let resp: ServerTimeResponse = serde_json::from_str(json).unwrap();
89 assert_eq!(resp.time, 1700000000);
90 }
91
92 #[test]
93 fn server_time_response_rejects_json_object() {
94 let json = r#"{"time": 1700000000}"#;
95 assert!(serde_json::from_str::<ServerTimeResponse>(json).is_err());
96 }
97
98 #[test]
99 fn server_time_response_rejects_string() {
100 let json = r#""1700000000""#;
101 assert!(serde_json::from_str::<ServerTimeResponse>(json).is_err());
102 }
103}