aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeerserverDE <himbeerserverde@gmail.com>2022-11-05 00:41:41 +0100
committerHimbeerserverDE <himbeerserverde@gmail.com>2022-11-05 00:41:41 +0100
commite5248adf8dc110b4f549d0b4af296deb765edb23 (patch)
treea8de224e177108e4bbb99edeefcb6a8c0dd81c4b
parentacb34a49e82db411f4b348374b2e8d6c234728b3 (diff)
switch to custom serde_xmlrpc fork
closes #3
-rw-r--r--Cargo.toml12
-rw-r--r--src/call/account.rs31
-rw-r--r--src/call/mod.rs7
-rw-r--r--src/call/nameserver.rs133
-rw-r--r--src/client.rs74
-rw-r--r--src/common/mod.rs78
-rw-r--r--src/common/nameserver.rs179
-rw-r--r--src/error.rs27
-rw-r--r--src/response/mod.rs11
-rw-r--r--src/response/nameserver.rs96
10 files changed, 112 insertions, 536 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 64a131e..e99a664 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,15 +6,17 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-iso8601 = "0.4.0"
+iso8601 = "0.3.0"
url = "2.2.2"
+serde = "1.0.147"
+serde_derive = "1.0.147"
[dependencies.reqwest]
version = "0.11"
default-features = false
features = ["blocking", "cookies", "rustls-tls"]
-[dependencies.xmlrpc]
-version = "0.15.1"
-default-features = false
-features = ["http"]
+[dependencies.serde_xmlrpc]
+version = "0.1.1"
+git = "https://github.com/HimbeerserverDE/serde_xml_rpc.git"
+branch = "serializer"
diff --git a/src/call/account.rs b/src/call/account.rs
index ea6fa6f..73d6dab 100644
--- a/src/call/account.rs
+++ b/src/call/account.rs
@@ -1,27 +1,16 @@
-use super::Call;
+use super::*;
-use std::collections::BTreeMap;
+use serde_derive::{Deserialize, Serialize};
// Contains login information. Used to create an API session.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct Login {
pub(crate) user: String,
pub(crate) pass: String,
+ #[serde(rename = "case-insensitive")]
pub(crate) case_insensitive: bool,
}
-impl From<Login> for xmlrpc::Value {
- fn from(login: Login) -> Self {
- let mut map = BTreeMap::new();
-
- map.insert("user".into(), login.user.into());
- map.insert("pass".into(), login.pass.into());
- map.insert("case-insensitive".into(), login.case_insensitive.into());
-
- xmlrpc::Value::Struct(map)
- }
-}
-
impl Call for Login {
fn method_name(&self) -> String {
String::from("account.login")
@@ -32,17 +21,13 @@ impl Call for Login {
}
}
+impl Response<()> for Login {}
+
// Contains no information. This just signals to the server
// that it should end the session.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct Logout;
-impl From<Logout> for xmlrpc::Value {
- fn from(_logout: Logout) -> Self {
- xmlrpc::Value::Nil
- }
-}
-
impl Call for Logout {
fn method_name(&self) -> String {
String::from("account.logout")
@@ -51,3 +36,5 @@ impl Call for Logout {
vec![1500]
}
}
+
+impl Response<()> for Logout {}
diff --git a/src/call/mod.rs b/src/call/mod.rs
index f8fe0a2..517f459 100644
--- a/src/call/mod.rs
+++ b/src/call/mod.rs
@@ -1,8 +1,11 @@
-// A call to the API.
-pub trait Call: Clone + std::fmt::Debug + Into<xmlrpc::Value> {
+/// A call to the API.
+pub trait Call: Clone + std::fmt::Debug + serde::Serialize {
fn method_name(&self) -> String;
fn expected(&self) -> Vec<i32>;
}
+/// This trait indicates the response data type to this a `Call`.
+pub trait Response<T> {}
+
pub mod account;
pub mod nameserver;
diff --git a/src/call/nameserver.rs b/src/call/nameserver.rs
index c490a31..3b59646 100644
--- a/src/call/nameserver.rs
+++ b/src/call/nameserver.rs
@@ -1,146 +1,55 @@
use super::Call;
-use crate::common::nameserver::{RecordType, UrlRdrType};
-use std::collections::BTreeMap;
+use serde_derive::{Deserialize, Serialize};
/// Optional search constraints to find nameserver records
/// the account has access to.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RecordInfo {
+ #[serde(rename = "domain")]
pub domain_name: Option<String>,
+ #[serde(rename = "roId")]
pub domain_id: Option<i32>,
+ #[serde(rename = "recordId")]
pub record_id: Option<i32>,
- pub record_type: Option<RecordType>,
+ #[serde(rename = "type")]
+ pub record_type: Option<String>,
pub name: Option<String>,
pub content: Option<String>,
pub ttl: Option<i32>,
+ #[serde(rename = "prio")]
pub priority: Option<i32>,
}
-impl From<RecordInfo> for xmlrpc::Value {
- fn from(info: RecordInfo) -> Self {
- let mut map = BTreeMap::new();
-
- if let Some(domain_name) = info.domain_name {
- map.insert("domain".into(), domain_name.into());
- }
-
- if let Some(domain_id) = info.domain_id {
- map.insert("roId".into(), domain_id.into());
- }
-
- if let Some(record_id) = info.record_id {
- map.insert("recordId".into(), record_id.into());
- }
-
- if let Some(record_type) = info.record_type {
- map.insert("type".into(), record_type.into());
- }
-
- if let Some(content) = info.content {
- map.insert("content".into(), content.into());
- }
-
- if let Some(ttl) = info.ttl {
- map.insert("ttl".into(), ttl.into());
- }
-
- if let Some(priority) = info.priority {
- map.insert("prio".into(), priority.into());
- }
-
- xmlrpc::Value::Struct(map)
- }
-}
-
-impl Call for RecordInfo {
- fn method_name(&self) -> String {
- String::from("nameserver.info")
- }
-
- fn expected(&self) -> Vec<i32> {
- vec![1000]
- }
-}
-
/// Update the records with the specified IDs.
/// Any `None` variants will remain unchanged.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RecordUpdate {
+ #[serde(rename = "id")]
pub ids: Vec<i32>,
pub name: Option<String>,
- pub record_type: Option<RecordType>,
+ #[serde(rename = "type")]
+ pub record_type: Option<String>,
pub content: Option<String>,
pub ttl: Option<i32>,
+ #[serde(rename = "prio")]
pub priority: Option<i32>,
- pub url_rdr_type: Option<UrlRdrType>,
+ #[serde(rename = "urlRedirectType")]
+ pub url_rdr_type: Option<String>,
+ #[serde(rename = "urlRedirectTitle")]
pub url_rdr_title: Option<String>,
+ #[serde(rename = "urlRedirectDescription")]
pub url_rdr_desc: Option<String>,
+ #[serde(rename = "urlRedirectKeywords")]
pub url_rdr_keywords: Option<String>,
+ #[serde(rename = "urlRedirectFavIcon")]
pub url_rdr_favicon: Option<String>,
+ #[serde(rename = "urlAppend")]
pub url_append: Option<bool>,
+ #[serde(rename = "testing")]
pub testing_mode: bool,
}
-impl From<RecordUpdate> for xmlrpc::Value {
- fn from(update: RecordUpdate) -> Self {
- let mut map = BTreeMap::new();
-
- map.insert(
- "id".into(),
- xmlrpc::Value::Array(update.ids.iter().map(|v| xmlrpc::Value::from(*v)).collect()),
- );
-
- if let Some(name) = update.name {
- map.insert("name".into(), name.into());
- }
-
- if let Some(record_type) = update.record_type {
- map.insert("type".into(), record_type.into());
- }
-
- if let Some(content) = update.content {
- map.insert("content".into(), content.into());
- }
-
- if let Some(ttl) = update.ttl {
- map.insert("ttl".into(), ttl.into());
- }
-
- if let Some(priority) = update.priority {
- map.insert("prio".into(), priority.into());
- }
-
- if let Some(url_rdr_type) = update.url_rdr_type {
- map.insert("urlRedirectType".into(), url_rdr_type.into());
- }
-
- if let Some(url_rdr_title) = update.url_rdr_title {
- map.insert("urlRedirectTitle".into(), url_rdr_title.into());
- }
-
- if let Some(url_rdr_desc) = update.url_rdr_desc {
- map.insert("urlRedirectDescription".into(), url_rdr_desc.into());
- }
-
- if let Some(url_rdr_keywords) = update.url_rdr_keywords {
- map.insert("urlRedirectKeywords".into(), url_rdr_keywords.into());
- }
-
- if let Some(url_rdr_favicon) = update.url_rdr_favicon {
- map.insert("urlRedirectFavIcon".into(), url_rdr_favicon.into());
- }
-
- if let Some(url_append) = update.url_append {
- map.insert("urlAppend".into(), url_append.into());
- }
-
- map.insert("testing".into(), update.testing_mode.into());
-
- xmlrpc::Value::Struct(map)
- }
-}
-
impl Call for RecordUpdate {
fn method_name(&self) -> String {
String::from("nameserver.updateRecord")
diff --git a/src/client.rs b/src/client.rs
index 8aeb099..add352d 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -1,7 +1,6 @@
-use crate::{call, response};
+use crate::call::{self, Response};
use crate::{Error, Result};
-use std::collections::BTreeMap;
use std::sync::Arc;
use reqwest::{blocking, Url};
@@ -59,47 +58,42 @@ impl Client {
/// Issues a `Call` and returns a `Response`
/// if successful and if the status code
/// matches one of the expected status codes.
- pub fn call(&self, call: impl call::Call) -> Result<response::Response> {
+ pub fn call<T, U>(&self, call: T) -> Result<U>
+ where
+ T: call::Call + Response<U>,
+ U: serde::de::DeserializeOwned,
+ {
let expected = call.expected();
+ let xml = serde_xmlrpc::request_to_str(&call.method_name(), vec![call])?;
- let transport = self.inner.http.post::<Url>(self.inner.endpoint.into());
-
- let binding = call.method_name();
- let request = xmlrpc::Request::new(&binding).arg(call);
-
- let raw = request.call(transport)?;
- match raw {
- xmlrpc::Value::Struct(map) => {
- let code = map
- .get("code")
- .ok_or_else(|| Error::Inexistent("code".into()))?;
-
- match code {
- xmlrpc::Value::Int(code) => {
- if expected.contains(code) {
- let default = &xmlrpc::Value::Struct(BTreeMap::new());
- let data = map.get("resData").unwrap_or(default);
-
- match data {
- xmlrpc::Value::Struct(response) => Ok(response::Response {
- status: *code,
- data: response.clone(),
- }),
- _ => Err(Error::Type(
- "resData".into(),
- "Struct".into(),
- data.clone(),
- )),
- }
- } else {
- Err(Error::BadStatus(expected, *code))
- }
- }
- _ => Err(Error::Type("code".into(), "Int".into(), code.clone())),
- }
- }
- _ => Err(Error::BadResponse(raw.clone())),
+ let raw_response = self.inner.http.post::<Url>(self.inner.endpoint.into())
+ .body(xml)
+ .send()?
+ .text()?;
+
+ let map = serde_xmlrpc::value_from_str(&raw_response)?;
+
+ let resp = map
+ .as_struct()
+ .ok_or_else(|| Error::MalformedResponse(map.clone()))?;
+
+ let code = resp
+ .get("code")
+ .ok_or_else(|| Error::MalformedResponse(map.clone()))?
+ .as_i32()
+ .ok_or_else(|| Error::MalformedResponse(map.clone()))?;
+
+ if !expected.contains(&code) {
+ return Err(Error::BadStatus(expected, code));
}
+
+ let data = resp
+ .get("resData")
+ .ok_or_else(|| Error::MalformedResponse(map.clone()))?;
+
+ let res_data = serde_xmlrpc::value_to_string(data.clone())?;
+
+ Ok(serde_xmlrpc::response_from_str(&res_data)?)
}
}
diff --git a/src/common/mod.rs b/src/common/mod.rs
index ef15d9c..aa5854f 100644
--- a/src/common/mod.rs
+++ b/src/common/mod.rs
@@ -1,79 +1 @@
-use crate::{Error, Result};
-
-use std::collections::BTreeMap;
-
-use iso8601::DateTime;
-
-pub(crate) fn get_str(map: &BTreeMap<String, xmlrpc::Value>, key: String) -> Result<String> {
- let value = map
- .get(&key)
- .ok_or_else(|| Error::Inexistent(key.clone()))?
- .as_str()
- .ok_or_else(|| Error::Type(key.clone(), "String".into(), map.get(&key).unwrap().clone()))?;
-
- Ok(value.to_owned())
-}
-
-pub(crate) fn get_i32(map: &BTreeMap<String, xmlrpc::Value>, key: String) -> Result<i32> {
- let value = map
- .get(&key)
- .ok_or_else(|| Error::Inexistent(key.clone()))?
- .as_i32()
- .ok_or_else(|| Error::Type(key.clone(), "Int".into(), map.get(&key).unwrap().clone()))?;
-
- Ok(value)
-}
-
-pub(crate) fn get_bool(map: &BTreeMap<String, xmlrpc::Value>, key: String) -> Result<bool> {
- let value = map
- .get(&key)
- .ok_or_else(|| Error::Inexistent(key.clone()))?
- .as_bool()
- .ok_or_else(|| Error::Type(key.clone(), "Bool".into(), map.get(&key).unwrap().clone()))?;
-
- Ok(value)
-}
-
-pub(crate) fn get_datetime(map: &BTreeMap<String, xmlrpc::Value>, key: String) -> Result<DateTime> {
- let value = map
- .get(&key)
- .ok_or_else(|| Error::Inexistent(key.clone()))?
- .as_datetime()
- .ok_or_else(|| {
- Error::Type(
- key.clone(),
- "DateTime".into(),
- map.get(&key).unwrap().clone(),
- )
- })?;
-
- Ok(value)
-}
-
-pub(crate) fn get_array(
- map: &BTreeMap<String, xmlrpc::Value>,
- key: String,
-) -> Result<Vec<xmlrpc::Value>> {
- let value = map
- .get(&key)
- .ok_or_else(|| Error::Inexistent(key.clone()))?
- .as_array()
- .ok_or_else(|| Error::Type(key.clone(), "Array".into(), map.get(&key).unwrap().clone()))?;
-
- Ok(value.to_vec())
-}
-
-pub(crate) fn get_map(
- map: &BTreeMap<String, xmlrpc::Value>,
- key: String,
-) -> Result<BTreeMap<String, xmlrpc::Value>> {
- let value = map
- .get(&key)
- .ok_or_else(|| Error::Inexistent(key.clone()))?
- .as_struct()
- .ok_or_else(|| Error::Type(key.clone(), "Struct".into(), map.get(&key).unwrap().clone()))?;
-
- Ok(value.to_owned())
-}
-
pub mod nameserver;
diff --git a/src/common/nameserver.rs b/src/common/nameserver.rs
index 706ae73..3507a85 100644
--- a/src/common/nameserver.rs
+++ b/src/common/nameserver.rs
@@ -1,183 +1,8 @@
-use super::*;
-use crate::{Error, Result};
-
-use std::fmt;
-
-/// The DNS record type.
-#[derive(Clone, Debug)]
-pub enum RecordType {
- A,
- Aaaa,
- Afsdb,
- Alias,
- Caa,
- Cert,
- Cname,
- Hinfo,
- Key,
- Loc,
- Mx,
- NaPtr,
- Ns,
- OpenPgpKey,
- Ptr,
- Rp,
- SmimeA,
- Soa,
- Srv,
- Sshfp,
- Tlsa,
- Txt,
- Uri,
- Url,
-}
-
-impl fmt::Display for RecordType {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::A => write!(fmt, "A"),
- Self::Aaaa => write!(fmt, "AAAA"),
- Self::Afsdb => write!(fmt, "AFSDB"),
- Self::Alias => write!(fmt, "ALIAS"),
- Self::Caa => write!(fmt, "CAA"),
- Self::Cert => write!(fmt, "CERT"),
- Self::Cname => write!(fmt, "CNAME"),
- Self::Hinfo => write!(fmt, "HINFO"),
- Self::Key => write!(fmt, "KEY"),
- Self::Loc => write!(fmt, "LOC"),
- Self::Mx => write!(fmt, "MX"),
- Self::NaPtr => write!(fmt, "NAPTR"),
- Self::Ns => write!(fmt, "NS"),
- Self::OpenPgpKey => write!(fmt, "OPENPGPKEY"),
- Self::Ptr => write!(fmt, "PTR"),
- Self::Rp => write!(fmt, "RP"),
- Self::SmimeA => write!(fmt, "SMIMEA"),
- Self::Soa => write!(fmt, "SOA"),
- Self::Srv => write!(fmt, "SRV"),
- Self::Sshfp => write!(fmt, "SSHFP"),
- Self::Tlsa => write!(fmt, "TLSA"),
- Self::Txt => write!(fmt, "TXT"),
- Self::Uri => write!(fmt, "URI"),
- Self::Url => write!(fmt, "URL"),
- }
- }
-}
-
-impl From<RecordType> for xmlrpc::Value {
- fn from(rt: RecordType) -> Self {
- xmlrpc::Value::String(rt.to_string())
- }
-}
-
-impl TryFrom<String> for RecordType {
- type Error = Error;
- fn try_from(s: String) -> Result<Self> {
- match s.as_str() {
- "A" => Ok(Self::A),
- "AAAA" => Ok(Self::Aaaa),
- "AFSDB" => Ok(Self::Afsdb),
- "ALIAS" => Ok(Self::Alias),
- "CAA" => Ok(Self::Caa),
- "CERT" => Ok(Self::Cert),
- "CNAME" => Ok(Self::Cname),
- "HINFO" => Ok(Self::Hinfo),
- "KEY" => Ok(Self::Key),
- "LOC" => Ok(Self::Loc),
- "MX" => Ok(Self::Mx),
- "NAPTR" => Ok(Self::NaPtr),
- "NS" => Ok(Self::Ns),
- "OPENPGPKEY" => Ok(Self::OpenPgpKey),
- "PTR" => Ok(Self::Ptr),
- "RP" => Ok(Self::Rp),
- "SMIMEA" => Ok(Self::SmimeA),
- "SOA" => Ok(Self::Soa),
- "SRV" => Ok(Self::Srv),
- "SSHFP" => Ok(Self::Sshfp),
- "TLSA" => Ok(Self::Tlsa),
- "TXT" => Ok(Self::Txt),
- "URI" => Ok(Self::Uri),
- "URL" => Ok(Self::Url),
- _ => Err(Error::BadVariant("RecordType".into(), s)),
- }
- }
-}
-
-/// The domain type. Can be master or slave.
-#[derive(Clone, Debug)]
-pub enum DomainType {
- Master,
- Slave,
-}
-
-impl fmt::Display for DomainType {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt.write_str(match self {
- Self::Master => "MASTER",
- Self::Slave => "SLAVE",
- })
- }
-}
-
-impl TryFrom<String> for DomainType {
- type Error = Error;
- fn try_from(s: String) -> Result<Self> {
- match s.as_str() {
- "MASTER" => Ok(Self::Master),
- "SLAVE" => Ok(Self::Slave),
- _ => Err(Error::BadVariant("DomainType".into(), s)),
- }
- }
-}
+use serde_derive::{Deserialize, Serialize};
/// Information on a slave nameserver.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SlaveDns {
pub hostname: String,
pub address: String,
}
-
-impl TryFrom<BTreeMap<String, xmlrpc::Value>> for SlaveDns {
- type Error = Error;
- fn try_from(map: BTreeMap<String, xmlrpc::Value>) -> Result<Self> {
- Ok(Self {
- hostname: get_str(&map, "name".into())?,
- address: get_str(&map, "ip".into())?,
- })
- }
-}
-
-/// Type of URL redirect. Can be a HTTP 301, 302 or frame.
-#[derive(Clone, Debug)]
-pub enum UrlRdrType {
- Permanent,
- Temporary,
- Frame,
-}
-
-impl fmt::Display for UrlRdrType {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt.write_str(match self {
- Self::Permanent => "HEADER301",
- Self::Temporary => "HEADER302",
- Self::Frame => "FRAME",
- })
- }
-}
-
-impl TryFrom<String> for UrlRdrType {
- type Error = Error;
- fn try_from(s: String) -> Result<Self> {
- match s.as_str() {
- "HEADER301" => Ok(Self::Permanent),
- "HEADER302" => Ok(Self::Temporary),
- "FRAME" => Ok(Self::Frame),
- _ => Err(Error::BadVariant("UrlRdrType".into(), s)),
- }
- }
-}
-
-impl From<UrlRdrType> for xmlrpc::Value {
- fn from(url_rdr_type: UrlRdrType) -> Self {
- url_rdr_type.to_string().into()
- }
-}
diff --git a/src/error.rs b/src/error.rs
index c32dbf4..e5238c6 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -5,12 +5,10 @@ use std::fmt;
pub enum Error {
ParseUrl(url::ParseError),
Reqwest(reqwest::Error),
- XmlRpc(xmlrpc::Error),
+ SerdeXmlRpc(serde_xmlrpc::Error),
Inexistent(String),
- Type(String, String, xmlrpc::Value),
- BadResponse(xmlrpc::Value),
+ MalformedResponse(serde_xmlrpc::Value),
BadStatus(Vec<i32>, i32),
- BadVariant(String, String),
}
impl std::error::Error for Error {}
@@ -19,24 +17,17 @@ impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::ParseUrl(e) => write!(fmt, "can't parse Url: {}", e),
- Error::Reqwest(e) => write!(fmt, "reqwest eor: {}", e),
- Error::XmlRpc(e) => write!(fmt, "xmlrpc eor: {}", e),
+ Error::Reqwest(e) => write!(fmt, "reqwest error: {}", e),
+ Error::SerdeXmlRpc(e) => write!(fmt, "serde_xmlrpc error: {}", e),
Error::Inexistent(what) => {
write!(fmt, "parameter {} does not exist", what)
}
- Error::Type(what, exp, got) => {
- write!(
- fmt,
- "parameter {what} is of wrong type {got:?} (expected: {exp})"
- )
+ Error::MalformedResponse(resp) => {
+ write!(fmt, "malformed response: {:?}", resp)
}
- Error::BadResponse(resp) => write!(fmt, "bad response: {:?}", resp),
Error::BadStatus(expected, got) => {
write!(fmt, "bad status {} (expected: {:?}", got, expected)
}
- Error::BadVariant(enum_name, var) => {
- write!(fmt, "{} is not a valid enum variant for {}", var, enum_name)
- }
}
}
}
@@ -53,9 +44,9 @@ impl From<reqwest::Error> for Error {
}
}
-impl From<xmlrpc::Error> for Error {
- fn from(e: xmlrpc::Error) -> Self {
- Self::XmlRpc(e)
+impl From<serde_xmlrpc::Error> for Error {
+ fn from(e: serde_xmlrpc::Error) -> Self {
+ Self::SerdeXmlRpc(e)
}
}
diff --git a/src/response/mod.rs b/src/response/mod.rs
index 5aab5a5..aa5854f 100644
--- a/src/response/mod.rs
+++ b/src/response/mod.rs
@@ -1,12 +1 @@
-use std::collections::BTreeMap;
-
-/// A Response to an API call including status and data.
-/// Data is guaranteed to be a `Struct`.
-/// [`Struct`]: xmlrpc::Value::Struct
-#[derive(Clone, Debug)]
-pub struct Response {
- pub status: i32,
- pub(crate) data: BTreeMap<String, xmlrpc::Value>,
-}
-
pub mod nameserver;
diff --git a/src/response/nameserver.rs b/src/response/nameserver.rs
index 6ac330b..76e7c85 100644
--- a/src/response/nameserver.rs
+++ b/src/response/nameserver.rs
@@ -1,97 +1,51 @@
-use super::Response;
-use crate::common::nameserver::{DomainType, RecordType, SlaveDns, UrlRdrType};
-use crate::common::*;
-use crate::{Error, Result};
+use crate::common::nameserver::SlaveDns;
-use iso8601::DateTime;
+use serde_derive::{Deserialize, Serialize};
+
+type DateTime = String;
/// A nameserver record. Contains DNS information as well as INWX metadata.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Record {
pub id: i32,
pub name: String,
- pub record_type: RecordType,
+ #[serde(rename = "type")]
+ pub record_type: String,
pub content: String,
pub ttl: i32,
+ #[serde(rename = "prio")]
pub priority: i32,
- pub url_rdr_type: Option<UrlRdrType>,
+ #[serde(rename = "urlRedirectType")]
+ pub url_rdr_type: Option<String>,
+ #[serde(rename = "urlRedirectTitle")]
pub url_rdr_title: Option<String>,
+ #[serde(rename = "urlRedirectDescription")]
pub url_rdr_desc: Option<String>,
+ #[serde(rename = "urlRedirectKeywords")]
pub url_rdr_keywords: Option<String>,
+ #[serde(rename = "urlRedirectFavIcon")]
pub url_rdr_favicon: Option<String>,
+ #[serde(rename = "urlAppend")]
pub url_append: Option<bool>,
}
-impl TryFrom<xmlrpc::Value> for Record {
- type Error = Error;
- fn try_from(v: xmlrpc::Value) -> Result<Self> {
- if let xmlrpc::Value::Struct(map) = v {
- let record = Self {
- id: get_i32(&map, "id".into())?,
- name: get_str(&map, "name".into())?,
- record_type: get_str(&map, "type".into())?.try_into()?,
- content: get_str(&map, "content".into())?,
- ttl: get_i32(&map, "ttl".into())?,
- priority: get_i32(&map, "prio".into())?,
- url_rdr_type: match get_str(&map, "urlRedirectType".into()).ok() {
- Some(url_rdr_type) => url_rdr_type.try_into().ok(),
- None => None,
- },
- url_rdr_title: get_str(&map, "urlRedirectTitle".into()).ok(),
- url_rdr_desc: get_str(&map, "urlRedirectDescription".into()).ok(),
- url_rdr_keywords: get_str(&map, "urlRedirectKeywords".into()).ok(),
- url_rdr_favicon: get_str(&map, "urlRedirectFavIcon".into()).ok(),
- url_append: get_bool(&map, "urlAppend".into()).ok(),
- };
-
- Ok(record)
- } else {
- Err(Error::Type("record".into(), "Struct".into(), v))
- }
- }
-}
-
/// The records that match a search.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RecordInfo {
+ #[serde(rename = "roId")]
pub domain_id: Option<i32>,
+ #[serde(rename = "domain")]
pub domain_name: Option<String>,
- pub domain_type: Option<DomainType>,
+ #[serde(rename = "type")]
+ pub domain_type: Option<String>,
+ #[serde(rename = "masterIp")]
pub master_address: Option<String>,
+ #[serde(rename = "lastZoneCheck")]
pub last_zone_check: Option<DateTime>,
+ #[serde(rename = "slaveDns")]
pub slave_dns: Option<SlaveDns>,
+ #[serde(rename = "SOAserial")]
pub soa_serial: Option<String>,
+ #[serde(rename = "record")]
pub records: Option<Vec<Record>>,
}
-
-impl TryFrom<Response> for RecordInfo {
- type Error = Error;
- fn try_from(resp: Response) -> Result<Self> {
- let info = Self {
- domain_id: get_i32(&resp.data, "roId".into()).ok(),
- domain_name: get_str(&resp.data, "domain".into()).ok(),
- domain_type: match get_str(&resp.data, "type".into()).ok() {
- Some(domain_type) => domain_type.try_into().ok(),
- None => None,
- },
- master_address: get_str(&resp.data, "masterIp".into()).ok(),
- last_zone_check: { get_datetime(&resp.data, "lastZoneCheck".into()).ok() },
- slave_dns: match get_map(&resp.data, "slaveDns".into()).ok() {
- Some(slave_dns) => slave_dns.try_into().ok(),
- None => None,
- },
- soa_serial: get_str(&resp.data, "SOAserial".into()).ok(),
- records: match get_array(&resp.data, "record".into()).ok() {
- Some(records) => Some(
- records
- .iter()
- .map(|v| v.to_owned().try_into())
- .collect::<Result<Vec<Record>>>()?,
- ),
- None => None,
- },
- };
-
- Ok(info)
- }
-}