krpc-core 0.2.0

RPC framework for service registration and discovery through API exposure, compatible with Dubbo3 protocol, intertunable with Java projects
Documentation
use std::vec;
use crate::register::{Info, Resource};

pub fn decode_url(url: &str) -> Result<Resource, String> {
    let mut url = &krpc_common::url_util::decode_url(url)?[..];
    if url.starts_with("tri://") {
        url = &url[6..];
        return Ok(Resource::Server(get_info(url)));
    } else if url.starts_with("consumer://") {
        url = &url[11..];
        return Ok(Resource::Client(get_info(url)));
    }
    return Err("decode err".to_string());
}

pub fn encode_url(resource: &Resource) -> String {
    let mut url = String::new();
    match resource {
        Resource::Client(info) => {
            url.push_str("consumer://");
            url.push_str(&(get_path(info) + &"/"));
            url.push_str(&(info.server_name.clone() + &"?"));
            url.push_str(&("interface=".to_owned() + &info.server_name));
            url.push_str(&get_field_url("&methods", &info.methods));
            if let Some(version) = &info.version {
                let value = vec![version.clone()];
                url.push_str(&get_field_url("&version", &value));
            }
            url.push_str("&dubbo=2.0.2&release=3.3.0-beta.1&side=consumer");
        }
        Resource::Server(info) => {
            url.push_str("tri://");
            url.push_str(&(get_path(info) + &"/"));
            url.push_str(&(info.server_name.clone() + &"?"));
            url.push_str(&("interface=".to_owned() + &info.server_name));
            url.push_str(&get_field_url("&methods", &info.methods));
            if let Some(version) = &info.version {
                let value = vec![version.clone()];
                url.push_str(&get_field_url("&version", &value));
            }
            url.push_str(
                "&dubbo=2.0.2&prefer.serialization=fastjson&release=3.3.0-beta.1&side=provider",
            );
        }
    }
    return "/".to_string() + &krpc_common::url_util::encode_url(&url);
}

fn get_ip(path: &str) -> (String, Option<String>) {
    let path: Vec<&str> = path.split(":").collect();
    let mut port = None;
    if path.len() > 1 {
        let _ = port.insert(path[1].to_string());
    }
    return (path[0].to_string(), port);
}

fn get_path(info: &Info) -> String {
    let mut ip = info.ip.clone();
    if let Some(port) = info.port.clone() {
        ip.push_str(":");
        ip.push_str(&port);
    }
    return ip.to_string();
}

fn get_info(url: &str) -> Info {
    let info: Vec<&str> = url.split("/").collect();
    let path = get_ip(info[0]);
    let info: Vec<&str> = info[1].split("?").collect();
    let server_name = info[0].to_string();
    let vision = get_field_values(info[1], "version");
    let mut revision = None;
    if !vision.is_empty(){
        let _ = revision.insert(vision[0].clone());
    }
    let info = Info {
        server_name,
        version: revision,
        methods: get_field_values(info[1], "methods"),
        ip: path.0,
        port: path.1,
    };
    return info;
}

fn get_field_values(str: &str, key: &str) -> Vec<String> {
    let fields: Vec<&str> = str.split("&").collect();
    let mut res = vec![];
    for field in fields {
        let field: Vec<&str> = field.split("=").collect();
        if field[0] == key {
            let velues: Vec<&str> = field[1].split(",").collect();
            res = velues.iter().fold(res, |mut res, &e| {
                res.push(e.to_string());
                res
            });
            break;
        }
    }
    return res;
}

fn get_field_url(key: &str, values: &Vec<String>) -> String {
    if values.is_empty() {
        return String::new();
    }
    let mut res = String::new();
    for value in values {
        res.push_str(&(value.to_owned() + ","));
    }
    return key.to_string() + "=" + &res[..res.len() - 1];
}