192 lines
7.7 KiB
C#
192 lines
7.7 KiB
C#
using System;
|
|
using System.Threading.Tasks;
|
|
using Opc.Ua;
|
|
using Opc.Ua.Configuration;
|
|
using Opc.Ua.Server;
|
|
using Serilog;
|
|
using ZB.MOM.WW.LmxOpcUa.Host.Configuration;
|
|
using ZB.MOM.WW.LmxOpcUa.Host.Domain;
|
|
using ZB.MOM.WW.LmxOpcUa.Host.Metrics;
|
|
|
|
namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
|
{
|
|
/// <summary>
|
|
/// Manages the OPC UA ApplicationInstance lifecycle. Programmatic config, no XML. (OPC-001, OPC-012, OPC-013)
|
|
/// </summary>
|
|
public class OpcUaServerHost : IDisposable
|
|
{
|
|
private static readonly ILogger Log = Serilog.Log.ForContext<OpcUaServerHost>();
|
|
|
|
private readonly OpcUaConfiguration _config;
|
|
private readonly IMxAccessClient _mxAccessClient;
|
|
private readonly PerformanceMetrics _metrics;
|
|
private ApplicationInstance? _application;
|
|
private LmxOpcUaServer? _server;
|
|
|
|
/// <summary>
|
|
/// Gets the active node manager that holds the published Galaxy namespace.
|
|
/// </summary>
|
|
public LmxNodeManager? NodeManager => _server?.NodeManager;
|
|
|
|
/// <summary>
|
|
/// Gets the number of currently connected OPC UA client sessions.
|
|
/// </summary>
|
|
public int ActiveSessionCount => _server?.ActiveSessionCount ?? 0;
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether the OPC UA server has been started and not yet stopped.
|
|
/// </summary>
|
|
public bool IsRunning => _server != null;
|
|
|
|
/// <summary>
|
|
/// Initializes a new host for the Galaxy-backed OPC UA server instance.
|
|
/// </summary>
|
|
/// <param name="config">The endpoint and session settings for the OPC UA host.</param>
|
|
/// <param name="mxAccessClient">The runtime client used by the node manager for live reads, writes, and subscriptions.</param>
|
|
/// <param name="metrics">The metrics collector shared with the node manager and runtime bridge.</param>
|
|
public OpcUaServerHost(OpcUaConfiguration config, IMxAccessClient mxAccessClient, PerformanceMetrics metrics)
|
|
{
|
|
_config = config;
|
|
_mxAccessClient = mxAccessClient;
|
|
_metrics = metrics;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starts the OPC UA application instance, prepares certificates, and binds the Galaxy namespace to the configured endpoint.
|
|
/// </summary>
|
|
public async Task StartAsync()
|
|
{
|
|
var namespaceUri = $"urn:{_config.GalaxyName}:LmxOpcUa";
|
|
|
|
var appConfig = new ApplicationConfiguration
|
|
{
|
|
ApplicationName = _config.ServerName,
|
|
ApplicationUri = namespaceUri,
|
|
ApplicationType = ApplicationType.Server,
|
|
ProductUri = namespaceUri,
|
|
|
|
ServerConfiguration = new ServerConfiguration
|
|
{
|
|
BaseAddresses = { $"opc.tcp://0.0.0.0:{_config.Port}{_config.EndpointPath}" },
|
|
MaxSessionCount = _config.MaxSessions,
|
|
MaxSessionTimeout = _config.SessionTimeoutMinutes * 60 * 1000, // ms
|
|
MinSessionTimeout = 10000,
|
|
SecurityPolicies =
|
|
{
|
|
new ServerSecurityPolicy
|
|
{
|
|
SecurityMode = MessageSecurityMode.None,
|
|
SecurityPolicyUri = SecurityPolicies.None
|
|
}
|
|
},
|
|
UserTokenPolicies =
|
|
{
|
|
new UserTokenPolicy(UserTokenType.Anonymous)
|
|
}
|
|
},
|
|
|
|
SecurityConfiguration = new SecurityConfiguration
|
|
{
|
|
ApplicationCertificate = new CertificateIdentifier
|
|
{
|
|
StoreType = CertificateStoreType.Directory,
|
|
StorePath = System.IO.Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
|
"OPC Foundation", "pki", "own"),
|
|
SubjectName = $"CN={_config.ServerName}, O=ZB MOM, DC=localhost"
|
|
},
|
|
TrustedIssuerCertificates = new CertificateTrustList
|
|
{
|
|
StoreType = CertificateStoreType.Directory,
|
|
StorePath = System.IO.Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
|
"OPC Foundation", "pki", "issuer")
|
|
},
|
|
TrustedPeerCertificates = new CertificateTrustList
|
|
{
|
|
StoreType = CertificateStoreType.Directory,
|
|
StorePath = System.IO.Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
|
"OPC Foundation", "pki", "trusted")
|
|
},
|
|
RejectedCertificateStore = new CertificateTrustList
|
|
{
|
|
StoreType = CertificateStoreType.Directory,
|
|
StorePath = System.IO.Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
|
"OPC Foundation", "pki", "rejected")
|
|
},
|
|
AutoAcceptUntrustedCertificates = true
|
|
},
|
|
|
|
TransportQuotas = new TransportQuotas
|
|
{
|
|
OperationTimeout = 120000,
|
|
MaxStringLength = 4 * 1024 * 1024,
|
|
MaxByteStringLength = 4 * 1024 * 1024,
|
|
MaxArrayLength = 65535,
|
|
MaxMessageSize = 4 * 1024 * 1024,
|
|
MaxBufferSize = 65535,
|
|
ChannelLifetime = 600000,
|
|
SecurityTokenLifetime = 3600000
|
|
},
|
|
|
|
TraceConfiguration = new TraceConfiguration
|
|
{
|
|
OutputFilePath = null,
|
|
TraceMasks = 0
|
|
}
|
|
};
|
|
|
|
await appConfig.Validate(ApplicationType.Server);
|
|
|
|
_application = new ApplicationInstance
|
|
{
|
|
ApplicationName = _config.ServerName,
|
|
ApplicationType = ApplicationType.Server,
|
|
ApplicationConfiguration = appConfig
|
|
};
|
|
|
|
// Check/create application certificate
|
|
bool certOk = await _application.CheckApplicationInstanceCertificate(false, 2048);
|
|
if (!certOk)
|
|
{
|
|
Log.Warning("Application certificate check failed, attempting to create...");
|
|
certOk = await _application.CheckApplicationInstanceCertificate(false, 2048);
|
|
}
|
|
|
|
_server = new LmxOpcUaServer(_config.GalaxyName, _mxAccessClient, _metrics);
|
|
await _application.Start(_server);
|
|
|
|
Log.Information("OPC UA server started on opc.tcp://localhost:{Port}{EndpointPath} (namespace={Namespace})",
|
|
_config.Port, _config.EndpointPath, namespaceUri);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops the OPC UA application instance and releases its in-memory server objects.
|
|
/// </summary>
|
|
public void Stop()
|
|
{
|
|
try
|
|
{
|
|
_server?.Stop();
|
|
Log.Information("OPC UA server stopped");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Warning(ex, "Error stopping OPC UA server");
|
|
}
|
|
finally
|
|
{
|
|
_server = null;
|
|
_application = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops the host and releases server resources.
|
|
/// </summary>
|
|
public void Dispose() => Stop();
|
|
}
|
|
}
|