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,
};
#[derive(Clone)]
pub struct NacosClient {
client_config: NacosConfig,
config_service: ConfigService,
naming_service: NamingService,
}
impl NacosClient {
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
}
}