use std::collections::HashMap;
use std::io::Read;
use url::percent_encoding::{ utf8_percent_encode, DEFAULT_ENCODE_SET };
use std::convert::{ From, AsRef };
use serde_json::builder::ObjectBuilder;
use serde_json as json;
use ::error::Error;
header! { (PhantPrivateKey, "Phant-Private-Key") => [String] }
pub struct StreamSpec {
pub title: String,
pub description: String,
pub fields: Vec<String>,
pub hidden: bool,
pub alias: Option<String>,
pub tags: Option<Vec<String>>
}
impl StreamSpec {
fn serialize(&self) -> String {
let mut object_builder = ObjectBuilder::new()
.insert("title".to_string(), &self.title)
.insert("description".to_string(), &self.description)
.insert("fields".to_string(), self.fields.join(","))
.insert("hidden".to_string(), if self.hidden { 1 } else { 0 });
if let Some(ref alias) = self.alias {
object_builder = object_builder.insert(
"alias".to_string(),
&alias);
}
if let Some(ref tags) = self.tags {
if tags.len() > 0 {
object_builder = object_builder.insert(
"tags".to_string(),
tags.join(","));
}
}
json::to_string(&object_builder.build()).ok().unwrap()
}
}
#[derive(Debug)]
pub struct Phant {
hostname: String,
public_key: String,
private_key: String,
delete_key: Option<String>,
data: HashMap<String, String>
}
impl Phant {
pub fn create_stream(hostname: &str, spec: StreamSpec) -> Result<Phant, Error> {
let serialized_spec = spec.serialize();
let mut response = try!(::web::create_stream(&hostname.to_string(), &serialized_spec));
let mut response_body = String::new();
try!(response.read_to_string(&mut response_body));
let data: json::Value = json::from_str(&response_body).unwrap();
let data_object = data.as_object().unwrap();
let success_value = data_object.get("success").unwrap();
match success_value.as_bool().unwrap() {
true => {
let public_key_value = data_object.get("publicKey").unwrap();
let private_key_value = data_object.get("privateKey").unwrap();
let delete_key_value = data_object.get("deleteKey").unwrap();
Ok(Phant {
hostname: hostname.to_string(),
public_key: public_key_value.as_str().unwrap().to_string(),
private_key: private_key_value.as_str().unwrap().to_string(),
delete_key: Some(delete_key_value.as_str().unwrap().to_string()),
data: HashMap::new()
})
}
false => {
let message_value = data_object.get("message").unwrap();
Err(Error::Phant(message_value.as_str().unwrap().to_string()))
}
}
}
pub fn new(
hostname: &str,
public_key: &str,
private_key: &str,
delete_key: Option<&str>) -> Phant {
Phant {
hostname: String::from(hostname),
public_key: String::from(public_key),
private_key: String::from(private_key),
delete_key: delete_key.map(|dk| dk.to_string()),
data: HashMap::new()
}
}
pub fn delete_stream(&self) -> Result<(), Error> {
if let Some(ref delete_key) = self.delete_key {
try!(::web::delete_stream(
&self.hostname,
&self.public_key,
&delete_key));
Ok(())
} else {
Err(Error::Phant("Delete key not provided".to_string()))
}
}
pub fn add<T: ToString>(&mut self, key: &str, value: T) {
self.data.insert(key.to_string(), value.to_string());
}
pub fn push(&mut self) -> Result<String, Error> {
let query_string = self.data_query_string();
let mut post_response = try!(::web::push_data(&self.hostname,
&self.public_key,
&self.private_key,
&query_string));
let mut response_body = String::new();
try!(post_response.read_to_string(&mut response_body));
self.clear_local();
Ok(response_body)
}
pub fn clear_local(&mut self) {
self.data.clear();
}
pub fn clear_server(&mut self) -> Result<String, Error> {
let mut clear_response = try!(::web::clear_data(&self.hostname,
&self.public_key,
&self.private_key));
let mut response_body = String::new();
try!(clear_response.read_to_string(&mut response_body));
Ok(response_body)
}
pub fn get_url(&self) -> String {
format!("{}/input/{}?private_key={}&{}", self.hostname, self.public_key, self.private_key, self.data_query_string())
}
pub fn row_data(&self) -> HashMap<String, String> {
self.data.clone()
}
pub fn public_key(&self) -> String {
self.public_key.clone()
}
pub fn private_key(&self) -> String {
self.private_key.clone()
}
pub fn delete_key(&self) -> Option<String> {
self.delete_key.clone()
}
fn data_query_string(&self) -> String {
let mut result_list = Vec::new();
for (key, value) in self.data.iter() {
result_list.push(format!("{}={}", key, value));
}
utf8_percent_encode(result_list.join("&").as_ref(), DEFAULT_ENCODE_SET).to_string()
}
}
#[cfg(test)]
mod test {
use super::Phant;
#[test]
fn test_get_url() {
let expected = "https://data.com/input/pub?private_key=priv&color=red".to_string();
let p = basic_phant();
assert_eq!(p.row_data().len(), 1);
assert_eq!(p.get_url(), expected);
assert_eq!(p.row_data().len(), 1);
}
#[test]
fn test_row_data() {
let expected_key = "color".to_string();
let expected_value = "red".to_string();
let p = basic_phant();
let mut row_data = p.row_data();
assert_eq!(row_data.len(), 1);
assert_eq!(row_data[&expected_key], expected_value);
row_data.insert("size".to_string(), "large".to_string());
assert_eq!(p.row_data().len(), 1);
}
#[test]
fn test_overwrite_column() {
let key = "color".to_string();
let first_value = "red".to_string();
let second_value = "green".to_string();
let mut p = basic_phant();
assert_eq!(p.row_data()[&key], first_value);
p.add(&key, &second_value);
assert_eq!(p.row_data().len(), 1);
assert_eq!(p.row_data()[&key], second_value);
}
#[test]
fn test_clear_local() {
let mut p = basic_phant();
assert!(p.row_data().len() > 0);
p.clear_local();
assert_eq!(p.row_data().len(), 0);
}
fn basic_phant() -> Phant {
let mut p = Phant::new("https://data.com", "pub", "priv", None);
p.add("color", "red");
p
}
}