use std::sync::OnceLock;
use std::time::Duration;
use serde::de::DeserializeOwned;
use ureq::config::{Config, IpFamily};
use ureq::Agent;
fn agent() -> &'static Agent {
static AGENT: OnceLock<Agent> = OnceLock::new();
AGENT.get_or_init(|| build_agent(IpFamily::Any))
}
fn ipv6_agent() -> &'static Agent {
static AGENT: OnceLock<Agent> = OnceLock::new();
AGENT.get_or_init(|| build_agent(IpFamily::Ipv6Only))
}
fn build_agent(family: IpFamily) -> Agent {
Config::builder()
.max_redirects(0)
.ip_family(family)
.build()
.new_agent()
}
#[must_use]
pub fn get_text(url: &str, timeout: Duration) -> Option<String> {
let mut response = agent()
.get(url)
.config()
.timeout_global(Some(timeout))
.build()
.call()
.ok()?;
if !response.status().is_success() {
return None;
}
response.body_mut().read_to_string().ok()
}
#[must_use]
pub fn get_json<T: DeserializeOwned>(url: &str, timeout: Duration) -> Option<T> {
let mut response = agent()
.get(url)
.config()
.timeout_global(Some(timeout))
.build()
.call()
.ok()?;
if !response.status().is_success() {
return None;
}
response.body_mut().read_json::<T>().ok()
}
#[must_use]
pub fn probe_ipv6(url: &str, timeout: Duration) -> bool {
let Ok(response) = ipv6_agent()
.get(url)
.config()
.timeout_global(Some(timeout))
.build()
.call()
else {
return false;
};
response.status().is_success()
}