diff options
Diffstat (limited to 'docs')
38 files changed, 714 insertions, 604 deletions
diff --git a/docs/Makefile b/docs/Makefile index a520f6a1..d44cd8a4 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -72,17 +72,17 @@ qthelp: @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SleekXMPP.qhcp" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Slixmpp.qhcp" @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SleekXMPP.qhc" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Slixmpp.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/SleekXMPP" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SleekXMPP" + @echo "# mkdir -p $$HOME/.local/share/devhelp/Slixmpp" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Slixmpp" @echo "# devhelp" epub: diff --git a/docs/_static/nature.css b/docs/_static/nature.css index 52b328ea..b271ec97 100644 --- a/docs/_static/nature.css +++ b/docs/_static/nature.css @@ -8,11 +8,11 @@ * :license: BSD, see LICENSE for details. * */ - + @import url("basic.css"); - + /* -- page layout ----------------------------------------------------------- */ - + body { font-family: Arial, sans-serif; font-size: 100%; @@ -34,18 +34,18 @@ div.bodywrapper { hr { border: 1px solid #B1B4B6; } - + div.document { background-color: #eee; } - + div.body { background-color: #ffffff; color: #3E4349; padding: 0 30px 30px 30px; font-size: 0.9em; } - + div.footer { color: #555; width: 100%; @@ -53,12 +53,12 @@ div.footer { text-align: center; font-size: 75%; } - + div.footer a { color: #444; text-decoration: underline; } - + div.related { background-color: #6BA81E; line-height: 32px; @@ -66,11 +66,11 @@ div.related { text-shadow: 0px 1px 0 #444; font-size: 0.9em; } - + div.related a { color: #E2F3CC; } - + div.sphinxsidebar { font-size: 0.75em; line-height: 1.5em; @@ -79,7 +79,7 @@ div.sphinxsidebar { div.sphinxsidebarwrapper{ padding: 20px 0; } - + div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: Arial, sans-serif; @@ -95,30 +95,30 @@ div.sphinxsidebar h4 { div.sphinxsidebar h4{ font-size: 1.1em; } - + div.sphinxsidebar h3 a { color: #444; } - - + + div.sphinxsidebar p { color: #888; padding: 5px 20px; } - + div.sphinxsidebar p.topless { } - + div.sphinxsidebar ul { margin: 10px 20px; padding: 0; color: #000; } - + div.sphinxsidebar a { color: #444; } - + div.sphinxsidebar input { border: 1px solid #ccc; font-family: sans-serif; @@ -128,19 +128,19 @@ div.sphinxsidebar input { div.sphinxsidebar input[type=text]{ margin-left: 20px; } - + /* -- body styles ----------------------------------------------------------- */ - + a { color: #005B81; text-decoration: none; } - + a:hover { color: #E32E00; text-decoration: underline; } - + div.body h1, div.body h2, div.body h3, @@ -155,30 +155,30 @@ div.body h6 { padding: 5px 0 5px 10px; text-shadow: 0px 1px 0 white } - + div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } div.body h2 { font-size: 150%; background-color: #C8D5E3; } div.body h3 { font-size: 120%; background-color: #D8DEE3; } div.body h4 { font-size: 110%; background-color: #D8DEE3; } div.body h5 { font-size: 100%; background-color: #D8DEE3; } div.body h6 { font-size: 100%; background-color: #D8DEE3; } - + a.headerlink { color: #c60f0f; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; } - + a.headerlink:hover { background-color: #c60f0f; color: white; } - + div.body p, div.body dd, div.body li { line-height: 1.5em; } - + div.admonition p.admonition-title + p { display: inline; } @@ -191,29 +191,29 @@ div.note { background-color: #eee; border: 1px solid #ccc; } - + div.seealso { background-color: #ffc; border: 1px solid #ff6; } - + div.topic { background-color: #eee; } - + div.warning { background-color: #ffe4e4; border: 1px solid #f66; } - + p.admonition-title { display: inline; } - + p.admonition-title:after { content: ":"; } - + pre { padding: 10px; background-color: White; @@ -225,7 +225,7 @@ pre { -webkit-box-shadow: 1px 1px 1px #d8d8d8; -moz-box-shadow: 1px 1px 1px #d8d8d8; } - + tt { background-color: #ecf0f3; color: #222; diff --git a/docs/_static/sphinxdoc.css b/docs/_static/sphinxdoc.css index 0a428074..55c574f6 100644 --- a/docs/_static/sphinxdoc.css +++ b/docs/_static/sphinxdoc.css @@ -134,7 +134,7 @@ div.footer a { /* -- body styles ----------------------------------------------------------- */ -p { +p { margin: 0.8em 0 0.5em 0; } diff --git a/docs/api/basexmpp.rst b/docs/api/basexmpp.rst index fa96322e..df05bb0b 100644 --- a/docs/api/basexmpp.rst +++ b/docs/api/basexmpp.rst @@ -2,7 +2,7 @@ BaseXMPP ======== -.. module:: sleekxmpp.basexmpp +.. module:: slixmpp.basexmpp .. autoclass:: BaseXMPP :members: diff --git a/docs/api/clientxmpp.rst b/docs/api/clientxmpp.rst index a6f32c43..232c37c3 100644 --- a/docs/api/clientxmpp.rst +++ b/docs/api/clientxmpp.rst @@ -2,7 +2,7 @@ ClientXMPP ========== -.. module:: sleekxmpp.clientxmpp +.. module:: slixmpp.clientxmpp .. autoclass:: ClientXMPP :members: diff --git a/docs/api/componentxmpp.rst b/docs/api/componentxmpp.rst index 989120c2..9c6366aa 100644 --- a/docs/api/componentxmpp.rst +++ b/docs/api/componentxmpp.rst @@ -2,7 +2,7 @@ ComponentXMPP ============= -.. module:: sleekxmpp.componentxmpp +.. module:: slixmpp.componentxmpp .. autoclass:: ComponentXMPP :members: diff --git a/docs/api/exceptions.rst b/docs/api/exceptions.rst index 7bc72ce5..51e2e170 100644 --- a/docs/api/exceptions.rst +++ b/docs/api/exceptions.rst @@ -1,9 +1,9 @@ Exceptions ========== -.. module:: sleekxmpp.exceptions +.. module:: slixmpp.exceptions + - .. autoexception:: XMPPError :members: diff --git a/docs/api/stanza/iq.rst b/docs/api/stanza/iq.rst new file mode 100644 index 00000000..0a7d7ffb --- /dev/null +++ b/docs/api/stanza/iq.rst @@ -0,0 +1,8 @@ +IQ Stanza +========= + +.. module:: slixmpp.stanza + +.. autoclass:: Iq + :members: + diff --git a/docs/api/stanza/message.rst b/docs/api/stanza/message.rst new file mode 100644 index 00000000..f01c62a7 --- /dev/null +++ b/docs/api/stanza/message.rst @@ -0,0 +1,7 @@ +Message Stanza +============== + +.. module:: slixmpp.stanza + +.. autoclass:: Message + :members: diff --git a/docs/api/stanza/presence.rst b/docs/api/stanza/presence.rst new file mode 100644 index 00000000..15ac7bf9 --- /dev/null +++ b/docs/api/stanza/presence.rst @@ -0,0 +1,8 @@ +Presence Stanza +=============== + +.. module:: slixmpp.stanza + +.. autoclass:: Presence + :members: + diff --git a/docs/api/stanza/rootstanza.rst b/docs/api/stanza/rootstanza.rst new file mode 100644 index 00000000..83d9f49b --- /dev/null +++ b/docs/api/stanza/rootstanza.rst @@ -0,0 +1,8 @@ +Root Stanza +=========== + +.. module:: slixmpp.stanza.rootstanza + +.. autoclass:: RootStanza + :members: + diff --git a/docs/api/xmlstream/filesocket.rst b/docs/api/xmlstream/filesocket.rst deleted file mode 100644 index 35f44019..00000000 --- a/docs/api/xmlstream/filesocket.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. module:: sleekxmpp.xmlstream.filesocket - -.. _filesocket: - -Python 2.6 File Socket Shims -============================ - -.. autoclass:: FileSocket - :members: - -.. autoclass:: Socket26 - :members: diff --git a/docs/api/xmlstream/handler.rst b/docs/api/xmlstream/handler.rst index 33c0bf42..9d2f5aba 100644 --- a/docs/api/xmlstream/handler.rst +++ b/docs/api/xmlstream/handler.rst @@ -3,22 +3,26 @@ Stanza Handlers The Basic Handler ----------------- -.. module:: sleekxmpp.xmlstream.handler.base +.. module:: slixmpp.xmlstream.handler.base .. autoclass:: BaseHandler :members: Callback -------- -.. module:: sleekxmpp.xmlstream.handler.callback +.. module:: slixmpp.xmlstream.handler .. autoclass:: Callback :members: +CoroutineCallback +----------------- + +.. autoclass:: CoroutineCallback + :members: Waiter ------ -.. module:: sleekxmpp.xmlstream.handler.waiter .. autoclass:: Waiter :members: diff --git a/docs/api/xmlstream/jid.rst b/docs/api/xmlstream/jid.rst index 22a2db45..2f0c65d0 100644 --- a/docs/api/xmlstream/jid.rst +++ b/docs/api/xmlstream/jid.rst @@ -1,7 +1,7 @@ Jabber IDs (JID) ================= -.. module:: sleekxmpp.xmlstream.jid +.. module:: slixmpp.jid .. autoclass:: JID :members: diff --git a/docs/api/xmlstream/matcher.rst b/docs/api/xmlstream/matcher.rst index df3591bc..793059f2 100644 --- a/docs/api/xmlstream/matcher.rst +++ b/docs/api/xmlstream/matcher.rst @@ -3,7 +3,7 @@ Stanza Matchers The Basic Matcher ----------------- -.. module:: sleekxmpp.xmlstream.matcher.base +.. module:: slixmpp.xmlstream.matcher.base .. autoclass:: MatcherBase :members: @@ -11,7 +11,7 @@ The Basic Matcher ID Matching ----------- -.. module:: sleekxmpp.xmlstream.matcher.id +.. module:: slixmpp.xmlstream.matcher.id .. autoclass:: MatcherId :members: @@ -19,7 +19,7 @@ ID Matching Stanza Path Matching -------------------- -.. module:: sleekxmpp.xmlstream.matcher.stanzapath +.. module:: slixmpp.xmlstream.matcher.stanzapath .. autoclass:: StanzaPath :members: @@ -27,7 +27,7 @@ Stanza Path Matching XPath ----- -.. module:: sleekxmpp.xmlstream.matcher.xpath +.. module:: slixmpp.xmlstream.matcher.xpath .. autoclass:: MatchXPath :members: @@ -35,7 +35,7 @@ XPath XMLMask ------- -.. module:: sleekxmpp.xmlstream.matcher.xmlmask +.. module:: slixmpp.xmlstream.matcher.xmlmask .. autoclass:: MatchXMLMask :members: diff --git a/docs/api/xmlstream/scheduler.rst b/docs/api/xmlstream/scheduler.rst deleted file mode 100644 index ff91701e..00000000 --- a/docs/api/xmlstream/scheduler.rst +++ /dev/null @@ -1,11 +0,0 @@ -========= -Scheduler -========= - -.. module:: sleekxmpp.xmlstream.scheduler - -.. autoclass:: Task - :members: - -.. autoclass:: Scheduler - :members: diff --git a/docs/api/xmlstream/stanzabase.rst b/docs/api/xmlstream/stanzabase.rst index f575299e..ad43a44a 100644 --- a/docs/api/xmlstream/stanzabase.rst +++ b/docs/api/xmlstream/stanzabase.rst @@ -4,9 +4,9 @@ Stanza Objects ============== -.. module:: sleekxmpp.xmlstream.stanzabase +.. module:: slixmpp.xmlstream.stanzabase -The :mod:`~sleekmxpp.xmlstream.stanzabase` module provides a wrapper for the +The :mod:`~slixmpp.xmlstream.stanzabase` module provides a wrapper for the standard :mod:`~xml.etree.ElementTree` module that makes working with XML less painful. Instead of having to manually move up and down an element tree and insert subelements and attributes, you can interact with an object @@ -52,17 +52,17 @@ elements of the original XML chunk. .. seealso:: :ref:`create-stanza-interfaces`. -Because the :mod:`~sleekxmpp.xmlstream.stanzabase` module was developed +Because the :mod:`~slixmpp.xmlstream.stanzabase` module was developed as part of an `XMPP <http://xmpp.org>`_ library, these chunks of XML are -referred to as :term:`stanzas <stanza>`, and in SleekXMPP we refer to a +referred to as :term:`stanzas <stanza>`, and in Slixmpp we refer to a subclass of :class:`ElementBase` which defines the interfaces needed for 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 @@ -72,7 +72,7 @@ plugin stanza object. Here is an example: <iq type="result"> <query xmlns="http://jabber.org/protocol/disco#info"> - <identity category="client" type="bot" name="SleekXMPP Bot" /> + <identity category="client" type="bot" name="Slixmpp Bot" /> </query> </iq> @@ -84,13 +84,13 @@ we can access the plugin as so:: >>> iq['disco_info'] '<query xmlns="http://jabber.org/protocol/disco#info"> - <identity category="client" type="bot" name="SleekXMPP Bot" /> + <identity category="client" type="bot" name="Slixmpp Bot" /> </query>' We can then drill down through the plugin object's interfaces as desired:: >>> iq['disco_info']['identities'] - [('client', 'bot', 'SleekXMPP Bot')] + [('client', 'bot', 'Slixmpp Bot')] Plugins may also add new interfaces to the parent stanza object as if they had been defined by the parent directly, and can also override the behaviour @@ -101,7 +101,7 @@ of an interface defined by the parent. - :ref:`create-stanza-plugins` - :ref:`create-extension-plugins` - :ref:`override-parent-interfaces` - + Registering Stanza Plugins -------------------------- diff --git a/docs/api/xmlstream/tostring.rst b/docs/api/xmlstream/tostring.rst index 82a8c2a5..68abbdb6 100644 --- a/docs/api/xmlstream/tostring.rst +++ b/docs/api/xmlstream/tostring.rst @@ -1,18 +1,18 @@ -.. module:: sleekxmpp.xmlstream.tostring +.. module:: slixmpp.xmlstream.tostring .. _tostring: XML Serialization ================= -Since the XML layer of SleekXMPP is based on :mod:`~xml.etree.ElementTree`, +Since the XML layer of Slixmpp is based on :mod:`~xml.etree.ElementTree`, why not just use the built-in :func:`~xml.etree.ElementTree.tostring` method? The answer is that using that method produces ugly results when using namespaces. The :func:`tostring()` method used here intelligently hides namespaces when able and does not introduce excessive namespace prefixes:: - >>> from sleekxmpp.xmlstream.tostring import tostring + >>> from slixmpp.xmlstream.tostring import tostring >>> from xml.etree import cElementTree as ET >>> xml = ET.fromstring('<foo xmlns="bar"><baz /></foo>') >>> ET.tostring(xml) @@ -25,10 +25,10 @@ produce unexpected results depending on how the :func:`tostring()` method is invoked. For example, when sending XML on the wire, the main XMPP stanzas with their namespace of ``jabber:client`` will not include the namespace because that is already declared by the stream header. But, if -you create a :class:`~sleekxmpp.stanza.message.Message` instance and dump +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 diff --git a/docs/api/xmlstream/xmlstream.rst b/docs/api/xmlstream/xmlstream.rst index 90a7a6af..539e03ca 100644 --- a/docs/api/xmlstream/xmlstream.rst +++ b/docs/api/xmlstream/xmlstream.rst @@ -2,9 +2,7 @@ XML Stream ========== -.. module:: sleekxmpp.xmlstream.xmlstream - -.. autoexception:: RestartStream +.. module:: slixmpp.xmlstream.xmlstream .. autoclass:: XMLStream :members: diff --git a/docs/architecture.rst b/docs/architecture.rst index a2e0a27d..75b70c8a 100644 --- a/docs/architecture.rst +++ b/docs/architecture.rst @@ -1,9 +1,9 @@ .. index:: XMLStream, BaseXMPP, ClientXMPP, ComponentXMPP -SleekXMPP Architecture +Slixmpp Architecture ====================== -The core of SleekXMPP is contained in four classes: ``XMLStream``, +The core of Slixmpp is contained in four classes: ``XMLStream``, ``BaseXMPP``, ``ClientXMPP``, and ``ComponentXMPP``. Along side this stack is a library for working with XML objects that eliminates most of the tedium of creating/manipulating XML. @@ -17,28 +17,27 @@ of the tedium of creating/manipulating XML. The Foundation: XMLStream ------------------------- -:class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` is a mostly XMPP-agnostic +:class:`~slixmpp.xmlstream.xmlstream.XMLStream` is a mostly XMPP-agnostic class whose purpose is to read and write from a bi-directional XML stream. It also allows for callback functions to execute when XML matching given 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:`~sleekxmpp.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 SleekXMPP 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 @@ -61,95 +60,69 @@ when this bit of XML is received (with an assumed namespace of new object is determined using a map of namespaced element names to classes. - Our incoming XML is thus turned into a :class:`~sleekxmpp.stanza.Message` + Our incoming XML is thus turned into a :class:`~slixmpp.stanza.Message` :term:`stanza object` because the namespaced element name ``{jabber:client}message`` is associated with the class - :class:`~sleekxmpp.stanza.Message`. + :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:`~sleekxmpp.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 SleekXMPP. 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:`~sleekxmpp.stanza.Iq` stanza), then custom events must be used. + :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. - - .. note:: - It is possible to skip the event queue and process an event immediately - by using ``direct=True`` when raising the event. + 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:: - - self.event('message', msg) + raises a ``'message'`` event - The event call then places the message object back into the event queue - paired with an :term:`event handler`:: + .. code-block:: python - ('event', 'message', msg_copy1, custom_event_handler_1) - ('event', 'message', msg_copy2, custom_evetn_handler_2) + self.event('message', msg) -5. **Process Custom Events** +#. **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>`. - For example, you could use ``self.event('custom', {'a': 'b'})``. - You don't even need any arguments: ``self.event('no_parameters')``. + Events may be raised without needing :term:`stanza objects <stanza object>`. + For example, you could use ``self.event('custom', {'a': 'b'})``. + You don't even need any arguments: ``self.event('no_parameters')``. However, every event handler MUST accept at least one argument. 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 Raising XMPP Awareness: BaseXMPP -------------------------------- -While :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` attempts to shy away -from anything too XMPP specific, :class:`~sleekxmpp.basexmpp.BaseXMPP`'s +While :class:`~slixmpp.xmlstream.xmlstream.XMLStream` attempts to shy away +from anything too XMPP specific, :class:`~slixmpp.basexmpp.BaseXMPP`'s sole purpose is to provide foundational support for sending and receiving XMPP stanzas. This support includes registering the basic message, presence, and iq stanzas, methods for creating and sending stanzas, and @@ -157,14 +130,14 @@ default handlers for incoming messages and keeping track of presence notifications. The plugin system for adding new XEP support is also maintained by -:class:`~sleekxmpp.basexmpp.BaseXMPP`. +:class:`~slixmpp.basexmpp.BaseXMPP`. .. index:: ClientXMPP, BaseXMPP ClientXMPP ---------- -:class:`~sleekxmpp.clientxmpp.ClientXMPP` extends -:class:`~sleekxmpp.clientxmpp.BaseXMPP` with additional logic for connecting +:class:`~slixmpp.clientxmpp.ClientXMPP` extends +:class:`~slixmpp.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. @@ -172,6 +145,6 @@ features such as STARTTLS and SASL. ComponentXMPP ------------- -:class:`~sleekxmpp.componentxmpp.ComponentXMPP` is only a thin layer on top of -:class:`~sleekxmpp.basexmpp.BaseXMPP` that implements the component handshake +:class:`~slixmpp.componentxmpp.ComponentXMPP` is only a thin layer on top of +:class:`~slixmpp.basexmpp.BaseXMPP` that implements the component handshake protocol. diff --git a/docs/conf.py b/docs/conf.py index 72e39d0f..898d00cd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# SleekXMPP documentation build configuration file, created by +# Slixmpp documentation build configuration file, created by # sphinx-quickstart on Tue Aug 9 22:27:06 2011. # # This file is execfile()d with the current directory set to its containing dir. @@ -40,7 +40,7 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'SleekXMPP' +project = u'Slixmpp' copyright = u'2011, Nathan Fritz, Lance Stout' # The version info for the project you're documenting, acts as replacement for @@ -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 = 'SleekXMPP' +html_title = 'slixmpp' # A shorter title for the navigation bar. Default is the same as html_title. html_short_title = '%s Documentation' % release @@ -168,7 +168,7 @@ html_additional_pages = { #html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'SleekXMPPdoc' +htmlhelp_basename = 'Slixmppdoc' # -- Options for LaTeX output -------------------------------------------------- @@ -182,7 +182,7 @@ htmlhelp_basename = 'SleekXMPPdoc' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'SleekXMPP.tex', u'SleekXMPP Documentation', + ('index', 'Slixmpp.tex', u'Slixmpp Documentation', u'Nathan Fritz, Lance Stout', 'manual'), ] @@ -215,8 +215,8 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'sleekxmpp', u'SleekXMPP Documentation', + ('index', 'slixmpp', u'Slixmpp Documentation', [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')} diff --git a/docs/create_plugin.rst b/docs/create_plugin.rst index 2b0514b8..9bfb053f 100644 --- a/docs/create_plugin.rst +++ b/docs/create_plugin.rst @@ -1,10 +1,10 @@ .. _create-plugin: -Creating a SleekXMPP Plugin +Creating a Slixmpp Plugin =========================== -One of the goals of SleekXMPP is to provide support for every draft or final -XMPP extension (`XEP <http://xmpp.org/extensions/>`_). To do this, SleekXMPP has a +One of the goals of Slixmpp is to provide support for every draft or final +XMPP extension (`XEP <http://xmpp.org/extensions/>`_). To do this, Slixmpp has a plugin mechanism for adding the functionalities required by each XEP. But even though plugins were made to quickly implement and prototype the official XMPP extensions, there is no reason you can't create your own plugin to implement @@ -14,11 +14,11 @@ This guide will help walk you through the steps to implement a rudimentary version of `XEP-0077 In-band Registration <http://xmpp.org/extensions/xep-0077.html>`_. In-band registration was implemented in example 14-6 (page 223) of `XMPP: The Definitive -Guide <http://oreilly.com/catalog/9780596521271>`_ because there was no SleekXMPP +Guide <http://oreilly.com/catalog/9780596521271>`_ because there was no Slixmpp plugin for XEP-0077 at the time of writing. We will partially fix that issue here by turning the example implementation from *XMPP: The Definitive Guide* into a plugin. Again, note that this will not a complete implementation, and a -different, more robust, official plugin for XEP-0077 may be added to SleekXMPP +different, more robust, official plugin for XEP-0077 may be added to Slixmpp in the future. .. note:: @@ -29,10 +29,10 @@ in the future. First Steps ----------- -Every plugin inherits from the class :mod:`base_plugin <sleekxmpp.plugins.base.base_plugin>`, +Every plugin inherits from the class :mod:`BasePlugin <slixmpp.plugins.base.BasePlugin`, and must include a ``plugin_init`` method. While the -plugins distributed with SleekXMPP must be placed in the plugins directory -``sleekxmpp/plugins`` to be loaded, custom plugins may be loaded from any +plugins distributed with Slixmpp must be placed in the plugins directory +``slixmpp/plugins`` to be loaded, custom plugins may be loaded from any module. To do so, use the following form when registering the plugin: .. code-block:: python @@ -40,9 +40,9 @@ module. To do so, use the following form when registering the plugin: self.register_plugin('myplugin', module=mod_containing_my_plugin) The plugin name must be the same as the plugin's class name. - + Now, we can open our favorite text editors and create ``xep_0077.py`` in -``SleekXMPP/sleekxmpp/plugins``. We want to do some basic house-keeping and +``Slixmpp/slixmpp/plugins``. We want to do some basic house-keeping and declare the name and description of the XEP we are implementing. If you are creating your own custom plugin, you don't need to include the ``xep`` attribute. @@ -50,15 +50,15 @@ attribute. .. code-block:: python """ - Creating a SleekXMPP Plugin + Creating a Slixmpp Plugin This is a minimal implementation of XEP-0077 to serve - as a tutorial for creating SleekXMPP plugins. + as a tutorial for creating Slixmpp plugins. """ - from sleekxmpp.plugins.base import base_plugin + from slixmpp.plugins.base import BasePlugin - class xep_0077(base_plugin): + class xep_0077(BasePlugin): """ XEP-0077 In-Band Registration """ @@ -68,7 +68,7 @@ attribute. self.xep = "0077" Now that we have a basic plugin, we need to edit -``sleekxmpp/plugins/__init__.py`` to include our new plugin by adding +``slixmpp/plugins/__init__.py`` to include our new plugin by adding ``'xep_0077'`` to the ``__all__`` declaration. Interacting with Other Plugins @@ -81,20 +81,20 @@ call in a method named ``post_init`` which will be called once the plugin has been loaded; by doing so we advertise that we can do registrations only after we finish activating the plugin. -The ``post_init`` method needs to call ``base_plugin.post_init(self)`` +The ``post_init`` method needs to call ``BasePlugin.post_init(self)`` which will mark that ``post_init`` has been called for the plugin. Once the -SleekXMPP object begins processing, ``post_init`` will be called on any plugins +Slixmpp object begins processing, ``post_init`` will be called on any plugins that have not already run ``post_init``. This allows you to register plugins and their dependencies without needing to worry about the order in which you do so. **Note:** by adding this call we have introduced a dependency on the XEP-0030 -plugin. Be sure to register ``'xep_0030'`` as well as ``'xep_0077'``. SleekXMPP +plugin. Be sure to register ``'xep_0030'`` as well as ``'xep_0077'``. Slixmpp does not automatically load plugin dependencies for you. .. code-block:: python def post_init(self): - base_plugin.post_init(self) + BasePlugin.post_init(self) self.xmpp['xep_0030'].add_feature("jabber:iq:register") Creating Custom Stanza Objects @@ -141,7 +141,7 @@ behaviour: **Note:** The accessor methods currently use title case, and not camel case. Thus if you need to access an item named ``"methodName"`` you will need to use ``getMethodname``. This naming convention might change to full camel - case in a future version of SleekXMPP. + case in a future version of Slixmpp. * ``sub_interfaces`` A subset of ``interfaces``, but these keys map to the text of any @@ -156,8 +156,8 @@ behaviour: .. code-block:: python - from sleekxmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin - from sleekxmpp import Iq + from slixmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin + from slixmpp import Iq class Registration(ElementBase): namespace = 'jabber:iq:register' @@ -209,7 +209,7 @@ registration to our ``plugin_init`` method. Also, we need to associate our ``Registration`` class with IQ stanzas; that requires the use of the ``register_stanza_plugin`` function (in -``sleekxmpp.xmlstream.stanzabase``) which takes the class of a parent stanza +``slixmpp.xmlstream.stanzabase``) which takes the class of a parent stanza type followed by the substanza type. In our case, the parent stanza is an IQ stanza, and the substanza is our registration query. @@ -347,7 +347,7 @@ method ``setForm`` which will take the names of the fields we wish to include. # Add a blank field reg.addField(field) - iq.reply().setPayload(reg.xml) + iq.reply().set_payload(reg.xml) iq.send() Note how we are able to access our ``Registration`` stanza object with @@ -421,7 +421,7 @@ to the IQ reply. ... def _sendError(self, iq, code, error_type, name, text=''): - iq.reply().setPayload(iq['register'].xml) + iq.reply().set_payload(iq['register'].xml) iq.error() iq['error']['code'] = code iq['error']['type'] = error_type @@ -464,7 +464,7 @@ component examples below for how to respond to this event. if self.backend.register(iq['from'].bare, iq['register']): # Successful registration self.xmpp.event('registered_user', iq) - iq.reply().setPayload(iq['register'].xml) + iq.reply().set_payload(iq['register'].xml) iq.send() else: # Conflicting registration @@ -484,15 +484,15 @@ and that we specified the form fields we wish to use with .. code-block:: python - import sleekxmpp.componentxmpp + import slixmpp.componentxmpp - class Example(sleekxmpp.componentxmpp.ComponentXMPP): + class Example(slixmpp.componentxmpp.ComponentXMPP): def __init__(self, jid, password): - sleekxmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'localhost', 8888) + slixmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'localhost', 8888) - self.registerPlugin('xep_0030') - self.registerPlugin('xep_0077') + self.register_plugin('xep_0030') + self.register_plugin('xep_0077') self.plugin['xep_0077'].setForm('username', 'password') self.add_event_handler("registered_user", self.reg) @@ -500,11 +500,11 @@ and that we specified the form fields we wish to use with def reg(self, iq): msg = "Welcome! %s" % iq['register']['username'] - self.sendMessage(iq['from'], msg, mfrom=self.fulljid) + self.send_message(iq['from'], msg, mfrom=self.fulljid) def unreg(self, iq): msg = "Bye! %s" % iq['register']['username'] - self.sendMessage(iq['from'], msg, mfrom=self.fulljid) + self.send_message(iq['from'], msg, mfrom=self.fulljid) **Congratulations!** We now have a basic, functioning implementation of XEP-0077. @@ -517,17 +517,17 @@ with some additional registration fields implemented. .. code-block:: python """ - Creating a SleekXMPP Plugin + Creating a Slixmpp Plugin This is a minimal implementation of XEP-0077 to serve - as a tutorial for creating SleekXMPP plugins. + as a tutorial for creating Slixmpp plugins. """ - from sleekxmpp.plugins.base import base_plugin - from sleekxmpp.xmlstream.handler.callback import Callback - from sleekxmpp.xmlstream.matcher.xpath import MatchXPath - from sleekxmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin - from sleekxmpp import Iq + from slixmpp.plugins.base import BasePlugin + from slixmpp.xmlstream.handler.callback import Callback + from slixmpp.xmlstream.matcher.xpath import MatchXPath + from slixmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin + from slixmpp import Iq import copy @@ -535,9 +535,9 @@ with some additional registration fields implemented. namespace = 'jabber:iq:register' name = 'query' plugin_attrib = 'register' - interfaces = set(('username', 'password', 'email', 'nick', 'name', - 'first', 'last', 'address', 'city', 'state', 'zip', - 'phone', 'url', 'date', 'misc', 'text', 'key', + interfaces = set(('username', 'password', 'email', 'nick', 'name', + 'first', 'last', 'address', 'city', 'state', 'zip', + 'phone', 'url', 'date', 'misc', 'text', 'key', 'registered', 'remove', 'instructions')) sub_interfaces = interfaces @@ -589,7 +589,7 @@ with some additional registration fields implemented. def unregister(self, jid): del self.users[jid] - class xep_0077(base_plugin): + class xep_0077(BasePlugin): """ XEP-0077 In-Band Registration """ @@ -608,7 +608,7 @@ with some additional registration fields implemented. register_stanza_plugin(Iq, Registration) def post_init(self): - base_plugin.post_init(self) + BasePlugin.post_init(self) self.xmpp['xep_0030'].add_feature("jabber:iq:register") def __handleRegistration(self, iq): @@ -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().setPayload(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().setPayload(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().setPayload(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() diff --git a/docs/differences.rst b/docs/differences.rst new file mode 100644 index 00000000..f6e005b5 --- /dev/null +++ b/docs/differences.rst @@ -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 **always** return a :class:`~.asyncio.Future` which result will be set + to the IQ reply when it is received, or to ``None`` if the IQ is not of + type ``get`` or ``set``. + + Many plugins (WIP) calls which retrieve information also return the same + future. + +**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. diff --git a/docs/event_index.rst b/docs/event_index.rst index ee8f5a95..07a4fbd0 100644 --- a/docs/event_index.rst +++ b/docs/event_index.rst @@ -6,33 +6,33 @@ Event Index connected - **Data:** ``{}`` - - **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream` + - **Source:** :py:class:`~slixmpp.xmlstream.XMLstream` Signal that a connection has been made with the XMPP server, but a session has not yet been established. connection_failed - **Data:** ``{}`` or ``Failure Stanza`` if available - - **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream` + - **Source:** :py:class:`~slixmpp.xmlstream.XMLstream` Signal that a connection can not be established after number of attempts. changed_status - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.roster.item.RosterItem` + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.roster.item.RosterItem` Triggered when a presence stanza is received from a JID with a show type different than the last presence stanza from the same JID. changed_subscription - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.BaseXMPP` + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.BaseXMPP` Triggered whenever a presence stanza with a type of ``subscribe``, ``subscribed``, ``unsubscribe``, or ``unsubscribed`` is received. Note that if the values ``xmpp.auto_authorize`` and ``xmpp.auto_subscribe`` - are set to ``True`` or ``False``, and not ``None``, then SleekXMPP will + are set to ``True`` or ``False``, and not ``None``, then Slixmpp will either accept or reject all subscription requests before your event handlers are called. Set these values to ``None`` if you wish to make more complex subscription decisions. @@ -58,20 +58,20 @@ Event Index - **Source:** disco_info - - **Data:** :py:class:`~sleekxmpp.plugins.xep_0030.stanza.DiscoInfo` - - **Source:** :py:class:`~sleekxmpp.plugins.xep_0030.disco.xep_0030` - + - **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoInfo` + - **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030` + Triggered whenever a ``disco#info`` result stanza is received. disco_items - - **Data:** :py:class:`~sleekxmpp.plugins.xep_0030.stanza.DiscoItems` - - **Source:** :py:class:`~sleekxmpp.plugins.xep_0030.disco.xep_0030` - + - **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoItems` + - **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030` + Triggered whenever a ``disco#items`` result stanza is received. disconnected - **Data:** ``{}`` - - **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream` + - **Source:** :py:class:`~slixmpp.xmlstream.XMLstream` Signal that the connection with the XMPP server has been lost. @@ -81,33 +81,33 @@ Event Index failed_auth - **Data:** ``{}`` - - **Source:** :py:class:`~sleekxmpp.ClientXMPP`, :py:class:`~sleekxmpp.plugins.xep_0078.xep_0078` + - **Source:** :py:class:`~slixmpp.ClientXMPP`, :py:class:`~slixmpp.plugins.xep_0078.xep_0078` Signal that the server has rejected the provided login credentials. gmail_notify - **Data:** ``{}`` - - **Source:** :py:class:`~sleekxmpp.plugins.gmail_notify.gmail_notify` - + - **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify` + Signal that there are unread emails for the Gmail account associated with the current XMPP account. gmail_messages - - **Data:** :py:class:`~sleekxmpp.Iq` - - **Source:** :py:class:`~sleekxmpp.plugins.gmail_notify.gmail_notify` - + - **Data:** :py:class:`~slixmpp.Iq` + - **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify` + Signal that there are unread emails for the Gmail account associated with the current XMPP account. got_online - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.roster.item.RosterItem` + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.roster.item.RosterItem` If a presence stanza is received from a JID which was previously marked as offline, and the presence has a show type of '``chat``', '``dnd``', '``away``', or '``xa``', then this event is triggered as well. got_offline - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.roster.item.RosterItem` + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.roster.item.RosterItem` Signal that an unavailable presence stanza has been received from a JID. @@ -116,25 +116,25 @@ Event Index - **Source:** groupchat_direct_invite - - **Data:** :py:class:`~sleekxmpp.Message` - - **Source:** :py:class:`~sleekxmpp.plugins.xep_0249.direct` + - **Data:** :py:class:`~slixmpp.Message` + - **Source:** :py:class:`~slixmpp.plugins.xep_0249.direct` groupchat_message - - **Data:** :py:class:`~sleekxmpp.Message` - - **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045` - + - **Data:** :py:class:`~slixmpp.Message` + - **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045` + Triggered whenever a message is received from a multi-user chat room. groupchat_presence - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045` - + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045` + Triggered whenever a presence stanza is received from a user in a multi-user chat room. groupchat_subject - - **Data:** :py:class:`~sleekxmpp.Message` - - **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045` - + - **Data:** :py:class:`~slixmpp.Message` + - **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045` + Triggered whenever the subject of a multi-user chat room is changed, or announced when joining a room. killed @@ -146,21 +146,28 @@ Event Index - **Source:** message - - **Data:** :py:class:`~sleekxmpp.Message` - - **Source:** :py:class:`BaseXMPP <sleekxmpp.BaseXMPP>` - + - **Data:** :py:class:`~slixmpp.Message` + - **Source:** :py:class:`BaseXMPP <slixmpp.BaseXMPP>` + Makes the contents of message stanzas available whenever one is received. Be sure to check the message type in order to handle error messages. + message_error + - **Data:** :py:class:`~slixmpp.Message` + - **Source:** :py:class:`BaseXMPP <slixmpp.BaseXMPP>` + + Makes the contents of message stanzas available whenever one is received. + Only handler messages with an ``error`` type. + message_form - - **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form` - - **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004` + - **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form` + - **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004` Currently the same as :term:`message_xform`. message_xform - - **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form` - - **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004` + - **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form` + - **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004` Triggered whenever a data form is received inside a message. @@ -181,74 +188,74 @@ Event Index - **Source:** presence_available - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.BaseXMPP` - + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.BaseXMPP` + A presence stanza with a type of '``available``' is received. presence_error - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.BaseXMPP` - + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.BaseXMPP` + A presence stanza with a type of '``error``' is received. presence_form - - **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form` - - **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004` - + - **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form` + - **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004` + This event is present in the XEP-0004 plugin code, but is currently not used. presence_probe - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.BaseXMPP` - + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.BaseXMPP` + A presence stanza with a type of '``probe``' is received. presence_subscribe - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.BaseXMPP` - + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.BaseXMPP` + A presence stanza with a type of '``subscribe``' is received. presence_subscribed - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.BaseXMPP` - + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.BaseXMPP` + A presence stanza with a type of '``subscribed``' is received. presence_unavailable - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.BaseXMPP` - + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.BaseXMPP` + A presence stanza with a type of '``unavailable``' is received. presence_unsubscribe - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.BaseXMPP` - + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.BaseXMPP` + A presence stanza with a type of '``unsubscribe``' is received. presence_unsubscribed - - **Data:** :py:class:`~sleekxmpp.Presence` - - **Source:** :py:class:`~sleekxmpp.BaseXMPP` - + - **Data:** :py:class:`~slixmpp.Presence` + - **Source:** :py:class:`~slixmpp.BaseXMPP` + A presence stanza with a type of '``unsubscribed``' is received. roster_update - - **Data:** :py:class:`~sleekxmpp.stanza.Roster` - - **Source:** :py:class:`~sleekxmpp.ClientXMPP` - + - **Data:** :py:class:`~slixmpp.stanza.Roster` + - **Source:** :py:class:`~slixmpp.ClientXMPP` + An IQ result containing roster entries is received. sent_presence - **Data:** ``{}`` - - **Source:** :py:class:`~sleekxmpp.roster.multi.Roster` - + - **Source:** :py:class:`~slixmpp.roster.multi.Roster` + Signal that an initial presence stanza has been written to the XML stream. session_end - **Data:** ``{}`` - - **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream` + - **Source:** :py:class:`~slixmpp.xmlstream.XMLstream` Signal that a connection to the XMPP server has been lost and the current stream session has ended. Currently equivalent to :term:`disconnected`, but @@ -260,16 +267,16 @@ Event Index session_start - **Data:** ``{}`` - - **Source:** :py:class:`ClientXMPP <sleekxmpp.ClientXMPP>`, - :py:class:`ComponentXMPP <sleekxmpp.ComponentXMPP>` - :py:class:`XEP-0078 <sleekxmpp.plugins.xep_0078>` + - **Source:** :py:class:`ClientXMPP <slixmpp.ClientXMPP>`, + :py:class:`ComponentXMPP <slixmpp.ComponentXMPP>` + :py:class:`XEP-0078 <slixmpp.plugins.xep_0078>` Signal that a connection to the XMPP server has been made and a session has been established. socket_error - **Data:** ``Socket`` exception object - - **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream` + - **Source:** :py:class:`~slixmpp.xmlstream.XMLstream` stream_error - - **Data:** :py:class:`~sleekxmpp.stanza.StreamError` - - **Source:** :py:class:`~sleekxmpp.BaseXMPP` + - **Data:** :py:class:`~slixmpp.stanza.StreamError` + - **Source:** :py:class:`~slixmpp.BaseXMPP` diff --git a/docs/getting_started/component.rst b/docs/getting_started/component.rst index ce548ba4..34aeda26 100644 --- a/docs/getting_started/component.rst +++ b/docs/getting_started/component.rst @@ -5,24 +5,16 @@ 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/sleekxmpp-discussion>`_ - or join the chat room at `sleek@conference.jabber.org - <xmpp:sleek@conference.jabber.org?join>`_. - -If you have not yet installed SleekXMPP, do so now by either checking out a version -from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip`` -or ``easy_install``. -.. code-block:: sh - - pip install sleekxmpp # Or: easy_install sleekxmpp + If you have any issues working through this quickstart guide + 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 +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 +Many XMPP applications eventually graduate to requiring to run as a server +component in order to meet scalability requirements. To demonstrate how to turn an XMPP client bot into a component, we'll turn the echobot example (:ref:`echobot`) into a component version. @@ -30,7 +22,7 @@ The first difference is that we will add an additional import statement: .. code-block:: python - from sleekxmpp.componentxmpp import ComponentXMPP + from slixmpp.componentxmpp import ComponentXMPP Likewise, we will change the bot's class definition to match: @@ -48,7 +40,7 @@ a MUC component, the following could be used: .. code-block:: python - muc = ComponentXMPP('muc.sleekxmpp.com', '******', 'sleekxmpp.com', 5555) + muc = ComponentXMPP('muc.slixmpp.com', '******', 'slixmpp.com', 5555) .. note:: @@ -62,10 +54,10 @@ with presence. The other, main difference with components is that the ``'from'`` value for every stanza must be explicitly set, since components may send stanzas from multiple JIDs. To do so, -the :meth:`~sleekxmpp.basexmpp.BaseXMPP.send_message()` and -:meth:`~sleekxmpp.basexmpp.BaseXMPP.send_presence()` accept the parameters +the :meth:`~slixmpp.basexmpp.BaseXMPP.send_message()` and +:meth:`~slixmpp.basexmpp.BaseXMPP.send_presence()` accept the parameters ``mfrom`` and ``pfrom``, respectively. For any method that uses -:class:`~sleekxmpp.stanza.iq.Iq` stanzas, ``ifrom`` may be used. +:class:`~slixmpp.stanza.iq.Iq` stanzas, ``ifrom`` may be used. Final Product diff --git a/docs/getting_started/echobot.rst b/docs/getting_started/echobot.rst index 7d29ec58..bb40a0b5 100644 --- a/docs/getting_started/echobot.rst +++ b/docs/getting_started/echobot.rst @@ -1,25 +1,17 @@ .. _echobot: =============================== -SleekXMPP Quickstart - Echo Bot +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/sleekxmpp-discussion>`_ - or join the chat room at `sleek@conference.jabber.org - <xmpp:sleek@conference.jabber.org?join>`_. - -If you have not yet installed SleekXMPP, do so now by either checking out a version -from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip`` -or ``easy_install``. - -.. code-block:: sh - pip install sleekxmpp # Or: easy_install sleekxmpp + If you have any issues working through this quickstart guide + 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 +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,11 +36,12 @@ 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 - import sleekxmpp + import slixmpp '''Here we will create out echo bot class''' @@ -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 SleekXMPP 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 sleekxmpp.util.misc_ops import setdefaultencoding - setdefaultencoding('utf8') - -.. warning:: - - Until we are able to ensure that SleekXMPP will always use Unicode in Python2.6+, this - may cause issues embedding SleekXMPP into other applications which assume ASCII encoding. - Creating the EchoBot Class -------------------------- @@ -85,15 +60,15 @@ clients. Since our echo bot will only be responding to a few people, and won't n to remember thousands of users, we will use a client connection. A client connection is the same type that you use with your standard IM client such as Pidgin or Psi. -SleekXMPP comes with a :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` class -which we can extend to add our message echoing feature. :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` +Slixmpp comes with a :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` class +which we can extend to add our message echoing feature. :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` requires the parameters ``jid`` and ``password``, so we will let our ``EchoBot`` class accept those as well. .. code-block:: python - class EchoBot(sleekxmpp.ClientXMPP): - + class EchoBot(slixmpp.ClientXMPP): + def __init__(self, jid, password): super(EchoBot, self).__init__(jid, password) @@ -102,7 +77,7 @@ Handling Session Start The XMPP spec requires clients to broadcast its presence and retrieve its roster (buddy list) once it connects and establishes a session with the XMPP server. Until these two tasks are completed, some servers may not deliver or send messages or presence notifications to the client. So we now -need to be sure that we retrieve our roster and send an initial presence once the session has +need to be sure that we retrieve our roster and send an initial presence once the session has started. To do that, we will register an event handler for the :term:`session_start` event. .. code-block:: python @@ -132,8 +107,8 @@ Our event handler, like every event handler, accepts a single parameter which ty that was received that caused the event. In this case, ``event`` will just be an empty dictionary since there is no associated data. -Our first task of sending an initial presence is done using :meth:`send_presence <sleekxmpp.basexmpp.BaseXMPP.send_presence>`. -Calling :meth:`send_presence <sleekxmpp.basexmpp.BaseXMPP.send_presence>` without any arguments will send the simplest +Our first task of sending an initial presence is done using :meth:`send_presence <slixmpp.basexmpp.BaseXMPP.send_presence>`. +Calling :meth:`send_presence <slixmpp.basexmpp.BaseXMPP.send_presence>` without any arguments will send the simplest stanza allowed in XMPP: .. code-block:: xml @@ -141,17 +116,17 @@ stanza allowed in XMPP: <presence /> -The second requirement is fulfilled using :meth:`get_roster <sleekxmpp.clientxmpp.ClientXMPP.get_roster>`, which +The second requirement is fulfilled using :meth:`get_roster <slixmpp.clientxmpp.ClientXMPP.get_roster>`, which will send an IQ stanza requesting the roster to the server and then wait for the response. You may be wondering -what :meth:`get_roster <sleekxmpp.clientxmpp.ClientXMPP.get_roster>` returns since we are not saving any return +what :meth:`get_roster <slixmpp.clientxmpp.ClientXMPP.get_roster>` returns since we are not saving any return value. The roster data is saved by an internal handler to ``self.roster``, and in the case of a :class:`ClientXMPP -<sleekxmpp.clientxmpp.ClientXMPP>` instance to ``self.client_roster``. (The difference between ``self.roster`` and +<slixmpp.clientxmpp.ClientXMPP>` instance to ``self.client_roster``. (The difference between ``self.roster`` and ``self.client_roster`` is that ``self.roster`` supports storing roster information for multiple JIDs, which is useful for components, whereas ``self.client_roster`` stores roster data for just the client's JID.) It is possible for a timeout to occur while waiting for the server to respond, which can happen if the network is excessively slow or the server is no longer responding. In that case, an :class:`IQTimeout -<sleekxmpp.exceptions.IQTimeout>` is raised. Similarly, an :class:`IQError <sleekxmpp.exceptions.IQError>` exception can +<slixmpp.exceptions.IQTimeout>` is raised. Similarly, an :class:`IQError <slixmpp.exceptions.IQError>` exception can be raised if the request contained bad data or requested the roster for the wrong user. In either case, you can wrap the ``get_roster()`` call in a ``try``/``except`` block to retry the roster retrieval process. @@ -198,10 +173,10 @@ or ``chat``. (Other potential types are ``error``, ``headline``, and ``groupchat Let's take a closer look at the ``.reply()`` method used above. For message stanzas, ``.reply()`` accepts the parameter ``body`` (also as the first positional argument), -which is then used as the value of the ``<body />`` element of the message. +which is then used as the value of the ``<body />`` element of the message. Setting the appropriate ``to`` JID is also handled by ``.reply()``. -Another way to have sent the reply message would be to use :meth:`send_message <sleekxmpp.basexmpp.BaseXMPP.send_message>`, +Another way to have sent the reply message would be to use :meth:`send_message <slixmpp.basexmpp.BaseXMPP.send_message>`, which is a convenience method for generating and sending a message based on the values passed to it. If we were to use this method, the above code would look as so: @@ -229,20 +204,20 @@ Whichever method you choose to use, the results in action will look like this: XMPP does not require stanzas sent by a client to include a ``from`` attribute, and leaves that responsibility to the XMPP server. However, if a sent stanza does include a ``from`` attribute, it must match the full JID of the client or some - servers will reject it. SleekXMPP thus leaves out the ``from`` attribute when replying + servers will reject it. Slixmpp thus leaves out the ``from`` attribute when replying using a client connection. Command Line Arguments and Logging ---------------------------------- -While this isn't part of SleekXMPP itself, we do want our echo bot program to be able +While this isn't part of Slixmpp itself, we do want our echo bot program to be able to accept a JID and password from the command line instead of hard coding them. We will use the ``optparse`` module for this, though there are several alternative methods, including the newer ``argparse`` module. We want to accept three parameters: the JID for the echo bot, its password, and a flag for displaying the debugging logs. We also want these to be optional parameters, since passing -a password directly through the command line can be a security risk. +a password directly through the command line can be a security risk. .. code-block:: python @@ -303,21 +278,21 @@ the ``EchoBot.__init__`` method instead. .. note:: - If you are using the OpenFire server, you will need to include an additional + If you are using the OpenFire server, you will need to include an additional configuration step. OpenFire supports a different version of SSL than what - most servers and SleekXMPP support. + most servers and Slixmpp support. .. code-block:: python - + import ssl 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:`sleekxmpp.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 SleekXMPP 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:`sleekxmpp.clientxmpp.ClientXMPP`. +to :meth:`slixmpp.clientxmpp.ClientXMPP`. .. code-block:: python @@ -330,35 +305,19 @@ to :meth:`sleekxmpp.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:`sleekxmpp.basexmpp.BaseXMPP.process` +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:`sleekxmpp.plugins.base.base_plugin.post_init` method on all registered plugins. By -passing ``block=True`` to :meth:`sleekxmpp.basexmpp.BaseXMPP.process` we are running the -main processing loop in the main thread of execution. The :meth:`sleekxmpp.basexmpp.BaseXMPP.process` -call will not return until after SleekXMPP disconnects. If you need to run the client in the background +the :meth:`slixmpp.plugins.base.BasePlugin.post_init` method on all registered plugins. By +passing ``block=True`` to :meth:`slixmpp.basexmpp.BaseXMPP.process` we are running the +main processing loop in the main thread of execution. The :meth:`slixmpp.basexmpp.BaseXMPP.process` +call will not return until after Slixmpp disconnects. If you need to run the client in the background for another program, use ``block=False`` to spawn the processing loop in its own thread. -.. note:: +.. note:: - Before 1.0, controlling the blocking behaviour of :meth:`sleekxmpp.basexmpp.BaseXMPP.process` was + Before 1.0, controlling the blocking behaviour of :meth:`slixmpp.basexmpp.BaseXMPP.process` was done via the ``threaded`` argument. This arrangement was a source of confusion because some users - interpreted that as controlling whether or not SleekXMPP used threads at all, instead of how + interpreted that as controlling whether or not Slixmpp used threads at all, instead of how the processing loop itself was spawned. The statements ``xmpp.process(threaded=False)`` and ``xmpp.process(block=True)`` are equivalent. @@ -370,7 +329,7 @@ The Final Product ----------------- Here then is what the final result should look like after working through the guide above. The code -can also be found in the SleekXMPP `examples directory <http://github.com/fritzy/SleekXMPP/tree/master/examples>`_. +can also be found in the Slixmpp `examples directory <http://github.com/fritzy/Slixmpp/tree/master/examples>`_. .. compound:: diff --git a/docs/getting_started/iq.rst b/docs/getting_started/iq.rst index 98e0bdaf..be15e170 100644 --- a/docs/getting_started/iq.rst +++ b/docs/getting_started/iq.rst @@ -1,17 +1,17 @@ Send/Receive IQ Stanzas ======================= -Unlike :class:`~sleekxmpp.stanza.message.Message` and -:class:`~sleekxmpp.stanza.presence.Presence` stanzas which only use -text data for basic usage, :class:`~sleekxmpp.stanza.iq.Iq` stanzas +Unlike :class:`~slixmpp.stanza.message.Message` and +:class:`~slixmpp.stanza.presence.Presence` stanzas which only use +text data for basic usage, :class:`~slixmpp.stanza.iq.Iq` stanzas require using XML payloads, and generally entail creating a new -SleekXMPP plugin to provide the necessary convenience methods to +Slixmpp plugin to provide the necessary convenience methods to make working with them easier. Basic Use --------- -XMPP's use of :class:`~sleekxmpp.stanza.iq.Iq` stanzas is built around +XMPP's use of :class:`~slixmpp.stanza.iq.Iq` stanzas is built around namespaced ``<query />`` elements. For clients, just sending the empty ``<query />`` element will suffice for retrieving information. For example, a very basic implementation of service discovery would just @@ -26,18 +26,18 @@ need to be able to send: Creating Iq Stanzas ~~~~~~~~~~~~~~~~~~~ -SleekXMPP provides built-in support for creating basic :class:`~sleekxmpp.stanza.iq.Iq` +Slixmpp provides built-in support for creating basic :class:`~slixmpp.stanza.iq.Iq` stanzas this way. The relevant methods are: -* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq` -* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_get` -* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_set` -* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_result` -* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_error` -* :meth:`~sleekxmpp.basexmpp.BaseXMPP.make_iq_query` +* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq` +* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_get` +* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_set` +* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_result` +* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_error` +* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_query` -These methods all follow the same pattern: create or modify an existing -:class:`~sleekxmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based +These methods all follow the same pattern: create or modify an existing +:class:`~slixmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based on the method name, and finally add a ``<query />`` element with the given namespace. For example, to produce the query above, you would use: @@ -50,14 +50,14 @@ namespace. For example, to produce the query above, you would use: Sending Iq Stanzas ~~~~~~~~~~~~~~~~~~ -Once an :class:`~sleekxmpp.stanza.iq.Iq` stanza is created, sending it -over the wire is done using its :meth:`~sleekxmpp.stanza.iq.Iq.send()` +Once an :class:`~slixmpp.stanza.iq.Iq` stanza is created, sending it +over the wire is done using its :meth:`~slixmpp.stanza.iq.Iq.send()` method, like any other stanza object. However, there are a few extra options to control how to wait for the query's response. These options are: -* ``block``: The default behaviour is that :meth:`~sleekxmpp.stanza.iq.Iq.send()` +* ``block``: The default behaviour is that :meth:`~slixmpp.stanza.iq.Iq.send()` will block until a response is received and the response stanza will be the return value. Setting ``block`` to ``False`` will cause the call to return immediately. In which case, you will need to arrange some way to capture @@ -74,7 +74,7 @@ These options are: To change the timeout for a single call, the ``timeout`` parameter works: .. code-block:: python - + iq.send(timeout=60) * ``callback``: When not using a blocking call, using the ``callback`` @@ -85,16 +85,16 @@ These options are: .. code-block:: python - cb_name = iq.send(callback=self.a_callback) + cb_name = iq.send(callback=self.a_callback) # ... later if we need to cancel self.remove_handler(cb_name) -Properly working with :class:`~sleekxmpp.stanza.iq.Iq` stanzas requires +Properly working with :class:`~slixmpp.stanza.iq.Iq` stanzas requires handling the intended, normal flow, error responses, and timed out requests. To make this easier, two exceptions may be thrown by -:meth:`~sleekxmpp.stanza.iq.Iq.send()`: :exc:`~sleekxmpp.exceptions.IqError` -and :exc:`~sleekxmpp.exceptions.IqTimeout`. These exceptions only +:meth:`~slixmpp.stanza.iq.Iq.send()`: :exc:`~slixmpp.exceptions.IqError` +and :exc:`~slixmpp.exceptions.IqTimeout`. These exceptions only apply to the default, blocking calls. .. code-block:: python @@ -110,7 +110,7 @@ apply to the default, blocking calls. pass If you do not care to distinguish between errors and timeouts, then you -can combine both cases with a generic :exc:`~sleekxmpp.exceptions.XMPPError` +can combine both cases with a generic :exc:`~slixmpp.exceptions.XMPPError` exception: .. code-block:: python @@ -124,24 +124,24 @@ exception: Advanced Use ------------ -Going beyond the basics provided by SleekXMPP requires building at least a -rudimentary SleekXMPP plugin to create a :term:`stanza object` for -interfacting with the :class:`~sleekxmpp.stanza.iq.Iq` payload. +Going beyond the basics provided by Slixmpp requires building at least a +rudimentary Slixmpp plugin to create a :term:`stanza object` for +interfacting with the :class:`~slixmpp.stanza.iq.Iq` payload. .. seealso:: * :ref:`create-plugin` * :ref:`work-with-stanzas` * :ref:`using-handlers-matchers` - -The typical way to respond to :class:`~sleekxmpp.stanza.iq.Iq` requests is + +The typical way to respond to :class:`~slixmpp.stanza.iq.Iq` requests is to register stream handlers. As an example, suppose we create a stanza class named ``CustomXEP`` which uses the XML element ``<query xmlns="custom-xep" />``, -and has a :attr:`~sleekxmpp.xmlstream.stanzabase.ElementBase.plugin_attrib` value +and has a :attr:`~slixmpp.xmlstream.stanzabase.ElementBase.plugin_attrib` value of ``custom_xep``. -There are two types of incoming :class:`~sleekxmpp.stanza.iq.Iq` requests: +There are two types of incoming :class:`~slixmpp.stanza.iq.Iq` requests: ``get`` and ``set``. You can register a handler that will accept both and then filter by type as needed, as so: @@ -167,7 +167,7 @@ filter by type as needed, as so: If you want to filter out query types beforehand, you can adjust the matching filter by using ``@type=get`` or ``@type=set`` if you are using the recommended -:class:`~sleekxmpp.xmlstream.matcher.stanzapath.StanzaPath` matcher. +:class:`~slixmpp.xmlstream.matcher.stanzapath.StanzaPath` matcher. .. code-block:: python diff --git a/docs/getting_started/muc.rst b/docs/getting_started/muc.rst index 26e1fa57..4dd1ff93 100644 --- a/docs/getting_started/muc.rst +++ b/docs/getting_started/muc.rst @@ -7,21 +7,13 @@ 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/sleekxmpp-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 SleekXMPP, do so now by either checking out a version -from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip`` -or ``easy_install``. +If you have not yet installed Slixmpp, do so now by either checking out a version +from `Git <http://git.poez.io/slixmpp>`_. -.. code-block:: sh - - pip install sleekxmpp # Or: easy_install sleekxmpp - - -Now that you've got the basic gist of using SleekXMPP by following the +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 to create a very popular XMPP starter project: a `Multi-User Chat`_ (MUC) bot. Our bot will login to an XMPP server, join an MUC chat room @@ -36,7 +28,7 @@ Joining The Room As usual, our code will be based on the pattern explained in :ref:`echobot`. To start, we create an ``MUCBot`` class based on -:class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` and which accepts +:class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` and which accepts parameters for the JID of the MUC room to join, and the nick that the bot will use inside the chat room. We also register an :term:`event handler` for the :term:`session_start` event. @@ -44,12 +36,12 @@ bot will use inside the chat room. We also register an .. code-block:: python - import sleekxmpp + import slixmpp - class MUCBot(sleekxmpp.ClientXMPP): + class MUCBot(slixmpp.ClientXMPP): def __init__(self, jid, password, room, nick): - sleekxmpp.ClientXMPP.__init__(self, jid, password) + slixmpp.ClientXMPP.__init__(self, jid, password) self.room = room self.nick = nick @@ -81,7 +73,7 @@ the roster. Next, we want to join the group chat, so we call the .. note:: - The :attr:`plugin <sleekxmpp.basexmpp.BaseXMPP.plugin>` attribute is + The :attr:`plugin <slixmpp.basexmpp.BaseXMPP.plugin>` attribute is dictionary that maps to instances of plugins that we have previously registered, by their names. @@ -115,7 +107,7 @@ event inside the bot's ``__init__`` function. .. code-block:: python def __init__(self, jid, password, room, nick): - sleekxmpp.ClientXMPP.__init__(self, jid, password) + slixmpp.ClientXMPP.__init__(self, jid, password) self.room = room self.nick = nick @@ -159,7 +151,7 @@ event so it's a good idea to register an event handler for it. .. code-block:: python def __init__(self, jid, password, room, nick): - sleekxmpp.ClientXMPP.__init__(self, jid, password) + slixmpp.ClientXMPP.__init__(self, jid, password) self.room = room self.nick = nick diff --git a/docs/getting_started/proxy.rst b/docs/getting_started/proxy.rst index 60d521c5..22439d4e 100644 --- a/docs/getting_started/proxy.rst +++ b/docs/getting_started/proxy.rst @@ -5,19 +5,17 @@ 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/sleekxmpp-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. -SleekXMPP provides support for basic HTTP proxying with DIGEST +Slixmpp provides support for basic HTTP proxying with DIGEST authentication. -Enabling proxy support is done in two steps. The first is to instruct SleekXMPP +Enabling proxy support is done in two steps. The first is to instruct Slixmpp to use a proxy, and the second is to configure the proxy details: .. code-block:: python diff --git a/docs/getting_started/sendlogout.rst b/docs/getting_started/sendlogout.rst index a1352db9..d5882c42 100644 --- a/docs/getting_started/sendlogout.rst +++ b/docs/getting_started/sendlogout.rst @@ -2,29 +2,27 @@ 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/sleekxmpp-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 SleekXMPP is to send one-off messages from -time to time. For example, one use case could be sending out a notice when +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 a shell script finishes a task. We will create our one-shot bot based on the pattern explained in :ref:`echobot`. To -start, we create a client class based on :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` and +start, we create a client class based on :class:`ClientXMPP <slixmpp.clientxmpp.ClientXMPP>` and register a handler for the :term:`session_start` event. We will also accept parameters for the JID that will receive our message, and the string content of the message. .. code-block:: python - import sleekxmpp + import slixmpp + + class SendMsgBot(slixmpp.ClientXMPP): - class SendMsgBot(sleekxmpp.ClientXMPP): - def __init__(self, jid, password, recipient, msg): super(SendMsgBot, self).__init__(jid, password) @@ -38,7 +36,7 @@ for the JID that will receive our message, and the string content of the message self.get_roster() Note that as in :ref:`echobot`, we need to include send an initial presence and request -the roster. Next, we want to send our message, and to do that we will use :meth:`send_message <sleekxmpp.basexmpp.BaseXMPP.send_message>`. +the roster. Next, we want to send our message, and to do that we will use :meth:`send_message <slixmpp.basexmpp.BaseXMPP.send_message>`. .. code-block:: python @@ -48,12 +46,12 @@ the roster. Next, we want to send our message, and to do that we will use :meth: self.send_message(mto=self.recipient, mbody=self.msg) -Finally, we need to disconnect the client using :meth:`disconnect <sleekxmpp.xmlstream.XMLStream.disconnect>`. +Finally, we need to disconnect the client using :meth:`disconnect <slixmpp.xmlstream.XMLStream.disconnect>`. Now, sent stanzas are placed in a queue to pass them to the send thread. If we were to call -:meth:`disconnect <sleekxmpp.xmlstream.XMLStream.disconnect>` without any parameters, then it is possible +:meth:`disconnect <slixmpp.xmlstream.XMLStream.disconnect>` without any parameters, then it is possible for the client to disconnect before the send queue is processed and the message is actually -sent on the wire. To ensure that our message is processed, we use -:meth:`disconnect(wait=True) <sleekxmpp.xmlstream.XMLStream.disconnect>`. +sent on the wire. To ensure that our message is processed, we use +:meth:`disconnect(wait=True) <slixmpp.xmlstream.XMLStream.disconnect>`. .. code-block:: python @@ -68,7 +66,7 @@ sent on the wire. To ensure that our message is processed, we use .. warning:: If you happen to be adding stanzas to the send queue faster than the send thread - can process them, then :meth:`disconnect(wait=True) <sleekxmpp.xmlstream.XMLStream.disconnect>` + can process them, then :meth:`disconnect(wait=True) <slixmpp.xmlstream.XMLStream.disconnect>` will block and not disconnect. Final Product diff --git a/docs/glossary.rst b/docs/glossary.rst index 35d2dc86..435df102 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -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 diff --git a/docs/guide_xep_0030.rst b/docs/guide_xep_0030.rst index 857f7ff1..70f92b0c 100644 --- a/docs/guide_xep_0030.rst +++ b/docs/guide_xep_0030.rst @@ -18,7 +18,7 @@ Working with service discovery is about creating and querying these nodes. According to XEP-0030, a node may contain three types of information: identities, features, and items. (Further, extensible, information types are defined in `XEP-0128 <http://xmpp.org/extensions/xep-0128.html>`_, but they are -not yet implemented by SleekXMPP.) SleekXMPP provides methods to configure each +not yet implemented by Slixmpp.) Slixmpp provides methods to configure each of these node attributes. Configuring Service Discovery @@ -119,7 +119,7 @@ the same order as expected using positional arguments. xmpp['xep_0030'].add_identity(category='client', itype='bot', - name='Sleek', + name='Slixmpp', node='foo', jid=xmpp.boundjid.full, lang='no') @@ -159,10 +159,10 @@ item itself, and the JID and node that will own the item. .. note:: In this case, the owning JID and node are provided with the - parameters ``ijid`` and ``node``. + parameters ``ijid`` and ``node``. Performing Disco Queries ------------------------ +------------------------ The methods ``get_info()`` and ``get_items()`` are used to query remote JIDs and their nodes for disco information. Since these methods are wrappers for sending Iq stanzas, they also accept all of the parameters of the ``Iq.send()`` @@ -172,11 +172,10 @@ the `XEP-0059 <http://xmpp.org/extensions/xep-0059.html>`_ plug-in. .. code-block:: python - info = self['xep_0030'].get_info(jid='foo@example.com', - node='bar', - ifrom='baz@mycomponent.example.com', - block=True, - timeout=30) + info = yield from self['xep_0030'].get_info(jid='foo@example.com', + node='bar', + ifrom='baz@mycomponent.example.com', + timeout=30) items = self['xep_0030'].get_info(jid='foo@example.com', node='bar', @@ -197,5 +196,5 @@ a full Iq stanza. info = self['xep_0030'].get_info(node='foo', local=True) items = self['xep_0030'].get_items(jid='somejid@mycomponent.example.com', - node='bar', + node='bar', local=True) diff --git a/docs/index.rst b/docs/index.rst index 6f6d8913..92e17eec 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,49 +1,36 @@ -SleekXMPP +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 sleekxmpp + git clone git://git.poez.io/slixmpp - The latest source code for SleekXMPP may be found on `Github - <http://github.com/fritzy/SleekXMPP>`_. 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/SleekXMPP/zipball/1.0>`_ - - **Develop Releases** - - `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_ - - - A mailing list and XMPP chat room are available for discussing and getting - help with SleekXMPP. - - **Mailing List** - `SleekXMPP Discussion on Google Groups <http://groups.google.com/group/sleekxmpp-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. -SleekXMPP 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 SleekXMPP. +.. 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`. -SleekXMPP's design goals and philosphy are: +Slixmpp is an :ref:`MIT licensed <license>` XMPP library for Python 3.4+, + +Slixmpp's design goals and philosphy are: **Low number of dependencies** - Installing and using SleekXMPP should be as simple as possible, without + Installing and using Slixmpp should be as simple as possible, without having to deal with long dependency chains. As part of reducing the number of dependencies, some third party - modules are included with SleekXMPP in the ``thirdparty`` directory. + modules are included with Slixmpp in the ``thirdparty`` directory. Imports from this module first try to import an existing installed version before loading the packaged version, when possible. @@ -55,19 +42,20 @@ SleekXMPP's design goals and philosphy are: XEPs. **Rewarding to work with** - As much as possible, SleekXMPP should allow things to "just work" using + As much as possible, Slixmpp should allow things to "just work" using 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 SleekXMPP Bot: + +Here's your first Slixmpp Bot: -------------------------------- .. code-block:: python + import asyncio import logging - from sleekxmpp import ClientXMPP - from sleekxmpp.exceptions import IqError, IqTimeout + from slixmpp import ClientXMPP class EchoBot(ClientXMPP): @@ -85,27 +73,13 @@ Here's your first SleekXMPP 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'): @@ -113,7 +87,7 @@ Here's your first SleekXMPP Bot: if __name__ == '__main__': - # Ideally use optparse or argparse to get JID, + # Ideally use optparse or argparse to get JID, # password, and log level. logging.basicConfig(level=logging.DEBUG, @@ -121,15 +95,24 @@ Here's your first SleekXMPP 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) ------------------------------- .. toctree:: :maxdepth: 1 - + getting_started/echobot getting_started/sendlogout getting_started/component @@ -144,8 +127,7 @@ Tutorials, FAQs, and How To Guides ---------------------------------- .. toctree:: :maxdepth: 1 - - faq + xeps xmpp_tdg howto/stanzas @@ -156,12 +138,12 @@ Tutorials, FAQs, and How To Guides Plugin Guides ~~~~~~~~~~~~~ -.. toctree:: +.. toctree:: :maxdepth: 1 guide_xep_0030 -SleekXMPP Architecture and Design +Slixmpp Architecture and Design --------------------------------- .. toctree:: :maxdepth: 3 @@ -173,7 +155,7 @@ API Reference ------------- .. toctree:: :maxdepth: 2 - + event_index api/clientxmpp api/componentxmpp @@ -184,9 +166,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 +177,6 @@ Core Stanzas api/stanza/message api/stanza/presence api/stanza/iq - api/stanza/error - api/stanza/stream_error Plugins ~~~~~~~ @@ -220,8 +198,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>`_, diff --git a/docs/license.rst b/docs/license.rst index cbcf5c11..d9505344 100644 --- a/docs/license.rst +++ b/docs/license.rst @@ -1,4 +1,4 @@ -.. _license: +.. _license: License (MIT) ============= diff --git a/docs/make.bat b/docs/make.bat index d97407a6..33fda62b 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -95,9 +95,9 @@ if "%1" == "qthelp" ( echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\SleekXMPP.qhcp + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Slixmpp.qhcp echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\SleekXMPP.ghc + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Slixmpp.ghc goto end ) 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() + + diff --git a/docs/xeps.rst b/docs/xeps.rst index 3653d10a..c5b4592d 100644 --- a/docs/xeps.rst +++ b/docs/xeps.rst @@ -4,9 +4,9 @@ Supported XEPS ======= ============================= ================ XEP Description Notes ======= ============================= ================ -`0004`_ Data forms -`0009`_ Jabber RPC -`0012`_ Last Activity +`0004`_ Data forms +`0009`_ Jabber RPC +`0012`_ Last Activity `0030`_ Service Discovery `0033`_ Extended Stanza Addressing `0045`_ Multi-User Chat (MUC) Client-side only diff --git a/docs/xmpp_tdg.rst b/docs/xmpp_tdg.rst index 3d12b1b6..b14fd9e1 100644 --- a/docs/xmpp_tdg.rst +++ b/docs/xmpp_tdg.rst @@ -1,20 +1,20 @@ Following *XMPP: The Definitive Guide* ====================================== -SleekXMPP was featured in the first edition of the O'Reilly book +Slixmpp was featured in the first edition of the O'Reilly book `XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271/>`_ by Peter Saint-Andre, Kevin Smith, and Remko Tronçon. The original source code for the book's examples can be found at http://github.com/remko/xmpp-tdg. An updated version of the source code, maintained to stay current with the latest -SleekXMPP release, is available at http://github.com/legastero/xmpp-tdg. +Slixmpp release, is available at http://github.com/legastero/xmpp-tdg. -However, since publication, SleekXMPP has advanced from version 0.2.1 to version +However, since publication, Slixmpp has advanced from version 0.2.1 to version 1.0 and there have been several major API changes. The most notable is the introduction of :term:`stanza objects <stanza object>` which have simplified and standardized interactions with the XMPP XML stream. What follows is a walk-through of *The Definitive Guide* highlighting the -changes needed to make the code examples work with version 1.0 of SleekXMPP. +changes needed to make the code examples work with version 1.0 of Slixmpp. These changes have been kept to a minimum to preserve the correlation with the book's explanations, so be aware that some code may not use current best practices. @@ -36,7 +36,7 @@ Updated Code .. code-block:: python def handleIncomingMessage(self, message): - self.xmpp.sendMessage(message["from"], message["body"]) + self.xmpp.send_message(message["from"], message["body"]) `View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_ | `View original code <http://github.com/remko/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_ @@ -47,7 +47,7 @@ Example 14-1. (Page 215) **CheshiR IM bot implementation.** The main event handling method in the Bot class is meant to process both message -events and presence update events. With the new changes in SleekXMPP 1.0, +events and presence update events. With the new changes in Slixmpp 1.0, extracting a CheshiR status "message" from both types of stanzas requires accessing different attributes. In the case of a message stanza, the ``"body"`` attribute would contain the CheshiR message. For a presence event, @@ -72,21 +72,21 @@ Updated Code .. code-block:: python def handleIncomingXMPPEvent(self, event): - msgLocations = {sleekxmpp.stanza.presence.Presence: "status", - sleekxmpp.stanza.message.Message: "body"} + msgLocations = {slixmpp.stanza.presence.Presence: "status", + slixmpp.stanza.message.Message: "body"} message = event[msgLocations[type(event)]] user = self.backend.getUserFromJID(event["from"].jid) if user is not None: self.backend.addMessageFromUser(message, user) - + def handleMessageAddedToBackend(self, message) : body = message.user + ": " + message.text htmlBody = "<p><a href='%(uri)s'>%(user)s</a>: %(message)s</p>" % { "uri": self.url + "/" + message.user, "user" : message.user, "message" : message.text } for subscriberJID in self.backend.getSubscriberJIDs(message.user) : - self.xmpp.sendMessage(subscriberJID, body, mhtml=htmlBody) + self.xmpp.send_message(subscriberJID, body, mhtml=htmlBody) `View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_ | `View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_ @@ -102,7 +102,7 @@ Example 14-3. (Page 217) The main difference for the configurable IM bot is the handling for the data form in ``handleConfigurationCommand``. The test for equality -with the string ``"1"`` is no longer required; SleekXMPP converts +with the string ``"1"`` is no longer required; Slixmpp converts boolean data form fields to the values ``True`` and ``False`` automatically. @@ -145,7 +145,7 @@ Example 14-4. (Page 220) Like several previous examples, a needed change is to replace ``subscription["from"]`` with ``subscription["from"].jid`` because the -``BaseXMPP`` method ``makePresence`` requires the JID to be a string. +``BaseXMPP`` method ``make_presence`` requires the JID to be a string. A correction needs to be made in ``handleXMPPPresenceProbe`` because a line was left out of the original implementation; the variable ``user`` is undefined. The @@ -154,7 +154,7 @@ JID of the user can be extracted from the presence stanza's ``from`` attribute. Since this implementation of CheshiR uses an XMPP component, it must include a ``from`` attribute in all messages that it sends. Adding the ``from`` attribute is done by including ``mfrom=self.xmpp.jid`` in calls to -``self.xmpp.sendMessage``. +``self.xmpp.send_message``. Updated Code ~~~~~~~~~~~~ @@ -162,19 +162,19 @@ Updated Code .. code-block:: python def handleXMPPPresenceProbe(self, event) : - self.xmpp.sendPresence(pto = event["from"]) + self.xmpp.send_presence(pto = event["from"]) def handleXMPPPresenceSubscription(self, subscription) : if subscription["type"] == "subscribe" : userJID = subscription["from"].jid - self.xmpp.sendPresenceSubscription(pto=userJID, ptype="subscribed") - self.xmpp.sendPresence(pto = userJID) - self.xmpp.sendPresenceSubscription(pto=userJID, ptype="subscribe") + self.xmpp.send_presence_subscription(pto=userJID, ptype="subscribed") + self.xmpp.send_presence(pto = userJID) + self.xmpp.send_presence_subscription(pto=userJID, ptype="subscribe") def handleMessageAddedToBackend(self, message) : body = message.user + ": " + message.text for subscriberJID in self.backend.getSubscriberJIDs(message.user) : - self.xmpp.sendMessage(subscriberJID, body, mfrom=self.xmpp.jid) + self.xmpp.send_message(subscriberJID, body, mfrom=self.xmpp.jid) `View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_ | `View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_ @@ -192,7 +192,7 @@ After applying the changes from Example 14-4 above, the registrable component implementation should work correctly. .. tip:: - To see how to implement in-band registration as a SleekXMPP plugin, + To see how to implement in-band registration as a Slixmpp plugin, see the tutorial :ref:`tutorial-create-plugin`. `View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/RegistrableComponent.py>`_ | @@ -203,13 +203,13 @@ Example 14-7. (Page 225) **Extended CheshiR IM server component implementation.** .. note:: - Since the CheshiR examples build on each other, see previous + Since the CheshiR examples build on each other, see previous sections for corrections to code that is not marked as new in the book example. While the final code example can look daunting with all of the changes made, it requires very few modifications to work with the latest version of -SleekXMPP. Most differences are the result of CheshiR's backend functions +Slixmpp. Most differences are the result of CheshiR's backend functions expecting JIDs to be strings so that they can be stripped to bare JIDs. To resolve these, use the ``jid`` attribute of the JID objects. Also, references to ``"message"`` and ``"jid"`` attributes need to @@ -239,11 +239,11 @@ Updated Code userJID = subscription["from"].jid user = self.backend.getUserFromJID(userJID) contactJID = subscription["to"] - self.xmpp.sendPresenceSubscription( + self.xmpp.send_presence_subscription( pfrom=contactJID, pto=userJID, ptype="subscribed", pnick=user) self.sendPresenceOfContactToUser(contactJID=contactJID, userJID=userJID) if contactJID == self.componentDomain : self.sendAllContactSubscriptionRequestsToUser(userJID) `View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_ | -`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_ +`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_ |