1.. _using_asyncio: 2 3============= 4Using asyncio 5============= 6 7Block on IQ sending 8~~~~~~~~~~~~~~~~~~~ 9 10:meth:`.Iq.send` now returns a :class:`~.Future` so you can easily block with: 11 12.. code-block:: python 13 14 result = yield from iq.send() 15 16.. warning:: 17 18 If the reply is an IQ with an ``error`` type, this will raise an 19 :class:`.IqError`, and if it timeouts, it will raise an 20 :class:`.IqTimeout`. Don't forget to catch it. 21 22You can still use callbacks instead. 23 24XEP plugin integration 25~~~~~~~~~~~~~~~~~~~~~~ 26 27The same changes from the SleekXMPP API apply, so you can do: 28 29.. code-block:: python 30 31 iq_info = yield from self.xmpp['xep_0030'].get_info(jid) 32 33But the following will only return a Future: 34 35.. code-block:: python 36 37 iq_info = self.xmpp['xep_0030'].get_info(jid) 38 39 40Callbacks, Event Handlers, and Stream Handlers 41~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 42 43IQ callbacks and :term:`Event Handlers <event handler>` can be coroutine 44functions; in this case, they will be scheduled in the event loop using 45:meth:`.asyncio.async` and not ran immediately. 46 47A :class:`.CoroutineCallback` class has been added as well for 48:term:`Stream Handlers <stream handler>`, which will use 49:meth:`.asyncio.async` to schedule the callback. 50 51Running the event loop 52~~~~~~~~~~~~~~~~~~~~~~ 53 54:meth:`.XMLStream.process` is only a thin wrapper on top of 55``loop.run_forever()`` (if ``timeout`` is provided then it will 56only run for this amount of time, and if ``forever`` is False it will 57run until disconnection). 58 59Therefore you can handle the event loop in any way you like 60instead of using ``process()``. 61 62 63Examples 64~~~~~~~~ 65 66Blocking until the session is established 67----------------------------------------- 68 69This code blocks until the XMPP session is fully established, which 70can be useful to make sure external events aren’t triggering XMPP 71callbacks while everything is not ready. 72 73.. code-block:: python 74 75 import asyncio, slixmpp 76 77 client = slixmpp.ClientXMPP('jid@example', 'password') 78 client.connected_event = asyncio.Event() 79 callback = lambda _: client.connected_event.set() 80 client.add_event_handler('session_start', callback) 81 client.connect() 82 loop.run_until_complete(event.wait()) 83 # do some other stuff before running the event loop, e.g. 84 # loop.run_until_complete(httpserver.init()) 85 client.process() 86 87 88Use with other asyncio-based libraries 89-------------------------------------- 90 91This code interfaces with aiohttp to retrieve two pages asynchronously 92when the session is established, and then send the HTML content inside 93a simple <message>. 94 95.. code-block:: python 96 97 import asyncio, aiohttp, slixmpp 98 99 @asyncio.coroutine 100 def get_pythonorg(event): 101 req = yield from aiohttp.request('get', 'http://www.python.org') 102 text = yield from req.text 103 client.send_message(mto='jid2@example', mbody=text) 104 105 @asyncio.coroutine 106 def get_asyncioorg(event): 107 req = yield from aiohttp.request('get', 'http://www.asyncio.org') 108 text = yield from req.text 109 client.send_message(mto='jid3@example', mbody=text) 110 111 client = slixmpp.ClientXMPP('jid@example', 'password') 112 client.add_event_handler('session_start', get_pythonorg) 113 client.add_event_handler('session_start', get_asyncioorg) 114 client.connect() 115 client.process() 116 117 118Blocking Iq 119----------- 120 121This client checks (via XEP-0092) the software used by every entity it 122receives a message from. After this, it sends a message to a specific 123JID indicating its findings. 124 125.. code-block:: python 126 127 import asyncio, slixmpp 128 129 class ExampleClient(slixmpp.ClientXMPP): 130 def __init__(self, *args, **kwargs): 131 slixmpp.ClientXMPP.__init__(self, *args, **kwargs) 132 self.register_plugin('xep_0092') 133 self.add_event_handler('message', self.on_message) 134 135 @asyncio.coroutine 136 def on_message(self, event): 137 # You should probably handle IqError and IqTimeout exceptions here 138 # but this is an example. 139 version = yield from self['xep_0092'].get_version(message['from']) 140 text = "%s sent me a message, he runs %s" % (message['from'], 141 version['software_version']['name']) 142 self.send_message(mto='master@example.tld', mbody=text) 143 144 client = ExampleClient('jid@example', 'password') 145 client.connect() 146 client.process() 147 148 149