plugin XEP-0353: intialisation refactor:

slight refactor of initialisation workflow, it's now split in two part, with
`self._send_jingle_after_accept` called in a deferred, so the session ID can be returned
early by the jingle application, and the session can be cancelled even if not fully
established (e.g. while ringing during a call).
This commit is contained in:
Goffi 2026-10-18 22:16:00 +02:00
commit c0860ca978

View file

@ -86,9 +86,10 @@ class XEP_0353:
"XEP-0166_initiate_elt_built", "XEP-0166_initiate_elt_built",
self, self,
self._on_initiate_trigger, self._on_initiate_trigger,
# this plugin set the resource, we want it to happen first so other triggers # must run last: it takes over the jingle IQ sending (sent in the
# can get the full peer JID # background once the proposal is accepted), after the other
priority=host.trigger.MAX_PRIORITY, # triggers have built the IQ
priority=host.trigger.MIN_PRIORITY,
) )
host.trigger.add_with_check( host.trigger.add_with_check(
"XEP-0166_terminate", "XEP-0166_terminate",
@ -176,23 +177,37 @@ class XEP_0353:
# FIXME: let's application decide timeout? # FIXME: let's application decide timeout?
response_d.addTimeout(2 * 60, reactor) response_d.addTimeout(2 * 60, reactor)
client._xep_0353_pending_sessions[session["id"]] = response_d client._xep_0353_pending_sessions[session["id"]] = response_d
await client.send_message_data(mess_data)
# the jingle IQ is sent in the background once the proposal is accepted: returning
# False takes over the sending, so the session id is available right away and the
# session can be cancelled while the proposal is pending
defer.ensureDeferred(
self._send_jingle_after_accept(client, session, iq_elt, response_d)
)
return False
async def _send_jingle_after_accept(
self,
client: SatXMPPEntity,
session: dict,
iq_elt: domish.Element,
response_d: defer.Deferred,
) -> None:
"""Send the jingle session-initiate once the proposal is accepted."""
session_id = session["id"]
e = None
try: try:
await client.send_message_data(mess_data)
accepting_jid = await response_d accepting_jid = await response_d
except defer.TimeoutError: except defer.TimeoutError as timeout_e:
log.warning( log.warning(
_("Message initiation with {peer_jid} timed out").format( _("Message initiation with {peer_jid} timed out").format(
peer_jid=peer_jid peer_jid=session["peer_jid"]
) )
) )
except exceptions.CancelError as e: e = exceptions.CancelError(timeout_e)
for content in session["contents"].values(): e.reason = "timeout"
await content["application"].handler.jingle_preflight_cancel( except (exceptions.CancelError, RetractException) as cancel_e:
client, session, e e = cancel_e
)
self._j.delete_session(client, session["id"])
return False
else: else:
if iq_elt["to"] != accepting_jid.userhost(): if iq_elt["to"] != accepting_jid.userhost():
raise exceptions.InternalError( raise exceptions.InternalError(
@ -202,9 +217,24 @@ class XEP_0353:
) )
iq_elt["to"] = accepting_jid.full() iq_elt["to"] = accepting_jid.full()
session["peer_jid"] = accepting_jid session["peer_jid"] = accepting_jid
if self._j.get_session(client, session_id) is None:
# the session was deleted while waiting for the acceptance
return
try:
await iq_elt.send()
except Exception:
log.exception("Error while sending jingle <iq/> stanza")
self._j.delete_session(client, session_id)
raise
finally: finally:
del client._xep_0353_pending_sessions[session["id"]] client._xep_0353_pending_sessions.pop(session_id, None)
return True if e is not None:
# notify the application of the cancelled initiation, then clean the session
for content in session["contents"].values():
await content["application"].handler.jingle_preflight_cancel(
client, session, e
)
self._j.delete_session(client, session_id)
def _terminate_trigger( def _terminate_trigger(
self, client: SatXMPPEntity, session: dict, reason_elt: domish.Element self, client: SatXMPPEntity, session: dict, reason_elt: domish.Element