feat: port sessions 12 & 13 — Events/Monitoring/MsgTrace + Config Reload

Session 12 (218 features, IDs 854-950, 2166-2251, 2405-2439):
- EventTypes: system subjects, event message types, InternalState, ConnectEventMsg,
  DisconnectEventMsg, AccountNumConns, ServerIdentity, DataStats
- MonitorTypes: Connz, ConnInfo, ConnzOptions, ConnState, ProxyInfo, TlsPeerCert
- MonitorSortOptions: SortOpt, ConnInfos, all 13 sort comparers
- MsgTraceTypes: IMsgTrace, MsgTraceBase + 6 concrete types, custom JSON converter

Session 13 (89 features, IDs 2800-2888):
- ReloadOptions: IReloadOption interface, NoopReloadOption base, 50 option classes
  covering logging, TLS, auth, cluster, JetStream, MQTT, OCSP, misc
This commit is contained in:
Joseph Doherty
2026-02-26 15:46:14 -05:00
parent 12a14ec476
commit ce45dff994
11 changed files with 2971 additions and 47 deletions

View File

@@ -0,0 +1,778 @@
// Copyright 2018-2026 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Adapted from server/events.go in the NATS server Go source.
using System.Text.Json.Serialization;
using ZB.MOM.NatsNet.Server.Auth.CertificateIdentityProvider;
using ZB.MOM.NatsNet.Server.Internal;
namespace ZB.MOM.NatsNet.Server;
// ============================================================================
// System subject constants
// Mirrors the const block at the top of server/events.go.
// ============================================================================
/// <summary>
/// System-account subject templates and constants used for internal NATS server
/// event routing. All format-string fields use <see cref="string.Format"/> with
/// the appropriate server/account ID substituted at call time.
/// Mirrors the const block in server/events.go.
/// </summary>
public static class SystemSubjects
{
// Account lookup / claims
public const string AccLookupReqSubj = "$SYS.REQ.ACCOUNT.{0}.CLAIMS.LOOKUP";
public const string AccPackReqSubj = "$SYS.REQ.CLAIMS.PACK";
public const string AccListReqSubj = "$SYS.REQ.CLAIMS.LIST";
public const string AccClaimsReqSubj = "$SYS.REQ.CLAIMS.UPDATE";
public const string AccDeleteReqSubj = "$SYS.REQ.CLAIMS.DELETE";
// Connection events
public const string ConnectEventSubj = "$SYS.ACCOUNT.{0}.CONNECT";
public const string DisconnectEventSubj = "$SYS.ACCOUNT.{0}.DISCONNECT";
// Direct request routing
public const string AccDirectReqSubj = "$SYS.REQ.ACCOUNT.{0}.{1}";
public const string AccPingReqSubj = "$SYS.REQ.ACCOUNT.PING.{0}";
// Account update events (both old and new forms kept for backward compatibility)
public const string AccUpdateEventSubjOld = "$SYS.ACCOUNT.{0}.CLAIMS.UPDATE";
public const string AccUpdateEventSubjNew = "$SYS.REQ.ACCOUNT.{0}.CLAIMS.UPDATE";
public const string ConnsRespSubj = "$SYS._INBOX_.{0}";
public const string AccConnsEventSubjNew = "$SYS.ACCOUNT.{0}.SERVER.CONNS";
public const string AccConnsEventSubjOld = "$SYS.SERVER.ACCOUNT.{0}.CONNS"; // backward compat
// Server lifecycle events
public const string LameDuckEventSubj = "$SYS.SERVER.{0}.LAMEDUCK";
public const string ShutdownEventSubj = "$SYS.SERVER.{0}.SHUTDOWN";
// Client control
public const string ClientKickReqSubj = "$SYS.REQ.SERVER.{0}.KICK";
public const string ClientLdmReqSubj = "$SYS.REQ.SERVER.{0}.LDM";
// Auth error events
public const string AuthErrorEventSubj = "$SYS.SERVER.{0}.CLIENT.AUTH.ERR";
public const string AuthErrorAccountEventSubj = "$SYS.ACCOUNT.CLIENT.AUTH.ERR";
// Stats
public const string ServerStatsSubj = "$SYS.SERVER.{0}.STATSZ";
public const string ServerDirectReqSubj = "$SYS.REQ.SERVER.{0}.{1}";
public const string ServerPingReqSubj = "$SYS.REQ.SERVER.PING.{0}";
public const string ServerStatsPingReqSubj = "$SYS.REQ.SERVER.PING"; // deprecated; use STATSZ variant
public const string ServerReloadReqSubj = "$SYS.REQ.SERVER.{0}.RELOAD";
// Leaf node
public const string LeafNodeConnectEventSubj = "$SYS.ACCOUNT.{0}.LEAFNODE.CONNECT"; // internal only
// Latency
public const string RemoteLatencyEventSubj = "$SYS.LATENCY.M2.{0}";
public const string InboxRespSubj = "$SYS._INBOX.{0}.{1}";
// User info
public const string UserDirectInfoSubj = "$SYS.REQ.USER.INFO";
public const string UserDirectReqSubj = "$SYS.REQ.USER.{0}.INFO";
// Subscription count
public const string AccNumSubsReqSubj = "$SYS.REQ.ACCOUNT.NSUBS";
// Debug
public const string AccSubsSubj = "$SYS.DEBUG.SUBSCRIBERS";
// OCSP peer events
public const string OcspPeerRejectEventSubj = "$SYS.SERVER.{0}.OCSP.PEER.CONN.REJECT";
public const string OcspPeerChainlinkInvalidEventSubj = "$SYS.SERVER.{0}.OCSP.PEER.LINK.INVALID";
// Parsing constants (token indexes / counts)
public const int AccLookupReqTokens = 6;
public const int ShutdownEventTokens = 4;
public const int ServerSubjectIndex = 2;
public const int AccUpdateTokensNew = 6;
public const int AccUpdateTokensOld = 5;
public const int AccUpdateAccIdxOld = 2;
public const int AccReqTokens = 5;
public const int AccReqAccIndex = 3;
}
// ============================================================================
// Advisory message type schema URI constants
// Mirrors the const string variables near each struct in server/events.go.
// ============================================================================
public static class EventMsgTypes
{
public const string ConnectEventMsgType = "io.nats.server.advisory.v1.client_connect";
public const string DisconnectEventMsgType = "io.nats.server.advisory.v1.client_disconnect";
public const string OcspPeerRejectEventMsgType = "io.nats.server.advisory.v1.ocsp_peer_reject";
public const string OcspPeerChainlinkInvalidEventMsgType = "io.nats.server.advisory.v1.ocsp_peer_link_invalid";
public const string AccountNumConnsMsgType = "io.nats.server.advisory.v1.account_connections";
}
// ============================================================================
// Heartbeat / rate-limit intervals (mirrors package-level vars in events.go)
// ============================================================================
/// <summary>
/// Default timing constants for server event heartbeats and rate limiting.
/// Mirrors Go package-level <c>var</c> declarations in events.go.
/// </summary>
public static class EventIntervals
{
/// <summary>Default HB interval for events. Mirrors Go <c>eventsHBInterval = 30s</c>.</summary>
public static readonly TimeSpan EventsHbInterval = TimeSpan.FromSeconds(30);
/// <summary>Default HB interval for stats. Mirrors Go <c>statsHBInterval = 10s</c>.</summary>
public static readonly TimeSpan StatsHbInterval = TimeSpan.FromSeconds(10);
/// <summary>Minimum interval between statsz publishes. Mirrors Go <c>defaultStatszRateLimit = 1s</c>.</summary>
public static readonly TimeSpan DefaultStatszRateLimit = TimeSpan.FromSeconds(1);
}
// ============================================================================
// SysMsgHandler — delegate for internal system message dispatch
// Mirrors Go <c>sysMsgHandler</c> func type in events.go.
// ============================================================================
/// <summary>
/// Callback invoked when an internal system message is dispatched.
/// Mirrors Go <c>sysMsgHandler</c> in server/events.go.
/// </summary>
public delegate void SysMsgHandler(
Subscription sub,
NatsClient client,
Account acc,
string subject,
string reply,
byte[] hdr,
byte[] msg);
// ============================================================================
// InSysMsg — queued internal system message
// Mirrors Go <c>inSysMsg</c> struct in server/events.go.
// ============================================================================
/// <summary>
/// Holds a system message queued for internal delivery, avoiding the
/// route/gateway path.
/// Mirrors Go <c>inSysMsg</c> struct in server/events.go.
/// </summary>
internal sealed class InSysMsg
{
public Subscription? Sub { get; set; }
public NatsClient? Client { get; set; }
public Account? Acc { get; set; }
public string Subject { get; set; } = string.Empty;
public string Reply { get; set; } = string.Empty;
public byte[]? Hdr { get; set; }
public byte[]? Msg { get; set; }
public SysMsgHandler? Cb { get; set; }
}
// ============================================================================
// InternalState — server internal/sys state
// Mirrors Go <c>internal</c> struct in server/events.go.
// Uses Monitor lock (lock(this)) in place of Go's embedded sync.Mutex.
// ============================================================================
/// <summary>
/// Holds all internal state used by the server's system-account event
/// machinery: account reference, client, send/receive queues, timers,
/// reply handlers, and heartbeat configuration.
/// Mirrors Go <c>internal</c> struct in server/events.go.
/// </summary>
internal sealed class InternalState
{
// ---- identity / sequencing ----
public Account? Account { get; set; }
public NatsClient? Client { get; set; }
public ulong Seq { get; set; }
public int Sid { get; set; }
// ---- remote server tracking ----
/// <summary>Map of server ID → serverUpdate. Mirrors Go <c>servers map[string]*serverUpdate</c>.</summary>
public Dictionary<string, ServerUpdate> Servers { get; set; } = new();
// ---- timers ----
/// <summary>Sweeper timer. Mirrors Go <c>sweeper *time.Timer</c>.</summary>
public System.Threading.Timer? Sweeper { get; set; }
/// <summary>Stats heartbeat timer. Mirrors Go <c>stmr *time.Timer</c>.</summary>
public System.Threading.Timer? StatsMsgTimer { get; set; }
// ---- reply handlers ----
/// <summary>
/// Pending reply subject → handler map.
/// Mirrors Go <c>replies map[string]msgHandler</c>.
/// </summary>
public Dictionary<string, Action<Subscription, NatsClient, Account, string, string, byte[], byte[]>> Replies { get; set; } = new();
// ---- queues ----
/// <summary>Outbound message send queue. Mirrors Go <c>sendq *ipQueue[*pubMsg]</c>.</summary>
public IpQueue<PubMsg>? SendQueue { get; set; }
/// <summary>Inbound receive queue. Mirrors Go <c>recvq *ipQueue[*inSysMsg]</c>.</summary>
public IpQueue<InSysMsg>? RecvQueue { get; set; }
/// <summary>Priority receive queue for STATSZ/Pings. Mirrors Go <c>recvqp *ipQueue[*inSysMsg]</c>.</summary>
public IpQueue<InSysMsg>? RecvQueuePriority { get; set; }
/// <summary>Reset channel used to restart the send loop. Mirrors Go <c>resetCh chan struct{}</c>.</summary>
public System.Threading.Channels.Channel<bool>? ResetChannel { get; set; }
// ---- durations ----
/// <summary>Maximum time before an orphaned server entry is removed. Mirrors Go <c>orphMax</c>.</summary>
public TimeSpan OrphanMax { get; set; }
/// <summary>Interval at which orphan checks run. Mirrors Go <c>chkOrph</c>.</summary>
public TimeSpan CheckOrphan { get; set; }
/// <summary>Interval between statsz publishes. Mirrors Go <c>statsz</c>.</summary>
public TimeSpan StatszInterval { get; set; }
/// <summary>Client-facing statsz interval. Mirrors Go <c>cstatsz</c>.</summary>
public TimeSpan ClientStatszInterval { get; set; }
// ---- misc ----
/// <summary>Short hash used for shared-inbox routing. Mirrors Go <c>shash string</c>.</summary>
public string ShortHash { get; set; } = string.Empty;
/// <summary>Inbox prefix for this server's internal client. Mirrors Go <c>inboxPre string</c>.</summary>
public string InboxPrefix { get; set; } = string.Empty;
/// <summary>Subscription for remote stats. Mirrors Go <c>remoteStatsSub *subscription</c>.</summary>
public Subscription? RemoteStatsSub { get; set; }
/// <summary>Time of the last statsz publish. Mirrors Go <c>lastStatsz time.Time</c>.</summary>
public DateTime LastStatsz { get; set; }
}
// ============================================================================
// ServerUpdate — remote server heartbeat tracking
// Mirrors Go <c>serverUpdate</c> struct in server/events.go.
// ============================================================================
/// <summary>
/// Tracks the sequence number and last-seen timestamp of a remote server's
/// system heartbeat. Used to detect orphaned servers.
/// Mirrors Go <c>serverUpdate</c> struct in server/events.go.
/// </summary>
internal sealed class ServerUpdate
{
/// <summary>Last sequence number received from the remote server.</summary>
public ulong Seq { get; set; }
/// <summary>Wall-clock time of the last heartbeat.</summary>
public DateTime LTime { get; set; }
}
// ============================================================================
// PubMsg — internally-queued outbound publish message
// Mirrors Go <c>pubMsg</c> struct in server/events.go.
// ============================================================================
/// <summary>
/// Holds an outbound message that the server wants to publish via the internal
/// send loop, avoiding direct route/gateway writes.
/// Mirrors Go <c>pubMsg</c> struct in server/events.go.
/// </summary>
internal sealed class PubMsg
{
public NatsClient? Client { get; set; }
public string Subject { get; set; } = string.Empty;
public string Reply { get; set; } = string.Empty;
public ServerInfo? Si { get; set; }
public byte[]? Hdr { get; set; }
public object? Msg { get; set; }
/// <summary>Compression type. TODO: session 12 — wire up compressionType enum.</summary>
public int Oct { get; set; }
public bool Echo { get; set; }
public bool Last { get; set; }
// TODO: session 12 — add pool return helper (returnToPool).
}
// ============================================================================
// DataStats — message/byte counter pair (sent or received)
// Mirrors Go <c>DataStats</c> struct in server/events.go.
// ============================================================================
/// <summary>
/// Reports how many messages and bytes were sent or received.
/// Optionally breaks out gateway, route, and leaf-node traffic.
/// Mirrors Go <c>DataStats</c> struct in server/events.go.
/// </summary>
public sealed class DataStats
{
[JsonPropertyName("msgs")]
public long Msgs { get; set; }
[JsonPropertyName("bytes")]
public long Bytes { get; set; }
[JsonPropertyName("gateways")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public MsgBytes? Gateways { get; set; }
[JsonPropertyName("routes")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public MsgBytes? Routes { get; set; }
[JsonPropertyName("leafs")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public MsgBytes? Leafs { get; set; }
}
// ============================================================================
// MsgBytes — simple message+byte pair used inside DataStats
// Mirrors Go <c>MsgBytes</c> struct in server/events.go.
// ============================================================================
/// <summary>
/// A simple pair of message and byte counts, used as a nested breakdown
/// inside <see cref="DataStats"/>.
/// Mirrors Go <c>MsgBytes</c> struct in server/events.go.
/// </summary>
public sealed class MsgBytes
{
[JsonPropertyName("msgs")]
public long Msgs { get; set; }
[JsonPropertyName("bytes")]
public long Bytes { get; set; }
}
// ============================================================================
// RouteStat / GatewayStat — per-route and per-gateway stat snapshots
// Mirrors Go <c>RouteStat</c> and <c>GatewayStat</c> in server/events.go.
// ============================================================================
/// <summary>
/// Statistics snapshot for a single cluster route connection.
/// Mirrors Go <c>RouteStat</c> in server/events.go.
/// </summary>
public sealed class RouteStat
{
[JsonPropertyName("rid")]
public ulong Id { get; set; }
[JsonPropertyName("name")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Name { get; set; }
[JsonPropertyName("sent")]
public DataStats Sent { get; set; } = new();
[JsonPropertyName("received")]
public DataStats Received { get; set; } = new();
[JsonPropertyName("pending")]
public int Pending { get; set; }
}
/// <summary>
/// Statistics snapshot for a gateway connection.
/// Mirrors Go <c>GatewayStat</c> in server/events.go.
/// </summary>
public sealed class GatewayStat
{
[JsonPropertyName("gwid")]
public ulong Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("sent")]
public DataStats Sent { get; set; } = new();
[JsonPropertyName("received")]
public DataStats Received { get; set; } = new();
[JsonPropertyName("inbound_connections")]
public int NumInbound { get; set; }
}
// ============================================================================
// ServerStatsMsg — periodic stats advisory published on $SYS.SERVER.{id}.STATSZ
// Mirrors Go <c>ServerStatsMsg</c> struct in server/events.go.
// ============================================================================
/// <summary>
/// Periodic advisory message containing the current server statistics.
/// Mirrors Go <c>ServerStatsMsg</c> struct in server/events.go.
/// </summary>
public sealed class ServerStatsMsg
{
[JsonPropertyName("server")]
public ServerInfo Server { get; set; } = new();
[JsonPropertyName("statsz")]
public ServerStatsAdvisory Stats { get; set; } = new();
}
// ============================================================================
// ServerStatsAdvisory — the statsz payload inside ServerStatsMsg
// Mirrors Go <c>ServerStats</c> struct (advisory form) in server/events.go.
// NOTE: distinct from the internal ServerStats in NatsServerTypes.cs.
// ============================================================================
/// <summary>
/// The JSON-serialisable statistics payload included inside <see cref="ServerStatsMsg"/>.
/// Mirrors Go <c>ServerStats</c> struct (advisory form) in server/events.go.
/// </summary>
public sealed class ServerStatsAdvisory
{
[JsonPropertyName("start")]
public DateTime Start { get; set; }
[JsonPropertyName("mem")]
public long Mem { get; set; }
[JsonPropertyName("cores")]
public int Cores { get; set; }
[JsonPropertyName("cpu")]
public double Cpu { get; set; }
[JsonPropertyName("connections")]
public int Connections { get; set; }
[JsonPropertyName("total_connections")]
public ulong TotalConnections { get; set; }
[JsonPropertyName("active_accounts")]
public int ActiveAccounts { get; set; }
[JsonPropertyName("subscriptions")]
public uint NumSubs { get; set; }
[JsonPropertyName("sent")]
public DataStats Sent { get; set; } = new();
[JsonPropertyName("received")]
public DataStats Received { get; set; } = new();
[JsonPropertyName("slow_consumers")]
public long SlowConsumers { get; set; }
[JsonPropertyName("slow_consumer_stats")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public SlowConsumersStats? SlowConsumersStats { get; set; }
[JsonPropertyName("stale_connections")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public long StaleConnections { get; set; }
[JsonPropertyName("stale_connection_stats")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public StaleConnectionStats? StaleConnectionStats { get; set; }
[JsonPropertyName("stalled_clients")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public long StalledClients { get; set; }
[JsonPropertyName("routes")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<RouteStat>? Routes { get; set; }
[JsonPropertyName("gateways")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<GatewayStat>? Gateways { get; set; }
[JsonPropertyName("active_servers")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int ActiveServers { get; set; }
/// <summary>JetStream stats. TODO: session 19 — wire JetStreamVarz type.</summary>
[JsonPropertyName("jetstream")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public object? JetStream { get; set; }
[JsonPropertyName("gomemlimit")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public long MemLimit { get; set; }
[JsonPropertyName("gomaxprocs")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int MaxProcs { get; set; }
}
// ============================================================================
// SlowConsumersStats / StaleConnectionStats — advisory-layer per-kind counters
// These are the JSON-serialisable variants used in ServerStatsAdvisory.
// The internal atomic counters live in NatsServerTypes.cs (SlowConsumerStats /
// StaleConnectionStats with different casing).
// ============================================================================
/// <summary>
/// Per-kind slow-consumer counters included in stats advisories.
/// Mirrors Go <c>SlowConsumersStats</c> in server/monitor.go.
/// </summary>
public sealed class SlowConsumersStats
{
[JsonPropertyName("clients")]
public ulong Clients { get; set; }
[JsonPropertyName("routes")]
public ulong Routes { get; set; }
[JsonPropertyName("gateways")]
public ulong Gateways { get; set; }
[JsonPropertyName("leafs")]
public ulong Leafs { get; set; }
}
/// <summary>
/// Per-kind stale-connection counters included in stats advisories.
/// Mirrors Go <c>StaleConnectionStats</c> in server/monitor.go.
/// </summary>
public sealed class StaleConnectionStats
{
[JsonPropertyName("clients")]
public ulong Clients { get; set; }
[JsonPropertyName("routes")]
public ulong Routes { get; set; }
[JsonPropertyName("gateways")]
public ulong Gateways { get; set; }
[JsonPropertyName("leafs")]
public ulong Leafs { get; set; }
}
// ============================================================================
// ConnectEventMsg / DisconnectEventMsg — client lifecycle advisories
// Mirrors Go structs in server/events.go.
// ============================================================================
/// <summary>
/// Advisory published on <c>$SYS.ACCOUNT.{acc}.CONNECT</c> when a new
/// client connection is established within a tracked account.
/// Mirrors Go <c>ConnectEventMsg</c> in server/events.go.
/// </summary>
public sealed class ConnectEventMsg : TypedEvent
{
[JsonPropertyName("server")]
public ServerInfo Server { get; set; } = new();
[JsonPropertyName("client")]
public ClientInfo Client { get; set; } = new();
}
/// <summary>
/// Advisory published on <c>$SYS.ACCOUNT.{acc}.DISCONNECT</c> when a
/// previously-tracked client connection closes.
/// Mirrors Go <c>DisconnectEventMsg</c> in server/events.go.
/// </summary>
public sealed class DisconnectEventMsg : TypedEvent
{
[JsonPropertyName("server")]
public ServerInfo Server { get; set; } = new();
[JsonPropertyName("client")]
public ClientInfo Client { get; set; } = new();
[JsonPropertyName("sent")]
public DataStats Sent { get; set; } = new();
[JsonPropertyName("received")]
public DataStats Received { get; set; } = new();
[JsonPropertyName("reason")]
public string Reason { get; set; } = string.Empty;
}
// ============================================================================
// OCSPPeerRejectEventMsg / OCSPPeerChainlinkInvalidEventMsg
// Mirrors Go structs in server/events.go.
// ============================================================================
/// <summary>
/// Advisory published when a peer TLS handshake is rejected due to OCSP
/// invalidation of the peer's leaf certificate.
/// Mirrors Go <c>OCSPPeerRejectEventMsg</c> in server/events.go.
/// </summary>
public sealed class OcspPeerRejectEventMsg : TypedEvent
{
[JsonPropertyName("kind")]
public string Kind { get; set; } = string.Empty;
[JsonPropertyName("peer")]
public CertInfo Peer { get; set; } = new();
[JsonPropertyName("server")]
public ServerInfo Server { get; set; } = new();
[JsonPropertyName("reason")]
public string Reason { get; set; } = string.Empty;
}
/// <summary>
/// Advisory published when a certificate in a valid TLS chain is found to be
/// OCSP-invalid during a peer handshake. Both the invalid link and the
/// peer's leaf cert are included.
/// Mirrors Go <c>OCSPPeerChainlinkInvalidEventMsg</c> in server/events.go.
/// </summary>
public sealed class OcspPeerChainlinkInvalidEventMsg : TypedEvent
{
[JsonPropertyName("link")]
public CertInfo Link { get; set; } = new();
[JsonPropertyName("peer")]
public CertInfo Peer { get; set; } = new();
[JsonPropertyName("server")]
public ServerInfo Server { get; set; } = new();
[JsonPropertyName("reason")]
public string Reason { get; set; } = string.Empty;
}
// ============================================================================
// AccountNumConns / AccountStat — account connection count advisories
// Mirrors Go structs in server/events.go.
// ============================================================================
/// <summary>
/// Advisory heartbeat published when the connection count for a tracked
/// account changes, or on a periodic schedule.
/// Mirrors Go <c>AccountNumConns</c> struct in server/events.go.
/// </summary>
public sealed class AccountNumConns : TypedEvent
{
[JsonPropertyName("server")]
public ServerInfo Server { get; set; } = new();
// Embedded AccountStat fields are inlined via composition.
[JsonPropertyName("acc")]
public string Account { get; set; } = string.Empty;
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("conns")]
public int Conns { get; set; }
[JsonPropertyName("leafnodes")]
public int LeafNodes { get; set; }
[JsonPropertyName("total_conns")]
public int TotalConns { get; set; }
[JsonPropertyName("num_subscriptions")]
public uint NumSubs { get; set; }
[JsonPropertyName("sent")]
public DataStats Sent { get; set; } = new();
[JsonPropertyName("received")]
public DataStats Received { get; set; } = new();
[JsonPropertyName("slow_consumers")]
public long SlowConsumers { get; set; }
}
/// <summary>
/// Statistic data common to <see cref="AccountNumConns"/> and account-level
/// monitoring responses.
/// Mirrors Go <c>AccountStat</c> struct in server/events.go.
/// </summary>
public sealed class AccountStat
{
[JsonPropertyName("acc")]
public string Account { get; set; } = string.Empty;
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("conns")]
public int Conns { get; set; }
[JsonPropertyName("leafnodes")]
public int LeafNodes { get; set; }
[JsonPropertyName("total_conns")]
public int TotalConns { get; set; }
[JsonPropertyName("num_subscriptions")]
public uint NumSubs { get; set; }
[JsonPropertyName("sent")]
public DataStats Sent { get; set; } = new();
[JsonPropertyName("received")]
public DataStats Received { get; set; } = new();
[JsonPropertyName("slow_consumers")]
public long SlowConsumers { get; set; }
}
/// <summary>
/// Internal request payload sent when this server first starts tracking an
/// account, asking peer servers for their local connection counts.
/// Mirrors Go <c>accNumConnsReq</c> struct in server/events.go.
/// </summary>
internal sealed class AccNumConnsReq
{
[JsonPropertyName("server")]
public ServerInfo Server { get; set; } = new();
[JsonPropertyName("acc")]
public string Account { get; set; } = string.Empty;
}
// ============================================================================
// ServerCapability / ServerID — server identity and capability flags
// Mirrors Go types in server/events.go.
// ============================================================================
/// <summary>
/// Bit-flag capability set for a remote server.
/// Mirrors Go <c>ServerCapability uint64</c> in server/events.go.
/// </summary>
[Flags]
public enum ServerCapability : ulong
{
/// <summary>No capabilities.</summary>
None = 0,
/// <summary>Server has JetStream enabled. Mirrors Go <c>JetStreamEnabled</c>.</summary>
JetStreamEnabled = 1UL << 0,
/// <summary>New stream snapshot capability. Mirrors Go <c>BinaryStreamSnapshot</c>.</summary>
BinaryStreamSnapshot = 1UL << 1,
/// <summary>Move NRG traffic out of system account. Mirrors Go <c>AccountNRG</c>.</summary>
AccountNrg = 1UL << 2,
}
/// <summary>
/// Minimal static identity for a remote server (name, host, ID).
/// Mirrors Go <c>ServerID</c> struct in server/events.go.
/// </summary>
public sealed class ServerIdentity
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("host")]
public string Host { get; set; } = string.Empty;
[JsonPropertyName("id")]
public string Id { get; set; } = string.Empty;
}