namespace ZB.MOM.WW.OtOpcUa.Commons.OpcUa; /// /// Wrapper that defers to an inner sink swapped in at /// runtime. Needed because the production sink (SdkAddressSpaceSink) wraps an /// OtOpcUaNodeManager that only exists after the SDK StandardServer has /// started — but Akka actors resolve their sink dependency at construction time, before /// the hosted service has booted the SDK. /// /// Bound as a singleton in DI on driver-role hosts; the OPC UA hosted service calls /// once the server is up. Until that swap happens, every call is a /// no-op against , so the actor stays safe to /// receive messages from the moment it boots. /// public sealed class DeferredAddressSpaceSink : IOpcUaAddressSpaceSink { private volatile IOpcUaAddressSpaceSink _inner = NullOpcUaAddressSpaceSink.Instance; /// Swap in the production sink. Pass null to revert to the null sink /// (used during graceful shutdown so post-stop writes don't hit a half-disposed manager). /// The sink implementation to use, or null to use the null sink. public void SetSink(IOpcUaAddressSpaceSink? sink) => _inner = sink ?? NullOpcUaAddressSpaceSink.Instance; /// Writes a value to the OPC UA address space through the inner sink. /// The node ID of the variable. /// The value to write. /// The OPC UA quality value. /// The source timestamp in UTC. public void WriteValue(string nodeId, object? value, OpcUaQuality quality, DateTime sourceTimestampUtc) => _inner.WriteValue(nodeId, value, quality, sourceTimestampUtc); /// Writes an alarm state through the inner sink. /// The node ID of the alarm condition. /// Whether the alarm is active. /// Whether the alarm has been acknowledged. /// The source timestamp in UTC. public void WriteAlarmState(string alarmNodeId, bool active, bool acknowledged, DateTime sourceTimestampUtc) => _inner.WriteAlarmState(alarmNodeId, active, acknowledged, sourceTimestampUtc); /// Ensures a folder exists in the address space through the inner sink. /// The node ID of the folder. /// The node ID of the parent folder, or null for root. /// The display name of the folder. public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName) => _inner.EnsureFolder(folderNodeId, parentNodeId, displayName); /// Ensures a variable exists in the address space through the inner sink. /// The node ID of the variable. /// The node ID of the parent folder, or null for root. /// The display name of the variable. /// The OPC UA data type of the variable. public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType) => _inner.EnsureVariable(variableNodeId, parentFolderNodeId, displayName, dataType); /// Rebuilds the address space through the inner sink. public void RebuildAddressSpace() => _inner.RebuildAddressSpace(); }