more intuitive serialization and object structure, and domain check command added
This commit is contained in:
parent
4de42f1951
commit
e879ce5d9a
|
@ -1,4 +1,5 @@
|
|||
use epp_client::{epp::request, connection, epp::xml::EppXml, epp::response::EppGreeting};
|
||||
use epp_client::{epp::request, epp::request::generate_client_tr_id, epp::request::domain, connection, epp::xml::EppXml, epp::response::EppGreeting, epp::object::ElementName};
|
||||
use epp_client::epp::response;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
@ -12,7 +13,8 @@ async fn main() {
|
|||
Err(e) => panic!("Error: {}", e)
|
||||
};
|
||||
|
||||
let epp_hello = request::Hello::new();
|
||||
let domains = vec!["eppdev.com", "hexonet.net"];
|
||||
let domain_check = domain::DomainCheck::epp_new(domains, generate_client_tr_id("eppdev").unwrap().as_str());
|
||||
|
||||
client.transact::<EppGreeting>(&epp_hello).await.unwrap();
|
||||
let response = client.transact::<domain::EppDomainCheck, response::domain::EppDomainCheckResponse>(&domain_check).await.unwrap();
|
||||
}
|
||||
|
|
|
@ -10,8 +10,7 @@ use tokio::{net::TcpStream, io::AsyncWriteExt, io::AsyncReadExt, io::split, io::
|
|||
|
||||
use crate::config::{CONFIG, EppClientConnection};
|
||||
use crate::error;
|
||||
use crate::epp::object::EppObject;
|
||||
use crate::epp::request::{EppRequest, Login, Logout};
|
||||
use crate::epp::request::{generate_client_tr_id, Login, EppLogin, Logout, EppLogout};
|
||||
use crate::epp::response::EppCommandResponse;
|
||||
use crate::epp::xml::EppXml;
|
||||
|
||||
|
@ -144,15 +143,15 @@ impl EppClient {
|
|||
credentials: credentials
|
||||
};
|
||||
|
||||
let client_tr_id = EppRequest::generate_client_tr_id(&client.credentials.0)?;
|
||||
let login_request = Login::new(&client.credentials.0, &client.credentials.1, client_tr_id.as_str());
|
||||
let client_tr_id = generate_client_tr_id(&client.credentials.0)?;
|
||||
let login_request = Login::epp_new(&client.credentials.0, &client.credentials.1, client_tr_id.as_str());
|
||||
|
||||
client.transact::<EppCommandResponse>(&login_request).await?;
|
||||
client.transact::<EppLogin, EppCommandResponse>(&login_request).await?;
|
||||
|
||||
Ok(client)
|
||||
}
|
||||
|
||||
pub async fn transact<E: EppXml + Debug>(&mut self, request: &EppRequest) -> Result<E::Output, Box<dyn Error>> {
|
||||
pub async fn transact<T: EppXml + Debug, E: EppXml + Debug>(&mut self, request: &T) -> Result<E::Output, Box<dyn Error>> {
|
||||
let epp_xml = request.serialize()?;
|
||||
|
||||
println!("Request:\r\n{}", epp_xml);
|
||||
|
@ -177,10 +176,10 @@ impl EppClient {
|
|||
}
|
||||
|
||||
pub async fn logout(&mut self) {
|
||||
let client_tr_id = EppRequest::generate_client_tr_id(&self.credentials.0).unwrap();
|
||||
let epp_logout = Logout::new(client_tr_id.as_str());
|
||||
let client_tr_id = generate_client_tr_id(&self.credentials.0).unwrap();
|
||||
let epp_logout = Logout::epp_new(client_tr_id.as_str());
|
||||
|
||||
self.transact::<EppCommandResponse>(&epp_logout).await;
|
||||
self.transact::<EppLogout, EppCommandResponse>(&epp_logout).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
pub mod command;
|
||||
pub mod object;
|
||||
pub mod quick_xml;
|
||||
pub mod request;
|
||||
pub mod xml;
|
||||
pub mod response;
|
||||
pub mod xml;
|
||||
pub use request::domain;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
use crate::epp::object::{ElementName, StringValue};
|
||||
use serde::ser::{SerializeStruct, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
pub struct Command<T: ElementName> {
|
||||
pub command: T,
|
||||
#[serde(rename = "clTRID")]
|
||||
pub client_tr_id: StringValue,
|
||||
}
|
||||
|
||||
impl<T: ElementName> ElementName for Command<T> {
|
||||
fn element_name(&self) -> &'static str {
|
||||
"command"
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ElementName + Serialize> Serialize for Command<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let command_name = self.command.element_name();
|
||||
let mut state = serializer.serialize_struct("command", 2)?;
|
||||
state.serialize_field(command_name, &self.command)?;
|
||||
state.serialize_field("clTRID", &self.client_tr_id)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
|
||||
|
||||
use crate::epp::xml::{EPP_XMLNS, EPP_XMLNS_XSI, EPP_XSI_SCHEMA_LOCATION};
|
||||
|
||||
|
@ -21,9 +21,13 @@ impl StringValueTrait for &str {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub trait ElementName {
|
||||
fn element_name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename = "epp")]
|
||||
pub struct EppObject<T> {
|
||||
pub struct EppObject<T: ElementName> {
|
||||
pub xmlns: String,
|
||||
#[serde(rename = "xmlns:xsi")]
|
||||
pub xmlns_xsi: String,
|
||||
|
@ -33,6 +37,21 @@ pub struct EppObject<T> {
|
|||
pub data: T,
|
||||
}
|
||||
|
||||
impl<T: ElementName + Serialize> Serialize for EppObject<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let data_name = self.data.element_name();
|
||||
let mut state = serializer.serialize_struct("epp", 4)?;
|
||||
state.serialize_field("xmlns", &self.xmlns)?;
|
||||
state.serialize_field("xmlns:xsi", &self.xmlns_xsi)?;
|
||||
state.serialize_field("xsi:schemaLocation", &self.xsi_schema_location)?;
|
||||
state.serialize_field(data_name, &self.data)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename = "options")]
|
||||
pub struct Options {
|
||||
|
@ -64,7 +83,7 @@ pub struct Services {
|
|||
pub svc_ext: Option<ServiceExtension>,
|
||||
}
|
||||
|
||||
impl<T> EppObject<T> {
|
||||
impl<T: ElementName> EppObject<T> {
|
||||
pub fn new(data: T) -> EppObject<T> {
|
||||
EppObject {
|
||||
data: data,
|
||||
|
|
|
@ -3,10 +3,10 @@ use quick_xml::se;
|
|||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::{error::Error, fmt::Debug};
|
||||
|
||||
use crate::epp::object::EppObject;
|
||||
use crate::epp::object::{ElementName, EppObject};
|
||||
use crate::epp::xml::{EppXml, EPP_XML_HEADER};
|
||||
|
||||
impl<T: Serialize + DeserializeOwned + Debug> EppXml for EppObject<T> {
|
||||
impl<T: Serialize + DeserializeOwned + ElementName + Debug> EppXml for EppObject<T> {
|
||||
type Output = EppObject<T>;
|
||||
|
||||
fn serialize(&self) -> Result<String, Box<dyn Error>> {
|
||||
|
|
|
@ -1,54 +1,38 @@
|
|||
pub mod domain;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::error::Error;
|
||||
use std::time::SystemTime;
|
||||
|
||||
pub use crate::epp::command::Command;
|
||||
use crate::epp::object::{
|
||||
EppObject, Options, ServiceExtension, Services, StringValue, StringValueTrait,
|
||||
ElementName, EppObject, Options, ServiceExtension, Services, StringValue, StringValueTrait,
|
||||
};
|
||||
use crate::epp::xml::{EPP_LANG, EPP_VERSION, EPP_XMLNS, EPP_XMLNS_XSI, EPP_XSI_SCHEMA_LOCATION};
|
||||
use crate::epp::xml::{EPP_LANG, EPP_VERSION};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum RequestType {
|
||||
Hello,
|
||||
#[serde(rename = "command")]
|
||||
CommandLogin {
|
||||
login: Login,
|
||||
#[serde(rename = "clTRID")]
|
||||
client_tr_id: StringValue,
|
||||
},
|
||||
#[serde(rename = "command")]
|
||||
CommandLogout {
|
||||
logout: Logout,
|
||||
#[serde(rename = "clTRID")]
|
||||
client_tr_id: StringValue,
|
||||
},
|
||||
pub type EppHello = EppObject<Hello>;
|
||||
pub type EppLogin = EppObject<Command<Login>>;
|
||||
pub type EppLogout = EppObject<Command<Logout>>;
|
||||
|
||||
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()))
|
||||
}
|
||||
|
||||
impl<RequestType> EppObject<RequestType> {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
|
||||
pub type EppRequest = EppObject<RequestType>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[serde(rename = "hello")]
|
||||
pub struct Hello;
|
||||
|
||||
impl Hello {
|
||||
pub fn new() -> EppRequest {
|
||||
EppRequest::new(RequestType::Hello)
|
||||
impl ElementName for Hello {
|
||||
fn element_name(&self) -> &'static str {
|
||||
"hello"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Command {
|
||||
login: Login,
|
||||
#[serde(rename = "clTRID")]
|
||||
client_tr_id: StringValue,
|
||||
impl Hello {
|
||||
pub fn epp_new() -> EppHello {
|
||||
EppObject::new(Hello {})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
|
@ -63,8 +47,14 @@ pub struct Login {
|
|||
services: Services,
|
||||
}
|
||||
|
||||
impl ElementName for Login {
|
||||
fn element_name(&self) -> &'static str {
|
||||
"login"
|
||||
}
|
||||
}
|
||||
|
||||
impl Login {
|
||||
pub fn new(username: &str, password: &str, client_tr_id: &str) -> EppRequest {
|
||||
pub fn epp_new(username: &str, password: &str, client_tr_id: &str) -> EppLogin {
|
||||
let login = Login {
|
||||
username: username.to_string_value(),
|
||||
password: password.to_string_value(),
|
||||
|
@ -86,8 +76,8 @@ impl Login {
|
|||
},
|
||||
};
|
||||
|
||||
EppRequest::new(RequestType::CommandLogin {
|
||||
login: login,
|
||||
EppObject::new(Command::<Login> {
|
||||
command: login,
|
||||
client_tr_id: client_tr_id.to_string_value(),
|
||||
})
|
||||
}
|
||||
|
@ -106,10 +96,16 @@ impl Login {
|
|||
pub struct Logout;
|
||||
|
||||
impl Logout {
|
||||
pub fn new(client_tr_id: &str) -> EppRequest {
|
||||
EppRequest::new(RequestType::CommandLogout {
|
||||
logout: Logout,
|
||||
pub fn epp_new(client_tr_id: &str) -> EppLogout {
|
||||
EppObject::new(Command::<Logout> {
|
||||
command: Logout,
|
||||
client_tr_id: client_tr_id.to_string_value(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementName for Logout {
|
||||
fn element_name(&self) -> &'static str {
|
||||
"logout"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
use crate::epp::command::Command;
|
||||
use crate::epp::object::{ElementName, EppObject, StringValue, StringValueTrait};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const EPP_DOMAIN_XMLNS: &str = "urn:ietf:params:xml:ns:domain-1.0";
|
||||
|
||||
pub type EppDomainCheck = EppObject<Command<DomainCheck>>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DomainList {
|
||||
pub xmlns: String,
|
||||
#[serde(rename = "name")]
|
||||
pub domains: Vec<StringValue>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DomainCheck {
|
||||
#[serde(rename = "check")]
|
||||
list: DomainList,
|
||||
}
|
||||
|
||||
impl ElementName for DomainCheck {
|
||||
fn element_name(&self) -> &'static str {
|
||||
"check"
|
||||
}
|
||||
}
|
||||
|
||||
impl DomainCheck {
|
||||
pub fn epp_new(domains: Vec<&str>, client_tr_id: &str) -> EppDomainCheck {
|
||||
let domains = domains
|
||||
.iter()
|
||||
.filter_map(|d| Some(d.to_string_value()))
|
||||
.collect::<Vec<StringValue>>();
|
||||
|
||||
let domain_check = DomainCheck {
|
||||
list: DomainList {
|
||||
xmlns: EPP_DOMAIN_XMLNS.to_string(),
|
||||
domains: domains,
|
||||
},
|
||||
};
|
||||
|
||||
EppObject::new(Command::<DomainCheck> {
|
||||
command: domain_check,
|
||||
client_tr_id: client_tr_id.to_string_value(),
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
pub mod domain;
|
||||
|
||||
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};
|
||||
use crate::epp::object::{
|
||||
ElementName, EppObject, Options, ServiceExtension, Services, StringValue,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub struct ResponseType<T>(T);
|
||||
|
||||
pub type EppGreeting = EppObject<ResponseType<Greeting>>;
|
||||
pub type EppCommandResponse = EppObject<ResponseType<CommandResponse>>;
|
||||
pub type EppGreeting = EppObject<Greeting>;
|
||||
pub type EppCommandResponse = EppObject<CommandResponse<String>>;
|
||||
|
||||
#[derive(Serialize, Debug, PartialEq)]
|
||||
pub struct ServiceMenu {
|
||||
|
@ -131,8 +129,22 @@ pub struct ResponseTRID {
|
|||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub struct CommandResponse {
|
||||
pub struct CommandResponse<T> {
|
||||
pub result: EppResult,
|
||||
#[serde(rename = "resData")]
|
||||
pub res_data: Option<T>,
|
||||
#[serde(rename = "trID")]
|
||||
pub tr_ids: ResponseTRID,
|
||||
}
|
||||
|
||||
impl ElementName for Greeting {
|
||||
fn element_name(&self) -> &'static str {
|
||||
"greeting"
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ElementName for CommandResponse<T> {
|
||||
fn element_name(&self) -> &'static str {
|
||||
"command"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::epp::object::{EppObject, StringValue};
|
||||
use crate::epp::response::CommandResponse;
|
||||
|
||||
pub type EppDomainCheckResponse = EppObject<CommandResponse<DomainCheckResult>>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum Availability {
|
||||
Unavailable,
|
||||
Available,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DomainCheck {
|
||||
#[serde(rename = "$value")]
|
||||
pub name: StringValue,
|
||||
#[serde(rename = "avail")]
|
||||
pub avail: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DomainCheckDataItem {
|
||||
pub name: DomainCheck,
|
||||
pub reason: Option<StringValue>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DomainCheckData {
|
||||
#[serde(rename = "cd")]
|
||||
pub domain_list: Vec<DomainCheckDataItem>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DomainCheckResult {
|
||||
#[serde(rename = "chkData")]
|
||||
pub check_data: DomainCheckData,
|
||||
}
|
Loading…
Reference in New Issue