summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormathieui <mathieui@mathieui.net>2021-02-15 21:46:59 +0100
committermathieui <mathieui@mathieui.net>2021-02-24 20:50:05 +0100
commitbabd98dac7ffca467d0f7303cfd8bb72cca11f1b (patch)
tree8e607c25086782f5ee7b02774d947cb9a424d286
parent73814605565df02ae534b5d0b57868b6cafa58f7 (diff)
downloadslixmpp-babd98dac7ffca467d0f7303cfd8bb72cca11f1b.tar.gz
slixmpp-babd98dac7ffca467d0f7303cfd8bb72cca11f1b.tar.bz2
slixmpp-babd98dac7ffca467d0f7303cfd8bb72cca11f1b.tar.xz
slixmpp-babd98dac7ffca467d0f7303cfd8bb72cca11f1b.zip
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.
-rw-r--r--slixmpp/xmlstream/xmlstream.py40
1 files changed, 39 insertions, 1 deletions
diff --git a/slixmpp/xmlstream/xmlstream.py b/slixmpp/xmlstream/xmlstream.py
index 8a726e15..2f506018 100644
--- a/slixmpp/xmlstream/xmlstream.py
+++ b/slixmpp/xmlstream/xmlstream.py
@@ -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.