diff --git a/src/device.py b/src/device.py index ca5eb3a..5eeef94 100644 --- a/src/device.py +++ b/src/device.py @@ -1,11 +1,40 @@ +# -*- 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 +# +# ***************************************************************************** + +"""Define SECoP Device classes + +also define helpers to derive properties of the device""" + from lib import attrdict class Status(object): - OK = 200 - MOVING = 210 - WARN = 220 - UNSTABLE = 230 - ERROR = 240 + """Map Menaing of a devices status to some constants + + which may be used for transport""" + OK = 100 + MOVING = 200 + WARN = 300 + UNSTABLE = 350 + ERROR = 400 UNKNOWN = 999 status = Status() @@ -13,53 +42,64 @@ status = Status() # XXX: deriving PARS/CMDS should be done in a suitable metaclass.... class Device(object): + """Minimalist Device + + all others derive from this""" name = None def read_status(self): - raise NotImplemented + raise NotImplementedError('All Devices need a Status!') def read_name(self): return self.name class Readable(Device): + """A Readable Device""" unit = '' def read_value(self): - raise NotImplemented + raise NotImplementedError('A Readable MUST provide a value') def read_unit(self): return self.unit class Writeable(Readable): + """Writeable can be told to change it's vallue""" + target = None def read_target(self): return self.target def write_target(self, target): self.target = target class Driveable(Writeable): - def do_wait(self): - raise NotImplemented + """A Moveable which may take a while to reach its target, + + hence stopping it may be desired""" def do_stop(self): - raise NotImplemented + raise NotImplementedError('A Driveable MUST implement the STOP() ' + 'command') def get_device_pars(dev): - # returns a mapping of the devices parameter names to some 'description' + """return a mapping of the devices parameter names to some + 'description'""" res = {} for n in dir(dev): if n.startswith('read_'): pname = n[5:] - entry = attrdict(readonly=True, description=getattr(dev,n).__doc__) + entry = attrdict(readonly=True, description=getattr(dev, n).__doc__) if hasattr(dev, 'write_%s' % pname): entry['readonly'] = False res[pname] = entry return res - + def get_device_cmds(dev): - # returns a mapping of the devices commands names to some 'description' + """return a mapping of the devices command names to some + 'description'""" res = {} for n in dir(dev): if n.startswith('do_'): cname = n[5:] - func = getattr(dev,n) - entry = attrdict(description=func.__doc__, args='unknown') # XXX: use inspect! + func = getattr(dev, n) + # XXX: use inspect! + entry = attrdict(description=func.__doc__, args='unknown') res[cname] = entry return res - + diff --git a/src/lib.py b/src/lib.py index 6744947..3c3ecf3 100644 --- a/src/lib.py +++ b/src/lib.py @@ -1,50 +1,38 @@ +# -*- 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 +# +# ***************************************************************************** + +"""Define helpers""" class attrdict(dict): def __getattr__(self, key): return self[key] + def __setattr__(self, key, value): + self[key] = value if __name__ == '__main__': - print "minimal testing: transport" - testcases = dict( - error=[ErrorReply(), - NoSuchDeviceErrorReply('device3'), - NoSuchParamErrorReply('device2', 'param3'), - ParamReadonlyErrorReply('device1', 'param1'), - UnsupportedFeatureErrorReply('feature5'), - NoSuchCommandErrorReply('device1','fance_command'), - CommandFailedErrorReply('device1','stop'), - InvalidParamValueErrorReply('device1','param2','STRING_Value'), - ], - reply=[Reply(), - ListDevicesReply('device1', 'device2'), - ListDeviceParamsReply('device', ['param1', 'param2']), - ReadValueReply('device2', 3.1415), - ReadParamReply('device1', 'param2', 2.718), - WriteParamReply('device1', 'param2', 2.718), - RequestAsyncDataReply('device1', 'XXX: what to put here?'), - AsyncDataUnit('device1', 'param2', 2.718), - ListOfFeaturesReply('feature1', 'feature2'), - ActivateFeatureReply(), - ], - request=[Request(), - ListDevicesRequest(), - ListDeviceParamsRequest('device1'), - ReadValueRequest('device2'), - ReadParamRequest('device1', 'param2'), - WriteParamRequest('device1', 'param2', 2.718), - RequestAsyncDataRequest('device1', ['param1', 'param2']), - ListOfFeaturesRequest(), - ActivateFeatureRequest('feature1'), - ], - ) - for msgtype, msgs in testcases.items(): - print "___ testing %ss ___" % msgtype - for msg in msgs: - print msg.__class__.__name__, 'is', msgtype, - decoded = parse(msg) - if decoded[0] != msgtype: - print "\tFAIL, got %r but expected %r" %(decoded[0], msgtype) - else: - print "\tOk" - print + print "minimal testing: lib" + d = attrdict(a=1, b=2) + _ = d.a + d['b'] + d.c = 9 + d['d'] = 'c' + assert d[d.d] == 9 diff --git a/src/messages.py b/src/messages.py index 2faa1c4..02fb4d5 100644 --- a/src/messages.py +++ b/src/messages.py @@ -1,7 +1,33 @@ +# -*- 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 +# +# ***************************************************************************** + +"""Define SECoP Messages""" from lib import attrdict +import time +from device import get_device_pars, get_device_cmds class Request(object): + """Base class for all Requests""" pars = [] def __repr__(self): pars = ', '.join('%s=%r' % (k, self.__dict__[k]) for k in self.pars) @@ -9,6 +35,7 @@ class Request(object): return s class Reply(object): + """Base class for all Replies""" pars = [] def __repr__(self): pars = ', '.join('%s=%r' % (k, self.__dict__[k]) for k in self.pars) @@ -31,15 +58,16 @@ class ListDeviceParamsRequest(Request): self.device = device class ListDeviceParamsReply(Reply): - pars = ['device', 'params'] + pars = ['device', 'params'] def __init__(self, device, params): self.device = device self.params = params class ReadValueRequest(Request): - pars = ['device'] + pars = ['device', 'maxage'] def __init__(self, device, maxage=0): self.device = device + self.maxage = maxage class ReadValueReply(Reply): pars = ['device', 'value', 'timestamp', 'error', 'unit'] @@ -52,10 +80,11 @@ class ReadValueReply(Reply): class ReadParamRequest(Request): - pars = ['device', 'param'] + pars = ['device', 'param', 'maxage'] def __init__(self, device, param, maxage=0): self.device = device self.param = param + self.maxage = maxage class ReadParamReply(Reply): pars = ['device', 'param', 'value', 'timestamp', 'error', 'unit'] @@ -74,17 +103,18 @@ class WriteParamRequest(Request): self.device = device self.param = param self.value = value - + class WriteParamReply(Reply): pars = ['device', 'param', 'readback_value', 'timestamp', 'error', 'unit'] - def __init__(self, device, param, readback_value, timestamp=0, error=0, unit=None): + def __init__(self, device, param, readback_value, timestamp=0, error=0, + unit=None): self.device = device self.param = param self.readback_value = readback_value self.timestamp = timestamp self.error = error self.unit = unit - + class RequestAsyncDataRequest(Request): pars = ['device', 'params'] @@ -121,7 +151,7 @@ class ActivateFeatureReply(Reply): pass -Features = [ +FEATURES = [ 'Feature1', 'Feature2', 'Feature3', @@ -176,10 +206,77 @@ class InvalidParamValueErrorReply(ErrorReply): self.param = param self.value = value -class attrdict(dict): - def __getattr__(self, key): - return self[key] - +class MessageHandler(object): + """puts meaning to the request objects""" + def handle_ListDevices(self, msgargs): + return ListDevicesReply(self.listDevices()) + + def handle_ListDeviceParams(self, msgargs): + devobj = self.getDevice(msgargs.device) + if devobj: + return ListDeviceParamsReply(msgargs.device, + get_device_pars(devobj)) + else: + return NoSuchDeviceErrorReply(msgargs.device) + + def handle_ReadValue(self, msgargs): + devobj = self.getDevice(msgargs.device) + if devobj: + return ReadValueReply(msgargs.device, devobj.read_value(), + timestamp=time.time()) + else: + return NoSuchDeviceErrorReply(msgargs.device) + + def handle_ReadParam(self, msgargs): + devobj = self.getDevice(msgargs.device) + if devobj: + readfunc = getattr(devobj, 'read_%s' % msgargs.param, None) + if readfunc: + return ReadParamReply(msgargs.device, msgargs.param, + readfunc(), timestamp=time.time()) + else: + return NoSuchParamErrorReply(msgargs.device, msgargs.param) + else: + return NoSuchDeviceErrorReply(msgargs.device) + + def handle_WriteParam(self, msgargs): + devobj = self.getDevice(msgargs.device) + if devobj: + writefunc = getattr(devobj, 'write_%s' % msgargs.param, None) + if writefunc: + readbackvalue = writefunc(msgargs.value) or msgargs.value + return WriteParamReply(msgargs.device, msgargs.param, + readbackvalue, + timestamp=time.time()) + else: + if getattr(devobj, 'read_%s' % msgargs.param, None): + return ParamReadonlyErrorReply(msgargs.device, + msgargs.param) + else: + return NoSuchParamErrorReply(msgargs.device, + msgargs.param) + else: + return NoSuchDeviceErrorReply(msgargs.device) + + def handle_RequestAsyncData(self, msgargs): + return ErrorReply('AsyncData is not (yet) supported') + + def handle_ListOfFeatures(self, msgargs): + # no features supported (yet) + return ListOfFeaturesReply([]) + + def handle_ActivateFeature(self, msgargs): + return ErrorReply('Features are not (yet) supported') + + def unhandled(self, msgname, msgargs): + """handler for unhandled Messages + + (no handle_ method was defined) + """ + self.log.error('IGN: got unhandled request %s' % msgname) + return ErrorReply('Got Unhandled Request') + + def parse(message): # parses a message and returns # msgtype, msgname and parameters of message (as dict) @@ -197,39 +294,53 @@ def parse(message): return msgtype, msgname, \ attrdict([(k, getattr(message, k)) for k in message.pars]) - +__ALL__ = ['ErrorReply', + 'NoSuchDeviceErrorReply', 'NoSuchParamErrorReply' + 'ParamReadonlyErrorReply', 'UnsupportedFeatureErrorReply', + 'NoSuchCommandErrorReply', 'CommandFailedErrorReply', + 'InvalidParamValueErrorReply', + 'Reply', + 'ListDevicesReply', 'ListDeviceParamsReply', 'ReadValueReply', + 'ReadParamReply', 'WriteParamReply', 'RequestAsyncDataReply', + 'AsyncDataUnit', 'ListOfFeaturesReply', 'ActivateFeatureReply', + 'Request', + 'ListDevicesRequest', 'ListDeviceParamsRequest', 'ReadValueRequest', + 'ReadParamRequest', 'WriteParamRequest', 'RequestAsyncDataRequest', + 'ListOfFeaturesRequest', 'ActivateFeatureRequest', + 'parse', 'MessageHandler', +] if __name__ == '__main__': print "minimal testing: transport" testcases = dict( - error=[ErrorReply(), + error=[ErrorReply(), NoSuchDeviceErrorReply('device3'), - NoSuchParamErrorReply('device2', 'param3'), + NoSuchParamErrorReply('device2', 'param3'), ParamReadonlyErrorReply('device1', 'param1'), - UnsupportedFeatureErrorReply('feature5'), - NoSuchCommandErrorReply('device1','fance_command'), - CommandFailedErrorReply('device1','stop'), - InvalidParamValueErrorReply('device1','param2','STRING_Value'), + UnsupportedFeatureErrorReply('feature5'), + NoSuchCommandErrorReply('device1', 'fance_command'), + CommandFailedErrorReply('device1', 'stop'), + InvalidParamValueErrorReply('device1', 'param2', 'STRING_Value'), ], - reply=[Reply(), - ListDevicesReply('device1', 'device2'), - ListDeviceParamsReply('device', ['param1', 'param2']), - ReadValueReply('device2', 3.1415), - ReadParamReply('device1', 'param2', 2.718), - WriteParamReply('device1', 'param2', 2.718), - RequestAsyncDataReply('device1', 'XXX: what to put here?'), - AsyncDataUnit('device1', 'param2', 2.718), - ListOfFeaturesReply('feature1', 'feature2'), + reply=[Reply(), + ListDevicesReply('device1', 'device2'), + ListDeviceParamsReply('device', ['param1', 'param2']), + ReadValueReply('device2', 3.1415), + ReadParamReply('device1', 'param2', 2.718), + WriteParamReply('device1', 'param2', 2.718), + RequestAsyncDataReply('device1', '?what to put here?'), + AsyncDataUnit('device1', 'param2', 2.718), + ListOfFeaturesReply('feature1', 'feature2'), ActivateFeatureReply(), ], - request=[Request(), - ListDevicesRequest(), - ListDeviceParamsRequest('device1'), - ReadValueRequest('device2'), - ReadParamRequest('device1', 'param2'), - WriteParamRequest('device1', 'param2', 2.718), - RequestAsyncDataRequest('device1', ['param1', 'param2']), - ListOfFeaturesRequest(), + request=[Request(), + ListDevicesRequest(), + ListDeviceParamsRequest('device1'), + ReadValueRequest('device2'), + ReadParamRequest('device1', 'param2'), + WriteParamRequest('device1', 'param2', 2.718), + RequestAsyncDataRequest('device1', ['param1', 'param2']), + ListOfFeaturesRequest(), ActivateFeatureRequest('feature1'), ], ) diff --git a/src/server.py b/src/server.py index b780ec6..9fc4419 100644 --- a/src/server.py +++ b/src/server.py @@ -1,19 +1,43 @@ +# -*- 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 +# +# ***************************************************************************** + +"""Define basic SECoP DeviceServer""" import logging import time -from messages import * -from device import * +from messages import parse, ListDevicesRequest, ListDeviceParamsRequest, \ + ReadParamRequest, ErrorReply, MessageHandler -class DeviceServer(object): + +class DeviceServer(MessageHandler): def __init__(self): self._devices = {} self.log = logging - + self.log.basicConfig(level=logging.WARNING, format='%(asctime)s %(levelname)s %(message)s') - + def registerDevice(self, deviceobj, devicename): # make the server export a deviceobj under a given name. # all exportet properties are taken from the device @@ -22,23 +46,36 @@ class DeviceServer(object): else: self._devices[devicename] = deviceobj deviceobj.name = devicename - + def unRegisterDevice(self, device_obj_or_name): if not device_obj_or_name in self._devices: - self.log.error('IGN: Device %r not registered!' % device_obj_or_name) + self.log.error('IGN: Device %r not registered!' % + device_obj_or_name) else: del self._devices[device_obj_or_name] # may need to do more - + + def getDevice(self, devname): + """returns the requested deviceObj or None""" + devobj = self._devices.get(devname, None) + return devobj + + def listDevices(self): + return list(self._devices.keys()) + def handle(self, msg): # server got a message, handle it msgtype, msgname, msgargs = parse(msg) if msgtype != 'request': - self.log.error('IGN: Server only handles request, but got %s/%s!' % (msgtype, msgname)) + self.log.error('IGN: Server only handles request, but got %s/%s!' % + (msgtype, msgname)) return try: self.log.info('handling message %s with %r' % (msgname, msgargs)) - res = self._handle(msgname, msgargs) + handler = getattr(self, 'handle_%s' * msgname, None) + if handler is None: + handler = self.unhandled + res = handler(msgargs) self.log.info('replying with %r' % res) return res except Exception as err: @@ -46,91 +83,40 @@ class DeviceServer(object): self.log.info('replying with %r' % res) return res - def _handle(self, msgname, msgargs): - # check all supported Requests, act and return reply - self.log.debug('handling request %r' % msgname) - if msgname == 'ListDevices': - return ListDevicesReply(list(self._devices.keys())) - elif msgname == 'ListDeviceParams': - devobj = self._devices.get(msgargs.device, None) - if devobj: - return ListDeviceParamsReply(msgargs.device, get_device_pars(devobj)) - else: - return NoSuchDeviceErrorReply(msgargs.device) - elif msgname == 'ReadValue': - devobj = self._devices.get(msgargs.device, None) - if devobj: - return ReadValueReply(msgargs.device, devobj.read_value(), timestamp=time.time()) - else: - return NoSuchDeviceErrorReply(msgargs.device) - elif msgname == 'ReadParam': - devobj = self._devices.get(msgargs.device, None) - if devobj: - readfunc = getattr(devobj, 'read_%s' % msgargs.param, None) - if readfunc: - return ReadParamReply(msgargs.device, msgargs.param, readfunc(), timestamp=time.time()) - else: - return NoSuchParamErrorReply(msgargs.device, msgargs.param) - else: - return NoSuchDeviceErrorReply(msgargs.device) - elif msgname == 'WriteParam': - devobj = self._devices.get(msgargs.device, None) - if devobj: - writefunc = getattr(devobj, 'write_%s' % msgargs.param, None) - if writefunc: - return WriteParamReply(msgargs.device, msgargs.param, writefunc(msgargs.value) or msgargs.value, timestamp=time.time()) - else: - if getattr(devobj, 'read_%s' % msgargs.param, None): - return ParamReadonlyErrorReply(msgargs.device, msgargs.param) - else: - return NoSuchParamErrorReply(msgargs.device, msgargs.param) - else: - - return NoSuchDeviceErrorReply(msgargs.device) - elif msgname == 'RequestAsyncData': - return ErrorReply('AsyncData is not (yet) supported') - elif msgname == 'ListOfFeatures': - return ListOfFeaturesReply([]) - elif msgname == 'ActivateFeature': - return ErrorReply('Features are not (yet) supported') - else: - self.log.error('IGN: got unhandled request %s' % msgname) - return ErrorReply('Got Unhandled Request') - - -class TestDevice(Driveable): - name = 'Unset' - unit = 'Oinks' - def read_status(self): - return status.OK - def read_value(self): - """The devices main value""" - return 3.1415 - def read_testpar1(self): - return 2.718 - def read_fail(self): - raise KeyError() - def read_none(self): - pass -# def read_NotImplemented(self): -# raise NotImplemented() - def do_wait(self): - time.sleep(3) - def do_stop(self): - pass - def do_count(self): - print "counting:" - for d in range(10-1,-1,-1): - print '%d', - time.sleep(1) - print - def do_add_args(self, arg1, arg2): - return arg1+arg2 - def do_return_stuff(self): - return [{a:1},(2,3)] - if __name__ == '__main__': + from device import Driveable, status + class TestDevice(Driveable): + name = 'Unset' + unit = 'Oinks' + def read_status(self): + return status.OK + def read_value(self): + """The devices main value""" + return 3.1415 + def read_testpar1(self): + return 2.718 + def read_fail(self): + raise KeyError() + def read_none(self): + pass + def read_NotImplemented(self): + raise NotImplementedError('funny errors should be transported') + def do_wait(self): + time.sleep(3) + def do_stop(self): + pass + def do_count(self): + print "counting:" + for d in range(10-1, -1, -1): + print '%d', + time.sleep(1) + print + def do_add_args(self, arg1, arg2): + return arg1 + arg2 + def do_return_stuff(self): + return [{'a':1}, (2, 3)] + print "minimal testing: server" srv = DeviceServer() srv.registerDevice(TestDevice(), 'dev1') @@ -143,15 +129,18 @@ if __name__ == '__main__': print '-has params: ', sorted(params.keys()) for p in sorted(params.keys()): pinfo = params[p] - if pinfo.readonly: + if pinfo.readonly: print ' - param %r is readonly' % p if pinfo.description: - print ' - param %r\'s description is: %r' % (p, pinfo.description) + print ' - param %r\'s description is: %r' % (p, + pinfo.description) else: print ' - param %r has no description' % p - replytype, replyname, rv = parse(srv.handle(ReadParamRequest(dev, p))) + replytype, replyname, rv = parse(srv.handle(ReadParamRequest(dev, + p))) if replytype == 'error': - print ' - reading param %r resulted in error/%s' %(p, replyname) + print ' - reading param %r resulted in error/%s' % (p, + replyname) else: print ' - param %r current value is %r' % (p, rv.value) print ' - param %r current unit is %r' % (p, rv.unit) diff --git a/src/transport.py b/src/transport.py index 20ae9fd..772dc79 100644 --- a/src/transport.py +++ b/src/transport.py @@ -27,7 +27,6 @@ import time import socket -import threading import SocketServer try: import cPickle as pickle @@ -55,8 +54,8 @@ def encodeMessageFrame(msg): def decodeMessageFrame(frame): """remove transport layer encapsulation/framing of messages""" if '\n' in frame: - # WARNING: ignores everything after first '\n' - return frame.split('\n', 1)[0] + # WARNING: ignores everything after first '\n' + return frame.split('\n', 1)[0] # invalid/incomplete frames return nothing here atm. return None @@ -78,8 +77,9 @@ class SECoPClient(object): def close(self): if not self._socket: raise Exception('%r is not connected!' % self) - self._socket.close(socket.SH_RDONLY) - self._socket.close(socket.SH_RDWR) + self._socket.shutdown(socket.SHUT_WR) + self._socket.shutdown(socket.SHUT_RDWR) + self._socket.close() self._socket = None def _sendRequest(self, request): @@ -93,7 +93,7 @@ class SECoPClient(object): rawdata = '' while True: data = self._socket.recv(MAX_MESSAGE_SIZE) - if not(data): + if not data: time.sleep(0.1) # XXX: needs timeout mechanism! continue @@ -101,7 +101,7 @@ class SECoPClient(object): msg = decodeMessageFrame(rawdata) if msg: return decodeMessage(msg) - + def _negotiateServerSettings(self): self._sendRequest(ListOfFeaturesRequest()) print self._recvReply() @@ -112,11 +112,11 @@ class SECoPRequestHandler(SocketServer.BaseRequestHandler): def handle(self): """handle a new tcp-connection""" # self.client_address - socket = self.request + mysocket = self.request frame = '' # start serving while True: - _frame = socket.recv(MAX_MESSAGE_SIZE) + _frame = mysocket.recv(MAX_MESSAGE_SIZE) if not _frame: time.sleep(0.1) continue @@ -125,19 +125,20 @@ class SECoPRequestHandler(SocketServer.BaseRequestHandler): if msg: requestObj = decodeMessage(msg) replyObj = self.handle_request(requestObj) - self.send(encodeMessageFrame(encodeMessage(replyObj))) + mysocket.send(encodeMessageFrame(encodeMessage(replyObj))) frame = '' def handle_request(self, requestObj): # XXX: handle connection/Server specific Requests # pass other (Device) requests to the DeviceServer return self.server.handle(requestObj) - + class SECoPServer(SocketServer.ThreadingTCPServer, DeviceServer): daemon_threads = False def startup_server(): - srv = SECoPServer(('localhost', DEF_PORT), SECoPRequestHandler, bind_and_activate=True) + srv = SECoPServer(('localhost', DEF_PORT), SECoPRequestHandler, + bind_and_activate=True) srv.serve_forever() srv.server_close()