internal static async Task ReadNodeStateAsync()

in src/Azure.IIoT.OpcUa.Publisher/src/Stack/Extensions/SessionEx.cs [437:615]


        internal static async Task<ServiceResultModel?> ReadNodeStateAsync(
            this IOpcUaSession session, RequestHeader requestHeader, NodeState nodeState,
            NodeId rootId, RelativePath? relativePath = null, CancellationToken ct = default)
        {
            var valuesToRead = new List<ReadValueId>();
            var objectsToBrowse = new List<BrowseDescription>();
            var resolveBrowsePaths = session.GetBrowsePathFromNodeState(rootId,
                nodeState, relativePath);
            if (resolveBrowsePaths.Count == 0)
            {
                // Nothing to do
                return ((StatusCode)StatusCodes.GoodNoData).CreateResultModel();
            }
            var limits = await session.GetOperationLimitsAsync(ct).ConfigureAwait(false);
            var resolveBrowsePathsBatches = resolveBrowsePaths
                .Batch(limits.GetMaxNodesPerTranslatePathsToNodeIds());
            foreach (var batch in resolveBrowsePathsBatches)
            {
                // translate browse paths.
                var response = await session.Services.TranslateBrowsePathsToNodeIdsAsync(
                    requestHeader, new BrowsePathCollection(batch), ct).ConfigureAwait(false);
                var results = response.Validate(response.Results, s => s.StatusCode,
                    response.DiagnosticInfos, batch);
                if (results.ErrorInfo != null)
                {
                    return results.ErrorInfo;
                }
                foreach (var result in results)
                {
                    if (result.Request.Handle is not NodeState node)
                    {
                        continue;
                    }
                    if (StatusCode.IsBad(result.StatusCode))
                    {
                        if (result.StatusCode.Code is StatusCodes.BadNodeIdUnknown or
                            StatusCodes.BadUnexpectedError)
                        {
                            return result.ErrorInfo;
                        }
                        if (node is BaseVariableState v)
                        {
                            // Initialize the variable
                            v.Value = null;
                            v.StatusCode = result.StatusCode;
                        }
                        continue;
                    }
                    if (result.Result.Targets.Count == 1 &&
                        result.Result.Targets[0].RemainingPathIndex == uint.MaxValue &&
                        !result.Result.Targets[0].TargetId.IsAbsolute)
                    {
                        node.NodeId = (NodeId)result.Result.Targets[0].TargetId;
                    }
                    else
                    {
                        if (node is BaseVariableState v)
                        {
                            // Initialize the variable
                            v.Value = null;
                            v.StatusCode = StatusCodes.BadNotSupported;
                        }
                        continue;
                    }
                    switch (node)
                    {
                        case BaseVariableState variable:
                            // Initialize the variable
                            variable.Value = null;
                            variable.StatusCode = StatusCodes.BadNotSupported;
                            valuesToRead.Add(new ReadValueId
                            {
                                NodeId = node.NodeId,
                                AttributeId = Attributes.Value,
                                Handle = node
                            });
                            break;
                        case FolderState folder:
                            // Save for browsing
                            objectsToBrowse.Add(new BrowseDescription
                            {
                                BrowseDirection = Opc.Ua.BrowseDirection.Forward,
                                Handle = folder,
                                IncludeSubtypes = true,
                                ReferenceTypeId = ReferenceTypeIds.Organizes,
                                NodeClassMask =
                                    (uint)Opc.Ua.NodeClass.Variable |
                                    (uint)Opc.Ua.NodeClass.Object,
                                NodeId = node.NodeId,
                                ResultMask = (uint)BrowseResultMask.All
                            });
                            break;
                    }
                }
            }

            if (objectsToBrowse.Count > 0)
            {
                foreach (var batch in objectsToBrowse.Batch(limits.GetMaxNodesPerBrowse()))
                {
                    // Browse folders with objects and variables in it
                    await foreach (var (description, references, errorInfo) in session.BrowseAsync(
                        requestHeader, null, new BrowseDescriptionCollection(batch),
                        ct).ConfigureAwait(false))
                    {
                        var obj = (BaseObjectState?)description?.Handle;
                        if (obj == null || references == null)
                        {
                            continue;
                        }
                        foreach (var reference in references)
                        {
                            switch (reference.NodeClass)
                            {
                                case Opc.Ua.NodeClass.Variable:
                                    // Add variable to the folder and set it to be read.
                                    var variable = new BaseDataVariableState(obj)
                                    {
                                        NodeId = (NodeId)reference.NodeId,
                                        BrowseName = reference.BrowseName,
                                        DisplayName = reference.DisplayName,
                                        StatusCode = StatusCodes.BadNotSupported,
                                        ReferenceTypeId = reference.ReferenceTypeId,
                                        Value = null
                                    };
                                    obj.AddChild(variable);
                                    valuesToRead.Add(new ReadValueId
                                    {
                                        NodeId = variable.NodeId,
                                        AttributeId = Attributes.Value,
                                        Handle = variable
                                    });
                                    break;
                                case Opc.Ua.NodeClass.Object:
                                    // Add object
#pragma warning disable CA2000 // Dispose objects before losing scope
                                    var child = new BaseObjectState(obj)
                                    {
                                        NodeId = (NodeId)reference.NodeId,
                                        BrowseName = reference.BrowseName,
                                        DisplayName = reference.DisplayName,
                                        ReferenceTypeId = reference.ReferenceTypeId
                                    };
#pragma warning restore CA2000 // Dispose objects before losing scope
                                    obj.AddChild(child);
                                    break;
                            }
                        }
                    }
                }
            }

            if (valuesToRead.Count > 0)
            {
                foreach (var batch in valuesToRead.Batch(limits.GetMaxNodesPerRead()))
                {
                    // read the values.
                    var readResponse = await session.Services.ReadAsync(
                        requestHeader, 0, Opc.Ua.TimestampsToReturn.Neither,
                        new ReadValueIdCollection(batch), ct).ConfigureAwait(false);
                    var readResults = readResponse.Validate(readResponse.Results,
                        s => s.StatusCode, readResponse.DiagnosticInfos,
                        batch);
                    if (readResults.ErrorInfo != null)
                    {
                        return readResults.ErrorInfo;
                    }
                    foreach (var readResult in readResults)
                    {
                        var variable = (BaseVariableState)readResult.Request.Handle;
                        variable.WrappedValue = readResult.Result.WrappedValue;
                        variable.DataType = TypeInfo.GetDataTypeId(readResult.Result.Value);
                        variable.StatusCode = readResult.Result.StatusCode;
                    }
                }
                return null;
            }
            return ((StatusCode)StatusCodes.BadUnexpectedError).CreateResultModel();
        }