using Opc.Ua; using Opc.Ua.Configuration; using Serilog; using ZB.MOM.WW.OtOpcUa.Client.Shared.Models; namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Adapters; /// /// Production implementation that builds a real OPC UA ApplicationConfiguration. /// internal sealed class DefaultApplicationConfigurationFactory : IApplicationConfigurationFactory { private static readonly ILogger Logger = Log.ForContext(); /// public async Task CreateAsync(ConnectionSettings settings, CancellationToken ct) { // Resolve the canonical PKI path lazily on first use so constructing a // ConnectionSettings instance — including the throwaway copies the client // service builds per failover attempt — does not touch the filesystem. // Callers that supply an explicit path override the default. var storePath = string.IsNullOrWhiteSpace(settings.CertificateStorePath) ? ClientStoragePaths.GetPkiPath() : settings.CertificateStorePath; var config = new ApplicationConfiguration(ClientTelemetry.Context) { ApplicationName = "OtOpcUaClient", ApplicationUri = "urn:localhost:OtOpcUaClient", ApplicationType = ApplicationType.Client, SecurityConfiguration = new SecurityConfiguration { ApplicationCertificate = new CertificateIdentifier { StoreType = CertificateStoreType.Directory, StorePath = Path.Combine(storePath, "own"), SubjectName = "CN=OtOpcUaClient" }, TrustedIssuerCertificates = new CertificateTrustList { StoreType = CertificateStoreType.Directory, StorePath = Path.Combine(storePath, "issuer") }, TrustedPeerCertificates = new CertificateTrustList { StoreType = CertificateStoreType.Directory, StorePath = Path.Combine(storePath, "trusted") }, RejectedCertificateStore = new CertificateTrustList { StoreType = CertificateStoreType.Directory, StorePath = Path.Combine(storePath, "rejected") }, AutoAcceptUntrustedCertificates = settings.AutoAcceptCertificates }, ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = settings.SessionTimeoutSeconds * 1000 } }; try { await config.ValidateAsync(ApplicationType.Client, ct); if (settings.SecurityMode != SecurityMode.None) { var app = new ApplicationInstance(ClientTelemetry.Context) { ApplicationName = "OtOpcUaClient", ApplicationType = ApplicationType.Client, ApplicationConfiguration = config }; await app.CheckApplicationInstanceCertificatesAsync(false, lifeTimeInMonths: 2048, ct: ct); } } catch { try { (config.CertificateManager as IDisposable)?.Dispose(); } catch (Exception ex) { Logger.Warning(ex, "Disposing certificate manager after configuration failure"); } throw; } Logger.Debug("ApplicationConfiguration created for {EndpointUrl}", settings.EndpointUrl); return config; } }