Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0166.py @ 3404:26a0af6e32c1
plugin XEP-0166: new trigger point + coroutines + helper methods:
- a new `XEP-0166_initiate` async trigger point is available
- `initate` is now a coroutine
- `jingleSessionInit` in applications and transports handlers are now called using
`utils.adDeferred`
- new `getApplication` helper method, to retrieve application from its namespace
- new `getContentData` helper method to retrieve application and its argument from content
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 12 Nov 2020 14:53:15 +0100 |
parents | ac9342f359e9 |
children | be6d91572633 |
comparison
equal
deleted
inserted
replaced
3403:404d4b29de52 | 3404:26a0af6e32c1 |
---|---|
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | 18 |
19 | 19 |
20 import uuid | 20 import uuid |
21 import time | 21 import time |
22 from typing import Tuple | |
22 from collections import namedtuple | 23 from collections import namedtuple |
23 from zope.interface import implementer | 24 from zope.interface import implementer |
24 from twisted.words.protocols.jabber import jid | 25 from twisted.words.protocols.jabber import jid |
25 from twisted.internet import defer | 26 from twisted.internet import defer |
26 from twisted.internet import reactor | 27 from twisted.internet import reactor |
334 @param session(dict): jingle session data | 335 @param session(dict): jingle session data |
335 @return (tuple[domish.Element, domish.Element]): parent <iq> element, <jingle> element | 336 @return (tuple[domish.Element, domish.Element]): parent <iq> element, <jingle> element |
336 """ | 337 """ |
337 return self._buildJingleElt(client, session, XEP_0166.A_SESSION_INFO) | 338 return self._buildJingleElt(client, session, XEP_0166.A_SESSION_INFO) |
338 | 339 |
339 @defer.inlineCallbacks | 340 def getApplication(self, namespace: str) -> object: |
340 def initiate(self, client, peer_jid, contents): | 341 """Retreive application corresponding to a namespace |
342 | |
343 @raise exceptions.NotFound if application can't be found | |
344 """ | |
345 try: | |
346 return self._applications[namespace] | |
347 except KeyError: | |
348 raise exceptions.NotFound( | |
349 f"No application registered for {namespace}" | |
350 ) | |
351 | |
352 def getContentData(self, content: dict) -> Tuple[object, list, dict, str]: | |
353 """"Retrieve application and its argument from content""" | |
354 app_ns = content["app_ns"] | |
355 try: | |
356 application = self.getApplication(app_ns) | |
357 except exceptions.NotFound as e: | |
358 raise exceptions.InternalError(str(e)) | |
359 app_args = content.get("app_args", []) | |
360 app_kwargs = content.get("app_kwargs", {}) | |
361 try: | |
362 content_name = content["name"] | |
363 except KeyError: | |
364 content_name = content["name"] = str(uuid.uuid4()) | |
365 return application, app_args, app_kwargs, content_name | |
366 | |
367 async def initiate(self, client, peer_jid, contents): | |
341 """Send a session initiation request | 368 """Send a session initiation request |
342 | 369 |
343 @param peer_jid(jid.JID): jid to establith session with | 370 @param peer_jid(jid.JID): jid to establith session with |
344 @param contents(list[dict]): list of contents to use: | 371 @param contents(list[dict]): list of contents to use: |
345 The dict must have the following keys: | 372 The dict must have the following keys: |
350 - name(unicode): name of the content | 377 - name(unicode): name of the content |
351 - senders(unicode): One of XEP_0166.ROLE_INITIATOR, XEP_0166.ROLE_RESPONDER, both or none | 378 - senders(unicode): One of XEP_0166.ROLE_INITIATOR, XEP_0166.ROLE_RESPONDER, both or none |
352 default to BOTH (see XEP-0166 §7.3) | 379 default to BOTH (see XEP-0166 §7.3) |
353 - app_args(list): args to pass to the application plugin | 380 - app_args(list): args to pass to the application plugin |
354 - app_kwargs(dict): keyword args to pass to the application plugin | 381 - app_kwargs(dict): keyword args to pass to the application plugin |
355 @return D(unicode): jingle session id | 382 @return (unicode): jingle session id |
356 """ | 383 """ |
357 assert contents # there must be at least one content | 384 assert contents # there must be at least one content |
358 if (peer_jid == client.jid | 385 if (peer_jid == client.jid |
359 or client.is_component and peer_jid.host == client.jid.host): | 386 or client.is_component and peer_jid.host == client.jid.host): |
360 raise ValueError(_("You can't do a jingle session with yourself")) | 387 raise ValueError(_("You can't do a jingle session with yourself")) |
369 "local_jid": client.jid, | 396 "local_jid": client.jid, |
370 "peer_jid": peer_jid, | 397 "peer_jid": peer_jid, |
371 "started": time.time(), | 398 "started": time.time(), |
372 "contents": {}, | 399 "contents": {}, |
373 } | 400 } |
401 | |
402 if not await self.host.trigger.asyncPoint( | |
403 "XEP-0166_initiate", | |
404 client, session, contents | |
405 ): | |
406 return | |
407 | |
374 iq_elt, jingle_elt = self._buildJingleElt( | 408 iq_elt, jingle_elt = self._buildJingleElt( |
375 client, session, XEP_0166.A_SESSION_INITIATE | 409 client, session, XEP_0166.A_SESSION_INITIATE |
376 ) | 410 ) |
377 jingle_elt["initiator"] = initiator.full() | 411 jingle_elt["initiator"] = initiator.full() |
378 | 412 |
379 contents_dict = session["contents"] | 413 contents_dict = session["contents"] |
380 | 414 |
381 for content in contents: | 415 for content in contents: |
382 # we get the application plugin | 416 # we get the application plugin |
383 app_ns = content["app_ns"] | 417 application, app_args, app_kwargs, content_name = self.getContentData(content) |
384 try: | |
385 application = self._applications[app_ns] | |
386 except KeyError: | |
387 raise exceptions.InternalError( | |
388 "No application registered for {}".format(app_ns) | |
389 ) | |
390 | 418 |
391 # and the transport plugin | 419 # and the transport plugin |
392 transport_type = content.get("transport_type", XEP_0166.TRANSPORT_STREAMING) | 420 transport_type = content.get("transport_type", XEP_0166.TRANSPORT_STREAMING) |
393 try: | 421 try: |
394 transport = self._type_transports[transport_type][0] | 422 transport = self._type_transports[transport_type][0] |
404 "transport": transport, | 432 "transport": transport, |
405 "transport_data": {}, | 433 "transport_data": {}, |
406 "creator": XEP_0166.ROLE_INITIATOR, | 434 "creator": XEP_0166.ROLE_INITIATOR, |
407 "senders": content.get("senders", "both"), | 435 "senders": content.get("senders", "both"), |
408 } | 436 } |
409 try: | 437 if content_name in contents_dict: |
410 content_name = content["name"] | 438 raise exceptions.InternalError( |
411 except KeyError: | 439 "There is already a content with this name" |
412 content_name = str(uuid.uuid4()) | 440 ) |
413 else: | |
414 if content_name in contents_dict: | |
415 raise exceptions.InternalError( | |
416 "There is already a content with this name" | |
417 ) | |
418 contents_dict[content_name] = content_data | 441 contents_dict[content_name] = content_data |
419 | 442 |
420 # we construct the content element | 443 # we construct the content element |
421 content_elt = jingle_elt.addElement("content") | 444 content_elt = jingle_elt.addElement("content") |
422 content_elt["creator"] = content_data["creator"] | 445 content_elt["creator"] = content_data["creator"] |
425 content_elt["senders"] = content["senders"] | 448 content_elt["senders"] = content["senders"] |
426 except KeyError: | 449 except KeyError: |
427 pass | 450 pass |
428 | 451 |
429 # then the description element | 452 # then the description element |
430 app_args = content.get("app_args", []) | 453 desc_elt = await utils.asDeferred( |
431 app_kwargs = content.get("app_kwargs", {}) | 454 application.handler.jingleSessionInit, |
432 desc_elt = yield application.handler.jingleSessionInit( | |
433 client, session, content_name, *app_args, **app_kwargs | 455 client, session, content_name, *app_args, **app_kwargs |
434 ) | 456 ) |
435 content_elt.addChild(desc_elt) | 457 content_elt.addChild(desc_elt) |
436 | 458 |
437 # and the transport one | 459 # and the transport one |
438 transport_elt = yield transport.handler.jingleSessionInit( | 460 transport_elt = await utils.asDeferred( |
461 transport.handler.jingleSessionInit, | |
439 client, session, content_name | 462 client, session, content_name |
440 ) | 463 ) |
441 content_elt.addChild(transport_elt) | 464 content_elt.addChild(transport_elt) |
442 | 465 |
443 try: | 466 try: |
444 yield iq_elt.send() | 467 await iq_elt.send() |
445 except Exception as e: | 468 except Exception as e: |
446 failure_ = failure.Failure(e) | 469 failure_ = failure.Failure(e) |
447 self._iqError(failure_, sid, client) | 470 self._iqError(failure_, sid, client) |
448 raise failure_ | 471 raise failure_ |
449 | 472 |