.. _using_asyncio: ============= Using asyncio ============= Block on IQ sending ~~~~~~~~~~~~~~~~~~~ :meth:`.Iq.send` now returns a :class:`~.Future` so you can easily block with: .. code-block:: python result = yield from iq.send() .. warning:: If the reply is an IQ with an ``error`` type, this will raise an :class:`.IqError`, and if it timeouts, it will raise an :class:`.IqTimeout`. Don't forget to catch it. You can still use callbacks instead. XEP plugin integration ~~~~~~~~~~~~~~~~~~~~~~ The same changes from the SleekXMPP API apply, so you can do: .. code-block:: python iq_info = yield from self.xmpp['xep_0030'].get_info(jid) But the following will only return a Future: .. code-block:: python iq_info = self.xmpp['xep_0030'].get_info(jid) Callbacks, Event Handlers, and Stream Handlers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IQ callbacks and :term:`Event Handlers <event handler>` can be coroutine functions; in this case, they will be scheduled in the event loop using :meth:`.asyncio.async` and not ran immediately. A :class:`.CoroutineCallback` class has been added as well for :term:`Stream Handlers <stream handler>`, which will use :meth:`.asyncio.async` to schedule the callback. Running the event loop ~~~~~~~~~~~~~~~~~~~~~~ :meth:`.XMLStream.process` is only a thin wrapper on top of ``loop.run_forever()`` (if ``timeout`` is provided then it will only run for this amount of time, and if ``forever`` is False it will run until disconnection). Therefore you can handle the event loop in any way you like instead of using ``process()``. Examples ~~~~~~~~ Blocking until the session is established ----------------------------------------- This code blocks until the XMPP session is fully established, which can be useful to make sure external events aren’t triggering XMPP callbacks while everything is not ready. .. code-block:: python import asyncio, slixmpp client = slixmpp.ClientXMPP('jid@example', 'password') client.connected_event = asyncio.Event() callback = lambda _: client.connected_event.set() client.add_event_handler('session_start', callback) client.connect() loop.run_until_complete(event.wait()) # do some other stuff before running the event loop, e.g. # loop.run_until_complete(httpserver.init()) client.process() Use with other asyncio-based libraries -------------------------------------- This code interfaces with aiohttp to retrieve two pages asynchronously when the session is established, and then send the HTML content inside a simple <message>. .. code-block:: python import asyncio, aiohttp, slixmpp @asyncio.coroutine def get_pythonorg(event): req = yield from aiohttp.request('get', 'http://www.python.org') text = yield from req.text client.send_message(mto='jid2@example', mbody=text) @asyncio.coroutine def get_asyncioorg(event): req = yield from aiohttp.request('get', 'http://www.asyncio.org') text = yield from req.text client.send_message(mto='jid3@example', mbody=text) client = slixmpp.ClientXMPP('jid@example', 'password') client.add_event_handler('session_start', get_pythonorg) client.add_event_handler('session_start', get_asyncioorg) client.connect() client.process() Blocking Iq ----------- This client checks (via XEP-0092) the software used by every entity it receives a message from. After this, it sends a message to a specific JID indicating its findings. .. code-block:: python import asyncio, slixmpp class ExampleClient(slixmpp.ClientXMPP): def __init__(self, *args, **kwargs): slixmpp.ClientXMPP.__init__(self, *args, **kwargs) self.register_plugin('xep_0092') self.add_event_handler('message', self.on_message) @asyncio.coroutine def on_message(self, event): # You should probably handle IqError and IqTimeout exceptions here # but this is an example. version = yield from self['xep_0092'].get_version(message['from']) text = "%s sent me a message, he runs %s" % (message['from'], version['software_version']['name']) self.send_message(mto='master@example.tld', mbody=text) client = ExampleClient('jid@example', 'password') client.connect() client.process()