Merge branch 'stream-features-sync-event' into 'master'

Allow "sync" events to be processed in-order

See merge request poezio/slixmpp!129
This commit is contained in:
mathieui 2021-02-24 20:59:12 +01:00
commit 5f9ab45a5e
2 changed files with 42 additions and 4 deletions

View file

@ -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

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.