#![warn(missing_docs)]
use std::cmp::max;
use std::str::FromStr;
use num_bigint::BigUint;
use serde::Deserialize;
use serde::Serialize;
use super::subring::Subring;
use crate::consts::VNODE_DATA_MAX_LEN;
use crate::dht::Did;
use crate::ecc::HashStr;
use crate::error::Error;
use crate::error::Result;
use crate::message::Encoded;
use crate::message::Encoder;
use crate::message::MessagePayload;
use crate::message::MessageVerificationExt;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum VNodeType {
Data,
Subring,
RelayMessage,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum VNodeOperation {
Overwrite(VirtualNode),
Extend(VirtualNode),
Touch(VirtualNode),
JoinSubring(String, Did),
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct VirtualNode {
pub did: Did,
pub data: Vec<Encoded>,
pub kind: VNodeType,
}
impl VirtualNode {
pub fn gen_did(topic: &str) -> Result<Did> {
let hash: HashStr = topic.into();
let did = Did::from_str(&hash.inner());
tracing::debug!("gen_did: topic: {}, did: {:?}", topic, did);
did
}
}
impl VNodeOperation {
pub fn did(&self) -> Result<Did> {
Ok(match self {
VNodeOperation::Overwrite(vnode) => vnode.did,
VNodeOperation::Extend(vnode) => vnode.did,
VNodeOperation::Touch(vnode) => vnode.did,
VNodeOperation::JoinSubring(name, _) => VirtualNode::gen_did(name)?,
})
}
pub fn kind(&self) -> VNodeType {
match self {
VNodeOperation::Overwrite(vnode) => vnode.kind,
VNodeOperation::Extend(vnode) => vnode.kind,
VNodeOperation::Touch(vnode) => vnode.kind,
VNodeOperation::JoinSubring(..) => VNodeType::Subring,
}
}
pub fn gen_default_vnode(self) -> Result<VirtualNode> {
match self {
VNodeOperation::JoinSubring(name, did) => Subring::new(&name, did)?.try_into(),
_ => Ok(VirtualNode {
did: self.did()?,
data: vec![],
kind: self.kind(),
}),
}
}
}
impl TryFrom<MessagePayload> for VirtualNode {
type Error = Error;
fn try_from(msg: MessagePayload) -> Result<Self> {
let did = BigUint::from(msg.signer()) + BigUint::from(1u16);
let data = msg.encode()?;
Ok(Self {
did: did.into(),
data: vec![data],
kind: VNodeType::RelayMessage,
})
}
}
impl TryFrom<(String, Encoded)> for VirtualNode {
type Error = Error;
fn try_from((topic, e): (String, Encoded)) -> Result<Self> {
Ok(Self {
did: Self::gen_did(&topic)?,
data: vec![e],
kind: VNodeType::Data,
})
}
}
impl TryFrom<(String, String)> for VirtualNode {
type Error = Error;
fn try_from((topic, s): (String, String)) -> Result<Self> {
let encoded_message = s.encode()?;
(topic, encoded_message).try_into()
}
}
impl TryFrom<String> for VirtualNode {
type Error = Error;
fn try_from(topic: String) -> Result<Self> {
(topic.clone(), topic).try_into()
}
}
impl VirtualNode {
pub fn affine(&self, scalar: u16) -> Vec<VirtualNode> {
self.did
.rotate_affine(scalar)
.iter()
.map(|did| self.clone_with_did(did.to_owned()))
.collect()
}
pub fn clone_with_did(&self, did: Did) -> Self {
let mut vnode = self.clone();
vnode.did = did;
vnode
}
pub fn operate(&self, op: VNodeOperation) -> Result<Self> {
match op {
VNodeOperation::Overwrite(vnode) => self.overwrite(vnode),
VNodeOperation::Extend(vnode) => self.extend(vnode),
VNodeOperation::Touch(vnode) => self.touch(vnode),
VNodeOperation::JoinSubring(_, did) => self.join_subring(did),
}
}
pub fn overwrite(&self, other: Self) -> Result<Self> {
if self.kind != VNodeType::Data {
return Err(Error::VNodeNotOverwritable);
}
if self.kind != other.kind {
return Err(Error::VNodeKindNotEqual);
}
if self.did != other.did {
return Err(Error::VNodeDidNotEqual);
}
Ok(other)
}
pub fn extend(&self, other: Self) -> Result<Self> {
if self.kind != VNodeType::Data {
return Err(Error::VNodeNotAppendable);
}
if self.kind != other.kind {
return Err(Error::VNodeKindNotEqual);
}
if self.did != other.did {
return Err(Error::VNodeDidNotEqual);
}
let trim_num = max(
0,
(self.data.len() + other.data.len()) as i64 - VNODE_DATA_MAX_LEN as i64,
) as usize;
let mut data = self.data.iter().skip(trim_num).cloned().collect::<Vec<_>>();
data.extend_from_slice(&other.data);
Ok(Self {
did: self.did,
data,
kind: self.kind,
})
}
pub fn touch(&self, other: Self) -> Result<Self> {
if self.kind != VNodeType::Data {
return Err(Error::VNodeNotAppendable);
}
if self.kind != other.kind {
return Err(Error::VNodeKindNotEqual);
}
if self.did != other.did {
return Err(Error::VNodeDidNotEqual);
}
let remains = self
.data
.iter()
.filter(|e| !other.data.contains(e))
.collect::<Vec<_>>();
let trim_num = max(
0,
(remains.len() + other.data.len()) as i64 - VNODE_DATA_MAX_LEN as i64,
) as usize;
let mut data = remains
.into_iter()
.skip(trim_num)
.cloned()
.collect::<Vec<_>>();
data.extend_from_slice(&other.data);
Ok(Self {
did: self.did,
data,
kind: self.kind,
})
}
pub fn join_subring(&self, did: Did) -> Result<Self> {
if self.kind != VNodeType::Subring {
return Err(Error::VNodeNotJoinable);
}
let mut subring: Subring = self.clone().try_into()?;
subring.finger.join(did);
subring.try_into()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vnode_extend_over_max_len() {
let topic = "test0".to_string();
let mut vnode: VirtualNode = topic.clone().try_into().unwrap();
assert_eq!(vnode.data.len(), 1);
for i in 1..VNODE_DATA_MAX_LEN {
let topic = topic.clone();
let data = format!("test{}", i);
let other = (topic, data).try_into().unwrap();
vnode = vnode.extend(other).unwrap();
assert_eq!(vnode.data.len(), i + 1);
}
for i in VNODE_DATA_MAX_LEN..VNODE_DATA_MAX_LEN + 10 {
let topic = topic.clone();
let data = format!("test{}", i);
let other = (topic, data.clone()).try_into().unwrap();
vnode = vnode.extend(other).unwrap();
assert_eq!(vnode.data.len(), VNODE_DATA_MAX_LEN);
assert_eq!(
vnode.data[0].decode::<String>().unwrap(),
format!("test{}", i - VNODE_DATA_MAX_LEN + 1)
);
assert_eq!(
vnode.data[VNODE_DATA_MAX_LEN - 1]
.decode::<String>()
.unwrap(),
data
);
}
}
}