using Opc.Ua; using Opc.Ua.Client; using Serilog; namespace ZB.MOM.WW.LmxOpcUa.Client.Shared.Adapters; /// /// Production endpoint discovery that queries the real server. /// internal sealed class DefaultEndpointDiscovery : IEndpointDiscovery { private static readonly ILogger Logger = Log.ForContext(); public EndpointDescription SelectEndpoint(ApplicationConfiguration config, string endpointUrl, MessageSecurityMode requestedMode) { if (requestedMode == MessageSecurityMode.None) { #pragma warning disable CS0618 // Acceptable for endpoint selection return CoreClientUtils.SelectEndpoint(config, endpointUrl, false); #pragma warning restore CS0618 } using var client = DiscoveryClient.Create(new Uri(endpointUrl)); var allEndpoints = client.GetEndpoints(null); EndpointDescription? best = null; foreach (var ep in allEndpoints) { if (ep.SecurityMode != requestedMode) continue; if (best == null) { best = ep; continue; } if (ep.SecurityPolicyUri == SecurityPolicies.Basic256Sha256) best = ep; } if (best == null) { var available = string.Join(", ", allEndpoints.Select(e => $"{e.SecurityMode}/{e.SecurityPolicyUri}")); throw new InvalidOperationException( $"No endpoint found with security mode '{requestedMode}'. Available endpoints: {available}"); } // Rewrite endpoint URL hostname to match user-supplied hostname var serverUri = new Uri(best.EndpointUrl); var requestedUri = new Uri(endpointUrl); if (serverUri.Host != requestedUri.Host) { var builder = new UriBuilder(best.EndpointUrl) { Host = requestedUri.Host }; best.EndpointUrl = builder.ToString(); Logger.Debug("Rewrote endpoint host from {ServerHost} to {RequestedHost}", serverUri.Host, requestedUri.Host); } return best; } }