fusen-rs 0.8.11

RPC framework for service registration and discovery through API exposure, compatible with Dubbo3 protocol, intertunable with Java projects
Documentation
use crate::protocol::fusen::{request::Path, service::MethodInfo};
use async_recursion::async_recursion;
use std::{collections::HashMap, sync::Arc};
use tokio::sync::RwLock;

#[derive(Debug, Default)]
pub struct PathCache {
    path_cache: HashMap<String, Arc<MethodInfo>>,
    rest_trie: Trie,
}

impl PathCache {
    pub async fn seach(&self, path: &Path) -> Option<QueryResult> {
        let key = format!("{}:{}", path.method, path.path);
        if let Some(method_info) = self.path_cache.get(key.as_str()) {
            Some(QueryResult {
                method_info: method_info.clone(),
                rest_fields: None,
            })
        } else {
            self.rest_trie.search(key.as_str()).await
        }
    }
    pub async fn build(method_infos: Vec<Arc<MethodInfo>>) -> Self {
        let mut rest_trie = Trie::default();
        let mut path_cache = HashMap::new();
        for method_info in method_infos {
            rest_trie.insert(method_info.clone()).await;
            let _ = path_cache.insert(
                format!("{}:{}", method_info.method, method_info.path),
                method_info,
            );
        }
        Self {
            path_cache,
            rest_trie,
        }
    }
}

#[derive(Debug, Default)]
pub struct Trie {
    root: Arc<RwLock<TreeNode>>,
}

unsafe impl Sync for Trie {}
unsafe impl Send for Trie {}

#[derive(Debug, Default)]
struct TreeNode {
    nodes: HashMap<String, Arc<RwLock<TreeNode>>>,
    value: Option<Arc<MethodInfo>>,
}

#[derive(Debug)]
pub struct QueryResult {
    pub method_info: Arc<MethodInfo>,
    pub rest_fields: Option<Vec<(String, String)>>,
}

impl Trie {
    pub async fn insert(&mut self, handler_info: Arc<MethodInfo>) {
        let path = format!("{}:{}", handler_info.method, handler_info.path);
        let paths: Vec<&str> = path.split('/').collect();
        let mut temp = self.root.clone();
        for item in paths {
            let res_node = temp.read().await.nodes.get(item).cloned();
            match res_node {
                Some(node) => {
                    temp = node;
                }
                None => {
                    let new_node = Arc::new(RwLock::new(Default::default()));
                    temp.clone()
                        .write()
                        .await
                        .nodes
                        .insert(item.to_owned(), new_node.clone());
                    temp = new_node;
                }
            }
        }
        let _ = temp.write().await.value.insert(handler_info);
    }

    pub async fn search(&self, path: &str) -> Option<QueryResult> {
        Self::search_by_nodes(path, self.root.clone()).await
    }

    #[async_recursion]
    async fn search_by_nodes(path: &str, mut temp: Arc<RwLock<TreeNode>>) -> Option<QueryResult> {
        let mut rest_fields: Vec<(String, String)> = vec![];
        let paths: Vec<&str> = path.split('/').collect();
        for (idx, item) in paths.iter().enumerate() {
            let res_node = temp.read().await.nodes.get(*item).cloned();
            match res_node {
                Some(node) => {
                    temp = node;
                }
                None => {
                    let temp_path = paths[idx + 1..].join("/").to_string();
                    for entry in temp.read().await.nodes.iter() {
                        if entry.0.starts_with('{') {
                            if temp_path.is_empty() && entry.1.read().await.value.is_some() {
                                rest_fields.push((
                                    entry.0[1..entry.0.len() - 1].to_string(),
                                    item.to_string(),
                                ));
                                return entry.1.read().await.value.as_ref().map(|method_info| {
                                    QueryResult {
                                        method_info: method_info.clone(),
                                        rest_fields: if rest_fields.is_empty() {
                                            None
                                        } else {
                                            Some(rest_fields)
                                        },
                                    }
                                });
                            }
                            if let Some(query_result) =
                                Self::search_by_nodes(&temp_path, entry.1.clone()).await
                            {
                                rest_fields.push((
                                    entry.0[1..entry.0.len() - 1].to_string(),
                                    item.to_string(),
                                ));
                                if let Some(mut temp_query_fields) = query_result.rest_fields {
                                    rest_fields.append(&mut temp_query_fields);
                                }
                                return Some(QueryResult {
                                    method_info: query_result.method_info,
                                    rest_fields: if rest_fields.is_empty() {
                                        None
                                    } else {
                                        Some(rest_fields)
                                    },
                                });
                            }
                        }
                    }
                    return None;
                }
            }
        }
        temp.read()
            .await
            .value
            .as_ref()
            .map(|method_info| QueryResult {
                method_info: method_info.clone(),
                rest_fields: if rest_fields.is_empty() {
                    None
                } else {
                    Some(rest_fields)
                },
            })
    }
}