plugin XEP-0166: handle content-add action + expose get_transport:
- `content-add` is now handled at this plugin level (implementation needs to be done in apps and transports plugins). - `get_transport` is now exposed. rel 447
This commit is contained in:
parent
6a4133b32c
commit
31c80d3626
1 changed files with 95 additions and 14 deletions
|
|
@ -96,6 +96,10 @@ class XEP_0166:
|
|||
A_SESSION_ACCEPT: Final = "session-accept"
|
||||
A_SESSION_TERMINATE: Final = "session-terminate"
|
||||
A_SESSION_INFO: Final = "session-info"
|
||||
A_CONTENT_ADD: Final = "content-add"
|
||||
A_CONTENT_MODIFY: Final = "content-modify"
|
||||
A_CONTENT_REJECT: Final = "content-reject"
|
||||
A_CONTENT_REMOVE: Final = "content-remove"
|
||||
A_TRANSPORT_REPLACE: Final = "transport-replace"
|
||||
A_TRANSPORT_ACCEPT: Final = "transport-accept"
|
||||
A_TRANSPORT_REJECT: Final = "transport-reject"
|
||||
|
|
@ -478,17 +482,24 @@ class XEP_0166:
|
|||
else:
|
||||
iq_elt, jingle_elt = self._build_jingle_elt(client, session, action)
|
||||
# FIXME: XEP-0260 § 2.3 Ex 5 has an initiator attribute, but it should not according to XEP-0166 §7.1 table 1, must be checked
|
||||
content_data = session["contents"][content_name]
|
||||
if action.startswith("content-"):
|
||||
creator = session["role"]
|
||||
transport_namespace = None
|
||||
else:
|
||||
content_data = session["contents"][content_name]
|
||||
creator = content_data["creator"]
|
||||
transport_namespace = content_data["transport"].namespace
|
||||
|
||||
content_elt = jingle_elt.addElement("content")
|
||||
content_elt["name"] = content_name
|
||||
content_elt["creator"] = content_data["creator"]
|
||||
content_elt["creator"] = creator
|
||||
|
||||
if context_elt is not None:
|
||||
if context_elt.parent is None:
|
||||
content_elt.addChild(context_elt)
|
||||
elif action == XEP_0166.A_TRANSPORT_INFO:
|
||||
context_elt = transport_elt = content_elt.addElement(
|
||||
"transport", content_data["transport"].namespace
|
||||
"transport", transport_namespace
|
||||
)
|
||||
else:
|
||||
raise exceptions.InternalError(f"unmanaged action {action}")
|
||||
|
|
@ -513,8 +524,10 @@ class XEP_0166:
|
|||
except KeyError:
|
||||
raise exceptions.NotFound(f"No application registered for {namespace}")
|
||||
|
||||
def get_content_data(self, content: dict, content_idx: int) -> ContentData:
|
||||
""" "Retrieve application and its argument from content"""
|
||||
def get_content_data(
|
||||
self, content: dict, content_idx: int | None = None
|
||||
) -> ContentData:
|
||||
"""Retrieve application and its argument from content"""
|
||||
app_ns = content["app_ns"]
|
||||
try:
|
||||
application = self.get_application(app_ns)
|
||||
|
|
@ -526,11 +539,32 @@ class XEP_0166:
|
|||
try:
|
||||
content_name = content["name"]
|
||||
except KeyError:
|
||||
if content_idx is None:
|
||||
raise exceptions.InternalError(
|
||||
'"content_idx" must be set if "content[\'name\']" is not set.'
|
||||
)
|
||||
content_name = content["name"] = str(content_idx)
|
||||
return ContentData(
|
||||
application, app_args, app_kwargs, transport_data, content_name
|
||||
)
|
||||
|
||||
def get_transport(
|
||||
self,
|
||||
client: SatXMPPEntity,
|
||||
content: dict,
|
||||
content_data: ContentData,
|
||||
) -> TransportData:
|
||||
"""Find a suitable transport for given content"""
|
||||
transport_type = content.get("transport_type", XEP_0166.TRANSPORT_STREAMING)
|
||||
for transport in self._type_transports[transport_type]:
|
||||
if transport.handler.is_usable(client, content_data):
|
||||
break
|
||||
else:
|
||||
raise exceptions.InternalError(
|
||||
"No transport registered for {}".format(transport_type)
|
||||
)
|
||||
return transport
|
||||
|
||||
async def initiate(
|
||||
self,
|
||||
client: SatXMPPEntity,
|
||||
|
|
@ -593,14 +627,7 @@ class XEP_0166:
|
|||
content_data = self.get_content_data(content, content_idx)
|
||||
|
||||
# and the transport plugin
|
||||
transport_type = content.get("transport_type", XEP_0166.TRANSPORT_STREAMING)
|
||||
for transport in self._type_transports[transport_type]:
|
||||
if transport.handler.is_usable(client, content_data):
|
||||
break
|
||||
else:
|
||||
raise exceptions.InternalError(
|
||||
"No transport registered for {}".format(transport_type)
|
||||
)
|
||||
transport = self.get_transport(client, content, content_data)
|
||||
|
||||
# we build the session data for this content
|
||||
application_data = {}
|
||||
|
|
@ -801,6 +828,8 @@ class XEP_0166:
|
|||
await self.on_session_accept(client, request, jingle_elt, session)
|
||||
elif action == XEP_0166.A_SESSION_INFO:
|
||||
await self.on_session_info(client, request, jingle_elt, session)
|
||||
elif action == XEP_0166.A_CONTENT_ADD:
|
||||
await self.on_content_add(client, request, jingle_elt, session)
|
||||
elif action == XEP_0166.A_TRANSPORT_INFO:
|
||||
self.on_transport_info(client, request, jingle_elt, session)
|
||||
elif action == XEP_0166.A_TRANSPORT_REPLACE:
|
||||
|
|
@ -994,7 +1023,10 @@ class XEP_0166:
|
|||
@return : list of launched methods results
|
||||
@raise exceptions.NotFound: method is not implemented
|
||||
"""
|
||||
contents_dict = session["contents"]
|
||||
if action == self.A_CONTENT_ADD:
|
||||
contents_dict = session["contents_new"]
|
||||
else:
|
||||
contents_dict = session["contents"]
|
||||
results = []
|
||||
for content_name, content_data in contents_dict.items():
|
||||
for method_name, handler_key, default_cb, elt_name in (
|
||||
|
|
@ -1023,6 +1055,9 @@ class XEP_0166:
|
|||
)
|
||||
results.append(result)
|
||||
|
||||
if action == self.A_CONTENT_ADD:
|
||||
del session["contents_new"]
|
||||
|
||||
return results
|
||||
|
||||
async def on_session_initiate(
|
||||
|
|
@ -1303,6 +1338,52 @@ class XEP_0166:
|
|||
else:
|
||||
client.send(xmlstream.toResponse(request, "result"))
|
||||
|
||||
async def on_content_add(
|
||||
self,
|
||||
client: SatXMPPEntity,
|
||||
request: domish.Element,
|
||||
jingle_elt: domish.Element,
|
||||
session: Dict[str, Any],
|
||||
) -> None:
|
||||
"""Called on content-add action
|
||||
|
||||
The "jingle_request_confirmation" method of each application will be called
|
||||
(or self.jingle_request_confirmation_default if the former doesn't exist).
|
||||
The session is only accepted if all application are confirmed.
|
||||
The application must manage itself multiple contents scenari (e.g. audio/video).
|
||||
@param client: %(doc_client)s
|
||||
@param request(domish.Element): full request
|
||||
@param jingle_elt(domish.Element): <jingle> element
|
||||
@param session(dict): session data
|
||||
"""
|
||||
return
|
||||
try:
|
||||
contents_dict = self._parse_elements(
|
||||
jingle_elt,
|
||||
{"id": session["id"], "contents": {}},
|
||||
request,
|
||||
client,
|
||||
True,
|
||||
XEP_0166.ROLE_INITIATOR,
|
||||
)
|
||||
except exceptions.CancelError:
|
||||
return
|
||||
|
||||
if not contents_dict:
|
||||
# there MUST be at least one content
|
||||
self.sendError(client, "bad-request", session["id"], request)
|
||||
return
|
||||
|
||||
session["contents_new"] = contents_dict
|
||||
|
||||
# at this point we can send the <iq/> result to confirm reception of the request
|
||||
client.send(xmlstream.toResponse(request, "result"))
|
||||
|
||||
assert "jingle_elt" not in session
|
||||
session["jingle_elt"] = jingle_elt
|
||||
|
||||
await self._call_plugins(client, XEP_0166.A_CONTENT_ADD, session, delete=False)
|
||||
|
||||
async def on_transport_replace(self, client, request, jingle_elt, session):
|
||||
"""A transport change is requested
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue