bigpanda_rs/
lib.rs

1pub mod alert;
2pub mod change;
3
4use headers::authorization::{Authorization, Bearer};
5use headers::{ContentType, HeaderMapExt};
6use hyper::client::connect::HttpConnector;
7use hyper::{Body, Method, StatusCode};
8use hyper_tls::HttpsConnector;
9use std::error::Error;
10use std::fmt::{self, Display, Formatter};
11
12pub const GET: Method = Method::GET;
13pub const POST: Method = Method::POST;
14pub const PUT: Method = Method::PUT;
15
16#[derive(Debug)]
17pub enum ApiType {
18    Alert,
19    Change,
20}
21
22#[derive(Debug)]
23pub enum BigPandaError {
24    NetworkError(hyper::Error),
25    HTTPError(StatusCode),
26}
27
28impl Display for BigPandaError {
29    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
30        match *self {
31            BigPandaError::NetworkError(ref err) => err.fmt(formatter),
32            BigPandaError::HTTPError(ref status_code) => {
33                write!(formatter, "Invalid status code: {}", status_code)
34            }
35        }
36    }
37}
38
39impl Error for BigPandaError {
40    fn source(&self) -> Option<&(dyn Error + 'static)> {
41        match *self {
42            BigPandaError::NetworkError(ref err) => Some(err),
43            _ => None,
44        }
45    }
46}
47
48pub struct Client {
49    api_type: ApiType,
50    app_key: String,
51    auth_token: String,
52    auth_header: Authorization<Bearer>,
53    http_client: hyper::Client<HttpsConnector<HttpConnector>>,
54}
55
56impl Client {
57    pub fn new(
58        api_type: ApiType,
59        app_key: &str,
60        auth_token: &str
61    ) -> Client {
62        Client {
63            api_type: api_type,
64            app_key: app_key.to_string(),
65            auth_token: auth_token.to_string(),
66            auth_header: Authorization::bearer(auth_token).unwrap(),
67            http_client: hyper::Client::builder().build(HttpsConnector::new()),
68        }
69    }
70
71    async fn send_request(
72        &self,
73        method: Method,
74        url: &str,
75        body: Body,
76    ) -> Result<(), BigPandaError> {
77        let mut request = hyper::Request::builder()
78            .method(method)
79            .uri(&*url)
80            .body(body)
81            .unwrap();
82
83        request.headers_mut().typed_insert(ContentType::json());
84        request.headers_mut().typed_insert(self.auth_header.clone());
85
86        // BigPanda's Change API is unique and requires an app key header
87        if matches!(self.api_type, ApiType::Change) {
88            request.headers_mut()
89                .append("x-bp-app-key", self.app_key.parse().unwrap());
90        }
91
92        let response = self
93            .http_client
94            .request(request)
95            .await
96            .map_err(BigPandaError::NetworkError)?;
97
98        match response.status() {
99            StatusCode::CREATED | StatusCode::OK | StatusCode::NO_CONTENT => {}
100            error => return Err(BigPandaError::HTTPError(error)),
101        };
102
103        Ok(())
104    }
105}