summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--slixmpp/plugins/xep_0077/register.py6
-rw-r--r--slixmpp/xmlstream/xmlstream.py40
2 files changed, 42 insertions, 4 deletions
diff --git a/slixmpp/plugins/xep_0077/register.py b/slixmpp/plugins/xep_0077/register.py
index 953fee70..1850b2c9 100644
--- a/slixmpp/plugins/xep_0077/register.py
+++ b/slixmpp/plugins/xep_0077/register.py
@@ -203,14 +203,14 @@ class XEP_0077(BasePlugin):
self.xmpp.del_filter('in', self._force_stream_feature)
return stanza
- def _handle_register_feature(self, features):
+ async def _handle_register_feature(self, features):
if 'mechanisms' in self.xmpp.features:
# We have already logged in with an account
return False
if self.create_account and self.xmpp.event_handled('register'):
- form = self.get_registration()
- self.xmpp.event('register', form)
+ form = await self.get_registration()
+ await self.xmpp.event_async('register', form)
return True
return False
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.