1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use super::error::{Result, ResultExt};
use super::xmlfmt::{from_params, into_params, parse, Call, Fault, Params, Response};
use hyper::{self, Client as HyperClient};
use serde::{Deserialize, Serialize};
use std;
use Url;

use hyper::header::Headers;
header! { (ContentType, "ContentType") => [String] }

pub fn call_value<Tkey>(uri: &Url, name: Tkey, params: Params) -> Result<Response>
where
    Tkey: Into<String>,
{
    Client::new()?.call_value(uri, name, params)
}

pub fn call<'a, Tkey, Treq, Tres>(
    uri: &Url,
    name: Tkey,
    req: Treq,
) -> Result<std::result::Result<Tres, Fault>>
where
    Tkey: Into<String>,
    Treq: Serialize,
    Tres: Deserialize<'a>,
{
    Client::new()?.call(uri, name, req)
}

pub struct Client {
    client: HyperClient,
}

impl Client {
    pub fn new() -> Result<Client> {
        let client = HyperClient::new();
        Ok(Client { client: client })
    }

    pub fn call_value<Tkey>(&mut self, uri: &Url, name: Tkey, params: Params) -> Result<Response>
    where
        Tkey: Into<String>,
    {
        use super::xmlfmt::value::ToXml;
        let body_str = Call {
            name: name.into(),
            params,
        }
        .to_xml();
        let bytes: &[u8] = body_str.as_bytes();
        let body = hyper::client::Body::BufBody(bytes, bytes.len());

        let mut headers = Headers::new();
        headers.set(ContentType("xml".to_owned()));

        let response = self
            .client
            .post(uri.as_ref())
            .headers(headers)
            .body(body)
            .send()
            .chain_err(|| "Failed to run the HTTP request within hyper.")?;

        parse::response(response).map_err(Into::into)
    }

    pub fn call<'a, Tkey, Treq, Tres>(
        &mut self,
        uri: &Url,
        name: Tkey,
        req: Treq,
    ) -> Result<std::result::Result<Tres, Fault>>
    where
        Tkey: Into<String>,
        Treq: Serialize,
        Tres: Deserialize<'a>,
    {
        match self.call_value(uri, name, into_params(&req)?) {
            Ok(Ok(v)) => from_params(v).map(Ok).map_err(Into::into),
            Ok(Err(v)) => Ok(Err(v)),
            Err(v) => Err(v),
        }
    }
}