deprecate(lmxproxy): move all LmxProxy code, tests, and docs to deprecated/

LmxProxy is no longer needed. Moved the entire lmxproxy/ workspace, DCL
adapter files, and related docs to deprecated/. Removed LmxProxy registration
from DataConnectionFactory, project reference from DCL, protocol option from
UI, and cleaned up all requirement docs.
This commit is contained in:
Joseph Doherty
2026-04-08 15:56:23 -04:00
parent 8423915ba1
commit 9dccf8e72f
220 changed files with 25 additions and 132 deletions

View File

@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.IO;
using Serilog;
namespace ZB.MOM.WW.LmxProxy.Host.Configuration
{
/// <summary>
/// Validates the LmxProxy configuration at startup.
/// Throws InvalidOperationException on any validation error.
/// </summary>
public static class ConfigurationValidator
{
private static readonly ILogger Log = Serilog.Log.ForContext(typeof(ConfigurationValidator));
/// <summary>
/// Validates all configuration settings and logs the effective values.
/// Throws on first validation error.
/// </summary>
public static void ValidateAndLog(LmxProxyConfiguration config)
{
var errors = new List<string>();
// GrpcPort
if (config.GrpcPort < 1 || config.GrpcPort > 65535)
errors.Add($"GrpcPort must be 1-65535, got {config.GrpcPort}");
// Connection
var conn = config.Connection;
if (conn.MonitorIntervalSeconds <= 0)
errors.Add($"Connection.MonitorIntervalSeconds must be > 0, got {conn.MonitorIntervalSeconds}");
if (conn.ConnectionTimeoutSeconds <= 0)
errors.Add($"Connection.ConnectionTimeoutSeconds must be > 0, got {conn.ConnectionTimeoutSeconds}");
if (conn.ReadTimeoutSeconds <= 0)
errors.Add($"Connection.ReadTimeoutSeconds must be > 0, got {conn.ReadTimeoutSeconds}");
if (conn.WriteTimeoutSeconds <= 0)
errors.Add($"Connection.WriteTimeoutSeconds must be > 0, got {conn.WriteTimeoutSeconds}");
if (conn.MaxConcurrentOperations <= 0)
errors.Add($"Connection.MaxConcurrentOperations must be > 0, got {conn.MaxConcurrentOperations}");
if (conn.NodeName != null && conn.NodeName.Length > 255)
errors.Add("Connection.NodeName must be <= 255 characters");
if (conn.GalaxyName != null && conn.GalaxyName.Length > 255)
errors.Add("Connection.GalaxyName must be <= 255 characters");
// Subscription
var sub = config.Subscription;
if (sub.ChannelCapacity < 0 || sub.ChannelCapacity > 100000)
errors.Add($"Subscription.ChannelCapacity must be 0-100000, got {sub.ChannelCapacity}");
var validModes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{ "DropOldest", "DropNewest", "Wait" };
if (!validModes.Contains(sub.ChannelFullMode))
errors.Add($"Subscription.ChannelFullMode must be DropOldest, DropNewest, or Wait, got '{sub.ChannelFullMode}'");
// ServiceRecovery
var sr = config.ServiceRecovery;
if (sr.FirstFailureDelayMinutes < 0)
errors.Add($"ServiceRecovery.FirstFailureDelayMinutes must be >= 0, got {sr.FirstFailureDelayMinutes}");
if (sr.SecondFailureDelayMinutes < 0)
errors.Add($"ServiceRecovery.SecondFailureDelayMinutes must be >= 0, got {sr.SecondFailureDelayMinutes}");
if (sr.SubsequentFailureDelayMinutes < 0)
errors.Add($"ServiceRecovery.SubsequentFailureDelayMinutes must be >= 0, got {sr.SubsequentFailureDelayMinutes}");
if (sr.ResetPeriodDays <= 0)
errors.Add($"ServiceRecovery.ResetPeriodDays must be > 0, got {sr.ResetPeriodDays}");
// TLS
if (config.Tls.Enabled)
{
if (!File.Exists(config.Tls.ServerCertificatePath))
Log.Warning("TLS enabled but server certificate not found at {Path} (will auto-generate)",
config.Tls.ServerCertificatePath);
if (!File.Exists(config.Tls.ServerKeyPath))
Log.Warning("TLS enabled but server key not found at {Path} (will auto-generate)",
config.Tls.ServerKeyPath);
}
// WebServer
if (config.WebServer.Enabled)
{
if (config.WebServer.Port < 1 || config.WebServer.Port > 65535)
errors.Add($"WebServer.Port must be 1-65535, got {config.WebServer.Port}");
}
if (errors.Count > 0)
{
foreach (var error in errors)
Log.Error("Configuration error: {Error}", error);
throw new InvalidOperationException(
$"Configuration validation failed with {errors.Count} error(s): {string.Join("; ", errors)}");
}
// Log effective configuration
Log.Information("Configuration validated successfully");
Log.Information(" GrpcPort: {Port}", config.GrpcPort);
Log.Information(" ApiKeyConfigFile: {File}", config.ApiKeyConfigFile);
Log.Information(" Connection.AutoReconnect: {AutoReconnect}", conn.AutoReconnect);
Log.Information(" Connection.MonitorIntervalSeconds: {Interval}", conn.MonitorIntervalSeconds);
Log.Information(" Connection.MaxConcurrentOperations: {Max}", conn.MaxConcurrentOperations);
Log.Information(" Subscription.ChannelCapacity: {Capacity}", sub.ChannelCapacity);
Log.Information(" Subscription.ChannelFullMode: {Mode}", sub.ChannelFullMode);
Log.Information(" Tls.Enabled: {Enabled}", config.Tls.Enabled);
Log.Information(" WebServer.Enabled: {Enabled}, Port: {Port}", config.WebServer.Enabled, config.WebServer.Port);
}
}
}

View File

@@ -0,0 +1,30 @@
namespace ZB.MOM.WW.LmxProxy.Host.Configuration
{
/// <summary>MxAccess connection settings.</summary>
public class ConnectionConfiguration
{
/// <summary>Auto-reconnect check interval in seconds. Default: 5.</summary>
public int MonitorIntervalSeconds { get; set; } = 5;
/// <summary>Initial connection timeout in seconds. Default: 30.</summary>
public int ConnectionTimeoutSeconds { get; set; } = 30;
/// <summary>Per-read operation timeout in seconds. Default: 5.</summary>
public int ReadTimeoutSeconds { get; set; } = 5;
/// <summary>Per-write operation timeout in seconds. Default: 5.</summary>
public int WriteTimeoutSeconds { get; set; } = 5;
/// <summary>Semaphore limit for concurrent MxAccess operations. Default: 10.</summary>
public int MaxConcurrentOperations { get; set; } = 10;
/// <summary>Enable auto-reconnect loop. Default: true.</summary>
public bool AutoReconnect { get; set; } = true;
/// <summary>MxAccess node name (optional).</summary>
public string? NodeName { get; set; }
/// <summary>MxAccess galaxy name (optional).</summary>
public string? GalaxyName { get; set; }
}
}

View File

@@ -0,0 +1,46 @@
namespace ZB.MOM.WW.LmxProxy.Host.Configuration
{
/// <summary>Root configuration class bound to appsettings.json.</summary>
public class LmxProxyConfiguration
{
/// <summary>gRPC server listen port. Default: 50051.</summary>
public int GrpcPort { get; set; } = 50051;
/// <summary>Path to API key configuration file. Default: apikeys.json.</summary>
public string ApiKeyConfigFile { get; set; } = "apikeys.json";
/// <summary>Unique client name for MxAccess Register(). Must be unique per instance. Default: auto-generated.</summary>
public string? ClientName { get; set; }
/// <summary>MxAccess connection settings.</summary>
public ConnectionConfiguration Connection { get; set; } = new ConnectionConfiguration();
/// <summary>Subscription channel settings.</summary>
public SubscriptionConfiguration Subscription { get; set; } = new SubscriptionConfiguration();
/// <summary>TLS/SSL settings.</summary>
public TlsConfiguration Tls { get; set; } = new TlsConfiguration();
/// <summary>Status web server settings.</summary>
public WebServerConfiguration WebServer { get; set; } = new WebServerConfiguration();
/// <summary>Windows SCM service recovery settings.</summary>
public ServiceRecoveryConfiguration ServiceRecovery { get; set; } = new ServiceRecoveryConfiguration();
/// <summary>Health check / active probe settings.</summary>
public HealthCheckConfiguration HealthCheck { get; set; } = new HealthCheckConfiguration();
}
/// <summary>Health check / probe configuration.</summary>
public class HealthCheckConfiguration
{
/// <summary>Tag address to subscribe to for connection liveness. Default: DevPlatform.Scheduler.ScanTime.</summary>
public string TestTagAddress { get; set; } = "DevPlatform.Scheduler.ScanTime";
/// <summary>
/// Maximum time (ms) without a value update on the test tag before forcing reconnect.
/// Default: 5000 (5 seconds).
/// </summary>
public int ProbeStaleThresholdMs { get; set; } = 5000;
}
}

View File

@@ -0,0 +1,18 @@
namespace ZB.MOM.WW.LmxProxy.Host.Configuration
{
/// <summary>Windows SCM service recovery settings.</summary>
public class ServiceRecoveryConfiguration
{
/// <summary>Restart delay after first failure in minutes. Default: 1.</summary>
public int FirstFailureDelayMinutes { get; set; } = 1;
/// <summary>Restart delay after second failure in minutes. Default: 5.</summary>
public int SecondFailureDelayMinutes { get; set; } = 5;
/// <summary>Restart delay after subsequent failures in minutes. Default: 10.</summary>
public int SubsequentFailureDelayMinutes { get; set; } = 10;
/// <summary>Days before failure count resets. Default: 1.</summary>
public int ResetPeriodDays { get; set; } = 1;
}
}

View File

@@ -0,0 +1,12 @@
namespace ZB.MOM.WW.LmxProxy.Host.Configuration
{
/// <summary>Subscription channel settings.</summary>
public class SubscriptionConfiguration
{
/// <summary>Per-client subscription buffer size. Default: 1000.</summary>
public int ChannelCapacity { get; set; } = 1000;
/// <summary>Backpressure strategy: DropOldest, DropNewest, or Wait. Default: DropOldest.</summary>
public string ChannelFullMode { get; set; } = "DropOldest";
}
}

View File

@@ -0,0 +1,24 @@
namespace ZB.MOM.WW.LmxProxy.Host.Configuration
{
/// <summary>TLS/SSL settings for the gRPC server.</summary>
public class TlsConfiguration
{
/// <summary>Enable TLS on the gRPC server. Default: false.</summary>
public bool Enabled { get; set; } = false;
/// <summary>PEM server certificate path. Default: certs/server.crt.</summary>
public string ServerCertificatePath { get; set; } = "certs/server.crt";
/// <summary>PEM server private key path. Default: certs/server.key.</summary>
public string ServerKeyPath { get; set; } = "certs/server.key";
/// <summary>CA certificate for mutual TLS client validation. Default: certs/ca.crt.</summary>
public string ClientCaCertificatePath { get; set; } = "certs/ca.crt";
/// <summary>Require client certificates (mutual TLS). Default: false.</summary>
public bool RequireClientCertificate { get; set; } = false;
/// <summary>Check certificate revocation lists. Default: false.</summary>
public bool CheckCertificateRevocation { get; set; } = false;
}
}

View File

@@ -0,0 +1,15 @@
namespace ZB.MOM.WW.LmxProxy.Host.Configuration
{
/// <summary>HTTP status web server settings.</summary>
public class WebServerConfiguration
{
/// <summary>Enable the status web server. Default: true.</summary>
public bool Enabled { get; set; } = true;
/// <summary>HTTP listen port. Default: 8080.</summary>
public int Port { get; set; } = 8080;
/// <summary>Custom URL prefix (defaults to http://+:{Port}/ if null).</summary>
public string? Prefix { get; set; }
}
}