use std::time::{Duration, Instant};
use futures_util::StreamExt;
use reqwest::Client;
use crate::engine::models::Server;
const PROBE_TIMEOUT: Duration = Duration::from_secs(3);
const PROBE_CONCURRENCY: usize = 16;
pub async fn probe(client: &Client, server: &Server) -> Option<Duration> {
let started = Instant::now();
let response = tokio::time::timeout(
PROBE_TIMEOUT,
client
.get(&server.endpoints.ping)
.header(reqwest::header::CACHE_CONTROL, "no-cache")
.send(),
)
.await
.ok()?
.ok()?;
response.status().is_success().then(|| started.elapsed())
}
pub async fn filter_reachable(client: &Client, servers: Vec<Server>) -> Vec<Server> {
let mut healthy: Vec<(Duration, Server)> = futures_util::stream::iter(servers)
.map(|server| async move {
let latency = probe(client, &server).await;
latency.map(|latency| (latency, server))
})
.buffer_unordered(PROBE_CONCURRENCY)
.filter_map(std::future::ready)
.collect()
.await;
healthy.sort_by_key(|(latency, _)| *latency);
healthy
.into_iter()
.map(|(duration, mut server)| {
server.probe_ms = Some(duration.as_secs_f64() * 1000.0);
server
})
.collect()
}