diff options
-rw-r--r-- | src/call/account.rs | 16 | ||||
-rw-r--r-- | src/client.rs | 47 | ||||
-rw-r--r-- | src/error/mod.rs | 25 | ||||
-rw-r--r-- | src/response/mod.rs | 4 |
4 files changed, 63 insertions, 29 deletions
diff --git a/src/call/account.rs b/src/call/account.rs index 865baf6..08bf077 100644 --- a/src/call/account.rs +++ b/src/call/account.rs @@ -22,8 +22,12 @@ impl From<Login<'_>> for xmlrpc::Value { } impl Call for Login<'_> { - fn method_name(&self) -> &'static str { "account.login" } - fn expected(&self) -> &'static [i32] { &[1000] } + fn method_name(&self) -> &'static str { + "account.login" + } + fn expected(&self) -> &'static [i32] { + &[1000] + } } // Contains no information. This just signals to the server @@ -37,6 +41,10 @@ impl From<Logout> for xmlrpc::Value { } impl Call for Logout { - fn method_name(&self) -> &'static str { "account.logout" } - fn expected(&self) -> &'static [i32] { &[1500] } + fn method_name(&self) -> &'static str { + "account.logout" + } + fn expected(&self) -> &'static [i32] { + &[1500] + } } diff --git a/src/client.rs b/src/client.rs index a1047ff..0f2890d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -7,6 +7,7 @@ use reqwest::{blocking, Url}; /// The INWX environment to use. The Sandbox is good for testing /// or debugging purposes. +#[derive(Clone, Copy, Debug)] pub enum Endpoint { Production, Sandbox, @@ -21,9 +22,9 @@ impl From<Endpoint> for &str { } } -impl Into<Url> for Endpoint { - fn into(self) -> Url { - Url::parse(self.into()).unwrap() +impl From<Endpoint> for Url { + fn from(endpoint: Endpoint) -> Self { + Url::parse(endpoint.into()).unwrap() } } @@ -58,47 +59,45 @@ impl Client { /// 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> { - let transport = self.inner.http.post(self.inner.endpoint.into()); + let expected = call.expected(); - let request = xmlrpc::Request::new(call.method_name()); - request.arg(call); + let transport = self.inner.http.post::<Url>(self.inner.endpoint.into()); + + let request = xmlrpc::Request::new(call.method_name()).arg(call); let raw = request.call(transport)?; match raw { xmlrpc::Value::Struct(map) => { - let code = map.get("code") - .ok_or(Error::Inexistent("code"))?; + let code = map.get("code").ok_or(Error::Inexistent("code"))?; match code { xmlrpc::Value::Int(code) => { - if call.expected().contains(code) { - let data = map.get("resData") - .ok_or(Error::Inexistent("resData"))?; + if expected.contains(code) { + let data = map.get("resData").ok_or(Error::Inexistent("resData"))?; match data { - xmlrpc::Value::Struct(response) => { - Ok(response::Response { - status: *code, - data: response, - }) - }, - _ => Err(Error::Type("resData", "Struct")), + xmlrpc::Value::Struct(response) => Ok(response::Response { + status: *code, + data: response.clone(), + }), + _ => Err(Error::Type("resData", "Struct", data.clone())), } } else { - Err(Error::BadStatus(call.expected(), code)) + Err(Error::BadStatus(expected, *code)) } - }, - _ => Err(Error::Type("code", "Int")), + } + _ => Err(Error::Type("code", "Int", code.clone())), } - }, - _ => Err(Error::BadResponse(raw)), + } + _ => Err(Error::BadResponse(raw.clone())), } } } impl Drop for Client { fn drop(&mut self) { - self.call(call::account::Logout); + // Ignore the result. Failed logout doesn't really matter. + self.call(call::account::Logout).ok(); } } diff --git a/src/error/mod.rs b/src/error/mod.rs index 8be0874..9c8bdfc 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -5,6 +5,11 @@ use std::fmt; pub enum Error { ParseUrl(url::ParseError), Reqwest(reqwest::Error), + XmlRpc(xmlrpc::Error), + Inexistent(&'static str), + Type(&'static str, &'static str, xmlrpc::Value), + BadResponse(xmlrpc::Value), + BadStatus(&'static [i32], i32), } impl std::error::Error for Error {} @@ -14,6 +19,20 @@ impl fmt::Display for Error { match self { Error::ParseUrl(err) => write!(fmt, "can't parse Url: {}", err), Error::Reqwest(err) => write!(fmt, "reqwest error: {}", err), + Error::XmlRpc(err) => write!(fmt, "xmlrpc error: {}", err), + 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::BadResponse(resp) => write!(fmt, "bad response: {:?}", resp), + Error::BadStatus(expected, got) => { + write!(fmt, "bad status {} (expected: {:?}", got, expected) + } } } } @@ -30,5 +49,11 @@ impl From<reqwest::Error> for Error { } } +impl From<xmlrpc::Error> for Error { + fn from(err: xmlrpc::Error) -> Self { + Self::XmlRpc(err) + } +} + /// A `Result` alias where the `Err` case is `inwx::Error`. pub type Result<T> = std::result::Result<T, Error>; diff --git a/src/response/mod.rs b/src/response/mod.rs index ddaa5f2..5c1584f 100644 --- a/src/response/mod.rs +++ b/src/response/mod.rs @@ -1,7 +1,9 @@ +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 pub struct Response { pub status: i32, - pub data: xmlrpc::Value, + pub data: BTreeMap<String, xmlrpc::Value>, } |