Remove template UnitTest1.cs placeholder. Add actual project structure, run commands for the NATS server host, and update test command examples to reference the real project paths.
8.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This project ports the NATS server from Go to .NET 10 / C#. The Go reference implementation lives in golang/nats-server/. The .NET port lives at the repository root.
NATS is a high-performance publish-subscribe messaging system. It supports wildcards (* single token, > multi-token), queue groups for load balancing, request-reply, clustering (full-mesh routes, gateways, leaf nodes), and persistent streaming via JetStream.
Build & Test Commands
The solution file is NatsDotNet.slnx.
# Build the solution
dotnet build
# Run all tests
dotnet test
# Run tests with verbose output
dotnet test -v normal
# Run a single test project
dotnet test tests/NATS.Server.Tests
# Run a specific test by name
dotnet test tests/NATS.Server.Tests --filter "FullyQualifiedName~TestName"
# Run the NATS server (default port 4222)
dotnet run --project src/NATS.Server.Host
# Run the NATS server on a custom port
dotnet run --project src/NATS.Server.Host -- -p 14222
# Clean and rebuild
dotnet clean && dotnet build
.NET Project Structure
NatsDotNet.slnx # Solution file
src/
NATS.Server/ # Core server library
NatsServer.cs # Server: listener, accept loop, shutdown
NatsClient.cs # Per-connection client: read/write loops, sub tracking
NatsOptions.cs # Server configuration (port, host, etc.)
Protocol/
NatsParser.cs # Protocol state machine (PUB, SUB, UNSUB, etc.)
NatsProtocol.cs # Wire-level protocol writing (INFO, MSG, PING/PONG)
Subscriptions/
SubjectMatch.cs # Subject validation and wildcard matching
SubList.cs # Trie-based subscription list with caching
SubListResult.cs # Match result container (plain subs + queue groups)
Subscription.cs # Subscription model (subject, sid, queue, client)
NATS.Server.Host/ # Executable host app
Program.cs # Entry point, CLI arg parsing (-p port)
tests/
NATS.Server.Tests/ # xUnit test project
ParserTests.cs # Protocol parser tests
SubjectMatchTests.cs # Subject validation & matching tests
SubListTests.cs # Subscription list trie tests
ClientTests.cs # Client-level protocol tests
ServerTests.cs # Server pubsub/wildcard tests
IntegrationTests.cs # End-to-end tests using NATS.Client.Core NuGet
Go Reference Commands
# Build the Go reference server
cd golang/nats-server && go build
# Run Go tests for a specific area
cd golang/nats-server && go test -v -run TestName ./server/ -count=1 -timeout=30m
# Run all Go server tests (slow, ~30min)
cd golang/nats-server && go test -v ./server/ -count=1 -timeout=30m
Architecture: NATS Server (Reference)
The Go source in golang/nats-server/server/ is the authoritative reference. Key files by subsystem:
Core Message Path
server.go— Server struct, startup lifecycle (NewServer→Run→WaitForShutdown), listener managementclient.go(6700 lines) — Connection handling,readLoop/writeLoopgoroutines, per-client subscription tracking, dynamic buffer sizing (512→65536 bytes), client types:CLIENT,ROUTER,GATEWAY,LEAF,SYSTEMparser.go— Protocol state machine. Text protocol:PUB,SUB,UNSUB,CONNECT,INFO,PING/PONG,MSG. Extended:HPUB/HMSG(headers),RPUB/RMSG(routes). Control line limit: 4096 bytes. Default max payload: 1MB.sublist.go— Trie-based subject matcher with wildcard support. Nodes havepsubs(plain),qsubs(queue groups), special pointers for*and>wildcards. Results are cached with atomic generation IDs for invalidation.
Authentication & Accounts
auth.go— Auth mechanisms: username/password, token, NKeys (Ed25519), JWT, external auth callout, LDAPaccounts.go(137KB) — Multi-tenant account isolation. Each account has its ownSublist, client set, and subject namespace. Supports exports/imports between accounts, service latency tracking.jwt.go,nkey.go— JWT claims parsing and NKey validation
Clustering
route.go— Full-mesh cluster routes. Route pooling (default 3 connections per peer). Account-specific dedicated routes. Protocol:RS+/RS-for subscribe propagation,RMSGfor routed messages.gateway.go(103KB) — Inter-cluster bridges. Interest-only mode optimizes traffic. Reply subject mapping (_GR_.prefix) avoids cross-cluster conflicts.leafnode.go— Hub-and-spoke topology for edge deployments. Only subscribed subjects shared with hub. Loop detection via$LDS.prefix.
JetStream (Persistence)
jetstream.go— Orchestration, API subject handlers ($JS.API.*)stream.go(8000 lines) — Stream lifecycle, retention policies (Limits, Interest, WorkQueue), subject transforms, mirroring/sourcingconsumer.go— Stateful readers. Push vs pull delivery. Ack policies: None, All, Explicit. Redelivery tracking, priority groups.filestore.go(337KB) — Block-based persistent storage with S2 compression, encryption (ChaCha20/AES-GCM), indexingmemstore.go— In-memory storage with hash-wheel TTL expirationraft.go— RAFT consensus for clustered JetStream. Meta-cluster for metadata, per-stream/consumer RAFT groups.
Configuration & Monitoring
opts.go— CLI flags + config file loading. CLI overrides config. Supports hot reload on signal.monitor.go— HTTP endpoints:/varz,/connz,/routez,/gatewayz,/jsz,/healthzconf/— Config file parser (custom format with includes)
Internal Data Structures
server/avl/— AVL tree for sparse sequence sets (ack tracking)server/stree/— Subject tree for per-subject state in streamsserver/gsl/— Generic subject list, optimized trieserver/thw/— Time hash wheel for efficient TTL expiration
Key Porting Considerations
Concurrency model: Go uses goroutines (one per connection readLoop + writeLoop). Map to async/await with Task-based I/O. Use Channel<T> or Pipe for producer-consumer patterns where Go uses channels.
Locking: Go sync.RWMutex maps to ReaderWriterLockSlim. Go sync.Map maps to ConcurrentDictionary. Go atomic operations map to Interlocked or volatile.
Subject matching: The Sublist trie is performance-critical. Every published message triggers a Match() call. Cache invalidation uses atomic generation counters.
Protocol parsing: The parser is a byte-by-byte state machine. In .NET, use System.IO.Pipelines for zero-copy parsing with ReadOnlySequence<byte>.
Buffer management: Go uses []byte slices with pooling. Map to ArrayPool<byte> and Memory<T>/Span<T>.
Compression: NATS uses S2 (Snappy variant) for route/gateway compression. Use an equivalent .NET S2 library or IronSnappy.
Ports: Client=4222, Cluster=6222, Monitoring=8222, Leaf=5222, Gateway=7222.
Message Flow Summary
Client PUB → parser → permission check → Sublist.Match() →
├─ Local subscribers: MSG to each (queue subs: pick one per group)
├─ Cluster routes: RMSG to peers (who deliver to their locals)
├─ Gateways: forward to interested remote clusters
└─ JetStream: if subject matches a stream, store + deliver to consumers
Conventions
- Reference the Go implementation file and line when porting a subsystem
- Maintain protocol compatibility — the .NET server must interoperate with existing NATS clients and Go servers in a cluster
- Use the same configuration file format as the Go server (parsed by
conf/package) - Match the Go server's monitoring JSON response shapes for tooling compatibility