diff options
author | HimbeerserverDE <himbeerserverde@gmail.com> | 2022-10-21 19:10:36 +0200 |
---|---|---|
committer | HimbeerserverDE <himbeerserverde@gmail.com> | 2022-10-21 19:10:36 +0200 |
commit | b346808516f3fe7d40ef389073a41583b32ef650 (patch) | |
tree | df84273b217f5f80cf070993b2a84ae986264d8f | |
parent | 0fce2abca02faa831183c42b8e08e1766f5e6d74 (diff) |
initial call/response structure
-rw-r--r-- | src/call/account.rs | 12 | ||||
-rw-r--r-- | src/call/mod.rs | 6 | ||||
-rw-r--r-- | src/client.rs | 62 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/response/mod.rs | 7 |
5 files changed, 78 insertions, 10 deletions
diff --git a/src/call/account.rs b/src/call/account.rs index f35ab00..865baf6 100644 --- a/src/call/account.rs +++ b/src/call/account.rs @@ -1,3 +1,5 @@ +use super::Call; + use std::collections::BTreeMap; // Contains login information. Used to create an API session. @@ -19,6 +21,11 @@ impl From<Login<'_>> for xmlrpc::Value { } } +impl Call for Login<'_> { + fn method_name(&self) -> &'static str { "account.login" } + fn expected(&self) -> &'static [i32] { &[1000] } +} + // Contains no information. This just signals to the server // that it should end the session. pub(crate) struct Logout; @@ -28,3 +35,8 @@ impl From<Logout> for xmlrpc::Value { xmlrpc::Value::Nil } } + +impl Call for Logout { + fn method_name(&self) -> &'static str { "account.logout" } + fn expected(&self) -> &'static [i32] { &[1500] } +} diff --git a/src/call/mod.rs b/src/call/mod.rs index b0edc6c..83de339 100644 --- a/src/call/mod.rs +++ b/src/call/mod.rs @@ -1 +1,7 @@ +// A call to the API. +pub trait Call: Into<xmlrpc::Value> { + fn method_name(&self) -> &'static str; + fn expected(&self) -> &'static [i32]; +} + pub mod account; diff --git a/src/client.rs b/src/client.rs index acb0760..a1047ff 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,8 +1,9 @@ +use crate::{call, response}; use crate::{Error, Result}; use std::sync::Arc; -use reqwest::Url; +use reqwest::{blocking, Url}; /// The INWX environment to use. The Sandbox is good for testing /// or debugging purposes. @@ -20,11 +21,9 @@ impl From<Endpoint> for &str { } } -impl TryInto<Url> for Endpoint { - type Error = Error; - fn try_into(self) -> Result<Url> { - let url = Url::parse(self.into())?; - Ok(url) +impl Into<Url> for Endpoint { + fn into(self) -> Url { + Url::parse(self.into()).unwrap() } } @@ -41,11 +40,12 @@ impl Client { pub fn login(ep: Endpoint, user: &str, pass: &str) -> Result<Client> { let client = Client { inner: Arc::new(ClientRef { - http: reqwest::Client::builder().cookie_store(true).build()?, + http: blocking::Client::builder().cookie_store(true).build()?, + endpoint: ep, }), }; - client.call(crate::call::account::Login { + client.call(call::account::Login { user, pass, case_insensitive: false, @@ -53,15 +53,57 @@ impl Client { Ok(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> { + let transport = self.inner.http.post(self.inner.endpoint.into()); + + let request = xmlrpc::Request::new(call.method_name()); + request.arg(call); + + let raw = request.call(transport)?; + match raw { + xmlrpc::Value::Struct(map) => { + 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"))?; + + match data { + xmlrpc::Value::Struct(response) => { + Ok(response::Response { + status: *code, + data: response, + }) + }, + _ => Err(Error::Type("resData", "Struct")), + } + } else { + Err(Error::BadStatus(call.expected(), code)) + } + }, + _ => Err(Error::Type("code", "Int")), + } + }, + _ => Err(Error::BadResponse(raw)), + } + } } impl Drop for Client { fn drop(&mut self) { - self.call(crate::call::account::Logout); + self.call(call::account::Logout); } } // The underlying data of a `Client`. struct ClientRef { - http: reqwest::Client, + http: blocking::Client, + endpoint: Endpoint, } @@ -1,6 +1,7 @@ pub mod call; pub mod client; pub mod error; +pub mod response; pub use client::Endpoint; pub use error::{Error, Result}; diff --git a/src/response/mod.rs b/src/response/mod.rs new file mode 100644 index 0000000..ddaa5f2 --- /dev/null +++ b/src/response/mod.rs @@ -0,0 +1,7 @@ +/// 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, +} |