batch37 task3 implement group B direct-get and pipeline
This commit is contained in:
@@ -0,0 +1,246 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Linq;
|
||||
using ZB.MOM.NatsNet.Server.Internal;
|
||||
using ZB.MOM.NatsNet.Server.Internal.DataStructures;
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server;
|
||||
|
||||
internal sealed partial class NatsStream
|
||||
{
|
||||
internal static (string Ttl, bool Ok) GetMessageScheduleTTL(byte[]? hdr)
|
||||
{
|
||||
if (hdr == null || hdr.Length == 0)
|
||||
return (string.Empty, true);
|
||||
|
||||
var ttl = NatsMessageHeaders.GetHeader(NatsHeaderConstants.JsScheduleTtl, hdr);
|
||||
if (ttl == null || ttl.Length == 0)
|
||||
return (string.Empty, true);
|
||||
|
||||
var ttlValue = Encoding.ASCII.GetString(ttl);
|
||||
var (_, err) = ParseMessageTTL(ttlValue);
|
||||
return err == null ? (ttlValue, true) : (string.Empty, false);
|
||||
}
|
||||
|
||||
internal static string GetMessageScheduleTarget(byte[]? hdr)
|
||||
{
|
||||
if (hdr == null || hdr.Length == 0)
|
||||
return string.Empty;
|
||||
|
||||
var value = NatsMessageHeaders.GetHeader(NatsHeaderConstants.JsScheduleTarget, hdr);
|
||||
return value == null || value.Length == 0 ? string.Empty : Encoding.ASCII.GetString(value);
|
||||
}
|
||||
|
||||
internal static string GetMessageScheduleSource(byte[]? hdr)
|
||||
{
|
||||
if (hdr == null || hdr.Length == 0)
|
||||
return string.Empty;
|
||||
|
||||
var value = NatsMessageHeaders.GetHeader(NatsHeaderConstants.JsScheduleSource, hdr);
|
||||
return value == null || value.Length == 0 ? string.Empty : Encoding.ASCII.GetString(value);
|
||||
}
|
||||
|
||||
internal static string GetBatchId(byte[]? hdr)
|
||||
{
|
||||
if (hdr == null || hdr.Length == 0)
|
||||
return string.Empty;
|
||||
|
||||
var value = NatsMessageHeaders.GetHeader(NatsHeaderConstants.JsBatchId, hdr);
|
||||
return value == null || value.Length == 0 ? string.Empty : Encoding.ASCII.GetString(value);
|
||||
}
|
||||
|
||||
internal static (ulong Seq, bool Exists) GetBatchSequence(byte[]? hdr)
|
||||
{
|
||||
if (hdr == null || hdr.Length == 0)
|
||||
return (0, false);
|
||||
|
||||
var value = NatsMessageHeaders.SliceHeader(NatsHeaderConstants.JsBatchSeq, hdr);
|
||||
if (value is null || value.Value.Length == 0)
|
||||
return (0, false);
|
||||
|
||||
var parsed = ServerUtilities.ParseInt64(value.Value.Span);
|
||||
return parsed < 0 ? (0, false) : ((ulong)parsed, true);
|
||||
}
|
||||
|
||||
public bool IsClustered()
|
||||
{
|
||||
_mu.EnterReadLock();
|
||||
try
|
||||
{
|
||||
return IsClusteredInternal();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mu.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsClusteredInternal() => _node is IRaftNode;
|
||||
|
||||
internal void QueueInbound(IpQueue<InMsg> inbound, string subject, string? reply, byte[]? hdr, byte[]? msg, object? sourceInfo, object? trace)
|
||||
{
|
||||
_ = sourceInfo;
|
||||
_ = trace;
|
||||
|
||||
var inboundMsg = InMsg.Rent();
|
||||
inboundMsg.Subject = subject;
|
||||
inboundMsg.Reply = reply;
|
||||
inboundMsg.Hdr = hdr;
|
||||
inboundMsg.Msg = msg;
|
||||
|
||||
var (_, error) = inbound.Push(inboundMsg);
|
||||
if (error != null)
|
||||
inboundMsg.ReturnToPool();
|
||||
}
|
||||
|
||||
internal JsApiMsgGetResponse ProcessDirectGetRequest(string reply, byte[]? hdr, byte[]? msg)
|
||||
{
|
||||
var response = new JsApiMsgGetResponse();
|
||||
if (string.IsNullOrWhiteSpace(reply))
|
||||
return response;
|
||||
|
||||
if (JetStreamVersioning.ErrorOnRequiredApiLevel(GetRequiredApiLevelHeader(hdr)))
|
||||
{
|
||||
response.Error = JsApiErrors.NewJSRequiredApiLevelError();
|
||||
return response;
|
||||
}
|
||||
|
||||
if (msg == null || msg.Length == 0)
|
||||
{
|
||||
response.Error = JsApiErrors.NewJSBadRequestError();
|
||||
return response;
|
||||
}
|
||||
|
||||
JsApiMsgGetRequest? request;
|
||||
try
|
||||
{
|
||||
request = JsonSerializer.Deserialize<JsApiMsgGetRequest>(msg);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
response.Error = JsApiErrors.NewJSBadRequestError();
|
||||
return response;
|
||||
}
|
||||
|
||||
if (request == null)
|
||||
{
|
||||
response.Error = JsApiErrors.NewJSBadRequestError();
|
||||
return response;
|
||||
}
|
||||
|
||||
return GetDirectRequest(request, reply);
|
||||
}
|
||||
|
||||
internal JsApiMsgGetResponse ProcessDirectGetLastBySubjectRequest(string subject, string reply, byte[]? hdr, byte[]? msg)
|
||||
{
|
||||
var response = new JsApiMsgGetResponse();
|
||||
if (string.IsNullOrWhiteSpace(reply))
|
||||
return response;
|
||||
|
||||
if (JetStreamVersioning.ErrorOnRequiredApiLevel(GetRequiredApiLevelHeader(hdr)))
|
||||
{
|
||||
response.Error = JsApiErrors.NewJSRequiredApiLevelError();
|
||||
return response;
|
||||
}
|
||||
|
||||
var request = msg == null || msg.Length == 0
|
||||
? new JsApiMsgGetRequest()
|
||||
: JsonSerializer.Deserialize<JsApiMsgGetRequest>(msg) ?? new JsApiMsgGetRequest();
|
||||
|
||||
var key = ExtractDirectGetLastBySubjectKey(subject);
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
response.Error = JsApiErrors.NewJSBadRequestError();
|
||||
return response;
|
||||
}
|
||||
|
||||
request.LastFor = key;
|
||||
return GetDirectRequest(request, reply);
|
||||
}
|
||||
|
||||
internal JsApiMsgGetResponse GetDirectMulti(JsApiMsgGetRequest request, string reply)
|
||||
{
|
||||
_ = reply;
|
||||
|
||||
if (Store == null)
|
||||
return new JsApiMsgGetResponse { Error = JsApiErrors.NewJSNoMessageFoundError() };
|
||||
|
||||
var filters = request.MultiLastFor ?? [];
|
||||
if (filters.Length == 0)
|
||||
return new JsApiMsgGetResponse { Error = JsApiErrors.NewJSNoMessageFoundError() };
|
||||
|
||||
var (seqs, error) = Store.MultiLastSeqs(filters, request.UpToSeq, 1024);
|
||||
if (error != null || seqs.Length == 0)
|
||||
return new JsApiMsgGetResponse { Error = JsApiErrors.NewJSNoMessageFoundError() };
|
||||
|
||||
var firstSeq = seqs[0];
|
||||
var loaded = Store.LoadMsg(firstSeq, new StoreMsg());
|
||||
if (loaded == null)
|
||||
return new JsApiMsgGetResponse { Error = JsApiErrors.NewJSNoMessageFoundError() };
|
||||
|
||||
return new JsApiMsgGetResponse { Message = ToStoredMsg(loaded) };
|
||||
}
|
||||
|
||||
internal JsApiMsgGetResponse GetDirectRequest(JsApiMsgGetRequest request, string reply)
|
||||
{
|
||||
_ = reply;
|
||||
if (request.MultiLastFor is { Length: > 0 })
|
||||
return GetDirectMulti(request, reply);
|
||||
|
||||
if (Store == null)
|
||||
return new JsApiMsgGetResponse { Error = JsApiErrors.NewJSNoMessageFoundError() };
|
||||
|
||||
StoreMsg? loaded = null;
|
||||
if (request.Seq > 0)
|
||||
{
|
||||
loaded = Store.LoadMsg(request.Seq, new StoreMsg());
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(request.LastFor))
|
||||
{
|
||||
loaded = Store.LoadLastMsg(request.LastFor!, new StoreMsg());
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(request.NextFor))
|
||||
{
|
||||
var (sm, _) = Store.LoadNextMsg(request.NextFor!, SubscriptionIndex.SubjectHasWildcard(request.NextFor!), request.Seq, new StoreMsg());
|
||||
loaded = sm;
|
||||
}
|
||||
else if (request.StartTime.HasValue)
|
||||
{
|
||||
var seq = Store.GetSeqFromTime(request.StartTime.Value);
|
||||
if (seq > 0)
|
||||
loaded = Store.LoadMsg(seq, new StoreMsg());
|
||||
}
|
||||
|
||||
if (loaded == null)
|
||||
return new JsApiMsgGetResponse { Error = JsApiErrors.NewJSNoMessageFoundError() };
|
||||
|
||||
return new JsApiMsgGetResponse { Message = ToStoredMsg(loaded) };
|
||||
}
|
||||
|
||||
private static StoredMsg ToStoredMsg(StoreMsg loaded) => new()
|
||||
{
|
||||
Subject = loaded.Subject,
|
||||
Sequence = loaded.Seq,
|
||||
Header = loaded.Hdr,
|
||||
Data = loaded.Msg,
|
||||
Time = DateTimeOffset.FromUnixTimeMilliseconds(loaded.Ts / 1_000_000L).UtcDateTime,
|
||||
};
|
||||
|
||||
private static string? GetRequiredApiLevelHeader(byte[]? hdr)
|
||||
{
|
||||
if (hdr == null || hdr.Length == 0)
|
||||
return null;
|
||||
|
||||
var value = NatsMessageHeaders.GetHeader(JsApiSubjects.JsRequiredApiLevel, hdr);
|
||||
return value == null || value.Length == 0 ? null : Encoding.ASCII.GetString(value);
|
||||
}
|
||||
|
||||
private static string ExtractDirectGetLastBySubjectKey(string subject)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(subject))
|
||||
return string.Empty;
|
||||
|
||||
var parts = subject.Split('.');
|
||||
return parts.Length <= 5 ? string.Empty : string.Join('.', parts.Skip(5));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user