use super::util::{get_hashmap_keys, get_micro_unix_timestemp, get_now_time, NodeTokens, token2string};
use anyhow::{anyhow, Error, Ok, Result};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use ring::digest;
use std::collections::HashMap;
use std::mem;
pub type VoterType = fn(&HashMap<String, PathNode>, &mut Context) -> Result<bool>;
pub type CheckerType = fn(&HashMap<String, PathNode>, &mut Context) -> Result<bool>;
#[derive(Debug)]
pub struct Context {
pub deep: u64,
pub is_ignore_dynamic_arg: bool,
pub is_need_cluster: bool,
}
impl Context {
pub fn new() -> Context {
Context {
deep: 0,
is_ignore_dynamic_arg: false,
is_need_cluster: true,
}
}
}
#[derive(Debug, Clone)]
pub struct PathNode {
pub name: String, pub index_name: String, pub id: u64, pub first_insert_time: u64, pub last_search_time: u64, pub match_counter: u64, pub try_cluster_time: u64, pub next_nodes: HashMap<String, PathNode>, pub is_end: bool,
}
impl PathNode {
pub fn new(name: &str) -> PathNode {
let now = get_now_time();
let pathnode = PathNode {
name: name.to_owned().clone(),
index_name: "".to_string(),
id: 0,
first_insert_time: now,
last_search_time: now,
match_counter: 0,
try_cluster_time: now,
next_nodes: HashMap::new(),
is_end: false,
};
pathnode
}
pub fn build(
name: &str,
index_name: String,
id: u64,
first_insert_time: u64,
last_search_time: u64,
match_counter: u64,
is_end: bool,
) -> PathNode {
let pathnode = PathNode {
name: name.to_string(),
id: id,
first_insert_time: first_insert_time,
last_search_time: last_search_time,
match_counter: match_counter,
try_cluster_time: 0,
next_nodes: HashMap::new(),
index_name: index_name.to_string(),
is_end: is_end,
};
return pathnode;
}
pub fn set_index_point(&mut self, index_name: String) -> Result<()> {
let id = PathNode::get_init_id(&self.name, index_name.to_string())?;
self.id = id;
self.index_name = index_name;
Ok(())
}
fn get_init_id(node_name: &str, index_name: String) -> Result<u64> {
let now = get_micro_unix_timestemp();
let rand_string: String = thread_rng()
.sample_iter(Alphanumeric)
.take(128)
.map(char::from)
.collect();
let hash_result = digest::digest(
&digest::SHA256,
format!("{}{}{}{}", now, index_name, node_name, rand_string).as_bytes(),
);
let b: u64;
let arr: [u8; 8] = hash_result.as_ref()[0..8].try_into()?;
unsafe {
b = mem::transmute::<[u8; 8], u64>(arr);
}
Ok(b)
}
pub fn is_exists(&self, name: &str) -> bool {
return self.next_nodes.contains_key(name);
}
pub fn get_mut(&mut self, name: &str) -> Option<&mut PathNode> {
if self.is_exists(name) {
self.get_mut_strictly(name)
} else if self.is_exists("*") {
self.get_mut_strictly("*")
} else {
return None;
}
}
pub fn get(&self, name: &str) -> Option<&PathNode> {
if self.is_exists(name) {
self.get_strictly(name)
} else if self.is_exists("*") {
self.get_strictly("*")
} else {
None
}
}
pub fn get_strictly(&self, name: &str) -> Option<&PathNode> {
self.next_nodes.get(name)
}
pub fn get_mut_strictly(&mut self, name: &str) -> Option<&mut PathNode> {
self.next_nodes.get_mut(name)
}
pub fn get_mut_by_node_list(&mut self, node_list: &[&str], context: &mut Context) -> Option<&mut PathNode> {
if node_list.len() == 0 {
return Some(self)
}
let node_name = node_list[0];
let new_node_list = &node_list[1..];
let get_result = if context.is_ignore_dynamic_arg {
self.get_mut_strictly(node_name)
}
else {
self.get_mut(node_name)
};
return if let Some(node) = get_result {
Some(node.get_mut_by_node_list(new_node_list, context)?)
}
else {
None
};
}
pub fn merge_by_node_list(&mut self, node_list: &[&str], context: &mut Context) -> Result<()> {
let r = self.get_mut_by_node_list(node_list, context);
match r {
Some(node) => {
node.merge_node()
}
None => {
Err(anyhow!("merge_by_node_list: node not find"))
}
}
}
pub fn set_token_by_node_list(&mut self, node_list: &[&str], token_type: NodeTokens, clear_node: bool, context: &mut Context) -> Result<()> {
let r = self.get_mut_by_node_list(node_list, context);
match r {
Some(node) => {
if clear_node {
node.next_nodes.clear();
}
let token_str = &token2string(token_type);
if !node.is_exists(&token_str) {
node.add(token_str)
}
else {
Ok(())
}
}
None => {
Err(anyhow!("merge_by_node_list: node not find"))
}
}
}
pub fn add(&mut self, node_name: &str) -> Result<()> {
let mut new_node = PathNode::new(node_name);
new_node.set_index_point(self.index_name.to_string())?;
self.add_pathnode(node_name, new_node)?;
Ok(())
}
pub fn add_pathnode(&mut self, node_name: &str, node: PathNode) -> Result<()> {
let is_exists = self.is_exists(node_name);
if is_exists {
panic!("node_name已存在, 该方法不允许进行覆盖");
} else {
self.next_nodes.insert(node_name.to_string(), node);
}
Ok(())
}
pub fn success_match(&mut self) -> Result<()> {
self.match_counter += 1;
self.last_search_time = get_now_time();
Ok(())
}
pub fn add_by_node_list(
&mut self,
node_list: &[&str],
context: &mut Context,
voter: VoterType,
checker: CheckerType,
) -> Result<()> {
context.deep += 1;
if node_list.len() == 0 {
if self.is_end == false {
self.is_end = true;
}
return Ok(());
}
let node_name = node_list[0];
let new_node_list = &node_list[1..];
let get_result = if context.is_ignore_dynamic_arg {
self.get_mut_strictly(node_name)
}
else {
self.get_mut(node_name)
};
match get_result {
Some(node) => {
node.success_match()?;
node
},
None => {
self.add(node_name)?;
self.get_mut(node_name).unwrap()
}
}
.add_by_node_list(new_node_list, context, voter, checker)?;
context.deep -= 1;
if context.is_need_cluster {
self.merge_node_by_func(voter, checker, context).unwrap();
}
Ok(())
}
pub fn get_next_ids_json_string(&self) -> Result<String> {
let mut ids: Vec<u64> = vec![];
for node in self.next_nodes.values() {
ids.push(node.id);
}
Ok(serde_json::to_string(&ids)?)
}
pub fn sync_read_callback(&self, callback: fn(&Self, &mut Context)->Result<()>, context: &mut Context, is_need_traversal: bool) -> Result<()> {
callback(&self, context)?;
if is_need_traversal {
for node in self.next_nodes.values() {
node.sync_read_callback(callback, context, is_need_traversal)?;
}
}
Ok(())
}
pub fn try_match_rule(&self, node_list: &[&str]) -> Result<String> {
if node_list.len() == 0 && self.is_end == true {
return Ok(format!("{}/", self.name.clone()));
} else if node_list.len() == 0 && self.is_end == false {
return Err(Error::msg(format!(
"规则匹配失败, node_name: {}, 为非终止节点",
self.name
)));
}
let node_name = node_list[0];
let new_node_list = &node_list[1..];
if self.is_exists(node_name) {
let path = self
.get(node_name)
.unwrap()
.try_match_rule(new_node_list)?;
Ok(format!("{}/{}", self.name.clone(), path))
} else if self.is_exists("*") {
let path = self.get("*").unwrap().try_match_rule(new_node_list)?;
Ok(format!("{}/{}", self.name.clone(), path))
} else {
Err(Error::msg(format!(
"规则匹配失败, node_name: {}, 不存在",
node_name
)))
}
}
fn merge_node(&mut self) -> Result<()> {
let mut new_next: HashMap<String, PathNode> = HashMap::new();
let next_nodes = &mut self.next_nodes;
let keys: Vec<String> = get_hashmap_keys(next_nodes);
for key in keys {
let level_1_child_node = next_nodes.get_mut(&key).unwrap();
let one_node_next = &mut level_1_child_node.next_nodes;
let level_2_keys: Vec<String> = get_hashmap_keys(one_node_next);
for node_name in level_2_keys {
let node = one_node_next.remove(&node_name).unwrap();
new_next.insert(node_name.to_owned(), node);
}
}
self.next_nodes.clear();
self.add("*")?;
let new_node = self.next_nodes.get_mut("*").unwrap();
new_node.next_nodes = new_next;
if new_node.next_nodes.len() == 0 {
new_node.is_end = true
}
Ok(())
}
pub fn merge_node_by_func(
&mut self,
voter: VoterType,
checker: CheckerType,
context: &mut Context,
) -> Result<()> {
let vote_result = voter(&self.next_nodes, context).unwrap();
if vote_result {
if checker(&self.next_nodes, context).unwrap() {
self.merge_node()?;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
}