pub use chrono::FixedOffset;
use crate::{Request, RequestExt};
use serde::{Deserialize, Serialize};
use std::net::IpAddr;
pub fn geo_lookup(ip: IpAddr) -> Option<Geo> {
fn do_request(ip: IpAddr) -> Result<Option<Geo>, crate::Error> {
let mut resp = Request::builder()
.header("Fastly-XQD-API", "geolocation")
.header("Fastly-XQD-arg1", ip.to_string())
.uri("http://www.fastly.com/geolocation")
.body(())?
.send("geolocation")?;
let raw: Option<RawGeo> = serde_json::from_reader(resp.body_mut())?;
Ok(raw.map(Into::into))
}
do_request(ip).unwrap_or(None)
}
#[derive(Clone, Debug, Deserialize, Serialize)]
struct RawGeo {
as_name: String,
as_number: u32,
area_code: u16,
city: String,
conn_speed: ConnSpeed,
conn_type: ConnType,
continent: Continent,
country_code: String,
country_code3: String,
country_name: String,
latitude: f64,
longitude: f64,
metro_code: i64,
postal_code: String,
proxy_description: ProxyDescription,
proxy_type: ProxyType,
region: Option<String>,
utc_offset: i32,
}
#[derive(Clone, Debug)]
pub struct Geo {
as_name: String,
as_number: u32,
area_code: u16,
city: String,
conn_speed: ConnSpeed,
conn_type: ConnType,
continent: Continent,
country_code: String,
country_code3: String,
country_name: String,
latitude: f64,
longitude: f64,
metro_code: i64,
postal_code: String,
proxy_description: ProxyDescription,
proxy_type: ProxyType,
region: Option<String>,
utc_offset: FixedOffset,
}
impl From<RawGeo> for Geo {
fn from(raw: RawGeo) -> Self {
let hours = raw.utc_offset / 100;
let minutes = raw.utc_offset % 100;
let seconds = (hours * 60 * 60) + (minutes * 60);
let utc_offset = FixedOffset::east(seconds);
Geo {
as_name: raw.as_name,
as_number: raw.as_number,
area_code: raw.area_code,
city: raw.city,
conn_speed: raw.conn_speed,
conn_type: raw.conn_type,
continent: raw.continent,
country_code: raw.country_code,
country_code3: raw.country_code3,
country_name: raw.country_name,
latitude: raw.latitude,
longitude: raw.longitude,
metro_code: raw.metro_code,
postal_code: raw.postal_code,
proxy_description: raw.proxy_description,
proxy_type: raw.proxy_type,
region: raw.region,
utc_offset,
}
}
}
impl Geo {
pub fn as_name(&self) -> &str {
self.as_name.as_str()
}
pub fn as_number(&self) -> u32 {
self.as_number
}
pub fn area_code(&self) -> u16 {
self.area_code
}
pub fn city(&self) -> &str {
self.city.as_str()
}
pub fn conn_speed(&self) -> ConnSpeed {
self.conn_speed
}
pub fn conn_type(&self) -> ConnType {
self.conn_type
}
pub fn continent(&self) -> Continent {
self.continent
}
pub fn country_code(&self) -> &str {
self.country_code.as_str()
}
pub fn country_code3(&self) -> &str {
self.country_code3.as_str()
}
pub fn country_name(&self) -> &str {
self.country_name.as_str()
}
pub fn latitude(&self) -> f64 {
self.latitude
}
pub fn longitude(&self) -> f64 {
self.longitude
}
pub fn metro_code(&self) -> i64 {
self.metro_code
}
pub fn postal_code(&self) -> &str {
self.postal_code.as_str()
}
pub fn proxy_description(&self) -> ProxyDescription {
self.proxy_description
}
pub fn proxy_type(&self) -> ProxyType {
self.proxy_type
}
pub fn region(&self) -> Option<&str> {
self.region.as_ref().map(|s| s.as_str())
}
pub fn utc_offset(&self) -> FixedOffset {
self.utc_offset
}
}
#[serde(rename_all = "kebab-case")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum ConnSpeed {
Broadband,
Cable,
Dialup,
Mobile,
Oc12,
Oc3,
T1,
T3,
Satellite,
Wireless,
Xdsl,
}
#[serde(rename_all = "kebab-case")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum ConnType {
Wired,
Wifi,
Mobile,
Dialup,
Satellite,
#[serde(other)]
#[serde(rename = "?")]
Unknown,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum Continent {
#[serde(rename = "AF")]
Africa,
#[serde(rename = "AN")]
Antarctica,
#[serde(rename = "AS")]
Asia,
#[serde(rename = "EU")]
Europe,
#[serde(rename = "NA")]
NorthAmerica,
#[serde(rename = "OC")]
Oceania,
#[serde(rename = "SA")]
SouthAmerica,
}
#[serde(rename_all = "kebab-case")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum ProxyDescription {
Cloud,
CloudSecurity,
Dns,
TorExit,
TorRelay,
Vpn,
WebBrowser,
#[serde(other)]
#[serde(rename = "?")]
Unknown,
}
#[serde(rename_all = "kebab-case")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub enum ProxyType {
Anonymous,
Aol,
Blackberry,
Corporate,
Edu,
Hosting,
Public,
Transparent,
#[serde(other)]
#[serde(rename = "?")]
Unknown,
}