From eeac27660165cb2b54f676040a782cbb3846cc24 Mon Sep 17 00:00:00 2001 From: Enrico Faulhaber Date: Mon, 18 Sep 2017 14:39:03 +0200 Subject: [PATCH] Remove obsolete protocol implementations Change-Id: I9342ff3d00666238b6412b41a3785dadd96a7778 Reviewed-on: https://forge.frm2.tum.de/review/16273 Tested-by: JenkinsCodeReview Reviewed-by: Enrico Faulhaber --- .../playground/server/protocol/encoding.rst | 6 + .../server/protocol/encoding/demo_v2.rst | 6 - .../server/protocol/encoding/demo_v3.rst | 6 - .../server/protocol/encoding/demo_v4.rst | 6 - .../server/protocol/encoding/demo_v5.rst | 6 - .../server/protocol/encoding/index.rst | 11 - .../playground/server/protocol/index.rst | 6 +- etc/amagnet.cfg | 2 +- etc/ccr12.cfg | 2 +- etc/cryo.cfg | 2 +- etc/demo.cfg | 2 +- etc/epics.cfg | 4 +- etc/test.cfg | 2 +- .../{encoding/demo_v5.py => encoding.py} | 47 ++- secop/protocol/encoding/__init__.py | 61 --- secop/protocol/encoding/demo_v2.py | 111 ----- secop/protocol/encoding/demo_v3.py | 387 ------------------ secop/protocol/encoding/demo_v4.py | 307 -------------- secop/protocol/encoding/pickle.py | 45 -- secop/protocol/encoding/simplecomm.py | 212 ---------- secop/protocol/encoding/text.py | 64 --- 21 files changed, 52 insertions(+), 1243 deletions(-) create mode 100644 doc/source/playground/server/protocol/encoding.rst delete mode 100644 doc/source/playground/server/protocol/encoding/demo_v2.rst delete mode 100644 doc/source/playground/server/protocol/encoding/demo_v3.rst delete mode 100644 doc/source/playground/server/protocol/encoding/demo_v4.rst delete mode 100644 doc/source/playground/server/protocol/encoding/demo_v5.rst delete mode 100644 doc/source/playground/server/protocol/encoding/index.rst rename secop/protocol/{encoding/demo_v5.py => encoding.py} (91%) delete mode 100644 secop/protocol/encoding/__init__.py delete mode 100644 secop/protocol/encoding/demo_v2.py delete mode 100644 secop/protocol/encoding/demo_v3.py delete mode 100644 secop/protocol/encoding/demo_v4.py delete mode 100644 secop/protocol/encoding/pickle.py delete mode 100644 secop/protocol/encoding/simplecomm.py delete mode 100644 secop/protocol/encoding/text.py diff --git a/doc/source/playground/server/protocol/encoding.rst b/doc/source/playground/server/protocol/encoding.rst new file mode 100644 index 0000000..642c681 --- /dev/null +++ b/doc/source/playground/server/protocol/encoding.rst @@ -0,0 +1,6 @@ +SECoP Encoding +============== + +.. automodule:: secop.protocol.encoding.secop + :members: + diff --git a/doc/source/playground/server/protocol/encoding/demo_v2.rst b/doc/source/playground/server/protocol/encoding/demo_v2.rst deleted file mode 100644 index 89a43ff..0000000 --- a/doc/source/playground/server/protocol/encoding/demo_v2.rst +++ /dev/null @@ -1,6 +0,0 @@ -Demo V2 -======= - -.. automodule:: secop.protocol.encoding.demo_v2 - :members: - diff --git a/doc/source/playground/server/protocol/encoding/demo_v3.rst b/doc/source/playground/server/protocol/encoding/demo_v3.rst deleted file mode 100644 index 5da8a19..0000000 --- a/doc/source/playground/server/protocol/encoding/demo_v3.rst +++ /dev/null @@ -1,6 +0,0 @@ -Demo V3 -======= - -.. automodule:: secop.protocol.encoding.demo_v2 - :members: - diff --git a/doc/source/playground/server/protocol/encoding/demo_v4.rst b/doc/source/playground/server/protocol/encoding/demo_v4.rst deleted file mode 100644 index f6e3676..0000000 --- a/doc/source/playground/server/protocol/encoding/demo_v4.rst +++ /dev/null @@ -1,6 +0,0 @@ -Demo V4 -======= - -.. automodule:: secop.protocol.encoding.demo_v2 - :members: - diff --git a/doc/source/playground/server/protocol/encoding/demo_v5.rst b/doc/source/playground/server/protocol/encoding/demo_v5.rst deleted file mode 100644 index 19ba734..0000000 --- a/doc/source/playground/server/protocol/encoding/demo_v5.rst +++ /dev/null @@ -1,6 +0,0 @@ -Demo V5 -======= - -.. automodule:: secop.protocol.encoding.demo_v2 - :members: - diff --git a/doc/source/playground/server/protocol/encoding/index.rst b/doc/source/playground/server/protocol/encoding/index.rst deleted file mode 100644 index a2c2a53..0000000 --- a/doc/source/playground/server/protocol/encoding/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -Encodings -========= - -.. toctree:: - :maxdepth: 3 - - demo_v2 - demo_v3 - demo_v4 - demo_v5 - diff --git a/doc/source/playground/server/protocol/index.rst b/doc/source/playground/server/protocol/index.rst index d8ab936..fa819cc 100644 --- a/doc/source/playground/server/protocol/index.rst +++ b/doc/source/playground/server/protocol/index.rst @@ -1,10 +1,10 @@ -Different protocols -=================== +protocol stack +============== .. toctree:: :maxdepth: 3 - encoding/index + encoding framing/index interface/index diff --git a/etc/amagnet.cfg b/etc/amagnet.cfg index 7e58e3b..9736cec 100644 --- a/etc/amagnet.cfg +++ b/etc/amagnet.cfg @@ -19,7 +19,7 @@ bindto=0.0.0.0 bindport=10767 # protocol to use for this interface framing=eol -encoding=demo +encoding=secop [device enable] class=secop_mlz.entangle.NamedDigitalOutput diff --git a/etc/ccr12.cfg b/etc/ccr12.cfg index b595f3d..04753a6 100644 --- a/etc/ccr12.cfg +++ b/etc/ccr12.cfg @@ -11,7 +11,7 @@ bindto=0.0.0.0 bindport=10767 # protocol to use for this interface framing=eol -encoding=demo +encoding=secop [device automatik] class=secop_mlz.entangle.NamedDigitalOutput diff --git a/etc/cryo.cfg b/etc/cryo.cfg index f046555..d8aaecf 100644 --- a/etc/cryo.cfg +++ b/etc/cryo.cfg @@ -11,7 +11,7 @@ bindto=0.0.0.0 bindport=10769 # protocol to use for this interface framing=eol -encoding=demo +encoding=secop [device cryo] diff --git a/etc/demo.cfg b/etc/demo.cfg index edfd69b..e86ff4d 100644 --- a/etc/demo.cfg +++ b/etc/demo.cfg @@ -7,7 +7,7 @@ bindto=0.0.0.0 bindport=10767 # protocol to use for this interface framing=eol -encoding=demo +encoding=secop [device heatswitch] class=secop_demo.modules.Switch diff --git a/etc/epics.cfg b/etc/epics.cfg index 3d0a40d..762903f 100644 --- a/etc/epics.cfg +++ b/etc/epics.cfg @@ -6,7 +6,7 @@ connectto=0.0.0.0 port=10767 interface = tcp framing=eol -encoding=text +encoding=secop [interface testing] interface=tcp @@ -14,7 +14,7 @@ bindto=0.0.0.0 bindport=10767 # protocol to use for this interface framing=eol -encoding=demo +encoding=secop [device tc1] class=secop_demo.demo.CoilTemp diff --git a/etc/test.cfg b/etc/test.cfg index 7f9aa5d..bfb2cf2 100644 --- a/etc/test.cfg +++ b/etc/test.cfg @@ -14,7 +14,7 @@ bindto=0.0.0.0 bindport=10768 # protocol to use for this interface framing=eol -encoding=demo +encoding=secop [device LN2] diff --git a/secop/protocol/encoding/demo_v5.py b/secop/protocol/encoding.py similarity index 91% rename from secop/protocol/encoding/demo_v5.py rename to secop/protocol/encoding.py index 710a942..211ba49 100644 --- a/secop/protocol/encoding/demo_v5.py +++ b/secop/protocol/encoding.py @@ -26,20 +26,37 @@ from __future__ import print_function -#from secop.lib.parsing import format_time -from secop.protocol.encoding import MessageEncoder -from secop.protocol.messages import * -#from secop.protocol.errors import ProtocolError -import ast +# Base class +class MessageEncoder(object): + """en/decode a single Messageobject""" + + def encode(self, msg): + """encodes the given message object into a frame""" + raise NotImplementedError + + def decode(self, encoded): + """decodes the given frame to a message object""" + raise NotImplementedError + + import re import json +#from secop.lib.parsing import format_time +from secop.protocol.messages import Value, IdentifyRequest, IdentifyReply, \ + DescribeRequest, DescribeReply, ActivateRequest, ActivateReply, \ + DeactivateRequest, DeactivateReply, CommandRequest, CommandReply, \ + WriteRequest, WriteReply, PollRequest, HeartbeatRequest, HeartbeatReply, \ + ErrorMessage, HelpMessage +#from secop.protocol.errors import ProtocolError + + # each message is like [ \space [ \space # ]] \lf # note: the regex allow <> for spec for testing only! -DEMO_RE = re.compile( +SECOP_RE = re.compile( r"""^(?P[\*\?\w]+)(?:\s(?P[\w:<>]+)(?:\s(?P.*))?)?$""", re.X) @@ -113,7 +130,7 @@ def encode_error_msg(emsg): ] -class DemoEncoder(MessageEncoder): +class SECoPEncoder(MessageEncoder): # map of msg to msgtype string as defined above. ENCODEMAP = { IdentifyRequest: (IDENTREQUEST, ), @@ -170,7 +187,7 @@ class DemoEncoder(MessageEncoder): DECODEMAP = { IDENTREQUEST: lambda spec, data: IdentifyRequest(), # handled specially, listed here for completeness - IDENTREPLY: lambda spec, data: IdentifyReply(encoded), + # IDENTREPLY: lambda spec, data: IdentifyReply(encoded), DESCRIPTIONSREQUEST: lambda spec, data: DescribeRequest(), DESCRIPTIONREPLY: lambda spec, data: DescribeReply(equipment_id=spec[0], description=data), ENABLEEVENTSREQUEST: lambda spec, data: ActivateRequest(), @@ -187,7 +204,8 @@ class DemoEncoder(MessageEncoder): HELPREQUEST: lambda spec, data: HelpMessage(), # HELPREPLY: lambda spec, data:None, # ignore this ERRORREPLY: lambda spec, data: ErrorMessage(errorclass=spec[0], errorinfo=data), - EVENT: lambda spec, data: Value(module=spec[0], parameter=spec[1], value=data[0], qualifiers=data[1] if len(data) > 1 else {}), + EVENT: lambda spec, data: Value(module=spec[0], parameter=spec[1], value=data[0], + qualifiers=data[1] if len(data) > 1 else {}), } def __init__(self, *args, **kwds): @@ -235,7 +253,7 @@ class DemoEncoder(MessageEncoder): def decode(self, encoded): # first check beginning - match = DEMO_RE.match(encoded) + match = SECOP_RE.match(encoded) if not match: print(repr(encoded), repr(IDENTREPLY)) if encoded == IDENTREPLY: # XXX:better just check the first 2 parts... @@ -277,7 +295,7 @@ class DemoEncoder(MessageEncoder): def tests(self): print("---- Testing encoding -----") - for msgclass, parts in sorted(self.ENCODEMAP.items()): + for msgclass in sorted(self.ENCODEMAP): print(msgclass) e = self.encode( msgclass( @@ -305,3 +323,10 @@ class DemoEncoder(MessageEncoder): print(self.encode(d)) print() print("---- Testing done -----") + + +ENCODERS = { + 'secop': SECoPEncoder, +} + +__ALL__ = ['ENCODERS'] diff --git a/secop/protocol/encoding/__init__.py b/secop/protocol/encoding/__init__.py deleted file mode 100644 index 1aa5e9c..0000000 --- a/secop/protocol/encoding/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# ***************************************************************************** -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later -# version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Module authors: -# Enrico Faulhaber -# -# ***************************************************************************** -"""Encoding/decoding Messages""" - -# implement as class as they may need some internal 'state' later on -# (think compressors) - -# Base classes - - -class MessageEncoder(object): - """en/decode a single Messageobject""" - - def encode(self, messageobj): - """encodes the given message object into a frame""" - raise NotImplemented - - def decode(self, frame): - """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 -from .demo_v5 import DemoEncoder as DemoEncoderV5 -from .text import TextEncoder -from .pickle import PickleEncoder -from .simplecomm import SCPEncoder - -ENCODERS = { - 'pickle': PickleEncoder, - 'text': TextEncoder, - 'demo_v2': DemoEncoderV2, - 'demo_v3': DemoEncoderV3, - 'demo_v4': DemoEncoderV4, - 'demo_v5': DemoEncoderV5, - 'demo': DemoEncoderV5, - 'scp': SCPEncoder, -} - -__ALL__ = ['ENCODERS'] diff --git a/secop/protocol/encoding/demo_v2.py b/secop/protocol/encoding/demo_v2.py deleted file mode 100644 index 3c42705..0000000 --- a/secop/protocol/encoding/demo_v2.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# ***************************************************************************** -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later -# version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Module authors: -# Enrico Faulhaber -# -# ***************************************************************************** -"""Encoding/decoding Messages""" - -# implement as class as they may need some internal 'state' later on -# (think compressors) - -from __future__ import print_function - -from secop.protocol.encoding import MessageEncoder -from secop.protocol import messages -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]*))?(?:\=(.*))?' -) - - -class DemoEncoder(MessageEncoder): - - def decode(sef, encoded): - # match [!][*|devicename][: *|paramname [: *|propname]] [=value] - match = DEMO_RE.match(encoded) - if match: - novalue, devname, pname, propname, assign = match.groups() - if assign: - print("parsing", assign,) - assign = parse_args(assign) - print("->", assign) - return messages.DemoRequest(novalue, devname, pname, propname, - assign) - return messages.HelpRequest() - - def encode(self, msg): - if isinstance(msg, messages.DemoReply): - return msg.lines - handler_name = '_encode_' + msg.__class__.__name__ - handler = getattr(self, handler_name, None) - if handler is None: - print("Handler %s not yet implemented!" % handler_name) - try: - args = dict((k, msg.__dict__[k]) for k in msg.ARGS) - result = handler(**args) - except Exception as e: - print("Error encoding %r with %r!" % (msg, handler)) - print(e) - return '~InternalError~' - return result - - 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): - return '~Error~ %r' % error - - def _encode_InternalError(self, error): - return '~InternalError~ %r' % error - - def _encode_ProtocollError(self, msgtype, msgname, msgargs): - return '~ProtocolError~ %s.%s.%r' % (msgtype, msgname, msgargs) - - def _encode_NoSuchModuleError(self, device): - return '~NoSuchModuleError~ %s' % device - - def _encode_NoSuchParamError(self, device, param): - return '~NoSuchParameterError~ %s:%s' % (device, param) - - def _encode_ParamReadonlyError(self, device, param): - return '~ParamReadOnlyError~ %s:%s' % (device, param) - - def _encode_NoSuchCommandError(self, device, command): - return '~NoSuchCommandError~ %s.%s' % (device, command) - - def _encode_CommandFailedError(self, device, command): - return '~CommandFailedError~ %s.%s' % (device, command) - - def _encode_InvalidParamValueError(self, device, param, value): - return '~InvalidValueForParamError~ %s:%s=%r' % (device, param, value) - - def _encode_HelpReply(self): - return [ - 'Help not yet implemented!', - 'ask Markus Zolliker about the protocol' - ] diff --git a/secop/protocol/encoding/demo_v3.py b/secop/protocol/encoding/demo_v3.py deleted file mode 100644 index 9e6e21c..0000000 --- a/secop/protocol/encoding/demo_v3.py +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# ***************************************************************************** -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later -# version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Module authors: -# Enrico Faulhaber -# -# ***************************************************************************** -"""Encoding/decoding Messages""" - -# implement as class as they may need some internal 'state' later on -# (think compressors) - -from __future__ import print_function - -from secop.protocol.encoding import MessageEncoder -from secop.protocol.messages import * -from secop.protocol.errors import ProtocolError - -import ast -import re - - -def floatify(s): - try: - return int(s) - except (ValueError, TypeError): - try: - return float(s) - except (ValueError, TypeError): - return s - - -def devspec(msg, result=''): - if isinstance(msg, Message): - devs = ','.join(msg.devs) - pars = ','.join(msg.pars) - props = ','.join(msg.props) - else: - devs = msg.dev - pars = msg.par - props = msg.prop - if devs: - result = '%s %s' % (result, devs) - if pars: - result = '%s:%s' % (result, pars) - if props: - result = '%s:%s' % (result, props) - return result.strip() - - -def encode_value(value, prefix='', targetvalue='', cmd=''): - result = [prefix] - if value.dev: - result.append(' ') - result.append(value.dev) - if value.param: - result.append(':%s' % value.param) - if value.prop: - result.append(':%s' % value.prop) - # only needed for WriteMessages - if targetvalue: - result.append('=%s' % repr(targetvalue)) - # only needed for CommandMessages - if cmd: - result.append(':%s' % cmd) - if value.value != Ellipsis: - # results always have a ';' - result.append('=%s;' % repr(value.value)) - result.append(';'.join('%s=%s' % (qn, repr(qv)) - for qn, qv in value.qualifiers.items())) - return ''.join(result).strip() - - -DEMO_RE_ERROR = re.compile( - r"""^error\s(?P\w+)\s(?P\w+)?(?:\s(?P\*|[\w,]+)(?:\:(?P\*|[\w,]+)(?:\:(?P\*|[\w,]+))?)?)?(?:(?:\=(?P[^=;\s"]*))|(?:\((?P[^\)]*)\)))?(?:\s"(?P[^"]*)")$""", - re.X) -DEMO_RE_OTHER = re.compile( - r"""^(?P\w+)(?:\s(?P\*|[\w,]+)(?:\:(?P\*|[\w,]+)(?:\:(?P\*|[\w,]+))?)?)?(?:(?:\=(?P[^=;]*))|(?::(?P\w+)\((?P[^\)]*)\)))?(?:=(?P[^;]+);(?P.*))?$""", - re.X) - - -class DemoEncoder(MessageEncoder): - - def __init__(self, *args, **kwds): - MessageEncoder.__init__(self, *args, **kwds) - self.result = [] # for decoding - self.expect_lines = 1 - # self.tests() - - def encode(self, msg): - """msg object -> transport layer message""" - # fun for Humans - if isinstance(msg, HelpMessage): - r = ['#5'] - r.append("help Try one of the following:") - r.append("help 'list' to query a list of modules") - r.append("help 'read ' to read a module") - r.append("help 'list ' to query a list of parameters") - r.append("help ... more to come") - return '\n'.join(r) - - if isinstance(msg, (ListMessage, SubscribeMessage, UnsubscribeMessage, - TriggerMessage)): - msgtype = msg.MSGTYPE - if msg.result: - if msg.devs: - # msg.result is always a list! - return "%s=%s" % (devspec(msg, msgtype), - ','.join(map(str, msg.result))) - return "%s=%s" % (msgtype, ','.join(map(str, msg.result))) - return devspec(msg, msgtype).strip() - - if isinstance(msg, (ReadMessage, PollMessage, EventMessage)): - msgtype = msg.MSGTYPE - result = [] - if len(msg.result or []) > 1: - result.append("#%d" % len(msg.result)) - for val in msg.result or []: - # encode 1..N replies - result.append(encode_value(val, msgtype)) - if not msg.result: - # encode a request (no results -> reply, else an error would - # have been sent) - result.append(devspec(msg, msgtype)) - return '\n'.join(result) - - if isinstance(msg, WriteMessage): - result = [] - if len(msg.result or []) > 1: - result.append("#%d" % len(msg.result)) - for val in msg.result or []: - # encode 1..N replies - result.append( - encode_value( - val, 'write', targetvalue=msg.target)) - if not msg.result: - # encode a request (no results -> reply, else an error would - # have been sent) - result.append('%s=%r' % (devspec(msg, 'write'), msg.target)) - return '\n'.join(result) - - if isinstance(msg, CommandMessage): - result = [] - if len(msg.result or []) > 1: - result.append("#%d" % len(msg.result)) - for val in msg.result or []: - # encode 1..N replies - result.append( - encode_value( - val, - 'command', - 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))) - return '\n'.join(result) - - if isinstance(msg, ErrorMessage): - return ('%s %s' % (devspec(msg, 'error %s' % msg.errortype), - msg.errorstring)).strip() - - return 'Can not handle object %r!' % msg - - def decode(self, encoded): - if encoded.startswith('#'): - # XXX: check if last message was complete - self.expect_lines = int(encoded[1:]) - if self.result: - # XXX: also flag an error? - self.result = [] - return None - - if encoded == '': - return HelpMessage() - # now decode the message and append to self.result - msg = self.decode_single_message(encoded) - if msg: - # XXX: check if messagetype is the same as the already existing, - # else error - self.result.append(msg) - else: - # XXX: flag an error? - return HelpMessage() - - self.expect_lines -= 1 - if self.expect_lines <= 0: - # reconstruct a multi-reply-message from the entries - # return the first message, but extend the result list first - # if there is only 1 message, just return this - res = self.result.pop(0) - while self.result: - m = self.result.pop(0) - res.result.append(m.result[0]) - self.expect_lines = 1 - return res - - # no complete message yet - return None - - def decode_single_message(self, encoded): - # just decode a single message line - - # 1) check for error msgs (more specific first) - m = DEMO_RE_ERROR.match(encoded) - if m: - return ErrorMessage(**m.groupdict()) - - # 2) check for 'normal' message - m = DEMO_RE_OTHER.match(encoded) - if m: - mgroups = m.groupdict() - msgtype = mgroups.pop('msgtype') - - # reformat devspec - def helper(stuff, sep=','): - if not stuff: - return [] - 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')) - - # sugar for listing stuff: - # map list -> list * - # map list x -> list x:* - # map list x:y -> list x:y:* - if msgtype == LIST: - if not devs: - devs = ['*'] - elif devs[0] != '*': - if not pars: - pars = ['*'] - elif pars[0] != '*': - if not props: - props = ['*'] - - # reformat cmdargs - args = ast.literal_eval(mgroups.pop('args') or '()') - if msgtype == COMMAND: - mgroups['args'] = args - - # reformat qualifiers - print(mgroups) - quals = dict( - qual.split('=', 1) - for qual in helper(mgroups.pop('qualifiers', ';'))) - - # reformat value - result = [] - readback = mgroups.pop('readback') - if readback or quals: - valargs = dict() - if devs: - valargs['dev'] = devs[0] - if pars: - valargs['par'] = pars[0] - if props: - valargs['prop'] = props[0] - result = [Value(floatify(readback), quals, **valargs)] - if msgtype == LIST and result: - result = [n.strip() for n in readback.split(',')] - - # construct messageobj - if msgtype in MESSAGE: - return MESSAGE[msgtype](devs=devs, - pars=pars, - props=props, - result=result, - **mgroups) - - 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', - ] - for m in testmsg: - print(repr(m)) - print(self.decode(m)) - print() - - -DEMO_RE_MZ = re.compile( - r"""^(?P[a-z]+)? # request type word (read/write/list/...) - \ ? # optional space - (?P[a-z][a-z0-9_]*)? # optional devicename - (?:\:(?P[a-z0-9_]*) # optional ':'+paramname - (?:\:(?P[a-z0-9_]*))?)? # optinal ':' + propname - (?:(?P[=\?])(?P[^;]+)(?:\;(?P.*))?)?$""", - re.X) - - -class DemoEncoder_MZ(MessageEncoder): - - def decode(sef, encoded): - m = DEMO_RE_MZ.match(encoded) - if m: - print("implement me !") - return HelpRequest() - - def encode(self, msg): - """msg object -> transport layer message""" - # fun for Humans - if isinstance(msg, HelpReply): - r = [] - r.append("Try one of the following:") - r.append("'list' to query a list of modules") - r.append("'read ' to read a module") - r.append("'list ' to query a list of parameters") - r.append("... more to come") - return '\n'.join(r) - - return { - ListModulesRequest: lambda msg: "list", - ListModulesReply: lambda msg: "list=%s" % ','.join(sorted(msg.list_of_devices)), - GetVersionRequest: lambda msg: "version", - GetVersionReply: lambda msg: "version=%r" % msg.version, - ListModuleParamsRequest: lambda msg: "list %s" % msg.device, - # do not include a '.' as param name! - ListModuleParamsReply: lambda msg: "list %s=%s" % (msg.device, ','.join(sorted(msg.params.keys()))), - ReadValueRequest: lambda msg: "read %s" % msg.device, - ReadValueReply: lambda msg: "read %s=%r" % (msg.device, msg.value), - WriteValueRequest: lambda msg: "write %s=%r" % (msg.device, msg.value), - WriteValueReply: lambda msg: "write %s=%r" % (msg.device, msg.readback_value), - ReadParamRequest: lambda msg: "read %s:%s" % (msg.device, msg.param), - ReadParamReply: lambda msg: "read %s:%s=%r" % (msg.device, msg.param, msg.value), - WriteParamRequest: lambda msg: "write %s:%s=%r" % (msg.device, msg.param, msg.value), - WriteParamReply: lambda msg: "write %s:%s=%r" % (msg.device, msg.param, msg.readback_value), - # extensions - ReadAllModulesRequest: lambda msg: "", - ReadAllModulesReply: lambda msg: "", - ListParamPropsRequest: lambda msg: "readprop %s:%s" % (msg.device, msg.param), - ListParamPropsReply: lambda msg: ["readprop %s:%s" % (msg.device, msg.param)] + ["%s:%s:%s=%s" % (msg.device, msg.param, k, v) for k, v in sorted(msg.props.items())], - ReadPropertyRequest: lambda msg: "readprop %s:%s:%s" % (msg.device, msg.param, msg.prop), - ReadPropertyReply: lambda msg: "readprop %s:%s:%s=%s" % (msg.device, msg.param, msg.prop, msg.value), - AsyncDataUnit: lambda msg: "", - SubscribeRequest: lambda msg: "subscribe %s:%s" % (msg.device, msg.param) if msg.param else ("subscribe %s" % msg.device), - SubscribeReply: lambda msg: "subscribe %s:%s" % (msg.device, msg.param) if msg.param else ("subscribe %s" % msg.device), - UnSubscribeRequest: lambda msg: "", - UnSubscribeReply: lambda msg: "", - CommandRequest: lambda msg: "command %s:%s" % (msg.device, msg.command), - CommandReply: lambda msg: "command %s:%s" % (msg.device, msg.command), - # errors - ErrorReply: lambda msg: "", - InternalError: lambda msg: "", - ProtocolError: lambda msg: "", - CommandFailedError: lambda msg: "error CommandError %s:%s %s" % (msg.device, msg.param, msg.error), - NoSuchCommandError: lambda msg: "error NoSuchCommand %s:%s" % (msg.device, msg.param, msg.error), - NoSuchModuleError: lambda msg: "error NoSuchModule %s" % msg.device, - NoSuchParamError: lambda msg: "error NoSuchParameter %s:%s" % (msg.device, msg.param), - ParamReadonlyError: lambda msg: "", - UnsupportedFeatureError: lambda msg: "", - InvalidParamValueError: lambda msg: "", - }[msg.__class__](msg) diff --git a/secop/protocol/encoding/demo_v4.py b/secop/protocol/encoding/demo_v4.py deleted file mode 100644 index 7592826..0000000 --- a/secop/protocol/encoding/demo_v4.py +++ /dev/null @@ -1,307 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# ***************************************************************************** -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later -# version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Module authors: -# Enrico Faulhaber -# -# ***************************************************************************** -"""Encoding/decoding Messages""" - -# implement as class as they may need some internal 'state' later on -# (think compressors) - -from __future__ import print_function - -from secop.lib.parsing import format_time -from secop.protocol.encoding import MessageEncoder -from secop.protocol.messages import * -#from secop.protocol.errors import ProtocolError - -import ast -import re -import json - -# each message is like [ \space [ \space -# ]] \lf - -# note: the regex allow <> for spec for testing only! -DEMO_RE = re.compile( - r"""^(?P[\*\?\w]+)(?:\s(?P[\w:<>]+)(?:\s(?P.*))?)?$""", - re.X) - -#""" -# messagetypes: -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,V2017-01-25,rc1' -DESCRIPTIONSREQUEST = 'describe' # literal -DESCRIPTIONREPLY = 'describing' # + +json -ENABLEEVENTSREQUEST = 'activate' # literal -ENABLEEVENTSREPLY = 'active' # literal, is end-of-initial-data-transfer -DISABLEEVENTSREQUEST = 'deactivate' # literal -DISABLEEVENTSREPLY = 'inactive' # literal -COMMANDREQUEST = 'do' # +module:command +json args (if needed) -# +module:command +json args (if needed) # send after the command finished ! -COMMANDREPLY = 'done' -# +module[:parameter] +json_value -> NO direct reply, calls TRIGGER internally! -WRITEREQUEST = 'change' -# +module[:parameter] +json_value # send with the read back value -WRITEREPLY = 'changed' -# +module[:parameter] -> NO direct reply, calls TRIGGER internally! -TRIGGERREQUEST = 'read' -EVENT = 'update' # +module[:parameter] +json_value (value, qualifiers_as_dict) -HEARTBEATREQUEST = 'ping' # +nonce_without_space -HEARTBEATREPLY = 'pong' # +nonce_without_space -ERRORREPLY = 'error' # +errorclass +json_extended_info -HELPREQUEST = 'help' # literal -HELPREPLY = 'helping' # +line number +json_text -ERRORCLASSES = [ - 'NoSuchModule', - '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 - - -def encode_cmd_result(msgobj): - q = msgobj.qualifiers.copy() - if 't' in q: - q['t'] = format_time(q['t']) - return msgobj.result, q - - -def encode_value_data(vobj): - q = vobj.qualifiers.copy() - if 't' in q: - q['t'] = format_time(q['t']) - return vobj.value, q - - -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') - ] - - -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', ), - 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, ), - } - DECODEMAP = { - IDENTREQUEST: lambda spec, data: IdentifyRequest(), - # handled specially, listed here for completeness - IDENTREPLY: lambda spec, data: IdentifyReply(encoded), - DESCRIPTIONSREQUEST: lambda spec, data: DescribeRequest(), - DESCRIPTIONREPLY: lambda spec, data: DescribeReply(equipment_id=spec[0], description=data), - ENABLEEVENTSREQUEST: lambda spec, data: ActivateRequest(), - ENABLEEVENTSREPLY: lambda spec, data: ActivateReply(), - DISABLEEVENTSREQUEST: lambda spec, data: DeactivateRequest(), - DISABLEEVENTSREPLY: lambda spec, data: DeactivateReply(), - COMMANDREQUEST: lambda spec, data: CommandRequest(module=spec[0], command=spec[1], arguments=data), - COMMANDREPLY: lambda spec, data: CommandReply(module=spec[0], command=spec[1], result=data), - WRITEREQUEST: lambda spec, data: WriteRequest(module=spec[0], parameter=spec[1], value=data), - WRITEREPLY: lambda spec, data: WriteReply(module=spec[0], parameter=spec[1], value=data), - TRIGGERREQUEST: lambda spec, data: PollRequest(module=spec[0], parameter=spec[1]), - HEARTBEATREQUEST: lambda spec, data: HeartbeatRequest(nonce=spec[0]), - HEARTBEATREPLY: lambda spec, data: HeartbeatReply(nonce=spec[0]), - HELPREQUEST: lambda spec, data: HelpMessage(), - # HELPREPLY: lambda spec, data:None, # ignore this - ERRORREPLY: lambda spec, data: ErrorMessage(errorclass=spec[0], errorinfo=data), - EVENT: lambda spec, data: Value(module=spec[0], parameter=spec[1], value=data[0], qualifiers=data[1] if len(data) > 1 else {}), - } - - def __init__(self, *args, **kwds): - MessageEncoder.__init__(self, *args, **kwds) - # self.tests() - - def encode(self, msg): - """msg object -> transport layer message""" - # fun for Humans - if isinstance(msg, HelpMessage): - text = """Try one of the following: - '%s' to query protocol version - '%s' to read the description - '%s [:]' to request reading a value - '%s [:] value' to request changing a value - '%s [:()]' to execute a command - '%s ' to request a heartbeat response - '%s' to activate async updates - '%s' to deactivate updates - """ % (IDENTREQUEST, DESCRIPTIONSREQUEST, TRIGGERREQUEST, - WRITEREQUEST, COMMANDREQUEST, HEARTBEATREQUEST, - ENABLEEVENTSREQUEST, DISABLEEVENTSREQUEST) - return '\n'.join('%s %d %s' % (HELPREPLY, i + 1, l.strip()) - for i, l in enumerate(text.split('\n')[:-1])) - if isinstance(msg, HeartbeatRequest): - if msg.nonce: - return 'ping %s' % msg.nonce - return 'ping' - if isinstance(msg, HeartbeatReply): - if msg.nonce: - return 'pong %s' % msg.nonce - return 'pong' - 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:] - ] - if len(parts) > 1: - parts[1] = str(parts[1]) - if len(parts) == 3: - parts[2] = json.dumps(parts[2]) - return ' '.join(parts) - - def decode(self, encoded): - # first check beginning - match = DEMO_RE.match(encoded) - if not match: - print(repr(encoded), repr(IDENTREPLY)) - if encoded == IDENTREPLY: # XXX:better just check the first 2 parts... - return IdentifyReply(version_string=encoded) - - return HelpMessage() -# return ErrorMessage(errorclass='Protocol', -# errorinfo='Regex did not match!', -# 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) - - if msgtype in self.DECODEMAP: - if msgspec and ':' in msgspec: - msgspec = msgspec.split(':', 1) - else: - msgspec = (msgspec, None) - if data: - try: - data = json.loads(data) - except ValueError as err: - 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, - is_request=True, - origin=encoded) - - def tests(self): - print("---- Testing encoding -----") - for msgclass, parts in sorted(self.ENCODEMAP.items()): - print(msgclass) - e = self.encode( - msgclass( - module='', - parameter='', - value=2.718, - equipment_id='', - description='descriptive data', - command='', - arguments='', - nonce='', - errorclass='InternalError', - errorinfo='nix')) - print(e) - print(self.decode(e)) - print() - print("---- Testing decoding -----") - for msgtype, _ in sorted(self.DECODEMAP.items()): - msg = '%s a:b 3' % msgtype - if msgtype == EVENT: - msg = '%s a:b [3,{"t":193868}]' % msgtype - print(msg) - d = self.decode(msg) - print(d) - print(self.encode(d)) - print() - print("---- Testing done -----") diff --git a/secop/protocol/encoding/pickle.py b/secop/protocol/encoding/pickle.py deleted file mode 100644 index 351e093..0000000 --- a/secop/protocol/encoding/pickle.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# ***************************************************************************** -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later -# version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Module authors: -# Enrico Faulhaber -# -# ***************************************************************************** -"""Encoding/decoding Messages""" - -# implement as class as they may need some internal 'state' later on -# (think compressors) - -from secop.protocol.encoding import MessageEncoder -from secop.protocol import messages -from secop.lib.parsing import * - -try: - import cPickle as pickle -except ImportError: - import pickle - - -class PickleEncoder(MessageEncoder): - - def encode(self, messageobj): - """msg object -> transport layer message""" - return pickle.dumps(messageobj) - - def decode(self, encoded): - """transport layer message -> msg object""" - return pickle.loads(encoded) diff --git a/secop/protocol/encoding/simplecomm.py b/secop/protocol/encoding/simplecomm.py deleted file mode 100644 index 13c7b68..0000000 --- a/secop/protocol/encoding/simplecomm.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# ***************************************************************************** -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later -# version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Module authors: -# Enrico Faulhaber -# -# ***************************************************************************** -"""Encoding/decoding Messages""" - -# implement as class as they may need some internal 'state' later on -# (think compressors) - -from secop.protocol.encoding import MessageEncoder -from secop.protocol.messages import * -from secop.lib.parsing import * - -import re -import ast - -SCPMESSAGE = re.compile( - r'^(?:(?P[0-9@])\ )?(?P[a-zA-Z0-9_\*]*)(?:/(?P[a-zA-Z0-9_\*]*))+(?P[-+=\?\ ])?(?P.*)' -) - - -class SCPEncoder(MessageEncoder): - - def encode(self, msg): - """msg object -> transport layer message""" - # fun for Humans - if isinstance(msg, HelpReply): - r = [] - r.append("Try one of the following:") - r.append("'/version?' to query the current version") - r.append("'/modules?' to query the list of modules") - r.append( - "'/parameters?' to query the list of params of a module" - ) - r.append("'/value?' to query the value of a module") - r.append("'/status?' to query the status of a module") - r.append("'/target=' to move a module") - r.append( - "replies copy the request and are prefixed with an errorcode:") - r.append( - "0=OK,3=NoSuchCommand,4=NosuchModule,5=NoSuchParam,6=SyntaxError,7=BadValue,8=Readonly,9=Forbidden,@=Async" - ) - r.append("extensions: @-prefix as error-code,") - r.append("'/+' subscribe all params of module") - r.append("'/+' subscribe a param of a module") - r.append("use '-' instead of '+' to unsubscribe") - r.append("'/commands?' list of commands") - r.append( - "'/@[possible args] execute command (ex. 'stop@')" - ) - return '\n'.join(r) - - return { - ListModulesRequest: lambda msg: "devices?", - ListModulesReply: lambda msg: "0 devices=" + repr(list(msg.list_of_devices)), - GetVersionRequest: lambda msg: "version?", - GetVersionReply: lambda msg: "0 version=%r" % msg.version, - ListModuleParamsRequest: lambda msg: "%s/parameters?" % msg.device, - ListModuleParamsReply: lambda msg: "0 %s/parameters=%r" % (msg.device, list(msg.params)), - ReadValueRequest: lambda msg: "%s/value?" % msg.device, - ReadValueReply: lambda msg: "0 %s/value?%r" % (msg.device, msg.value), - WriteValueRequest: lambda msg: "%s/value=%r" % (msg.device, msg.value), - WriteValueReply: lambda msg: "0 %s/value=%r" % (msg.device, msg.value), - ReadParamRequest: lambda msg: "%s/%s?" % (msg.device, msg.param), - ReadParamReply: lambda msg: "0 %s/%s?%r" % (msg.device, msg.param, msg.value), - WriteParamRequest: lambda msg: "%s/%s=%r" % (msg.device, msg.param, msg.value), - WriteParamReply: lambda msg: "0 %s/%s=%r" % (msg.device, msg.param, msg.readback_value), - # extensions - ReadAllModulesRequest: lambda msg: "*/value?", - ReadAllModulesReply: lambda msg: ["0 %s/value=%s" % (m.device, m.value) for m in msg.readValueReplies], - ListParamPropsRequest: lambda msg: "%s/%s/?" % (msg.device, msg.param), - ListParamPropsReply: lambda msg: ["0 %s/%s/%s" % (msg.device, msg.param, p) for p in msg.props], - AsyncDataUnit: lambda msg: "@ %s/%s=%r" % (msg.devname, msg.pname, msg.value), - SubscribeRequest: lambda msg: "%s/%s+" % (msg.devname, msg.pname), - # violates spec ! we would need the original request here.... - SubscribeReply: lambda msg: "0 / %r" % [repr(s) for s in msg.subscriptions], - UnSubscribeRequest: lambda msg: "%s/%s+" % (msg.devname, msg.pname), - # violates spec ! we would need the original request here.... - UnSubscribeReply: lambda msg: "0 / %r" % [repr(s) for s in msg.subscriptions], - # errors - # violates spec ! we would need the original request here.... - ErrorReply: lambda msg: "1 /%r" % msg.error, - # violates spec ! we would need the original request here.... - InternalError: lambda msg: "1 /%r" % msg.error, - # violates spec ! we would need the original request here.... - ProtocollError: lambda msg: "6 /%r" % msg.error, - # violates spec ! we would need the original request here.... - CommandFailedError: lambda msg: "1 %s/%s" % (msg.device, msg.command), - # violates spec ! we would need the original request here.... - NoSuchCommandError: lambda msg: "3 %s/%s" % (msg.device, msg.command), - # violates spec ! we would need the original request here.... - NoSuchModuleError: lambda msg: "4 %s/ %r" % (msg.device, msg.error), - # violates spec ! we would need the original request here.... - NoSuchParamError: lambda msg: "5 %s/%s %r" % (msg.device, msg.param, msg.error), - # violates spec ! we would need the original request here.... - ParamReadonlyError: lambda msg: "8 %s/%s %r" % (msg.device, msg.param, msg.error), - # violates spec ! we would need the original request here.... - UnsupportedFeatureError: lambda msg: "3 / %r" % msg.feature, - # violates spec ! we would need the original request here.... - InvalidParamValueError: lambda msg: "7 %s/%s=%r %r" % (msg.device, msg.param, msg.value, msg.error), - }[msg.__class__](msg) - - def decode(self, encoded): - """transport layer message -> msg object""" - match = SCPMESSAGE.match(encoded) - if not (match): - return HelpRequest() - err, dev, par, op, val = match.groups() - if val is not None: - try: - val = ast.literal_eval(val) - except Exception as e: - return SyntaxError('while decoding %r: %s' % (encoded, e)) - if err == '@': - # async - if op == '=': - return AsyncDataUnit(dev, par, val) - return ProtocolError("Asyncupdates must have op = '='!") - elif err is None: - # request - if op == '+': - # subscribe - if dev: - if par: - return SubscribeRequest(dev, par) - return SubscribeRequest(dev, '*') - if op == '-': - # unsubscribe - if dev: - if par: - return UnsubscribeRequest(dev, par) - return UnsubscribeRequest(dev, '*') - if op == '?': - if dev is None: - # 'server' commands - if par == 'devices': - return ListModulesRequest() - elif par == 'version': - return GetVersionRequest() - return ProtocolError() - if par == 'parameters': - return ListModuleParamsRequest(dev) - elif par == 'value': - return ReadValueRequest(dev) - elif dev == '*' and par == 'value': - return ReadAllModulesRequest() - else: - return ReadParamRequest(dev, par) - elif op == '=': - if dev and (par == 'value'): - return WriteValueRequest(dev, val) - if par.endswith('/') and op == '?': - return ListParamPropsRequest(dev, par) - return WriteParamRequest(dev, par, val) - elif err == '0': - # reply - if dev == '': - if par == 'devices': - return ListModulesReply(val) - elif par == 'version': - return GetVersionReply(val) - return ProtocolError(encoded) - if par == 'parameters': - return ListModuleParamsReply(dev, val) - if par == 'value': - if op == '?': - return ReadValueReply(dev, val) - elif op == '=': - return WriteValueReply(dev, val) - return ProtocolError(encoded) - if op == '+': - return SubscribeReply(ast.literal_eval(dev)) - if op == '-': - return UnSubscribeReply(ast.literal_eval(dev)) - if op == '?': - return ReadParamReply(dev, par, val) - if op == '=': - return WriteParamReply(dev, par, val) - return ProtocolError(encoded) - else: - # error - if err in ('1', '2'): - return InternalError(encoded) - elif err == '3': - return NoSuchCommandError(dev, par) - elif err == '4': - return NoSuchModuleError(dev, encoded) - elif err == '5': - return NoSuchParamError(dev, par, val) - elif err == '7': - return InvalidParamValueError(dev, par, val, encoded) - elif err == '8': - return ParamReadonlyError(dev, par, encoded) - else: # err == 6 or other stuff - return ProtocollError(encoded) diff --git a/secop/protocol/encoding/text.py b/secop/protocol/encoding/text.py deleted file mode 100644 index 41b4647..0000000 --- a/secop/protocol/encoding/text.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# ***************************************************************************** -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later -# version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# Module authors: -# Enrico Faulhaber -# -# ***************************************************************************** -"""Encoding/decoding Messages""" - -# implement as class as they may need some internal 'state' later on -# (think compressors) - -from secop.protocol.encoding import MessageEncoder -from secop.protocol import messages -from secop.lib.parsing import * - - -class TextEncoder(MessageEncoder): - - def __init__(self): - # build safe namespace - ns = dict() - for n in dir(messages): - if n.endswith(('Request', 'Reply')): - ns[n] = getattr(messages, n) - self.namespace = ns - - def encode(self, messageobj): - """msg object -> transport layer message""" - # fun for Humans - if isinstance(messageobj, messages.HelpMessage): - return "Error: try one of the following requests:\n" + \ - '\n'.join(['%s(%s)' % (getattr(messages, m).__name__, - ', '.join(getattr(messages, m).ARGS)) - for m in dir(messages) - if m.endswith('Request') and len(m) > len("Request")]) - res = [] - for k in messageobj.ARGS: - res.append('%s=%r' % (k, getattr(messageobj, k, None))) - result = '%s(%s)' % (messageobj.__class__.__name__, ', '.join(res)) - return result - - def decode(self, encoded): - """transport layer message -> msg object""" - # WARNING: highly unsafe! - # think message='import os\nos.unlink('\')\n' - try: - return eval(encoded, self.namespace, {}) - except SyntaxError: - return messages.HelpMessage()