diff 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
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0166.py	Thu Nov 12 14:53:15 2020 +0100
+++ b/sat/plugins/plugin_xep_0166.py	Thu Nov 12 14:53:15 2020 +0100
@@ -19,6 +19,7 @@
 
 import uuid
 import time
+from typing import Tuple
 from collections import namedtuple
 from zope.interface import implementer
 from twisted.words.protocols.jabber import jid
@@ -336,8 +337,34 @@
         """
         return self._buildJingleElt(client, session, XEP_0166.A_SESSION_INFO)
 
-    @defer.inlineCallbacks
-    def initiate(self, client, peer_jid, contents):
+    def getApplication(self, namespace: str) -> object:
+        """Retreive application corresponding to a namespace
+
+        @raise exceptions.NotFound if application can't be found
+        """
+        try:
+            return self._applications[namespace]
+        except KeyError:
+            raise exceptions.NotFound(
+                f"No application registered for {namespace}"
+            )
+
+    def getContentData(self, content: dict) -> Tuple[object, list, dict, str]:
+        """"Retrieve application and its argument from content"""
+        app_ns = content["app_ns"]
+        try:
+            application = self.getApplication(app_ns)
+        except exceptions.NotFound as e:
+            raise exceptions.InternalError(str(e))
+        app_args = content.get("app_args", [])
+        app_kwargs = content.get("app_kwargs", {})
+        try:
+            content_name = content["name"]
+        except KeyError:
+            content_name = content["name"] = str(uuid.uuid4())
+        return application, app_args, app_kwargs, content_name
+
+    async def initiate(self, client, peer_jid, contents):
         """Send a session initiation request
 
         @param peer_jid(jid.JID): jid to establith session with
@@ -352,7 +379,7 @@
                     default to BOTH (see XEP-0166 ยง7.3)
                 - app_args(list): args to pass to the application plugin
                 - app_kwargs(dict): keyword args to pass to the application plugin
-        @return D(unicode): jingle session id
+        @return (unicode): jingle session id
         """
         assert contents  # there must be at least one content
         if (peer_jid == client.jid
@@ -371,6 +398,13 @@
             "started": time.time(),
             "contents": {},
         }
+
+        if not await self.host.trigger.asyncPoint(
+            "XEP-0166_initiate",
+            client, session, contents
+        ):
+            return
+
         iq_elt, jingle_elt = self._buildJingleElt(
             client, session, XEP_0166.A_SESSION_INITIATE
         )
@@ -380,13 +414,7 @@
 
         for content in contents:
             # we get the application plugin
-            app_ns = content["app_ns"]
-            try:
-                application = self._applications[app_ns]
-            except KeyError:
-                raise exceptions.InternalError(
-                    "No application registered for {}".format(app_ns)
-                )
+            application, app_args, app_kwargs, content_name = self.getContentData(content)
 
             # and the transport plugin
             transport_type = content.get("transport_type", XEP_0166.TRANSPORT_STREAMING)
@@ -406,15 +434,10 @@
                 "creator": XEP_0166.ROLE_INITIATOR,
                 "senders": content.get("senders", "both"),
             }
-            try:
-                content_name = content["name"]
-            except KeyError:
-                content_name = str(uuid.uuid4())
-            else:
-                if content_name in contents_dict:
-                    raise exceptions.InternalError(
-                        "There is already a content with this name"
-                    )
+            if content_name in contents_dict:
+                raise exceptions.InternalError(
+                    "There is already a content with this name"
+                )
             contents_dict[content_name] = content_data
 
             # we construct the content element
@@ -427,21 +450,21 @@
                 pass
 
             # then the description element
-            app_args = content.get("app_args", [])
-            app_kwargs = content.get("app_kwargs", {})
-            desc_elt = yield application.handler.jingleSessionInit(
+            desc_elt = await utils.asDeferred(
+                application.handler.jingleSessionInit,
                 client, session, content_name, *app_args, **app_kwargs
             )
             content_elt.addChild(desc_elt)
 
             # and the transport one
-            transport_elt = yield transport.handler.jingleSessionInit(
+            transport_elt = await utils.asDeferred(
+                transport.handler.jingleSessionInit,
                 client, session, content_name
             )
             content_elt.addChild(transport_elt)
 
         try:
-            yield iq_elt.send()
+            await iq_elt.send()
         except Exception as e:
             failure_ = failure.Failure(e)
             self._iqError(failure_, sid, client)