task5(batch39): add reply parsing and consumer identity helpers

This commit is contained in:
Joseph Doherty
2026-03-01 01:25:26 -05:00
parent 519ee6ad49
commit c0ec1f3341
4 changed files with 293 additions and 0 deletions

View File

@@ -0,0 +1,118 @@
namespace ZB.MOM.NatsNet.Server;
internal sealed partial class NatsConsumer
{
internal static (ulong StreamSequence, ulong DeliverySequence, ulong DeliveryCount, long Timestamp, ulong Pending) ReplyInfo(string subject)
{
if (string.IsNullOrWhiteSpace(subject))
return (0, 0, 0, 0, 0);
var tokens = subject.Split('.', StringSplitOptions.RemoveEmptyEntries);
if (tokens.Length < 9 || !string.Equals(tokens[0], "$JS", StringComparison.Ordinal) || !string.Equals(tokens[1], "ACK", StringComparison.Ordinal))
return (0, 0, 0, 0, 0);
var deliveryCount = (ulong)Math.Max(0, ParseAckReplyNum(tokens[4]));
var streamSequence = (ulong)Math.Max(0, ParseAckReplyNum(tokens[5]));
var deliverySequence = (ulong)Math.Max(0, ParseAckReplyNum(tokens[6]));
var timestamp = ParseAckReplyNum(tokens[7]);
var pending = (ulong)Math.Max(0, ParseAckReplyNum(tokens[8]));
return (streamSequence, deliverySequence, deliveryCount, timestamp, pending);
}
internal ulong NextSeq()
{
_mu.EnterReadLock();
try
{
return _state.Delivered.Consumer + 1;
}
finally
{
_mu.ExitReadLock();
}
}
internal bool HasSkipListPending() => false;
internal void SelectStartingSeqNo()
{
_mu.EnterWriteLock();
try
{
var start = Config.OptStartSeq > 0 ? Config.OptStartSeq : 1UL;
_state.Delivered = new SequencePair { Consumer = 1, Stream = start };
_state.AckFloor = new SequencePair { Consumer = 0, Stream = start > 0 ? start - 1 : 0 };
_npc = 0;
_npf = _state.AckFloor.Stream;
}
finally
{
_mu.ExitWriteLock();
}
}
internal static bool IsDurableConsumer(ConsumerConfig? config) =>
config is not null && !string.IsNullOrWhiteSpace(config.Durable);
internal bool IsDurable() => !string.IsNullOrWhiteSpace(Config.Durable);
internal string String() => Name;
internal static string CreateConsumerName() => Guid.NewGuid().ToString("N")[..12];
internal NatsStream? GetStream()
{
_mu.EnterReadLock();
try
{
return _streamRef;
}
finally
{
_mu.ExitReadLock();
}
}
internal string StreamName() => GetStream()?.Name ?? string.Empty;
internal bool IsActive()
{
_mu.EnterReadLock();
try
{
return !_closed && (_hasLocalDeliveryInterest || IsPullMode());
}
finally
{
_mu.ExitReadLock();
}
}
internal bool HasNoLocalInterest() => !HasDeliveryInterest(localInterest: true);
internal void Purge()
{
_mu.EnterWriteLock();
try
{
_state.Pending?.Clear();
_state.Redelivered?.Clear();
_redeliveryQueue.Clear();
_redeliveryIndex.Clear();
_npc = 0;
}
finally
{
_mu.ExitWriteLock();
}
}
internal static Timer? StopAndClearTimer(Timer? timer)
{
timer?.Dispose();
return null;
}
internal void DeleteWithoutAdvisory() => Stop();
}

View File

@@ -227,6 +227,20 @@ internal sealed partial class NatsStream
}
}
internal Exception? DeleteConsumer(NatsConsumer consumer)
{
ArgumentNullException.ThrowIfNull(consumer);
lock (_consumersSync)
{
_consumers.Remove(consumer.Name);
_consumerList.RemoveAll(c => ReferenceEquals(c, consumer));
}
consumer.DeleteWithoutAdvisory();
return null;
}
internal void SwapSigSubs(NatsConsumer consumer, string[]? newFilters)
{
_ = consumer;