use std::net::IpAddr;
use std::sync::OnceLock;
use super::geo::Table;
#[cfg(feature = "geo")]
static BUNDLED: &[u8] = include_bytes!("hosting.bin");
const PROVIDERS: [(&[u8; 2], &str); 20] = [
(b"AW", "AWS"),
(b"GC", "Google Cloud"),
(b"AZ", "Azure"),
(b"OR", "Oracle Cloud"),
(b"AL", "Alibaba Cloud"),
(b"TC", "Tencent Cloud"),
(b"HW", "Huawei Cloud"),
(b"DO", "DigitalOcean"),
(b"LI", "Linode"),
(b"VU", "Vultr"),
(b"OV", "OVHcloud"),
(b"HZ", "Hetzner"),
(b"CB", "Contabo"),
(b"SC", "Scaleway"),
(b"LW", "Leaseweb"),
(b"IO", "IONOS"),
(b"HG", "Hostinger"),
(b"IB", "IBM Cloud"),
(b"RS", "Rackspace"),
(b"DC", "other hosting"),
];
pub fn table() -> Option<&'static Table> {
static TABLE: OnceLock<Option<Table>> = OnceLock::new();
TABLE.get_or_init(bundled).as_ref()
}
#[cfg(feature = "geo")]
fn bundled() -> Option<Table> {
match Table::decode(BUNDLED) {
Ok(table) => Some(table),
Err(e) => {
eprintln!("traffic: built-in hosting table: {e}");
None
}
}
}
#[cfg(not(feature = "geo"))]
fn bundled() -> Option<Table> {
None
}
pub fn provider(ip: IpAddr) -> Option<&'static str> {
provider_in(table()?, ip)
}
#[doc(hidden)]
pub fn provider_in(table: &Table, ip: IpAddr) -> Option<&'static str> {
let code = table.country(ip)?;
Some(PROVIDERS.iter().find(|(c, _)| **c == code).map_or("other hosting", |(_, name)| name))
}