connectors/PYRO/__init__.py
changeset 3884 34da877021d5
parent 3883 a6e7dd8bac36
child 3885 22a009561502
equal deleted inserted replaced
3883:a6e7dd8bac36 3884:34da877021d5
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 # This file is part of Beremiz, a Integrated Development Environment for
       
     5 # programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
       
     6 #
       
     7 # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
       
     8 #
       
     9 # See COPYING file for copyrights details.
       
    10 #
       
    11 # This program is free software; you can redistribute it and/or
       
    12 # modify it under the terms of the GNU General Public License
       
    13 # as published by the Free Software Foundation; either version 2
       
    14 # of the License, or (at your option) any later version.
       
    15 #
       
    16 # This program is distributed in the hope that it will be useful,
       
    17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    19 # GNU General Public License for more details.
       
    20 #
       
    21 # You should have received a copy of the GNU General Public License
       
    22 # along with this program; if not, write to the Free Software
       
    23 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
       
    24 
       
    25 
       
    26 from time import sleep
       
    27 import copy
       
    28 import socket
       
    29 import os.path
       
    30 
       
    31 import Pyro5
       
    32 import Pyro5.client
       
    33 import Pyro5.errors
       
    34 
       
    35 # TODO: PSK
       
    36 
       
    37 import importlib
       
    38 
       
    39 
       
    40 Pyro5.config.SERIALIZER = "msgpack"
       
    41 
       
    42 
       
    43 def PYRO_connector_factory(uri, confnodesroot):
       
    44     """
       
    45     This returns the connector to Pyro style PLCobject
       
    46     """
       
    47     confnodesroot.logger.write(_("PYRO connecting to URI : %s\n") % uri)
       
    48 
       
    49     scheme, location = uri.split("://")
       
    50 
       
    51     # TODO: use ssl
       
    52 
       
    53     schemename = "PYRO"
       
    54 
       
    55     # Try to get the proxy object
       
    56     try:
       
    57         RemotePLCObjectProxy = Pyro5.client.Proxy(f"{schemename}:PLCObject@{location}")
       
    58     except Exception as e:
       
    59         confnodesroot.logger.write_error(
       
    60             _("Connection to {loc} failed with exception {ex}\n").format(
       
    61                 loc=location, ex=str(e)))
       
    62         return None
       
    63 
       
    64     RemotePLCObjectProxy._pyroTimeout = 60
       
    65 
       
    66     class MissingCallException(Exception):
       
    67         pass
       
    68 
       
    69     def PyroCatcher(func, default=None):
       
    70         """
       
    71         A function that catch a Pyro exceptions, write error to logger
       
    72         and return default value when it happen
       
    73         """
       
    74         def catcher_func(*args, **kwargs):
       
    75             try:
       
    76                 return func(*args, **kwargs)
       
    77             except Pyro5.errors.ConnectionClosedError as e:
       
    78                 confnodesroot._SetConnector(None)
       
    79                 confnodesroot.logger.write_error(_("Connection lost!\n"))
       
    80             except Pyro5.errors.ProtocolError as e:
       
    81                 confnodesroot.logger.write_error(_("Pyro exception: %s\n") % e)
       
    82             except MissingCallException as e:
       
    83                 confnodesroot.logger.write_warning(_("Remote call not supported: %s\n") % e.message)
       
    84             except Exception as e:
       
    85                 errmess = ''.join(Pyro5.errors.get_pyro_traceback())
       
    86                 confnodesroot.logger.write_error(errmess + "\n")
       
    87                 print(errmess)
       
    88                 confnodesroot._SetConnector(None)
       
    89             return default
       
    90         return catcher_func
       
    91 
       
    92     # Check connection is effective.
       
    93     # lambda is for getattr of GetPLCstatus to happen inside catcher
       
    94     IDPSK = PyroCatcher(RemotePLCObjectProxy.GetPLCID)()
       
    95     if IDPSK is None:
       
    96         confnodesroot.logger.write_warning(_("PLC did not provide identity and security infomation.\n"))
       
    97     else:
       
    98         ID, secret = IDPSK
       
    99         PSK.UpdateID(confnodesroot.ProjectPath, ID, secret, uri)
       
   100 
       
   101     class PyroProxyProxy(object):
       
   102         """
       
   103         A proxy proxy class to handle Beremiz Pyro interface specific behavior.
       
   104         And to put Pyro exception catcher in between caller and Pyro proxy
       
   105         """
       
   106         def __getattr__(self, attrName):
       
   107             member = self.__dict__.get(attrName, None)
       
   108             if member is None:
       
   109                 def my_local_func(*args, **kwargs):
       
   110                     call = RemotePLCObjectProxy.__getattr__(attrName)
       
   111                     if call is None:
       
   112                         raise MissingCallException(attrName)
       
   113                     else:
       
   114                         return call(*args, **kwargs)
       
   115                 member = PyroCatcher(my_local_func, self.PLCObjDefaults.get(attrName, None))
       
   116                 self.__dict__[attrName] = member
       
   117             return member
       
   118 
       
   119     return PyroProxyProxy