Fix OPC UA adapter: pass connection details, certificate stores, endpoint discovery
- DataConnectionActor now stores and passes connection details to adapter ConnectAsync - DataConnectionManagerActor passes connection details when creating actor - RealOpcUaClient uses DiscoveryClient for endpoint selection with no-security preference - Added certificate trust store paths to prevent TrustedIssuerCertificates error - Sanitize connection names for Akka actor paths (replace spaces)
This commit is contained in:
@@ -58,14 +58,18 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
|||||||
private int _totalSubscribed;
|
private int _totalSubscribed;
|
||||||
private int _resolvedTags;
|
private int _resolvedTags;
|
||||||
|
|
||||||
|
private readonly IDictionary<string, string> _connectionDetails;
|
||||||
|
|
||||||
public DataConnectionActor(
|
public DataConnectionActor(
|
||||||
string connectionName,
|
string connectionName,
|
||||||
IDataConnection adapter,
|
IDataConnection adapter,
|
||||||
DataConnectionOptions options)
|
DataConnectionOptions options,
|
||||||
|
IDictionary<string, string>? connectionDetails = null)
|
||||||
{
|
{
|
||||||
_connectionName = connectionName;
|
_connectionName = connectionName;
|
||||||
_adapter = adapter;
|
_adapter = adapter;
|
||||||
_options = options;
|
_options = options;
|
||||||
|
_connectionDetails = connectionDetails ?? new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PreStart()
|
protected override void PreStart()
|
||||||
@@ -204,7 +208,7 @@ public class DataConnectionActor : UntypedActor, IWithStash, IWithTimers
|
|||||||
{
|
{
|
||||||
_log.Debug("[{0}] Attempting connection...", _connectionName);
|
_log.Debug("[{0}] Attempting connection...", _connectionName);
|
||||||
var self = Self;
|
var self = Self;
|
||||||
_adapter.ConnectAsync(new Dictionary<string, string>()).ContinueWith(t =>
|
_adapter.ConnectAsync(_connectionDetails).ContinueWith(t =>
|
||||||
{
|
{
|
||||||
if (t.IsCompletedSuccessfully)
|
if (t.IsCompletedSuccessfully)
|
||||||
return new ConnectResult(true, null);
|
return new ConnectResult(true, null);
|
||||||
|
|||||||
@@ -44,9 +44,13 @@ public class DataConnectionManagerActor : ReceiveActor
|
|||||||
var adapter = _factory.Create(command.ProtocolType, command.ConnectionDetails);
|
var adapter = _factory.Create(command.ProtocolType, command.ConnectionDetails);
|
||||||
|
|
||||||
var props = Props.Create(() => new DataConnectionActor(
|
var props = Props.Create(() => new DataConnectionActor(
|
||||||
command.ConnectionName, adapter, _options));
|
command.ConnectionName, adapter, _options, command.ConnectionDetails));
|
||||||
|
|
||||||
var actorRef = Context.ActorOf(props, command.ConnectionName);
|
// Sanitize name for Akka actor path (replace spaces and invalid chars)
|
||||||
|
var actorName = new string(command.ConnectionName
|
||||||
|
.Select(c => char.IsLetterOrDigit(c) || "-_.*$+:@&=,!~';()".Contains(c) ? c : '-')
|
||||||
|
.ToArray());
|
||||||
|
var actorRef = Context.ActorOf(props, actorName);
|
||||||
_connectionActors[command.ConnectionName] = actorRef;
|
_connectionActors[command.ConnectionName] = actorRef;
|
||||||
|
|
||||||
_log.Info("Created DataConnectionActor for {0} (protocol={1})",
|
_log.Info("Created DataConnectionActor for {0} (protocol={1})",
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ public class RealOpcUaClient : IOpcUaClient
|
|||||||
SecurityConfiguration = new SecurityConfiguration
|
SecurityConfiguration = new SecurityConfiguration
|
||||||
{
|
{
|
||||||
AutoAcceptUntrustedCertificates = true,
|
AutoAcceptUntrustedCertificates = true,
|
||||||
ApplicationCertificate = new CertificateIdentifier()
|
ApplicationCertificate = new CertificateIdentifier(),
|
||||||
|
TrustedIssuerCertificates = new CertificateTrustList { StorePath = Path.Combine(Path.GetTempPath(), "ScadaLink", "pki", "issuers") },
|
||||||
|
TrustedPeerCertificates = new CertificateTrustList { StorePath = Path.Combine(Path.GetTempPath(), "ScadaLink", "pki", "trusted") },
|
||||||
|
RejectedCertificateStore = new CertificateTrustList { StorePath = Path.Combine(Path.GetTempPath(), "ScadaLink", "pki", "rejected") }
|
||||||
},
|
},
|
||||||
ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
|
ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
|
||||||
TransportQuotas = new TransportQuotas { OperationTimeout = 15000 }
|
TransportQuotas = new TransportQuotas { OperationTimeout = 15000 }
|
||||||
@@ -35,11 +38,26 @@ public class RealOpcUaClient : IOpcUaClient
|
|||||||
await appConfig.ValidateAsync(ApplicationType.Client);
|
await appConfig.ValidateAsync(ApplicationType.Client);
|
||||||
appConfig.CertificateValidator.CertificateValidation += (_, e) => e.Accept = true;
|
appConfig.CertificateValidator.CertificateValidation += (_, e) => e.Accept = true;
|
||||||
|
|
||||||
var endpoint = new EndpointDescription(endpointUrl)
|
// Discover endpoints from the server, pick the no-security one
|
||||||
|
EndpointDescription? endpoint;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
SecurityMode = MessageSecurityMode.None,
|
#pragma warning disable CS0618
|
||||||
SecurityPolicyUri = SecurityPolicies.None
|
using var discoveryClient = DiscoveryClient.Create(new Uri(endpointUrl));
|
||||||
};
|
#pragma warning restore CS0618
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
var endpoints = discoveryClient.GetEndpoints(null);
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
endpoint = endpoints
|
||||||
|
.Where(e => e.SecurityMode == MessageSecurityMode.None)
|
||||||
|
.FirstOrDefault() ?? endpoints.FirstOrDefault();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Fallback: construct endpoint description manually
|
||||||
|
endpoint = new EndpointDescription(endpointUrl);
|
||||||
|
}
|
||||||
|
|
||||||
var endpointConfig = EndpointConfiguration.Create(appConfig);
|
var endpointConfig = EndpointConfiguration.Create(appConfig);
|
||||||
var configuredEndpoint = new ConfiguredEndpoint(null, endpoint, endpointConfig);
|
var configuredEndpoint = new ConfiguredEndpoint(null, endpoint, endpointConfig);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user