polishing for a demo

+ adopting additional requests

Change-Id: If5ca29b5d247f1bc429ca101b0081b1d14f6e6f1
This commit is contained in:
Enrico Faulhaber
2017-01-25 11:47:19 +01:00
parent d5e935788f
commit 6ec30e38e8
43 changed files with 828 additions and 578 deletions

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Define SECoP Device classes
"""

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Dispatcher for SECoP Messages
Interface to the service offering part:
@@ -47,7 +46,6 @@ from secop.lib.parsing import format_time
class Dispatcher(object):
def __init__(self, logger, options):
self.equipment_id = options.pop('equipment_id')
self.log = logger
@@ -85,15 +83,18 @@ class Dispatcher(object):
reply = handler(conn, msg)
except SECOPError as err:
self.log.exception(err)
reply = msg.get_error(errorclass=err.__class__.__name__,
errorinfo=[repr(err), str(msg)])
reply = msg.get_error(
errorclass=err.__class__.__name__,
errorinfo=[repr(err), str(msg)])
except (ValueError, TypeError) as err:
reply = msg.get_error(errorclass='BadValue',
errorinfo=[repr(err), str(msg)])
reply = msg.get_error(
errorclass='BadValue',
errorinfo=[repr(err), str(msg)])
except Exception as err:
self.log.exception(err)
reply = msg.get_error(errorclass='InternalError',
errorinfo=[repr(err), str(msg)])
reply = msg.get_error(
errorclass='InternalError',
errorinfo=[repr(err), str(msg)])
else:
self.log.debug('Can not handle msg %r' % msg)
reply = self.unhandled(conn, msg)
@@ -106,8 +107,8 @@ class Dispatcher(object):
listeners = self._connections
else:
if getattr(msg, 'command', None) is None:
eventname = '%s:%s' % (
msg.module, msg.parameter if msg.parameter else 'value')
eventname = '%s:%s' % (msg.module, msg.parameter
if msg.parameter else 'value')
else:
eventname = '%s:%s()' % (msg.module, msg.command)
listeners = self._subscriptions.get(eventname, [])
@@ -198,8 +199,7 @@ class Dispatcher(object):
res = {}
for cmdname, cmdobj in self.get_module(modulename).CMDS.items():
res[cmdname] = cmdobj.as_dict()
self.log.debug('list cmds for module %s -> %r' %
(modulename, res))
self.log.debug('list cmds for module %s -> %r' % (modulename, res))
return res
self.log.debug('-> module is not to be exported!')
return {}
@@ -210,12 +210,13 @@ class Dispatcher(object):
for modulename in self._export:
module = self.get_module(modulename)
# some of these need rework !
dd = {'class': module.__class__.__name__,
'bases': [b.__name__ for b in module.__class__.__bases__],
'parameters': self.list_module_params(modulename),
'commands': self.list_module_cmds(modulename),
'baseclass': 'Readable',
}
dd = {
'class': module.__class__.__name__,
'bases': [b.__name__ for b in module.__class__.__bases__],
'parameters': self.list_module_params(modulename),
'commands': self.list_module_cmds(modulename),
'interfaceclass': 'Readable',
}
result['modules'][modulename] = dd
result['equipment_id'] = self.equipment_id
result['firmware'] = 'The SECoP playground'
@@ -244,8 +245,11 @@ class Dispatcher(object):
# note: exceptions are handled in handle_request, not here!
func = getattr(moduleobj, 'do' + command)
res = func(*arguments)
res = CommandReply(module=modulename, command=command,
result=res, qualifiers=dict(t=time.time()))
res = CommandReply(
module=modulename,
command=command,
result=res,
qualifiers=dict(t=time.time()))
# res = Value(modulename, command=command, value=func(*arguments), t=time.time())
return res
@@ -268,15 +272,11 @@ class Dispatcher(object):
setattr(moduleobj, pname, value)
if pobj.timestamp:
return WriteReply(
module=modulename, parameter=pname, value=[
pobj.value, dict(
t=format_time(pobj.timestamp))])
module=modulename,
parameter=pname,
value=[pobj.value, dict(t=format_time(pobj.timestamp))])
return WriteReply(
module=modulename,
parameter=pname,
value=[
pobj.value,
{}])
module=modulename, parameter=pname, value=[pobj.value, {}])
def _getParamValue(self, modulename, pname):
moduleobj = self.get_module(modulename)
@@ -370,9 +370,12 @@ class Dispatcher(object):
except SECOPError as e:
self.log.error('decide what to do here!')
self.log.exception(e)
res = Value(module=modulename, parameter=pname,
value=pobj.value, t=pobj.timestamp,
unit=pobj.unit)
res = Value(
module=modulename,
parameter=pname,
value=pobj.value,
t=pobj.timestamp,
unit=pobj.unit)
if res.value != Ellipsis: # means we do not have a value at all so skip this
self.broadcast_event(res)
conn.queue_async_reply(ActivateReply(**msg.as_dict()))
@@ -392,5 +395,5 @@ class Dispatcher(object):
(no handle_<messagename> method was defined)
"""
self.log.error('IGN: got unhandled request %s' % msg)
return msg.get_error(errorclass="InternalError",
errorinfo="Unhandled Request")
return msg.get_error(
errorclass="InternalError", errorinfo="Unhandled Request")

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Messages"""
# implement as class as they may need some internal 'state' later on
@@ -39,6 +38,7 @@ class MessageEncoder(object):
"""decodes the given frame to a message object"""
raise NotImplemented
from demo_v2 import DemoEncoder as DemoEncoderV2
from demo_v3 import DemoEncoder as DemoEncoderV3
from demo_v4 import DemoEncoder as DemoEncoderV4

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Messages"""
# implement as class as they may need some internal 'state' later on
@@ -32,11 +31,11 @@ from secop.lib.parsing import *
import re
DEMO_RE = re.compile(
r'^([!+-])?(\*|[a-z_][a-z_0-9]*)?(?:\:(\*|[a-z_][a-z_0-9]*))?(?:\:(\*|[a-z_][a-z_0-9]*))?(?:\=(.*))?')
r'^([!+-])?(\*|[a-z_][a-z_0-9]*)?(?:\:(\*|[a-z_][a-z_0-9]*))?(?:\:(\*|[a-z_][a-z_0-9]*))?(?:\=(.*))?'
)
class DemoEncoder(MessageEncoder):
def decode(sef, encoded):
# match [!][*|devicename][: *|paramname [: *|propname]] [=value]
match = DEMO_RE.match(encoded)
@@ -46,8 +45,8 @@ class DemoEncoder(MessageEncoder):
print "parsing", assign,
assign = parse_args(assign)
print "->", assign
return messages.DemoRequest(
novalue, devname, pname, propname, assign)
return messages.DemoRequest(novalue, devname, pname, propname,
assign)
return messages.HelpRequest()
def encode(self, msg):
@@ -66,8 +65,13 @@ class DemoEncoder(MessageEncoder):
return '~InternalError~'
return result
def _encode_AsyncDataUnit(self, devname, pname, value, timestamp,
error=None, unit=''):
def _encode_AsyncDataUnit(self,
devname,
pname,
value,
timestamp,
error=None,
unit=''):
return '#%s:%s=%s;t=%.3f' % (devname, pname, value, timestamp)
def _encode_Error(self, error):
@@ -98,5 +102,7 @@ class DemoEncoder(MessageEncoder):
return '~InvalidValueForParamError~ %s:%s=%r' % (device, param, value)
def _encode_HelpReply(self):
return ['Help not yet implemented!',
'ask Markus Zolliker about the protocol']
return [
'Help not yet implemented!',
'ask Markus Zolliker about the protocol'
]

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Messages"""
# implement as class as they may need some internal 'state' later on
@@ -93,7 +92,6 @@ DEMO_RE_OTHER = re.compile(
class DemoEncoder(MessageEncoder):
def __init__(self, *args, **kwds):
MessageEncoder.__init__(self, *args, **kwds)
self.result = [] # for decoding
@@ -112,8 +110,8 @@ class DemoEncoder(MessageEncoder):
r.append("help ... more to come")
return '\n'.join(r)
if isinstance(msg, (ListMessage, SubscribeMessage,
UnsubscribeMessage, TriggerMessage)):
if isinstance(msg, (ListMessage, SubscribeMessage, UnsubscribeMessage,
TriggerMessage)):
msgtype = msg.MSGTYPE
if msg.result:
if msg.devs:
@@ -145,9 +143,7 @@ class DemoEncoder(MessageEncoder):
# encode 1..N replies
result.append(
encode_value(
val,
'write',
targetvalue=msg.target))
val, 'write', targetvalue=msg.target))
if not msg.result:
# encode a request (no results -> reply, else an error would
# have been sent)
@@ -164,28 +160,17 @@ class DemoEncoder(MessageEncoder):
encode_value(
val,
'command',
cmd='%s(%s)' %
(msg.cmd,
','.join(
msg.args))))
cmd='%s(%s)' % (msg.cmd, ','.join(msg.args))))
if not msg.result:
# encode a request (no results -> reply, else an error would
# have been sent)
result.append(
'%s:%s(%s)' %
(devspec(
msg, 'command'), msg.cmd, ','.join(
msg.args)))
result.append('%s:%s(%s)' % (devspec(msg, 'command'), msg.cmd,
','.join(msg.args)))
return '\n'.join(result)
if isinstance(msg, ErrorMessage):
return (
'%s %s' %
(devspec(
msg,
'error %s' %
msg.errortype),
msg.errorstring)).strip()
return ('%s %s' % (devspec(msg, 'error %s' % msg.errortype),
msg.errorstring)).strip()
return 'Can not handle object %r!' % msg
@@ -246,6 +231,7 @@ class DemoEncoder(MessageEncoder):
if sep in stuff:
return stuff.split(sep)
return [stuff]
devs = helper(mgroups.pop('devs'))
pars = helper(mgroups.pop('pars'))
props = helper(mgroups.pop('props'))
@@ -272,12 +258,8 @@ class DemoEncoder(MessageEncoder):
# reformat qualifiers
print mgroups
quals = dict(
qual.split(
'=',
1) for qual in helper(
mgroups.pop(
'qualifiers',
';')))
qual.split('=', 1)
for qual in helper(mgroups.pop('qualifiers', ';')))
# reformat value
result = []
@@ -296,48 +278,49 @@ class DemoEncoder(MessageEncoder):
# construct messageobj
if msgtype in MESSAGE:
return MESSAGE[msgtype](
devs=devs,
pars=pars,
props=props,
result=result,
**mgroups)
return MESSAGE[msgtype](devs=devs,
pars=pars,
props=props,
result=result,
**mgroups)
return ErrorMessage(errortype="SyntaxError",
errorstring="Can't handle %r" % encoded)
return ErrorMessage(
errortype="SyntaxError", errorstring="Can't handle %r" % encoded)
def tests(self):
testmsg = ['list',
'list *',
'list device',
'list device:param1,param2',
'list *:*',
'list *=ts,tcoil,mf,lhe,ln2;',
'read blub=12;t=3',
'command ts:stop()',
'command mf:quench(1,"now")',
'error GibbetNich query x:y:z=9 "blubub blah"',
'#3',
'read blub:a=12;t=3',
'read blub:b=13;t=3.1',
'read blub:c=14;t=3.3',
]
testmsg = [
'list',
'list *',
'list device',
'list device:param1,param2',
'list *:*',
'list *=ts,tcoil,mf,lhe,ln2;',
'read blub=12;t=3',
'command ts:stop()',
'command mf:quench(1,"now")',
'error GibbetNich query x:y:z=9 "blubub blah"',
'#3',
'read blub:a=12;t=3',
'read blub:b=13;t=3.1',
'read blub:c=14;t=3.3',
]
for m in testmsg:
print repr(m)
print self.decode(m)
print
DEMO_RE_MZ = re.compile(r"""^(?P<type>[a-z]+)? # request type word (read/write/list/...)
DEMO_RE_MZ = re.compile(
r"""^(?P<type>[a-z]+)? # request type word (read/write/list/...)
\ ? # optional space
(?P<device>[a-z][a-z0-9_]*)? # optional devicename
(?:\:(?P<param>[a-z0-9_]*) # optional ':'+paramname
(?:\:(?P<prop>[a-z0-9_]*))?)? # optinal ':' + propname
(?:(?P<op>[=\?])(?P<value>[^;]+)(?:\;(?P<quals>.*))?)?$""", re.X)
(?:(?P<op>[=\?])(?P<value>[^;]+)(?:\;(?P<quals>.*))?)?$""",
re.X)
class DemoEncoder_MZ(MessageEncoder):
def decode(sef, encoded):
m = DEMO_RE_MZ.match(encoded)
if m:

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Messages"""
# implement as class as they may need some internal 'state' later on
@@ -47,7 +46,8 @@ DEMO_RE = re.compile(
IDENTREQUEST = '*IDN?' # literal
# literal! first part is fixed!
#IDENTREPLY = 'SECoP, SECoPTCP, V2016-11-30, rc1'
IDENTREPLY = 'SINE2020&ISSE,SECoP,V2016-11-30,rc1'
#IDENTREPLY = 'SINE2020&ISSE,SECoP,V2016-11-30,rc1'
IDENTREPLY = 'SINE2020&ISSE,SECoP,V2017-01-25,rc1'
DESCRIPTIONSREQUEST = 'describe' # literal
DESCRIPTIONREPLY = 'describing' # +<id> +json
ENABLEEVENTSREQUEST = 'activate' # literal
@@ -69,10 +69,22 @@ HEARTBEATREPLY = 'pong' # +nonce_without_space
ERRORREPLY = 'error' # +errorclass +json_extended_info
HELPREQUEST = 'help' # literal
HELPREPLY = 'helping' # +line number +json_text
ERRORCLASSES = ['NoSuchDevice', 'NoSuchParameter', 'NoSuchCommand',
'CommandFailed', 'ReadOnly', 'BadValue', 'CommunicationFailed',
'IsBusy', 'IsError', 'ProtocolError', 'InternalError',
'CommandRunning', 'Disabled', ]
ERRORCLASSES = [
'NoSuchDevice',
'NoSuchParameter',
'NoSuchCommand',
'CommandFailed',
'ReadOnly',
'BadValue',
'CommunicationFailed',
'IsBusy',
'IsError',
'ProtocolError',
'InternalError',
'CommandRunning',
'Disabled',
]
# note: above strings need to be unique in the sense, that none is/or
# starts with another
@@ -93,33 +105,61 @@ def encode_value_data(vobj):
def encode_error_msg(emsg):
# note: result is JSON-ified....
return [emsg.origin, dict((k, getattr(emsg, k))
for k in emsg.ARGS if k != 'origin')]
return [
emsg.origin, dict((k, getattr(emsg, k)) for k in emsg.ARGS
if k != 'origin')
]
class DemoEncoder(MessageEncoder):
# map of msg to msgtype string as defined above.
ENCODEMAP = {
IdentifyRequest: (IDENTREQUEST,),
IdentifyReply: (IDENTREPLY,),
DescribeRequest: (DESCRIPTIONSREQUEST,),
DescribeReply: (DESCRIPTIONREPLY, 'equipment_id', 'description',),
ActivateRequest: (ENABLEEVENTSREQUEST,),
ActivateReply: (ENABLEEVENTSREPLY,),
DeactivateRequest: (DISABLEEVENTSREQUEST,),
DeactivateReply: (DISABLEEVENTSREPLY,),
CommandRequest: (COMMANDREQUEST, lambda msg: "%s:%s" % (msg.module, msg.command), 'arguments',),
CommandReply: (COMMANDREPLY, lambda msg: "%s:%s" % (msg.module, msg.command), encode_cmd_result,),
WriteRequest: (WRITEREQUEST, lambda msg: "%s:%s" % (msg.module, msg.parameter) if msg.parameter else msg.module, 'value',),
WriteReply: (WRITEREPLY, lambda msg: "%s:%s" % (msg.module, msg.parameter) if msg.parameter else msg.module, 'value', ),
PollRequest: (TRIGGERREQUEST, lambda msg: "%s:%s" % (msg.module, msg.parameter) if msg.parameter else msg.module, ),
HeartbeatRequest: (HEARTBEATREQUEST, 'nonce',),
HeartbeatReply: (HEARTBEATREPLY, 'nonce',),
IdentifyRequest: (IDENTREQUEST, ),
IdentifyReply: (IDENTREPLY, ),
DescribeRequest: (DESCRIPTIONSREQUEST, ),
DescribeReply: (
DESCRIPTIONREPLY,
'equipment_id',
'description', ),
ActivateRequest: (ENABLEEVENTSREQUEST, ),
ActivateReply: (ENABLEEVENTSREPLY, ),
DeactivateRequest: (DISABLEEVENTSREQUEST, ),
DeactivateReply: (DISABLEEVENTSREPLY, ),
CommandRequest: (
COMMANDREQUEST,
lambda msg: "%s:%s" % (msg.module, msg.command),
'arguments', ),
CommandReply: (
COMMANDREPLY,
lambda msg: "%s:%s" % (msg.module, msg.command),
encode_cmd_result, ),
WriteRequest: (
WRITEREQUEST,
lambda msg: "%s:%s" % (msg.module, msg.parameter) if msg.parameter else msg.module,
'value', ),
WriteReply: (
WRITEREPLY,
lambda msg: "%s:%s" % (msg.module, msg.parameter) if msg.parameter else msg.module,
'value', ),
PollRequest: (
TRIGGERREQUEST,
lambda msg: "%s:%s" % (msg.module, msg.parameter) if msg.parameter else msg.module,
),
HeartbeatRequest: (
HEARTBEATREQUEST,
'nonce', ),
HeartbeatReply: (
HEARTBEATREPLY,
'nonce', ),
HelpMessage: (HELPREQUEST, ),
ErrorMessage: (ERRORREPLY, "errorclass", encode_error_msg,),
Value: (EVENT, lambda msg: "%s:%s" % (msg.module, msg.parameter or (msg.command + '()'))
if msg.parameter or msg.command else msg.module,
encode_value_data,),
ErrorMessage: (
ERRORREPLY,
"errorclass",
encode_error_msg, ),
Value: (
EVENT,
lambda msg: "%s:%s" % (msg.module, msg.parameter or (msg.command + '()')) if msg.parameter or msg.command else msg.module,
encode_value_data, ),
}
DECODEMAP = {
IDENTREQUEST: lambda spec, data: IdentifyRequest(),
@@ -177,8 +217,10 @@ class DemoEncoder(MessageEncoder):
for msgcls, parts in self.ENCODEMAP.items():
if isinstance(msg, msgcls):
# resolve lambdas
parts = [parts[0]] + [p(msg) if callable(p)
else getattr(msg, p) for p in parts[1:]]
parts = [parts[0]] + [
p(msg) if callable(p) else getattr(msg, p)
for p in parts[1:]
]
if len(parts) > 1:
parts[1] = str(parts[1])
if len(parts) == 3:
@@ -199,10 +241,11 @@ class DemoEncoder(MessageEncoder):
# is_request=True)
msgtype, msgspec, data = match.groups()
if msgspec is None and data:
return ErrorMessage(errorclass='Internal',
errorinfo='Regex matched json, but not spec!',
is_request=True,
origin=encoded)
return ErrorMessage(
errorclass='Internal',
errorinfo='Regex matched json, but not spec!',
is_request=True,
origin=encoded)
if msgtype in self.DECODEMAP:
if msgspec and ':' in msgspec:
@@ -213,16 +256,16 @@ class DemoEncoder(MessageEncoder):
try:
data = json.loads(data)
except ValueError as err:
return ErrorMessage(errorclass='BadValue',
errorinfo=[repr(err), str(encoded)],
origin=encoded)
return ErrorMessage(
errorclass='BadValue',
errorinfo=[repr(err), str(encoded)],
origin=encoded)
msg = self.DECODEMAP[msgtype](msgspec, data)
msg.setvalue("origin", encoded)
return msg
return ErrorMessage(
errorclass='Protocol',
errorinfo='%r: No Such Messagetype defined!' %
encoded,
errorinfo='%r: No Such Messagetype defined!' % encoded,
is_request=True,
origin=encoded)

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Messages"""
# implement as class as they may need some internal 'state' later on
@@ -36,7 +35,6 @@ except ImportError:
class PickleEncoder(MessageEncoder):
def encode(self, messageobj):
"""msg object -> transport layer message"""
return pickle.dumps(messageobj)

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Messages"""
# implement as class as they may need some internal 'state' later on
@@ -32,13 +31,12 @@ from secop.lib.parsing import *
import re
import ast
SCPMESSAGE = re.compile(
r'^(?:(?P<errorcode>[0-9@])\ )?(?P<device>[a-zA-Z0-9_\*]*)(?:/(?P<param>[a-zA-Z0-9_\*]*))+(?P<op>[-+=\?\ ])?(?P<value>.*)')
r'^(?:(?P<errorcode>[0-9@])\ )?(?P<device>[a-zA-Z0-9_\*]*)(?:/(?P<param>[a-zA-Z0-9_\*]*))+(?P<op>[-+=\?\ ])?(?P<value>.*)'
)
class SCPEncoder(MessageEncoder):
def encode(self, msg):
"""msg object -> transport layer message"""
# fun for Humans
@@ -48,20 +46,24 @@ class SCPEncoder(MessageEncoder):
r.append("'/version?' to query the current version")
r.append("'/modules?' to query the list of modules")
r.append(
"'<module>/parameters?' to query the list of params of a module")
"'<module>/parameters?' to query the list of params of a module"
)
r.append("'<module>/value?' to query the value of a module")
r.append("'<module>/status?' to query the status of a module")
r.append("'<module>/target=<new_value>' to move a module")
r.append("replies copy the request and are prefixed with an errorcode:")
r.append(
"0=OK,3=NoSuchCommand,4=NosuchDevice,5=NoSuchParam,6=SyntaxError,7=BadValue,8=Readonly,9=Forbidden,@=Async")
"replies copy the request and are prefixed with an errorcode:")
r.append(
"0=OK,3=NoSuchCommand,4=NosuchDevice,5=NoSuchParam,6=SyntaxError,7=BadValue,8=Readonly,9=Forbidden,@=Async"
)
r.append("extensions: @-prefix as error-code,")
r.append("'<module>/+' subscribe all params of module")
r.append("'<module>/<param>+' subscribe a param of a module")
r.append("use '-' instead of '+' to unsubscribe")
r.append("'<module>/commands?' list of commands")
r.append(
"'<module>/<command>@[possible args] execute command (ex. 'stop@')")
"'<module>/<command>@[possible args] execute command (ex. 'stop@')"
)
return '\n'.join(r)
return {
@@ -117,7 +119,7 @@ class SCPEncoder(MessageEncoder):
def decode(self, encoded):
"""transport layer message -> msg object"""
match = SCPMESSAGE.match(encoded)
if not(match):
if not (match):
return HelpRequest()
err, dev, par, op, val = match.groups()
if val is not None:

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Messages"""
# implement as class as they may need some internal 'state' later on
@@ -31,7 +30,6 @@ from secop.lib.parsing import *
class TextEncoder(MessageEncoder):
def __init__(self):
# build safe namespace
ns = dict()

View File

@@ -19,12 +19,10 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Define (internal) SECoP Errors"""
class SECOPError(RuntimeError):
def __init__(self, *args, **kwds):
self.args = args
for k, v in kwds.items():
@@ -91,8 +89,7 @@ EXCEPTIONS = dict(
BadValue=BadValueError,
Readonly=ReadonlyError,
CommandFailed=CommandFailedError,
InvalidParam=InvalidParamValueError,
)
InvalidParam=InvalidParamValueError, )
if __name__ == '__main__':
print("Minimal testing of errors....")

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Frames"""
@@ -45,7 +44,6 @@ class Framer(object):
"""resets the de/encoding stage (clears internal information)"""
raise NotImplemented
# now some Implementations
from null import NullFramer
from eol import EOLFramer

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Frames"""
from secop.protocol.framing import Framer

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Frames"""
from secop.protocol.framing import Framer

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Frames"""
from secop.protocol.framing import Framer

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Encoding/decoding Frames"""
from secop.protocol.framing import Framer

View File

@@ -23,9 +23,7 @@
from tcp import TCPServer
INTERFACES = {
'tcp': TCPServer,
}
INTERFACES = {'tcp': TCPServer, }
# for 'from protocol.interface import *' to only import the dict
__ALL__ = ['INTERFACES']

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""provides tcp interface to the SECoP Server"""
import os
@@ -36,7 +35,6 @@ from secop.protocol.messages import HelpMessage
class TCPRequestHandler(SocketServer.BaseRequestHandler):
def setup(self):
self.log = self.server.log
self._queue = collections.deque(maxlen=100)
@@ -49,13 +47,13 @@ class TCPRequestHandler(SocketServer.BaseRequestHandler):
mysocket = self.request
clientaddr = self.client_address
serverobj = self.server
self.log.debug("handling new connection from %s" % repr(clientaddr))
self.log.info("handling new connection from %s:%d" % clientaddr)
# notify dispatcher of us
serverobj.dispatcher.add_connection(self)
mysocket.settimeout(.3)
# mysocket.setblocking(False)
# mysocket.setblocking(False)
# start serving
while True:
# send replys fist, then listen for requests, timing out after 0.1s
@@ -66,7 +64,10 @@ class TCPRequestHandler(SocketServer.BaseRequestHandler):
outmsg = self._queue.popleft()
outframes = self.encoding.encode(outmsg)
outdata = self.framing.encode(outframes)
mysocket.sendall(outdata)
try:
mysocket.sendall(outdata)
except Exception:
return
# XXX: improve: use polling/select here?
try:
@@ -101,6 +102,7 @@ class TCPRequestHandler(SocketServer.BaseRequestHandler):
def finish(self):
"""called when handle() terminates, i.e. the socket closed"""
self.log.info('closing connection from %s:%d' % self.client_address)
# notify dispatcher
self.server.dispatcher.remove_connection(self)
# close socket
@@ -132,7 +134,6 @@ class TCPServer(SocketServer.ThreadingTCPServer):
self.log.debug("TCPServer using framing=%s" % self.framingCLS.__name__)
self.log.debug("TCPServer using encoding=%s" %
self.encodingCLS.__name__)
SocketServer.ThreadingTCPServer.__init__(self, (bindto, portnum),
TCPRequestHandler,
bind_and_activate=True)
SocketServer.ThreadingTCPServer.__init__(
self, (bindto, portnum), TCPRequestHandler, bind_and_activate=True)
self.log.info("TCPServer initiated")

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Define SECoP Messages"""
@@ -51,8 +50,11 @@ class Message(object):
class Value(object):
def __init__(self, module, parameter=None, command=None, value=Ellipsis,
def __init__(self,
module,
parameter=None,
command=None,
value=Ellipsis,
**qualifiers):
self.module = module
self.parameter = parameter
@@ -67,9 +69,10 @@ class Value(object):
devspec = '%s:%s' % (devspec, self.parameter)
elif self.command:
devspec = '%s:%s()' % (devspec, self.command)
return '%s:Value(%s)' % (devspec, ', '.join(
[repr(self.value)] +
['%s=%s' % (k, format_time(v) if k == "timestamp" else repr(v)) for k, v in self.qualifiers.items()]))
return '%s:Value(%s)' % (devspec, ', '.join([repr(self.value)] + [
'%s=%s' % (k, format_time(v) if k == "timestamp" else repr(v))
for k, v in self.qualifiers.items()
]))
class Request(Message):
@@ -95,8 +98,7 @@ class Request(Message):
for k in self.ARGS:
m.setvalue(k, self.__dict__[k])
m.setvalue("errorclass", errorclass[:-5]
if errorclass.endswith('rror')
else errorclass)
if errorclass.endswith('rror') else errorclass)
m.setvalue("errorinfo", errorinfo)
return m

View File

@@ -19,7 +19,6 @@
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
"""Define SECoP Messages"""
# Request Types
@@ -79,8 +78,9 @@ class Message(object):
r = 'Device' if self.devs != ['*'] else 'Devices'
t = ''
if self.MSGTYPE in [LIST, READ, WRITE, COMMAND,
POLL, SUBSCRIBE, UNSUBSCRIBE, HELP]:
if self.MSGTYPE in [
LIST, READ, WRITE, COMMAND, POLL, SUBSCRIBE, UNSUBSCRIBE, HELP
]:
t = 'Request' if not self.result else 'Reply'
if self.errortype is None:
@@ -95,7 +95,6 @@ class Message(object):
class Value(object):
def __init__(self, value=Ellipsis, qualifiers=None, **kwds):
self.dev = ''
self.param = ''
@@ -111,9 +110,9 @@ class Value(object):
if self.prop:
devspec = '%s:%s' % (devspec, self.prop)
return '%s:Value(%s)' % (
devspec, ', '.join(
[repr(self.value)] +
['%s=%r' % (k, v) for k, v in self.qualifiers.items()]))
devspec,
', '.join([repr(self.value)] +
['%s=%r' % (k, v) for k, v in self.qualifiers.items()]))
class ListMessage(Message):
@@ -167,28 +166,29 @@ class HelpMessage(Message):
class NoSuchDeviceError(ErrorMessage):
def __init__(self, *devs):
ErrorMessage.__init__(
self, devs=devs, errorstring="Device %r does not exist" %
devs[0], errortype='NoSuchDevice')
self,
devs=devs,
errorstring="Device %r does not exist" % devs[0],
errortype='NoSuchDevice')
class NoSuchParamError(ErrorMessage):
def __init__(self, dev, *params):
ErrorMessage.__init__(
self, devs=(dev,),
params=params, errorstring="Device %r has no parameter %r" %
(dev, params[0]),
self,
devs=(dev, ),
params=params,
errorstring="Device %r has no parameter %r" % (dev, params[0]),
errortype='NoSuchParam')
class ParamReadonlyError(ErrorMessage):
def __init__(self, dev, *params):
ErrorMessage.__init__(
self, devs=(dev,),
self,
devs=(dev, ),
params=params,
errorstring="Device %r, parameter %r is not writeable!" %
(dev, params[0]),
@@ -196,30 +196,28 @@ class ParamReadonlyError(ErrorMessage):
class InvalidParamValueError(ErrorMessage):
def __init__(self, dev, param, value, e):
ErrorMessage.__init__(
self, devs=(dev,),
params=params, values=(value),
self,
devs=(dev, ),
params=params,
values=(value),
errorstring=str(e),
errortype='InvalidParamValueError')
class InternalError(ErrorMessage):
def __init__(self, err, **kwds):
ErrorMessage.__init__(
self, errorstring=str(err),
errortype='InternalError', **kwds)
self, errorstring=str(err), errortype='InternalError', **kwds)
MESSAGE = dict(
(cls.MSGTYPE, cls)
for cls
in
[HelpMessage, ErrorMessage, EventMessage, TriggerMessage,
UnsubscribeMessage, SubscribeMessage, PollMessage, CommandMessage,
WriteMessage, ReadMessage, ListMessage])
MESSAGE = dict((cls.MSGTYPE, cls)
for cls in [
HelpMessage, ErrorMessage, EventMessage, TriggerMessage,
UnsubscribeMessage, SubscribeMessage, PollMessage,
CommandMessage, WriteMessage, ReadMessage, ListMessage
])
if __name__ == '__main__':
print("Minimal testing of messages....")

View File

@@ -23,9 +23,9 @@
# could also be some objects
OK = 100
BUSY = 200
WARN = 300
UNSTABLE = 350
WARN = 200
UNSTABLE = 250
BUSY = 300
ERROR = 400
UNKNOWN = -1