mirror of
https://github.com/NetworkCats/rustyip.git
synced 2026-11-13 16:17:46 +00:00
refactor: split models.rs into mmdb/api sub-modules with pub(crate) visibility
Split the 865-line models.rs into 3 focused files: - models/mod.rs: conversion logic, helpers, re-exports, tests - models/mmdb.rs: MMDB deserialization types (internal, pub(crate)) - models/api.rs: API serialization types (public) with From<MmdbProxy> impl Mmdb types are now pub(crate) since they are internal deserialization details that should not be part of the public API surface.
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
use serde::Serialize;
|
||||
|
||||
use super::mmdb::MmdbProxy;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct IpInfo {
|
||||
pub ip: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub city: Option<CityInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub continent: Option<ContinentInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub country: Option<CountryInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub location: Option<LocationInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub postal: Option<PostalInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub registered_country: Option<CountryInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub subdivisions: Option<Vec<SubdivisionInfo>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub asn: Option<AsnInfo>,
|
||||
pub proxy: ProxyInfo,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Names {
|
||||
#[serde(rename = "de", skip_serializing_if = "Option::is_none")]
|
||||
pub german: Option<String>,
|
||||
#[serde(rename = "en", skip_serializing_if = "Option::is_none")]
|
||||
pub english: Option<String>,
|
||||
#[serde(rename = "es", skip_serializing_if = "Option::is_none")]
|
||||
pub spanish: Option<String>,
|
||||
#[serde(rename = "fr", skip_serializing_if = "Option::is_none")]
|
||||
pub french: Option<String>,
|
||||
#[serde(rename = "ja", skip_serializing_if = "Option::is_none")]
|
||||
pub japanese: Option<String>,
|
||||
#[serde(rename = "pt-BR", skip_serializing_if = "Option::is_none")]
|
||||
pub brazilian_portuguese: Option<String>,
|
||||
#[serde(rename = "ru", skip_serializing_if = "Option::is_none")]
|
||||
pub russian: Option<String>,
|
||||
#[serde(rename = "zh-CN", skip_serializing_if = "Option::is_none")]
|
||||
pub simplified_chinese: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct CityInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub names: Option<Names>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ContinentInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub code: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub names: Option<Names>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct CountryInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub iso_code: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub names: Option<Names>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct LocationInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub accuracy_radius: Option<u16>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub latitude: Option<f64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub longitude: Option<f64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub metro_code: Option<u16>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub time_zone: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct PostalInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub code: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SubdivisionInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub iso_code: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub names: Option<Names>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct AsnInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub autonomous_system_number: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub autonomous_system_organization: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub as_domain: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ProxyInfo {
|
||||
pub is_proxy: bool,
|
||||
pub is_vpn: bool,
|
||||
pub is_tor: bool,
|
||||
pub is_hosting: bool,
|
||||
pub is_cdn: bool,
|
||||
pub is_school: bool,
|
||||
pub is_anonymous: bool,
|
||||
}
|
||||
|
||||
impl From<MmdbProxy> for ProxyInfo {
|
||||
fn from(p: MmdbProxy) -> Self {
|
||||
Self {
|
||||
is_proxy: p.is_proxy,
|
||||
is_vpn: p.is_vpn,
|
||||
is_tor: p.is_tor,
|
||||
is_hosting: p.is_hosting,
|
||||
is_cdn: p.is_cdn,
|
||||
is_school: p.is_school,
|
||||
is_anonymous: p.is_anonymous,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbRecord<'a> {
|
||||
#[serde(borrow, default)]
|
||||
pub city: MmdbCity<'a>,
|
||||
#[serde(default)]
|
||||
pub continent: MmdbContinent<'a>,
|
||||
#[serde(default)]
|
||||
pub country: MmdbCountry<'a>,
|
||||
#[serde(default)]
|
||||
pub location: MmdbLocation<'a>,
|
||||
#[serde(default)]
|
||||
pub postal: MmdbPostal<'a>,
|
||||
#[serde(default)]
|
||||
pub registered_country: MmdbCountry<'a>,
|
||||
#[serde(default)]
|
||||
pub subdivisions: Vec<MmdbSubdivision<'a>>,
|
||||
#[serde(default)]
|
||||
pub asn: MmdbAsn<'a>,
|
||||
#[serde(default)]
|
||||
pub proxy: MmdbProxy,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbCity<'a> {
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(borrow, default)]
|
||||
pub names: MmdbNames<'a>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbContinent<'a> {
|
||||
pub code: Option<&'a str>,
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(borrow, default)]
|
||||
pub names: MmdbNames<'a>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbCountry<'a> {
|
||||
pub geoname_id: Option<u32>,
|
||||
pub iso_code: Option<&'a str>,
|
||||
#[serde(borrow, default)]
|
||||
pub names: MmdbNames<'a>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbLocation<'a> {
|
||||
pub accuracy_radius: Option<u16>,
|
||||
pub latitude: Option<f64>,
|
||||
pub longitude: Option<f64>,
|
||||
pub metro_code: Option<u16>,
|
||||
pub time_zone: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbPostal<'a> {
|
||||
pub code: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbSubdivision<'a> {
|
||||
pub geoname_id: Option<u32>,
|
||||
pub iso_code: Option<&'a str>,
|
||||
#[serde(borrow, default)]
|
||||
pub names: MmdbNames<'a>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbAsn<'a> {
|
||||
pub autonomous_system_number: Option<u32>,
|
||||
pub autonomous_system_organization: Option<&'a str>,
|
||||
pub as_domain: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default, Clone, Copy)]
|
||||
pub struct MmdbProxy {
|
||||
#[serde(default)]
|
||||
pub is_proxy: bool,
|
||||
#[serde(default)]
|
||||
pub is_vpn: bool,
|
||||
#[serde(default)]
|
||||
pub is_tor: bool,
|
||||
#[serde(default)]
|
||||
pub is_hosting: bool,
|
||||
#[serde(default)]
|
||||
pub is_cdn: bool,
|
||||
#[serde(default)]
|
||||
pub is_school: bool,
|
||||
#[serde(default)]
|
||||
pub is_anonymous: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbNames<'a> {
|
||||
#[serde(rename = "de", default)]
|
||||
pub german: Option<&'a str>,
|
||||
#[serde(rename = "en", default)]
|
||||
pub english: Option<&'a str>,
|
||||
#[serde(rename = "es", default)]
|
||||
pub spanish: Option<&'a str>,
|
||||
#[serde(rename = "fr", default)]
|
||||
pub french: Option<&'a str>,
|
||||
#[serde(rename = "ja", default)]
|
||||
pub japanese: Option<&'a str>,
|
||||
#[serde(rename = "pt-BR", default)]
|
||||
pub brazilian_portuguese: Option<&'a str>,
|
||||
#[serde(rename = "ru", default)]
|
||||
pub russian: Option<&'a str>,
|
||||
#[serde(rename = "zh-CN", default)]
|
||||
pub simplified_chinese: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl MmdbNames<'_> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.english.is_none()
|
||||
&& self.german.is_none()
|
||||
&& self.spanish.is_none()
|
||||
&& self.french.is_none()
|
||||
&& self.japanese.is_none()
|
||||
&& self.brazilian_portuguese.is_none()
|
||||
&& self.russian.is_none()
|
||||
&& self.simplified_chinese.is_none()
|
||||
}
|
||||
}
|
||||
@@ -1,257 +1,14 @@
|
||||
//! Data models for MMDB deserialization and JSON API serialization.
|
||||
|
||||
pub mod api;
|
||||
pub mod mmdb;
|
||||
|
||||
use std::fmt::Write;
|
||||
use std::net::IpAddr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// --- Deserialization types (from MMDB) ---
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbRecord<'a> {
|
||||
#[serde(borrow, default)]
|
||||
pub city: MmdbCity<'a>,
|
||||
#[serde(default)]
|
||||
pub continent: MmdbContinent<'a>,
|
||||
#[serde(default)]
|
||||
pub country: MmdbCountry<'a>,
|
||||
#[serde(default)]
|
||||
pub location: MmdbLocation<'a>,
|
||||
#[serde(default)]
|
||||
pub postal: MmdbPostal<'a>,
|
||||
#[serde(default)]
|
||||
pub registered_country: MmdbCountry<'a>,
|
||||
#[serde(default)]
|
||||
pub subdivisions: Vec<MmdbSubdivision<'a>>,
|
||||
#[serde(default)]
|
||||
pub asn: MmdbAsn<'a>,
|
||||
#[serde(default)]
|
||||
pub proxy: MmdbProxy,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbCity<'a> {
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(borrow, default)]
|
||||
pub names: MmdbNames<'a>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbContinent<'a> {
|
||||
pub code: Option<&'a str>,
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(borrow, default)]
|
||||
pub names: MmdbNames<'a>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbCountry<'a> {
|
||||
pub geoname_id: Option<u32>,
|
||||
pub iso_code: Option<&'a str>,
|
||||
#[serde(borrow, default)]
|
||||
pub names: MmdbNames<'a>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbLocation<'a> {
|
||||
pub accuracy_radius: Option<u16>,
|
||||
pub latitude: Option<f64>,
|
||||
pub longitude: Option<f64>,
|
||||
pub metro_code: Option<u16>,
|
||||
pub time_zone: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbPostal<'a> {
|
||||
pub code: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbSubdivision<'a> {
|
||||
pub geoname_id: Option<u32>,
|
||||
pub iso_code: Option<&'a str>,
|
||||
#[serde(borrow, default)]
|
||||
pub names: MmdbNames<'a>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbAsn<'a> {
|
||||
pub autonomous_system_number: Option<u32>,
|
||||
pub autonomous_system_organization: Option<&'a str>,
|
||||
pub as_domain: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbProxy {
|
||||
#[serde(default)]
|
||||
pub is_proxy: bool,
|
||||
#[serde(default)]
|
||||
pub is_vpn: bool,
|
||||
#[serde(default)]
|
||||
pub is_tor: bool,
|
||||
#[serde(default)]
|
||||
pub is_hosting: bool,
|
||||
#[serde(default)]
|
||||
pub is_cdn: bool,
|
||||
#[serde(default)]
|
||||
pub is_school: bool,
|
||||
#[serde(default)]
|
||||
pub is_anonymous: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Default)]
|
||||
pub struct MmdbNames<'a> {
|
||||
#[serde(rename = "de", default)]
|
||||
pub german: Option<&'a str>,
|
||||
#[serde(rename = "en", default)]
|
||||
pub english: Option<&'a str>,
|
||||
#[serde(rename = "es", default)]
|
||||
pub spanish: Option<&'a str>,
|
||||
#[serde(rename = "fr", default)]
|
||||
pub french: Option<&'a str>,
|
||||
#[serde(rename = "ja", default)]
|
||||
pub japanese: Option<&'a str>,
|
||||
#[serde(rename = "pt-BR", default)]
|
||||
pub brazilian_portuguese: Option<&'a str>,
|
||||
#[serde(rename = "ru", default)]
|
||||
pub russian: Option<&'a str>,
|
||||
#[serde(rename = "zh-CN", default)]
|
||||
pub simplified_chinese: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl MmdbNames<'_> {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.english.is_none()
|
||||
&& self.german.is_none()
|
||||
&& self.spanish.is_none()
|
||||
&& self.french.is_none()
|
||||
&& self.japanese.is_none()
|
||||
&& self.brazilian_portuguese.is_none()
|
||||
&& self.russian.is_none()
|
||||
&& self.simplified_chinese.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
// --- Serialization types (API output) ---
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct IpInfo {
|
||||
pub ip: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub city: Option<CityInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub continent: Option<ContinentInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub country: Option<CountryInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub location: Option<LocationInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub postal: Option<PostalInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub registered_country: Option<CountryInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub subdivisions: Option<Vec<SubdivisionInfo>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub asn: Option<AsnInfo>,
|
||||
pub proxy: ProxyInfo,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Names {
|
||||
#[serde(rename = "de", skip_serializing_if = "Option::is_none")]
|
||||
pub german: Option<String>,
|
||||
#[serde(rename = "en", skip_serializing_if = "Option::is_none")]
|
||||
pub english: Option<String>,
|
||||
#[serde(rename = "es", skip_serializing_if = "Option::is_none")]
|
||||
pub spanish: Option<String>,
|
||||
#[serde(rename = "fr", skip_serializing_if = "Option::is_none")]
|
||||
pub french: Option<String>,
|
||||
#[serde(rename = "ja", skip_serializing_if = "Option::is_none")]
|
||||
pub japanese: Option<String>,
|
||||
#[serde(rename = "pt-BR", skip_serializing_if = "Option::is_none")]
|
||||
pub brazilian_portuguese: Option<String>,
|
||||
#[serde(rename = "ru", skip_serializing_if = "Option::is_none")]
|
||||
pub russian: Option<String>,
|
||||
#[serde(rename = "zh-CN", skip_serializing_if = "Option::is_none")]
|
||||
pub simplified_chinese: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct CityInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub names: Option<Names>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ContinentInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub code: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub names: Option<Names>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct CountryInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub iso_code: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub names: Option<Names>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct LocationInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub accuracy_radius: Option<u16>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub latitude: Option<f64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub longitude: Option<f64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub metro_code: Option<u16>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub time_zone: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct PostalInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub code: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SubdivisionInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub geoname_id: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub iso_code: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub names: Option<Names>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct AsnInfo {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub autonomous_system_number: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub autonomous_system_organization: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub as_domain: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ProxyInfo {
|
||||
pub is_proxy: bool,
|
||||
pub is_vpn: bool,
|
||||
pub is_tor: bool,
|
||||
pub is_hosting: bool,
|
||||
pub is_cdn: bool,
|
||||
pub is_school: bool,
|
||||
pub is_anonymous: bool,
|
||||
}
|
||||
pub use api::*;
|
||||
// Mmdb types are re-exported as pub(crate) since they are internal deserialization details.
|
||||
pub(crate) use mmdb::*;
|
||||
|
||||
// --- Conversion from MMDB record to API output ---
|
||||
|
||||
@@ -390,15 +147,7 @@ pub fn from_mmdb_record(ip: IpAddr, record: &MmdbRecord<'_>) -> IpInfo {
|
||||
None
|
||||
};
|
||||
|
||||
let proxy = ProxyInfo {
|
||||
is_proxy: record.proxy.is_proxy,
|
||||
is_vpn: record.proxy.is_vpn,
|
||||
is_tor: record.proxy.is_tor,
|
||||
is_hosting: record.proxy.is_hosting,
|
||||
is_cdn: record.proxy.is_cdn,
|
||||
is_school: record.proxy.is_school,
|
||||
is_anonymous: record.proxy.is_anonymous,
|
||||
};
|
||||
let proxy = ProxyInfo::from(record.proxy);
|
||||
|
||||
let mut ip_str = String::with_capacity(45);
|
||||
write!(ip_str, "{ip}").expect("IP address formatting cannot fail");
|
||||
Reference in New Issue
Block a user