connectors/PYRO/__init__.py
author Edouard Tisserant
Wed, 15 May 2013 17:13:49 +0900
changeset 1144 21475ee0e688
parent 1116 300f98a8d4c6
child 1434 6e0cd0ceabb7
permissions -rwxr-xr-x
Added stub code and declarations for bidirectional access to PLC globals from python code (untested)
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
     1
#!/usr/bin/env python
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
     2
# -*- coding: utf-8 -*-
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
     3
#
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
     4
#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
     5
#
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
     6
#See COPYING file for copyrights details.
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
     7
#
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
     8
#This library is free software; you can redistribute it and/or
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
     9
#modify it under the terms of the GNU General Public
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    10
#License as published by the Free Software Foundation; either
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    11
#version 2.1 of the License, or (at your option) any later version.
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    12
#
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    13
#This library is distributed in the hope that it will be useful,
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    14
#but WITHOUT ANY WARRANTY; without even the implied warranty of
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    15
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    16
#General Public License for more details.
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    17
#
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    18
#You should have received a copy of the GNU General Public
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    19
#License along with this library; if not, write to the Free Software
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    20
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    21
import Pyro.core as pyro
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    22
from Pyro.errors import PyroError
477
f66a092b6e74 Arbitrary variable forcing
Edouard TISSERANT <edouard.tisserant@gmail.com>
parents: 465
diff changeset
    23
import Pyro.util
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    24
import traceback
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    25
from time import sleep
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
    26
import copy
763
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    27
import socket
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    28
service_type = '_PYRO._tcp.local.'
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    29
399
77e23bf04c33 Merging some improvements from BCT
laurent
parents: 361
diff changeset
    30
# this module attribute contains a list of DNS-SD (Zeroconf) service types
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
    31
# supported by this connector confnode.
399
77e23bf04c33 Merging some improvements from BCT
laurent
parents: 361
diff changeset
    32
#
77e23bf04c33 Merging some improvements from BCT
laurent
parents: 361
diff changeset
    33
# for connectors that do not support DNS-SD, this attribute can be omitted
77e23bf04c33 Merging some improvements from BCT
laurent
parents: 361
diff changeset
    34
# or set to an empty list.
77e23bf04c33 Merging some improvements from BCT
laurent
parents: 361
diff changeset
    35
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
    36
def PYRO_connector_factory(uri, confnodesroot):
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    37
    """
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    38
    This returns the connector to Pyro style PLCobject
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    39
    """
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
    40
    confnodesroot.logger.write(_("Connecting to URI : %s\n")%uri)
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    41
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    42
    servicetype, location = uri.split("://")
763
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    43
    if location.find(service_type) != -1:
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    44
        try :
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    45
            from util.Zeroconf import Zeroconf
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    46
            r = Zeroconf()
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    47
            i=r.getServiceInfo(service_type, location)
1035
0f905e027d18 Better mdns resolution failure signaling, added fixed bug whith runtime autostart
Edouard Tisserant
parents: 969
diff changeset
    48
            if i is None : raise Exception, "'%s' not found"%location
763
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    49
            ip = str(socket.inet_ntoa(i.getAddress()))
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    50
            port = str(i.getPort())
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    51
            newlocation = ip+':'+port
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    52
            confnodesroot.logger.write(_("'%s' is located at %s\n")%(location, newlocation))
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    53
            location = newlocation
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    54
            r.close()
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    55
        except Exception, msg:
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    56
            confnodesroot.logger.write_error(_("MDNS resolution failure for '%s'\n")%location)
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    57
            confnodesroot.logger.write_error(traceback.format_exc())
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    58
            return None
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    59
    
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    60
    # Try to get the proxy object
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    61
    try :
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    62
        RemotePLCObjectProxy = pyro.getAttrProxyForURI("PYROLOC://"+location+"/PLCObject")
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    63
    except Exception, msg:
763
c1104099c151 Now, PYRO:// locations also accept MDNS service names
Edouard Tisserant
parents: 733
diff changeset
    64
        confnodesroot.logger.write_error(_("Connection to '%s' failed.\n")%location)
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
    65
        confnodesroot.logger.write_error(traceback.format_exc())
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    66
        return None
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    67
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    68
    def PyroCatcher(func, default=None):
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    69
        """
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    70
        A function that catch a pyro exceptions, write error to logger
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    71
        and return defaul value when it happen
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    72
        """
218
71fddab24be9 remove old code and fix typo
greg
parents: 203
diff changeset
    73
        def catcher_func(*args,**kwargs):
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    74
            try:
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    75
                return func(*args,**kwargs)
1116
300f98a8d4c6 Fixed bug connector not resetted when connection is lost
Laurent Bessard
parents: 1070
diff changeset
    76
            except Pyro.errors.ConnectionClosedError, e:
300f98a8d4c6 Fixed bug connector not resetted when connection is lost
Laurent Bessard
parents: 1070
diff changeset
    77
                confnodesroot.logger.write_error("Connection lost!\n")
300f98a8d4c6 Fixed bug connector not resetted when connection is lost
Laurent Bessard
parents: 1070
diff changeset
    78
                confnodesroot._SetConnector(None)
493
015a803301b9 Catch ProtocolError exception when connection failed
laurent
parents: 486
diff changeset
    79
            except Pyro.errors.ProtocolError, e:
1070
86ee833e33ef Added exception printing on Pyro connector, tracking random connection failure...
Edouard Tisserant
parents: 1035
diff changeset
    80
                confnodesroot.logger.write_error("Pyro exception: "+str(e)+"\n")
477
f66a092b6e74 Arbitrary variable forcing
Edouard TISSERANT <edouard.tisserant@gmail.com>
parents: 465
diff changeset
    81
            except Exception,e:
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
    82
                #confnodesroot.logger.write_error(traceback.format_exc())
477
f66a092b6e74 Arbitrary variable forcing
Edouard TISSERANT <edouard.tisserant@gmail.com>
parents: 465
diff changeset
    83
                errmess = ''.join(Pyro.util.getPyroTraceback(e))
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
    84
                confnodesroot.logger.write_error(errmess+"\n")
477
f66a092b6e74 Arbitrary variable forcing
Edouard TISSERANT <edouard.tisserant@gmail.com>
parents: 465
diff changeset
    85
                print errmess
1116
300f98a8d4c6 Fixed bug connector not resetted when connection is lost
Laurent Bessard
parents: 1070
diff changeset
    86
                confnodesroot._SetConnector(None)
1070
86ee833e33ef Added exception printing on Pyro connector, tracking random connection failure...
Edouard Tisserant
parents: 1035
diff changeset
    87
            return default
218
71fddab24be9 remove old code and fix typo
greg
parents: 203
diff changeset
    88
        return catcher_func
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    89
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    90
    # Check connection is effective. 
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    91
    # lambda is for getattr of GetPLCstatus to happen inside catcher
923
6ef6e0b3a908 Fixed crash (segfault) when logging debug messages
Edouard Tisserant
parents: 917
diff changeset
    92
    if PyroCatcher(lambda:RemotePLCObjectProxy.GetPLCstatus())() is None:
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
    93
        confnodesroot.logger.write_error(_("Cannot get PLC status - connection failed.\n"))
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    94
        return None
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
    95
284
3fecc96090c8 Fixed problem with re-use of Pyro connector proxy copy across debug sessions
etisserant
parents: 235
diff changeset
    96
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    97
    class PyroProxyProxy:
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    98
        """
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
    99
        A proxy proxy class to handle Beremiz Pyro interface specific behavior.
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   100
        And to put pyro exception catcher in between caller and pyro proxy
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   101
        """
284
3fecc96090c8 Fixed problem with re-use of Pyro connector proxy copy across debug sessions
etisserant
parents: 235
diff changeset
   102
        def __init__(self):
3fecc96090c8 Fixed problem with re-use of Pyro connector proxy copy across debug sessions
etisserant
parents: 235
diff changeset
   103
            # for safe use in from debug thread, must create a copy
3fecc96090c8 Fixed problem with re-use of Pyro connector proxy copy across debug sessions
etisserant
parents: 235
diff changeset
   104
            self.RemotePLCObjectProxyCopy = None
3fecc96090c8 Fixed problem with re-use of Pyro connector proxy copy across debug sessions
etisserant
parents: 235
diff changeset
   105
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   106
        def GetPyroProxy(self):
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   107
            """
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   108
            This func returns the real Pyro Proxy.
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   109
            Use this if you musn't keep reference to it.
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   110
            """
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   111
            return RemotePLCObjectProxy
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   112
235
a66e150f2888 Improved debug data feedback.
etisserant
parents: 231
diff changeset
   113
        def _PyroStartPLC(self, *args, **kwargs):
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   114
            """
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
   115
            confnodesroot._connector.GetPyroProxy() is used 
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   116
            rather than RemotePLCObjectProxy because
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   117
            object is recreated meanwhile, 
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   118
            so we must not keep ref to it here
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   119
            """
969
1950fe687dde Fix warning with LogMessage function
Laurent Bessard
parents: 923
diff changeset
   120
            current_status, log_count = confnodesroot._connector.GetPyroProxy().GetPLCstatus()
465
67d32a91d70b Fixes in debug + reconnect to running PLC
Edouard TISSERANT <edouard.tisserant@gmail.com>
parents: 446
diff changeset
   121
            if current_status == "Dirty":
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   122
                """
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   123
                Some bad libs with static symbols may polute PLC
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   124
                ask runtime to suicide and come back again
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   125
                """
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
   126
                confnodesroot.logger.write(_("Force runtime reload\n"))
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
   127
                confnodesroot._connector.GetPyroProxy().ForceReload()
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
   128
                confnodesroot._Disconnect()
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   129
                # let remote PLC time to resurect.(freeze app)
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   130
                sleep(0.5)
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
   131
                confnodesroot._Connect()
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
   132
            self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
   133
            return confnodesroot._connector.GetPyroProxy().StartPLC(*args, **kwargs)
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   134
        StartPLC = PyroCatcher(_PyroStartPLC, False)
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   135
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   136
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   137
        def _PyroGetTraceVariables(self):
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   138
            """
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   139
            for safe use in from debug thread, must use the copy
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   140
            """
465
67d32a91d70b Fixes in debug + reconnect to running PLC
Edouard TISSERANT <edouard.tisserant@gmail.com>
parents: 446
diff changeset
   141
            if self.RemotePLCObjectProxyCopy is None:
717
1c23952dbde1 refactoring
Edouard Tisserant
parents: 699
diff changeset
   142
                self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
446
1edde533db19 Some cleanup in PLC status - removed that \"Starting\" state ...
ed
parents: 411
diff changeset
   143
            return self.RemotePLCObjectProxyCopy.GetTraceVariables()
917
401e44bae7c0 Now logging have 4 levels
Edouard Tisserant
parents: 906
diff changeset
   144
        GetTraceVariables = PyroCatcher(_PyroGetTraceVariables,("Broken",None,None))
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   145
446
1edde533db19 Some cleanup in PLC status - removed that \"Starting\" state ...
ed
parents: 411
diff changeset
   146
        def _PyroGetPLCstatus(self):
1edde533db19 Some cleanup in PLC status - removed that \"Starting\" state ...
ed
parents: 411
diff changeset
   147
            return RemotePLCObjectProxy.GetPLCstatus()
923
6ef6e0b3a908 Fixed crash (segfault) when logging debug messages
Edouard Tisserant
parents: 917
diff changeset
   148
        GetPLCstatus = PyroCatcher(_PyroGetPLCstatus, ("Broken",None))
446
1edde533db19 Some cleanup in PLC status - removed that \"Starting\" state ...
ed
parents: 411
diff changeset
   149
699
6ff64cadb1ff Adding support for executing python scripts on remote runtime
laurent
parents: 493
diff changeset
   150
        def _PyroRemoteExec(self, script, **kwargs):
6ff64cadb1ff Adding support for executing python scripts on remote runtime
laurent
parents: 493
diff changeset
   151
            return RemotePLCObjectProxy.RemoteExec(script, **kwargs)
6ff64cadb1ff Adding support for executing python scripts on remote runtime
laurent
parents: 493
diff changeset
   152
        RemoteExec = PyroCatcher(_PyroRemoteExec, (-1, "RemoteExec script failed!"))
6ff64cadb1ff Adding support for executing python scripts on remote runtime
laurent
parents: 493
diff changeset
   153
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   154
        def __getattr__(self, attrName):
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   155
            member = self.__dict__.get(attrName, None)
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   156
            if member is None:
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   157
                def my_local_func(*args,**kwargs):
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   158
                    return RemotePLCObjectProxy.__getattr__(attrName)(*args,**kwargs)
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   159
                member = PyroCatcher(my_local_func, None)
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   160
                self.__dict__[attrName] = member
231
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   161
            return member
f1db3ce8f40a Re-organized pyro connector proxy members mascarading
etisserant
parents: 218
diff changeset
   162
203
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   163
    return PyroProxyProxy()
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   164
    
cb9901076a21 Added concepts :
etisserant
parents:
diff changeset
   165