tin-nacos-wrapper 0.1.0

A Rust library for Nacos service discovery and configuration management
Documentation
use crate::config::NacosConfig;
use crate::error::{Error, Result};
use crate::listener::{SimpleConfigChangeListener, SimpleInstanceChangeListener};
use nacos_sdk::api::{
    config::{ConfigService, ConfigServiceBuilder},
    naming::{NamingService, NamingServiceBuilder, ServiceInstance},
    props::ClientProps,
};

/// Nacos客户端配置结构体
#[derive(Clone)]
pub struct NacosClient {
    client_config: NacosConfig,
    config_service: ConfigService,
    naming_service: NamingService,
}

impl NacosClient {
    /// 初始化Nacos服务,返回包含服务实例的客户端
    pub async fn init(
        client_config: NacosConfig,
    ) -> Result<NacosClient> {
        let client_props = Self::create_client_props(
            client_config.server_addr.clone(),
            client_config.namespace.clone(),
            client_config.app_name.clone(),
            client_config.auth_username.clone(),
            client_config.auth_password.clone(),
        );
        let config_service = Self::create_config_service(
            client_props.clone(),
            client_config.app_name.clone(),
            client_config.group_name.clone(),
        )
        .await?;
        let naming_service = Self::create_naming_service(client_props).await?;

        let nacos_client = NacosClient {
            client_config,
            config_service,
            naming_service,
        };

        nacos_client.register_self().await?;

        Ok(nacos_client)
    }

    /// 创建客户端配置属性
    fn create_client_props(
        server_addr: String,
        namespace: String,
        app_name: String,
        auth_username: Option<String>,
        auth_password: Option<String>,
    ) -> ClientProps {
        let mut client_props = ClientProps::new()
            .server_addr(server_addr)
            .namespace(namespace)
            .app_name(app_name)
            .remote_grpc_port(9848);

        if let Some(username) = auth_username {
            client_props = client_props.auth_username(username);
        }
        if let Some(password) = auth_password {
            client_props = client_props.auth_password(password);
        }

        client_props
    }

    /// 创建配置服务
    async fn create_config_service(
        client_props: ClientProps,
        data_id: String,
        group_name: String,
    ) -> Result<ConfigService> {
        let config_service = ConfigServiceBuilder::new(client_props)
            .enable_auth_plugin_http()
            .build()?;

        let listen = config_service
            .add_listener(
                data_id,
                group_name,
                std::sync::Arc::new(SimpleConfigChangeListener {}),
            )
            .await;

        match listen {
            Ok(_) => log::info!("成功添加Nacos配置监听器"),
            Err(err) => log::error!("添加Nacos配置监听器失败,错误信息: {err:?}"),
        }

        Ok(config_service)
    }

    /// 创建命名服务
    async fn create_naming_service(
        client_props: ClientProps,
    ) -> Result<NamingService> {
        let naming_service = NamingServiceBuilder::new(client_props)
            .enable_auth_plugin_http()
            .build();

        let naming_service = match naming_service {
            Ok(service) => {
                log::info!("Nacos服务注册与发现客户端构建成功");
                service
            }
            Err(e) => {
                log::error!("构建NamingService失败: {e}");
                return Err(Error::Nacos(e));
            }
        };

        Ok(naming_service)
    }

    /// 注册服务实例
    pub async fn register_instance(
        &self,
        service_name: String,
        group_name: Option<String>,
        ip: String,
        port: i32,
    ) -> Result<()> {
        let service_instance = ServiceInstance {
            ip,
            port,
            ..Default::default()
        };

        let register_result = self
            .naming_service
            .register_instance(service_name.clone(), group_name, service_instance)
            .await;

        match register_result {
            Ok(_) => {
                log::info!("成功注册服务实例: {service_name}");
                Ok(())
            }
            Err(err) => {
                log::error!("注册服务实例 {service_name} 失败,错误信息: {err:?}");
                Err(Error::Nacos(err))
            }
        }
    }

    /// 订阅服务变更通知
    pub async fn subscribe_service(
        &self,
        group_name: Option<String>,
        service_name: String,
    ) -> Result<()> {
        let subscribe_result = self
            .naming_service
            .subscribe(
                service_name.clone(),
                group_name,
                vec![],
                std::sync::Arc::new(SimpleInstanceChangeListener {}),
            )
            .await;

        match subscribe_result {
            Ok(_) => {
                log::info!("成功订阅服务 '{service_name}'");
                Ok(())
            }
            Err(err) => {
                log::error!("订阅服务 '{service_name}' 失败,错误信息: {err:?}");
                Err(Error::Nacos(err))
            }
        }
    }

    /// 注册服务实例
    async fn register_self(&self) -> Result<()> {
        let service_instance = ServiceInstance {
            ip: self.client_config.client_ip.clone(),
            port: self.client_config.client_port,
            ..Default::default()
        };

        let register_result = self
            .naming_service
            .register_instance(
                self.client_config.app_name.clone(),
                Some(self.client_config.group_name.clone()),
                service_instance,
            )
            .await;

        let service_name = self.client_config.app_name.clone();

        match register_result {
            Ok(_) => {
                log::info!("成功注册服务实例: {service_name}");
                Ok(())
            }
            Err(err) => {
                log::error!("注册服务实例失败 - 服务名: {service_name}, 错误信息: {err:?}");
                Err(Error::Nacos(err))
            }
        }
    }

    /// 获取配置服务引用
    pub fn get_config_service(&self) -> &ConfigService {
        &self.config_service
    }

    /// 获取命名服务引用
    pub fn get_naming_service(&self) -> &NamingService {
        &self.naming_service
    }

    /// 获取客户端配置引用
    pub fn get_config(&self) -> &NacosConfig {
        &self.client_config
    }
}