batata-client

Crates.iobatata-client
lib.rsbatata-client
version0.0.2
created_at2025-12-21 00:11:12.400075+00
updated_at2025-12-21 00:47:37.67163+00
descriptionRust client for Batata/Nacos service discovery and configuration management
homepage
repositoryhttps://github.com/easynet-cn/batata-client
max_upload_size
id1997137
size316,011
梁天语 (easynet-cn)

documentation

README

Batata Client

A Rust client library for Nacos service discovery and configuration management.

Crates.io Documentation License

English | 中文

Features

  • Configuration Management

    • Get, publish, and remove configurations
    • Listen for configuration changes with callbacks
    • Search configurations with pagination
    • Local caching with MD5 validation
  • Service Discovery

    • Register, deregister, and update service instances
    • Query service instances (all or healthy only)
    • Subscribe to service change notifications
    • Automatic heartbeat for ephemeral instances
  • Authentication

    • Username/Password authentication
    • AccessKey/SecretKey authentication (Alibaba Cloud style)
    • Automatic token refresh
  • Enterprise Features

    • TLS/SSL support
    • Multiple server addresses with load balancing
    • Automatic failover and retry
    • Local file cache for disaster recovery

Installation

Add to your Cargo.toml:

[dependencies]
batata-client = "0.0.1"
tokio = { version = "1", features = ["full"] }

Quick Start

Basic Usage

use batata_client::{BatataClient, Result};

#[tokio::main]
async fn main() -> Result<()> {
    // Create client
    let client = BatataClient::builder()
        .server_addr("localhost:8848")
        .namespace("public")
        .build()
        .await?;

    // Configuration management
    let config_service = client.config_service();

    // Get configuration
    let content = config_service.get_config("my-config", "DEFAULT_GROUP").await?;
    println!("Config: {}", content);

    // Publish configuration
    config_service.publish_config("my-config", "DEFAULT_GROUP", "key=value").await?;

    // Service discovery
    let naming_service = client.naming_service();

    // Register instance
    naming_service.register_instance_simple("my-service", "127.0.0.1", 8080).await?;

    // Get healthy instances
    let instances = naming_service.select_instances("my-service", "DEFAULT_GROUP", true).await?;

    // Shutdown
    client.shutdown().await;

    Ok(())
}

With Authentication

use batata_client::BatataClient;

// Username/Password authentication
let client = BatataClient::builder()
    .server_addr("localhost:8848")
    .username_password("nacos", "nacos")
    .build()
    .await?;

// AccessKey/SecretKey authentication
let client = BatataClient::builder()
    .server_addr("localhost:8848")
    .access_key("your-access-key", "your-secret-key")
    .build()
    .await?;

With TLS

use batata_client::{BatataClient, TlsConfig};

let client = BatataClient::builder()
    .server_addr("localhost:8848")
    .tls_config(
        TlsConfig::new()
            .with_ca_cert("/path/to/ca.pem")
            .with_client_cert("/path/to/cert.pem", "/path/to/key.pem")
    )
    .build()
    .await?;

Listen for Configuration Changes

use batata_client::{BatataClient, ConfigChangeEvent};

let client = BatataClient::builder()
    .server_addr("localhost:8848")
    .build()
    .await?;

let config_service = client.config_service();

// Add listener with callback
config_service.add_callback_listener("my-config", "DEFAULT_GROUP", |event: ConfigChangeEvent| {
    println!("Config changed: {} -> {}",
        event.old_content.unwrap_or_default(),
        event.new_content);
});

// Start config service to enable listening
client.start_config_service().await?;

Subscribe to Service Changes

use batata_client::{BatataClient, ServiceChangeEvent};

let client = BatataClient::builder()
    .server_addr("localhost:8848")
    .build()
    .await?;

let naming_service = client.naming_service();

// Subscribe with callback
naming_service.subscribe_callback("my-service", "DEFAULT_GROUP", |event: ServiceChangeEvent| {
    println!("Service instances changed: {:?}", event.instances);
}).await?;

Search Configurations

let config_service = client.config_service();

// Search with pagination
let (total, items) = config_service
    .search_config("test*", "DEFAULT_GROUP", 1, 10)
    .await?;

println!("Found {} configs", total);
for item in items {
    println!("- {}: {}", item.data_id, item.group);
}

Update Service Instance

use batata_client::Instance;

let naming_service = client.naming_service();

// Update instance weight and status
let instance = Instance::new("127.0.0.1", 8080)
    .with_weight(2.0)
    .with_enabled(false)
    .with_metadata("version", "2.0.0");

naming_service.update_instance("my-service", "DEFAULT_GROUP", instance).await?;

Local Cache for Failover

let client = BatataClient::builder()
    .server_addr("localhost:8848")
    .cache_dir("/tmp/nacos-cache")
    .build()
    .await?;

Configuration Options

Option Description Default
server_addr Nacos server address localhost:8848
server_addrs Multiple server addresses -
namespace Namespace ID public
app_name Application name -
timeout_ms Request timeout in milliseconds 3000
retry_times Number of retry attempts 3
username_password Username and password for auth -
access_key Access key and secret key for auth -
tls Enable TLS false
tls_config TLS configuration -
cache_dir Local cache directory -

Examples

Run the examples:

# Configuration example
cargo run --example config_example

# Naming example
cargo run --example naming_example

License

Apache License 2.0

Commit count: 0

cargo fmt