diff options
Diffstat (limited to 'docs/using_asyncio.rst')
-rw-r--r-- | docs/using_asyncio.rst | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/docs/using_asyncio.rst b/docs/using_asyncio.rst new file mode 100644 index 00000000..55ed7679 --- /dev/null +++ b/docs/using_asyncio.rst @@ -0,0 +1,148 @@ +.. _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() + + |