Rust:如何将 SocketAddr 转换为 IpNetwork?
Rust: how to convert SocketAddr to IpNetwork?
使用 Diesel 和 Rocket 我希望能够记录请求来自的 IP。 Here 是类似的讨论,但没有结论。 Diesel 将 Postgres inet
类型映射到 IpNetwork
,但 Rocket returns SocketAddr
来自请求数据。如何将SocketAddr
转换成IpNetwork
?
models.rs:
#![allow(proc_macro_derive_resolution_fallback)]
use crate::schema::bs_date_forecast;
use chrono::{NaiveDate, NaiveDateTime};
use ipnetwork::IpNetwork;
use diesel::prelude::*;
#[derive(Queryable, Insertable, Serialize, Deserialize)]
#[table_name="bs_date_forecast"]
pub struct BsDateForecast {
pub id: Option<i32>,
pub predicted_date: NaiveDate,
pub seer_ip: IpNetwork,
pub created_timestamp: NaiveDateTime, // Defined automatically at the database level
}
impl BsDateForecast {
pub fn create(forecast: BsDateForecast,
conn: &PgConnection) -> Vec<BsDateForecast> {
diesel::insert_into(bs_date_forecast::table)
.values(&forecast)
.get_results(conn)
.expect("Error creating record")
}
}
routes.rs:
#[post("/predictions", format = "application/json", data = "<prediction>")]
pub fn create(prediction: Json<BsDateForecast>,
conn: DbConn,
user_ip: SocketAddr) -> Json<Vec<BsDateForecast>> {
let insert = BsDateForecast{
id: None,
seer_ip: user_ip.to_string(), // How to get IpNetwork here???
..prediction.into_inner()
};
Json(BsDateForecast::create(insert, &conn))
}
INET类型可以存储子网(包括子网掩码)或单个主机。 IpNetwork 类型用于存储子网,但可以通过指定全长前缀以 Postgres 方式存储单个主机。
SocketAddr 是 IpAddr 加上端口号。
所以转换是:获取 SocketAddr 的 IP 部分,通过指定正确的前缀从中创建一个 IpNetwork。
这里的复杂之处在于 IP4 和 IP6 的前缀不同。
fn socket_addr_to_ip_network(socket_addr: &SocketAddr) -> IpNetwork {
let ip = socket_addr.ip();
IpNetwork::new(ip, single_host_prefix(ip))
.expect("single_host_prefix created invalid prefix")
}
fn single_host_prefix(ip_addr: &IpAddr) -> u8 {
match ip_addr { &IpAddr::V4(_) => 32, &IpAddr::V6(_) => 128 }
}
使用 Diesel 和 Rocket 我希望能够记录请求来自的 IP。 Here 是类似的讨论,但没有结论。 Diesel 将 Postgres inet
类型映射到 IpNetwork
,但 Rocket returns SocketAddr
来自请求数据。如何将SocketAddr
转换成IpNetwork
?
models.rs:
#![allow(proc_macro_derive_resolution_fallback)]
use crate::schema::bs_date_forecast;
use chrono::{NaiveDate, NaiveDateTime};
use ipnetwork::IpNetwork;
use diesel::prelude::*;
#[derive(Queryable, Insertable, Serialize, Deserialize)]
#[table_name="bs_date_forecast"]
pub struct BsDateForecast {
pub id: Option<i32>,
pub predicted_date: NaiveDate,
pub seer_ip: IpNetwork,
pub created_timestamp: NaiveDateTime, // Defined automatically at the database level
}
impl BsDateForecast {
pub fn create(forecast: BsDateForecast,
conn: &PgConnection) -> Vec<BsDateForecast> {
diesel::insert_into(bs_date_forecast::table)
.values(&forecast)
.get_results(conn)
.expect("Error creating record")
}
}
routes.rs:
#[post("/predictions", format = "application/json", data = "<prediction>")]
pub fn create(prediction: Json<BsDateForecast>,
conn: DbConn,
user_ip: SocketAddr) -> Json<Vec<BsDateForecast>> {
let insert = BsDateForecast{
id: None,
seer_ip: user_ip.to_string(), // How to get IpNetwork here???
..prediction.into_inner()
};
Json(BsDateForecast::create(insert, &conn))
}
INET类型可以存储子网(包括子网掩码)或单个主机。 IpNetwork 类型用于存储子网,但可以通过指定全长前缀以 Postgres 方式存储单个主机。
SocketAddr 是 IpAddr 加上端口号。
所以转换是:获取 SocketAddr 的 IP 部分,通过指定正确的前缀从中创建一个 IpNetwork。
这里的复杂之处在于 IP4 和 IP6 的前缀不同。
fn socket_addr_to_ip_network(socket_addr: &SocketAddr) -> IpNetwork {
let ip = socket_addr.ip();
IpNetwork::new(ip, single_host_prefix(ip))
.expect("single_host_prefix created invalid prefix")
}
fn single_host_prefix(ip_addr: &IpAddr) -> u8 {
match ip_addr { &IpAddr::V4(_) => 32, &IpAddr::V6(_) => 128 }
}