feat: port sessions 14-16 — Routes, Leaf Nodes & Gateways
Session 14 (57 features, IDs 2895-2951): - RouteTypes: RouteType enum, Route, RouteInfo, ConnectInfo, ASubs, GossipMode Session 15 (71 features, IDs 1979-2049): - LeafNodeTypes: Leaf, LeafNodeCfg (replaces stub), LeafConnectInfo Session 16 (91 features, IDs 1263-1353): - GatewayTypes: GatewayInterestMode, SrvGateway (replaces stub), GatewayCfg, Gateway, OutSide, InSide, SitAlly, GwReplyMap, GwReplyMapping
This commit is contained in:
202
dotnet/src/ZB.MOM.NatsNet.Server/LeafNode/LeafNodeTypes.cs
Normal file
202
dotnet/src/ZB.MOM.NatsNet.Server/LeafNode/LeafNodeTypes.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
// Copyright 2019-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/leafnode.go in the NATS server Go source.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using ZB.MOM.NatsNet.Server.Auth;
|
||||
using ZB.MOM.NatsNet.Server.Internal;
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server;
|
||||
|
||||
// ============================================================================
|
||||
// Session 15: Leaf Nodes
|
||||
// ============================================================================
|
||||
|
||||
/// <summary>
|
||||
/// Per-connection leaf-node state embedded in <see cref="ClientConnection"/>
|
||||
/// when the connection kind is <c>Leaf</c>.
|
||||
/// Mirrors Go <c>leaf</c> struct in leafnode.go.
|
||||
/// </summary>
|
||||
internal sealed class Leaf
|
||||
{
|
||||
/// <summary>
|
||||
/// Config for solicited (outbound) leaf connections; null for accepted connections.
|
||||
/// </summary>
|
||||
public LeafNodeCfg? Remote { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True when we are the spoke side of a hub/spoke leaf pair.
|
||||
/// </summary>
|
||||
public bool IsSpoke { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cluster name of the remote server when we are a hub and the spoke is
|
||||
/// part of a cluster.
|
||||
/// </summary>
|
||||
public string RemoteCluster { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Remote server name or ID.</summary>
|
||||
public string RemoteServer { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Domain name of the remote server.</summary>
|
||||
public string RemoteDomain { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Account name of the remote server.</summary>
|
||||
public string RemoteAccName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// When true, suppresses propagation of east-west interest from other leaf nodes.
|
||||
/// </summary>
|
||||
public bool Isolated { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Subject-interest suppression map shared with the remote side.
|
||||
/// Key = subject, Value = interest count (positive = subscribe, negative = unsubscribe delta).
|
||||
/// </summary>
|
||||
public Dictionary<string, int> Smap { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Short-lived set of subscriptions added during <c>initLeafNodeSmapAndSendSubs</c>
|
||||
/// to detect and avoid double-counting races.
|
||||
/// </summary>
|
||||
public HashSet<Subscription>? Tsub { get; set; }
|
||||
|
||||
/// <summary>Timer that clears <see cref="Tsub"/> after the initialization window.</summary>
|
||||
public Timer? Tsubt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Selected compression mode, which may differ from the server-configured mode.
|
||||
/// </summary>
|
||||
public string Compression { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gateway-mapped reply subscription used for GW reply routing via leaf nodes.
|
||||
/// </summary>
|
||||
public Subscription? GwSub { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runtime configuration for a remote (solicited) leaf-node connection.
|
||||
/// Wraps <see cref="RemoteLeafOpts"/> with connection-attempt state and a
|
||||
/// reader-writer lock for concurrent access.
|
||||
/// Mirrors Go <c>leafNodeCfg</c> struct in leafnode.go.
|
||||
/// Replaces the stub that was in <c>NatsServerTypes.cs</c>.
|
||||
/// </summary>
|
||||
public sealed class LeafNodeCfg
|
||||
{
|
||||
private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.SupportsRecursion);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Embedded RemoteLeafOpts fields
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>The raw remote options this cfg was constructed from.</summary>
|
||||
public RemoteLeafOpts? RemoteOpts { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Runtime connection-attempt fields
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>Resolved URLs to attempt connections to.</summary>
|
||||
public List<Uri> Urls { get; set; } = [];
|
||||
|
||||
/// <summary>Currently selected URL from <see cref="Urls"/>.</summary>
|
||||
public Uri? CurUrl { get; set; }
|
||||
|
||||
/// <summary>TLS server name override for SNI.</summary>
|
||||
public string TlsName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Username for authentication (resolved from credentials or options).</summary>
|
||||
public string Username { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Password for authentication (resolved from credentials or options).</summary>
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Publish/subscribe permission overrides for this connection.</summary>
|
||||
public Permissions? Perms { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Delay before the next connection attempt (e.g. during loop-detection back-off).
|
||||
/// </summary>
|
||||
public TimeSpan ConnDelay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timer used to trigger JetStream account migration for this leaf.
|
||||
/// </summary>
|
||||
public Timer? JsMigrateTimer { get; set; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Forwarded properties from RemoteLeafOpts
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public string LocalAccount { get => RemoteOpts?.LocalAccount ?? string.Empty; }
|
||||
public bool NoRandomize { get => RemoteOpts?.NoRandomize ?? false; }
|
||||
public string Credentials { get => RemoteOpts?.Credentials ?? string.Empty; }
|
||||
public bool Disabled { get => RemoteOpts?.Disabled ?? false; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Lock helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public void AcquireReadLock() => _lock.EnterReadLock();
|
||||
public void ReleaseReadLock() => _lock.ExitReadLock();
|
||||
public void AcquireWriteLock() => _lock.EnterWriteLock();
|
||||
public void ReleaseWriteLock() => _lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CONNECT protocol payload sent by a leaf-node connection.
|
||||
/// Fields map 1-to-1 with the JSON tags in Go's <c>leafConnectInfo</c>.
|
||||
/// Mirrors Go <c>leafConnectInfo</c> struct in leafnode.go.
|
||||
/// </summary>
|
||||
internal sealed class LeafConnectInfo
|
||||
{
|
||||
[JsonPropertyName("version")] public string Version { get; set; } = string.Empty;
|
||||
[JsonPropertyName("nkey")] public string Nkey { get; set; } = string.Empty;
|
||||
[JsonPropertyName("jwt")] public string Jwt { get; set; } = string.Empty;
|
||||
[JsonPropertyName("sig")] public string Sig { get; set; } = string.Empty;
|
||||
[JsonPropertyName("user")] public string User { get; set; } = string.Empty;
|
||||
[JsonPropertyName("pass")] public string Pass { get; set; } = string.Empty;
|
||||
[JsonPropertyName("auth_token")] public string Token { get; set; } = string.Empty;
|
||||
[JsonPropertyName("server_id")] public string Id { get; set; } = string.Empty;
|
||||
[JsonPropertyName("domain")] public string Domain { get; set; } = string.Empty;
|
||||
[JsonPropertyName("name")] public string Name { get; set; } = string.Empty;
|
||||
[JsonPropertyName("is_hub")] public bool Hub { get; set; }
|
||||
[JsonPropertyName("cluster")] public string Cluster { get; set; } = string.Empty;
|
||||
[JsonPropertyName("headers")] public bool Headers { get; set; }
|
||||
[JsonPropertyName("jetstream")] public bool JetStream { get; set; }
|
||||
[JsonPropertyName("deny_pub")] public string[] DenyPub { get; set; } = [];
|
||||
[JsonPropertyName("isolate")] public bool Isolate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compression mode string. The legacy boolean field was never used; this
|
||||
/// string field uses a different JSON tag to avoid conflicts.
|
||||
/// </summary>
|
||||
[JsonPropertyName("compress_mode")] public string Compression { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Used only to detect wrong-port connections (client connecting to leaf port).
|
||||
/// </summary>
|
||||
[JsonPropertyName("gateway")] public string Gateway { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Account name the remote is binding to on the accept side.</summary>
|
||||
[JsonPropertyName("remote_account")] public string RemoteAccount { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Protocol version sent by the soliciting side so the accepting side knows
|
||||
/// which features are supported (e.g. message tracing).
|
||||
/// </summary>
|
||||
[JsonPropertyName("protocol")] public int Proto { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user