Commit 1eebe28f authored by Denis Štogl's avatar Denis Štogl

Server side deleting of nodes.

parent 2374dd32
import sys
sys.path.insert(0, "..")
import logging
import time
try:
from IPython import embed
except ImportError:
import code
def embed():
vars = globals()
vars.update(locals())
shell = code.InteractiveConsole(vars)
shell.interact()
from opcua import Client
from opcua import ua
class SubHandler(object):
"""
Subscription Handler. To receive events from server for a subscription
data_change and event methods are called directly from receiving thread.
Do not do expensive, slow or network operation there. Create another
thread if you need to do such a thing
"""
def datachange_notification(self, node, val, data):
print("Python: New data change event", node, val)
def event_notification(self, event):
print("Python: New event", event)
if __name__ == "__main__":
logging.basicConfig(level=logging.WARN)
#logger = logging.getLogger("KeepAlive")
#logger.setLevel(logging.DEBUG)
#client = Client("opc.tcp://localhost:4840/freeopcua/server/")
client = Client("opc.tcp://admin@localhost:4840/freeopcua/server/") #connect using a user
try:
client.connect()
# Client has a few methods to get proxy to UA nodes that should always be in address space such as Root or Objects
root = client.get_root_node()
print("Root node is: ", root)
objects = client.get_objects_node()
print("Objects node is: ", objects)
# Node objects have methods to read and write node attributes as well as browse or populate address space
print("Children of root are: ", root.get_children())
# get a specific node knowing its node id
#var = client.get_node(ua.NodeId(1002, 2))
#var = client.get_node("ns=3;i=2002")
#print(var)
#var.get_data_value() # get value of node as a DataValue object
#var.get_value() # get value of node as a python builtin
#var.set_value(ua.Variant([23], ua.VariantType.Int64)) #set node value using explicit data type
#var.set_value(3.9) # set node value using implicit data type
# Now getting a variable node using its browse path
myvar = root.get_child(["0:Objects", "2:MyObject", "2:MyVariable"])
obj = root.get_child(["0:Objects", "2:MyObject"])
print("myvar is: ", myvar)
# subscribing to a variable node
handler = SubHandler()
sub = client.create_subscription(500, handler)
handle = sub.subscribe_data_change(myvar)
time.sleep(0.1)
# we can also subscribe to events from server
sub.subscribe_events()
# sub.unsubscribe(handle)
# sub.delete()
# calling a method on server
res = obj.call_method("2:multiply", 3, "klk")
print("method result is: ", res)
print("Children of MyObject are: ", obj.get_children())
print("myvar should be still there")
obj.delete_child(["2:MyVariable"])
print("Children of MyObject are: ", obj.get_children())
print("myvar should disapear")
embed()
finally:
client.disconnect()
...@@ -423,13 +423,13 @@ class BinaryClient(object): ...@@ -423,13 +423,13 @@ class BinaryClient(object):
response = ua.AddNodesResponse.from_binary(data) response = ua.AddNodesResponse.from_binary(data)
response.ResponseHeader.ServiceResult.check() response.ResponseHeader.ServiceResult.check()
return response.Results return response.Results
def delete_nodes(self, nodestodelete): def delete_nodes(self, nodestodelete):
self.logger.info("delete_nodes") self.logger.info("delete_nodes")
request = ua.DeleteNodesRequest() request = ua.DeleteNodesRequest()
request.Parameters.NodesToDelete = nodestodelete request.Parameters.NodesToDelete = nodestodelete
data = self._uasocket.send_request(request) data = self._uasocket.send_request(request)
response = ua.AddNodesResponse.from_binary(data) response = ua.DeleteNodesResponse.from_binary(data)
response.ResponseHeader.ServiceResult.check() response.ResponseHeader.ServiceResult.check()
return response.Results return response.Results
......
...@@ -285,7 +285,7 @@ class Client(object): ...@@ -285,7 +285,7 @@ class Client(object):
uris = [] uris = []
params = ua.FindServersParameters() params = ua.FindServersParameters()
params.EndpointUrl = self.server_url.geturl() params.EndpointUrl = self.server_url.geturl()
params.ServerUris = uris params.ServerUris = uris
return self.bclient.find_servers(params) return self.bclient.find_servers(params)
def find_servers_on_network(self): def find_servers_on_network(self):
...@@ -357,7 +357,7 @@ class Client(object): ...@@ -357,7 +357,7 @@ class Client(object):
params.UserTokenSignature.Signature = sig params.UserTokenSignature.Signature = sig
else: else:
params.UserIdentityToken = ua.UserNameIdentityToken() params.UserIdentityToken = ua.UserNameIdentityToken()
params.UserIdentityToken.UserName = username params.UserIdentityToken.UserName = username
if self.server_url.password: if self.server_url.password:
pubkey = uacrypto.x509_from_der(self.security_policy.server_certificate).public_key() pubkey = uacrypto.x509_from_der(self.security_policy.server_certificate).public_key()
# see specs part 4, 7.36.3: if the token is encrypted, password # see specs part 4, 7.36.3: if the token is encrypted, password
...@@ -401,7 +401,7 @@ class Client(object): ...@@ -401,7 +401,7 @@ class Client(object):
handler argument is a class with data_change and/or event methods. handler argument is a class with data_change and/or event methods.
These methods will be called when notfication from server are received. These methods will be called when notfication from server are received.
See example-client.py. See example-client.py.
Do not do expensive/slow or network operation from these methods Do not do expensive/slow or network operation from these methods
since they are called directly from receiving thread. This is a design choice, since they are called directly from receiving thread. This is a design choice,
start another thread if you need to do such a thing. start another thread if you need to do such a thing.
""" """
......
...@@ -254,6 +254,9 @@ class Node(object): ...@@ -254,6 +254,9 @@ class Node(object):
# FIXME: seems this method may return several nodes # FIXME: seems this method may return several nodes
return Node(self.server, result.Targets[0].TargetId) return Node(self.server, result.Targets[0].TargetId)
def delete_child(self, path):
self.delete_node(self.get_child(path).nodeid)
def read_raw_history(self, starttime=None, endtime=None, numvalues=0, returnbounds=True): def read_raw_history(self, starttime=None, endtime=None, numvalues=0, returnbounds=True):
""" """
Read raw history of a node Read raw history of a node
...@@ -288,7 +291,7 @@ class Node(object): ...@@ -288,7 +291,7 @@ class Node(object):
# Hack for convenience methods # Hack for convenience methods
# local import is ugly but necessary for python2 support # local import is ugly but necessary for python2 support
# feel fri to propose something better but I want to split all those # feel fri to propose something better but I want to split all those
# create methods fro Node # create methods fro Node
def add_folder(*args, **kwargs): def add_folder(*args, **kwargs):
...@@ -315,3 +318,9 @@ class Node(object): ...@@ -315,3 +318,9 @@ class Node(object):
from opcua.common import methods from opcua.common import methods
return methods.call_method(*args, **kwargs) return methods.call_method(*args, **kwargs)
def delete_node(self, nodeid, deleterefs=True):
deletenode = ua.DeleteNodesItem()
deletenode.NodeId = nodeid
deletenode.DeleteTargetReferences = deleterefs
results = self.server.delete_nodes([deletenode])
results[0].check()
...@@ -181,7 +181,7 @@ class NodeManagementService(object): ...@@ -181,7 +181,7 @@ class NodeManagementService(object):
result = ua.AddNodesResult() result = ua.AddNodesResult()
if item.RequestedNewNodeId in self._aspace: if item.RequestedNewNodeId in self._aspace:
self.logger.warning("AddNodeItem: node already exists") self.logger.warning("AddNodesItem: node already exists")
result.StatusCode = ua.StatusCode(ua.StatusCodes.BadNodeIdExists) result.StatusCode = ua.StatusCode(ua.StatusCodes.BadNodeIdExists)
return result return result
nodedata = NodeData(item.RequestedNewNodeId) nodedata = NodeData(item.RequestedNewNodeId)
...@@ -233,6 +233,32 @@ class NodeManagementService(object): ...@@ -233,6 +233,32 @@ class NodeManagementService(object):
return result return result
def delete_nodes(self, deletenodeitems, user=User.Admin):
results = []
for item in deletenodeitems:
results.append(self._delete_node(item, user))
return results
def _delete_node(self, item, user):
#TODO: Check if node is monitored if it is: "When any of the Nodes deleted by an invocation of this Service is being monitored, then a Notification containing the status code Bad_NodeIdUnknown is sent to the monitoring Client indicating that the Node has been deleted."
if not user == User.Admin:
return ua.StatusCode(ua.StatusCodes.BadUserAccessDenied)
if item.NodeId not in self._aspace:
self.logger.warning("DeleteNodesItem: node does not exists")
return ua.StatusCode(ua.StatusCodes.BadNodeIdUnknown)
if item.DeleteTargetReferences:
for elem in self._aspace.keys():
for rdesc in self._aspace[elem].references:
if rdesc.NodeId == item.NodeId:
self._aspace[elem].references.remove(rdesc)
print self._aspace[item.NodeId]
del self._aspace[item.NodeId]
return ua.StatusCode()
def add_references(self, refs, user=User.Admin): def add_references(self, refs, user=User.Admin):
result = [] result = []
for ref in refs: for ref in refs:
...@@ -260,6 +286,36 @@ class NodeManagementService(object): ...@@ -260,6 +286,36 @@ class NodeManagementService(object):
self._aspace[addref.SourceNodeId].references.append(rdesc) self._aspace[addref.SourceNodeId].references.append(rdesc)
return ua.StatusCode() return ua.StatusCode()
def delete_references(self, refs, user=User.Admin):
result = []
for ref in refs:
result.append(self._delete_reference(ref, user))
return result
def _delete_reference(self, item, user):
if item.SourceNodeId not in self._aspace:
return ua.StatusCode(ua.StatusCodes.BadSourceNodeIdInvalid)
if item.TargetNodeId not in self._aspace:
return ua.StatusCode(ua.StatusCodes.BadTargetNodeIdInvalid)
if not user == User.Admin:
return ua.StatusCode(ua.StatusCodes.BadUserAccessDenied)
for rdesc in self._aspace[item.SourceNodeId].references:
if rdesc.NodeId is item.TargetNodeId:
if rdesc.RefrenceTypeId != item.RefrenceTypeId:
return ua.StatusCode(ua.StatusCode.BadReferenceTypeInvalid)
if rdesc.IsForward == item.IsForward or item.DeleteBidirectional:
self._aspace[item.SourceNodeId].references.remove(rdesc)
for rdesc in self._aspace[item.TargetNodeId].references:
if rdesc.NodeId is item.SourceNodeId:
if rdesc.RefrenceTypeId != item.RefrenceTypeId:
return ua.StatusCode(ua.StatusCode.BadReferenceTypeInvalid)
if rdesc.IsForward == item.IsForward or item.DeleteBidirectional:
self._aspace[item.SourceNodeId].references.remove(rdesc)
return ua.StatusCode()
def _add_node_attr(self, item, nodedata, name, vtype=None): def _add_node_attr(self, item, nodedata, name, vtype=None):
if item.SpecifiedAttributes & getattr(ua.NodeAttributesMask, name): if item.SpecifiedAttributes & getattr(ua.NodeAttributesMask, name):
dv = ua.DataValue(ua.Variant(getattr(item, name), vtype)) dv = ua.DataValue(ua.Variant(getattr(item, name), vtype))
...@@ -351,6 +407,14 @@ class AddressSpace(object): ...@@ -351,6 +407,14 @@ class AddressSpace(object):
with self._lock: with self._lock:
return self._nodes.__contains__(nodeid) return self._nodes.__contains__(nodeid)
def __delitem__(self, nodeid):
with self._lock:
self._nodes.__delitem__(nodeid)
def keys(self):
with self._lock:
return self._nodes.keys()
def dump(self, path): def dump(self, path):
""" """
dump address space as binary to file dump address space as binary to file
......
...@@ -55,9 +55,9 @@ class InternalServer(object): ...@@ -55,9 +55,9 @@ class InternalServer(object):
self.method_service = MethodService(self.aspace) self.method_service = MethodService(self.aspace)
self.node_mgt_service = NodeManagementService(self.aspace) self.node_mgt_service = NodeManagementService(self.aspace)
# import address space from code generated from xml # import address space from code generated from xml
standard_address_space.fill_address_space(self.node_mgt_service) standard_address_space.fill_address_space(self.node_mgt_service)
# import address space from save db to disc # import address space from save db to disc
#standard_address_space.fill_address_space_from_disk(self.aspace) #standard_address_space.fill_address_space_from_disk(self.aspace)
# import address space directly from xml, this has preformance impact so disabled # import address space directly from xml, this has preformance impact so disabled
#importer = xmlimporter.XmlImporter(self.node_mgt_service) #importer = xmlimporter.XmlImporter(self.node_mgt_service)
...@@ -120,7 +120,7 @@ class InternalServer(object): ...@@ -120,7 +120,7 @@ class InternalServer(object):
def find_servers(self, params): def find_servers(self, params):
if not params.ServerUris: if not params.ServerUris:
return [desc.Server for desc in self._known_servers.values()] return [desc.Server for desc in self._known_servers.values()]
servers = [] servers = []
for serv in self._known_servers.values(): for serv in self._known_servers.values():
serv_uri = serv.Server.ApplicationUri.split(":") serv_uri = serv.Server.ApplicationUri.split(":")
...@@ -215,8 +215,8 @@ class InternalSession(object): ...@@ -215,8 +215,8 @@ class InternalSession(object):
return self.iserver.attribute_service.read(params) return self.iserver.attribute_service.read(params)
def write(self, params): def write(self, params):
if not self.external: if not self.external:
# If session is internal we need to store a copy og object, not a reference, # If session is internal we need to store a copy og object, not a reference,
#otherwise users may change it and we will not generate expected events #otherwise users may change it and we will not generate expected events
for ntw in params.NodesToWrite: for ntw in params.NodesToWrite:
ntw.Value.Value.Value = copy(ntw.Value.Value.Value) ntw.Value.Value.Value = copy(ntw.Value.Value.Value)
...@@ -231,9 +231,15 @@ class InternalSession(object): ...@@ -231,9 +231,15 @@ class InternalSession(object):
def add_nodes(self, params): def add_nodes(self, params):
return self.iserver.node_mgt_service.add_nodes(params, self.user) return self.iserver.node_mgt_service.add_nodes(params, self.user)
def delete_nodes(self, params):
return self.iserver.node_mgt_service.delete_nodes(params, self.user)
def add_references(self, params): def add_references(self, params):
return self.iserver.node_mgt_service.add_references(params, self.user) return self.iserver.node_mgt_service.add_references(params, self.user)
def delete_references(self, params):
return self.iserver.node_mgt_service.delete_references(params, self.user)
def add_method_callback(self, methodid, callback): def add_method_callback(self, methodid, callback):
return self.aspace.add_method_callback(methodid, callback) return self.aspace.add_method_callback(methodid, callback)
......
...@@ -256,6 +256,18 @@ class UAProcessor(object): ...@@ -256,6 +256,18 @@ class UAProcessor(object):
self.logger.info("sending add node response") self.logger.info("sending add node response")
self.send_response(requesthdr.RequestHandle, algohdr, seqhdr, response) self.send_response(requesthdr.RequestHandle, algohdr, seqhdr, response)
elif typeid == ua.NodeId(ua.ObjectIds.DeleteNodesRequest_Encoding_DefaultBinary):
self.logger.info("delete nodes request")
params = ua.DeleteNodesParameters.from_binary(body)
results = self.session.delete_nodes(params.NodesToDelete)
response = ua.DeleteNodesResponse()
response.Results = results
self.logger.info("sending delete node response")
self.send_response(requesthdr.RequestHandle, algohdr, seqhdr, response)
elif typeid == ua.NodeId(ua.ObjectIds.CreateSubscriptionRequest_Encoding_DefaultBinary): elif typeid == ua.NodeId(ua.ObjectIds.CreateSubscriptionRequest_Encoding_DefaultBinary):
self.logger.info("create subscription request") self.logger.info("create subscription request")
params = ua.CreateSubscriptionParameters.from_binary(body) params = ua.CreateSubscriptionParameters.from_binary(body)
......
...@@ -801,19 +801,19 @@ class DiagnosticInfo(FrozenClass): ...@@ -801,19 +801,19 @@ class DiagnosticInfo(FrozenClass):
if self.InnerStatusCode: self.Encoding |= (1 << 5) if self.InnerStatusCode: self.Encoding |= (1 << 5)
if self.InnerDiagnosticInfo: self.Encoding |= (1 << 6) if self.InnerDiagnosticInfo: self.Encoding |= (1 << 6)
packet.append(uatype_UInt8.pack(self.Encoding)) packet.append(uatype_UInt8.pack(self.Encoding))
if self.SymbolicId: if self.SymbolicId:
packet.append(uatype_Int32.pack(self.SymbolicId)) packet.append(uatype_Int32.pack(self.SymbolicId))
if self.NamespaceURI: if self.NamespaceURI:
packet.append(uatype_Int32.pack(self.NamespaceURI)) packet.append(uatype_Int32.pack(self.NamespaceURI))
if self.Locale: if self.Locale:
packet.append(uatype_Int32.pack(self.Locale)) packet.append(uatype_Int32.pack(self.Locale))
if self.LocalizedText: if self.LocalizedText:
packet.append(uatype_Int32.pack(self.LocalizedText)) packet.append(uatype_Int32.pack(self.LocalizedText))
if self.AdditionalInfo: if self.AdditionalInfo:
packet.append(pack_bytes(self.AdditionalInfo)) packet.append(pack_bytes(self.AdditionalInfo))
if self.InnerStatusCode: if self.InnerStatusCode:
packet.append(self.InnerStatusCode.to_binary()) packet.append(self.InnerStatusCode.to_binary())
if self.InnerDiagnosticInfo: if self.InnerDiagnosticInfo:
packet.append(self.InnerDiagnosticInfo.to_binary()) packet.append(self.InnerDiagnosticInfo.to_binary())
return b''.join(packet) return b''.join(packet)
...@@ -4971,8 +4971,14 @@ class DeleteNodesRequest(FrozenClass): ...@@ -4971,8 +4971,14 @@ class DeleteNodesRequest(FrozenClass):
__repr__ = __str__ __repr__ = __str__
class DeleteNodesResult(FrozenClass): class DeleteNodesResponse(FrozenClass):
''' '''
Delete one or more nodes from the server address space.
:ivar TypeId:
:vartype TypeId: NodeId
:ivar ResponseHeader:
:vartype ResponseHeader: ResponseHeader
:ivar Results: :ivar Results:
:vartype Results: StatusCode :vartype Results: StatusCode
:ivar DiagnosticInfos: :ivar DiagnosticInfos:
...@@ -4983,12 +4989,16 @@ class DeleteNodesResult(FrozenClass): ...@@ -4983,12 +4989,16 @@ class DeleteNodesResult(FrozenClass):
self._binary_init(binary) self._binary_init(binary)
self._freeze = True self._freeze = True
return return
self.TypeId = FourByteNodeId(ObjectIds.DeleteNodesResponse_Encoding_DefaultBinary)
self.ResponseHeader = ResponseHeader()
self.Results = [] self.Results = []
self.DiagnosticInfos = [] self.DiagnosticInfos = []
self._freeze = True self._freeze = True
def to_binary(self): def to_binary(self):
packet = [] packet = []
packet.append(self.TypeId.to_binary())
packet.append(self.ResponseHeader.to_binary())
packet.append(uatype_Int32.pack(len(self.Results))) packet.append(uatype_Int32.pack(len(self.Results)))
for fieldname in self.Results: for fieldname in self.Results:
packet.append(fieldname.to_binary()) packet.append(fieldname.to_binary())
...@@ -4999,9 +5009,11 @@ class DeleteNodesResult(FrozenClass): ...@@ -4999,9 +5009,11 @@ class DeleteNodesResult(FrozenClass):
@staticmethod @staticmethod
def from_binary(data): def from_binary(data):
return DeleteNodesResult(data) return DeleteNodesResponse(data)
def _binary_init(self, data): def _binary_init(self, data):
self.TypeId = NodeId.from_binary(data)
self.ResponseHeader = ResponseHeader.from_binary(data)
length = uatype_Int32.unpack(data.read(4))[0] length = uatype_Int32.unpack(data.read(4))[0]
array = [] array = []
if length != -1: if length != -1:
...@@ -5015,54 +5027,11 @@ class DeleteNodesResult(FrozenClass): ...@@ -5015,54 +5027,11 @@ class DeleteNodesResult(FrozenClass):
array.append(DiagnosticInfo.from_binary(data)) array.append(DiagnosticInfo.from_binary(data))
self.DiagnosticInfos = array self.DiagnosticInfos = array
def __str__(self):
return 'DeleteNodesResult(' + 'Results:' + str(self.Results) + ', ' + \
'DiagnosticInfos:' + str(self.DiagnosticInfos) + ')'
__repr__ = __str__
class DeleteNodesResponse(FrozenClass):
'''
Delete one or more nodes from the server address space.
:ivar TypeId:
:vartype TypeId: NodeId
:ivar ResponseHeader:
:vartype ResponseHeader: ResponseHeader
:ivar Parameters:
:vartype Parameters: DeleteNodesResult
'''
def __init__(self, binary=None):
if binary is not None:
self._binary_init(binary)
self._freeze = True
return
self.TypeId = FourByteNodeId(ObjectIds.DeleteNodesResponse_Encoding_DefaultBinary)
self.ResponseHeader = ResponseHeader()
self.Parameters = DeleteNodesResult()
self._freeze = True
def to_binary(self):
packet = []
packet.append(self.TypeId.to_binary())
packet.append(self.ResponseHeader.to_binary())
packet.append(self.Parameters.to_binary())
return b''.join(packet)
@staticmethod
def from_binary(data):
return DeleteNodesResponse(data)
def _binary_init(self, data):
self.TypeId = NodeId.from_binary(data)
self.ResponseHeader = ResponseHeader.from_binary(data)
self.Parameters = DeleteNodesResult.from_binary(data)
def __str__(self): def __str__(self):
return 'DeleteNodesResponse(' + 'TypeId:' + str(self.TypeId) + ', ' + \ return 'DeleteNodesResponse(' + 'TypeId:' + str(self.TypeId) + ', ' + \
'ResponseHeader:' + str(self.ResponseHeader) + ', ' + \ 'ResponseHeader:' + str(self.ResponseHeader) + ', ' + \
'Parameters:' + str(self.Parameters) + ')' 'Results:' + str(self.Results) + ', ' + \
'DiagnosticInfos:' + str(self.DiagnosticInfos) + ')'
__repr__ = __str__ __repr__ = __str__
......
...@@ -11,10 +11,10 @@ import xml.etree.ElementTree as ET ...@@ -11,10 +11,10 @@ import xml.etree.ElementTree as ET
NeedOverride = [] NeedOverride = []
NeedConstructor = []#["RelativePathElement", "ReadValueId", "OpenSecureChannelParameters", "UserIdentityToken", "RequestHeader", "ResponseHeader", "ReadParameters", "UserIdentityToken", "BrowseDescription", "ReferenceDescription", "CreateSubscriptionParameters", "PublishResult", "NotificationMessage", "SetPublishingModeParameters"] NeedConstructor = []#["RelativePathElement", "ReadValueId", "OpenSecureChannelParameters", "UserIdentityToken", "RequestHeader", "ResponseHeader", "ReadParameters", "UserIdentityToken", "BrowseDescription", "ReferenceDescription", "CreateSubscriptionParameters", "PublishResult", "NotificationMessage", "SetPublishingModeParameters"]
IgnoredEnums = []#["IdType", "NodeIdType"] IgnoredEnums = []#["IdType", "NodeIdType"]
#we want to implement som struct by hand, to make better interface or simply because they are too complicated #we want to implement som struct by hand, to make better interface or simply because they are too complicated
IgnoredStructs = []#["NodeId", "ExpandedNodeId", "Variant", "QualifiedName", "DataValue", "LocalizedText"]#, "ExtensionObject"] IgnoredStructs = []#["NodeId", "ExpandedNodeId", "Variant", "QualifiedName", "DataValue", "LocalizedText"]#, "ExtensionObject"]
#by default we split requests and respons in header and parameters, but some are so simple we do not split them #by default we split requests and respons in header and parameters, but some are so simple we do not split them
NoSplitStruct = ["GetEndpointsResponse", "CloseSessionRequest", "AddNodesResponse", "BrowseResponse", "HistoryReadResponse", "HistoryUpdateResponse", "RegisterServerResponse", "CloseSecureChannelRequest", "CloseSecureChannelResponse", "CloseSessionRequest", "CloseSessionResponse", "UnregisterNodesResponse", "MonitoredItemModifyRequest", "MonitoredItemsCreateRequest", "ReadResponse", "WriteResponse", "TranslateBrowsePathsToNodeIdsResponse", "DeleteSubscriptionsResponse", "DeleteMonitoredItemsResponse", "CreateMonitoredItemsResponse", "ServiceFault", "AddReferencesRequest", "AddReferencesResponse", "ModifyMonitoredItemsResponse", "RepublishResponse", "CallResponse", "FindServersResponse", "RegisterServerRequest", "RegisterServer2Response"] NoSplitStruct = ["GetEndpointsResponse", "CloseSessionRequest", "AddNodesResponse", "DeleteNodesResponse", "BrowseResponse", "HistoryReadResponse", "HistoryUpdateResponse", "RegisterServerResponse", "CloseSecureChannelRequest", "CloseSecureChannelResponse", "CloseSessionRequest", "CloseSessionResponse", "UnregisterNodesResponse", "MonitoredItemModifyRequest", "MonitoredItemsCreateRequest", "ReadResponse", "WriteResponse", "TranslateBrowsePathsToNodeIdsResponse", "DeleteSubscriptionsResponse", "DeleteMonitoredItemsResponse", "CreateMonitoredItemsResponse", "ServiceFault", "AddReferencesRequest", "AddReferencesResponse", "ModifyMonitoredItemsResponse", "RepublishResponse", "CallResponse", "FindServersResponse", "RegisterServerRequest", "RegisterServer2Response"]
#structs that end with Request or Response but are not #structs that end with Request or Response but are not
NotRequest = ["MonitoredItemCreateRequest", "MonitoredItemModifyRequest", "CallMethodRequest"] NotRequest = ["MonitoredItemCreateRequest", "MonitoredItemModifyRequest", "CallMethodRequest"]
OverrideTypes = {}#AttributeId": "AttributeID", "ResultMask": "BrowseResultMask", "NodeClassMask": "NodeClass", "AccessLevel": "VariableAccessLevel", "UserAccessLevel": "VariableAccessLevel", "NotificationData": "NotificationData"} OverrideTypes = {}#AttributeId": "AttributeID", "ResultMask": "BrowseResultMask", "NodeClassMask": "NodeClass", "AccessLevel": "VariableAccessLevel", "UserAccessLevel": "VariableAccessLevel", "NotificationData": "NotificationData"}
...@@ -54,7 +54,7 @@ class Struct(object): ...@@ -54,7 +54,7 @@ class Struct(object):
if f.name == name: if f.name == name:
return f return f
raise Exception("field not found: " + name) raise Exception("field not found: " + name)
def __str__(self): def __str__(self):
return "Struct {}:{}".format(self.name, self.basetype) return "Struct {}:{}".format(self.name, self.basetype)
...@@ -69,7 +69,7 @@ class Field(object): ...@@ -69,7 +69,7 @@ class Field(object):
self.sourcetype = None self.sourcetype = None
self.switchfield = None self.switchfield = None
self.switchvalue = None self.switchvalue = None
self.bitlength = 1 self.bitlength = 1
def __str__(self): def __str__(self):
return "Field {}({})".format(self.name, self.uatype) return "Field {}({})".format(self.name, self.uatype)
...@@ -213,7 +213,7 @@ def remove_duplicates(model): ...@@ -213,7 +213,7 @@ def remove_duplicates(model):
names.append(field.name) names.append(field.name)
fields.append(field) fields.append(field)
struct.fields = fields struct.fields = fields
def add_encoding_field(model): def add_encoding_field(model):
for struct in model.structs: for struct in model.structs:
newfields = [] newfields = []
...@@ -226,7 +226,7 @@ def add_encoding_field(model): ...@@ -226,7 +226,7 @@ def add_encoding_field(model):
b.name = field.name b.name = field.name
b.idx = 0 b.idx = 0
b.container = container b.container = container
b.length = 6 b.length = 6
idx = b.length idx = b.length
struct.bits[b.name] = b struct.bits[b.name] = b
...@@ -299,10 +299,10 @@ def split_requests(model): ...@@ -299,10 +299,10 @@ def split_requests(model):
paramstruct = Struct() paramstruct = Struct()
if structtype == "Request": if structtype == "Request":
basename = struct.name.replace("Request", "") + "Parameters" basename = struct.name.replace("Request", "") + "Parameters"
paramstruct.name = basename paramstruct.name = basename
else: else:
basename = struct.name.replace("Response", "") + "Result" basename = struct.name.replace("Response", "") + "Result"
paramstruct.name = basename paramstruct.name = basename
paramstruct.fields = struct.fields[2:] paramstruct.fields = struct.fields[2:]
paramstruct.bits = struct.bits paramstruct.bits = struct.bits
...@@ -311,8 +311,8 @@ def split_requests(model): ...@@ -311,8 +311,8 @@ def split_requests(model):
structs.append(paramstruct) structs.append(paramstruct)
typeid = Field() typeid = Field()
typeid.name = "Parameters" typeid.name = "Parameters"
typeid.uatype = paramstruct.name typeid.uatype = paramstruct.name
struct.fields.append(typeid) struct.fields.append(typeid)
structs.append(struct) structs.append(struct)
model.structs = structs model.structs = structs
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment