Update the documentation and examples
- update most of the examples with slixmpp - change the help channels pointed out in the doc - add a page listing differences from slixmpp and how to use asyncio nicely with slixmpp - fix some in-code rst documentation
This commit is contained in:
8
docs/api/stanza/iq.rst
Normal file
8
docs/api/stanza/iq.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
IQ Stanza
|
||||
=========
|
||||
|
||||
.. module:: slixmpp.stanza
|
||||
|
||||
.. autoclass:: Iq
|
||||
:members:
|
||||
|
||||
7
docs/api/stanza/message.rst
Normal file
7
docs/api/stanza/message.rst
Normal file
@@ -0,0 +1,7 @@
|
||||
Message Stanza
|
||||
==============
|
||||
|
||||
.. module:: slixmpp.stanza
|
||||
|
||||
.. autoclass:: Message
|
||||
:members:
|
||||
8
docs/api/stanza/presence.rst
Normal file
8
docs/api/stanza/presence.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
Presence Stanza
|
||||
===============
|
||||
|
||||
.. module:: slixmpp.stanza
|
||||
|
||||
.. autoclass:: Presence
|
||||
:members:
|
||||
|
||||
8
docs/api/stanza/rootstanza.rst
Normal file
8
docs/api/stanza/rootstanza.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
Root Stanza
|
||||
===========
|
||||
|
||||
.. module:: slixmpp.stanza.rootstanza
|
||||
|
||||
.. autoclass:: RootStanza
|
||||
:members:
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
.. module:: slixmpp.xmlstream.filesocket
|
||||
|
||||
.. _filesocket:
|
||||
|
||||
Python 2.6 File Socket Shims
|
||||
============================
|
||||
|
||||
.. autoclass:: FileSocket
|
||||
:members:
|
||||
|
||||
.. autoclass:: Socket26
|
||||
:members:
|
||||
@@ -10,15 +10,19 @@ The Basic Handler
|
||||
|
||||
Callback
|
||||
--------
|
||||
.. module:: slixmpp.xmlstream.handler.callback
|
||||
.. module:: slixmpp.xmlstream.handler
|
||||
|
||||
.. autoclass:: Callback
|
||||
:members:
|
||||
|
||||
CoroutineCallback
|
||||
-----------------
|
||||
|
||||
.. autoclass:: CoroutineCallback
|
||||
:members:
|
||||
|
||||
Waiter
|
||||
------
|
||||
.. module:: slixmpp.xmlstream.handler.waiter
|
||||
|
||||
.. autoclass:: Waiter
|
||||
:members:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Jabber IDs (JID)
|
||||
=================
|
||||
|
||||
.. module:: slixmpp.xmlstream.jid
|
||||
.. module:: slixmpp.jid
|
||||
|
||||
.. autoclass:: JID
|
||||
:members:
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
=========
|
||||
Scheduler
|
||||
=========
|
||||
|
||||
.. module:: slixmpp.xmlstream.scheduler
|
||||
|
||||
.. autoclass:: Task
|
||||
:members:
|
||||
|
||||
.. autoclass:: Scheduler
|
||||
:members:
|
||||
@@ -61,8 +61,8 @@ interacting with a given :term:`stanza` a :term:`stanza object`.
|
||||
To make dealing with more complicated and nested :term:`stanzas <stanza>`
|
||||
or XML chunks easier, :term:`stanza objects <stanza object>` can be
|
||||
composed in two ways: as iterable child objects or as plugins. Iterable
|
||||
child stanzas, or :term:`substanzas`, are accessible through a special
|
||||
``'substanzas'`` interface. This option is useful for stanzas which
|
||||
child stanzas, or :term:`substanzas <substanza>`, are accessible through a
|
||||
special ``'substanzas'`` interface. This option is useful for stanzas which
|
||||
may contain more than one of the same kind of element. When there is
|
||||
only one child element, the plugin method is more useful. For plugins,
|
||||
a parent stanza object delegates one of its XML child elements to the
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace because that is already declared by the stream header. But, if
|
||||
you create a :class:`~slixmpp.stanza.message.Message` instance and dump
|
||||
it to the terminal, the ``jabber:client`` namespace will appear.
|
||||
|
||||
.. autofunction:: tostring
|
||||
.. autofunction:: slixmpp.xmlstream.tostring
|
||||
|
||||
Escaping Special Characters
|
||||
---------------------------
|
||||
@@ -43,4 +43,5 @@ In the future, the use of CDATA sections may be allowed to reduce the
|
||||
size of escaped text or for when other XMPP processing agents do not
|
||||
undertand these entities.
|
||||
|
||||
.. autofunction:: xml_escape
|
||||
..
|
||||
autofunction:: xml_escape
|
||||
|
||||
@@ -24,21 +24,20 @@ patterns is received; these callbacks are also referred to as :term:`stream
|
||||
handlers <stream handler>`. The class also provides a basic eventing system
|
||||
which can be triggered either manually or on a timed schedule.
|
||||
|
||||
The Main Threads
|
||||
~~~~~~~~~~~~~~~~
|
||||
:class:`~slixmpp.xmlstream.xmlstream.XMLStream` instances run using at
|
||||
least three background threads: the send thread, the read thread, and the
|
||||
scheduler thread. The send thread is in charge of monitoring the send queue
|
||||
and writing text to the outgoing XML stream. The read thread pulls text off
|
||||
of the incoming XML stream and stores the results in an event queue. The
|
||||
scheduler thread is used to emit events after a given period of time.
|
||||
The event loop
|
||||
~~~~~~~~~~~~~~
|
||||
:class:`~slixmpp.xmlstream.xmlstream.XMLStream` instances inherit the
|
||||
:class:`asyncio.BaseProtocol` class, and therefore do not have to handle
|
||||
reads and writes directly, but receive data through
|
||||
:meth:`~slixmpp.xmlstream.xmlstream.XMLStream.data_received` and write
|
||||
data in the socket transport.
|
||||
|
||||
Additionally, the main event processing loop may be executed in its
|
||||
own thread if Slixmpp is being used in the background for another
|
||||
application.
|
||||
Upon receiving data, :term:`stream handlers <stream handler>` are run
|
||||
immediately, except if they are coroutines, in which case they are
|
||||
scheduled using :meth:`asyncio.async`.
|
||||
|
||||
Short-lived threads may also be spawned as requested for threaded
|
||||
:term:`event handlers <event handler>`.
|
||||
:term:`Event handlers <event handler>` (which are called inside
|
||||
:term:`stream handlers <stream handler>`) work the same way.
|
||||
|
||||
How XML Text is Turned into Action
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -53,7 +52,7 @@ when this bit of XML is received (with an assumed namespace of
|
||||
</message>
|
||||
|
||||
|
||||
1. **Convert XML strings into objects.**
|
||||
#. **Convert XML strings into objects.**
|
||||
|
||||
Incoming text is parsed and converted into XML objects (using
|
||||
ElementTree) which are then wrapped into what are referred to as
|
||||
@@ -66,65 +65,43 @@ when this bit of XML is received (with an assumed namespace of
|
||||
``{jabber:client}message`` is associated with the class
|
||||
:class:`~slixmpp.stanza.Message`.
|
||||
|
||||
2. **Match stanza objects to callbacks.**
|
||||
#. **Match stanza objects to callbacks.**
|
||||
|
||||
These objects are then compared against the stored patterns associated
|
||||
with the registered callback handlers. For each match, a copy of the
|
||||
:term:`stanza object` is paired with a reference to the handler and
|
||||
placed into the event queue.
|
||||
with the registered callback handlers.
|
||||
|
||||
Our :class:`~slixmpp.stanza.Message` object is thus paired with the message stanza handler
|
||||
:meth:`BaseXMPP._handle_message` to create the tuple::
|
||||
Each handler matching our :term:`stanza object` is then added to a list.
|
||||
|
||||
('stanza', stanza_obj, handler)
|
||||
#. **Processing callbacks**
|
||||
|
||||
3. **Process the event queue.**
|
||||
Every handler in the list is then called with the :term:`stanza object`
|
||||
as a parameter; if the handler is a
|
||||
:class:`~slixmpp.xmlstream.handler.CoroutineCallback`
|
||||
then it will be scheduled in the event loop using :meth:`asyncio.async`
|
||||
instead of run.
|
||||
|
||||
The event queue is the heart of Slixmpp. Nearly every action that
|
||||
takes place is first inserted into this queue, whether that be received
|
||||
stanzas, custom events, or scheduled events.
|
||||
|
||||
When the stanza is pulled out of the event queue with an associated
|
||||
callback, the callback function is executed with the stanza as its only
|
||||
parameter.
|
||||
|
||||
.. warning::
|
||||
The callback, aka :term:`stream handler`, is executed in the main event
|
||||
processing thread. If the handler blocks, event processing will also
|
||||
block.
|
||||
|
||||
4. **Raise Custom Events**
|
||||
#. **Raise Custom Events**
|
||||
|
||||
Since a :term:`stream handler` shouldn't block, if extensive processing
|
||||
for a stanza is required (such as needing to send and receive an
|
||||
:class:`~slixmpp.stanza.Iq` stanza), then custom events must be used.
|
||||
These events are not explicitly tied to the incoming XML stream and may
|
||||
be raised at any time. Importantly, these events may be handled in their
|
||||
own thread.
|
||||
be raised at any time.
|
||||
|
||||
When the event is raised, a copy of the stanza is created for each
|
||||
handler registered for the event. In contrast to :term:`stream handlers
|
||||
<stream handler>`, these functions are referred to as :term:`event
|
||||
handlers <event handler>`. Each stanza/handler pair is then put into the
|
||||
event queue.
|
||||
In contrast to :term:`stream handlers <stream handler>`, these functions
|
||||
are referred to as :term:`event handlers <event handler>`.
|
||||
|
||||
The code for :meth:`BaseXMPP._handle_message` follows this pattern, and
|
||||
raises a ``'message'`` event::
|
||||
raises a ``'message'`` event
|
||||
|
||||
self.event('message', msg)
|
||||
.. code-block:: python
|
||||
|
||||
The event call then places the message object back into the event queue
|
||||
paired with an :term:`event handler`::
|
||||
self.event('message', msg)
|
||||
|
||||
('event', 'message', msg_copy1, custom_event_handler_1)
|
||||
('event', 'message', msg_copy2, custom_evetn_handler_2)
|
||||
#. **Process Custom Events**
|
||||
|
||||
5. **Process Custom Events**
|
||||
|
||||
The stanza and :term:`event handler` are then pulled from the event
|
||||
queue, and the handler is executed, passing the stanza as its only
|
||||
argument. If the handler was registered as threaded, then a new thread
|
||||
will be spawned for it.
|
||||
The :term:`event handlers <event handler>` are then executed, passing
|
||||
the stanza as the only argument.
|
||||
|
||||
.. note::
|
||||
Events may be raised without needing :term:`stanza objects <stanza object>`.
|
||||
@@ -135,9 +112,9 @@ when this bit of XML is received (with an assumed namespace of
|
||||
Finally, after a long trek, our message is handed off to the user's
|
||||
custom handler in order to do awesome stuff::
|
||||
|
||||
msg.reply()
|
||||
msg['body'] = "Hey! This is awesome!"
|
||||
msg.send()
|
||||
reply = msg.reply()
|
||||
reply['body'] = "Hey! This is awesome!"
|
||||
reply.send()
|
||||
|
||||
|
||||
.. index:: BaseXMPP, XMLStream
|
||||
|
||||
@@ -105,7 +105,7 @@ html_theme = 'haiku'
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
html_title = 'Slixmpp'
|
||||
html_title = 'slixmpp'
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
html_short_title = '%s Documentation' % release
|
||||
@@ -219,4 +219,4 @@ man_pages = [
|
||||
[u'Nathan Fritz, Lance Stout'], 1)
|
||||
]
|
||||
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.2', 'python-objects.inv')}
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/3.4', 'python-objects.inv')}
|
||||
|
||||
@@ -634,8 +634,9 @@ with some additional registration fields implemented.
|
||||
if self.backend.register(iq['from'].bare, iq['register']):
|
||||
# Successful registration
|
||||
self.xmpp.event('registered_user', iq)
|
||||
iq.reply().set_payload(iq['register'].xml)
|
||||
iq.send()
|
||||
reply = iq.reply()
|
||||
reply.set_payload(iq['register'].xml)
|
||||
reply.send()
|
||||
else:
|
||||
# Conflicting registration
|
||||
self._sendError(iq, '409', 'cancel', 'conflict',
|
||||
@@ -666,14 +667,16 @@ with some additional registration fields implemented.
|
||||
# Add a blank field
|
||||
reg.addField(field)
|
||||
|
||||
iq.reply().set_payload(reg.xml)
|
||||
iq.send()
|
||||
reply = iq.reply()
|
||||
reply.set_payload(reg.xml)
|
||||
reply.send()
|
||||
|
||||
def _sendError(self, iq, code, error_type, name, text=''):
|
||||
iq.reply().set_payload(iq['register'].xml)
|
||||
iq.error()
|
||||
iq['error']['code'] = code
|
||||
iq['error']['type'] = error_type
|
||||
iq['error']['condition'] = name
|
||||
iq['error']['text'] = text
|
||||
iq.send()
|
||||
reply = iq.reply()
|
||||
reply.set_payload(iq['register'].xml)
|
||||
reply.error()
|
||||
reply['error']['code'] = code
|
||||
reply['error']['type'] = error_type
|
||||
reply['error']['condition'] = name
|
||||
reply['error']['text'] = text
|
||||
reply.send()
|
||||
|
||||
47
docs/differences.rst
Normal file
47
docs/differences.rst
Normal file
@@ -0,0 +1,47 @@
|
||||
.. _differences:
|
||||
|
||||
Differences from SleekXMPP
|
||||
==========================
|
||||
|
||||
**Python 3.4+ only**
|
||||
slixmpp will only work on python 3.4 and above.
|
||||
|
||||
**Stanza copies**
|
||||
The same stanza object is given through all the handlers; a handler that
|
||||
edits the stanza object should make its own copy.
|
||||
|
||||
**Replies**
|
||||
Because stanzas are not copied anymore,
|
||||
:meth:`Stanza.reply() <.StanzaBase.reply>` calls
|
||||
(for :class:`IQs <.Iq>`, :class:`Messages <.Message>`, etc)
|
||||
now return a new object instead of editing the stanza object
|
||||
in-place.
|
||||
|
||||
**Block and threaded arguments**
|
||||
All the functions that had a ``threaded=`` or ``block=`` argument
|
||||
do not have it anymore. Also, :meth:`.Iq.send` **does not block
|
||||
anymore**.
|
||||
|
||||
**Coroutine facilities**
|
||||
**See** :ref:`using_asyncio`
|
||||
|
||||
If an event handler is a coroutine, it will be called asynchronously
|
||||
in the event loop instead of inside the event caller.
|
||||
|
||||
A CoroutineCallback class has been added to create coroutine stream
|
||||
handlers, which will be also handled in the event loop.
|
||||
|
||||
The :class:`~.slixmpp.stanza.Iq` object’s :meth:`~.slixmpp.stanza.Iq.send`
|
||||
method now takes a *coroutine* parameter which, if set to ``True``,
|
||||
will return a coroutine which will (asyncio-)block until the reply
|
||||
is received.
|
||||
|
||||
Many plugins (WIP) calls which retrieve information also accept this
|
||||
``coroutine`` parameter.
|
||||
|
||||
**Architectural differences**
|
||||
slixmpp does not have an event queue anymore, and instead processes
|
||||
handlers directly after receiving the XML stanza.
|
||||
|
||||
.. note::
|
||||
If you find something that doesn’t work but should, please report it.
|
||||
@@ -7,19 +7,11 @@ Create and Run a Server Component
|
||||
.. note::
|
||||
|
||||
If you have any issues working through this quickstart guide
|
||||
or the other tutorials here, please either send a message to the
|
||||
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
||||
or join the chat room at `sleek@conference.jabber.org
|
||||
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||
join the chat room at `slixmpp@muc.poez.io
|
||||
<xmpp:slixmpp@muc.poez.io?join>`_.
|
||||
|
||||
If you have not yet installed Slixmpp, do so now by either checking out a version
|
||||
from `Github <http://github.com/fritzy/Slixmpp>`_, or installing it using ``pip``
|
||||
or ``easy_install``.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
pip install slixmpp # Or: easy_install slixmpp
|
||||
|
||||
with `Git <http://git.poez.io/slixmpp>`_.
|
||||
|
||||
Many XMPP applications eventually graduate to requiring to run as a server
|
||||
component in order to meet scalability requirements. To demonstrate how to
|
||||
|
||||
@@ -7,19 +7,11 @@ Slixmpp Quickstart - Echo Bot
|
||||
.. note::
|
||||
|
||||
If you have any issues working through this quickstart guide
|
||||
or the other tutorials here, please either send a message to the
|
||||
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
||||
or join the chat room at `sleek@conference.jabber.org
|
||||
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||
join the chat room at `slixmpp@muc.poez.io
|
||||
<xmpp:slixmpp@muc.poez.io?join>`_.
|
||||
|
||||
If you have not yet installed Slixmpp, do so now by either checking out a version
|
||||
from `Github <http://github.com/fritzy/Slixmpp>`_, or installing it using ``pip``
|
||||
or ``easy_install``.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
pip install slixmpp # Or: easy_install slixmpp
|
||||
|
||||
with `Git <http://git.poez.io/slixmpp>`_.
|
||||
|
||||
As a basic starting project, we will create an echo bot which will reply to any
|
||||
messages sent to it. We will also go through adding some basic command line configuration
|
||||
@@ -44,6 +36,7 @@ To get started, here is a brief outline of the structure that the final project
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import asyncio
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
@@ -59,24 +52,6 @@ To get started, here is a brief outline of the structure that the final project
|
||||
|
||||
'''Finally, we connect the bot and start listening for messages'''
|
||||
|
||||
Default Encoding
|
||||
----------------
|
||||
XMPP requires support for UTF-8 and so Slixmpp must use UTF-8 as well. In
|
||||
Python3 this is simple because Unicode is the default string type. For Python2.6+
|
||||
the situation is not as easy because standard strings are simply byte arrays and
|
||||
use ASCII. We can get Python to use UTF-8 as the default encoding by including:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
from slixmpp.util.misc_ops import setdefaultencoding
|
||||
setdefaultencoding('utf8')
|
||||
|
||||
.. warning::
|
||||
|
||||
Until we are able to ensure that Slixmpp will always use Unicode in Python2.6+, this
|
||||
may cause issues embedding Slixmpp into other applications which assume ASCII encoding.
|
||||
|
||||
Creating the EchoBot Class
|
||||
--------------------------
|
||||
|
||||
@@ -313,9 +288,9 @@ the ``EchoBot.__init__`` method instead.
|
||||
xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
Now we're ready to connect and begin echoing messages. If you have the package
|
||||
``dnspython`` installed, then the :meth:`slixmpp.clientxmpp.ClientXMPP` method
|
||||
``aiodns`` installed, then the :meth:`slixmpp.clientxmpp.ClientXMPP` method
|
||||
will perform a DNS query to find the appropriate server to connect to for the
|
||||
given JID. If you do not have ``dnspython``, then Slixmpp will attempt to
|
||||
given JID. If you do not have ``aiodns``, then Slixmpp will attempt to
|
||||
connect to the hostname used by the JID, unless an address tuple is supplied
|
||||
to :meth:`slixmpp.clientxmpp.ClientXMPP`.
|
||||
|
||||
@@ -330,22 +305,6 @@ to :meth:`slixmpp.clientxmpp.ClientXMPP`.
|
||||
else:
|
||||
print('Unable to connect')
|
||||
|
||||
.. note::
|
||||
|
||||
For Google Talk users withouth ``dnspython`` installed, the above code
|
||||
should look like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# .. option parsing & echo bot configuration
|
||||
|
||||
if xmpp.connect(('talk.google.com', 5222)):
|
||||
xmpp.process(block=True)
|
||||
else:
|
||||
print('Unable to connect')
|
||||
|
||||
To begin responding to messages, you'll see we called :meth:`slixmpp.basexmpp.BaseXMPP.process`
|
||||
which will start the event handling, send queue, and XML reader threads. It will also call
|
||||
the :meth:`slixmpp.plugins.base.BasePlugin.post_init` method on all registered plugins. By
|
||||
|
||||
@@ -7,19 +7,11 @@ Mulit-User Chat (MUC) Bot
|
||||
.. note::
|
||||
|
||||
If you have any issues working through this quickstart guide
|
||||
or the other tutorials here, please either send a message to the
|
||||
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
||||
or join the chat room at `sleek@conference.jabber.org
|
||||
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||
join the chat room at `slixmpp@muc.poez.io
|
||||
<xmpp:slixmpp@muc.poez.io?join>`_.
|
||||
|
||||
If you have not yet installed Slixmpp, do so now by either checking out a version
|
||||
from `Github <http://github.com/fritzy/Slixmpp>`_, or installing it using ``pip``
|
||||
or ``easy_install``.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
pip install slixmpp # Or: easy_install slixmpp
|
||||
|
||||
from `Git <http://git.poez.io/slixmpp>`_.
|
||||
|
||||
Now that you've got the basic gist of using Slixmpp by following the
|
||||
echobot example (:ref:`echobot`), we can use one of the bundled plugins
|
||||
|
||||
@@ -7,10 +7,8 @@ Enable HTTP Proxy Support
|
||||
.. note::
|
||||
|
||||
If you have any issues working through this quickstart guide
|
||||
or the other tutorials here, please either send a message to the
|
||||
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
||||
or join the chat room at `sleek@conference.jabber.org
|
||||
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||
join the chat room at `slixmpp@muc.poez.io
|
||||
<xmpp:slixmpp@muc.poez.io?join>`_.
|
||||
|
||||
In some instances, you may wish to route XMPP traffic through
|
||||
an HTTP proxy, probably to get around restrictive firewalls.
|
||||
|
||||
@@ -4,10 +4,8 @@ Sign in, Send a Message, and Disconnect
|
||||
.. note::
|
||||
|
||||
If you have any issues working through this quickstart guide
|
||||
or the other tutorials here, please either send a message to the
|
||||
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
||||
or join the chat room at `sleek@conference.jabber.org
|
||||
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||
join the chat room at `slixmpp@muc.poez.io
|
||||
<xmpp:slixmpp@muc.poez.io?join>`_.
|
||||
|
||||
A common use case for Slixmpp is to send one-off messages from
|
||||
time to time. For example, one use case could be sending out a notice when
|
||||
|
||||
@@ -9,21 +9,20 @@ Glossary
|
||||
stream handler
|
||||
A callback function that accepts stanza objects pulled directly
|
||||
from the XML stream. A stream handler is encapsulated in a
|
||||
object that includes a :term:`Matcher` object, and which provides
|
||||
additional semantics. For example, the ``Waiter`` handler wrapper
|
||||
blocks thread execution until a matching stanza is received.
|
||||
object that includes a :class:`Matcher <.MatcherBase>` object, and
|
||||
which provides additional semantics. For example, the
|
||||
:class:`.Waiter` handler wrapper blocks thread execution until a
|
||||
matching stanza is received.
|
||||
|
||||
event handler
|
||||
A callback function that responds to events raised by
|
||||
``XMLStream.event``. An event handler may be marked as
|
||||
threaded, allowing it to execute outside of the main processing
|
||||
loop.
|
||||
:meth:`.XMLStream.event`.
|
||||
|
||||
stanza object
|
||||
Informally may refer both to classes which extend ``ElementBase``
|
||||
or ``StanzaBase``, and to objects of such classes.
|
||||
Informally may refer both to classes which extend :class:`.ElementBase`
|
||||
or :class:`.StanzaBase`, and to objects of such classes.
|
||||
|
||||
A stanza object is a wrapper for an XML object which exposes ``dict``
|
||||
A stanza object is a wrapper for an XML object which exposes :class:`dict`
|
||||
like interfaces which may be assigned to, read from, or deleted.
|
||||
|
||||
stanza plugin
|
||||
|
||||
@@ -3,38 +3,25 @@ Slixmpp
|
||||
|
||||
.. sidebar:: Get the Code
|
||||
|
||||
.. code-block:: sh
|
||||
The latest source code for Slixmpp may be found on the `Git repo
|
||||
<http://git.poez.io/slixmpp>`_. ::
|
||||
|
||||
pip install slixmpp
|
||||
git clone git://git.poez.io/slixmpp
|
||||
|
||||
The latest source code for Slixmpp may be found on `Github
|
||||
<http://github.com/fritzy/Slixmpp>`_. Releases can be found in the
|
||||
``master`` branch, while the latest development version is in the
|
||||
``develop`` branch.
|
||||
|
||||
**Latest Stable Release**
|
||||
- `1.0 <http://github.com/fritzy/Slixmpp/zipball/1.0>`_
|
||||
|
||||
**Develop Releases**
|
||||
- `Latest Develop Version <http://github.com/fritzy/Slixmpp/zipball/develop>`_
|
||||
|
||||
|
||||
A mailing list and XMPP chat room are available for discussing and getting
|
||||
help with Slixmpp.
|
||||
|
||||
**Mailing List**
|
||||
`Slixmpp Discussion on Google Groups <http://groups.google.com/group/slixmpp-discussion>`_
|
||||
An XMPP chat room is available for discussing and getting help with slixmpp.
|
||||
|
||||
**Chat**
|
||||
`sleek@conference.jabber.org <xmpp:sleek@conference.jabber.org?join>`_
|
||||
`slixmpp@muc.poez.io <xmpp:slixmpp@muc.poez.io?join>`_
|
||||
|
||||
**Reporting bugs**
|
||||
You can report bugs at http://dev.louiz.org/projects/slixmpp/issues.
|
||||
|
||||
Slixmpp is an :ref:`MIT licensed <license>` XMPP library for Python 2.6/3.1+,
|
||||
and is featured in examples in
|
||||
`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271>`_
|
||||
by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived
|
||||
here from reading the Definitive Guide, please see the notes on updating
|
||||
the examples to the latest version of Slixmpp.
|
||||
.. note::
|
||||
slixmpp is a friendly fork of `SleekXMPP <https://github.com/fritzy/SleekXMPP>`_
|
||||
which goal is to use asyncio instead of threads to handle networking. See
|
||||
:ref:`differences`.
|
||||
|
||||
Slixmpp is an :ref:`MIT licensed <license>` XMPP library for Python 3.4+,
|
||||
|
||||
Slixmpp's design goals and philosphy are:
|
||||
|
||||
@@ -59,11 +46,13 @@ Slixmpp's design goals and philosphy are:
|
||||
sensible defaults and appropriate abstractions. XML can be ugly to work
|
||||
with, but it doesn't have to be that way.
|
||||
|
||||
|
||||
Here's your first Slixmpp Bot:
|
||||
--------------------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from slixmpp import ClientXMPP
|
||||
@@ -85,27 +74,13 @@ Here's your first Slixmpp Bot:
|
||||
# Here's how to access plugins once you've registered them:
|
||||
# self['xep_0030'].add_feature('echo_demo')
|
||||
|
||||
# If you are working with an OpenFire server, you will
|
||||
# need to use a different SSL version:
|
||||
# import ssl
|
||||
# self.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
def session_start(self, event):
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
|
||||
# Most get_*/set_* methods from plugins use Iq stanzas, which
|
||||
# can generate IqError and IqTimeout exceptions
|
||||
#
|
||||
# try:
|
||||
# self.get_roster()
|
||||
# except IqError as err:
|
||||
# logging.error('There was an error getting the roster')
|
||||
# logging.error(err.iq['error']['condition'])
|
||||
# self.disconnect()
|
||||
# except IqTimeout:
|
||||
# logging.error('Server is taking too long to respond')
|
||||
# self.disconnect()
|
||||
# are sent asynchronously. You can almost always provide a
|
||||
# callback that will be executed when the reply is received.
|
||||
|
||||
def message(self, msg):
|
||||
if msg['type'] in ('chat', 'normal'):
|
||||
@@ -121,9 +96,18 @@ Here's your first Slixmpp Bot:
|
||||
|
||||
xmpp = EchoBot('somejid@example.com', 'use_getpass')
|
||||
xmpp.connect()
|
||||
xmpp.process(block=True)
|
||||
xmpp.process()
|
||||
|
||||
|
||||
To read if you come from SleekXMPP
|
||||
----------------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
differences
|
||||
using_asyncio
|
||||
|
||||
|
||||
Getting Started (with Examples)
|
||||
-------------------------------
|
||||
@@ -145,7 +129,6 @@ Tutorials, FAQs, and How To Guides
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
faq
|
||||
xeps
|
||||
xmpp_tdg
|
||||
howto/stanzas
|
||||
@@ -184,9 +167,7 @@ API Reference
|
||||
api/xmlstream/handler
|
||||
api/xmlstream/matcher
|
||||
api/xmlstream/xmlstream
|
||||
api/xmlstream/scheduler
|
||||
api/xmlstream/tostring
|
||||
api/xmlstream/filesocket
|
||||
|
||||
Core Stanzas
|
||||
~~~~~~~~~~~~
|
||||
@@ -197,8 +178,6 @@ Core Stanzas
|
||||
api/stanza/message
|
||||
api/stanza/presence
|
||||
api/stanza/iq
|
||||
api/stanza/error
|
||||
api/stanza/stream_error
|
||||
|
||||
Plugins
|
||||
~~~~~~~
|
||||
@@ -220,8 +199,14 @@ Additional Info
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
Credits
|
||||
-------
|
||||
SleekXMPP Credits
|
||||
-----------------
|
||||
|
||||
.. note::
|
||||
Those people made SleekXMPP, so you should not bother them if
|
||||
you have an issue with slixmpp. But it’s still fair to credit
|
||||
them for their work.
|
||||
|
||||
|
||||
**Main Author:** `Nathan Fritz <http://andyet.net/team/fritzy>`_
|
||||
`fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_,
|
||||
|
||||
125
docs/using_asyncio.rst
Normal file
125
docs/using_asyncio.rst
Normal file
@@ -0,0 +1,125 @@
|
||||
.. _using_asyncio:
|
||||
|
||||
=============
|
||||
Using asyncio
|
||||
=============
|
||||
|
||||
Block on IQ sending
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:meth:`.Iq.send` now accepts a ``coroutine`` parameter which, if ``True``,
|
||||
will return a coroutine waiting for the IQ reply to be received.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
result = yield from iq.send(coroutine=True)
|
||||
|
||||
XEP plugin integration
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Many XEP plugins have been modified to accept this ``coroutine`` parameter as
|
||||
well, so you can do things like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
iq_info = yield from self.xmpp['xep_0030'].get_info(jid, coroutine=True)
|
||||
|
||||
|
||||
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).
|
||||
|
||||
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 event: 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'],
|
||||
coroutine=True)
|
||||
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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user