feat(browse): Wave-0 Batch C — CapturingAddressSpaceBuilder + CapturedTreeBrowseSession
Task 6: CapturedTree/CapturedNode model + CapturingAddressSpaceBuilder — an in-memory
IAddressSpaceBuilder that records a driver's DiscoverAsync stream (folder nesting,
leaf FullName as node id, alarm mark, node-cap truncation, no-op alarm sink).
Task 7: CapturedTreeBrowseSession — serves the captured snapshot through IBrowseSession
(Root/Expand/Attributes from memory, truncation marker, shared-immutable-tree dispose).
13 unit tests green.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Commons.Browsing;
|
||||
|
||||
/// <summary>One node captured from a driver's DiscoverAsync stream. Folder ids are
|
||||
/// path-composed ("/parent/child"); leaf ids are the driver FullName (the commit value).</summary>
|
||||
public sealed class CapturedNode
|
||||
{
|
||||
/// <summary>Stable identifier. Folder = path-composed ("/parent/child"); leaf = driver FullName.</summary>
|
||||
public required string Id { get; init; }
|
||||
|
||||
/// <summary>Browse name (the path segment under the parent).</summary>
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>Human-readable display name.</summary>
|
||||
public required string DisplayName { get; init; }
|
||||
|
||||
/// <summary>True for a variable (terminal); false for a folder.</summary>
|
||||
public required bool IsLeaf { get; init; }
|
||||
|
||||
/// <summary>Driver-side attribute metadata; set only on leaves.</summary>
|
||||
public DriverAttributeInfo? Attribute { get; init; }
|
||||
|
||||
/// <summary>True when the driver marked this leaf as an alarm condition during discovery.</summary>
|
||||
public bool IsAlarmMarked { get; set; }
|
||||
|
||||
/// <summary>Captured child nodes (folders first-or-interleaved in stream order).</summary>
|
||||
public List<CapturedNode> Children { get; } = [];
|
||||
|
||||
/// <summary>Captured static properties attached to this node via AddProperty.</summary>
|
||||
public List<(string Name, DriverDataType Type, object? Value)> Properties { get; } = [];
|
||||
}
|
||||
|
||||
/// <summary>Immutable-after-Build snapshot of a whole discovery capture. May be shared by
|
||||
/// multiple coalesced browse sessions — sessions drop their reference on dispose, never mutate.</summary>
|
||||
public sealed class CapturedTree
|
||||
{
|
||||
/// <summary>Synthetic root; its Children are the top-level captured nodes.</summary>
|
||||
public required CapturedNode Root { get; init; }
|
||||
|
||||
/// <summary>True when the node cap was hit and recording stopped short.</summary>
|
||||
public required bool Truncated { get; init; }
|
||||
|
||||
/// <summary>Number of nodes actually recorded (bounded by the node cap).</summary>
|
||||
public required int Count { get; init; }
|
||||
|
||||
/// <summary>Flat lookup from node id to node (for O(1) Expand/Attributes serving).</summary>
|
||||
public required IReadOnlyDictionary<string, CapturedNode> ById { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user