use std::sync::Mutex;
use std::time::{Duration, Instant};
use reqwest::{Method, Response};
use crate::client::HttpClient;
use crate::error::ApiError;
use crate::hooks::{Authenticator, Cost, DynAuthenticator, RequestParts};
use crate::request::RequestError;
#[derive(Debug)]
#[non_exhaustive]
pub struct Pong {
pub round_trip: Duration,
pub response: Response,
}
#[derive(Default)]
struct Stopwatch(Mutex<Option<Instant>>);
impl Stopwatch {
fn elapsed(&self) -> Duration {
self.0
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
.map_or(Duration::ZERO, |sent| sent.elapsed())
}
}
impl Authenticator for Stopwatch {
async fn sign(&self, _parts: &mut RequestParts, _attempt: u32) -> Result<(), ApiError> {
*self
.0
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner()) = Some(Instant::now());
Ok(())
}
}
impl HttpClient {
pub async fn health<E: RequestError>(&self, path: &str, costs: &[Cost]) -> Result<Pong, E> {
let stopwatch = Stopwatch::default();
let response = self
.send(
RequestParts::new(Method::GET, path),
costs,
Some(DynAuthenticator::from_ref(&stopwatch)),
)
.await?;
let round_trip = stopwatch.elapsed();
if !response.status().is_success() {
return Err(ApiError::from_response(response).await.into());
}
Ok(Pong {
round_trip,
response,
})
}
}