Flatten XML abstraction
This commit is contained in:
parent
3f91647370
commit
ca19e545fd
|
@ -21,7 +21,7 @@ use crate::error::Error;
|
||||||
use crate::hello::{Greeting, GreetingDocument, HelloDocument};
|
use crate::hello::{Greeting, GreetingDocument, HelloDocument};
|
||||||
use crate::request::{Command, CommandDocument, Extension, Transaction};
|
use crate::request::{Command, CommandDocument, Extension, Transaction};
|
||||||
use crate::response::{Response, ResponseDocument, ResponseStatus};
|
use crate::response::{Response, ResponseDocument, ResponseStatus};
|
||||||
use crate::xml::EppXml;
|
use crate::xml;
|
||||||
|
|
||||||
/// An `EppClient` provides an interface to sending EPP requests to a registry
|
/// An `EppClient` provides an interface to sending EPP requests to a registry
|
||||||
///
|
///
|
||||||
|
@ -107,13 +107,13 @@ impl<C: Connector> EppClient<C> {
|
||||||
|
|
||||||
/// Executes an EPP Hello call and returns the response as a `Greeting`
|
/// Executes an EPP Hello call and returns the response as a `Greeting`
|
||||||
pub async fn hello(&mut self) -> Result<Greeting, Error> {
|
pub async fn hello(&mut self) -> Result<Greeting, Error> {
|
||||||
let hello_xml = HelloDocument::default().serialize()?;
|
let xml = xml::serialize(&HelloDocument::default())?;
|
||||||
|
|
||||||
debug!("{}: hello: {}", self.connection.registry, &hello_xml);
|
debug!("{}: hello: {}", self.connection.registry, &xml);
|
||||||
let response = self.connection.transact(&hello_xml)?.await?;
|
let response = self.connection.transact(&xml)?.await?;
|
||||||
debug!("{}: greeting: {}", self.connection.registry, &response);
|
debug!("{}: greeting: {}", self.connection.registry, &response);
|
||||||
|
|
||||||
Ok(GreetingDocument::deserialize(&response)?.data)
|
Ok(xml::deserialize::<GreetingDocument>(&response)?.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn transact<'c, 'e, Cmd, Ext>(
|
pub async fn transact<'c, 'e, Cmd, Ext>(
|
||||||
|
@ -127,14 +127,13 @@ impl<C: Connector> EppClient<C> {
|
||||||
{
|
{
|
||||||
let data = data.into();
|
let data = data.into();
|
||||||
let document = CommandDocument::new(data.command, data.extension, id);
|
let document = CommandDocument::new(data.command, data.extension, id);
|
||||||
let xml = document.serialize()?;
|
let xml = xml::serialize(&document)?;
|
||||||
|
|
||||||
debug!("{}: request: {}", self.connection.registry, &xml);
|
debug!("{}: request: {}", self.connection.registry, &xml);
|
||||||
let response = self.connection.transact(&xml)?.await?;
|
let response = self.connection.transact(&xml)?.await?;
|
||||||
debug!("{}: response: {}", self.connection.registry, &response);
|
debug!("{}: response: {}", self.connection.registry, &response);
|
||||||
|
|
||||||
let rsp =
|
let rsp = xml::deserialize::<ResponseDocument<Cmd::Response, Ext::Response>>(&response)?;
|
||||||
<ResponseDocument<Cmd::Response, Ext::Response> as EppXml>::deserialize(&response)?;
|
|
||||||
if rsp.data.result.code.is_success() {
|
if rsp.data.result.code.is_success() {
|
||||||
return Ok(rsp.data);
|
return Ok(rsp.data);
|
||||||
}
|
}
|
||||||
|
@ -161,7 +160,7 @@ impl<C: Connector> EppClient<C> {
|
||||||
|
|
||||||
/// Returns the greeting received on establishment of the connection as an `Greeting`
|
/// Returns the greeting received on establishment of the connection as an `Greeting`
|
||||||
pub fn greeting(&self) -> Result<Greeting, Error> {
|
pub fn greeting(&self) -> Result<Greeting, Error> {
|
||||||
GreetingDocument::deserialize(&self.connection.greeting).map(|obj| obj.data)
|
xml::deserialize::<GreetingDocument>(&self.connection.greeting).map(|obj| obj.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn reconnect(&mut self) -> Result<(), Error> {
|
pub async fn reconnect(&mut self) -> Result<(), Error> {
|
||||||
|
|
11
src/hello.rs
11
src/hello.rs
|
@ -4,7 +4,6 @@ use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
use crate::common::{Options, ServiceExtension, Services, StringValue, EPP_XMLNS};
|
use crate::common::{Options, ServiceExtension, Services, StringValue, EPP_XMLNS};
|
||||||
use crate::xml::EppXml;
|
|
||||||
|
|
||||||
// Request
|
// Request
|
||||||
|
|
||||||
|
@ -27,8 +26,6 @@ impl Default for HelloDocument {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EppXml for HelloDocument {}
|
|
||||||
|
|
||||||
// Response
|
// Response
|
||||||
|
|
||||||
/// Type for data within the <svcMenu> section of an EPP greeting
|
/// Type for data within the <svcMenu> section of an EPP greeting
|
||||||
|
@ -302,20 +299,18 @@ pub struct GreetingDocument {
|
||||||
pub data: Greeting,
|
pub data: Greeting,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EppXml for GreetingDocument {}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
|
|
||||||
use super::{ExpiryType, GreetingDocument, HelloDocument, Relative};
|
use super::{ExpiryType, GreetingDocument, HelloDocument, Relative};
|
||||||
use crate::tests::get_xml;
|
use crate::tests::get_xml;
|
||||||
use crate::xml::EppXml;
|
use crate::xml;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hello() {
|
fn hello() {
|
||||||
let xml = get_xml("request/hello.xml").unwrap();
|
let xml = get_xml("request/hello.xml").unwrap();
|
||||||
let serialized = HelloDocument::default().serialize().unwrap();
|
let serialized = xml::serialize(&HelloDocument::default()).unwrap();
|
||||||
|
|
||||||
assert_eq!(xml, serialized);
|
assert_eq!(xml, serialized);
|
||||||
}
|
}
|
||||||
|
@ -323,7 +318,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn greeting() {
|
fn greeting() {
|
||||||
let xml = get_xml("response/greeting.xml").unwrap();
|
let xml = get_xml("response/greeting.xml").unwrap();
|
||||||
let object = GreetingDocument::deserialize(xml.as_str()).unwrap();
|
let object = xml::deserialize::<GreetingDocument>(xml.as_str()).unwrap();
|
||||||
|
|
||||||
assert_eq!(object.data.service_id, "ISPAPI EPP Server");
|
assert_eq!(object.data.service_id, "ISPAPI EPP Server");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -3,10 +3,7 @@
|
||||||
use serde::{de::DeserializeOwned, ser::SerializeStruct, ser::Serializer, Serialize};
|
use serde::{de::DeserializeOwned, ser::SerializeStruct, ser::Serializer, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use crate::{
|
use crate::common::{StringValue, EPP_XMLNS};
|
||||||
common::{StringValue, EPP_XMLNS},
|
|
||||||
xml::EppXml,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const EPP_VERSION: &str = "1.0";
|
pub const EPP_VERSION: &str = "1.0";
|
||||||
pub const EPP_LANG: &str = "en";
|
pub const EPP_LANG: &str = "en";
|
||||||
|
@ -73,5 +70,3 @@ impl<'a, Cmd, Ext> CommandDocument<'a, Cmd, Ext> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, D: Serialize, E: Serialize> EppXml for CommandDocument<'a, D, E> {}
|
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use serde::{de::DeserializeOwned, Deserialize};
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::common::StringValue;
|
use crate::common::StringValue;
|
||||||
use crate::xml::EppXml;
|
|
||||||
|
|
||||||
/// Type corresponding to the <undef> tag an EPP response XML
|
/// Type corresponding to the <undef> tag an EPP response XML
|
||||||
#[derive(Deserialize, Debug, PartialEq)]
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
|
@ -218,8 +217,6 @@ pub struct ResponseDocument<D, E> {
|
||||||
pub data: Response<D, E>,
|
pub data: Response<D, E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: DeserializeOwned, E: DeserializeOwned> EppXml for ResponseDocument<D, E> {}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq)]
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
#[serde(rename = "epp")]
|
#[serde(rename = "epp")]
|
||||||
pub struct ResultDocument {
|
pub struct ResultDocument {
|
||||||
|
@ -227,8 +224,6 @@ pub struct ResultDocument {
|
||||||
pub data: ResponseStatus,
|
pub data: ResponseStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EppXml for ResultDocument {}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, PartialEq)]
|
#[derive(Deserialize, Debug, PartialEq)]
|
||||||
/// Type corresponding to the <response> tag in an EPP response XML
|
/// Type corresponding to the <response> tag in an EPP response XML
|
||||||
/// without <msgQ> or <resData> sections. Generally used for error handling
|
/// without <msgQ> or <resData> sections. Generally used for error handling
|
||||||
|
@ -261,12 +256,12 @@ impl<T, E> Response<T, E> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{ResultCode, ResultDocument};
|
use super::{ResultCode, ResultDocument};
|
||||||
use crate::tests::{get_xml, CLTRID, SVTRID};
|
use crate::tests::{get_xml, CLTRID, SVTRID};
|
||||||
use crate::xml::EppXml;
|
use crate::xml;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn error() {
|
fn error() {
|
||||||
let xml = get_xml("response/error.xml").unwrap();
|
let xml = get_xml("response/error.xml").unwrap();
|
||||||
let object = ResultDocument::deserialize(xml.as_str()).unwrap();
|
let object = xml::deserialize::<ResultDocument>(xml.as_str()).unwrap();
|
||||||
|
|
||||||
assert_eq!(object.data.result.code, ResultCode::ObjectDoesNotExist);
|
assert_eq!(object.data.result.code, ResultCode::ObjectDoesNotExist);
|
||||||
assert_eq!(object.data.result.message, "Object does not exist".into());
|
assert_eq!(object.data.result.message, "Object does not exist".into());
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
common::NoExtension,
|
common::NoExtension,
|
||||||
request::{Command, CommandDocument, Extension, Transaction},
|
request::{Command, CommandDocument, Extension, Transaction},
|
||||||
response::{Response, ResponseDocument},
|
response::{Response, ResponseDocument},
|
||||||
xml::EppXml,
|
xml,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) const RESOURCES_DIR: &str = "./tests/resources";
|
pub(crate) const RESOURCES_DIR: &str = "./tests/resources";
|
||||||
|
@ -47,8 +47,7 @@ pub(crate) fn assert_serialized<'c, 'e, Cmd, Ext>(
|
||||||
let expected = get_xml(path).unwrap();
|
let expected = get_xml(path).unwrap();
|
||||||
let req = req.into();
|
let req = req.into();
|
||||||
let document = CommandDocument::new(req.command, req.extension, CLTRID);
|
let document = CommandDocument::new(req.command, req.extension, CLTRID);
|
||||||
let actual = EppXml::serialize(&document).unwrap();
|
assert_eq!(expected, xml::serialize(&document).unwrap());
|
||||||
assert_eq!(expected, actual);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn response_from_file<'c, Cmd>(
|
pub(crate) fn response_from_file<'c, Cmd>(
|
||||||
|
@ -68,8 +67,7 @@ where
|
||||||
Ext: Extension,
|
Ext: Extension,
|
||||||
{
|
{
|
||||||
let xml = get_xml(path).unwrap();
|
let xml = get_xml(path).unwrap();
|
||||||
let rsp =
|
let rsp = xml::deserialize::<ResponseDocument<Cmd::Response, Ext::Response>>(&xml).unwrap();
|
||||||
<ResponseDocument<Cmd::Response, Ext::Response> as EppXml>::deserialize(&xml).unwrap();
|
|
||||||
assert!(rsp.data.result.code.is_success());
|
assert!(rsp.data.result.code.is_success());
|
||||||
rsp.data
|
rsp.data
|
||||||
}
|
}
|
||||||
|
|
31
src/xml.rs
31
src/xml.rs
|
@ -6,25 +6,14 @@ use crate::error::Error;
|
||||||
|
|
||||||
pub const EPP_XML_HEADER: &str = r#"<?xml version="1.0" encoding="UTF-8" standalone="no"?>"#;
|
pub const EPP_XML_HEADER: &str = r#"<?xml version="1.0" encoding="UTF-8" standalone="no"?>"#;
|
||||||
|
|
||||||
/// Trait to be implemented by serializers. Currently the only included serializer is `quick-xml`
|
pub(crate) fn serialize(doc: &impl Serialize) -> Result<String, Error> {
|
||||||
pub trait EppXml: Sized {
|
Ok(format!(
|
||||||
/// Serializes the EppObject instance to an EPP XML document
|
"{}\r\n{}",
|
||||||
fn serialize(&self) -> Result<String, Error>
|
EPP_XML_HEADER,
|
||||||
where
|
quick_xml::se::to_string(doc).map_err(|e| Error::Xml(e.into()))?
|
||||||
Self: Serialize,
|
))
|
||||||
{
|
}
|
||||||
Ok(format!(
|
|
||||||
"{}\r\n{}",
|
pub(crate) fn deserialize<T: DeserializeOwned>(xml: &str) -> Result<T, Error> {
|
||||||
EPP_XML_HEADER,
|
quick_xml::de::from_str(xml).map_err(|e| Error::Xml(e.into()))
|
||||||
quick_xml::se::to_string(self).map_err(|e| Error::Xml(e.into()))?
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deserializes an EPP XML document to an EppObject instance
|
|
||||||
fn deserialize(epp_xml: &str) -> Result<Self, Error>
|
|
||||||
where
|
|
||||||
Self: DeserializeOwned + Sized,
|
|
||||||
{
|
|
||||||
quick_xml::de::from_str::<Self>(epp_xml).map_err(|e| Error::Xml(e.into()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue