# This file is part of Beremiz, a Integrated Development Environment for
# programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
# Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
# See COPYING file for copyrights details.
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from __future__ import absolute_import
from __future__ import print_function
from functools import partial
from threading import Thread, Event
from six import text_type as text
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
_WampSessionEvent = Event()
class WampSession(wamp.ApplicationSession):
def onJoin(self, details):
print('WAMP session joined for :', self.config.extra["ID"])
def onLeave(self, details):
_WampSessionEvent.clear()
print('WAMP session left')
def _WAMP_connector_factory(cls, uri, confnodesroot):
WAMP://127.0.0.1:12345/path#realm#ID
WAMPS://127.0.0.1:12345/path#realm#ID
scheme, location = uri.split("://")
urlpath, realm, ID = location.split('#')
urlprefix = {"WAMP": "ws",
url = urlprefix+"://"+urlpath
def RegisterWampClient():
# start logging to console
# log.startLogging(sys.stdout)
# create a WAMP application session factory
component_config = types.ComponentConfig(
session_factory = wamp.ApplicationSessionFactory(
session_factory.session = cls
# create a WAMP-over-WebSocket transport client factory
transport_factory = WampWebSocketClientFactory(
serializers=[MsgPackSerializer()])
# start the client from a Twisted endpoint
conn = connectWS(transport_factory)
confnodesroot.logger.write(_("WAMP connecting to URL : %s\n") % url)
AddToDoBeforeQuit = confnodesroot.AppFrame.AddToDoBeforeQuit
_WampConnection = RegisterWampClient()
AddToDoBeforeQuit(reactor.stop)
reactor.run(installSignalHandlers=False)
class WampPLCObjectProxy(object):
Thread(target=ThreadProc).start()
_WampConnection = threads.blockingCallFromThread(
reactor, RegisterWampClient)
if not _WampSessionEvent.wait(5):
_WampConnection.stopConnecting()
raise Exception(_("WAMP connection timeout"))
_WampConnection.disconnect()
def WampSessionProcMapper(self, funcname):
wampfuncname = text('.'.join((ID, funcname)))
def catcher_func(*args, **kwargs):
if _WampSession is not None:
return threads.blockingCallFromThread(
reactor, _WampSession.call, wampfuncname,
confnodesroot.logger.write_error(_("Connection lost!\n"))
confnodesroot._SetConnector(None)
errmess = traceback.format_exc()
confnodesroot.logger.write_error(errmess+"\n")
# confnodesroot._SetConnector(None)
return self.PLCObjDefaults.get(funcname)
def __getattr__(self, attrName):
member = self.__dict__.get(attrName, None)
member = self.WampSessionProcMapper(attrName)
self.__dict__[attrName] = member
return WampPLCObjectProxy
WAMP_connector_factory = partial(_WAMP_connector_factory, WampSession)