# HG changeset patch # User Edouard Tisserant # Date 1423410654 -3600 # Node ID e8daabf2c438b83da8dfad1400eda28b74a18653 # Parent a68cd425325943e4adad323c07731738b563d4ea Runtime : Added PLCobject methods registring. IDE : Added WAMP connector. Still need some fixes diff -r a68cd4253259 -r e8daabf2c438 connectors/PYRO/__init__.py --- a/connectors/PYRO/__init__.py Thu Feb 05 23:32:31 2015 +0100 +++ b/connectors/PYRO/__init__.py Sun Feb 08 16:50:54 2015 +0100 @@ -37,7 +37,7 @@ """ This returns the connector to Pyro style PLCobject """ - confnodesroot.logger.write(_("Connecting to URI : %s\n")%uri) + confnodesroot.logger.write(_("PYRO connecting to URI : %s\n")%uri) servicetype, location = uri.split("://") if location.find(service_type) != -1: diff -r a68cd4253259 -r e8daabf2c438 connectors/WAMP/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/connectors/WAMP/__init__.py Sun Feb 08 16:50:54 2015 +0100 @@ -0,0 +1,146 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +#Copyright (C) 2015: Edouard TISSERANT +# +#See COPYING file for copyrights details. +# +#This library 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.1 of the License, or (at your option) any later version. +# +#This library 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 library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import sys, traceback +#from twisted.python import log +from twisted.internet import reactor, threads +from autobahn.twisted import wamp +from autobahn.twisted.websocket import WampWebSocketClientFactory, connectWS +from autobahn.wamp import types +from autobahn.wamp.exception import TransportLost +from autobahn.wamp.serializer import MsgPackSerializer +from threading import Thread, Event + +_WampSession = None +_ReactorThread = None +_WampSessionEvent = Event() + +class WampSession(wamp.ApplicationSession): + def onJoin(self, details): + global _WampSession + _WampSession = self + _WampSessionEvent.set() + print 'WAMP session joined for :', self.config.extra["ID"] + + def onLeave(self, details): + global _WampSession + _WampSessionEvent.clear() + _WampSession = None + print 'WAMP session left' + +PLCObjDefaults = { "StartPLC": False, + "GetTraceVariables" : ("Broken",None), + "GetPLCstatus" : ("Broken",None), + "RemoteExec" : (-1, "RemoteExec script failed!")} + +def WAMP_connector_factory(uri, confnodesroot): + """ + WAMP://127.0.0.1:12345/path#realm#ID + WAMPS://127.0.0.1:12345/path#realm#ID + """ + global _WampSession, _ReactorThread, _WampSessionEvent + + servicetype, location = uri.split("://") + urlpath, realm, ID = location.split('#') + urlprefix = {"WAMP":"ws", + "WAMPS":"wss"}[servicetype] + url = urlprefix+"://"+urlpath + + def RegisterWampClient(): + + ## start logging to console + # log.startLogging(sys.stdout) + + # create a WAMP application session factory + component_config = types.ComponentConfig( + realm = realm, + extra = {"ID":ID}) + session_factory = wamp.ApplicationSessionFactory( + config = component_config) + session_factory.session = WampSession + + # create a WAMP-over-WebSocket transport client factory + transport_factory = WampWebSocketClientFactory( + session_factory, + url = url, + serializers = [MsgPackSerializer()], + debug = False, + debug_wamp = False) + + # start the client from a Twisted endpoint + conn = connectWS(transport_factory) + confnodesroot.logger.write(_("WAMP connecting to URL : %s\n")%url) + return conn + + def WampSessionProcMapper(funcname): + def catcher_func(*args,**kwargs): + if _WampSession is not None : + try: + return threads.blockingCallFromThread( + reactor, _WampSession.call, funcname, + *args,**kwargs) + except TransportLost, e: + confnodesroot.logger.write_error("Connection lost!\n") + confnodesroot._SetConnector(None) + except Exception,e: + errmess = traceback.format_exc() + confnodesroot.logger.write_error(errmess+"\n") + print errmess + #confnodesroot._SetConnector(None) + return PLCObjDefaults.get(funcname) + return catcher_func + + class WampPLCObjectProxy(object): + def __init__(self): + if not reactor.running: + def ThreadProc(): + self.connection = RegisterWampClient() + reactor.run(installSignalHandlers=False) + Thread(target=ThreadProc).start() + else: + self.connection = threads.blockingCallFromThread( + reactor, RegisterWampClient) + if not _WampSessionEvent.wait(5): + self.connection.stopConnecting() + raise Exception, _("WAMP connection timeout") + + def __del__(self): + self.connection.disconnect() + #reactor.Stop() + + def __getattr__(self, attrName): + member = self.__dict__.get(attrName, None) + if member is None: + member = WampSessionProcMapper(attrName) + self.__dict__[attrName] = member + return member + + # Try to get the proxy object + try : + return WampPLCObjectProxy() + except Exception, msg: + confnodesroot.logger.write_error(_("WAMP connection to '%s' failed.\n")%location) + confnodesroot.logger.write_error(traceback.format_exc()) + return None + + + + diff -r a68cd4253259 -r e8daabf2c438 connectors/__init__.py --- a/connectors/__init__.py Thu Feb 05 23:32:31 2015 +0100 +++ b/connectors/__init__.py Sun Feb 08 16:50:54 2015 +0100 @@ -30,9 +30,9 @@ def _GetLocalConnectorClassFactory(name): return lambda:getattr(__import__(name,globals(),locals()), name + "_connector_factory") -connectors = {name:_GetLocalConnectorClassFactory(name) - for name in listdir(_base_path) - if path.isdir(path.join(_base_path, name)) +connectors = {name:_GetLocalConnectorClassFactory(name) + for name in listdir(_base_path) + if path.isdir(path.join(_base_path, name)) and not name.startswith("__")} def ConnectorFactory(uri, confnodesroot): @@ -40,15 +40,23 @@ Return a connector corresponding to the URI or None if cannot connect to URI """ - servicetype = uri.split("://")[0] - if servicetype in connectors: - # import module according to uri type - connectorclass = connectors[servicetype]() - elif servicetype == "LOCAL": - from PYRO import PYRO_connector_factory as connectorclass - runtime_port = confnodesroot.AppFrame.StartLocalRuntime(taskbaricon=True) + servicetype = uri.split("://")[0].upper() + if servicetype == "LOCAL": + # Local is special case + # pyro connection to local runtime + # started on demand, listening on random port + servicetype = "PYRO" + runtime_port = confnodesroot.AppFrame.StartLocalRuntime( + taskbaricon=True) uri="PYRO://127.0.0.1:"+str(runtime_port) + elif servicetype in connectors: + pass + elif servicetype[-1]=='S' and servicetype[:-1] in connectors: + servicetype = servicetype[:-1] else : - return None + return None + + # import module according to uri type + connectorclass = connectors[servicetype]() return connectorclass(uri, confnodesroot) diff -r a68cd4253259 -r e8daabf2c438 runtime/PLCObject.py --- a/runtime/PLCObject.py Thu Feb 05 23:32:31 2015 +0100 +++ b/runtime/PLCObject.py Sun Feb 08 16:50:54 2015 +0100 @@ -447,7 +447,8 @@ last_md5 = open(self._GetMD5FileName(), "r").read() return last_md5 == MD5 except: - return False + pass + return False def SetTraceVariablesList(self, idxs): """ @@ -534,7 +535,7 @@ self._TracesFlush() - def RemoteExec(self, script, **kwargs): + def RemoteExec(self, script, *kwargs): try: exec script in kwargs except: diff -r a68cd4253259 -r e8daabf2c438 runtime/WampClient.py --- a/runtime/WampClient.py Thu Feb 05 23:32:31 2015 +0100 +++ b/runtime/WampClient.py Sun Feb 08 16:50:54 2015 +0100 @@ -2,38 +2,59 @@ # -*- coding: utf-8 -*- import sys -from twisted.python import log - -from twisted.internet import reactor, ssl +#from twisted.python import log from autobahn.twisted import wamp from autobahn.twisted.websocket import WampWebSocketClientFactory, connectWS +from twisted.internet.defer import inlineCallbacks from autobahn.wamp import types +from autobahn.wamp.serializer import MsgPackSerializer import json _WampSession = None _PySrv = None +ExposedCalls = ["StartPLC", + "StopPLC", + "ForceReload", + "GetPLCstatus", + "NewPLC", + "MatchMD5", + "SetTraceVariablesList", + "GetTraceVariables", + "RemoteExec", + "GetLogMessage", + ] + +def MakeCallee(name): + global _PySrv + def Callee(*args,**kwargs): + return getattr(_PySrv.plcobj, name)(*args,**kwargs) + return Callee + + class WampSession(wamp.ApplicationSession): + + @inlineCallbacks def onJoin(self, details): global _WampSession _WampSession = self print 'WAMP session joined by :', self.config.extra["ID"] + for name in ExposedCalls: + reg = yield self.register(MakeCallee(name), name) def onLeave(self, details): global _WampSession _WampSession = None print 'WAMP session left' - def RegisterWampClient(wampconf): WSClientConf = json.load(open(wampconf)) - ## TODO log to PLC console instead - ## 0) start logging to console - log.startLogging(sys.stdout) + ## start logging to console + # log.startLogging(sys.stdout) - ## 1) create a WAMP application session factory + # create a WAMP application session factory component_config = types.ComponentConfig( realm = WSClientConf["realm"], extra = {"ID":WSClientConf["ID"]}) @@ -41,27 +62,17 @@ config = component_config) session_factory.session = WampSession - ## TODO select optimum serializer for passing session lists - ## optional: use specific set of serializers - #from autobahn.wamp.serializer import * - #serializers = [] - ##serializers.append(JsonSerializer(batched = True)) - ##serializers.append(MsgPackSerializer(batched = True)) - #serializers.append(JsonSerializer()) - ##serializers.append(MsgPackSerializer()) - serializers = None - - ## 2) create a WAMP-over-WebSocket transport client factory + # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory( session_factory, url = WSClientConf["url"], - serializers = serializers, + serializers = [MsgPackSerializer()], debug = False, debug_wamp = False) - ## 3) start the client from a Twisted endpoint + # start the client from a Twisted endpoint conn = connectWS(transport_factory) - print "WAMP clien connecting to :",WSClientConf["url"] + print "WAMP client connecting to :",WSClientConf["url"] return conn def GetSession(): diff -r a68cd4253259 -r e8daabf2c438 tests/wamp/.crossbar/config.json --- a/tests/wamp/.crossbar/config.json Thu Feb 05 23:32:31 2015 +0100 +++ b/tests/wamp/.crossbar/config.json Sun Feb 08 16:50:54 2015 +0100 @@ -34,7 +34,8 @@ "type": "tcp", "port": 8888 }, - "url": "ws://127.0.0.1:8888/" + "url": "ws://127.0.0.1:8888/", + "serializers" : ["msgpack"] } ] } diff -r a68cd4253259 -r e8daabf2c438 tests/wamp/beremiz.xml --- a/tests/wamp/beremiz.xml Thu Feb 05 23:32:31 2015 +0100 +++ b/tests/wamp/beremiz.xml Sun Feb 08 16:50:54 2015 +0100 @@ -1,4 +1,4 @@ - + diff -r a68cd4253259 -r e8daabf2c438 tests/wamp/plc.xml --- a/tests/wamp/plc.xml Thu Feb 05 23:32:31 2015 +0100 +++ b/tests/wamp/plc.xml Sun Feb 08 16:50:54 2015 +0100 @@ -1,7 +1,7 @@ - +