Replace HostAddr with IpAddr in the public interface

This commit is contained in:
Dirkjan Ochtman 2022-02-10 22:15:05 +01:00
parent 95b62891c9
commit 29b7db7530
7 changed files with 108 additions and 55 deletions

View File

@ -1,7 +1,8 @@
//! Common data types included in EPP Requests and Responses //! Common data types included in EPP Requests and Responses
use std::{borrow::Cow, fmt::Display}; use std::{borrow::Cow, fmt::Display, net::IpAddr};
use serde::ser::SerializeSeq;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::request::Extension; use crate::request::Extension;
@ -148,37 +149,42 @@ pub struct Services<'a> {
/// The &lt;hostAddr&gt; types domain or host transactions /// The &lt;hostAddr&gt; types domain or host transactions
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct HostAddr<'a> { pub(crate) struct HostAddr<'a> {
#[serde(rename = "ip")] #[serde(rename = "ip")]
pub ip_version: Option<Cow<'a, str>>, pub ip_version: Option<Cow<'a, str>>,
#[serde(rename = "$value")] #[serde(rename = "$value")]
pub address: Cow<'a, str>, pub address: Cow<'a, str>,
} }
impl<'a> HostAddr<'a> { impl From<&IpAddr> for HostAddr<'static> {
/// Creates a 'v4' type HostAddr (mostly useful when you don't want to include an 'ip' attr in the XML) fn from(addr: &IpAddr) -> Self {
pub fn new(ip_version: &'a str, address: &'a str) -> Self {
Self { Self {
ip_version: Some(ip_version.into()), ip_version: Some(match addr {
address: address.into(), IpAddr::V4(_) => "v4".into(),
IpAddr::V6(_) => "v6".into(),
}),
address: addr.to_string().into(),
} }
} }
}
/// Creates a 'v4' type HostAddr pub(crate) fn serialize_host_addrs_option<T: AsRef<[IpAddr]>, S>(
pub fn new_v4(address: &'a str) -> HostAddr { addrs: &Option<T>,
HostAddr { ser: S,
ip_version: Some("v4".into()), ) -> Result<S::Ok, S::Error>
address: address.into(), where
} S: serde::ser::Serializer,
} {
let addrs = match addrs {
Some(addrs) => addrs.as_ref(),
None => return ser.serialize_none(),
};
/// Creates a 'v6' type HostAddr let mut seq = ser.serialize_seq(Some(addrs.len()))?;
pub fn new_v6(address: &'a str) -> HostAddr { for addr in addrs {
HostAddr { seq.serialize_element(&HostAddr::from(addr))?;
ip_version: Some("v6".into()),
address: address.into(),
}
} }
seq.end()
} }
/// The &lt;status&gt; type on contact transactions /// The &lt;status&gt; type on contact transactions

View File

@ -1,8 +1,10 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::net::IpAddr;
use std::str::FromStr;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::common::{HostAddr, StringValue}; use crate::common::{serialize_host_addrs_option, HostAddr, StringValue};
use crate::Error; use crate::Error;
pub mod check; pub mod check;
@ -35,8 +37,34 @@ pub struct HostAttr<'a> {
#[serde(rename = "domain:hostName", alias = "hostName")] #[serde(rename = "domain:hostName", alias = "hostName")]
pub name: StringValue<'a>, pub name: StringValue<'a>,
/// The &lt;hostAddr&gt; tags /// The &lt;hostAddr&gt; tags
#[serde(rename = "domain:hostAddr", alias = "hostAddr")] #[serde(
pub addresses: Option<Vec<HostAddr<'a>>>, rename = "domain:hostAddr",
alias = "hostAddr",
serialize_with = "serialize_host_addrs_option",
deserialize_with = "deserialize_host_addrs_option"
)]
pub addresses: Option<Vec<IpAddr>>,
}
fn deserialize_host_addrs_option<'de, D>(de: D) -> Result<Option<Vec<IpAddr>>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let addrs = Option::<Vec<HostAddr<'static>>>::deserialize(de)?;
let addrs = match addrs {
Some(addrs) => addrs,
None => return Ok(None),
};
let result = addrs
.into_iter()
.map(|addr| IpAddr::from_str(&addr.address))
.collect::<Result<_, _>>();
match result {
Ok(addrs) => Ok(Some(addrs)),
Err(e) => Err(serde::de::Error::custom(format!("{}", e))),
}
} }
/// The list of &lt;hostAttr&gt; types for domain transactions. Typically under an &lt;ns&gt; tag /// The list of &lt;hostAttr&gt; types for domain transactions. Typically under an &lt;ns&gt; tag

View File

@ -104,11 +104,12 @@ pub struct DomainCreateResponse {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{DomainContact, DomainCreate, HostList, Period}; use super::{DomainContact, DomainCreate, HostList, Period};
use crate::common::{HostAddr, NoExtension}; use crate::common::NoExtension;
use crate::domain::{HostAttr, HostAttrList, HostObjList}; use crate::domain::{HostAttr, HostAttrList, HostObjList};
use crate::request::Transaction; use crate::request::Transaction;
use crate::response::ResultCode; use crate::response::ResultCode;
use crate::tests::{get_xml, CLTRID, SUCCESS_MSG, SVTRID}; use crate::tests::{get_xml, CLTRID, SUCCESS_MSG, SVTRID};
use std::net::IpAddr;
#[test] #[test]
fn command() { fn command() {
@ -208,8 +209,8 @@ mod tests {
HostAttr { HostAttr {
name: "ns2.eppdev-1.com".into(), name: "ns2.eppdev-1.com".into(),
addresses: Some(vec![ addresses: Some(vec![
HostAddr::new_v4("177.232.12.58"), IpAddr::from([177, 232, 12, 58]),
HostAddr::new_v6("2404:6800:4001:801::200e"), IpAddr::from([0x2404, 0x6800, 0x4001, 0x801, 0, 0, 0, 0x200e]),
]), ]),
}, },
]; ];

View File

@ -1,7 +1,9 @@
//! Types for EPP host create request //! Types for EPP host create request
use std::net::IpAddr;
use super::XMLNS; use super::XMLNS;
use crate::common::{HostAddr, NoExtension, StringValue}; use crate::common::{serialize_host_addrs_option, NoExtension, StringValue};
use crate::request::{Command, Transaction}; use crate::request::{Command, Transaction};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -13,7 +15,7 @@ impl<'a> Command for HostCreate<'a> {
} }
impl<'a> HostCreate<'a> { impl<'a> HostCreate<'a> {
pub fn new(host: &'a str, addresses: Option<&'a [HostAddr]>) -> Self { pub fn new(host: &'a str, addresses: Option<&'a [IpAddr]>) -> Self {
Self { Self {
host: HostCreateRequestData { host: HostCreateRequestData {
xmlns: XMLNS, xmlns: XMLNS,
@ -36,8 +38,8 @@ pub struct HostCreateRequestData<'a> {
#[serde(rename = "host:name")] #[serde(rename = "host:name")]
pub name: StringValue<'a>, pub name: StringValue<'a>,
/// The list of IP addresses for the host /// The list of IP addresses for the host
#[serde(rename = "host:addr")] #[serde(rename = "host:addr", serialize_with = "serialize_host_addrs_option")]
pub addresses: Option<&'a [HostAddr<'a>]>, pub addresses: Option<&'a [IpAddr]>,
} }
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
@ -70,8 +72,8 @@ pub struct HostCreateResponse {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::HostCreate; use super::{HostCreate, IpAddr};
use crate::common::{HostAddr, NoExtension}; use crate::common::NoExtension;
use crate::request::Transaction; use crate::request::Transaction;
use crate::response::ResultCode; use crate::response::ResultCode;
use crate::tests::{get_xml, CLTRID, SUCCESS_MSG, SVTRID}; use crate::tests::{get_xml, CLTRID, SUCCESS_MSG, SVTRID};
@ -81,8 +83,8 @@ mod tests {
let xml = get_xml("request/host/create.xml").unwrap(); let xml = get_xml("request/host/create.xml").unwrap();
let addresses = &[ let addresses = &[
HostAddr::new("v4", "29.245.122.14"), IpAddr::from([29, 245, 122, 14]),
HostAddr::new("v6", "2404:6800:4001:801::200e"), IpAddr::from([0x2404, 0x6800, 0x4001, 0x801, 0, 0, 0, 0x200e]),
]; ];
let object = HostCreate::new("host1.eppdev-1.com", Some(addresses)); let object = HostCreate::new("host1.eppdev-1.com", Some(addresses));

View File

@ -1,5 +1,8 @@
//! Types for EPP host info request //! Types for EPP host info request
use std::net::IpAddr;
use std::str::FromStr;
use super::XMLNS; use super::XMLNS;
use crate::common::{HostAddr, NoExtension, ObjectStatus, StringValue}; use crate::common::{HostAddr, NoExtension, ObjectStatus, StringValue};
use crate::request::{Command, Transaction}; use crate::request::{Command, Transaction};
@ -57,8 +60,8 @@ pub struct HostInfoResponseData {
#[serde(rename = "status")] #[serde(rename = "status")]
pub statuses: Vec<ObjectStatus<'static>>, pub statuses: Vec<ObjectStatus<'static>>,
/// The list of host IP addresses /// The list of host IP addresses
#[serde(rename = "addr")] #[serde(rename = "addr", deserialize_with = "deserialize_host_addrs")]
pub addresses: Vec<HostAddr<'static>>, pub addresses: Vec<IpAddr>,
/// The epp user to whom the host belongs /// The epp user to whom the host belongs
#[serde(rename = "clID")] #[serde(rename = "clID")]
pub client_id: StringValue<'static>, pub client_id: StringValue<'static>,
@ -79,6 +82,18 @@ pub struct HostInfoResponseData {
pub transferred_at: Option<StringValue<'static>>, pub transferred_at: Option<StringValue<'static>>,
} }
fn deserialize_host_addrs<'de, D>(de: D) -> Result<Vec<IpAddr>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let addrs = Vec::<HostAddr<'static>>::deserialize(de)?;
addrs
.into_iter()
.map(|addr| IpAddr::from_str(&addr.address))
.collect::<Result<_, _>>()
.map_err(|e| serde::de::Error::custom(format!("{}", e)))
}
/// Type that represents the &lt;resData&gt; tag for host info response /// Type that represents the &lt;resData&gt; tag for host info response
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct HostInfoResponse { pub struct HostInfoResponse {
@ -89,7 +104,7 @@ pub struct HostInfoResponse {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::HostInfo; use super::{HostInfo, IpAddr};
use crate::common::NoExtension; use crate::common::NoExtension;
use crate::request::Transaction; use crate::request::Transaction;
use crate::response::ResultCode; use crate::response::ResultCode;
@ -122,20 +137,12 @@ mod tests {
assert_eq!(result.info_data.roid, "UNDEF-ROID".into()); assert_eq!(result.info_data.roid, "UNDEF-ROID".into());
assert_eq!(result.info_data.statuses[0].status, "ok".to_string()); assert_eq!(result.info_data.statuses[0].status, "ok".to_string());
assert_eq!( assert_eq!(
*(result.info_data.addresses[0].ip_version.as_ref().unwrap()), result.info_data.addresses[0],
"v4".to_string() IpAddr::from([29, 245, 122, 14])
); );
assert_eq!( assert_eq!(
result.info_data.addresses[0].address, result.info_data.addresses[1],
"29.245.122.14".to_string() IpAddr::from([0x2404, 0x6800, 0x4001, 0x801, 0, 0, 0, 0x200e])
);
assert_eq!(
*(result.info_data.addresses[1].ip_version.as_ref().unwrap()),
"v6".to_string()
);
assert_eq!(
result.info_data.addresses[1].address,
"2404:6800:4001:0801:0000:0000:0000:200e".to_string()
); );
assert_eq!(result.info_data.client_id, "eppdev".into()); assert_eq!(result.info_data.client_id, "eppdev".into());
assert_eq!(result.info_data.creator_id, "creator".into()); assert_eq!(result.info_data.creator_id, "creator".into());

View File

@ -1,7 +1,9 @@
//! Types for EPP host update request //! Types for EPP host update request
use std::net::IpAddr;
use super::XMLNS; use super::XMLNS;
use crate::common::{HostAddr, NoExtension, ObjectStatus, StringValue}; use crate::common::{serialize_host_addrs_option, NoExtension, ObjectStatus, StringValue};
use crate::request::{Command, Transaction}; use crate::request::{Command, Transaction};
use serde::Serialize; use serde::Serialize;
@ -53,8 +55,8 @@ pub struct HostChangeInfo<'a> {
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
pub struct HostAddRemove<'a> { pub struct HostAddRemove<'a> {
/// The IP addresses to be added to or removed from the host /// The IP addresses to be added to or removed from the host
#[serde(rename = "host:addr")] #[serde(rename = "host:addr", serialize_with = "serialize_host_addrs_option")]
pub addresses: Option<&'a [HostAddr<'a>]>, pub addresses: Option<&'a [IpAddr]>,
/// The statuses to be added to or removed from the host /// The statuses to be added to or removed from the host
#[serde(rename = "host:status")] #[serde(rename = "host:status")]
pub statuses: Option<&'a [ObjectStatus<'a>]>, pub statuses: Option<&'a [ObjectStatus<'a>]>,
@ -90,8 +92,9 @@ pub struct HostUpdate<'a> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::IpAddr;
use super::{HostAddRemove, HostChangeInfo, HostUpdate}; use super::{HostAddRemove, HostChangeInfo, HostUpdate};
use crate::common::{HostAddr, NoExtension, ObjectStatus}; use crate::common::{NoExtension, ObjectStatus};
use crate::request::Transaction; use crate::request::Transaction;
use crate::response::ResultCode; use crate::response::ResultCode;
use crate::tests::{get_xml, CLTRID, SUCCESS_MSG, SVTRID}; use crate::tests::{get_xml, CLTRID, SUCCESS_MSG, SVTRID};
@ -100,7 +103,9 @@ mod tests {
fn command() { fn command() {
let xml = get_xml("request/host/update.xml").unwrap(); let xml = get_xml("request/host/update.xml").unwrap();
let addr = &[HostAddr::new("v6", "2404:6800:4001:801::200e")]; let addr = &[IpAddr::from([
0x2404, 0x6800, 0x4001, 0x801, 0, 0, 0, 0x200e,
])];
let add = HostAddRemove { let add = HostAddRemove {
addresses: Some(addr), addresses: Some(addr),

View File

@ -55,6 +55,7 @@ mod tests {
use crate::request::Transaction; use crate::request::Transaction;
use crate::response::ResultCode; use crate::response::ResultCode;
use crate::tests::{get_xml, CLTRID, SVTRID}; use crate::tests::{get_xml, CLTRID, SVTRID};
use std::net::IpAddr;
#[test] #[test]
fn command() { fn command() {
@ -142,7 +143,10 @@ mod tests {
assert_eq!(host.roid, "1234".into()); assert_eq!(host.roid, "1234".into());
assert!(host.statuses.iter().any(|s| s.status == "ok")); assert!(host.statuses.iter().any(|s| s.status == "ok"));
assert!(host.addresses.iter().any(|a| a.address == *"1.1.1.1")); assert!(host
.addresses
.iter()
.any(|a| a == &IpAddr::from([1, 1, 1, 1])));
assert_eq!(host.client_id, "1234".into()); assert_eq!(host.client_id, "1234".into());
assert_eq!(host.creator_id, "user".into()); assert_eq!(host.creator_id, "user".into());
assert_eq!(host.created_at, "2021-12-01T22:40:48Z".into()); assert_eq!(host.created_at, "2021-12-01T22:40:48Z".into());