use reqwest::header;
use serde::de::DeserializeOwned;
use uuid::Uuid;
use endpoints::{DefaultClient, GeenyApi};
use errors::*;
use models::*;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ThingsApi(GeenyApi);
impl Default for ThingsApi {
fn default() -> Self {
Self::new("https://labs.geeny.io".into(), 443)
}
}
impl ThingsApi {
pub fn new(host: String, port: u16) -> Self {
ThingsApi(GeenyApi {
host: host,
port: port,
client: DefaultClient::default(),
})
}
pub fn create_message_type(
&self,
token: &str,
req: &MessageTypeRequest,
) -> Result<MessageType> {
let mut rreq = self.0
.client
.0
.post(&self.0.endpoint("/things/api/v1/messageTypes"));
rreq.json(req);
info!("Requesting: {:?}", rreq);
rreq.header(header::Authorization(format!("JWT {}", token)));
let mut resp = rreq.send()?;
info!("Response: {:?}", resp);
Ok(resp.json().chain_err(|| "Failed to deserialize")?)
}
pub fn create_thing_type(&self, token: &str, req: &ThingTypeRequest) -> Result<ThingType> {
let mut rreq = self.0
.client
.0
.post(&self.0.endpoint("/things/api/v1/thingTypes"));
rreq.json(req);
info!("Requesting: {:?}", rreq);
rreq.header(header::Authorization(format!("JWT {}", token)));
let mut resp = rreq.send()?;
info!("Response: {:?}", resp);
Ok(resp.json().chain_err(|| "Failed to deserialize")?)
}
pub fn create_thing(&self, token: &str, req: &ThingRequest) -> Result<Thing> {
let mut rreq = self.0
.client
.0
.post(&self.0.endpoint("/things/api/v1/things"));
rreq.json(req);
info!("Requesting: {:?}", rreq);
rreq.header(header::Authorization(format!("JWT {}", token)));
let mut resp = rreq.send()?;
info!("Response: {:?}", resp);
Ok(resp.json().chain_err(|| "Failed to deserialize")?)
}
pub fn delete_thing(&self, token: &str, id: &Uuid) -> Result<Thing> {
let mut rreq = self.0.client.0.delete(&self.0
.endpoint(&format!("/things/api/v1/things/{}", id.hyphenated())));
info!("Requesting: {:?}", rreq);
rreq.header(header::Authorization(format!("JWT {}", token)));
let mut resp = rreq.send()?;
info!("Response: {:?}", resp);
Ok(resp.json().chain_err(|| "Failed to deserialize")?)
}
pub fn get_thing_types(&self, token: &str) -> Result<Vec<ThingType>> {
get_all(&self.0, token, "/things/api/v1/thingTypes")
}
pub fn get_message_types(&self, token: &str) -> Result<Vec<MessageType>> {
get_all(&self.0, token, "/things/api/v1/messageTypes")
}
pub fn get_things(&self, token: &str) -> Result<Vec<Thing>> {
get_all(&self.0, token, "/things/api/v1/things")
}
pub fn get_thing_type_resources(&self, token: &str, ttid: &Uuid) -> Result<Vec<Resource>> {
get_all(
&self.0,
token,
&format!("/things/api/v1/thingTypes/{}/resources", ttid.hyphenated()),
)
}
pub fn get_thing_by_serial(&self, token: &str, serial: &str) -> Result<Option<Thing>> {
let things = self.get_things(token)?;
let found = things.iter().find(|i| i.serial_number == serial);
let thing = match found {
Some(t) => Some(t.to_owned()),
None => None,
};
Ok(thing)
}
}
fn get_all<T>(api: &GeenyApi, token: &str, endpoint: &str) -> Result<Vec<T>>
where
T: DeserializeOwned,
{
let mut response = vec![];
loop {
let url = format!("{}?offset={}", endpoint, response.len());
let mut rreq = api.client.0.get(&api.endpoint(&url));
info!("Requesting: {:?}", rreq);
rreq.header(header::Authorization(format!("JWT {}", token)));
let mut resp = rreq.send()?;
info!("Response: {:?}", resp);
let mut data_resp = resp.json::<GenericResponse<T>>()
.chain_err(|| "Failed to deserialize")?;
let len = data_resp.data.len();
response.append(&mut data_resp.data);
if len != data_resp.meta.limit {
break;
}
}
Ok(response)
}
#[cfg(test)]
mod test {
use super::*;
use serde_json;
use models::*;
#[test]
fn serialize_test() {
let api = ThingsApi::default();
let s = serde_json::to_string(&api).unwrap();
assert_eq!(s, "{\"host\":\"https://labs.geeny.io\",\"port\":443}");
}
#[test]
fn deserialize_test() {
let api = ThingsApi::default();
let de_api: ThingsApi = serde_json::from_str(
r#"
{
"host": "https://labs.geeny.io",
"port": 443
}
"#,
).unwrap();
assert_eq!(api.0.host, de_api.0.host);
assert_eq!(api.0.port, de_api.0.port);
}
#[ignore]
#[test]
fn basic_test() {
let token = get_token();
let api = ThingsApi::default();
assert!(api.get_things(&token).is_ok());
}
fn get_token() -> String {
use std::env;
use endpoints::connect::ConnectApi;
let user = env::var("TEST_USER").unwrap();
let pass = env::var("TEST_PASSWORD").unwrap();
let api = ConnectApi::default();
let req = AuthLoginRequest {
email: user,
password: pass,
};
api.login(&req).unwrap().token
}
}