use std::collections::{BTreeMap, HashMap};
use std::error::Error;
use xmlrpc::Request as XMLRequest;
use xmlrpc::Transport;
use crate::request::Request;
use reqwest::header::HeaderMap;
use reqwest::Response;
use super::RequestError;
use super::Value;
pub(crate) struct Connection {
pub(crate) testing: bool,
pub(crate) debug: bool,
pub(crate) cookies: HashMap<String, String>,
}
impl Connection {
pub(crate) fn new(testing: bool, debug: bool) -> Self {
Self {
testing,
debug,
cookies: HashMap::new(),
}
}
pub(crate) fn url(&self) -> &'static str {
const TESTING_URL: &'static str = "https://api.ote.domrobot.com/xmlrpc/";
const URL: &'static str = "https://api.domrobot.com/xmlrpc/";
match self.testing {
true => TESTING_URL,
false => URL,
}
}
pub(crate) fn send(
&mut self,
req: &Request,
) -> Result<Option<BTreeMap<String, Value>>, RequestError> {
let res = {
let tp = INWXTransport { conn: self };
let res = req.build().call(tp);
res.map_err(|_| RequestError::SendFailed)?
};
const E: RequestError = RequestError::InvalidResponse;
if self.debug {
println!("Response: {:?}", res);
}
let res = res.as_struct().ok_or(E)?;
let code = res.get("code").ok_or(E)?.as_i32().ok_or(E)?;
let msg = res.get("msg").ok_or(E)?.as_str().ok_or(E)?;
match code {
1000 | 1500 => {
if let Some(data) = res.get("resData") {
Ok(Some(data.as_struct().ok_or(E)?.clone()))
} else {
Ok(None)
}
}
_ => Err(RequestError::CallError(code, msg.to_string())),
}
}
fn header_map(&self) -> HeaderMap {
use reqwest::header::COOKIE;
self.cookies
.iter()
.map(|(n, v)| (COOKIE, format!("{}={}", n, v).parse().unwrap()))
.collect()
}
}
struct INWXTransport<'a> {
conn: &'a mut Connection,
}
impl<'a> Transport for INWXTransport<'a> {
type Stream = Response;
fn transmit(self, request: &XMLRequest) -> Result<Self::Stream, Box<Error + Send + Sync>> {
use reqwest::Client;
use xmlrpc::http::{build_headers, check_response};
let mut body = Vec::new();
request.write_as_xml(&mut body).unwrap();
let req = Client::new().post(self.conn.url());
let req = build_headers(req, body.len() as u64);
let res = req.headers(self.conn.header_map()).body(body).send()?;
check_response(&res)?;
for cookie in res.cookies() {
self.conn
.cookies
.insert(cookie.name().into(), cookie.value().into());
}
Ok(res)
}
}