chore: organize solution into module folders (Core/Server/Drivers/Client/Tooling)

Group all 69 projects into category subfolders under src/ and tests/ so the
Rider Solution Explorer mirrors the module structure. Folders: Core, Server,
Drivers (with a nested Driver CLIs subfolder), Client, Tooling.

- Move every project folder on disk with git mv (history preserved as renames).
- Recompute relative paths in 57 .csproj files: cross-category ProjectReferences,
  the lib/ HintPath+None refs in Driver.Historian.Wonderware, and the external
  mxaccessgw refs in Driver.Galaxy and its test project.
- Rebuild ZB.MOM.WW.OtOpcUa.slnx with nested solution folders.
- Re-prefix project paths in functional scripts (e2e, compliance, smoke SQL,
  integration, install).

Build green (0 errors); unit tests pass. Docs left for a separate pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-17 01:55:28 -04:00
parent 69f02fed7f
commit a25593a9c6
1044 changed files with 365 additions and 343 deletions
@@ -0,0 +1,58 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Health;
/// <summary>
/// Pushes the synthetic top-level transport-health entry into the
/// <see cref="HostStatusAggregator"/>. Each driver instance has one entry under its
/// <c>MxAccess.ClientName</c> reflecting the gateway transport state — useful for
/// dashboards that want a single "Galaxy is up" signal independent of any individual
/// platform's ScanState.
/// </summary>
/// <remarks>
/// The eventual production source for this signal is the gateway's <c>StreamSessionHealth</c>
/// RPC (mxaccessgw issue gw-6). Until that ships, the driver-side reconnect supervisor
/// (PR 4.5) calls <see cref="SetTransport"/> on transport state transitions:
/// <see cref="HostState.Running"/> when the gw session re-Registers, <see cref="HostState.Stopped"/>
/// when the supervisor moves to <c>TransportLost</c>. The forwarder is intentionally
/// stateless beyond the cached client name + last-pushed value so the supervisor can
/// drive it without any back-pressure plumbing.
/// </remarks>
public sealed class HostConnectivityForwarder : IDisposable
{
private readonly string _clientName;
private readonly HostStatusAggregator _aggregator;
private readonly ILogger _logger;
private bool _disposed;
public HostConnectivityForwarder(string clientName, HostStatusAggregator aggregator, ILogger? logger = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(clientName);
_clientName = clientName;
_aggregator = aggregator ?? throw new ArgumentNullException(nameof(aggregator));
_logger = logger ?? NullLogger.Instance;
}
/// <summary>
/// Push a transport state into the aggregator. Idempotent at the aggregator layer —
/// repeated calls with the same state don't fan out duplicate transitions.
/// </summary>
public void SetTransport(HostState state)
{
ObjectDisposedException.ThrowIf(_disposed, this);
var status = new HostConnectivityStatus(_clientName, state, DateTime.UtcNow);
_aggregator.Update(status);
_logger.LogDebug(
"GalaxyDriver transport state for {ClientName}: {State}",
_clientName, state);
}
public void Dispose()
{
// No-op today; reserved for the eventual gw-6 StreamSessionHealth consumer that
// will own a long-running task this method tears down.
_disposed = true;
}
}