Some more docs house cleaning

This commit is contained in:
Lance Stout 2011-11-22 15:25:24 -08:00
parent 6906c15e8e
commit 329b0df3f6
2 changed files with 70 additions and 134 deletions

View file

@ -17,21 +17,21 @@ of the tedium of creating/manipulating XML.
The Foundation: XMLStream The Foundation: XMLStream
------------------------- -------------------------
``XMLStream`` is a mostly XMPP-agnostic class whose purpose is to read :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` is a mostly XMPP-agnostic
and write from a bi-directional XML stream. It also allows for callback class whose purpose is to read and write from a bi-directional XML stream.
functions to execute when XML matching given patterns is received; these It also allows for callback functions to execute when XML matching given
callbacks are also referred to as :term:`stream handlers <stream handler>`. patterns is received; these callbacks are also referred to as :term:`stream
The class also provides a basic eventing system which can be triggered handlers <stream handler>`. The class also provides a basic eventing system
either manually or on a timed schedule. which can be triggered either manually or on a timed schedule.
The Main Threads The Main Threads
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
``XMLStream`` instances run using at least three background threads: the :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` instances run using at
send thread, the read thread, and the scheduler thread. The send thread is least three background threads: the send thread, the read thread, and the
in charge of monitoring the send queue and writing text to the outgoing scheduler thread. The send thread is in charge of monitoring the send queue
XML stream. The read thread pulls text off of the incoming XML stream and and writing text to the outgoing XML stream. The read thread pulls text off
stores the results in an event queue. The scheduler thread is used to emit of the incoming XML stream and stores the results in an event queue. The
events after a given period of time. scheduler thread is used to emit events after a given period of time.
Additionally, the main event processing loop may be executed in its Additionally, the main event processing loop may be executed in its
own thread if SleekXMPP is being used in the background for another own thread if SleekXMPP is being used in the background for another
@ -61,9 +61,10 @@ when this bit of XML is received (with an assumed namespace of
new object is determined using a map of namespaced element names to new object is determined using a map of namespaced element names to
classes. classes.
Our incoming XML is thus turned into a ``Message`` :term:`stanza object` Our incoming XML is thus turned into a :class:`~sleekxmpp.stanza.Message`
because the namespaced element name ``{jabber:client}message`` is :term:`stanza object` because the namespaced element name
associated with the class ``sleekxmpp.stanza.Message``. ``{jabber:client}message`` is associated with the class
:class:`~sleekxmpp.stanza.Message`.
2. **Match stanza objects to callbacks.** 2. **Match stanza objects to callbacks.**
@ -72,8 +73,8 @@ when this bit of XML is received (with an assumed namespace of
:term:`stanza object` is paired with a reference to the handler and :term:`stanza object` is paired with a reference to the handler and
placed into the event queue. placed into the event queue.
Our ``Message`` object is thus paired with the message stanza handler Our :class:`~sleekxmpp.stanza.Message` object is thus paired with the message stanza handler
``BaseXMPP._handle_message`` to create the tuple:: :meth:`BaseXMPP._handle_message` to create the tuple::
('stanza', stanza_obj, handler) ('stanza', stanza_obj, handler)
@ -88,7 +89,7 @@ when this bit of XML is received (with an assumed namespace of
parameter. parameter.
.. warning:: .. warning::
The callback, aka :term:`stream handler`, is executed in the main The callback, aka :term:`stream handler`, is executed in the main event
processing thread. If the handler blocks, event processing will also processing thread. If the handler blocks, event processing will also
block. block.
@ -96,20 +97,22 @@ when this bit of XML is received (with an assumed namespace of
Since a :term:`stream handler` shouldn't block, if extensive processing Since a :term:`stream handler` shouldn't block, if extensive processing
for a stanza is required (such as needing to send and receive an for a stanza is required (such as needing to send and receive an
``Iq`` stanza), then custom events must be used. These events are not :class:`~sleekxmpp.stanza.Iq` stanza), then custom events must be used.
explicitly tied to the incoming XML stream and may be raised at any These events are not explicitly tied to the incoming XML stream and may
time. Importantly, these events may be handled in their own thread. be raised at any time. Importantly, these events may be handled in their
own thread.
When the event is raised, a copy of the stanza is created for each 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>`, handler registered for the event. In contrast to :term:`stream handlers
these functions are referred to as :term:`event handlers <event handler>`. <stream handler>`, these functions are referred to as :term:`event
Each stanza/handler pair is then put into the event queue. handlers <event handler>`. Each stanza/handler pair is then put into the
event queue.
.. note:: .. note::
It is possible to skip the event queue and process an event immediately It is possible to skip the event queue and process an event immediately
by using ``direct=True`` when raising the event. by using ``direct=True`` when raising the event.
The code for ``BaseXMPP._handle_message`` follows this pattern, and The code for :meth:`BaseXMPP._handle_message` follows this pattern, and
raises a ``'message'`` event:: raises a ``'message'`` event::
self.event('message', msg) self.event('message', msg)
@ -145,125 +148,30 @@ when this bit of XML is received (with an assumed namespace of
Raising XMPP Awareness: BaseXMPP Raising XMPP Awareness: BaseXMPP
-------------------------------- --------------------------------
While ``XMLStream`` attempts to shy away from anything too XMPP specific, While :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` attempts to shy away
``BaseXMPP``'s sole purpose is to provide foundational support for sending from anything too XMPP specific, :class:`~sleekxmpp.basexmpp.BaseXMPP`'s
and receiving XMPP stanzas. This support includes registering the basic sole purpose is to provide foundational support for sending and receiving
message, presence, and iq stanzas, methods for creating and sending XMPP stanzas. This support includes registering the basic message,
stanzas, and default handlers for incoming messages and keeping track of presence, and iq stanzas, methods for creating and sending stanzas, and
presence notifications. default handlers for incoming messages and keeping track of presence
notifications.
The plugin system for adding new XEP support is also maintained by The plugin system for adding new XEP support is also maintained by
``BaseXMPP``. :class:`~sleekxmpp.basexmpp.BaseXMPP`.
.. index:: ClientXMPP, BaseXMPP .. index:: ClientXMPP, BaseXMPP
ClientXMPP ClientXMPP
---------- ----------
``ClientXMPP`` extends ``BaseXMPP`` with additional logic for connecting to :class:`~sleekxmpp.clientxmpp.ClientXMPP` extends
an XMPP server by performing DNS lookups. It also adds support for stream :class:`~sleekxmpp.clientxmpp.BaseXMPP` with additional logic for connecting
to an XMPP server by performing DNS lookups. It also adds support for stream
features such as STARTTLS and SASL. features such as STARTTLS and SASL.
.. index:: ComponentXMPP, BaseXMPP .. index:: ComponentXMPP, BaseXMPP
ComponentXMPP ComponentXMPP
------------- -------------
``ComponentXMPP`` is only a thin layer on top of ``BaseXMPP`` that :class:`~sleekxmpp.componentxmpp.ComponentXMPP` is only a thin layer on top of
implements the component handshake protocol. :class:`~sleekxmpp.basexmpp.BaseXMPP` that implements the component handshake
protocol.
.. index::
double: object; stanza
Stanza Objects: A Brief Look
----------------------------
.. seealso::
See :ref:`api-stanza-objects` for a more detailed overview.
Almost worthy of their own standalone library, :term:`stanza objects <stanza object>`
are wrappers for XML objects which expose dictionary like interfaces
for manipulating their XML content. For example, consider the XML:
.. code-block:: xml
<message />
A very plain element to start with, but we can create a :term:`stanza object`
using ``sleekxmpp.stanza.Message`` as so::
msg = Message(xml=ET.fromstring("<message />"))
The ``Message`` stanza class defines interfaces such as ``'body'`` and
``'to'``, so we can assign values to those interfaces to include new XML
content::
msg['body'] = "Following so far?"
msg['to'] = 'user@example.com'
Dumping the XML content of ``msg`` (using ``msg.xml``), we find:
.. code-block:: xml
<message to="user@example.com">
<body>Following so far?</body>
</message>
The process is similar for reading from interfaces and deleting interface
contents. A :term:`stanza object` behaves very similarly to a regular
``dict`` object: you may assign to keys, read from keys, and ``del`` keys.
Stanza interfaces come with built-in behaviours such as adding/removing
attribute and sub element values. However, a lot of the time more custom
logic is needed. This can be provided by defining methods of the form
``get_*``, ``set_*``, and ``del_*`` for any interface which requires custom
behaviour.
Stanza Plugins
~~~~~~~~~~~~~~
Since it is generally possible to embed one XML element inside another,
:term:`stanza objects <stanza object>` may be nested. Nested
:term:`stanza objects <stanza object>` are referred to as :term:`stanza plugins <stanza plugin>`
or :term:`substanzas <substanza>`.
A :term:`stanza plugin` exposes its own interfaces by adding a new
interface to its parent stanza. To demonstrate, consider these two stanza
class definitions using ``sleekxmpp.xmlstream.ElementBase``:
.. code-block:: python
class Parent(ElementBase):
name = "the-parent-xml-element-name"
namespace = "the-parent-namespace"
interfaces = set(('foo', 'bar'))
class Child(ElementBase):
name = "the-child-xml-element-name"
namespace = "the-child-namespace"
plugin_attrib = 'child'
interfaces = set(('baz',))
If we register the ``Child`` stanza as a plugin of the ``Parent`` stanza as
so, using ``sleekxmpp.xmlstream.register_stanza_plugin``::
register_stanza_plugin(Parent, Child)
Then we can access content in the child stanza through the parent.
Note that the interface used to access the child stanza is the same as
``Child.plugin_attrib``::
parent = Parent()
parent['foo'] = 'a'
parent['child']['baz'] = 'b'
The above code would produce:
.. code-block:: xml
<the-parent-xml-element xmlns="the-parent-namespace" foo="a">
<the-child-xml-element xmlsn="the-child-namespace" baz="b" />
</the-parent-xml-element>
It is also possible to allow a :term:`substanza` to appear multiple times
by using ``iterable=True`` in the ``register_stanza_plugin`` call. All
iterable :term:`substanzas <substanza>` can be accessed using a standard
``substanzas`` interface.

28
docs/howto/stanzas.rst Normal file
View file

@ -0,0 +1,28 @@
How to Work with Stanza Objects
===============================
.. _create-stanza-interfaces:
Defining Stanza Interfaces
--------------------------
.. _create-stanza-plugins:
Creating Stanza Plugins
-----------------------
.. _create-extension-plugins:
Creating a Stanza Extension
---------------------------
.. _override-parent-interfaces:
Overriding a Parent Stanza
--------------------------