- Convert WsReadInfo from mutable struct to class (prevents silent copy bugs)
- Add handshake timeout enforcement via CancellationToken in WsUpgrade
- Use buffered reading (512 bytes) in ReadHttpRequestAsync instead of byte-at-a-time
- Add IAsyncDisposable to WsConnection for proper async cleanup
- Simplify redundant mask bit check in WsReadInfo
- Remove unused WsGuid and CompressLastBlock dead code from WsConstants
- Document single-reader assumption on WsConnection read-side state
Add WebSocket listener support to NatsServer alongside the existing TCP
listener. When WebSocketOptions.Port >= 0, the server binds a second
socket, performs HTTP upgrade via WsUpgrade.TryUpgradeAsync, wraps the
connection in WsConnection for transparent frame/deframe, and hands it
to the standard NatsClient pipeline.
Changes:
- NatsClient: add IsWebSocket and WsInfo properties
- NatsServer: add RunWebSocketAcceptLoopAsync and AcceptWebSocketClientAsync,
WS listener lifecycle in StartAsync/ShutdownAsync/Dispose
- NatsOptions: change WebSocketOptions.Port default from 0 to -1 (disabled)
- WsConnection.ReadAsync: fix premature end-of-stream when ReadFrames
returns no payloads by looping until data is available
- Add WsIntegration tests (connect, ping, pub/sub over WebSocket)
- Add WsConnection masked frame and end-of-stream unit tests
Covers 6 implementation layers: ClientKind enum + INatsClient interface,
event infrastructure with Channel<T>, system event publishing, request-reply
monitoring services, import/export model with ACCOUNT client, and response
routing with latency tracking.
Wire up the config parsing infrastructure into the server:
- NatsServer: add ReloadConfig() with digest-based change detection,
diff/validate, CLI override preservation, and side-effect triggers
- Program.cs: two-pass CLI parsing — load config file first, then
apply CLI args on top with InCmdLine tracking for reload precedence
- SIGHUP handler upgraded from stub warning to actual reload
- Remove config file "not yet supported" warning from StartAsync
- Add integration tests for config loading, CLI overrides, and
reload validation
- WsReadInfo: validate 64-bit frame payload length against maxPayload
before casting to int (prevents overflow/memory exhaustion)
- WsReadInfo: always send close response per RFC 6455 Section 5.5.1,
including for empty close frames
- WsUpgrade: restrict no-masking to leaf node connections only (browser
clients must always mask frames)
Port of Go server/reload.go option interface and diffing logic. Compares
NatsOptions property-by-property to detect changes, tags each with category
flags (logging, auth, TLS, non-reloadable), validates that non-reloadable
options (Host, Port, ServerName) are not changed at runtime, and provides
MergeCliOverrides to ensure CLI flags always take precedence over config
file values during hot reload.
- CreateCloseMessage now operates on UTF-8 byte length (matching Go's
len(body) behavior) instead of character length, with proper UTF-8
boundary detection during truncation
- WsCompression.Compress now uses try/finally for exception-safe disposal
of DeflateStream and MemoryStream
- Add MaxIncludeDepth = 10 constant and thread _includeDepth through ParserState
constructors, ProcessInclude, ParseFile (private overload), and ParseEnvValue
to prevent StackOverflowException from recursive includes
- Fix PopContext to check _ctxs.Count <= 1 instead of == 0 so the root context
is never popped, replacing silent crash with clear InvalidOperationException
- Add else throw in SetValue so unknown context types surface as bugs rather
than silently dropping values
Implement WsCompression with Compress/Decompress methods per RFC 7692.
Key .NET adaptation: Flush() without Dispose() on DeflateStream to produce
the correct sync flush marker that can be stripped and re-appended.