feat(mqtt): add MQTT packet parser, dispatch, and ReadLoop integration

Implement Task 2 of MQTT orchestration:
- Create MqttParser.cs with loop-based packet parser and dispatch switch
- Add MqttReader field to MqttHandler for per-connection parsing state
- Wire ReadLoop to call MqttParser for MQTT connections
- Implement PINGREQ handler (enqueues PINGRESP)
- CONNECT-first enforcement (rejects non-CONNECT as first packet)
- Partial packet handling via MqttReader pending buffer
- 13 unit tests covering parser, dispatch, partial packets, and edge cases
- Stub dispatch entries for CONNECT, PUBLISH, SUB, UNSUB, DISCONNECT (NotImplementedException)
This commit is contained in:
Joseph Doherty
2026-03-01 15:41:45 -05:00
parent 6fb7f43335
commit 2e2ffee41a
5 changed files with 504 additions and 1 deletions

View File

@@ -25,6 +25,7 @@ using Microsoft.Extensions.Logging;
using ZB.MOM.NatsNet.Server.Auth;
using ZB.MOM.NatsNet.Server.Internal;
using ZB.MOM.NatsNet.Server.Internal.DataStructures;
using ZB.MOM.NatsNet.Server.Mqtt;
using ZB.MOM.NatsNet.Server.Protocol;
using ZB.MOM.NatsNet.Server.WebSocket;
@@ -1405,8 +1406,59 @@ public sealed partial class ClientConnection
internal void ReadLoop(byte[]? pre)
{
LastIn = DateTime.UtcNow;
// Process any pre-read bytes first.
if (pre is { Length: > 0 })
{
TraceInOp("PRE", pre);
if (IsMqtt())
{
var preErr = MqttParser.Parse(this, pre, pre.Length);
if (preErr != null)
{
CloseConnection(ClosedState.ParseError);
return;
}
}
}
// MQTT clients use the MqttParser; NATS clients use ProtocolParser (not yet wired).
if (!IsMqtt())
return;
// Main read loop — read from network stream until closed.
var buf = new byte[32768]; // 32 KB read buffer
try
{
while (true)
{
int n;
try
{
n = _nc!.Read(buf, 0, buf.Length);
}
catch
{
break; // Connection closed or errored.
}
if (n <= 0)
break; // Connection closed.
LastIn = DateTime.UtcNow;
var err = MqttParser.Parse(this, buf, n);
if (err != null)
{
CloseConnection(ClosedState.ParseError);
return;
}
}
}
finally
{
CloseConnection(ClosedState.ClientClosed);
}
}
// =========================================================================