200 lines
12 KiB
Markdown
200 lines
12 KiB
Markdown
# nats.rs: Overview and Architecture
|
|
|
|
**Version**: async-nats 0.49.1, nats-server 0.1.0
|
|
**Repository**: https://github.com/nats-io/nats.rs
|
|
**License**: Apache-2.0
|
|
**Rust Edition**: 2021
|
|
**MSRV**: 1.88.0
|
|
**Protocol**: NATS Client Protocol (INFO/CONNECT/PUB/SUB/UNSUB/PING/PONG)
|
|
|
|
## What It Is
|
|
|
|
The `nats.rs` repository contains the **official Rust client for NATS.io**, a high-performance messaging system. The active crate is **`async-nats`** — a fully async, Tokio-based NATS client. The deprecated `nats` crate (synchronous) receives security fixes only.
|
|
|
|
The `nats-server` crate is **not** an implementation of the NATS server. It is a **test harness** that spawns the Go-based `nats-server` binary for integration tests. The actual NATS server is a separate Go project at `github.com/nats-io/nats-server`.
|
|
|
|
Core design decisions:
|
|
- **Fully async** — all I/O is Tokio-based with async/await throughout
|
|
- **Cloneable Client handle** — `Client` is cheap to clone (Arc internals), all protocol work happens in a single `ConnectionHandler` task
|
|
- **Channel-based internal communication** — `Client` sends `Command` variants via `mpsc` channel to `ConnectionHandler`
|
|
- **Multiplexed request-reply** — one internal subscription handles all request-response patterns via inbox token routing
|
|
- **Automatic reconnection** — exponential backoff with configurable server pool rotation
|
|
- **Feature-gated subsystems** — JetStream, KV, Object Store, Service API, NKeys, WebSockets, and crypto backends are all optional
|
|
|
|
## Workspace Structure
|
|
|
|
```
|
|
nats.rs/
|
|
├── async-nats/ # Primary crate — async NATS client
|
|
│ ├── src/
|
|
│ │ ├── lib.rs # Entry point: connect(), ServerOp, ClientOp, Command, ConnectionHandler, Subscriber
|
|
│ │ ├── client.rs # Client handle: publish, subscribe, request, flush, drain
|
|
│ │ ├── connection.rs # Low-level I/O: protocol parsing, read/write buffers
|
|
│ │ ├── connector.rs # Connection establishment, reconnection, server pool
|
|
│ │ ├── options.rs # ConnectOptions builder
|
|
│ │ ├── auth.rs # Auth struct (credentials container)
|
|
│ │ ├── auth_utils.rs # Credential file parsing (.creds files)
|
|
│ │ ├── error.rs # Generic Error<Kind> type
|
|
│ │ ├── header.rs # HeaderMap — NATS message headers
|
|
│ │ ├── subject.rs # Subject type, ToSubject trait
|
|
│ │ ├── status.rs # StatusCode (100-999 NATS protocol codes)
|
|
│ │ ├── message.rs # Message and OutboundMessage types
|
|
│ │ ├── tls.rs # TLS configuration helpers
|
|
│ │ ├── crypto.rs # Crypto feature support
|
|
│ │ ├── id_generator.rs # NUID/rand-based unique ID generation
|
|
│ │ ├── datetime.rs # DateTime helpers for JetStream/Service
|
|
│ │ ├── jetstream/ # JetStream API (feature-gated)
|
|
│ │ │ ├── mod.rs # Module root, jetstream::new(), with_domain()
|
|
│ │ │ ├── context.rs # JetStream Context — streams, publishing, consumers
|
|
│ │ │ ├── stream.rs # Stream management, Config, Info, Consumer creation
|
|
│ │ │ ├── consumer/ # Pull, Push, Ordered consumers
|
|
│ │ │ ├── message.rs # JetStream Message with ack methods
|
|
│ │ │ ├── publish.rs # PublishAck
|
|
│ │ │ ├── response.rs # Response wrapper
|
|
│ │ │ ├── errors.rs # JetStream error codes
|
|
│ │ │ ├── account.rs # Account info
|
|
│ │ │ ├── kv/ # Key-Value store (feature: "kv")
|
|
│ │ │ └── object_store/ # Object store (feature: "object-store")
|
|
│ │ └── service/ # Service API (feature-gated)
|
|
│ │ ├── mod.rs # Service, ServiceBuilder
|
|
│ │ ├── endpoint.rs # Endpoint handling
|
|
│ │ └── error.rs # Service errors
|
|
│ ├── tests/ # Integration tests (require nats-server binary)
|
|
│ ├── examples/ # Runnable examples
|
|
│ └── benches/ # Criterion benchmarks
|
|
├── nats-server/ # Test harness — spawns Go nats-server for tests
|
|
│ ├── src/lib.rs # Server struct, run_server(), run_cluster()
|
|
│ └── configs/ # Server config files for tests
|
|
│ └── jetstream.conf
|
|
└── nats/ # DEPRECATED sync client — do not modify
|
|
```
|
|
|
|
## Architecture Diagram
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ Application Layer │
|
|
│ │
|
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
|
│ │ JetStream│ │ KV │ │ Object │ │ Service │ │
|
|
│ │ Context │ │ Store │ │ Store │ │ API │ │
|
|
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
|
|
│ └──────────────┴─────────────┴─────────────┘ │
|
|
│ │ │
|
|
│ ┌──────┴──────┐ │
|
|
│ │ Client │ Cloneable handle │
|
|
│ │ (mpsc::Sender) │
|
|
│ └──────┬──────┘ │
|
|
│ │ Command channel │
|
|
└──────────────────────────┼────────────────────────────────┘
|
|
│
|
|
┌──────────────────────────┼────────────────────────────────┐
|
|
│ ConnectionHandler │
|
|
│ (single Tokio task) │
|
|
│ │ │
|
|
│ ┌───────────┐ ┌───────┴───────┐ ┌──────────────────┐ │
|
|
│ │Subscriptions│ │ Multiplexer │ │ Flush Observers │ │
|
|
│ │ HashMap │ │ (request-reply)│ │ │ │
|
|
│ └──────┬──────┘ └───────┬───────┘ └──────────────────┘ │
|
|
│ └────────────────┼ │
|
|
│ ┌──────┴──────┐ │
|
|
│ │ Connector │ Server pool, reconnect │
|
|
│ └──────┬──────┘ │
|
|
│ │ │
|
|
│ ┌──────┴──────┐ │
|
|
│ │ Connection │ Protocol I/O │
|
|
│ │ (read/write)│ ServerOp / ClientOp │
|
|
│ └──────┬──────┘ │
|
|
└──────────────────────────┼────────────────────────────────┘
|
|
│
|
|
┌──────┴──────┐
|
|
│ NATS Server │ (Go binary, TCP/TLS/WS)
|
|
└─────────────┘
|
|
```
|
|
|
|
## Key Concepts
|
|
|
|
### Subject
|
|
NATS uses subject strings for message addressing. A `Subject` is a validated, immutable, UTF-8 string backed by `Bytes`. Subjects use dot-delimited tokens (e.g., `events.data.sensor1`). Wildcards `*` (single token) and `>` (multi-token suffix) are supported for subscriptions.
|
|
|
|
### ClientOp / ServerOp
|
|
The NATS client-server protocol is text-based with binary payloads. The client sends `ClientOp` variants (CONNECT, PUB/HPUB, SUB, UNSUB, PING, PONG) and receives `ServerOp` variants (INFO, MSG/HMSG, +OK, -ERR, PING, PONG).
|
|
|
|
### Command
|
|
Internal command type sent from `Client` to `ConnectionHandler` via `mpsc` channel. Includes Publish, Request, Subscribe, Unsubscribe, Flush, Drain, Reconnect, SetServerPool, ServerPool.
|
|
|
|
### Multiplexer
|
|
A single internal subscription (SID 0) that routes all request-reply responses. When a `Request` is made, a unique inbox token is registered in the multiplexer's sender map, and the response is dispatched to the corresponding `oneshot::Sender`.
|
|
|
|
### ConnectionHandler
|
|
A single Tokio task that drives all protocol I/O. It processes server operations from `Connection`, handles client commands from the `mpsc` channel, manages subscriptions, maintains ping/pong health, and orchestrates reconnection.
|
|
|
|
## nats-server Test Harness
|
|
|
|
The `nats-server` crate provides utilities for launching real NATS server instances in tests:
|
|
|
|
- `run_server(cfg)` — starts a single server with optional config
|
|
- `run_cluster(cfg)` — starts a 3-node cluster
|
|
- `Server` struct — holds the child process, cleans up on drop
|
|
- `Server::restart()` — kills and restarts the server process
|
|
- `Server::client_url()` — reads the INFO from the server to get the client URL
|
|
- `set_lame_duck_mode(server)` — sends LDM signal to the server process
|
|
|
|
The test harness spawns the Go `nats-server` binary via `std::process::Command`, using dynamic ports for parallel test execution. It auto-discovers the client URL by connecting to the server's TCP port and parsing the `INFO` JSON. On `Drop`, it kills the child process and cleans up JetStream storage directories.
|
|
|
|
## Feature Flags
|
|
|
|
```toml
|
|
# Default: everything enabled
|
|
default = ["server_2_10", "server_2_11", "server_2_12", "server_2_14",
|
|
"service", "ring", "jetstream", "nkeys", "crypto",
|
|
"object-store", "kv", "websockets", "nuid"]
|
|
|
|
# Subsystems
|
|
jetstream # JetStream API
|
|
kv # Key-Value store (requires jetstream)
|
|
object-store # Object store (requires jetstream + crypto)
|
|
service # Service API
|
|
|
|
# Crypto backends (pick one)
|
|
ring # Default crypto backend
|
|
aws-lc-rs # Alternative backend
|
|
fips # FIPS mode (requires aws-lc-rs)
|
|
|
|
# Auth
|
|
nkeys # NKey authentication
|
|
|
|
# Other
|
|
nuid # NUID-based ID generation (falls back to rand)
|
|
crypto # Encryption support
|
|
websockets # WebSocket transport
|
|
experimental # Experimental features
|
|
|
|
# Server version markers (enable version-specific API fields)
|
|
server_2_10
|
|
server_2_11
|
|
server_2_12
|
|
server_2_14
|
|
```
|
|
|
|
## Dependencies (Key)
|
|
|
|
| Dependency | Purpose |
|
|
|-----------|---------|
|
|
| `tokio` | Async runtime (macros, rt, net, sync, time, io-util) |
|
|
| `bytes` | Zero-copy byte buffers for payloads |
|
|
| `tokio-rustls` | TLS via rustls |
|
|
| `rustls-native-certs` | Load native TLS root certificates |
|
|
| `serde` / `serde_json` | JSON serialization for protocol messages and JetStream API |
|
|
| `memchr` | Fast CRLF search for protocol parsing |
|
|
| `futures-util` | Stream trait, Sink trait, StreamExt |
|
|
| `tracing` | Structured logging |
|
|
| `thiserror` | Error type derivation |
|
|
| `url` | URL parsing for server addresses |
|
|
| `portable-atomic` | Portable atomic operations |
|
|
|
|
## References
|
|
|
|
- [NATS Protocol Specification](https://docs.nats.io/reference/reference-protocols/nats-protocol)
|
|
- [NATS JetStream Documentation](https://docs.nats.io/nats-concepts/jetstream)
|
|
- [async-nats on docs.rs](https://docs.rs/async-nats) |