agile-config-client 0.1.0

AgileConfig client that integrates with the config crate as an AsyncSource.
Documentation

agile-config-client

A Rust client for AgileConfig.

The crate pulls published configuration over HTTP, can keep a WebSocket session for live reload notifications, and exposes an AsyncSource for the config crate.

Crates.io Documentation

More API detail is in the crate documentation.

Install

[dependencies]

agile-config-client = "0.1"

config = { version = "0.15", features = ["async"] }

tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

AES encryption of the on-disk cache is optional and pulls extra crates (aes, ecb, sha1). Enable it only when you set cache.encrypt = true:

agile-config-client = { version = "0.1", features = ["cache-encrypt"] }

Build a client

Client::new takes a public ClientOptions struct. Client::builder fills the same struct and then calls new.

use agile_config_client::{Client, ClientOptions};

let from_struct = Client::new(ClientOptions {
    app_id: "app".into(),
    secret: "secret".into(),
    nodes: vec!["http://localhost:5000".into(), "http://localhost:5001".into()],
    env: "DEV".into(),
    name: Some("order-service".into()),
    tag: Some("canary".into()),
    ..ClientOptions::default()
})?;

let from_builder = Client::builder()
    .app_id("app")
    .secret("secret")
    .nodes(["http://localhost:5000"])
    .env("DEV")
    .build()?;

Required fields are app_id and at least one node URL. secret may be empty. env is uppercased. Comma-separated node strings are split.

Options

Field Default Meaning
app_id empty (required) Application id from the AgileConfig console
secret empty Application secret
nodes empty (required) Node base URLs (http:// / https://)
env empty Target environment; empty lets the server choose
name / tag None Labels shown in the admin console
http_timeout 100s HTTP pull timeout
reconnect_interval 5s WebSocket reconnect delay
heartbeat_interval 30s WebSocket ping interval
cache.enabled true Persist the last successful pull
cache.directory empty (cwd) Directory for {appId}.agileconfig.client.configs.cache
cache.encrypt false AES-encrypt the cache file (C# compatible). Requires the cache-encrypt feature

Use with the config crate

Client does not implement AsyncSource. Call client.source() to get a Source. collect performs HTTP (and cache fallback) if needed. It does not open a WebSocket.

let settings = config::Config::builder()
    .add_async_source(client.source())
    .build()
    .await?;

let connection = settings.get_string("db.connection")?;

AgileConfig items with a group become group:key in the snapshot (same as the C# client) and group.key in config (db:connectiondb.connection). Lookups are case-sensitive.

Live updates

Call connect() to pull configuration and start WebSocket heartbeat/reconnect. Keep the Client alive. This crate never rebuilds config::Config; subscribe and apply the new snapshot yourself.

client.connect().await?;

let settings = config::Config::builder()
    .add_async_source(client.source())
    .build()
    .await?;

let mut rx = client.subscribe();
while rx.changed().await.is_ok() {
    let snapshot = client.snapshot();
    // Rebuild `config::Config` or swap application state here.
    let _ = snapshot.get("db:connection");
}

A WebSocket failure is not fatal as long as HTTP or the local cache produced a snapshot. Dropping the last Client/Source clone cancels background tasks.

Examples

# One-shot HTTP pull

AGILE_CONFIG_APP_ID=app AGILE_CONFIG_SECRET=secret \

  AGILE_CONFIG_NODES=http://localhost:5000 AGILE_CONFIG_ENV=DEV \

  cargo run --example fetch


# WebSocket session and reload notifications

AGILE_CONFIG_APP_ID=app AGILE_CONFIG_SECRET=secret \

  AGILE_CONFIG_NODES=http://localhost:5000 \

  cargo run --example watch

Differences from the C# client

  • No static singleton and no injectable logger; use tracing
  • No service registration or discovery in this version
  • config::Config is a snapshot; reload is caller-owned via subscribe()
  • Dictionary lookups are case-sensitive