33 from autobahn.wamp import types, auth |
33 from autobahn.wamp import types, auth |
34 from autobahn.wamp.serializer import MsgPackSerializer |
34 from autobahn.wamp.serializer import MsgPackSerializer |
35 from twisted.internet.defer import inlineCallbacks |
35 from twisted.internet.defer import inlineCallbacks |
36 from twisted.internet.protocol import ReconnectingClientFactory |
36 from twisted.internet.protocol import ReconnectingClientFactory |
37 |
37 |
|
38 import runtime.NevowServer as NS |
|
39 |
|
40 from formless import annotate |
38 |
41 |
39 mandatoryConfigItems = ["ID", "active", "realm", "url"] |
42 mandatoryConfigItems = ["ID", "active", "realm", "url"] |
40 |
43 |
41 _transportFactory = None |
44 _transportFactory = None |
42 _WampSession = None |
45 _WampSession = None |
85 else: |
89 else: |
86 self.join(u"Automation") |
90 self.join(u"Automation") |
87 |
91 |
88 def onChallenge(self, challenge): |
92 def onChallenge(self, challenge): |
89 if challenge.method == u"wampcra": |
93 if challenge.method == u"wampcra": |
90 secret = self.config.extra["secret"].encode('utf8') |
94 if "secret" in self.config.extra: |
91 signature = auth.compute_wcs(secret, challenge.extra['challenge'].encode('utf8')) |
95 secret = self.config.extra["secret"].encode('utf8') |
92 return signature.decode("ascii") |
96 signature = auth.compute_wcs(secret, challenge.extra['challenge'].encode('utf8')) |
|
97 return signature.decode("ascii") |
|
98 else: |
|
99 raise Exception("no secret given for authentication") |
93 else: |
100 else: |
94 raise Exception("don't know how to handle authmethod {}".format(challenge.method)) |
101 raise Exception("don't know how to handle authmethod {}".format(challenge.method)) |
95 |
102 |
96 @inlineCallbacks |
103 @inlineCallbacks |
97 def onJoin(self, details): |
104 def onJoin(self, details): |
155 super(ReconnectingWampWebSocketClientFactory, self).clientConnectionFailed(connector, reason) |
162 super(ReconnectingWampWebSocketClientFactory, self).clientConnectionFailed(connector, reason) |
156 else: |
163 else: |
157 del connector |
164 del connector |
158 |
165 |
159 |
166 |
|
167 def CheckConfiguration(WSClientConf): |
|
168 url = WSClientConf["url"] |
|
169 if not IsCorrectUri(url): |
|
170 raise annotate.ValidateError( |
|
171 {"url":"Invalid URL: {}".format(url)}, |
|
172 _("WAMP confiuration error:")) |
|
173 |
160 def GetConfiguration(): |
174 def GetConfiguration(): |
|
175 global lastKnownConfig |
|
176 |
161 WSClientConf = json.load(open(_WampConf)) |
177 WSClientConf = json.load(open(_WampConf)) |
162 for itemName in mandatoryConfigItems: |
178 for itemName in mandatoryConfigItems: |
163 if WSClientConf.get(itemName, None) is None : |
179 if WSClientConf.get(itemName, None) is None : |
164 raise Exception(_("WAMP configuration error : missing '{}' parameter.").format(itemName)) |
180 raise Exception(_("WAMP configuration error : missing '{}' parameter.").format(itemName)) |
165 |
181 |
|
182 CheckConfiguration(WSClientConf) |
|
183 |
|
184 lastKnownConfig = WSClientConf.copy() |
166 return WSClientConf |
185 return WSClientConf |
167 |
186 |
168 |
187 |
169 def SetConfiguration(WSClientConf): |
188 def SetConfiguration(WSClientConf): |
170 try: |
189 global lastKnownConfig |
171 with open(os.path.realpath(_WampConf), 'w') as f: |
190 |
172 json.dump(WSClientConf, f, sort_keys=True, indent=4) |
191 CheckConfiguration(WSClientConf) |
173 if 'active' in WSClientConf and WSClientConf['active']: |
192 |
174 if _transportFactory and _WampSession: |
193 lastKnownConfig = WSClientConf.copy() |
175 StopReconnectWampClient() |
194 |
176 StartReconnectWampClient() |
195 with open(os.path.realpath(_WampConf), 'w') as f: |
177 else: |
196 json.dump(WSClientConf, f, sort_keys=True, indent=4) |
|
197 if 'active' in WSClientConf and WSClientConf['active']: |
|
198 if _transportFactory and _WampSession: |
178 StopReconnectWampClient() |
199 StopReconnectWampClient() |
179 |
200 StartReconnectWampClient() |
180 return WSClientConf |
201 else: |
181 except ValueError, ve: |
202 StopReconnectWampClient() |
182 print(_("WAMP save error: "), ve) |
203 |
183 return None |
204 return WSClientConf |
184 except Exception, e: |
|
185 print(_("WAMP save error: "), e) |
|
186 return None |
|
187 |
205 |
188 |
206 |
189 def LoadWampSecret(secretfname): |
207 def LoadWampSecret(secretfname): |
190 try: |
208 WSClientWampSecret = open(secretfname, 'rb').read() |
191 WSClientWampSecret = open(secretfname, 'rb').read() |
209 if len(WSClientWampSecret) == 0 : |
192 return WSClientWampSecret |
210 raise Exception(_("WAMP secret empty")) |
193 except ValueError, ve: |
211 return WSClientWampSecret |
194 print(_("Wamp secret load error:"), ve) |
|
195 return None |
|
196 except Exception: |
|
197 return None |
|
198 |
212 |
199 |
213 |
200 def IsCorrectUri(uri): |
214 def IsCorrectUri(uri): |
201 if re.match(r'w{1}s{1,2}:{1}/{2}.+:{1}[0-9]+/{1}.+', uri): |
215 return re.match(r'wss?://[^\s?:#-]+(:[0-9]+)?(/[^\s]*)?$', uri) is not None |
202 return True |
|
203 else: |
|
204 return False |
|
205 |
216 |
206 |
217 |
207 def RegisterWampClient(wampconf=None, wampsecret=None): |
218 def RegisterWampClient(wampconf=None, wampsecret=None): |
208 global _WampConf, _WampSecret |
219 global _WampConf, _WampSecret |
209 if wampsecret: |
220 if wampsecret: |
211 if wampconf: |
222 if wampconf: |
212 _WampConf = wampconf |
223 _WampConf = wampconf |
213 |
224 |
214 WSClientConf = GetConfiguration() |
225 WSClientConf = GetConfiguration() |
215 |
226 |
216 if not IsCorrectUri(WSClientConf["url"]): |
|
217 raise Exception(_("WAMP url {} is not correct!").format(WSClientConf["url"])) |
|
218 |
|
219 if not WSClientConf["active"]: |
227 if not WSClientConf["active"]: |
220 print(_("WAMP deactivated in configuration")) |
228 print(_("WAMP deactivated in configuration")) |
221 return |
229 return |
222 |
230 |
223 WampSecret = LoadWampSecret(_WampSecret) |
231 if _WampSecret is not None: |
224 |
232 WSClientConf["secret"] = LoadWampSecret(_WampSecret) |
225 if WampSecret is not None: |
|
226 WSClientConf["secret"] = WampSecret |
|
227 |
233 |
228 # create a WAMP application session factory |
234 # create a WAMP application session factory |
229 component_config = types.ComponentConfig( |
235 component_config = types.ComponentConfig( |
230 realm=WSClientConf["realm"], |
236 realm=WSClientConf["realm"], |
231 extra=WSClientConf) |
237 extra=WSClientConf) |
267 |
275 |
268 |
276 |
269 def GetSession(): |
277 def GetSession(): |
270 return _WampSession |
278 return _WampSession |
271 |
279 |
272 |
280 def getWampStatus(): |
273 def StatusWampClient(): |
281 if _transportFactory is not None : |
274 return _WampSession and _WampSession.is_attached() |
282 if _WampSession is not None : |
|
283 if _WampSession.is_attached() : |
|
284 return "Attached" |
|
285 return "Established" |
|
286 return "Connecting" |
|
287 return "Disconnected" |
275 |
288 |
276 |
289 |
277 def SetServer(pysrv): |
290 def SetServer(pysrv): |
278 _PySrv = pysrv |
291 _PySrv = pysrv |
|
292 |
|
293 |
|
294 #### WEB CONFIGURATION INTERFACE #### |
|
295 |
|
296 webExposedConfigItems = ['active', 'url', 'ID'] |
|
297 |
|
298 def wampConfigDefault(ctx,argument): |
|
299 if lastKnownConfig is not None : |
|
300 return lastKnownConfig.get(argument.name, None) |
|
301 |
|
302 def wampConfig(**kwargs): |
|
303 newConfig = lastKnownConfig.copy() |
|
304 for argname in webExposedConfigItems: |
|
305 newConfig[argname] = kwargs[argname] |
|
306 |
|
307 SetConfiguration(newConfig) |
|
308 |
|
309 webFormInterface = [ |
|
310 ("status", |
|
311 annotate.String(label=_("Current status"), |
|
312 immutable = True, |
|
313 default = lambda *k:getWampStatus())), |
|
314 ("ID", |
|
315 annotate.String(label=_("ID"), |
|
316 default = wampConfigDefault)), |
|
317 ("active", |
|
318 annotate.Boolean(label=_("Enable WAMP connection"), |
|
319 default=wampConfigDefault)), |
|
320 ("url", |
|
321 annotate.String(label=_("WAMP Server URL"), |
|
322 default=wampConfigDefault))] |
|
323 |
|
324 |
|
325 NS.ConfigurableSettings.addExtension( |
|
326 "wamp", |
|
327 _("Wamp Settings"), |
|
328 webFormInterface, |
|
329 _("Set"), |
|
330 wampConfig) |