Auto: opcuaclient-8 — type definition mirroring
Adds an opt-in pass-3 walk of the upstream TypesFolder (i=86) so the OPC UA Client driver can mirror upstream type definitions into the local address space. Honours the curation rules from PR-7 (#359). Structural mirror only — binary-encoding priming via LoadDataTypeSystem is tracked as a follow-up because that helper was removed from the public ISession surface in OPCFoundation.NetStandard 1.5.378+. - IAddressSpaceBuilder.RegisterTypeNode (default no-op for back-compat) - MirroredTypeNodeInfo + MirroredTypeKind in Core.Abstractions - OpcUaClientDriverOptions.MirrorTypeDefinitions (default false) - DiscoverAsync pass-3: FetchTypeTreeAsync + recursive HasSubtype walk per branch (ObjectTypes/VariableTypes/DataTypes/ReferenceTypes), best-effort IsAbstract read, IncludePaths/ExcludePaths still applied - 6 new unit tests; all 153 OpcUaClient unit tests pass Closes #280
This commit is contained in:
@@ -35,8 +35,77 @@ public interface IAddressSpaceBuilder
|
||||
/// <c>_base</c> equipment-class template).
|
||||
/// </summary>
|
||||
void AddProperty(string browseName, DriverDataType dataType, object? value);
|
||||
|
||||
/// <summary>
|
||||
/// Register a type-definition node (ObjectType / VariableType / DataType / ReferenceType)
|
||||
/// mirrored from an upstream OPC UA server. Optional surface — drivers that don't mirror
|
||||
/// types simply never call it; address-space builders that don't materialise upstream
|
||||
/// types can leave the default no-op in place. Default implementation drops the call so
|
||||
/// adding this method doesn't break existing <see cref="IAddressSpaceBuilder"/>
|
||||
/// implementations.
|
||||
/// </summary>
|
||||
/// <param name="info">Metadata describing the type-definition node to mirror.</param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The OPC UA Client driver is the primary caller — it walks <c>i=86</c>
|
||||
/// (TypesFolder) during <c>DiscoverAsync</c> when
|
||||
/// <c>OpcUaClientDriverOptions.MirrorTypeDefinitions</c> is set so downstream clients
|
||||
/// see the upstream type system instead of rendering structured-type values as opaque
|
||||
/// strings.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The default no-op is intentional — most builders (Galaxy, Modbus, FOCAS, S7,
|
||||
/// TwinCAT, AB-CIP) don't have a meaningful type folder to project into and would
|
||||
/// otherwise need empty-stub overrides.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
void RegisterTypeNode(MirroredTypeNodeInfo info) { /* default: no-op */ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Categorises a mirrored type-definition node so the receiving builder can route it into
|
||||
/// the right OPC UA standard subtree (<c>ObjectTypesFolder</c>, <c>VariableTypesFolder</c>,
|
||||
/// <c>DataTypesFolder</c>, <c>ReferenceTypesFolder</c>) when projecting upstream types into
|
||||
/// the local address space.
|
||||
/// </summary>
|
||||
public enum MirroredTypeKind
|
||||
{
|
||||
ObjectType,
|
||||
VariableType,
|
||||
DataType,
|
||||
ReferenceType,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Metadata describing a single type-definition node mirrored from an upstream OPC UA
|
||||
/// server. Built by the OPC UA Client driver during type-mirror pass and consumed by
|
||||
/// <see cref="IAddressSpaceBuilder.RegisterTypeNode"/>.
|
||||
/// </summary>
|
||||
/// <param name="Kind">Type category — drives which standard sub-folder the node lives under.</param>
|
||||
/// <param name="UpstreamNodeId">
|
||||
/// Stringified upstream NodeId (e.g. <c>"ns=2;i=1234"</c>) — preserves the original identity
|
||||
/// so a builder that wants to project the type with a stable cross-namespace reference can do
|
||||
/// so. The driver applies any configured namespace remap before stamping this field.
|
||||
/// </param>
|
||||
/// <param name="BrowseName">OPC UA BrowseName segment from the upstream BrowseName.</param>
|
||||
/// <param name="DisplayName">Human-readable display name; falls back to <paramref name="BrowseName"/>.</param>
|
||||
/// <param name="SuperTypeNodeId">
|
||||
/// Stringified upstream NodeId of the super-type (parent type), or <c>null</c> when the node
|
||||
/// sits directly under the root (e.g. <c>BaseObjectType</c>, <c>BaseVariableType</c>). Lets
|
||||
/// the builder reconstruct the inheritance chain.
|
||||
/// </param>
|
||||
/// <param name="IsAbstract">
|
||||
/// <c>true</c> when the upstream node has the <c>IsAbstract</c> flag set (Object / Variable /
|
||||
/// ReferenceType). DataTypes also expose this — the driver passes it through verbatim.
|
||||
/// </param>
|
||||
public sealed record MirroredTypeNodeInfo(
|
||||
MirroredTypeKind Kind,
|
||||
string UpstreamNodeId,
|
||||
string BrowseName,
|
||||
string DisplayName,
|
||||
string? SuperTypeNodeId,
|
||||
bool IsAbstract);
|
||||
|
||||
/// <summary>Opaque handle for a registered variable. Used by Core for subscription routing.</summary>
|
||||
public interface IVariableHandle
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user