use polyoxide_core::HttpClient;
use serde::{Deserialize, Serialize};
use std::time::{Duration, Instant};
use crate::{
error::ClobError,
request::{AuthMode, Request},
};
#[derive(Clone)]
pub struct Health {
pub(crate) http_client: HttpClient,
pub(crate) chain_id: u64,
}
impl Health {
pub async fn ping(&self) -> Result<Duration, ClobError> {
let start = Instant::now();
let response = self
.http_client
.client
.get(self.http_client.base_url.clone())
.send()
.await?;
let latency = start.elapsed();
if !response.status().is_success() {
return Err(ClobError::from_response(response).await);
}
Ok(latency)
}
pub fn server_time(&self) -> Request<ServerTimeResponse> {
Request::get(
self.http_client.clone(),
"/time",
AuthMode::None,
self.chain_id,
)
}
}
#[derive(Debug, Clone, Serialize)]
pub struct ServerTimeResponse {
pub time: i64,
}
impl<'de> Deserialize<'de> for ServerTimeResponse {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let time = i64::deserialize(deserializer)?;
Ok(ServerTimeResponse { time })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn server_time_response_deserializes() {
let json = "1700000000";
let resp: ServerTimeResponse = serde_json::from_str(json).unwrap();
assert_eq!(resp.time, 1700000000);
}
#[test]
fn server_time_response_rejects_json_object() {
let json = r#"{"time": 1700000000}"#;
assert!(serde_json::from_str::<ServerTimeResponse>(json).is_err());
}
#[test]
fn server_time_response_rejects_string() {
let json = r#""1700000000""#;
assert!(serde_json::from_str::<ServerTimeResponse>(json).is_err());
}
}