16d1b95e9a
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
105 lines
5.4 KiB
C#
105 lines
5.4 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|