connectors/PYRO/__init__.py
changeset 1455 4ba27ed51e48
parent 1441 826730e60407
child 1571 486f94a8032c
equal deleted inserted replaced
1454:29b02164e65d 1455:4ba27ed51e48
     1 #!/usr/bin/env python
     1 #!/usr/bin/env python
     2 # -*- coding: utf-8 -*-
     2 # -*- coding: utf-8 -*-
     3 #
     3 #
     4 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
     4 # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
     5 #
     5 #
     6 #See COPYING file for copyrights details.
     6 # See COPYING file for copyrights details.
     7 #
     7 #
     8 #This library is free software; you can redistribute it and/or
     8 # This library is free software; you can redistribute it and/or
     9 #modify it under the terms of the GNU General Public
     9 # modify it under the terms of the GNU General Public
    10 #License as published by the Free Software Foundation; either
    10 # License as published by the Free Software Foundation; either
    11 #version 2.1 of the License, or (at your option) any later version.
    11 # version 2.1 of the License, or (at your option) any later version.
    12 #
    12 #
    13 #This library is distributed in the hope that it will be useful,
    13 # This library is distributed in the hope that it will be useful,
    14 #but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
    15 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    16 #General Public License for more details.
    16 # General Public License for more details.
    17 #
    17 #
    18 #You should have received a copy of the GNU General Public
    18 # You should have received a copy of the GNU General Public
    19 #License along with this library; if not, write to the Free Software
    19 # License along with this library; if not, write to the Free Software
    20 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    21 import Pyro.core as pyro
    21 import Pyro
       
    22 import Pyro.core
       
    23 import Pyro.util
    22 from Pyro.errors import PyroError
    24 from Pyro.errors import PyroError
    23 import Pyro.util
       
    24 import traceback
    25 import traceback
    25 from time import sleep
    26 from time import sleep
    26 import copy
    27 import copy
    27 import socket
    28 import socket
    28 service_type = '_PYRO._tcp.local.'
    29 service_type = '_PYRO._tcp.local.'
    29 
    30 import os.path
    30 # this module attribute contains a list of DNS-SD (Zeroconf) service types
    31 # this module attribute contains a list of DNS-SD (Zeroconf) service types
    31 # supported by this connector confnode.
    32 # supported by this connector confnode.
    32 #
    33 #
    33 # for connectors that do not support DNS-SD, this attribute can be omitted
    34 # for connectors that do not support DNS-SD, this attribute can be omitted
    34 # or set to an empty list.
    35 # or set to an empty list.
    35 
    36 
    36 def PYRO_connector_factory(uri, confnodesroot):
    37 def PYRO_connector_factory(uri, confnodesroot):
    37     """
    38     """
    38     This returns the connector to Pyro style PLCobject
    39     This returns the connector to Pyro style PLCobject
    39     """
    40     """
    40     confnodesroot.logger.write(_("PYRO connecting to URI : %s\n")%uri)
    41     confnodesroot.logger.write(_("PYRO connecting to URI : %s\n") % uri)
    41 
    42 
    42     servicetype, location = uri.split("://")
    43     servicetype, location = uri.split("://")
       
    44     if servicetype == "PYROS":
       
    45         schemename = "PYROLOCSSL"
       
    46         # Protect against name->IP substitution in Pyro3
       
    47         Pyro.config.PYRO_DNS_URI = True
       
    48         # Beware Pyro lib need str path, not unicode
       
    49         # don't rely on PYRO_STORAGE ! see documentation
       
    50         Pyro.config.PYROSSL_CERTDIR = os.path.abspath(str(confnodesroot.ProjectPath) + '/certs')
       
    51         if not os.path.exists(Pyro.config.PYROSSL_CERTDIR):
       
    52             confnodesroot.logger.write_error(
       
    53                 'Error : the directory %s is missing for SSL certificates (certs_dir).'
       
    54                 'Please fix it in your project.\n' % Pyro.config.PYROSSL_CERTDIR)
       
    55             return None
       
    56         else:
       
    57             confnodesroot.logger.write(_("PYRO using certificates in '%s' \n")
       
    58                                        % (Pyro.config.PYROSSL_CERTDIR))
       
    59         Pyro.config.PYROSSL_CERT = "client.crt"
       
    60         Pyro.config.PYROSSL_KEY = "client.key"
       
    61         # Ugly Monkey Patching
       
    62         def _gettimeout(self):
       
    63             return self.timeout
       
    64 
       
    65         def _settimeout(self, timeout):
       
    66             self.timeout = timeout
       
    67         from M2Crypto.SSL import Connection
       
    68         Connection.timeout = None
       
    69         Connection.gettimeout = _gettimeout
       
    70         Connection.settimeout = _settimeout
       
    71         # M2Crypto.SSL.Checker.WrongHost: Peer certificate commonName does not
       
    72         # match host, expected 127.0.0.1, got server
       
    73         Connection.clientPostConnectionCheck = None
       
    74     else:
       
    75         schemename = "PYROLOC"
    43     if location.find(service_type) != -1:
    76     if location.find(service_type) != -1:
    44         try :
    77         try:
    45             from util.Zeroconf import Zeroconf
    78             from util.Zeroconf import Zeroconf
    46             r = Zeroconf()
    79             r = Zeroconf()
    47             i=r.getServiceInfo(service_type, location)
    80             i = r.getServiceInfo(service_type, location)
    48             if i is None : raise Exception, "'%s' not found"%location
    81             if i is None:
       
    82                 raise Exception("'%s' not found" % location)
    49             ip = str(socket.inet_ntoa(i.getAddress()))
    83             ip = str(socket.inet_ntoa(i.getAddress()))
    50             port = str(i.getPort())
    84             port = str(i.getPort())
    51             newlocation = ip+':'+port
    85             newlocation = ip + ':' + port
    52             confnodesroot.logger.write(_("'%s' is located at %s\n")%(location, newlocation))
    86             confnodesroot.logger.write(_("'%s' is located at %s\n") % (location, newlocation))
    53             location = newlocation
    87             location = newlocation
    54             r.close()
    88             r.close()
    55         except Exception, msg:
    89         except Exception, msg:
    56             confnodesroot.logger.write_error(_("MDNS resolution failure for '%s'\n")%location)
    90             confnodesroot.logger.write_error(_("MDNS resolution failure for '%s'\n") % location)
    57             confnodesroot.logger.write_error(traceback.format_exc())
    91             confnodesroot.logger.write_error(traceback.format_exc())
    58             return None
    92             return None
    59 
    93 
    60     # Try to get the proxy object
    94     # Try to get the proxy object
    61     try :
    95     try:
    62         RemotePLCObjectProxy = pyro.getAttrProxyForURI("PYROLOC://"+location+"/PLCObject")
    96         RemotePLCObjectProxy = Pyro.core.getAttrProxyForURI(schemename + "://" + location + "/PLCObject")
    63     except Exception, msg:
    97     except Exception, msg:
    64         confnodesroot.logger.write_error(_("Connection to '%s' failed.\n")%location)
    98         confnodesroot.logger.write_error(_("Connection to '%s' failed.\n") % location)
    65         confnodesroot.logger.write_error(traceback.format_exc())
    99         confnodesroot.logger.write_error(traceback.format_exc())
    66         return None
   100         return None
    67 
   101 
    68     def PyroCatcher(func, default=None):
   102     def PyroCatcher(func, default=None):
    69         """
   103         """
    70         A function that catch a pyro exceptions, write error to logger
   104         A function that catch a Pyro exceptions, write error to logger
    71         and return defaul value when it happen
   105         and return default value when it happen
    72         """
   106         """
    73         def catcher_func(*args,**kwargs):
   107         def catcher_func(*args, **kwargs):
    74             try:
   108             try:
    75                 return func(*args,**kwargs)
   109                 return func(*args, **kwargs)
    76             except Pyro.errors.ConnectionClosedError, e:
   110             except Pyro.errors.ConnectionClosedError, e:
    77                 confnodesroot.logger.write_error("Connection lost!\n")
   111                 confnodesroot.logger.write_error("Connection lost!\n")
    78                 confnodesroot._SetConnector(None)
   112                 confnodesroot._SetConnector(None)
    79             except Pyro.errors.ProtocolError, e:
   113             except Pyro.errors.ProtocolError, e:
    80                 confnodesroot.logger.write_error("Pyro exception: "+str(e)+"\n")
   114                 confnodesroot.logger.write_error("Pyro exception: " + str(e) + "\n")
    81             except Exception,e:
   115             except Exception, e:
    82                 #confnodesroot.logger.write_error(traceback.format_exc())
   116                 # confnodesroot.logger.write_error(traceback.format_exc())
    83                 errmess = ''.join(Pyro.util.getPyroTraceback(e))
   117                 errmess = ''.join(Pyro.util.getPyroTraceback(e))
    84                 confnodesroot.logger.write_error(errmess+"\n")
   118                 confnodesroot.logger.write_error(errmess + "\n")
    85                 print errmess
   119                 print errmess
    86                 confnodesroot._SetConnector(None)
   120                 confnodesroot._SetConnector(None)
    87             return default
   121             return default
    88         return catcher_func
   122         return catcher_func
    89 
   123 
    90     # Check connection is effective.
   124     # Check connection is effective.
    91     # lambda is for getattr of GetPLCstatus to happen inside catcher
   125     # lambda is for getattr of GetPLCstatus to happen inside catcher
    92     if PyroCatcher(lambda:RemotePLCObjectProxy.GetPLCstatus())() is None:
   126     if PyroCatcher(lambda: RemotePLCObjectProxy.GetPLCstatus())() is None:
    93         confnodesroot.logger.write_error(_("Cannot get PLC status - connection failed.\n"))
   127         confnodesroot.logger.write_error(_("Cannot get PLC status - connection failed.\n"))
    94         return None
   128         return None
    95 
       
    96 
   129 
    97     class PyroProxyProxy(object):
   130     class PyroProxyProxy(object):
    98         """
   131         """
    99         A proxy proxy class to handle Beremiz Pyro interface specific behavior.
   132         A proxy proxy class to handle Beremiz Pyro interface specific behavior.
   100         And to put pyro exception catcher in between caller and pyro proxy
   133         And to put Pyro exception catcher in between caller and Pyro proxy
   101         """
   134         """
   102         def __init__(self):
   135         def __init__(self):
   103             # for safe use in from debug thread, must create a copy
   136             # for safe use in from debug thread, must create a copy
   104             self.RemotePLCObjectProxyCopy = None
   137             self.RemotePLCObjectProxyCopy = None
   105 
   138 
   131                 confnodesroot._Connect()
   164                 confnodesroot._Connect()
   132             self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
   165             self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
   133             return confnodesroot._connector.GetPyroProxy().StartPLC(*args, **kwargs)
   166             return confnodesroot._connector.GetPyroProxy().StartPLC(*args, **kwargs)
   134         StartPLC = PyroCatcher(_PyroStartPLC, False)
   167         StartPLC = PyroCatcher(_PyroStartPLC, False)
   135 
   168 
   136 
       
   137         def _PyroGetTraceVariables(self):
   169         def _PyroGetTraceVariables(self):
   138             """
   170             """
   139             for safe use in from debug thread, must use the copy
   171             for safe use in from debug thread, must use the copy
   140             """
   172             """
   141             if self.RemotePLCObjectProxyCopy is None:
   173             if self.RemotePLCObjectProxyCopy is None:
   142                 self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
   174                 self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
   143             return self.RemotePLCObjectProxyCopy.GetTraceVariables()
   175             return self.RemotePLCObjectProxyCopy.GetTraceVariables()
   144         GetTraceVariables = PyroCatcher(_PyroGetTraceVariables,("Broken",None))
   176         GetTraceVariables = PyroCatcher(_PyroGetTraceVariables, ("Broken", None))
   145 
   177 
   146         def _PyroGetPLCstatus(self):
   178         def _PyroGetPLCstatus(self):
   147             return RemotePLCObjectProxy.GetPLCstatus()
   179             return RemotePLCObjectProxy.GetPLCstatus()
   148         GetPLCstatus = PyroCatcher(_PyroGetPLCstatus, ("Broken",None))
   180         GetPLCstatus = PyroCatcher(_PyroGetPLCstatus, ("Broken", None))
   149 
   181 
   150         def _PyroRemoteExec(self, script, **kwargs):
   182         def _PyroRemoteExec(self, script, **kwargs):
   151             return RemotePLCObjectProxy.RemoteExec(script, **kwargs)
   183             return RemotePLCObjectProxy.RemoteExec(script, **kwargs)
   152         RemoteExec = PyroCatcher(_PyroRemoteExec, (-1, "RemoteExec script failed!"))
   184         RemoteExec = PyroCatcher(_PyroRemoteExec, (-1, "RemoteExec script failed!"))
   153 
   185 
   154         def __getattr__(self, attrName):
   186         def __getattr__(self, attrName):
   155             member = self.__dict__.get(attrName, None)
   187             member = self.__dict__.get(attrName, None)
   156             if member is None:
   188             if member is None:
   157                 def my_local_func(*args,**kwargs):
   189                 def my_local_func(*args, **kwargs):
   158                     return RemotePLCObjectProxy.__getattr__(attrName)(*args,**kwargs)
   190                     return RemotePLCObjectProxy.__getattr__(attrName)(*args, **kwargs)
   159                 member = PyroCatcher(my_local_func, None)
   191                 member = PyroCatcher(my_local_func, None)
   160                 self.__dict__[attrName] = member
   192                 self.__dict__[attrName] = member
   161             return member
   193             return member
   162 
   194 
   163     return PyroProxyProxy()
   195     return PyroProxyProxy()
   164 
       
   165