xmlstream: add event_async() for events that need in-order processing

Essentially stream feature handlers which can then make sure the feature
has been process correctly (e.g. 0077).

This is the same approach as slixmpp!4.
This commit is contained in:
mathieui 2021-02-15 21:46:59 +01:00
parent 7381460556
commit babd98dac7

View file

@ -850,8 +850,46 @@ class XMLStream(asyncio.BaseProtocol):
"""
return len(self.__event_handlers.get(name, []))
def event(self, name, data={}):
async def event_async(self, name: str, data: Any = {}):
"""Manually trigger a custom event, but await coroutines immediately.
This event generator should only be called in situations when
in-order processing of events is important, such as features
handling.
:param name: The name of the event to trigger.
:param data: Data that will be passed to each event handler.
Defaults to an empty dictionary, but is usually
a stanza object.
"""
handlers = self.__event_handlers.get(name, [])[:]
for handler in handlers:
handler_callback, disposable = handler
if disposable:
# If the handler is disposable, we will go ahead and
# remove it now instead of waiting for it to be
# processed in the queue.
try:
self.__event_handlers[name].remove(handler)
except ValueError:
pass
# If the callback is a coroutine, schedule it instead of
# running it directly
if iscoroutinefunction(handler_callback):
try:
await handler_callback(data)
except Exception as exc:
self.exception(exc)
else:
try:
handler_callback(data)
except Exception as e:
self.exception(e)
def event(self, name: str, data: Any = {}):
"""Manually trigger a custom event.
Coroutine handlers are wrapped into a future and sent into the
event loop for their execution, and not awaited.
:param name: The name of the event to trigger.
:param data: Data that will be passed to each event handler.