using ZB.MOM.WW.Configuration; namespace ZB.MOM.WW.ScadaBridge.Host; /// /// Validates at host startup (arch-review 08 round 2 /// NF4). The headline invariant: must be /// non-empty — an empty value normalises to a NULL SourceNode audit /// column, silently degrading the audit trail (the wonder-app-vd03 failure /// mode), so the host must fail fast at boot instead. Ports are bounded to the /// TCP range; 0 stays valid because it requests a dynamically-assigned /// port (CompositionRootTests rely on this). /// public sealed class NodeOptionsValidator : OptionsValidatorBase { /// protected override void Validate(ValidationBuilder builder, NodeOptions options) { builder.RequireThat(!string.IsNullOrWhiteSpace(options.NodeName), $"ScadaBridge:Node:{nameof(NodeOptions.NodeName)} must be a non-empty label " + "— an empty node name stamps the SourceNode audit column NULL."); RequirePort(builder, options.RemotingPort, nameof(NodeOptions.RemotingPort)); RequirePort(builder, options.GrpcPort, nameof(NodeOptions.GrpcPort)); RequirePort(builder, options.MetricsPort, nameof(NodeOptions.MetricsPort)); RequirePort(builder, options.CentralGrpcPort, nameof(NodeOptions.CentralGrpcPort)); } // 0 stays valid (dynamic-port request); reject only out-of-TCP-range values. private static void RequirePort(ValidationBuilder builder, int port, string field) { builder.RequireThat(port is >= 0 and <= 65_535, $"ScadaBridge:Node:{field} ({port}) must be in [0, 65535]."); } }