// Copyright 2012-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/server.go in the NATS server Go source.
using System.Collections.Concurrent;
using System.Threading.Channels;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using ZB.MOM.NatsNet.Server.Auth;
using ZB.MOM.NatsNet.Server.Auth.Ocsp;
using ZB.MOM.NatsNet.Server.Internal;
using ZB.MOM.NatsNet.Server.Internal.DataStructures;
using ZB.MOM.NatsNet.Server.WebSocket;
namespace ZB.MOM.NatsNet.Server;
///
/// The core NATS server class.
/// Mirrors Go Server struct in server/server.go.
/// Session 09: initialization, configuration, and account management.
/// Sessions 10-23 add further capabilities as partial class files.
///
public sealed partial class NatsServer : INatsServer
{
// =========================================================================
// Build-time stamps (mirrors package-level vars in server.go)
// =========================================================================
///
/// Binary-stamped trusted operator keys (space-separated NKey public keys).
/// In Go this is a package-level var that can be overridden at build time.
/// In .NET it can be set before constructing any server instance.
/// Mirrors Go package-level trustedKeys var.
///
public static string StampedTrustedKeys { get; set; } = string.Empty;
// =========================================================================
// Atomic counters (mirrors fields accessed with atomic operations)
// =========================================================================
private ulong _gcid; // global client id counter
private long _pinnedAccFail; // pinned-account auth failures
private int _activeAccounts; // number of active accounts
// =========================================================================
// Stats (embedded Go structs: stats, scStats, staleStats)
// =========================================================================
private readonly ServerStats _stats = new();
private readonly SlowConsumerStats _scStats = new();
private readonly InternalStaleStats _staleStats = new();
// =========================================================================
// Core identity
// =========================================================================
// kp / xkp are NKey keypairs — represented as byte arrays here.
// Full crypto operations deferred to auth session.
private byte[]? _kpSeed; // server NKey seed
private string _pub = string.Empty; // server public key (server ID)
private byte[]? _xkpSeed; // x25519 key seed
private string _xpub = string.Empty; // x25519 public key
// =========================================================================
// Server info (wire protocol)
// =========================================================================
private readonly ReaderWriterLockSlim _mu = new(LockRecursionPolicy.SupportsRecursion);
private readonly ReaderWriterLockSlim _reloadMu = new(LockRecursionPolicy.SupportsRecursion);
internal ServerInfo _info = new();
private string _configFile = string.Empty;
// =========================================================================
// Options (protected by _optsMu)
// =========================================================================
private readonly ReaderWriterLockSlim _optsMu = new(LockRecursionPolicy.NoRecursion);
private ServerOptions _opts;
// =========================================================================
// Running / shutdown state
// =========================================================================
private int _running; // 1 = running, 0 = not (Interlocked)
private int _shutdown; // 1 = shutting down
private readonly CancellationTokenSource _quitCts = new();
private readonly TaskCompletionSource _startupComplete = new(TaskCreationOptions.RunContinuationsAsynchronously);
private readonly TaskCompletionSource _shutdownComplete = new(TaskCreationOptions.RunContinuationsAsynchronously);
private Task? _quitTask;
// =========================================================================
// Listeners (forward-declared stubs — fully wired in session 10)
// =========================================================================
private System.Net.Sockets.TcpListener? _listener;
private Exception? _listenerErr;
// HTTP monitoring listener
private System.Net.Sockets.TcpListener? _http;
// Route listener
private System.Net.Sockets.TcpListener? _routeListener;
private Exception? _routeListenerErr;
// Gateway listener
private System.Net.Sockets.TcpListener? _gatewayListener;
private Exception? _gatewayListenerErr;
// Leaf-node listener
private System.Net.Sockets.TcpListener? _leafNodeListener;
private Exception? _leafNodeListenerErr;
// Profiling listener
private System.Net.Sockets.TcpListener? _profiler;
// Accept-loop done channel — each accept loop sends true when it exits.
private readonly System.Threading.Channels.Channel _done =
System.Threading.Channels.Channel.CreateUnbounded();
// Lame-duck channel — created in lameDuckMode, receives one signal per accept loop.
private System.Threading.Channels.Channel? _ldmCh;
// The no-auth user that only the system account can use (auth session).
private string _sysAccOnlyNoAuthUser = string.Empty;
// =========================================================================
// Accounts
// =========================================================================
private Account? _gacc; // global account
private Account? _sysAccAtomic; // system account (atomic)
private readonly ConcurrentDictionary _accounts = new(StringComparer.Ordinal);
private readonly ConcurrentDictionary _tmpAccounts = new(StringComparer.Ordinal);
private IAccountResolver? _accResolver;
private InternalState? _sys; // system messaging state
// =========================================================================
// Client/route/leaf tracking
// =========================================================================
private readonly Dictionary _clients = [];
private readonly Dictionary _leafs = [];
private Dictionary> _routes = [];
private int _routesPoolSize = 1;
private bool _routesReject;
private int _routesNoPool;
private Dictionary>? _accRoutes;
private readonly ConcurrentDictionary _accRouteByHash = new(StringComparer.Ordinal);
private Channel? _accAddedCh; // stub
private string _accAddedReqId = string.Empty;
// =========================================================================
// User / nkey maps
// =========================================================================
private Dictionary? _users;
private Dictionary? _nkeys;
// =========================================================================
// Connection tracking
// =========================================================================
private ulong _totalClients;
private ClosedRingBuffer _closed = new(0);
private DateTime _start;
private DateTime _configTime;
// =========================================================================
// Goroutine / WaitGroup tracking
// =========================================================================
private readonly object _grMu = new();
private bool _grRunning;
private readonly Dictionary _grTmpClients = [];
private readonly WaitGroup _grWg = new();
// =========================================================================
// Cluster name (separate lock)
// =========================================================================
private readonly ReaderWriterLockSlim _cnMu = new(LockRecursionPolicy.NoRecursion);
private string _cn = string.Empty;
private ServerInfo _routeInfo = new();
private bool _leafNoCluster;
private bool _leafNodeEnabled;
private bool _leafDisableConnect;
private bool _ldm;
// =========================================================================
// Trusted keys
// =========================================================================
private List? _trustedKeys;
private HashSet _strictSigningKeyUsage = [];
// =========================================================================
// Monitoring / stats endpoint
// =========================================================================
private string _httpBasePath = string.Empty;
private readonly Dictionary _httpReqStats = [];
private object? _httpHandler;
// =========================================================================
// Client connect URLs
// =========================================================================
private readonly List _clientConnectUrls = [];
private readonly RefCountedUrlSet _clientConnectUrlsMap = new();
// =========================================================================
// Gateway / Websocket / MQTT / OCSP stubs
// =========================================================================
private readonly SrvGateway _gateway = new();
private readonly SrvWebsocket _websocket = new();
private readonly SrvMqtt _mqtt = new();
private OcspMonitor[]? _ocsps;
private bool _ocspPeerVerify;
private IOcspResponseCache? _ocsprc;
// =========================================================================
// Gateway reply map (stub — session 16)
// =========================================================================
private readonly SubscriptionIndex _gwLeafSubs;
// =========================================================================
// NUID event ID generator
// =========================================================================
// Replaced by actual NUID in session 10. Use Guid for now.
private string NextEventId() => Guid.NewGuid().ToString("N");
// =========================================================================
// Various stubs
// =========================================================================
private readonly List _leafRemoteCfgs = []; // stub — session 15
private readonly List