#![allow(dead_code)]
use chunk_store::ChunkStore;
use routing_types::*;
use transfer_parser::transfer_tags::SD_MANAGER_ACCOUNT_TAG;
pub struct StructuredDataManager {
chunk_store_ : ChunkStore
}
impl StructuredDataManager {
pub fn new() -> StructuredDataManager {
StructuredDataManager { chunk_store_: ChunkStore::with_max_disk_usage(1073741824) }
}
pub fn handle_get(&self, name: NameType) ->Result<Vec<MethodCall>, ResponseError> {
let data = self.chunk_store_.get(name);
if data.len() == 0 {
return Err(ResponseError::Abort);
}
let sd : StructuredData = try!(::routing::utils::decode(&data));
Ok(vec![MethodCall::Reply { data: Data::StructuredData(sd) }])
}
pub fn handle_put(&mut self, structured_data: StructuredData) ->Result<Vec<MethodCall>, ResponseError> {
if self.chunk_store_.has_chunk(structured_data.name()) {
Err(ResponseError::FailedRequestForData(Data::StructuredData(structured_data)))
} else {
let serialised_data = try!(::routing::utils::encode(&structured_data));
self.chunk_store_.put(structured_data.name(), serialised_data);
Ok(vec![MethodCall::Reply { data: Data::StructuredData(structured_data) }])
}
}
pub fn handle_post(&mut self, in_coming_data: StructuredData) ->Result<Vec<MethodCall>, ResponseError> {
let data = self.chunk_store_.get(in_coming_data.name());
if data.len() == 0 {
return Err(ResponseError::InvalidRequest(Data::StructuredData(in_coming_data)));
}
let mut sd : StructuredData = try!(::routing::utils::decode(&data));
debug!("sd_manager updating {:?} to {:?}", sd, in_coming_data);
match sd.replace_with_other(in_coming_data.clone()) {
Ok(_) => {},
Err(_) => { return Err(ResponseError::InvalidRequest(Data::StructuredData(in_coming_data))); }
}
let serialised_data = try!(::routing::utils::encode(&sd));
self.chunk_store_.put(in_coming_data.name(), serialised_data);
Ok(vec![])
}
pub fn handle_account_transfer(&mut self, in_coming_sd: Vec<u8>) {
let sd : StructuredData = match ::routing::utils::decode(&in_coming_sd) {
Ok(result) => { result }
Err(_) => return
};
self.chunk_store_.delete(sd.name());
self.chunk_store_.put(sd.name(), in_coming_sd);
}
pub fn retrieve_all_and_reset(&mut self) -> Vec<MethodCall> {
let names = self.chunk_store_.names();
let mut actions = Vec::with_capacity(names.len());
for name in names {
let data = self.chunk_store_.get(name.clone());
actions.push(MethodCall::Refresh {
type_tag: SD_MANAGER_ACCOUNT_TAG,
from_group: name,
payload: data
});
}
self.chunk_store_ = ChunkStore::with_max_disk_usage(1073741824);
actions
}
}
#[cfg(test)]
mod test {
use super::*;
use sodiumoxide::crypto;
use routing_types::*;
#[test]
fn handle_put_get() {
let mut sd_manager = StructuredDataManager::new();
let name = NameType([3u8; 64]);
let value = generate_random_vec_u8(1024);
let keys = crypto::sign::gen_keypair();
let sdv = StructuredData::new(0, name, 0, value.clone(), vec![keys.0], vec![], Some(&keys.1)).ok().unwrap();
{
let put_result = sd_manager.handle_put(sdv.clone());
assert_eq!(put_result.is_ok(), true);
let mut calls = put_result.ok().unwrap();
assert_eq!(calls.len(), 1);
match calls.remove(0) {
MethodCall::Reply { data } => {
match data {
Data::StructuredData(sd) => {
assert_eq!(sd, sdv);
}
_ => panic!("Unexpected"),
}
}
_ => panic!("Unexpected"),
}
}
{
let data_name = NameType::new(sdv.name().0);
let get_result = sd_manager.handle_get(data_name);
assert_eq!(get_result.is_err(), false);
let mut calls = get_result.ok().unwrap();
assert_eq!(calls.len(), 1);
match calls.remove(0) {
MethodCall::Reply { data } => {
match data {
Data::StructuredData(sd) => {
assert_eq!(sd, sdv);
assert_eq!(sd.name(), StructuredData::compute_name(0, &NameType([3u8; 64])));
assert_eq!(*sd.get_data(), value);
}
_ => panic!("Unexpected"),
}
}
_ => panic!("Unexpected"),
}
}
}
#[test]
fn handle_post() {
let mut sd_manager = StructuredDataManager::new();
let name = NameType([3u8; 64]);
let value = generate_random_vec_u8(1024);
let keys = crypto::sign::gen_keypair();
let sdv = StructuredData::new(0, name, 0, value.clone(), vec![keys.0], vec![], Some(&keys.1)).ok().unwrap();
{ match sd_manager.handle_post(sdv.clone()) {
Err(result) => { assert_eq!(result, ResponseError::InvalidRequest(Data::StructuredData(sdv.clone()))); }
_ => panic!("Unexpected"),
}
}
{
let put_result = sd_manager.handle_put(sdv.clone());
assert_eq!(put_result.is_ok(), true);
let mut calls = put_result.ok().unwrap();
assert_eq!(calls.len(), 1);
match calls.remove(0) {
MethodCall::Reply { data } => {
match data {
Data::StructuredData(sd) => {
assert_eq!(sd, sdv);
}
_ => panic!("Unexpected"),
}
}
_ => panic!("Unexpected"),
}
}
{ let sdv_new = StructuredData::new(0, name, 3, value.clone(), vec![keys.0], vec![], Some(&keys.1)).ok().unwrap();
match sd_manager.handle_post(sdv_new.clone()) {
Err(result) => { assert_eq!(result, ResponseError::InvalidRequest(Data::StructuredData(sdv_new))); }
_ => panic!("Unexpected"),
}
}
{ let sdv_new = StructuredData::new(0, name, 1, value.clone(), vec![keys.0], vec![], Some(&keys.1)).ok().unwrap();
match sd_manager.handle_post(sdv_new.clone()) {
Ok(_) => {}
_ => panic!("Unexpected"),
}
}
let keys2 = crypto::sign::gen_keypair();
{ let sdv_new = StructuredData::new(0, name, 2, value.clone(), vec![keys2.0], vec![keys.0], Some(&keys2.1)).ok().unwrap();
match sd_manager.handle_post(sdv_new.clone()) {
Err(result) => { assert_eq!(result, ResponseError::InvalidRequest(Data::StructuredData(sdv_new))); }
_ => panic!("Unexpected"),
}
}
{ let sdv_new = StructuredData::new(0, name, 2, value.clone(), vec![keys2.0], vec![keys.0], Some(&keys.1)).ok().unwrap();
match sd_manager.handle_post(sdv_new.clone()) {
Ok(_) => {}
_ => panic!("Unexpected"),
}
}
}
#[test]
fn handle_account_transfer() {
let name = NameType([3u8; 64]);
let value = generate_random_vec_u8(1024);
let keys = crypto::sign::gen_keypair();
let sdv = StructuredData::new(0, name, 0, value, vec![keys.0], vec![], Some(&keys.1)).ok().unwrap();
let mut sd_manager = StructuredDataManager::new();
let serialised_data = match ::routing::utils::encode(&sdv) {
Ok(result) => result,
Err(_) => panic!("Unexpected"),
};
sd_manager.handle_account_transfer(serialised_data);
assert_eq!(sd_manager.chunk_store_.has_chunk(StructuredData::compute_name(0, &NameType([3u8; 64]))), true);
}
}