Runtime : Added PLCobject methods registring. IDE : Added WAMP connector. Still need some fixes
--- 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:
--- /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
+
+
+
+
--- 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)
--- 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:
--- 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():
--- 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"]
}
]
}
--- 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 @@
<?xml version='1.0' encoding='utf-8'?>
-<BeremizRoot xmlns:xsd="http://www.w3.org/2001/XMLSchema" URI_location="PYRO://127.0.0.1:3000">
+<BeremizRoot xmlns:xsd="http://www.w3.org/2001/XMLSchema" URI_location="WAMP://127.0.0.1:8888#Automation#wamptest">
<TargetType/>
</BeremizRoot>
--- 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 @@
<?xml version='1.0' encoding='utf-8'?>
<project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.plcopen.org/xml/tc6_0201">
<fileHeader companyName="Beremiz" productName="Beremiz" productVersion="1" creationDateTime="2015-02-05T11:44:55" contentDescription=" "/>
- <contentHeader name="WAMPTest" modificationDateTime="2015-02-05T13:45:38">
+ <contentHeader name="WAMPTest" modificationDateTime="2015-02-07T22:25:01">
<coordinateInfo>
<fbd>
<scaling x="0" y="0"/>