refactor(historian-gateway): retire Wonderware historian projects (gateway is sole backend)

The HistorianGateway driver is now the sole historian read/write+alarm backend, so the
Wonderware sidecar projects are dead code. Removes the 5 Wonderware projects (driver,
.Client, .Client.Contracts, + their 2 test projects) from the solution and tree, and fully
retires the vestigial 'Historian.Wonderware' driver type (UI/probe-only; it had no driver
factory): the Host probe registration, the AdminUI driver-config surface (driver page,
tag-config editor/model/validator entry, address picker/builder, driver-type catalog +
dropdown + edit-router entries), and their tests. Prunes the now-unused Wonderware
connection fields (Host/Port/UseTls/ServerCertThumbprint/SharedSecret) from
AlarmHistorianOptions (keeping Enabled + the SQLite store-and-forward knobs) and refreshes
the stale XML docs that named Wonderware as the production backend.

Claude-Session: https://claude.ai/code/session_012SDSQ3AcaXqPcBtDESBRii
This commit is contained in:
Joseph Doherty
2026-06-26 19:25:21 -04:00
parent 245db98f5e
commit 0b4b2e4cfd
84 changed files with 37 additions and 9345 deletions
@@ -233,13 +233,9 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
/// <summary>
/// Returns true when the driver should boot in DEV-STUB mode based on host platform and
/// configured roles. Only the v1 in-process types stay Windows-only:
/// <list type="bullet">
/// <item><c>"Galaxy"</c> — legacy MXAccess COM proxy (retired in PR 7.2; gated for any
/// leftover DriverInstance rows that still reference the old type name).</item>
/// <item><c>"Historian.Wonderware"</c> — Wonderware Historian sidecar over Windows-only
/// named pipes.</item>
/// </list>
/// configured roles. Only the legacy v1 in-process <c>"Galaxy"</c> type stays Windows-only:
/// the legacy MXAccess COM proxy (retired in PR 7.2; gated for any leftover DriverInstance
/// rows that still reference the old type name).
/// The v2 <c>"GalaxyMxGateway"</c> driver talks gRPC to an external mxaccessgw process,
/// so it runs on any platform .NET 10 supports — Linux containers included. Not stubbed.
/// </summary>
@@ -247,7 +243,7 @@ public sealed class DriverInstanceActor : ReceiveActor, IWithTimers
/// <param name="roles">Operational roles configured for this instance.</param>
public static bool ShouldStub(string driverType, IEnumerable<string> roles)
{
var isWindowsOnly = driverType is "Galaxy" or "Historian.Wonderware";
var isWindowsOnly = driverType is "Galaxy";
if (!OperatingSystem.IsWindows() && isWindowsOnly) return true;
if (roles.Contains("dev") && isWindowsOnly) return true;
return false;
@@ -8,8 +8,10 @@ namespace ZB.MOM.WW.OtOpcUa.Runtime.Historian;
/// Binds the <c>AlarmHistorian</c> configuration section that gates the durable
/// store-and-forward alarm sink. When <see cref="Enabled"/> is <c>true</c>,
/// <c>AddAlarmHistorian</c> registers a <c>SqliteStoreAndForwardSink</c> (draining to the
/// Wonderware TCP writer supplied by the Host) in place of the
/// <c>NullAlarmHistorianSink</c> default; otherwise the Null default survives.
/// gateway alarm writer supplied by the Host) in place of the
/// <c>NullAlarmHistorianSink</c> default; otherwise the Null default survives. This section
/// supplies only the <see cref="Enabled"/> gate and the SQLite store-and-forward knobs — the
/// downstream connection (endpoint/key/TLS) is sourced from the <c>ServerHistorian</c> section.
/// </summary>
public sealed class AlarmHistorianOptions
{
@@ -25,21 +27,6 @@ public sealed class AlarmHistorianOptions
/// <summary>Filesystem path to the local SQLite store-and-forward queue database.</summary>
public string DatabasePath { get; init; } = "alarm-historian.db";
/// <summary>TCP hostname or IP address the Wonderware historian sidecar listens on.</summary>
public string Host { get; init; } = "localhost";
/// <summary>TCP port the Wonderware historian sidecar listens on.</summary>
public int Port { get; init; } = 32569;
/// <summary>When <c>true</c>, the client connects over TLS.</summary>
public bool UseTls { get; init; }
/// <summary>Expected TLS server certificate thumbprint (hex, no spaces). Null or empty disables pinning.</summary>
public string? ServerCertThumbprint { get; init; }
/// <summary>Per-process shared secret the sidecar verifies in the Hello frame.</summary>
public string SharedSecret { get; init; } = "";
/// <summary>Maximum number of queued rows the drain worker forwards in a single batch.</summary>
public int BatchSize { get; init; } = 100;
@@ -64,8 +51,6 @@ public sealed class AlarmHistorianOptions
{
var warnings = new List<string>();
if (!Enabled) return warnings;
if (string.IsNullOrWhiteSpace(SharedSecret))
warnings.Add("AlarmHistorian:SharedSecret is empty while the historian is enabled — the Wonderware sidecar Hello frame will carry an empty secret.");
if (!Path.IsPathRooted(DatabasePath))
warnings.Add($"AlarmHistorian:DatabasePath '{DatabasePath}' is relative — it resolves against the process working directory (e.g. System32 for a Windows service). Set an absolute path.");
if (DrainIntervalSeconds <= 0)
@@ -39,7 +39,7 @@ public static class ServiceCollectionExtensions
/// <summary>
/// Registers shared runtime services. Currently binds <see cref="IAlarmHistorianSink"/>
/// to <see cref="NullAlarmHistorianSink"/> as the default; production deployments
/// override this with <c>SqliteStoreAndForwardSink</c> wrapping <c>WonderwareHistorianClient</c>.
/// override this with <c>SqliteStoreAndForwardSink</c> wrapping the HistorianGateway alarm writer.
/// Call this BEFORE <c>AddAkka</c>.
/// </summary>
/// <param name="services">The service collection to register with.</param>
@@ -63,14 +63,14 @@ public static class ServiceCollectionExtensions
/// <c>Enabled=true</c>, registers a <see cref="SqliteStoreAndForwardSink"/> (draining via the
/// <paramref name="writerFactory"/>-supplied writer) as the <see cref="IAlarmHistorianSink"/>,
/// overriding the <see cref="NullAlarmHistorianSink"/> default. Otherwise a no-op (Null stays).
/// The writer is injected so the durable downstream (Wonderware named-pipe client) can be supplied
/// by the Host, which is the only project that references it.
/// The writer is injected so the durable downstream (the HistorianGateway alarm writer) can be
/// supplied by the Host, which is the only project that references it.
/// </summary>
/// <param name="services">The service collection to register with.</param>
/// <param name="configuration">The configuration carrying the <c>AlarmHistorian</c> section.</param>
/// <param name="writerFactory">
/// Factory the Host supplies to build the concrete <see cref="IAlarmHistorianWriter"/>
/// (the Wonderware named-pipe client) from the bound options + the resolving provider.
/// (the HistorianGateway alarm writer) from the bound options + the resolving provider.
/// </param>
/// <returns>The same <paramref name="services"/> instance for chaining.</returns>
public static IServiceCollection AddAlarmHistorian(