use client::{Client, MDataInfo};
use crypto::shared_secretbox;
use errors::CoreError;
use futures::{Future, IntoFuture};
use maidsafe_utilities::serialisation::{deserialise, serialise};
use nfs::{File, Mode, NfsError, NfsFuture, Reader, Writer};
use routing::{ClientError, EntryActions};
use self_encryption_storage::SelfEncryptionStorage;
use utils::FutureExt;
pub fn insert<S, T>(
client: Client<T>,
parent: MDataInfo,
name: S,
file: &File,
) -> Box<NfsFuture<()>>
where
S: AsRef<str>,
T: 'static,
{
let name = name.as_ref();
trace!("Inserting file with name '{}'", name);
serialise(&file)
.map_err(From::from)
.and_then(|encoded| {
let key = parent.enc_entry_key(name.as_bytes())?;
let value = parent.enc_entry_value(&encoded)?;
Ok((key, value))
})
.into_future()
.and_then(move |(key, value)| {
client.mutate_mdata_entries(
parent.name,
parent.type_tag,
EntryActions::new().ins(key, value, 0).into(),
)
})
.map_err(From::from)
.into_box()
}
pub fn fetch<S, T>(client: Client<T>, parent: MDataInfo, name: S) -> Box<NfsFuture<(u64, File)>>
where
S: AsRef<str>,
T: 'static,
{
parent
.enc_entry_key(name.as_ref().as_bytes())
.into_future()
.and_then(move |key| {
client
.get_mdata_value(parent.name, parent.type_tag, key)
.map(move |value| (value, parent))
})
.and_then(move |(value, parent)| {
let plaintext = parent.decrypt(&value.content)?;
let file = deserialise(&plaintext)?;
Ok((value.entry_version, file))
})
.map_err(convert_error)
.into_box()
}
pub fn read<T: 'static>(
client: Client<T>,
file: &File,
encryption_key: Option<shared_secretbox::Key>,
) -> Box<NfsFuture<Reader<T>>> {
trace!("Reading file {:?}", file);
Reader::new(
client.clone(),
SelfEncryptionStorage::new(client),
file,
encryption_key,
)
}
pub fn delete<S, T>(
client: &Client<T>,
parent: &MDataInfo,
name: S,
version: u64,
) -> Box<NfsFuture<()>>
where
S: AsRef<str>,
T: 'static,
{
let name = name.as_ref();
trace!("Deleting file with name {}.", name);
let key = fry!(parent.enc_entry_key(name.as_bytes()));
client
.mutate_mdata_entries(
parent.name,
parent.type_tag,
EntryActions::new().del(key, version).into(),
)
.map_err(convert_error)
.into_box()
}
pub fn update<S, T>(
client: Client<T>,
parent: MDataInfo,
name: S,
file: &File,
version: u64,
) -> Box<NfsFuture<()>>
where
S: AsRef<str>,
T: 'static,
{
let name = name.as_ref();
trace!("Updating file with name '{}'", name);
let client2 = client.clone();
serialise(&file)
.map_err(From::from)
.and_then(|encoded| {
let key = parent.enc_entry_key(name.as_bytes())?;
let content = parent.enc_entry_value(&encoded)?;
Ok((key, content))
})
.into_future()
.and_then(move |(key, content)| if version != 0 {
ok!((key, content, version, parent))
} else {
client
.get_mdata_value(parent.name, parent.type_tag, key.clone())
.map(move |value| (key, content, value.entry_version + 1, parent))
.into_box()
})
.and_then(move |(key, content, version, parent)| {
client2.mutate_mdata_entries(
parent.name,
parent.type_tag,
EntryActions::new().update(key, content, version).into(),
)
})
.map_err(convert_error)
.into_box()
}
pub fn write<T>(
client: Client<T>,
file: File,
mode: Mode,
encryption_key: Option<shared_secretbox::Key>,
) -> Box<NfsFuture<Writer<T>>>
where
T: 'static,
{
trace!("Creating a writer for a file");
Writer::new(
client.clone(),
SelfEncryptionStorage::new(client),
file,
mode,
encryption_key,
)
}
fn convert_error(err: CoreError) -> NfsError {
match err {
CoreError::RoutingClientError(ClientError::NoSuchEntry) => NfsError::FileNotFound,
_ => NfsError::from(err),
}
}