1
0
mirror of https://github.com/JoelBender/bacpypes synced 2025-09-28 22:15:23 +08:00

simplify the error handling and update the API

This commit is contained in:
Joel Bender 2016-08-27 18:51:25 -04:00
parent 40a9a7892d
commit 2b00378904
2 changed files with 82 additions and 116 deletions

View File

@ -29,6 +29,7 @@ __email__ = 'joel@carrickbender.com'
from . import comm from . import comm
from . import task from . import task
from . import singleton from . import singleton
from . import capability
# #
# Link Layer Modules # Link Layer Modules

View File

@ -24,6 +24,8 @@ class LocalRecordAccessFileObject(FileObject):
if 'fileAccessMethod' in kwargs: if 'fileAccessMethod' in kwargs:
if kwargs['fileAccessMethod'] != 'recordAccess': if kwargs['fileAccessMethod'] != 'recordAccess':
raise ValueError("inconsistent file access method") raise ValueError("inconsistent file access method")
else:
kwargs['fileAccessMethod'] = 'recordAccess'
FileObject.__init__(self, FileObject.__init__(self,
fileAccessMethod='recordAccess', fileAccessMethod='recordAccess',
@ -34,13 +36,13 @@ class LocalRecordAccessFileObject(FileObject):
""" Return the number of records. """ """ Return the number of records. """
raise NotImplementedError("__len__") raise NotImplementedError("__len__")
def read_file(self, start_record, record_count): def read_record(self, start_record, record_count):
""" Read a number of records starting at a specific record. """ """ Read a number of records starting at a specific record. """
raise NotImplementedError("read_file") raise NotImplementedError("read_record")
def write_file(self, start_record, record_count, record_data): def write_record(self, start_record, record_count, record_data):
""" Write a number of records, starting at a specific record. """ """ Write a number of records, starting at a specific record. """
raise NotImplementedError("write_file") raise NotImplementedError("write_record")
# #
# Local Stream Access File Object Type # Local Stream Access File Object Type
@ -59,9 +61,10 @@ class LocalStreamAccessFileObject(FileObject):
if 'fileAccessMethod' in kwargs: if 'fileAccessMethod' in kwargs:
if kwargs['fileAccessMethod'] != 'streamAccess': if kwargs['fileAccessMethod'] != 'streamAccess':
raise ValueError("inconsistent file access method") raise ValueError("inconsistent file access method")
else:
kwargs['fileAccessMethod'] = 'streamAccess'
FileObject.__init__(self, FileObject.__init__(self,
fileAccessMethod='streamAccess',
**kwargs **kwargs
) )
@ -69,157 +72,131 @@ class LocalStreamAccessFileObject(FileObject):
""" Return the number of octets in the file. """ """ Return the number of octets in the file. """
raise NotImplementedError("write_file") raise NotImplementedError("write_file")
def read_file(self, start_position, octet_count): def read_stream(self, start_position, octet_count):
""" Read a chunk of data out of the file. """ """ Read a chunk of data out of the file. """
raise NotImplementedError("write_file") raise NotImplementedError("read_stream")
def write_file(self, start_position, data): def write_stream(self, start_position, data):
""" Write a number of octets, starting at a specific offset. """ """ Write a number of octets, starting at a specific offset. """
raise NotImplementedError("write_file") raise NotImplementedError("write_stream")
# #
# File Application Mixin # File Application Mixin
# #
@bacpypes_debugging @bacpypes_debugging
class FileApplicationMixin(object): class FileServices(Capability):
def __init__(self, *args, **kwargs): def __init__(self):
if _debug: FileApplicationMixin._debug("__init__") if _debug: FileServices._debug("__init__")
super(FileApplicationMixin, self).__init__(*args, **kwargs) Capability.__init__(self)
def do_AtomicReadFileRequest(self, apdu): def do_AtomicReadFileRequest(self, apdu):
"""Return one of our records.""" """Return one of our records."""
if _debug: FileApplicationMixin._debug("do_AtomicReadFileRequest %r", apdu) if _debug: FileServices._debug("do_AtomicReadFileRequest %r", apdu)
if (apdu.fileIdentifier[0] != 'file'): if (apdu.fileIdentifier[0] != 'file'):
resp = Error(errorClass='services', errorCode='inconsistentObjectType', context=apdu) raise ExecutionError('services', 'inconsistentObjectType')
if _debug: FileApplicationMixin._debug(" - error resp: %r", resp)
self.response(resp)
return
# get the object # get the object
obj = self.get_object_id(apdu.fileIdentifier) obj = self.get_object_id(apdu.fileIdentifier)
if _debug: FileApplicationMixin._debug(" - object: %r", obj) if _debug: FileServices._debug(" - object: %r", obj)
if not obj: if not obj:
resp = Error(errorClass='object', errorCode='unknownObject', context=apdu) raise ExecutionError('object', 'unknownObject')
elif apdu.accessMethod.recordAccess:
if apdu.accessMethod.recordAccess:
# check against the object # check against the object
if obj.fileAccessMethod != 'recordAccess': if obj.fileAccessMethod != 'recordAccess':
resp = Error(errorClass='services', raise ExecutionError('services', 'invalidFileAccessMethod')
errorCode='invalidFileAccessMethod',
context=apdu
)
### verify start is valid - double check this (empty files?)
elif (apdu.accessMethod.recordAccess.fileStartRecord < 0) or \
(apdu.accessMethod.recordAccess.fileStartRecord >= len(obj)):
resp = Error(errorClass='services',
errorCode='invalidFileStartPosition',
context=apdu
)
else:
# pass along to the object
end_of_file, record_data = obj.ReadFile(
apdu.accessMethod.recordAccess.fileStartRecord,
apdu.accessMethod.recordAccess.requestedRecordCount,
)
if _debug: FileApplicationMixin._debug(" - record_data: %r", record_data)
# this is an ack ### verify start is valid - double check this (empty files?)
resp = AtomicReadFileACK(context=apdu, if (apdu.accessMethod.recordAccess.fileStartRecord < 0) or \
endOfFile=end_of_file, (apdu.accessMethod.recordAccess.fileStartRecord >= len(obj)):
accessMethod=AtomicReadFileACKAccessMethodChoice( raise ExecutionError('services', 'invalidFileStartPosition')
recordAccess=AtomicReadFileACKAccessMethodRecordAccess(
fileStartRecord=apdu.accessMethod.recordAccess.fileStartRecord, # pass along to the object
returnedRecordCount=len(record_data), end_of_file, record_data = obj.read_record(
fileRecordData=record_data, apdu.accessMethod.recordAccess.fileStartRecord,
), apdu.accessMethod.recordAccess.requestedRecordCount,
)
if _debug: FileServices._debug(" - record_data: %r", record_data)
# this is an ack
resp = AtomicReadFileACK(context=apdu,
endOfFile=end_of_file,
accessMethod=AtomicReadFileACKAccessMethodChoice(
recordAccess=AtomicReadFileACKAccessMethodRecordAccess(
fileStartRecord=apdu.accessMethod.recordAccess.fileStartRecord,
returnedRecordCount=len(record_data),
fileRecordData=record_data,
), ),
) ),
)
elif apdu.accessMethod.streamAccess: elif apdu.accessMethod.streamAccess:
# check against the object # check against the object
if obj.fileAccessMethod != 'streamAccess': if obj.fileAccessMethod != 'streamAccess':
resp = Error(errorClass='services', raise ExecutionError('services', 'invalidFileAccessMethod')
errorCode='invalidFileAccessMethod',
context=apdu
)
### verify start is valid - double check this (empty files?) ### verify start is valid - double check this (empty files?)
elif (apdu.accessMethod.streamAccess.fileStartPosition < 0) or \ if (apdu.accessMethod.streamAccess.fileStartPosition < 0) or \
(apdu.accessMethod.streamAccess.fileStartPosition >= len(obj)): (apdu.accessMethod.streamAccess.fileStartPosition >= len(obj)):
resp = Error(errorClass='services', raise ExecutionError('services', 'invalidFileStartPosition')
errorCode='invalidFileStartPosition',
context=apdu
)
else:
# pass along to the object
end_of_file, record_data = obj.ReadFile(
apdu.accessMethod.streamAccess.fileStartPosition,
apdu.accessMethod.streamAccess.requestedOctetCount,
)
if _debug: FileApplicationMixin._debug(" - record_data: %r", record_data)
# this is an ack # pass along to the object
resp = AtomicReadFileACK(context=apdu, end_of_file, record_data = obj.read_stream(
endOfFile=end_of_file, apdu.accessMethod.streamAccess.fileStartPosition,
accessMethod=AtomicReadFileACKAccessMethodChoice( apdu.accessMethod.streamAccess.requestedOctetCount,
streamAccess=AtomicReadFileACKAccessMethodStreamAccess( )
fileStartPosition=apdu.accessMethod.streamAccess.fileStartPosition, if _debug: FileServices._debug(" - record_data: %r", record_data)
fileData=record_data,
), # this is an ack
resp = AtomicReadFileACK(context=apdu,
endOfFile=end_of_file,
accessMethod=AtomicReadFileACKAccessMethodChoice(
streamAccess=AtomicReadFileACKAccessMethodStreamAccess(
fileStartPosition=apdu.accessMethod.streamAccess.fileStartPosition,
fileData=record_data,
), ),
) ),
)
if _debug: FileApplicationMixin._debug(" - resp: %r", resp) if _debug: FileServices._debug(" - resp: %r", resp)
# return the result # return the result
self.response(resp) self.response(resp)
def do_AtomicWriteFileRequest(self, apdu): def do_AtomicWriteFileRequest(self, apdu):
"""Return one of our records.""" """Return one of our records."""
if _debug: FileApplicationMixin._debug("do_AtomicWriteFileRequest %r", apdu) if _debug: FileServices._debug("do_AtomicWriteFileRequest %r", apdu)
if (apdu.fileIdentifier[0] != 'file'): if (apdu.fileIdentifier[0] != 'file'):
resp = Error(errorClass='services', errorCode='inconsistentObjectType', context=apdu) raise ExecutionError('services', 'inconsistentObjectType')
if _debug: FileApplicationMixin._debug(" - error resp: %r", resp)
self.response(resp)
return
# get the object # get the object
obj = self.get_object_id(apdu.fileIdentifier) obj = self.get_object_id(apdu.fileIdentifier)
if _debug: FileApplicationMixin._debug(" - object: %r", obj) if _debug: FileServices._debug(" - object: %r", obj)
if not obj: if not obj:
resp = Error(errorClass='object', errorCode='unknownObject', context=apdu) raise ExecutionError('object', 'unknownObject')
elif apdu.accessMethod.recordAccess:
if apdu.accessMethod.recordAccess:
# check against the object # check against the object
if obj.fileAccessMethod != 'recordAccess': if obj.fileAccessMethod != 'recordAccess':
resp = Error(errorClass='services', raise ExecutionError('services', 'invalidFileAccessMethod')
errorCode='invalidFileAccessMethod',
context=apdu
)
if _debug: FileApplicationMixin._debug(" - error resp: %r", resp)
self.response(resp)
return
# check for read-only # check for read-only
if obj.readOnly: if obj.readOnly:
resp = Error(errorClass='services', raise ExecutionError('services', 'fileAccessDenied')
errorCode='fileAccessDenied',
context=apdu
)
if _debug: FileApplicationMixin._debug(" - error resp: %r", resp)
self.response(resp)
return
# pass along to the object # pass along to the object
start_record = obj.WriteFile( start_record = obj.write_record(
apdu.accessMethod.recordAccess.fileStartRecord, apdu.accessMethod.recordAccess.fileStartRecord,
apdu.accessMethod.recordAccess.recordCount, apdu.accessMethod.recordAccess.recordCount,
apdu.accessMethod.recordAccess.fileRecordData, apdu.accessMethod.recordAccess.fileRecordData,
) )
if _debug: FileApplicationMixin._debug(" - start_record: %r", start_record) if _debug: FileServices._debug(" - start_record: %r", start_record)
# this is an ack # this is an ack
resp = AtomicWriteFileACK(context=apdu, resp = AtomicWriteFileACK(context=apdu,
@ -229,37 +206,25 @@ class FileApplicationMixin(object):
elif apdu.accessMethod.streamAccess: elif apdu.accessMethod.streamAccess:
# check against the object # check against the object
if obj.fileAccessMethod != 'streamAccess': if obj.fileAccessMethod != 'streamAccess':
resp = Error(errorClass='services', raise ExecutionError('services', 'invalidFileAccessMethod')
errorCode='invalidFileAccessMethod',
context=apdu
)
if _debug: FileApplicationMixin._debug(" - error resp: %r", resp)
self.response(resp)
return
# check for read-only # check for read-only
if obj.readOnly: if obj.readOnly:
resp = Error(errorClass='services', raise ExecutionError('services', 'fileAccessDenied')
errorCode='fileAccessDenied',
context=apdu
)
if _debug: FileApplicationMixin._debug(" - error resp: %r", resp)
self.response(resp)
return
# pass along to the object # pass along to the object
start_position = obj.WriteFile( start_position = obj.write_stream(
apdu.accessMethod.streamAccess.fileStartPosition, apdu.accessMethod.streamAccess.fileStartPosition,
apdu.accessMethod.streamAccess.fileData, apdu.accessMethod.streamAccess.fileData,
) )
if _debug: FileApplicationMixin._debug(" - start_position: %r", start_position) if _debug: FileServices._debug(" - start_position: %r", start_position)
# this is an ack # this is an ack
resp = AtomicWriteFileACK(context=apdu, resp = AtomicWriteFileACK(context=apdu,
fileStartPosition=start_position, fileStartPosition=start_position,
) )
if _debug: FileApplicationMixin._debug(" - resp: %r", resp) if _debug: FileServices._debug(" - resp: %r", resp)
# return the result # return the result
self.response(resp) self.response(resp)