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
This commit is contained in:
Goffi 2020-11-12 14:53:15 +01:00
commit aab9a8bf91

View file

@ -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 @@ class XEP_0166(object):
"""
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 @@ class XEP_0166(object):
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 @@ class XEP_0166(object):
"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 @@ class XEP_0166(object):
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 @@ class XEP_0166(object):
"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 @@ class XEP_0166(object):
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)