use crate::client_handler::COST_OF_PUT;
use crate::{rpc::Rpc, vault::Init, Result};
use bincode;
use log::{error, trace};
use pickledb::{PickleDb, PickleDbDumpPolicy};
use rand::{distributions::Standard, thread_rng, Rng};
use safe_nd::{
ClientPublicId, Coins, IDataAddress, PublicId, PublicKey, Request, Result as NdResult, XorName,
};
use serde::Serialize;
use std::{borrow::Cow, fs, path::Path};
use unwrap::unwrap;
pub(crate) fn new_db<D: AsRef<Path>, N: AsRef<Path>>(
db_dir: D,
db_name: N,
init_mode: Init,
) -> Result<PickleDb> {
let db_path = db_dir.as_ref().join(db_name);
if init_mode == Init::New {
trace!("Creating database at {}", db_path.display());
fs::create_dir_all(db_dir)?;
let mut db = PickleDb::new_bin(db_path, PickleDbDumpPolicy::AutoDump);
db.set("", &"")?;
let _ = db.rem("")?;
return Ok(db);
}
trace!("Loading database at {}", db_path.display());
let result = PickleDb::load_bin(db_path.clone(), PickleDbDumpPolicy::AutoDump);
if let Err(ref error) = &result {
error!("Failed to load {}: {}", db_path.display(), error);
}
Ok(result?)
}
pub(crate) fn random_vec(size: usize) -> Vec<u8> {
thread_rng().sample_iter(&Standard).take(size).collect()
}
pub(crate) fn serialise<T: Serialize>(data: &T) -> Vec<u8> {
unwrap!(bincode::serialize(data))
}
pub(crate) fn owner(public_id: &PublicId) -> Option<&ClientPublicId> {
match public_id {
PublicId::Node(_) => None,
PublicId::Client(pub_id) => Some(pub_id),
PublicId::App(pub_id) => Some(pub_id.owner()),
}
}
pub(crate) fn client(public_id: &PublicId) -> Option<&ClientPublicId> {
match public_id {
PublicId::Node(_) | PublicId::App(_) => None,
PublicId::Client(pub_id) => Some(pub_id),
}
}
pub(crate) fn own_key(public_id: &PublicId) -> Option<&PublicKey> {
match public_id {
PublicId::Node(_) => None,
PublicId::Client(ref client) => Some(client.public_key()),
PublicId::App(ref app) => Some(app.public_key()),
}
}
pub(crate) fn requester_address(rpc: &Rpc) -> &XorName {
match rpc {
Rpc::Request { ref requester, .. } | Rpc::Response { ref requester, .. } => {
requester.name()
}
}
}
pub(crate) fn destination_address(request: &Request) -> Option<Cow<XorName>> {
use Request::*;
match request {
PutIData(ref data) => Some(Cow::Borrowed(data.name())),
GetIData(ref address) => Some(Cow::Borrowed(address.name())),
DeleteUnpubIData(ref address) => Some(Cow::Borrowed(address.name())),
PutMData(ref data) => Some(Cow::Borrowed(data.name())),
GetMData(ref address)
| GetMDataValue { ref address, .. }
| DeleteMData(ref address)
| GetMDataShell(ref address)
| GetMDataVersion(ref address)
| ListMDataEntries(ref address)
| ListMDataKeys(ref address)
| ListMDataValues(ref address)
| SetMDataUserPermissions { ref address, .. }
| DelMDataUserPermissions { ref address, .. }
| ListMDataPermissions(ref address)
| ListMDataUserPermissions { ref address, .. }
| MutateMDataEntries { ref address, .. } => Some(Cow::Borrowed(address.name())),
PutAData(ref data) => Some(Cow::Borrowed(data.name())),
GetAData(ref address)
| GetADataValue { ref address, .. }
| GetADataShell { ref address, .. }
| DeleteAData(ref address)
| GetADataRange { ref address, .. }
| GetADataIndices(ref address)
| GetADataLastEntry(ref address)
| GetADataPermissions { ref address, .. }
| GetPubADataUserPermissions { ref address, .. }
| GetUnpubADataUserPermissions { ref address, .. }
| GetADataOwners { ref address, .. }
| AddPubADataPermissions { ref address, .. }
| AddUnpubADataPermissions { ref address, .. }
| SetADataOwner { ref address, .. } => Some(Cow::Borrowed(address.name())),
AppendSeq { ref append, .. } | AppendUnseq(ref append) => {
Some(Cow::Borrowed(append.address.name()))
}
TransferCoins {
ref destination, ..
} => Some(Cow::Borrowed(destination)),
CreateBalance {
ref new_balance_owner,
..
} => Some(Cow::Owned(XorName::from(*new_balance_owner))),
CreateLoginPacket(login_packet) => Some(Cow::Borrowed(login_packet.destination())),
CreateLoginPacketFor {
new_login_packet, ..
} => Some(Cow::Borrowed(new_login_packet.destination())),
UpdateLoginPacket(login_packet) => Some(Cow::Borrowed(login_packet.destination())),
GetLoginPacket(ref name) => Some(Cow::Borrowed(name)),
GetBalance | ListAuthKeysAndVersion | InsAuthKey { .. } | DelAuthKey { .. } => None,
}
}
pub(crate) enum AuthorisationKind {
GetPub,
GetUnpub,
GetBalance,
Mut,
ManageAppKeys,
TransferCoins,
MutAndTransferCoins,
}
pub(crate) fn authorisation_kind(request: &Request) -> AuthorisationKind {
use Request::*;
match request {
PutIData(_)
| DeleteUnpubIData(_)
| PutMData(_)
| DeleteMData(_)
| SetMDataUserPermissions { .. }
| DelMDataUserPermissions { .. }
| MutateMDataEntries { .. }
| PutAData(_)
| DeleteAData(_)
| AddPubADataPermissions { .. }
| AddUnpubADataPermissions { .. }
| SetADataOwner { .. }
| AppendSeq { .. }
| AppendUnseq(_)
| CreateLoginPacket(_)
| UpdateLoginPacket(_) => AuthorisationKind::Mut,
CreateBalance { amount, .. } | CreateLoginPacketFor { amount, .. } => {
if amount.as_nano() == 0 {
AuthorisationKind::Mut
} else {
AuthorisationKind::MutAndTransferCoins
}
}
TransferCoins { .. } => AuthorisationKind::TransferCoins,
GetIData(IDataAddress::Pub(_)) => AuthorisationKind::GetPub,
GetIData(IDataAddress::Unpub(_))
| GetMData(_)
| GetMDataValue { .. }
| GetMDataShell(_)
| GetMDataVersion(_)
| ListMDataEntries(_)
| ListMDataKeys(_)
| ListMDataValues(_)
| ListMDataPermissions(_)
| ListMDataUserPermissions { .. }
| GetLoginPacket(_) => AuthorisationKind::GetUnpub,
GetAData(address)
| GetADataValue { address, .. }
| GetADataShell { address, .. }
| GetADataRange { address, .. }
| GetADataIndices(address)
| GetADataLastEntry(address)
| GetADataPermissions { address, .. }
| GetPubADataUserPermissions { address, .. }
| GetUnpubADataUserPermissions { address, .. }
| GetADataOwners { address, .. } => {
if address.is_pub() {
AuthorisationKind::GetPub
} else {
AuthorisationKind::GetUnpub
}
}
GetBalance => AuthorisationKind::GetBalance,
ListAuthKeysAndVersion | InsAuthKey { .. } | DelAuthKey { .. } => {
AuthorisationKind::ManageAppKeys
}
}
}
pub(crate) fn get_refund_for_put<T>(result: &NdResult<T>) -> Option<Coins> {
if result.is_err() {
Some(*COST_OF_PUT)
} else {
None
}
}