deserialization boilerplate
This commit is contained in:
parent
0ced95dee7
commit
85ae3d601c
|
@ -5,8 +5,13 @@ edition = "2018"
|
|||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[[example]]
|
||||
name = "example-client"
|
||||
path = "examples/client.rs"
|
||||
|
||||
[dependencies]
|
||||
bytes = "1"
|
||||
chrono = "0.4"
|
||||
confy = "0.4"
|
||||
futures = "0.3"
|
||||
lazy_static = "1.4"
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
pub mod config;
|
||||
pub mod connection;
|
||||
pub mod epp;
|
||||
pub mod error;
|
||||
|
||||
use std::time::SystemTime;
|
||||
use tokio::time::{sleep, Duration};
|
||||
use crate::{epp::request};
|
||||
use epp_client::{epp::request, connection, epp::xml::EppXml, epp::response::EppResponse};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let mut client = match connection::connect("hexonet").await {
|
||||
Ok(client) => {
|
||||
println!("{}", client.greeting());
|
||||
let greeting = client.greeting();
|
||||
let greeting_object = EppResponse::deserialize(&greeting).unwrap();
|
||||
println!("{:?}", greeting_object);
|
||||
client
|
||||
},
|
||||
Err(e) => panic!("Error: {}", e)
|
|
@ -2,3 +2,4 @@ pub mod object;
|
|||
pub mod quick_xml;
|
||||
pub mod request;
|
||||
pub mod xml;
|
||||
pub mod response;
|
||||
|
|
|
@ -1,5 +1,26 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::epp::xml::{EPP_XMLNS, EPP_XMLNS_XSI, EPP_XSI_SCHEMA_LOCATION};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct StringValue(String);
|
||||
|
||||
impl Default for StringValue {
|
||||
fn default() -> Self {
|
||||
Self(String::from(""))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StringValueTrait {
|
||||
fn to_string_value(&self) -> StringValue;
|
||||
}
|
||||
|
||||
impl StringValueTrait for &str {
|
||||
fn to_string_value(&self) -> StringValue {
|
||||
StringValue(self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename = "epp")]
|
||||
pub struct EppObject<T> {
|
||||
|
@ -8,5 +29,48 @@ pub struct EppObject<T> {
|
|||
pub xmlns_xsi: String,
|
||||
#[serde(rename = "xsi:schemaLocation")]
|
||||
pub xsi_schema_location: String,
|
||||
#[serde(alias = "greeting")]
|
||||
pub data: T,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename = "options")]
|
||||
pub struct Options {
|
||||
pub version: StringValue,
|
||||
pub lang: StringValue,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
pub fn build(version: &str, lang: &str) -> Options {
|
||||
Options {
|
||||
version: version.to_string_value(),
|
||||
lang: lang.to_string_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename = "svcExtension")]
|
||||
pub struct ServiceExtension {
|
||||
#[serde(rename = "extURI")]
|
||||
pub ext_uris: Option<Vec<StringValue>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Services {
|
||||
#[serde(rename = "objURI")]
|
||||
pub obj_uris: Vec<StringValue>,
|
||||
#[serde(rename = "svcExtension")]
|
||||
pub svc_ext: Option<ServiceExtension>,
|
||||
}
|
||||
|
||||
impl<T> EppObject<T> {
|
||||
pub fn new(data: T) -> EppObject<T> {
|
||||
EppObject {
|
||||
data: data,
|
||||
xmlns: EPP_XMLNS.to_string(),
|
||||
xmlns_xsi: EPP_XMLNS_XSI.to_string(),
|
||||
xsi_schema_location: EPP_XSI_SCHEMA_LOCATION.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,24 @@
|
|||
use quick_xml::de::from_str;
|
||||
use quick_xml::se;
|
||||
use serde::Serialize;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::error::Error;
|
||||
|
||||
use crate::epp::object::EppObject;
|
||||
use crate::epp::xml::{EppXml, EPP_XML_HEADER};
|
||||
|
||||
impl<T: Serialize> EppXml for EppObject<T> {
|
||||
impl<T: Serialize + DeserializeOwned> EppXml for EppObject<T> {
|
||||
type Object = EppObject<T>;
|
||||
|
||||
fn serialize(&self) -> Result<String, Box<dyn Error>> {
|
||||
let epp_xml = format!("{}\r\n{}", EPP_XML_HEADER, se::to_string(self)?);
|
||||
|
||||
Ok(epp_xml)
|
||||
}
|
||||
|
||||
fn deserialize(epp_xml: &str) -> Result<Self::Object, Box<dyn Error>> {
|
||||
match from_str(epp_xml) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(format!("epp-client Deserialization Error: {}", e).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,39 +2,17 @@ use serde::{Deserialize, Serialize};
|
|||
use std::error::Error;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use crate::epp::object::EppObject;
|
||||
|
||||
const EPP_XMLNS: &str = "urn:ietf:params:xml:ns:epp-1.0";
|
||||
const EPP_XMLNS_XSI: &str = "http://www.w3.org/2001/XMLSchema-instance";
|
||||
const EPP_XSI_SCHEMA_LOCATION: &str = "urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd";
|
||||
|
||||
const EPP_VERSION: &str = "1.0";
|
||||
const EPP_LANG: &str = "en";
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct StringValue(String);
|
||||
|
||||
impl Default for StringValue {
|
||||
fn default() -> Self {
|
||||
Self(String::from(""))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StringValueTrait {
|
||||
fn to_string_value(&self) -> StringValue;
|
||||
}
|
||||
|
||||
impl StringValueTrait for &str {
|
||||
fn to_string_value(&self) -> StringValue {
|
||||
StringValue(self.to_string())
|
||||
}
|
||||
}
|
||||
use crate::epp::object::{
|
||||
EppObject, Options, ServiceExtension, Services, StringValue, StringValueTrait,
|
||||
};
|
||||
use crate::epp::xml::{EPP_LANG, EPP_VERSION, EPP_XMLNS, EPP_XMLNS_XSI, EPP_XSI_SCHEMA_LOCATION};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum RequestType {
|
||||
Hello,
|
||||
Command {
|
||||
#[serde(rename = "command")]
|
||||
CommandLogin {
|
||||
login: Login,
|
||||
#[serde(rename = "clTRID")]
|
||||
client_tr_id: StringValue,
|
||||
|
@ -48,15 +26,6 @@ pub enum RequestType {
|
|||
}
|
||||
|
||||
impl<RequestType> EppObject<RequestType> {
|
||||
pub fn new(data: RequestType) -> EppObject<RequestType> {
|
||||
EppObject {
|
||||
data: data,
|
||||
xmlns: EPP_XMLNS.to_string(),
|
||||
xmlns_xsi: EPP_XMLNS_XSI.to_string(),
|
||||
xsi_schema_location: EPP_XSI_SCHEMA_LOCATION.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_client_tr_id(username: &str) -> Result<String, Box<dyn Error>> {
|
||||
let timestamp = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
|
||||
Ok(format!("{}:{}", username, timestamp.as_secs()))
|
||||
|
@ -75,37 +44,6 @@ impl Hello {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename = "options")]
|
||||
pub struct LoginOptions {
|
||||
version: StringValue,
|
||||
lang: StringValue,
|
||||
}
|
||||
|
||||
impl LoginOptions {
|
||||
pub fn build(version: &str, lang: &str) -> LoginOptions {
|
||||
LoginOptions {
|
||||
version: version.to_string_value(),
|
||||
lang: lang.to_string_value(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename = "svcExtension")]
|
||||
pub struct ServiceExtension {
|
||||
#[serde(rename = "extURI")]
|
||||
ext_uris: Option<Vec<StringValue>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Services {
|
||||
#[serde(rename = "objURI")]
|
||||
obj_uris: Vec<StringValue>,
|
||||
#[serde(rename = "svcExtension")]
|
||||
svc_ext: Option<ServiceExtension>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Command {
|
||||
login: Login,
|
||||
|
@ -120,7 +58,7 @@ pub struct Login {
|
|||
username: StringValue,
|
||||
#[serde(rename = "pw", default)]
|
||||
password: StringValue,
|
||||
options: LoginOptions,
|
||||
options: Options,
|
||||
#[serde(rename = "svcs")]
|
||||
services: Services,
|
||||
}
|
||||
|
@ -130,7 +68,7 @@ impl Login {
|
|||
let login = Login {
|
||||
username: username.to_string_value(),
|
||||
password: password.to_string_value(),
|
||||
options: LoginOptions {
|
||||
options: Options {
|
||||
version: EPP_VERSION.to_string_value(),
|
||||
lang: EPP_LANG.to_string_value(),
|
||||
},
|
||||
|
@ -148,13 +86,13 @@ impl Login {
|
|||
},
|
||||
};
|
||||
|
||||
EppRequest::new(RequestType::Command {
|
||||
EppRequest::new(RequestType::CommandLogin {
|
||||
login: login,
|
||||
client_tr_id: client_tr_id.to_string_value(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_options(&mut self, options: LoginOptions) {
|
||||
pub fn set_options(&mut self, options: Options) {
|
||||
self.options = options;
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1,118 @@
|
|||
// use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::error::Error;
|
||||
|
||||
use crate::epp::object::{EppObject, Options, ServiceExtension, Services, StringValue};
|
||||
use crate::epp::xml::{EPP_XMLNS, EPP_XMLNS_XSI, EPP_XSI_SCHEMA_LOCATION};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ResponseType {
|
||||
#[serde(rename = "greeting")]
|
||||
Greeting(Greeting),
|
||||
}
|
||||
|
||||
pub type EppResponse = EppObject<ResponseType>;
|
||||
|
||||
#[derive(Serialize, Debug, PartialEq)]
|
||||
pub struct ServiceMenu {
|
||||
pub options: Options,
|
||||
pub services: Services,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
struct FlattenedServiceMenu {
|
||||
pub version: StringValue,
|
||||
pub lang: StringValue,
|
||||
#[serde(rename = "objURI")]
|
||||
pub obj_uris: Vec<StringValue>,
|
||||
#[serde(rename = "svcExtension")]
|
||||
pub svc_ext: Option<ServiceExtension>,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ServiceMenu {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let flattened_svc_menu = FlattenedServiceMenu::deserialize(deserializer)?;
|
||||
|
||||
let svc_menu = ServiceMenu {
|
||||
options: Options {
|
||||
version: flattened_svc_menu.version,
|
||||
lang: flattened_svc_menu.lang,
|
||||
},
|
||||
services: Services {
|
||||
obj_uris: flattened_svc_menu.obj_uris,
|
||||
svc_ext: flattened_svc_menu.svc_ext,
|
||||
},
|
||||
};
|
||||
|
||||
Ok(svc_menu)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct All;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Access {
|
||||
all: All,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Admin;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Prov;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Purpose {
|
||||
admin: Admin,
|
||||
prov: Prov,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Ours;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Public;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Recipient {
|
||||
ours: Ours,
|
||||
public: Public,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Stated;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Retention {
|
||||
stated: Stated,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Statement {
|
||||
purpose: Purpose,
|
||||
recipient: Recipient,
|
||||
retention: Retention,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Dcp {
|
||||
access: Access,
|
||||
statement: Statement,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub struct Greeting {
|
||||
#[serde(rename = "svID")]
|
||||
service_id: String,
|
||||
#[serde(rename = "svDate")]
|
||||
service_date: String,
|
||||
#[serde(rename = "svcMenu")]
|
||||
svc_menu: ServiceMenu,
|
||||
dcp: Dcp,
|
||||
}
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
use std::error::Error;
|
||||
|
||||
// use crate::epp::object::EppObject;
|
||||
|
||||
pub const EPP_XML_HEADER: &str = r#"<?xml version="1.0" encoding="UTF-8" standalone="no"?>"#;
|
||||
pub const EPP_XMLNS: &str = "urn:ietf:params:xml:ns:epp-1.0";
|
||||
pub const EPP_XMLNS_XSI: &str = "http://www.w3.org/2001/XMLSchema-instance";
|
||||
pub const EPP_XSI_SCHEMA_LOCATION: &str = "urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd";
|
||||
|
||||
pub const EPP_VERSION: &str = "1.0";
|
||||
pub const EPP_LANG: &str = "en";
|
||||
|
||||
pub trait EppXml {
|
||||
type Object;
|
||||
|
||||
fn serialize(&self) -> Result<String, Box<dyn Error>>;
|
||||
// fn deserialize(&self) -> Result<Self, Box<dyn Error>>;
|
||||
fn deserialize(epp_xml: &str) -> Result<Self::Object, Box<dyn Error>>;
|
||||
}
|
||||
|
|
58
src/lib.rs
58
src/lib.rs
|
@ -1,34 +1,34 @@
|
|||
// pub mod config;
|
||||
// pub mod connection;
|
||||
// pub mod epp;
|
||||
// pub mod error;
|
||||
pub mod config;
|
||||
pub mod connection;
|
||||
pub mod epp;
|
||||
pub mod error;
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::config;
|
||||
// use super::connection;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::config;
|
||||
use super::connection;
|
||||
|
||||
// #[test]
|
||||
// fn config() {
|
||||
// let servers = &config::CONFIG.servers;
|
||||
#[test]
|
||||
fn config() {
|
||||
let servers = &config::CONFIG.servers;
|
||||
|
||||
// ()
|
||||
// }
|
||||
()
|
||||
}
|
||||
|
||||
// macro_rules! aw {
|
||||
// ($e:expr) => {
|
||||
// tokio_test::block_on($e)
|
||||
// };
|
||||
// }
|
||||
macro_rules! aw {
|
||||
($e:expr) => {
|
||||
tokio_test::block_on($e)
|
||||
};
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn connect() {
|
||||
// let mut client = match aw!(connection::connect("hexonet")) {
|
||||
// Ok(client) => {
|
||||
// println!("{}", client.greeting());
|
||||
// client
|
||||
// },
|
||||
// Err(e) => panic!("Error: {}", e)
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
#[test]
|
||||
fn connect() {
|
||||
let mut client = match aw!(connection::connect("hexonet")) {
|
||||
Ok(client) => {
|
||||
println!("{}", client.greeting());
|
||||
client
|
||||
},
|
||||
Err(e) => panic!("Error: {}", e)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue