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 |
|