namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions; /// /// Streaming builder API a driver uses to register OPC UA nodes during discovery. /// Core owns the tree; driver streams AddFolder / AddVariable calls /// as it discovers nodes — no buffering of the whole tree. /// /// /// Per docs/v2/plan.md decision #52 — drivers register nodes via this builder /// rather than returning a tree object. Supports incremental / large address spaces /// without forcing the driver to buffer the whole tree. /// public interface IAddressSpaceBuilder { /// /// Add a folder node. Returns a child builder scoped to inside this folder, so subsequent /// calls on the child place nodes under it. /// /// OPC UA browse name (the segment of the path under the parent). /// Human-readable display name. May equal . IAddressSpaceBuilder Folder(string browseName, string displayName); /// /// Add a variable node corresponding to a tag. Driver-side full reference + data-type /// metadata come from the DTO. /// /// OPC UA browse name (the segment of the path under the parent folder). /// Human-readable display name. May equal . /// Driver-side metadata for the variable. IVariableHandle Variable(string browseName, string displayName, DriverAttributeInfo attributeInfo); /// /// Add a property to the current node (folder or variable). Properties are static metadata /// read once at build time (e.g. OPC 40010 Identification fields per the schemas-repo /// _base equipment-class template). /// void AddProperty(string browseName, DriverDataType dataType, object? value); /// /// 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 /// implementations. /// /// Metadata describing the type-definition node to mirror. /// /// /// The OPC UA Client driver is the primary caller — it walks i=86 /// (TypesFolder) during DiscoverAsync when /// OpcUaClientDriverOptions.MirrorTypeDefinitions is set so downstream clients /// see the upstream type system instead of rendering structured-type values as opaque /// strings. /// /// /// 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. /// /// void RegisterTypeNode(MirroredTypeNodeInfo info) { /* default: no-op */ } /// /// Register a method node mirrored from an upstream OPC UA server. The method is /// registered as a child of the current builder scope (i.e. the folder representing /// the upstream Object that owns the method). Optional surface — drivers that don't /// mirror methods simply never call it; address-space builders that don't materialise /// method nodes can leave the default no-op in place. Default implementation drops /// the call so adding this method doesn't break existing /// implementations. /// /// Metadata describing the method node, including input/output argument schemas. /// /// /// The OPC UA Client driver is the primary caller — it picks up /// NodeClass.Method nodes during the HierarchicalReferences browse /// pass, then walks each method's HasProperty references to harvest the /// InputArguments / OutputArguments property values. /// /// /// The OPC UA server-side DriverNodeManager overrides this to materialize /// a real MethodNode in the local address space and wire its /// OnCallMethod handler to the driver's /// . Other builders (Galaxy, Modbus, /// FOCAS, S7, TwinCAT, AB-CIP, AB-Legacy) ignore the projection because their /// backends don't expose method nodes. /// /// void RegisterMethodNode(MirroredMethodNodeInfo info) { /* default: no-op */ } } /// /// Metadata describing a single method node mirrored from an upstream OPC UA server. /// Built by the OPC UA Client driver during the discovery browse pass and consumed by /// . /// /// OPC UA BrowseName segment from the upstream BrowseName. /// Human-readable display name; falls back to . /// /// Stringified NodeId of the parent Object that owns this method — the ObjectId /// argument the dispatcher passes back to . /// /// /// Stringified NodeId of the method node itself — the MethodId argument. /// /// /// Declaration of the method's input arguments, in order. null or empty when the /// method takes no inputs (or the upstream property couldn't be read). /// /// /// Declaration of the method's output arguments, in order. null or empty when the /// method returns no outputs (or the upstream property couldn't be read). /// public sealed record MirroredMethodNodeInfo( string BrowseName, string DisplayName, string ObjectNodeId, string MethodNodeId, IReadOnlyList? InputArguments, IReadOnlyList? OutputArguments); /// /// One row of an OPC UA Argument array — name + data type + array hint. Mirrors the /// Opc.Ua.Argument structure but without the SDK-only types so this DTO can live /// in Core.Abstractions. /// /// Argument name from the upstream Argument structure. /// /// Mapped local . Unknown / structured upstream types fall /// through to — same convention as variable mirroring. /// /// /// OPC UA ValueRank: -1 = scalar, 0 = OneOrMoreDimensions, 1+ = array /// dimensions. Driven directly from the upstream Argument's ValueRank. /// /// /// Human-readable description from the upstream Argument structure; null when the /// upstream doesn't carry one. /// public sealed record MethodArgumentInfo( string Name, DriverDataType DriverDataType, int ValueRank, string? Description); /// /// Categorises a mirrored type-definition node so the receiving builder can route it into /// the right OPC UA standard subtree (ObjectTypesFolder, VariableTypesFolder, /// DataTypesFolder, ReferenceTypesFolder) when projecting upstream types into /// the local address space. /// public enum MirroredTypeKind { ObjectType, VariableType, DataType, ReferenceType, } /// /// 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 /// . /// /// Type category — drives which standard sub-folder the node lives under. /// /// Stringified upstream NodeId (e.g. "ns=2;i=1234") — 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. /// /// OPC UA BrowseName segment from the upstream BrowseName. /// Human-readable display name; falls back to . /// /// Stringified upstream NodeId of the super-type (parent type), or null when the node /// sits directly under the root (e.g. BaseObjectType, BaseVariableType). Lets /// the builder reconstruct the inheritance chain. /// /// /// true when the upstream node has the IsAbstract flag set (Object / Variable / /// ReferenceType). DataTypes also expose this — the driver passes it through verbatim. /// public sealed record MirroredTypeNodeInfo( MirroredTypeKind Kind, string UpstreamNodeId, string BrowseName, string DisplayName, string? SuperTypeNodeId, bool IsAbstract); /// Opaque handle for a registered variable. Used by Core for subscription routing. public interface IVariableHandle { /// Driver-side full reference for read/write addressing. string FullReference { get; } /// /// Annotate this variable with an OPC UA AlarmConditionState. Drivers with /// = true call this during discovery so the /// concrete address-space builder can materialize a sibling condition node. The returned /// sink receives lifecycle transitions raised through /// — the generic node manager wires the subscription; the concrete builder decides how /// to surface the state (e.g. OPC UA AlarmConditionState.Activate, /// Acknowledge, Deactivate). /// IAlarmConditionSink MarkAsAlarmCondition(AlarmConditionInfo info); } /// /// Metadata used to materialize an OPC UA AlarmConditionState sibling for a variable. /// Populated by the driver's discovery step; concrete builders decide how to surface it. /// /// Human-readable alarm name used for the SourceName event field. /// Severity at address-space build time; updates arrive via . /// Initial description; updates arrive via . public sealed record AlarmConditionInfo( string SourceName, AlarmSeverity InitialSeverity, string? InitialDescription); /// /// Sink a concrete address-space builder returns from . /// The generic node manager routes per-alarm payloads here — /// the sink translates the transition into an OPC UA condition state change or whatever the /// concrete builder's backing address space supports. /// public interface IAlarmConditionSink { /// Push an alarm transition (Active / Acknowledged / Inactive) for this condition. void OnTransition(AlarmEventArgs args); }