feat: add protocol tracing (<<- op arg) at LogLevel.Trace
This commit is contained in:
@@ -48,6 +48,7 @@ public sealed class NatsClient : IDisposable
|
||||
public ClientOptions? ClientOpts { get; private set; }
|
||||
public IMessageRouter? Router { get; set; }
|
||||
public Account? Account { get; private set; }
|
||||
public ClientPermissions? Permissions => _permissions;
|
||||
|
||||
private readonly ClientFlagHolder _flags = new();
|
||||
public bool ConnectReceived => _flags.HasFlag(ClientFlags.ConnectReceived);
|
||||
@@ -90,7 +91,7 @@ public sealed class NatsClient : IDisposable
|
||||
_nonce = nonce;
|
||||
_logger = logger;
|
||||
_serverStats = serverStats;
|
||||
_parser = new NatsParser(options.MaxPayload);
|
||||
_parser = new NatsParser(options.MaxPayload, options.Trace ? logger : null);
|
||||
StartTime = DateTime.UtcNow;
|
||||
_lastActivityTicks = StartTime.Ticks;
|
||||
if (socket.RemoteEndPoint is IPEndPoint ep)
|
||||
@@ -348,6 +349,7 @@ public sealed class NatsClient : IDisposable
|
||||
?? new ClientOptions();
|
||||
|
||||
// Authenticate if auth is required
|
||||
AuthResult? authResult = null;
|
||||
if (_authService.IsAuthRequired)
|
||||
{
|
||||
var context = new ClientAuthContext
|
||||
@@ -356,8 +358,8 @@ public sealed class NatsClient : IDisposable
|
||||
Nonce = _nonce ?? [],
|
||||
};
|
||||
|
||||
var result = _authService.Authenticate(context);
|
||||
if (result == null)
|
||||
authResult = _authService.Authenticate(context);
|
||||
if (authResult == null)
|
||||
{
|
||||
_logger.LogWarning("Client {ClientId} authentication failed", Id);
|
||||
await SendErrAndCloseAsync(NatsProtocol.ErrAuthorizationViolation, ClientClosedReason.AuthenticationViolation);
|
||||
@@ -365,12 +367,12 @@ public sealed class NatsClient : IDisposable
|
||||
}
|
||||
|
||||
// Build permissions from auth result
|
||||
_permissions = ClientPermissions.Build(result.Permissions);
|
||||
_permissions = ClientPermissions.Build(authResult.Permissions);
|
||||
|
||||
// Resolve account
|
||||
if (Router is NatsServer server)
|
||||
{
|
||||
var accountName = result.AccountName ?? Account.GlobalAccountName;
|
||||
var accountName = authResult.AccountName ?? Account.GlobalAccountName;
|
||||
Account = server.GetOrCreateAccount(accountName);
|
||||
if (!Account.AddClient(Id))
|
||||
{
|
||||
@@ -381,7 +383,7 @@ public sealed class NatsClient : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogDebug("Client {ClientId} authenticated as {Identity}", Id, result.Identity);
|
||||
_logger.LogDebug("Client {ClientId} authenticated as {Identity}", Id, authResult.Identity);
|
||||
|
||||
// Clear nonce after use -- defense-in-depth against memory dumps
|
||||
if (_nonce != null)
|
||||
@@ -413,6 +415,32 @@ public sealed class NatsClient : IDisposable
|
||||
_flags.SetFlag(ClientFlags.ConnectReceived);
|
||||
_flags.SetFlag(ClientFlags.ConnectProcessFinished);
|
||||
_logger.LogDebug("CONNECT received from client {ClientId}, name={ClientName}", Id, ClientOpts?.Name);
|
||||
|
||||
// Start auth expiry timer if needed
|
||||
if (_authService.IsAuthRequired && authResult?.Expiry is { } expiry)
|
||||
{
|
||||
var remaining = expiry - DateTimeOffset.UtcNow;
|
||||
if (remaining > TimeSpan.Zero)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(remaining, _clientCts!.Token);
|
||||
_logger.LogDebug("Client {ClientId} authentication expired", Id);
|
||||
await SendErrAndCloseAsync("Authentication Expired",
|
||||
ClientClosedReason.AuthenticationExpired);
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
}, _clientCts!.Token);
|
||||
}
|
||||
else
|
||||
{
|
||||
await SendErrAndCloseAsync("Authentication Expired",
|
||||
ClientClosedReason.AuthenticationExpired);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessSub(ParsedCommand cmd)
|
||||
@@ -425,6 +453,24 @@ public sealed class NatsClient : IDisposable
|
||||
return;
|
||||
}
|
||||
|
||||
// Per-connection subscription limit
|
||||
if (_options.MaxSubs > 0 && _subs.Count >= _options.MaxSubs)
|
||||
{
|
||||
_logger.LogDebug("Client {ClientId} max subscriptions exceeded", Id);
|
||||
_ = SendErrAndCloseAsync(NatsProtocol.ErrMaxSubscriptionsExceeded,
|
||||
ClientClosedReason.MaxSubscriptionsExceeded);
|
||||
return;
|
||||
}
|
||||
|
||||
// Per-account subscription limit
|
||||
if (Account != null && !Account.IncrementSubscriptions())
|
||||
{
|
||||
_logger.LogDebug("Client {ClientId} account subscription limit exceeded", Id);
|
||||
_ = SendErrAndCloseAsync(NatsProtocol.ErrMaxSubscriptionsExceeded,
|
||||
ClientClosedReason.MaxSubscriptionsExceeded);
|
||||
return;
|
||||
}
|
||||
|
||||
var sub = new Subscription
|
||||
{
|
||||
Subject = cmd.Subject!,
|
||||
@@ -455,6 +501,7 @@ public sealed class NatsClient : IDisposable
|
||||
}
|
||||
|
||||
_subs.Remove(cmd.Sid!);
|
||||
Account?.DecrementSubscriptions();
|
||||
|
||||
Account?.SubList.Remove(sub);
|
||||
}
|
||||
@@ -701,6 +748,12 @@ public sealed class NatsClient : IDisposable
|
||||
catch (ObjectDisposedException) { }
|
||||
}
|
||||
|
||||
public void RemoveSubscription(string sid)
|
||||
{
|
||||
if (_subs.Remove(sid))
|
||||
Account?.DecrementSubscriptions();
|
||||
}
|
||||
|
||||
public void RemoveAllSubscriptions(SubList subList)
|
||||
{
|
||||
foreach (var sub in _subs.Values)
|
||||
|
||||
Reference in New Issue
Block a user