Mercurial > libervia-backend
comparison src/plugins/plugin_xep_0166.py @ 1616:1e05b776a55b
plugin XEP-0166: session-info action handling
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 17 Nov 2015 19:40:37 +0100 |
parents | a1e5bcd9a6eb |
children | d05f9179fe22 |
comparison
equal
deleted
inserted
replaced
1615:a1e5bcd9a6eb | 1616:1e05b776a55b |
---|---|
23 from sat.tools import xml_tools | 23 from sat.tools import xml_tools |
24 log = getLogger(__name__) | 24 log = getLogger(__name__) |
25 from sat.core import exceptions | 25 from sat.core import exceptions |
26 from twisted.words.protocols.jabber import jid | 26 from twisted.words.protocols.jabber import jid |
27 from twisted.internet import defer | 27 from twisted.internet import defer |
28 # from wokkel import disco, iwokkel, data_form, compat | |
29 from wokkel import disco, iwokkel | 28 from wokkel import disco, iwokkel |
30 from twisted.words.protocols.jabber import error | 29 from twisted.words.protocols.jabber import error |
31 from twisted.words.protocols.jabber import xmlstream | 30 from twisted.words.protocols.jabber import xmlstream |
32 from twisted.python import failure | 31 from twisted.python import failure |
33 from collections import namedtuple | 32 from collections import namedtuple |
72 REASON_FAILED_APPLICATION='failed-application' | 71 REASON_FAILED_APPLICATION='failed-application' |
73 REASON_FAILED_TRANSPORT='failed-transport' | 72 REASON_FAILED_TRANSPORT='failed-transport' |
74 A_SESSION_INITIATE = "session-initiate" | 73 A_SESSION_INITIATE = "session-initiate" |
75 A_SESSION_ACCEPT = "session-accept" | 74 A_SESSION_ACCEPT = "session-accept" |
76 A_SESSION_TERMINATE = "session-terminate" | 75 A_SESSION_TERMINATE = "session-terminate" |
76 A_SESSION_INFO = "session-info" | |
77 A_TRANSPORT_INFO = "transport-info" | 77 A_TRANSPORT_INFO = "transport-info" |
78 # non standard actions | 78 # non standard actions |
79 A_PREPARE_INITIATOR = "prepare-initiator" # initiator must prepare tranfer | 79 A_PREPARE_INITIATOR = "prepare-initiator" # initiator must prepare tranfer |
80 A_PREPARE_RESPONDER = "prepare-responder" # responder must prepare tranfer | 80 A_PREPARE_RESPONDER = "prepare-responder" # responder must prepare tranfer |
81 A_ACCEPTED_ACK = "accepted-ack" # session accepted ack has been received from initiator | 81 A_ACCEPTED_ACK = "accepted-ack" # session accepted ack has been received from initiator |
254 transport_elt['sid'] = content_data['transport_data']['sid'] | 254 transport_elt['sid'] = content_data['transport_data']['sid'] |
255 else: | 255 else: |
256 raise exceptions.InternalError(u"unmanaged action {}".format(action)) | 256 raise exceptions.InternalError(u"unmanaged action {}".format(action)) |
257 | 257 |
258 return iq_elt, context_elt | 258 return iq_elt, context_elt |
259 | |
260 def buildSessionInfo(self, session, profile=C.PROF_KEY_NONE): | |
261 """Build a session-info action | |
262 | |
263 @param session(dict): jingle session data | |
264 @param profile: %(doc_profile)s | |
265 @return (tuple[domish.Element, domish.Element]): parent <iq> element, <jingle> element | |
266 """ | |
267 client = self.host.getClient(profile) | |
268 return self._buildJingleElt(client, session, XEP_0166.A_SESSION_INFO) | |
259 | 269 |
260 @defer.inlineCallbacks | 270 @defer.inlineCallbacks |
261 def initiate(self, peer_jid, contents, profile=C.PROF_KEY_NONE): | 271 def initiate(self, peer_jid, contents, profile=C.PROF_KEY_NONE): |
262 """Send a session initiation request | 272 """Send a session initiation request |
263 | 273 |
437 self.onSessionInitiate(client, request, jingle_elt, session) | 447 self.onSessionInitiate(client, request, jingle_elt, session) |
438 elif action == XEP_0166.A_SESSION_TERMINATE: | 448 elif action == XEP_0166.A_SESSION_TERMINATE: |
439 self.onSessionTerminate(client, request, jingle_elt, session) | 449 self.onSessionTerminate(client, request, jingle_elt, session) |
440 elif action == XEP_0166.A_SESSION_ACCEPT: | 450 elif action == XEP_0166.A_SESSION_ACCEPT: |
441 self.onSessionAccept(client, request, jingle_elt, session) | 451 self.onSessionAccept(client, request, jingle_elt, session) |
452 elif action == XEP_0166.A_SESSION_INFO: | |
453 self.onSessionInfo(client, request, jingle_elt, session) | |
442 elif action == XEP_0166.A_TRANSPORT_INFO: | 454 elif action == XEP_0166.A_TRANSPORT_INFO: |
443 self.onTransportInfo(client, request, jingle_elt, session) | 455 self.onTransportInfo(client, request, jingle_elt, session) |
444 else: | 456 else: |
445 raise exceptions.InternalError(u"Unknown action {}".format(action)) | 457 raise exceptions.InternalError(u"Unknown action {}".format(action)) |
446 | 458 |
539 if 'transport_elt' in content_data: | 551 if 'transport_elt' in content_data: |
540 raise exceptions.InternalError(u"desc_elt should not exist at this point") | 552 raise exceptions.InternalError(u"desc_elt should not exist at this point") |
541 | 553 |
542 content_data['transport_elt'] = transport_elt | 554 content_data['transport_elt'] = transport_elt |
543 | 555 |
544 def _callPlugins(self, action, session, app_method_name='jingleHandler', transp_method_name='jingleHandler', app_default_cb=None, transp_default_cb=None, delete=True, elements=True, profile=C.PROF_KEY_NONE): | 556 def _callPlugins(self, action, session, app_method_name='jingleHandler', transp_method_name='jingleHandler', |
557 app_default_cb=None, transp_default_cb=None, delete=True, | |
558 elements=True, force_element=None, profile=C.PROF_KEY_NONE): | |
545 """Call application and transport plugin methods for all contents | 559 """Call application and transport plugin methods for all contents |
546 | 560 |
547 @param action(unicode): jingle action name | 561 @param action(unicode): jingle action name |
548 @param session(dict): jingle session data | 562 @param session(dict): jingle session data |
549 @param app_method_name(unicode, None): name of the method to call for applications | 563 @param app_method_name(unicode, None): name of the method to call for applications |
555 @param transp_default_cb(callable, None): default callback to use if plugin has not transp_method_name | 569 @param transp_default_cb(callable, None): default callback to use if plugin has not transp_method_name |
556 None to raise an exception instead | 570 None to raise an exception instead |
557 @param delete(bool): if True, remove desc_elt and transport_elt from session | 571 @param delete(bool): if True, remove desc_elt and transport_elt from session |
558 ignored if elements is False | 572 ignored if elements is False |
559 @param elements(bool): True if elements(desc_elt and tranport_elt) must be managed | 573 @param elements(bool): True if elements(desc_elt and tranport_elt) must be managed |
560 must be True if _callPlugins is use in a request, and False if it used after a request (i.e. on <iq> result or error) | 574 must be True if _callPlugins is used in a request, and False if it used after a request (i.e. on <iq> result or error) |
575 @param force_element(None, domish.Element, object): if elements is None, it is used as element parameter | |
576 else it is ignored | |
561 @param profile(unicode): %(doc_profile)s | 577 @param profile(unicode): %(doc_profile)s |
562 @return (list[defer.Deferred]): list of launched Deferred | 578 @return (list[defer.Deferred]): list of launched Deferred |
579 @raise exceptions.NotFound: method is not implemented | |
563 """ | 580 """ |
564 contents_dict = session['contents'] | 581 contents_dict = session['contents'] |
565 defers_list = [] | 582 defers_list = [] |
566 for content_name, content_data in contents_dict.iteritems(): | 583 for content_name, content_data in contents_dict.iteritems(): |
567 for method_name, handler_key, default_cb, elt_name in ( | 584 for method_name, handler_key, default_cb, elt_name in ( |
575 method = getattr(handler, method_name) | 592 method = getattr(handler, method_name) |
576 except AttributeError: | 593 except AttributeError: |
577 if default_cb is not None: | 594 if default_cb is not None: |
578 method = default_cb | 595 method = default_cb |
579 else: | 596 else: |
580 raise exceptions.InternalError(u'{} not implemented !'.format(method_name)) | 597 raise exceptions.NotFound(u'{} not implemented !'.format(method_name)) |
581 finally: | 598 if elements: |
582 if elements: | 599 elt = content_data.pop(elt_name) if delete else content_data[elt_name] |
583 elt = content_data.pop(elt_name) if delete else content_data[elt_name] | 600 else: |
584 else: | 601 elt = force_element |
585 elt = None | 602 d = defer.maybeDeferred(method, action, session, content_name, elt, profile) |
586 d = defer.maybeDeferred(method, action, session, content_name, elt, profile) | |
587 defers_list.append(d) | 603 defers_list.append(d) |
588 | 604 |
589 return defers_list | 605 return defers_list |
590 | 606 |
591 def onSessionInitiate(self, client, request, jingle_elt, session): | 607 def onSessionInitiate(self, client, request, jingle_elt, session): |
713 negociate_dlist = defer.DeferredList(negociate_defers) | 729 negociate_dlist = defer.DeferredList(negociate_defers) |
714 | 730 |
715 # after negociations we start the transfer | 731 # after negociations we start the transfer |
716 negociate_dlist.addCallback(lambda dummy: self._callPlugins(XEP_0166.A_START, session, app_method_name=None, elements=False, profile=client.profile)) | 732 negociate_dlist.addCallback(lambda dummy: self._callPlugins(XEP_0166.A_START, session, app_method_name=None, elements=False, profile=client.profile)) |
717 | 733 |
734 def _onSessionCb(self, result, client, request, jingle_elt, session): | |
735 client.xmlstream.send(xmlstream.toResponse(request, 'result')) | |
736 | |
737 def _onSessionEb(self, failure_, client, request, jingle_elt, session): | |
738 log.error(u"Error while handling onSessionInfo: {}".format(failure_.value)) | |
739 # XXX: only error managed so far, maybe some applications/transports need more | |
740 self.sendError('feature-not-implemented', None, request, 'unsupported-info', client.profile) | |
741 | |
742 def onSessionInfo(self, client, request, jingle_elt, session): | |
743 """Method called when a session-info action is received from other peer | |
744 | |
745 This method is only called for initiator | |
746 @param client: %(doc_client)s | |
747 @param request(domish.Element): full <iq> request | |
748 @param jingle_elt(domish.Element): the <jingle> element | |
749 @param session(dict): session data | |
750 """ | |
751 if not jingle_elt.children: | |
752 # this is a session ping, see XEP-0166 ยง6.8 | |
753 client.xmlstream.send(xmlstream.toResponse(request, 'result')) | |
754 return | |
755 | |
756 try: | |
757 # XXX: session-info is most likely only used for application, so we don't call transport plugins | |
758 # if a future transport use it, this behaviour must be adapted | |
759 defers = self._callPlugins(XEP_0166.A_SESSION_INFO, session, 'jingleSessionInfo', None, | |
760 elements=False, force_element=jingle_elt, profile=client.profile) | |
761 except exceptions.NotFound as e: | |
762 self._onSessionEb(failure.Failure(e), client, request, jingle_elt, session) | |
763 return | |
764 | |
765 dlist = defer.DeferredList(defers, fireOnOneErrback=True) | |
766 dlist.addCallback(self._onSessionCb, client, request, jingle_elt, session) | |
767 dlist.addErrback(self._onSessionCb, client, request, jingle_elt, session) | |
768 | |
718 def onTransportInfo(self, client, request, jingle_elt, session): | 769 def onTransportInfo(self, client, request, jingle_elt, session): |
719 """Method called when a transport-info action is received from other peer | 770 """Method called when a transport-info action is received from other peer |
720 | 771 |
721 The request is parsed, and jingleHandler is called on concerned transport plugin(s) | 772 The request is parsed, and jingleHandler is called on concerned transport plugin(s) |
722 @param client: %(doc_client)s | 773 @param client: %(doc_client)s |