| 68 | |
| 69 | |
| 70 | class ViewService(object): |
| 71 | |
| 72 | def __init__(self, aspace): |
| 73 | self.logger = logging.getLogger(__name__) |
| 74 | self._aspace = aspace |
| 75 | |
| 76 | def browse(self, params): |
| 77 | self.logger.debug("browse %s", params) |
| 78 | res = [] |
| 79 | for desc in params.NodesToBrowse: |
| 80 | res.append(self._browse(desc)) |
| 81 | return res |
| 82 | |
| 83 | def _browse(self, desc): |
| 84 | res = ua.BrowseResult() |
| 85 | if desc.NodeId not in self._aspace: |
| 86 | res.StatusCode = ua.StatusCode(ua.StatusCodes.BadNodeIdInvalid) |
| 87 | return res |
| 88 | node = self._aspace[desc.NodeId] |
| 89 | for ref in node.references: |
| 90 | if not self._is_suitable_ref(desc, ref): |
| 91 | continue |
| 92 | res.References.append(ref) |
| 93 | return res |
| 94 | |
| 95 | def _is_suitable_ref(self, desc, ref): |
| 96 | if not self._suitable_direction(desc.BrowseDirection, ref.IsForward): |
| 97 | self.logger.debug("%s is not suitable due to direction", ref) |
| 98 | return False |
| 99 | if not self._suitable_reftype(desc.ReferenceTypeId, ref.ReferenceTypeId, desc.IncludeSubtypes): |
| 100 | self.logger.debug("%s is not suitable due to type", ref) |
| 101 | return False |
| 102 | if desc.NodeClassMask and ((desc.NodeClassMask & ref.NodeClass) == 0): |
| 103 | self.logger.debug("%s is not suitable due to class", ref) |
| 104 | return False |
| 105 | self.logger.debug("%s is a suitable ref for desc %s", ref, desc) |
| 106 | return True |
| 107 | |
| 108 | def _suitable_reftype(self, ref1, ref2, subtypes): |
| 109 | """ |
| 110 | """ |
| 111 | if ref1 == ua.NodeId(ua.ObjectIds.Null): |
| 112 | # If ReferenceTypeId is not specified in the BrowseDescription, |
| 113 | # all References are returned and includeSubtypes is ignored. |
| 114 | return True |
| 115 | if not subtypes and ref2.Identifier == ua.ObjectIds.HasSubtype: |
| 116 | return False |
| 117 | if ref1.Identifier == ref2.Identifier: |
| 118 | return True |
| 119 | oktypes = self._get_sub_ref(ref1) |
| 120 | if not subtypes and ua.NodeId(ua.ObjectIds.HasSubtype) in oktypes: |
| 121 | oktypes.remove(ua.NodeId(ua.ObjectIds.HasSubtype)) |
| 122 | return ref2 in oktypes |
| 123 | |
| 124 | def _get_sub_ref(self, ref): |
| 125 | res = [] |
| 126 | nodedata = self._aspace[ref] |
| 127 | if nodedata is not None: |