tin-nacos-wrapper 0.1.0

A Rust library for Nacos service discovery and configuration management
Documentation
use serde_json::{Map, Value};
use std::net::IpAddr;

pub trait QueryParam {
    fn to_param_value(&self) -> Option<String>;
}

impl QueryParam for String {
    fn to_param_value(&self) -> Option<String> {
        Some(self.clone())
    }
}

impl QueryParam for str {
    fn to_param_value(&self) -> Option<String> {
        Some(self.to_string())
    }
}

impl<T: QueryParam> QueryParam for Option<T> {
    fn to_param_value(&self) -> Option<String> {
        self.as_ref().and_then(|v| v.to_param_value())
    }
}

macro_rules! impl_query_param_for_primitive {
    ($($t:ty),*) => {
        $(
            impl QueryParam for $t {
                fn to_param_value(&self) -> Option<String> {
                    Some(self.to_string())
                }
            }
        )*
    };
}

impl_query_param_for_primitive!(i32, i64, u32, u64, f32, f64, bool, usize);

/// Nacos 工具类
pub struct NacosUtils;

impl NacosUtils {
    /// 验证API响应代码
    pub fn validate_api_code(code: &str) -> Result<(), String> {
        if !code.eq("200") {
            return Err(format!("Request failed with code: {code}"));
        }
        Ok(())
    }

    /// 工具函数:将 Option 类型的参数拼接为查询参数
    pub fn build_query_params(params: &[(&str, &dyn QueryParam)]) -> String {
        let mut query = vec![];
        for (k, v) in params {
            if let Some(val) = v.to_param_value() {
                query.push(format!("{}={}", k, urlencoding::encode(&val)));
            }
        }
        if query.is_empty() {
            String::new()
        } else {
            format!("?{}", query.join("&"))
        }
    }

    /// 工具函数:将 Option 类型参数构建为 JSON 对象
    pub fn build_json_body(params: &[(&str, Option<Value>)]) -> Value {
        let mut map = Map::new();
        for (k, v) in params {
            if let Some(val) = v {
                map.insert(k.to_string(), val.clone());
            }
        }
        Value::Object(map)
    }

    pub fn get_local_ip() -> Option<IpAddr> {
        let addrs = local_ip_address::list_afinet_netifas().ok()?;
        log::debug!("Local network interfaces: {addrs:?}");
        for (_name, ip) in addrs {
            if ip.is_ipv4() && !ip.is_loopback() {
                log::debug!("Local IP address found: {ip}");
                return Some(ip);
            }
        }
        None
    }
}