feat: port session 03 — Configuration & Options types, Clone, MergeOptions, SetBaseline
- ServerOptionTypes.cs: all supporting types — ClusterOpts, GatewayOpts, LeafNodeOpts, WebsocketOpts, MqttOpts, RemoteLeafOpts, RemoteGatewayOpts, CompressionOpts, TlsConfigOpts, JsLimitOpts, JsTpmOpts, AuthCalloutOpts, ProxiesConfig, IAuthentication, IAccountResolver, enums (WriteTimeoutPolicy, StoreCipher, OcspMode) - ServerOptions.cs: full Options struct with ~100 properties across 10 subsystems (general, logging, networking, TLS, cluster, gateway, leafnode, websocket, MQTT, JetStream) - ServerOptions.Methods.cs: Clone (deep copy), MergeOptions, SetBaselineOptions, RoutesFromStr, NormalizeBasePath, OverrideTls, OverrideCluster, ExpandPath, HomeDir, MaybeReadPidFile, GetDefaultAuthTimeout, ConfigFlags.NoErrOnUnknownFields - 17 tests covering defaults, random port, merge, clone, expand path, auth timeout, routes parsing, normalize path, cluster override, config flags - Config file parsing (processConfigFileLine 765-line function) deferred to follow-up - All 130 tests pass (129 unit + 1 integration) - DB: features 344/3673 complete, tests 148/3257 complete (9.1% overall)
This commit is contained in:
569
dotnet/src/ZB.MOM.NatsNet.Server/ServerOptions.Methods.cs
Normal file
569
dotnet/src/ZB.MOM.NatsNet.Server/ServerOptions.Methods.cs
Normal file
@@ -0,0 +1,569 @@
|
||||
// Copyright 2012-2025 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/opts.go in the NATS server Go source.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server;
|
||||
|
||||
// Global flag for unknown field handling.
|
||||
internal static class ConfigFlags
|
||||
{
|
||||
private static int _allowUnknownTopLevelField;
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether unknown top-level config fields should be allowed.
|
||||
/// Mirrors <c>NoErrOnUnknownFields</c> in opts.go.
|
||||
/// </summary>
|
||||
public static void NoErrOnUnknownFields(bool noError) =>
|
||||
Interlocked.Exchange(ref _allowUnknownTopLevelField, noError ? 1 : 0);
|
||||
|
||||
public static bool AllowUnknownTopLevelField =>
|
||||
Interlocked.CompareExchange(ref _allowUnknownTopLevelField, 0, 0) != 0;
|
||||
}
|
||||
|
||||
public sealed partial class ServerOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Snapshot of command-line flags, populated during <see cref="ConfigureOptions"/>.
|
||||
/// Mirrors <c>FlagSnapshot</c> in opts.go.
|
||||
/// </summary>
|
||||
public static ServerOptions? FlagSnapshot { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Deep-copies this <see cref="ServerOptions"/> instance.
|
||||
/// Mirrors <c>Options.Clone()</c> in opts.go.
|
||||
/// </summary>
|
||||
public ServerOptions Clone()
|
||||
{
|
||||
// Start with a shallow memberwise clone.
|
||||
var clone = (ServerOptions)MemberwiseClone();
|
||||
|
||||
// Deep-copy reference types that need isolation.
|
||||
if (Routes.Count > 0)
|
||||
clone.Routes = Routes.Select(u => new Uri(u.ToString())).ToList();
|
||||
|
||||
clone.Cluster = CloneClusterOpts(Cluster);
|
||||
clone.Gateway = CloneGatewayOpts(Gateway);
|
||||
clone.LeafNode = CloneLeafNodeOpts(LeafNode);
|
||||
clone.Websocket = CloneWebsocketOpts(Websocket);
|
||||
clone.Mqtt = CloneMqttOpts(Mqtt);
|
||||
|
||||
clone.Tags = [.. Tags];
|
||||
clone.Metadata = new Dictionary<string, string>(Metadata);
|
||||
clone.TrustedKeys = [.. TrustedKeys];
|
||||
clone.JsAccDefaultDomain = new Dictionary<string, string>(JsAccDefaultDomain);
|
||||
clone.InConfig = new Dictionary<string, bool>(InConfig);
|
||||
clone.InCmdLine = new Dictionary<string, bool>(InCmdLine);
|
||||
clone.OperatorJwt = [.. OperatorJwt];
|
||||
clone.ResolverPreloads = new Dictionary<string, string>(ResolverPreloads);
|
||||
clone.ResolverPinnedAccounts = [.. ResolverPinnedAccounts];
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the SHA-256 digest of the configuration.
|
||||
/// Mirrors <c>Options.ConfigDigest()</c> in opts.go.
|
||||
/// </summary>
|
||||
public string ConfigDigest() => ConfigDigestValue;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Merge / Baseline
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Merges file-based options with command-line flag options.
|
||||
/// Flag options override file options where set.
|
||||
/// Mirrors <c>MergeOptions</c> in opts.go.
|
||||
/// </summary>
|
||||
public static ServerOptions MergeOptions(ServerOptions? fileOpts, ServerOptions? flagOpts)
|
||||
{
|
||||
if (fileOpts == null) return flagOpts ?? new ServerOptions();
|
||||
if (flagOpts == null) return fileOpts;
|
||||
|
||||
var opts = fileOpts.Clone();
|
||||
|
||||
if (flagOpts.Port != 0) opts.Port = flagOpts.Port;
|
||||
if (!string.IsNullOrEmpty(flagOpts.Host)) opts.Host = flagOpts.Host;
|
||||
if (flagOpts.DontListen) opts.DontListen = true;
|
||||
if (!string.IsNullOrEmpty(flagOpts.ClientAdvertise)) opts.ClientAdvertise = flagOpts.ClientAdvertise;
|
||||
if (!string.IsNullOrEmpty(flagOpts.Username)) opts.Username = flagOpts.Username;
|
||||
if (!string.IsNullOrEmpty(flagOpts.Password)) opts.Password = flagOpts.Password;
|
||||
if (!string.IsNullOrEmpty(flagOpts.Authorization)) opts.Authorization = flagOpts.Authorization;
|
||||
if (flagOpts.HttpPort != 0) opts.HttpPort = flagOpts.HttpPort;
|
||||
if (!string.IsNullOrEmpty(flagOpts.HttpBasePath)) opts.HttpBasePath = flagOpts.HttpBasePath;
|
||||
if (flagOpts.Debug) opts.Debug = true;
|
||||
if (flagOpts.Trace) opts.Trace = true;
|
||||
if (flagOpts.Logtime) opts.Logtime = true;
|
||||
if (!string.IsNullOrEmpty(flagOpts.LogFile)) opts.LogFile = flagOpts.LogFile;
|
||||
if (!string.IsNullOrEmpty(flagOpts.PidFile)) opts.PidFile = flagOpts.PidFile;
|
||||
if (!string.IsNullOrEmpty(flagOpts.PortsFileDir)) opts.PortsFileDir = flagOpts.PortsFileDir;
|
||||
if (flagOpts.ProfPort != 0) opts.ProfPort = flagOpts.ProfPort;
|
||||
if (!string.IsNullOrEmpty(flagOpts.Cluster.ListenStr)) opts.Cluster.ListenStr = flagOpts.Cluster.ListenStr;
|
||||
if (flagOpts.Cluster.NoAdvertise) opts.Cluster.NoAdvertise = true;
|
||||
if (flagOpts.Cluster.ConnectRetries != 0) opts.Cluster.ConnectRetries = flagOpts.Cluster.ConnectRetries;
|
||||
if (!string.IsNullOrEmpty(flagOpts.Cluster.Advertise)) opts.Cluster.Advertise = flagOpts.Cluster.Advertise;
|
||||
if (!string.IsNullOrEmpty(flagOpts.RoutesStr)) MergeRoutes(opts, flagOpts);
|
||||
if (flagOpts.JetStream) opts.JetStream = true;
|
||||
if (!string.IsNullOrEmpty(flagOpts.StoreDir)) opts.StoreDir = flagOpts.StoreDir;
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses route URLs from a comma-separated string.
|
||||
/// Mirrors <c>RoutesFromStr</c> in opts.go.
|
||||
/// </summary>
|
||||
public static List<Uri> RoutesFromStr(string routesStr)
|
||||
{
|
||||
var parts = routesStr.Split(',');
|
||||
if (parts.Length == 0) return [];
|
||||
|
||||
var urls = new List<Uri>();
|
||||
foreach (var r in parts)
|
||||
{
|
||||
var trimmed = r.Trim();
|
||||
if (Uri.TryCreate(trimmed, UriKind.Absolute, out var u))
|
||||
urls.Add(u);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies system-wide defaults to any unset options.
|
||||
/// Mirrors <c>setBaselineOptions</c> in opts.go.
|
||||
/// </summary>
|
||||
public void SetBaselineOptions()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Host))
|
||||
Host = ServerConstants.DefaultHost;
|
||||
if (string.IsNullOrEmpty(HttpHost))
|
||||
HttpHost = Host;
|
||||
if (Port == 0)
|
||||
Port = ServerConstants.DefaultPort;
|
||||
else if (Port == ServerConstants.RandomPort)
|
||||
Port = 0;
|
||||
if (MaxConn == 0)
|
||||
MaxConn = ServerConstants.DefaultMaxConnections;
|
||||
if (PingInterval == TimeSpan.Zero)
|
||||
PingInterval = ServerConstants.DefaultPingInterval;
|
||||
if (MaxPingsOut == 0)
|
||||
MaxPingsOut = ServerConstants.DefaultPingMaxOut;
|
||||
if (TlsTimeout == 0)
|
||||
TlsTimeout = ServerConstants.TlsTimeout.TotalSeconds;
|
||||
if (AuthTimeout == 0)
|
||||
AuthTimeout = GetDefaultAuthTimeout(TlsConfig, TlsTimeout);
|
||||
|
||||
// Cluster defaults
|
||||
if (Cluster.Port != 0 || !string.IsNullOrEmpty(Cluster.ListenStr))
|
||||
{
|
||||
if (string.IsNullOrEmpty(Cluster.Host))
|
||||
Cluster.Host = ServerConstants.DefaultHost;
|
||||
if (Cluster.TlsTimeout == 0)
|
||||
Cluster.TlsTimeout = ServerConstants.TlsTimeout.TotalSeconds;
|
||||
if (Cluster.AuthTimeout == 0)
|
||||
Cluster.AuthTimeout = GetDefaultAuthTimeout(Cluster.TlsConfig, Cluster.TlsTimeout);
|
||||
if (Cluster.PoolSize == 0)
|
||||
Cluster.PoolSize = ServerConstants.DefaultRoutePoolSize;
|
||||
|
||||
// Add system account to pinned accounts if pool is enabled.
|
||||
if (Cluster.PoolSize > 0)
|
||||
{
|
||||
var sysAccName = SystemAccount;
|
||||
if (string.IsNullOrEmpty(sysAccName) && !NoSystemAccount)
|
||||
sysAccName = ServerConstants.DefaultSystemAccount;
|
||||
if (!string.IsNullOrEmpty(sysAccName) && !Cluster.PinnedAccounts.Contains(sysAccName))
|
||||
Cluster.PinnedAccounts.Add(sysAccName);
|
||||
}
|
||||
|
||||
// Default compression to "accept".
|
||||
if (string.IsNullOrEmpty(Cluster.Compression.Mode))
|
||||
Cluster.Compression.Mode = CompressionModes.Accept;
|
||||
}
|
||||
|
||||
// LeafNode defaults
|
||||
if (LeafNode.Port != 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(LeafNode.Host))
|
||||
LeafNode.Host = ServerConstants.DefaultHost;
|
||||
if (LeafNode.TlsTimeout == 0)
|
||||
LeafNode.TlsTimeout = ServerConstants.TlsTimeout.TotalSeconds;
|
||||
if (LeafNode.AuthTimeout == 0)
|
||||
LeafNode.AuthTimeout = GetDefaultAuthTimeout(LeafNode.TlsConfig, LeafNode.TlsTimeout);
|
||||
if (string.IsNullOrEmpty(LeafNode.Compression.Mode))
|
||||
LeafNode.Compression.Mode = CompressionModes.S2Auto;
|
||||
}
|
||||
|
||||
// Remote leafnode defaults
|
||||
foreach (var r in LeafNode.Remotes)
|
||||
{
|
||||
foreach (var u in r.Urls)
|
||||
{
|
||||
if (u.IsDefaultPort || string.IsNullOrEmpty(u.GetComponents(UriComponents.Port, UriFormat.Unescaped)))
|
||||
{
|
||||
var builder = new UriBuilder(u) { Port = ServerConstants.DefaultLeafNodePort };
|
||||
r.Urls[r.Urls.IndexOf(u)] = builder.Uri;
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(r.Compression.Mode))
|
||||
r.Compression.Mode = CompressionModes.S2Auto;
|
||||
if (r.FirstInfoTimeout <= TimeSpan.Zero)
|
||||
r.FirstInfoTimeout = ServerConstants.DefaultLeafNodeInfoWait;
|
||||
}
|
||||
|
||||
if (LeafNode.ReconnectInterval == TimeSpan.Zero)
|
||||
LeafNode.ReconnectInterval = ServerConstants.DefaultLeafNodeReconnect;
|
||||
|
||||
// Protocol limits
|
||||
if (MaxControlLine == 0)
|
||||
MaxControlLine = ServerConstants.MaxControlLineSize;
|
||||
if (MaxPayload == 0)
|
||||
MaxPayload = ServerConstants.MaxPayloadSize;
|
||||
if (MaxPending == 0)
|
||||
MaxPending = ServerConstants.MaxPendingSize;
|
||||
if (WriteDeadline == TimeSpan.Zero)
|
||||
WriteDeadline = ServerConstants.DefaultFlushDeadline;
|
||||
if (MaxClosedClients == 0)
|
||||
MaxClosedClients = ServerConstants.DefaultMaxClosedClients;
|
||||
if (LameDuckDuration == TimeSpan.Zero)
|
||||
LameDuckDuration = ServerConstants.DefaultLameDuckDuration;
|
||||
if (LameDuckGracePeriod == TimeSpan.Zero)
|
||||
LameDuckGracePeriod = ServerConstants.DefaultLameDuckGracePeriod;
|
||||
|
||||
// Gateway defaults
|
||||
if (Gateway.Port != 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Gateway.Host))
|
||||
Gateway.Host = ServerConstants.DefaultHost;
|
||||
if (Gateway.TlsTimeout == 0)
|
||||
Gateway.TlsTimeout = ServerConstants.TlsTimeout.TotalSeconds;
|
||||
if (Gateway.AuthTimeout == 0)
|
||||
Gateway.AuthTimeout = GetDefaultAuthTimeout(Gateway.TlsConfig, Gateway.TlsTimeout);
|
||||
}
|
||||
|
||||
// Error reporting
|
||||
if (ConnectErrorReports == 0)
|
||||
ConnectErrorReports = ServerConstants.DefaultConnectErrorReports;
|
||||
if (ReconnectErrorReports == 0)
|
||||
ReconnectErrorReports = ServerConstants.DefaultReconnectErrorReports;
|
||||
|
||||
// WebSocket defaults
|
||||
if (Websocket.Port != 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Websocket.Host))
|
||||
Websocket.Host = ServerConstants.DefaultHost;
|
||||
}
|
||||
|
||||
// MQTT defaults
|
||||
if (Mqtt.Port != 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Mqtt.Host))
|
||||
Mqtt.Host = ServerConstants.DefaultHost;
|
||||
if (Mqtt.TlsTimeout == 0)
|
||||
Mqtt.TlsTimeout = ServerConstants.TlsTimeout.TotalSeconds;
|
||||
}
|
||||
|
||||
// JetStream defaults
|
||||
if (JetStreamMaxMemory == 0 && !MaxMemSet)
|
||||
JetStreamMaxMemory = -1;
|
||||
if (JetStreamMaxStore == 0 && !MaxStoreSet)
|
||||
JetStreamMaxStore = -1;
|
||||
if (SyncInterval == TimeSpan.Zero && !SyncSet)
|
||||
SyncInterval = TimeSpan.FromMinutes(2); // defaultSyncInterval
|
||||
if (JetStreamRequestQueueLimit <= 0)
|
||||
JetStreamRequestQueueLimit = 4096; // JSDefaultRequestQueueLimit
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes an HTTP base path (ensure leading slash, clean redundant separators).
|
||||
/// Mirrors <c>normalizeBasePath</c> in opts.go.
|
||||
/// </summary>
|
||||
public static string NormalizeBasePath(string p)
|
||||
{
|
||||
if (string.IsNullOrEmpty(p)) return "/";
|
||||
if (p[0] != '/') p = "/" + p;
|
||||
// Simple path clean: collapse repeated slashes and remove trailing slash.
|
||||
while (p.Contains("//")) p = p.Replace("//", "/");
|
||||
return p.Length > 1 && p.EndsWith('/') ? p[..^1] : p;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the default auth timeout based on TLS config presence.
|
||||
/// Mirrors <c>getDefaultAuthTimeout</c> in opts.go.
|
||||
/// </summary>
|
||||
public static double GetDefaultAuthTimeout(object? tlsConfig, double tlsTimeout)
|
||||
{
|
||||
if (tlsConfig != null)
|
||||
return tlsTimeout + 1.0;
|
||||
return ServerConstants.AuthTimeout.TotalSeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the user's home directory.
|
||||
/// Mirrors <c>homeDir</c> in opts.go.
|
||||
/// </summary>
|
||||
public static string HomeDir() => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
|
||||
/// <summary>
|
||||
/// Expands environment variables and ~/ prefix in a path.
|
||||
/// Mirrors <c>expandPath</c> in opts.go.
|
||||
/// </summary>
|
||||
public static string ExpandPath(string p)
|
||||
{
|
||||
p = Environment.ExpandEnvironmentVariables(p);
|
||||
if (!p.StartsWith('~')) return p;
|
||||
return Path.Combine(HomeDir(), p[1..].TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a PID from a file path if possible, otherwise returns the string as-is.
|
||||
/// Mirrors <c>maybeReadPidFile</c> in opts.go.
|
||||
/// </summary>
|
||||
public static string MaybeReadPidFile(string pidStr)
|
||||
{
|
||||
try { return File.ReadAllText(pidStr).Trim(); }
|
||||
catch { return pidStr; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies TLS overrides from command-line options.
|
||||
/// Mirrors <c>overrideTLS</c> in opts.go.
|
||||
/// </summary>
|
||||
public Exception? OverrideTls()
|
||||
{
|
||||
if (string.IsNullOrEmpty(TlsCert))
|
||||
return new InvalidOperationException("TLS Server certificate must be present and valid");
|
||||
if (string.IsNullOrEmpty(TlsKey))
|
||||
return new InvalidOperationException("TLS Server private key must be present and valid");
|
||||
|
||||
// TLS config generation is deferred to GenTlsConfig (session 06+).
|
||||
// For now, mark that TLS is enabled.
|
||||
Tls = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides cluster options from the --cluster flag.
|
||||
/// Mirrors <c>overrideCluster</c> in opts.go.
|
||||
/// </summary>
|
||||
public Exception? OverrideCluster()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Cluster.ListenStr))
|
||||
{
|
||||
Cluster.Port = 0;
|
||||
return null;
|
||||
}
|
||||
|
||||
var listenStr = Cluster.ListenStr;
|
||||
var wantsRandom = false;
|
||||
if (listenStr.EndsWith(":-1"))
|
||||
{
|
||||
wantsRandom = true;
|
||||
listenStr = listenStr[..^3] + ":0";
|
||||
}
|
||||
|
||||
if (!Uri.TryCreate(listenStr, UriKind.Absolute, out var clusterUri))
|
||||
return new InvalidOperationException($"could not parse cluster URL: {Cluster.ListenStr}");
|
||||
|
||||
Cluster.Host = clusterUri.Host;
|
||||
Cluster.Port = wantsRandom ? -1 : clusterUri.Port;
|
||||
|
||||
var userInfo = clusterUri.UserInfo;
|
||||
if (!string.IsNullOrEmpty(userInfo))
|
||||
{
|
||||
var parts = userInfo.Split(':', 2);
|
||||
if (parts.Length != 2)
|
||||
return new InvalidOperationException("expected cluster password to be set");
|
||||
Cluster.Username = parts[0];
|
||||
Cluster.Password = parts[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
Cluster.Username = string.Empty;
|
||||
Cluster.Password = string.Empty;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Private helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private static void MergeRoutes(ServerOptions opts, ServerOptions flagOpts)
|
||||
{
|
||||
var routeUrls = RoutesFromStr(flagOpts.RoutesStr);
|
||||
if (routeUrls.Count == 0) return;
|
||||
opts.Routes = routeUrls;
|
||||
opts.RoutesStr = flagOpts.RoutesStr;
|
||||
}
|
||||
|
||||
internal static void TrackExplicitVal(Dictionary<string, bool> pm, string name, bool val) =>
|
||||
pm[name] = val;
|
||||
|
||||
private static ClusterOpts CloneClusterOpts(ClusterOpts src) => new()
|
||||
{
|
||||
Name = src.Name,
|
||||
Host = src.Host,
|
||||
Port = src.Port,
|
||||
Username = src.Username,
|
||||
Password = src.Password,
|
||||
AuthTimeout = src.AuthTimeout,
|
||||
TlsTimeout = src.TlsTimeout,
|
||||
TlsConfig = src.TlsConfig,
|
||||
TlsMap = src.TlsMap,
|
||||
TlsCheckKnownUrls = src.TlsCheckKnownUrls,
|
||||
TlsPinnedCerts = src.TlsPinnedCerts != null ? new PinnedCertSet(src.TlsPinnedCerts) : null,
|
||||
TlsHandshakeFirst = src.TlsHandshakeFirst,
|
||||
TlsHandshakeFirstFallback = src.TlsHandshakeFirstFallback,
|
||||
ListenStr = src.ListenStr,
|
||||
Advertise = src.Advertise,
|
||||
NoAdvertise = src.NoAdvertise,
|
||||
ConnectRetries = src.ConnectRetries,
|
||||
ConnectBackoff = src.ConnectBackoff,
|
||||
PoolSize = src.PoolSize,
|
||||
PinnedAccounts = [.. src.PinnedAccounts],
|
||||
Compression = new CompressionOpts { Mode = src.Compression.Mode, RttThresholds = [.. src.Compression.RttThresholds] },
|
||||
PingInterval = src.PingInterval,
|
||||
MaxPingsOut = src.MaxPingsOut,
|
||||
WriteDeadline = src.WriteDeadline,
|
||||
WriteTimeout = src.WriteTimeout,
|
||||
};
|
||||
|
||||
private static GatewayOpts CloneGatewayOpts(GatewayOpts src) => new()
|
||||
{
|
||||
Name = src.Name,
|
||||
Host = src.Host,
|
||||
Port = src.Port,
|
||||
Username = src.Username,
|
||||
Password = src.Password,
|
||||
AuthTimeout = src.AuthTimeout,
|
||||
TlsConfig = src.TlsConfig,
|
||||
TlsTimeout = src.TlsTimeout,
|
||||
TlsMap = src.TlsMap,
|
||||
TlsCheckKnownUrls = src.TlsCheckKnownUrls,
|
||||
TlsPinnedCerts = src.TlsPinnedCerts != null ? new PinnedCertSet(src.TlsPinnedCerts) : null,
|
||||
Advertise = src.Advertise,
|
||||
ConnectRetries = src.ConnectRetries,
|
||||
ConnectBackoff = src.ConnectBackoff,
|
||||
Gateways = src.Gateways.Select(g => new RemoteGatewayOpts
|
||||
{
|
||||
Name = g.Name,
|
||||
TlsConfig = g.TlsConfig,
|
||||
TlsTimeout = g.TlsTimeout,
|
||||
Urls = g.Urls.Select(u => new Uri(u.ToString())).ToList(),
|
||||
}).ToList(),
|
||||
RejectUnknown = src.RejectUnknown,
|
||||
WriteDeadline = src.WriteDeadline,
|
||||
WriteTimeout = src.WriteTimeout,
|
||||
};
|
||||
|
||||
private static LeafNodeOpts CloneLeafNodeOpts(LeafNodeOpts src) => new()
|
||||
{
|
||||
Host = src.Host,
|
||||
Port = src.Port,
|
||||
Username = src.Username,
|
||||
Password = src.Password,
|
||||
ProxyRequired = src.ProxyRequired,
|
||||
Nkey = src.Nkey,
|
||||
Account = src.Account,
|
||||
AuthTimeout = src.AuthTimeout,
|
||||
TlsConfig = src.TlsConfig,
|
||||
TlsTimeout = src.TlsTimeout,
|
||||
TlsMap = src.TlsMap,
|
||||
TlsPinnedCerts = src.TlsPinnedCerts != null ? new PinnedCertSet(src.TlsPinnedCerts) : null,
|
||||
TlsHandshakeFirst = src.TlsHandshakeFirst,
|
||||
TlsHandshakeFirstFallback = src.TlsHandshakeFirstFallback,
|
||||
Advertise = src.Advertise,
|
||||
NoAdvertise = src.NoAdvertise,
|
||||
ReconnectInterval = src.ReconnectInterval,
|
||||
WriteDeadline = src.WriteDeadline,
|
||||
WriteTimeout = src.WriteTimeout,
|
||||
Compression = new CompressionOpts { Mode = src.Compression.Mode, RttThresholds = [.. src.Compression.RttThresholds] },
|
||||
Remotes = src.Remotes.Select(r => new RemoteLeafOpts
|
||||
{
|
||||
LocalAccount = r.LocalAccount,
|
||||
NoRandomize = r.NoRandomize,
|
||||
Urls = r.Urls.Select(u => new Uri(u.ToString())).ToList(),
|
||||
Credentials = r.Credentials,
|
||||
Nkey = r.Nkey,
|
||||
Tls = r.Tls,
|
||||
TlsTimeout = r.TlsTimeout,
|
||||
TlsHandshakeFirst = r.TlsHandshakeFirst,
|
||||
Hub = r.Hub,
|
||||
DenyImports = [.. r.DenyImports],
|
||||
DenyExports = [.. r.DenyExports],
|
||||
FirstInfoTimeout = r.FirstInfoTimeout,
|
||||
Compression = new CompressionOpts { Mode = r.Compression.Mode, RttThresholds = [.. r.Compression.RttThresholds] },
|
||||
JetStreamClusterMigrate = r.JetStreamClusterMigrate,
|
||||
JetStreamClusterMigrateDelay = r.JetStreamClusterMigrateDelay,
|
||||
LocalIsolation = r.LocalIsolation,
|
||||
RequestIsolation = r.RequestIsolation,
|
||||
Disabled = r.Disabled,
|
||||
}).ToList(),
|
||||
MinVersion = src.MinVersion,
|
||||
IsolateLeafnodeInterest = src.IsolateLeafnodeInterest,
|
||||
};
|
||||
|
||||
private static WebsocketOpts CloneWebsocketOpts(WebsocketOpts src) => new()
|
||||
{
|
||||
Host = src.Host,
|
||||
Port = src.Port,
|
||||
Advertise = src.Advertise,
|
||||
NoAuthUser = src.NoAuthUser,
|
||||
JwtCookie = src.JwtCookie,
|
||||
UsernameCookie = src.UsernameCookie,
|
||||
PasswordCookie = src.PasswordCookie,
|
||||
TokenCookie = src.TokenCookie,
|
||||
Username = src.Username,
|
||||
Password = src.Password,
|
||||
Token = src.Token,
|
||||
AuthTimeout = src.AuthTimeout,
|
||||
NoTls = src.NoTls,
|
||||
TlsConfig = src.TlsConfig,
|
||||
TlsMap = src.TlsMap,
|
||||
TlsPinnedCerts = src.TlsPinnedCerts != null ? new PinnedCertSet(src.TlsPinnedCerts) : null,
|
||||
SameOrigin = src.SameOrigin,
|
||||
AllowedOrigins = [.. src.AllowedOrigins],
|
||||
Compression = src.Compression,
|
||||
HandshakeTimeout = src.HandshakeTimeout,
|
||||
PingInterval = src.PingInterval,
|
||||
Headers = new Dictionary<string, string>(src.Headers),
|
||||
};
|
||||
|
||||
private static MqttOpts CloneMqttOpts(MqttOpts src) => new()
|
||||
{
|
||||
Host = src.Host,
|
||||
Port = src.Port,
|
||||
NoAuthUser = src.NoAuthUser,
|
||||
Username = src.Username,
|
||||
Password = src.Password,
|
||||
Token = src.Token,
|
||||
JsDomain = src.JsDomain,
|
||||
StreamReplicas = src.StreamReplicas,
|
||||
ConsumerReplicas = src.ConsumerReplicas,
|
||||
ConsumerMemoryStorage = src.ConsumerMemoryStorage,
|
||||
ConsumerInactiveThreshold = src.ConsumerInactiveThreshold,
|
||||
AuthTimeout = src.AuthTimeout,
|
||||
TlsConfig = src.TlsConfig,
|
||||
TlsMap = src.TlsMap,
|
||||
TlsTimeout = src.TlsTimeout,
|
||||
TlsPinnedCerts = src.TlsPinnedCerts != null ? new PinnedCertSet(src.TlsPinnedCerts) : null,
|
||||
AckWait = src.AckWait,
|
||||
JsApiTimeout = src.JsApiTimeout,
|
||||
MaxAckPending = src.MaxAckPending,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user