Files
LowderPlay_cheburcheck/querying/src/geoip.rs
T
dependabot[bot]andLowder 2c0345a0e5 chore(deps): bump maxminddb from 0.26.0 to 0.27.3 (#45)
* chore(deps): bump maxminddb from 0.26.0 to 0.27.3

Bumps [maxminddb](https://github.com/oschwald/maxminddb-rust) from 0.26.0 to 0.27.3.
- [Release notes](https://github.com/oschwald/maxminddb-rust/releases)
- [Changelog](https://github.com/oschwald/maxminddb-rust/blob/main/CHANGELOG.md)
- [Commits](https://github.com/oschwald/maxminddb-rust/compare/0.26.0...v0.27.3)

---
updated-dependencies:
- dependency-name: maxminddb
  dependency-version: 0.27.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: implement new version

* chore: cleanup imports

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Lowder <me@lowderplay.dev>
2026-04-08 15:55:40 +05:00

121 lines
3.8 KiB
Rust

use crate::updater::{fetch_db, Updatable};
use async_trait::async_trait;
use maxminddb::geoip2::{City, Country};
use maxminddb::{geoip2, MaxMindDbError};
use serde::Serialize;
use std::io::Error;
use std::net::IpAddr;
use std::io;
pub struct GeoIp {
asn: Option<maxminddb::Reader<Vec<u8>>>,
city: Option<maxminddb::Reader<Vec<u8>>>,
country: Option<maxminddb::Reader<Vec<u8>>>,
}
#[derive(Serialize, Debug, Clone)]
pub struct IpInfo {
pub asn: Option<String>,
pub country_code: Option<String>,
pub organisation: Option<String>,
pub city_geo_name_id: Option<u32>,
location: String,
}
impl Default for IpInfo {
fn default() -> IpInfo {
IpInfo {
asn: None,
country_code: None,
organisation: None,
city_geo_name_id: None,
location: "-".to_string(),
}
}
}
impl GeoIp {
pub fn new() -> Self {
GeoIp {
asn: None,
country: None,
city: None
}
}
pub fn load(asn: Vec<u8>, country: Vec<u8>, city: Vec<u8>) -> Result<Self, MaxMindDbError> {
let mut geoip = Self::new();
geoip.update(asn, country, city)?;
Ok(geoip)
}
pub fn update(&mut self, asn: Vec<u8>, country: Vec<u8>, city: Vec<u8>) -> Result<(), MaxMindDbError> {
self.asn = Some(maxminddb::Reader::from_source(asn)?);
self.country = Some(maxminddb::Reader::from_source(country)?);
self.city = Some(maxminddb::Reader::from_source(city)?);
Ok(())
}
pub fn lookup(&self, ip: IpAddr) -> Result<IpInfo, MaxMindDbError> {
let asn = if let Some(db) = &self.asn {
db.lookup(ip)?.decode::<geoip2::Asn>()?
} else { None };
let city = if let Some(db) = &self.city {
db.lookup(ip)?.decode::<City>()?
} else { None };
let country = if let Some(db) = &self.country {
db.lookup(ip)?.decode::<Country>()?
} else { None };
let country_code = country.as_ref()
.map(|c| c.country.iso_code)
.flatten()
.map(|c| c.to_string());
let city_geo_name_id = city.as_ref()
.map(|c| c.city.geoname_id)
.flatten();
let mut location = (None, None);
if let Some(city) = city {
location.0 = city.city.names.russian.or(city.city.names.english);
}
if let Some(country) = country {
location.1 = country.country.names.russian.or(country.country.names.english);
}
let location = match location {
(Some(city), Some(country)) => format!("{}, {}", city, country),
(Some(city), None) => city.to_string(),
(None, Some(country)) => country.to_string(),
(None, None) => "-".to_string(),
};
Ok(IpInfo {
location,
country_code,
city_geo_name_id,
asn: asn.clone().and_then(|asn| asn.autonomous_system_number)
.map(|asn| format!("AS{}", asn)),
organisation: asn.and_then(|asn| asn.autonomous_system_organization)
.map(|org| org.to_string()),
})
}
}
#[async_trait]
impl Updatable for GeoIp {
type Base = (Vec<u8>, Vec<u8>, Vec<u8>);
async fn download() -> Result<Self::Base, Error> {
Ok((fetch_db(Self::get_url("GEO_ASN", "https://git.io/GeoLite2-ASN.mmdb")).await?,
fetch_db(Self::get_url("GEO_COUNTRY", "https://git.io/GeoLite2-Country.mmdb")).await?,
fetch_db(Self::get_url("GEO_CITY", "https://git.io/GeoLite2-City.mmdb")).await?))
}
async fn install(&mut self, (asn, country, city): Self::Base) -> Result<(), Error> {
self.update(asn, country, city)
.map_err(|e| Error::new(io::ErrorKind::Other, e))
}
}