48 lines
1.8 KiB
C#
48 lines
1.8 KiB
C#
using ZB.MOM.WW.OtOpcUa.Core.OpcUa;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Server.OpcUa;
|
|
|
|
/// <summary>
|
|
/// Holds pre-loaded <see cref="EquipmentNamespaceContent"/> snapshots keyed by
|
|
/// <c>DriverInstanceId</c>. Populated once during <see cref="OpcUaServerService"/> startup
|
|
/// (after <see cref="NodeBootstrap"/> resolves the generation) so the synchronous lookup
|
|
/// delegate on <see cref="OpcUaApplicationHost"/> can serve the walker from memory without
|
|
/// blocking on async DB I/O mid-dispatch.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>The registry is intentionally a shared mutable singleton with set-once-per-bootstrap
|
|
/// semantics rather than an immutable map passed by value — the composition in Program.cs
|
|
/// builds <see cref="OpcUaApplicationHost"/> before <see cref="NodeBootstrap"/> runs, so the
|
|
/// registry must exist at DI-compose time but be empty until the generation is known. A
|
|
/// driver registered after the initial populate pass simply returns null from
|
|
/// <see cref="Get"/> + the wire-in falls back to the "no UNS content, let DiscoverAsync own
|
|
/// it" path that PR #155 established.</para>
|
|
/// </remarks>
|
|
public sealed class DriverEquipmentContentRegistry
|
|
{
|
|
private readonly Dictionary<string, EquipmentNamespaceContent> _content =
|
|
new(StringComparer.OrdinalIgnoreCase);
|
|
private readonly Lock _lock = new();
|
|
|
|
public EquipmentNamespaceContent? Get(string driverInstanceId)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return _content.TryGetValue(driverInstanceId, out var c) ? c : null;
|
|
}
|
|
}
|
|
|
|
public void Set(string driverInstanceId, EquipmentNamespaceContent content)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_content[driverInstanceId] = content;
|
|
}
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get { lock (_lock) { return _content.Count; } }
|
|
}
|
|
}
|