Skip to main content

epp_client/host/
info.rs

1//! Types for EPP host info request
2
3use std::net::IpAddr;
4use std::str::FromStr;
5
6use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8
9use super::XMLNS;
10use crate::common::{HostAddr, NoExtension, ObjectStatus, StringValue};
11use crate::request::{Command, Transaction};
12
13impl<'a> Transaction<NoExtension> for HostInfo<'a> {}
14
15impl<'a> Command for HostInfo<'a> {
16    type Response = HostInfoResponse;
17    const COMMAND: &'static str = "info";
18}
19
20impl<'a> HostInfo<'a> {
21    pub fn new(name: &'a str) -> Self {
22        Self {
23            info: HostInfoRequestData {
24                xmlns: XMLNS,
25                name: name.into(),
26            },
27        }
28    }
29}
30
31// Request
32
33/// Type for data under the host &lt;info&gt; tag
34#[derive(Serialize, Debug)]
35pub struct HostInfoRequestData<'a> {
36    /// XML namespace for host commands
37    #[serde(rename = "xmlns:host")]
38    xmlns: &'a str,
39    /// The name of the host to be queried
40    #[serde(rename = "host:name")]
41    name: StringValue<'a>,
42}
43
44#[derive(Serialize, Debug)]
45/// Type for EPP XML &lt;info&gt; command for hosts
46pub struct HostInfo<'a> {
47    /// The instance holding the data for the host query
48    #[serde(rename = "host:info")]
49    info: HostInfoRequestData<'a>,
50}
51
52// Response
53
54/// Type that represents the &lt;infData&gt; tag for host info response
55#[derive(Deserialize, Debug)]
56pub struct HostInfoResponseData {
57    /// The host name
58    pub name: StringValue<'static>,
59    /// The host ROID
60    pub roid: StringValue<'static>,
61    /// The list of host statuses
62    #[serde(rename = "status")]
63    pub statuses: Vec<ObjectStatus<'static>>,
64    /// The list of host IP addresses
65    #[serde(rename = "addr", deserialize_with = "deserialize_host_addrs")]
66    pub addresses: Vec<IpAddr>,
67    /// The epp user to whom the host belongs
68    #[serde(rename = "clID")]
69    pub client_id: StringValue<'static>,
70    /// THe epp user that created the host
71    #[serde(rename = "crID")]
72    pub creator_id: StringValue<'static>,
73    /// The host creation date
74    #[serde(rename = "crDate")]
75    pub created_at: DateTime<Utc>,
76    /// The epp user that last updated the host
77    #[serde(rename = "upID")]
78    pub updater_id: Option<StringValue<'static>>,
79    /// The host last update date
80    #[serde(rename = "upDate")]
81    pub updated_at: Option<DateTime<Utc>>,
82    /// The host transfer date
83    #[serde(rename = "trDate")]
84    pub transferred_at: Option<DateTime<Utc>>,
85}
86
87fn deserialize_host_addrs<'de, D>(de: D) -> Result<Vec<IpAddr>, D::Error>
88where
89    D: serde::de::Deserializer<'de>,
90{
91    let addrs = Vec::<HostAddr<'static>>::deserialize(de)?;
92    addrs
93        .into_iter()
94        .map(|addr| IpAddr::from_str(&addr.address))
95        .collect::<Result<_, _>>()
96        .map_err(|e| serde::de::Error::custom(format!("{}", e)))
97}
98
99/// Type that represents the &lt;resData&gt; tag for host info response
100#[derive(Deserialize, Debug)]
101pub struct HostInfoResponse {
102    /// Data under the &lt;infData&gt; tag
103    #[serde(rename = "infData")]
104    pub info_data: HostInfoResponseData,
105}
106
107#[cfg(test)]
108mod tests {
109    use chrono::{TimeZone, Utc};
110
111    use super::{HostInfo, IpAddr};
112    use crate::response::ResultCode;
113    use crate::tests::{assert_serialized, response_from_file, CLTRID, SUCCESS_MSG, SVTRID};
114
115    #[test]
116    fn command() {
117        let object = HostInfo::new("ns1.eppdev-1.com");
118        assert_serialized("request/host/info.xml", &object);
119    }
120
121    #[test]
122    fn response() {
123        let object = response_from_file::<HostInfo>("response/host/info.xml");
124        let result = object.res_data().unwrap();
125
126        assert_eq!(object.result.code, ResultCode::CommandCompletedSuccessfully);
127        assert_eq!(object.result.message, SUCCESS_MSG.into());
128        assert_eq!(result.info_data.name, "host2.eppdev-1.com".into());
129        assert_eq!(result.info_data.roid, "UNDEF-ROID".into());
130        assert_eq!(result.info_data.statuses[0].status, "ok".to_string());
131        assert_eq!(
132            result.info_data.addresses[0],
133            IpAddr::from([29, 245, 122, 14])
134        );
135        assert_eq!(
136            result.info_data.addresses[1],
137            IpAddr::from([0x2404, 0x6800, 0x4001, 0x801, 0, 0, 0, 0x200e])
138        );
139        assert_eq!(result.info_data.client_id, "eppdev".into());
140        assert_eq!(result.info_data.creator_id, "creator".into());
141        assert_eq!(
142            result.info_data.created_at,
143            Utc.with_ymd_and_hms(2021, 7, 26, 5, 28, 55).unwrap()
144        );
145        assert_eq!(
146            *(result.info_data.updater_id.as_ref().unwrap()),
147            "creator".into()
148        );
149        assert_eq!(
150            result.info_data.updated_at,
151            Utc.with_ymd_and_hms(2021, 7, 26, 5, 28, 55).single()
152        );
153        assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID.into());
154        assert_eq!(object.tr_ids.server_tr_id, SVTRID.into());
155    }
156}