feat: port sessions 21-23 — Streams, Consumers, MQTT, WebSocket & OCSP
Session 21 (402 features, IDs 3195-3387, 584-792): - JetStream/StreamTypes.cs: StreamInfo, ConsumerInfo, SequenceInfo, JSPubAckResponse, WaitQueue, ClusterInfo, PeerInfo, message types, ConsumerAction enum, CreateConsumerRequest, PriorityGroupState - JetStream/NatsStream.cs: NatsStream class (stub methods, IDisposable) - JetStream/NatsConsumer.cs: NatsConsumer class (stub methods, IDisposable) - Updated JetStreamApiTypes.cs: removed duplicate StreamInfo/ConsumerInfo stubs Session 22 (153 features, IDs 2252-2404): - Mqtt/MqttConstants.cs: all MQTT protocol constants, packet types, flags - Mqtt/MqttTypes.cs: MqttSession, MqttSubscription, MqttWill, MqttJsa, MqttAccountSessionManager, MqttHandler and supporting types - Mqtt/MqttHandler.cs: per-client MQTT state, MqttServerExtensions stubs Session 23 (97 features, IDs 3506-3543, 2443-2501): - WebSocket/WebSocketConstants.cs: WsOpCode enum, frame bits, close codes - WebSocket/WebSocketTypes.cs: WsReadInfo, SrvWebsocket (replaces stub), WebSocketHandler stubs - Auth/Ocsp/OcspTypes.cs: OcspMode, OcspMonitor (replaces stub), IOcspResponseCache (replaces stub), NoOpCache, LocalDirCache All features (3503 complete, 0 not_started). Phase 6 now at 58.9%.
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
// Copyright 2020-2025 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Adapted from server/websocket.go in the NATS server Go source.
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server.WebSocket;
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket opcode values as defined in RFC 6455 §5.2.
|
||||
/// Mirrors Go <c>wsOpCode</c> type in server/websocket.go.
|
||||
/// </summary>
|
||||
internal enum WsOpCode : int
|
||||
{
|
||||
Continuation = 0,
|
||||
Text = 1,
|
||||
Binary = 2,
|
||||
Close = 8,
|
||||
Ping = 9,
|
||||
Pong = 10,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WebSocket protocol constants.
|
||||
/// Mirrors the constant block at the top of server/websocket.go.
|
||||
/// </summary>
|
||||
internal static class WsConstants
|
||||
{
|
||||
// Frame header bits
|
||||
public const int FinalBit = 1 << 7;
|
||||
public const int Rsv1Bit = 1 << 6; // Used for per-message compression (RFC 7692)
|
||||
public const int Rsv2Bit = 1 << 5;
|
||||
public const int Rsv3Bit = 1 << 4;
|
||||
public const int MaskBit = 1 << 7;
|
||||
|
||||
// Frame size limits
|
||||
public const int MaxFrameHeaderSize = 14; // LeafNode may behave as a client
|
||||
public const int MaxControlPayloadSize = 125;
|
||||
public const int FrameSizeForBrowsers = 4096; // From experiment, browsers behave better with limited frame size
|
||||
public const int CompressThreshold = 64; // Don't compress for small buffer(s)
|
||||
public const int CloseStatusSize = 2;
|
||||
|
||||
// Close status codes (RFC 6455 §11.7)
|
||||
public const int CloseNormalClosure = 1000;
|
||||
public const int CloseGoingAway = 1001;
|
||||
public const int CloseProtocolError = 1002;
|
||||
public const int CloseUnsupportedData = 1003;
|
||||
public const int CloseNoStatusReceived = 1005;
|
||||
public const int CloseInvalidPayloadData = 1007;
|
||||
public const int ClosePolicyViolation = 1008;
|
||||
public const int CloseMessageTooBig = 1009;
|
||||
public const int CloseInternalError = 1011;
|
||||
public const int CloseTlsHandshake = 1015;
|
||||
|
||||
// Header strings
|
||||
public const string NoMaskingHeader = "Nats-No-Masking";
|
||||
public const string NoMaskingValue = "true";
|
||||
public const string XForwardedForHeader = "X-Forwarded-For";
|
||||
public const string PMCExtension = "permessage-deflate"; // per-message compression
|
||||
public const string PMCSrvNoCtx = "server_no_context_takeover";
|
||||
public const string PMCCliNoCtx = "client_no_context_takeover";
|
||||
public const string SecProtoHeader = "Sec-Websocket-Protocol";
|
||||
public const string MQTTSecProtoVal = "mqtt";
|
||||
public const string SchemePrefix = "ws";
|
||||
public const string SchemePrefixTls = "wss";
|
||||
}
|
||||
110
dotnet/src/ZB.MOM.NatsNet.Server/WebSocket/WebSocketTypes.cs
Normal file
110
dotnet/src/ZB.MOM.NatsNet.Server/WebSocket/WebSocketTypes.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
// Copyright 2020-2025 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Adapted from server/websocket.go in the NATS server Go source.
|
||||
|
||||
using ZB.MOM.NatsNet.Server.Internal;
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server.WebSocket;
|
||||
|
||||
/// <summary>
|
||||
/// Per-connection WebSocket read state.
|
||||
/// Mirrors Go <c>wsReadInfo</c> struct in server/websocket.go.
|
||||
/// </summary>
|
||||
internal sealed class WsReadInfo
|
||||
{
|
||||
/// <summary>Whether masking is disabled for this connection (e.g. leaf node).</summary>
|
||||
public bool NoMasking { get; set; }
|
||||
|
||||
/// <summary>Whether per-message deflate compression is active.</summary>
|
||||
public bool Compressed { get; set; }
|
||||
|
||||
/// <summary>The current frame opcode.</summary>
|
||||
public WsOpCode FrameType { get; set; }
|
||||
|
||||
/// <summary>Number of payload bytes remaining in the current frame.</summary>
|
||||
public int PayloadLeft { get; set; }
|
||||
|
||||
/// <summary>The 4-byte masking key (only valid when masking is active).</summary>
|
||||
public int[] Mask { get; set; } = new int[4];
|
||||
|
||||
/// <summary>Current offset into <see cref="Mask"/>.</summary>
|
||||
public int MaskOffset { get; set; }
|
||||
|
||||
/// <summary>Accumulated compressed payload buffers awaiting decompression.</summary>
|
||||
public byte[]? Compress { get; set; }
|
||||
|
||||
public WsReadInfo() { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Server-level WebSocket state, shared across all WebSocket connections.
|
||||
/// Mirrors Go <c>srvWebsocket</c> struct in server/websocket.go.
|
||||
/// Replaces the stub in NatsServerTypes.cs.
|
||||
/// </summary>
|
||||
internal sealed class SrvWebsocket
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracks WebSocket connect URLs per server (ref-counted).
|
||||
/// Mirrors Go <c>connectURLsMap refCountedUrlSet</c>.
|
||||
/// </summary>
|
||||
public RefCountedUrlSet ConnectUrlsMap { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// TLS configuration for the WebSocket listener.
|
||||
/// Mirrors Go <c>tls bool</c> field (true if TLS is required).
|
||||
/// </summary>
|
||||
public System.Net.Security.SslServerAuthenticationOptions? TlsConfig { get; set; }
|
||||
|
||||
/// <summary>Whether per-message deflate compression is enabled globally.</summary>
|
||||
public bool Compression { get; set; }
|
||||
|
||||
/// <summary>Host the WebSocket server is listening on.</summary>
|
||||
public string Host { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Port the WebSocket server is listening on (may be ephemeral).</summary>
|
||||
public int Port { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles WebSocket upgrade and framing for a single connection.
|
||||
/// Mirrors the WebSocket-related methods on Go <c>client</c> in server/websocket.go.
|
||||
/// Full implementation is deferred to session 23.
|
||||
/// </summary>
|
||||
internal sealed class WebSocketHandler
|
||||
{
|
||||
private readonly NatsServer _server;
|
||||
|
||||
public WebSocketHandler(NatsServer server)
|
||||
{
|
||||
_server = server;
|
||||
}
|
||||
|
||||
/// <summary>Upgrades an HTTP connection to WebSocket protocol.</summary>
|
||||
public void UpgradeToWebSocket(
|
||||
System.IO.Stream stream,
|
||||
System.Net.Http.Headers.HttpRequestHeaders headers)
|
||||
=> throw new NotImplementedException("TODO: session 23 — websocket");
|
||||
|
||||
/// <summary>Parses a WebSocket frame from the given buffer slice.</summary>
|
||||
public void ParseFrame(byte[] data, int offset, int count)
|
||||
=> throw new NotImplementedException("TODO: session 23 — websocket");
|
||||
|
||||
/// <summary>Writes a WebSocket frame with the given payload.</summary>
|
||||
public void WriteFrame(WsOpCode opCode, byte[] payload, bool final, bool compress)
|
||||
=> throw new NotImplementedException("TODO: session 23 — websocket");
|
||||
|
||||
/// <summary>Writes a WebSocket close frame with the given status code and reason.</summary>
|
||||
public void WriteCloseFrame(int statusCode, string reason)
|
||||
=> throw new NotImplementedException("TODO: session 23 — websocket");
|
||||
}
|
||||
Reference in New Issue
Block a user