feat(batch5): implement jetstream error helpers and group01 constructors

This commit is contained in:
Joseph Doherty
2026-02-28 08:25:56 -05:00
parent 9fa81d472e
commit 9f30fe6033
6 changed files with 349 additions and 25 deletions

View File

@@ -0,0 +1,147 @@
// Copyright 2020-2026 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
//
// Generated constructor surface for JetStream API errors.
// Source parity: server/jetstream_errors_generated.go
namespace ZB.MOM.NatsNet.Server;
public static partial class JsApiErrors
{
public static JsApiError NewJSAccountResourcesExceededError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(AccountResourcesExceeded);
}
public static JsApiError NewJSAtomicPublishContainsDuplicateMessageError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(AtomicPublishContainsDuplicateMessage);
}
public static JsApiError NewJSAtomicPublishDisabledError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(AtomicPublishDisabled);
}
public static JsApiError NewJSAtomicPublishIncompleteBatchError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(AtomicPublishIncompleteBatch);
}
public static JsApiError NewJSAtomicPublishInvalidBatchCommitError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(AtomicPublishInvalidBatchCommit);
}
public static JsApiError NewJSAtomicPublishInvalidBatchIDError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(AtomicPublishInvalidBatchID);
}
public static JsApiError NewJSAtomicPublishMissingSeqError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(AtomicPublishMissingSeq);
}
public static JsApiError NewJSBadRequestError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(BadRequest);
}
public static JsApiError NewJSClusterIncompleteError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(ClusterIncomplete);
}
public static JsApiError NewJSClusterNotActiveError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(ClusterNotActive);
}
public static JsApiError NewJSClusterNotAssignedError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(ClusterNotAssigned);
}
public static JsApiError NewJSClusterNotAvailError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(ClusterNotAvail);
}
public static JsApiError NewJSClusterNotLeaderError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(ClusterNotLeader);
}
public static JsApiError NewJSClusterPeerNotMemberError(params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(ClusterPeerNotMember);
}
public static JsApiError NewJSAtomicPublishTooLargeBatchError(object? size, params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return NewWithTags(AtomicPublishTooLargeBatch, "{size}", size);
}
public static JsApiError NewJSAtomicPublishUnsupportedHeaderBatchError(object? header, params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return NewWithTags(AtomicPublishUnsupportedHeaderBatch, "{header}", header);
}
public static JsApiError NewJSClusterNoPeersError(Exception err, params ErrorOption[] opts)
{
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return NewWithTags(ClusterNoPeers, "{err}", err);
}
}

View File

@@ -43,7 +43,7 @@ public sealed class JsApiError
/// Pre-built <see cref="JsApiError"/> instances for all JetStream error codes.
/// Mirrors the <c>ApiErrors</c> map in server/jetstream_errors_generated.go.
/// </summary>
public static class JsApiErrors
public static partial class JsApiErrors
{
public delegate object? ErrorOption();
@@ -356,14 +356,10 @@ public static class JsApiErrors
/// </summary>
public static JsApiError NewJSRestoreSubscribeFailedError(Exception err, string subject, params ErrorOption[] opts)
{
var overridden = ParseUnless(opts);
if (overridden != null)
return overridden;
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return NewWithTags(
RestoreSubscribeFailed,
("{err}", err.Message),
("{subject}", subject));
return NewWithTags(RestoreSubscribeFailed, "{subject}", subject, "{err}", err);
}
/// <summary>
@@ -371,11 +367,10 @@ public static class JsApiErrors
/// </summary>
public static JsApiError NewJSStreamRestoreError(Exception err, params ErrorOption[] opts)
{
var overridden = ParseUnless(opts);
if (overridden != null)
return overridden;
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return NewWithTags(StreamRestore, ("{err}", err.Message));
return NewWithTags(StreamRestore, "{err}", err);
}
/// <summary>
@@ -383,20 +378,20 @@ public static class JsApiErrors
/// </summary>
public static JsApiError NewJSPeerRemapError(params ErrorOption[] opts)
{
var overridden = ParseUnless(opts);
return overridden ?? Clone(PeerRemap);
if (ParseOpts(opts) is JsApiError overridden)
return Clone(overridden);
return Clone(PeerRemap);
}
private static JsApiError? ParseUnless(ReadOnlySpan<ErrorOption> opts)
private static object? ParseOpts(params ErrorOption[] opts)
{
foreach (var opt in opts)
{
var value = opt();
if (value is JsApiError apiErr)
return Clone(apiErr);
}
object? value = null;
return null;
foreach (var opt in opts)
value = opt();
return value;
}
private static JsApiError Clone(JsApiError source) => new()
@@ -406,13 +401,43 @@ public static class JsApiErrors
Description = source.Description,
};
private static JsApiError NewWithTags(JsApiError source, params (string key, string value)[] replacements)
private static string[] ToReplacerArgs(params object?[] replacements)
{
var args = new List<string>(replacements.Length);
string key = string.Empty;
for (var i = 0; i < replacements.Length; i++)
{
if (i % 2 == 0)
{
key = replacements[i] as string
?? throw new InvalidOperationException("Replacement keys must be strings.");
continue;
}
var value = replacements[i] switch
{
string s => s,
Exception ex => ex.Message,
null => string.Empty,
var other => other.ToString() ?? string.Empty,
};
args.Add(key);
args.Add(value);
}
return args.ToArray();
}
private static JsApiError NewWithTags(JsApiError source, params object?[] replacements)
{
var clone = Clone(source);
var description = clone.Description ?? string.Empty;
var args = ToReplacerArgs(replacements);
foreach (var (key, value) in replacements)
description = description.Replace(key, value, StringComparison.Ordinal);
for (var i = 0; i + 1 < args.Length; i += 2)
description = description.Replace(args[i], args[i + 1], StringComparison.Ordinal);
clone.Description = description;
return clone;