Ports server/server.go lines 2577–4782 (~1,881 Go LOC), implementing ~97 features (IDs 3051–3147) across three new partial-class files. New files: - NatsServer.Lifecycle.cs: Shutdown, WaitForShutdown, RemoveClient, SendLDMToClients, LameDuckMode, LDMClientByID, rate-limit logging, DisconnectClientByID, SendAsyncInfoToClients - NatsServer.Listeners.cs: AcceptLoop, GetServerListener, InProcessConn, AcceptConnections, GenerateInfoJson, CopyInfo, CreateClient/Ex/InProcess, StartMonitoring (HTTP/HTTPS), AddConnectURLs/RemoveConnectURLs, TlsVersion/TlsVersionFromString, GetClientConnectURLs, ResolveHostPorts, PortsInfo/PortFile/LogPorts, ReadyForListeners, GetRandomIP, AcceptError - Internal/WaitGroup.cs: Go-style WaitGroup using TaskCompletionSource Modified: - Auth/AuthTypes.cs: Account now implements INatsAccount (stub) - NatsServerTypes.cs: ServerInfo.ShallowClone(), removed duplicate RefCountedUrlSet - NatsServer.cs: _info promoted to internal for test access - Properties/AssemblyInfo.cs: InternalsVisibleTo(DynamicProxyGenAssembly2) - ServerTests.cs: 20 new session-10 unit tests (GenerateInfoJson, TlsVersion, CopyInfo, GetRandomIP — Test IDs 2895, 2906) All 565 unit tests + 1 integration test pass.
65 lines
2.3 KiB
C#
65 lines
2.3 KiB
C#
// 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.
|
|
|
|
namespace ZB.MOM.NatsNet.Server.Internal;
|
|
|
|
/// <summary>
|
|
/// A Go-like WaitGroup: tracks a set of in-flight operations and lets callers
|
|
/// block until all of them complete.
|
|
/// </summary>
|
|
internal sealed class WaitGroup
|
|
{
|
|
private int _count;
|
|
private volatile TaskCompletionSource<bool> _tcs;
|
|
|
|
public WaitGroup()
|
|
{
|
|
_tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
_tcs.SetResult(true); // starts at zero, so "done" immediately
|
|
}
|
|
|
|
/// <summary>
|
|
/// Increment the counter by <paramref name="delta"/> (usually 1).
|
|
/// Must be called before starting the goroutine it tracks.
|
|
/// </summary>
|
|
public void Add(int delta = 1)
|
|
{
|
|
var newCount = Interlocked.Add(ref _count, delta);
|
|
if (newCount < 0)
|
|
throw new InvalidOperationException("WaitGroup counter went negative");
|
|
|
|
if (newCount == 0)
|
|
{
|
|
// All goroutines done — signal any waiters.
|
|
Volatile.Read(ref _tcs).TrySetResult(true);
|
|
}
|
|
else if (delta > 0 && newCount == delta)
|
|
{
|
|
// Transitioning from 0 to positive — replace the completed TCS
|
|
// with a fresh unsignaled one so Wait() will block correctly.
|
|
Volatile.Write(ref _tcs,
|
|
new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously));
|
|
}
|
|
}
|
|
|
|
/// <summary>Decrement the counter by 1. Called when a goroutine finishes.</summary>
|
|
public void Done() => Add(-1);
|
|
|
|
/// <summary>Block synchronously until the counter reaches 0.</summary>
|
|
public void Wait()
|
|
{
|
|
if (Volatile.Read(ref _count) == 0) return;
|
|
Volatile.Read(ref _tcs).Task.GetAwaiter().GetResult();
|
|
}
|
|
}
|