Remove all trailing whitespaces.

This commit is contained in:
Emmanuel Gil Peyrot 2014-08-17 21:53:34 +02:00 committed by Florent Le Coz
parent ed37174a2b
commit 17174016ec
41 changed files with 1012 additions and 1012 deletions

View File

@ -80,7 +80,7 @@ Slixmpp projects::
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,
@ -101,15 +101,15 @@ Credits
-------
**Main Author:** Nathan Fritz
`fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_,
`fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_,
`@fritzy <http://twitter.com/fritzy>`_
Nathan is also the author of XMPPHP and `Seesmic-AS3-XMPP
<http://code.google.com/p/seesmic-as3-xmpp/>`_, and a former member of
<http://code.google.com/p/seesmic-as3-xmpp/>`_, and a former member of
the XMPP Council.
**Co-Author:** Lance Stout
`lancestout@gmail.com <xmpp:lancestout@gmail.com?message>`_,
`lancestout@gmail.com <xmpp:lancestout@gmail.com?message>`_,
`@lancestout <http://twitter.com/lancestout>`_
**Contributors:**

View File

@ -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;

View File

@ -134,7 +134,7 @@ div.footer a {
/* -- body styles ----------------------------------------------------------- */
p {
p {
margin: 0.8em 0 0.5em 0;
}

View File

@ -3,7 +3,7 @@ Exceptions
.. module:: slixmpp.exceptions
.. autoexception:: XMPPError
:members:

View File

@ -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
--------------------------

View File

@ -88,7 +88,7 @@ when this bit of XML is received (with an assumed namespace of
callback, the callback function is executed with the stanza as its only
parameter.
.. warning::
.. warning::
The callback, aka :term:`stream handler`, is executed in the main event
processing thread. If the handler blocks, event processing will also
block.
@ -117,7 +117,7 @@ when this bit of XML is received (with an assumed namespace of
paired with an :term:`event handler`::
('event', 'message', msg_copy1, custom_event_handler_1)
('event', 'message', msg_copy2, custom_evetn_handler_2)
('event', 'message', msg_copy2, custom_evetn_handler_2)
5. **Process Custom Events**
@ -127,9 +127,9 @@ when this bit of XML is received (with an assumed namespace of
will be spawned for it.
.. 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

View File

@ -40,7 +40,7 @@ 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
``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
@ -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

View File

@ -60,13 +60,13 @@ Event Index
disco_info
- **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:`~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
@ -88,13 +88,13 @@ Event Index
gmail_notify
- **Data:** ``{}``
- **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:`~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
@ -122,19 +122,19 @@ Event Index
groupchat_message
- **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:`~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:`~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
@ -148,7 +148,7 @@ Event Index
message
- **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.
@ -183,67 +183,67 @@ Event Index
presence_available
- **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:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``error``' is received.
presence_form
- **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:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``probe``' is received.
presence_subscribe
- **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:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``subscribed``' is received.
presence_unavailable
- **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:`~slixmpp.Presence`
- **Source:** :py:class:`~slixmpp.BaseXMPP`
A presence stanza with a type of '``unsubscribe``' is received.
presence_unsubscribed
- **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:`~slixmpp.stanza.Roster`
- **Source:** :py:class:`~slixmpp.ClientXMPP`
An IQ result containing roster entries is received.
sent_presence
- **Data:** ``{}``
- **Source:** :py:class:`~slixmpp.roster.multi.Roster`
Signal that an initial presence stanza has been written to the XML stream.
session_end

View File

@ -5,7 +5,7 @@ Create and Run a Server Component
=================================
.. note::
If you have any issues working through this quickstart guide
or the other tutorials here, please either send a message to the
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
@ -21,8 +21,8 @@ or ``easy_install``.
pip install slixmpp # Or: easy_install 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.

View File

@ -5,7 +5,7 @@ Slixmpp Quickstart - Echo Bot
===============================
.. note::
If you have any issues working through this quickstart guide
or the other tutorials here, please either send a message to the
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
@ -93,7 +93,7 @@ as well.
.. code-block:: python
class EchoBot(slixmpp.ClientXMPP):
def __init__(self, jid, password):
super(EchoBot, self).__init__(jid, password)
@ -102,7 +102,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
@ -198,7 +198,7 @@ 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 <slixmpp.basexmpp.BaseXMPP.send_message>`,
@ -242,7 +242,7 @@ 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 +303,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 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:`slixmpp.clientxmpp.ClientXMPP` method
will perform a DNS query to find the appropriate server to connect to for the
given JID. If you do not have ``dnspython``, then Slixmpp will attempt to
given JID. If you do not have ``dnspython``, then Slixmpp will attempt to
connect to the hostname used by the JID, unless an address tuple is supplied
to :meth:`slixmpp.clientxmpp.ClientXMPP`.
to :meth:`slixmpp.clientxmpp.ClientXMPP`.
.. code-block:: python
@ -349,12 +349,12 @@ to :meth:`slixmpp.clientxmpp.ClientXMPP`.
To begin responding to messages, you'll see we called :meth:`slixmpp.basexmpp.BaseXMPP.process`
which will start the event handling, send queue, and XML reader threads. It will also call
the :meth:`slixmpp.plugins.base.base_plugin.post_init` method on all registered plugins. By
passing ``block=True`` to :meth:`slixmpp.basexmpp.BaseXMPP.process` we are running the
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:`slixmpp.basexmpp.BaseXMPP.process` was
done via the ``threaded`` argument. This arrangement was a source of confusion because some users

View File

@ -36,7 +36,7 @@ stanzas this way. The relevant methods are:
* :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
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:
@ -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,7 +85,7 @@ 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)
@ -133,7 +133,7 @@ interfacting with the :class:`~slixmpp.stanza.iq.Iq` payload.
* :ref:`create-plugin`
* :ref:`work-with-stanzas`
* :ref:`using-handlers-matchers`
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

View File

@ -5,7 +5,7 @@ Enable HTTP Proxy Support
=========================
.. note::
If you have any issues working through this quickstart guide
or the other tutorials here, please either send a message to the
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_

View File

@ -2,7 +2,7 @@ Sign in, Send a Message, and Disconnect
=======================================
.. note::
If you have any issues working through this quickstart guide
or the other tutorials here, please either send a message to the
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
@ -10,7 +10,7 @@ Sign in, Send a Message, and Disconnect
<xmpp:sleek@conference.jabber.org?join>`_.
A common use case for Slixmpp is to send one-off messages from
time to time. For example, one use case could be sending out a notice when
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
@ -24,7 +24,7 @@ for the JID that will receive our message, and the string content of the message
class SendMsgBot(slixmpp.ClientXMPP):
def __init__(self, jid, password, recipient, msg):
super(SendMsgBot, self).__init__(jid, password)
@ -52,7 +52,7 @@ Finally, we need to disconnect the client using :meth:`disconnect <slixmpp.xmlst
Now, sent stanzas are placed in a queue to pass them to the send thread. If we were to call
: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
sent on the wire. To ensure that our message is processed, we use
:meth:`disconnect(wait=True) <slixmpp.xmlstream.XMLStream.disconnect>`.
.. code-block:: python

View File

@ -159,7 +159,7 @@ 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``.
Peforming Disco Queries
-----------------------
@ -197,5 +197,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)

View File

@ -31,7 +31,7 @@ Slixmpp
Slixmpp is an :ref:`MIT licensed <license>` XMPP library for Python 2.6/3.1+,
and is featured in examples in
`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271>`_
`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271>`_
by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived
here from reading the Definitive Guide, please see the notes on updating
the examples to the latest version of Slixmpp.
@ -113,7 +113,7 @@ Here's your first Slixmpp 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,
@ -129,7 +129,7 @@ Getting Started (with Examples)
-------------------------------
.. toctree::
:maxdepth: 1
getting_started/echobot
getting_started/sendlogout
getting_started/component
@ -144,7 +144,7 @@ Tutorials, FAQs, and How To Guides
----------------------------------
.. toctree::
:maxdepth: 1
faq
xeps
xmpp_tdg
@ -156,7 +156,7 @@ Tutorials, FAQs, and How To Guides
Plugin Guides
~~~~~~~~~~~~~
.. toctree::
.. toctree::
:maxdepth: 1
guide_xep_0030
@ -173,7 +173,7 @@ API Reference
-------------
.. toctree::
:maxdepth: 2
event_index
api/clientxmpp
api/componentxmpp

View File

@ -1,4 +1,4 @@
.. _license:
.. _license:
License (MIT)
=============

View File

@ -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

View File

@ -1,7 +1,7 @@
Following *XMPP: The Definitive Guide*
======================================
Slixmpp 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
@ -79,7 +79,7 @@ Updated Code
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>" % {
@ -203,7 +203,7 @@ 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.
@ -246,4 +246,4 @@ Updated Code
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>`_

View File

@ -82,7 +82,7 @@ class ActionUserBot(slixmpp.ClientXMPP):
iq2['type'] = 'set'
iq2['action']['method'] = 'bye'
iq2.send(block=False)
# The wait=True delays the disconnect until the queue
# of stanzas to be sent becomes empty.
self.disconnect(wait=True)

View File

@ -11,7 +11,7 @@ class Action(ElementBase):
<status>X</status>
</action>
"""
#: The `name` field refers to the basic XML tag name of the
#: stanza. Here, the tag name will be 'action'.
name = 'action'
@ -22,9 +22,9 @@ class Action(ElementBase):
#: The `plugin_attrib` value is the name that can be used
#: with a parent stanza to access this stanza. For example
#: from an Iq stanza object, accessing:
#:
#:
#: iq['action']
#:
#:
#: would reference an Action object, and will even create
#: an Action object and append it to the Iq stanza if
#: one doesn't already exist.
@ -49,7 +49,7 @@ class Action(ElementBase):
#: the sub_interfaces set. For example, here all interfaces
#: are marked as sub_interfaces, and so the XML produced will
#: look like:
#:
#:
#: <action xmlns="slixmpp:custom:actions">
#: <method>foo</method>
#: </action>

View File

@ -121,7 +121,7 @@ if __name__ == '__main__':
if args.password is None:
args.password = getpass("Password: ")
access_token = None
# Since documentation on how to work with Google tokens
@ -147,7 +147,7 @@ if __name__ == '__main__':
'Passwd': args.password
})
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
'Content-Type': 'application/x-www-form-urlencoded'
}
try:
conn.request('POST', '/accounts/ClientLogin', params, headers)
@ -195,12 +195,12 @@ if __name__ == '__main__':
# We're using an access token instead of a password, so we'll use `''` as
# a password argument filler.
xmpp = ThirdPartyAuthBot(args.jid, '')
xmpp = ThirdPartyAuthBot(args.jid, '')
xmpp.credentials['access_token'] = access_token
# The credentials dictionary is used to provide additional authentication
# information beyond just a password.
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0060') # PubSub
@ -218,7 +218,7 @@ if __name__ == '__main__':
# xmpp.ca_certs = "path/to/ca/cert"
# Connect to the XMPP server and start processing XMPP stanzas.
# Google only allows one SASL attempt per connection, so in order to
# Google only allows one SASL attempt per connection, so in order to
# enable the X-GOOGLE-TOKEN mechanism, we'll disable TLS.
xmpp.connect()
xmpp.process()

View File

@ -25,7 +25,7 @@ class LocationBot(ClientXMPP):
super(LocationBot, self).__init__(jid, password)
self.add_event_handler('session_start', self.start)
self.add_event_handler('user_location_publish',
self.add_event_handler('user_location_publish',
self.user_location_publish)
self.register_plugin('xep_0004')

View File

@ -1,218 +1,218 @@
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON).
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from slixmpp import Iq
from slixmpp.xmlstream import ET, register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import MatchXPath
from slixmpp.plugins import BasePlugin
from slixmpp.plugins.xep_0009 import stanza
from slixmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse
log = logging.getLogger(__name__)
class XEP_0009(BasePlugin):
name = 'xep_0009'
description = 'XEP-0009: Jabber-RPC'
dependencies = set(['xep_0030'])
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Iq, RPCQuery)
register_stanza_plugin(RPCQuery, MethodCall)
register_stanza_plugin(RPCQuery, MethodResponse)
self.xmpp.register_handler(
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
self._handle_method_call)
)
self.xmpp.register_handler(
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
self._handle_method_response)
)
self.xmpp.register_handler(
Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)),
self._handle_error)
)
self.xmpp.add_event_handler('jabber_rpc_method_call', self._on_jabber_rpc_method_call)
self.xmpp.add_event_handler('jabber_rpc_method_response', self._on_jabber_rpc_method_response)
self.xmpp.add_event_handler('jabber_rpc_method_fault', self._on_jabber_rpc_method_fault)
self.xmpp.add_event_handler('jabber_rpc_error', self._on_jabber_rpc_error)
self.xmpp.add_event_handler('error', self._handle_error)
#self.activeCalls = []
self.xmpp['xep_0030'].add_feature('jabber:iq:rpc')
self.xmpp['xep_0030'].add_identity('automation','rpc')
def make_iq_method_call(self, pto, pmethod, params):
iq = self.xmpp.makeIqSet()
iq.attrib['to'] = pto
iq.attrib['from'] = self.xmpp.boundjid.full
iq.enable('rpc_query')
iq['rpc_query']['method_call']['method_name'] = pmethod
iq['rpc_query']['method_call']['params'] = params
return iq;
def make_iq_method_response(self, pid, pto, params):
iq = self.xmpp.makeIqResult(pid)
iq.attrib['to'] = pto
iq.attrib['from'] = self.xmpp.boundjid.full
iq.enable('rpc_query')
iq['rpc_query']['method_response']['params'] = params
return iq
def make_iq_method_response_fault(self, pid, pto, params):
iq = self.xmpp.makeIqResult(pid)
iq.attrib['to'] = pto
iq.attrib['from'] = self.xmpp.boundjid.full
iq.enable('rpc_query')
iq['rpc_query']['method_response']['params'] = None
iq['rpc_query']['method_response']['fault'] = params
return iq
# def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition):
# iq = self.xmpp.makeIqError(pid)
# iq.attrib['to'] = pto
# iq.attrib['from'] = self.xmpp.boundjid.full
# iq['error']['code'] = code
# iq['error']['type'] = type
# iq['error']['condition'] = condition
# iq['rpc_query']['method_call']['method_name'] = pmethod
# iq['rpc_query']['method_call']['params'] = params
# return iq
def _item_not_found(self, iq):
payload = iq.get_payload()
iq.reply().error().set_payload(payload);
iq['error']['code'] = '404'
iq['error']['type'] = 'cancel'
iq['error']['condition'] = 'item-not-found'
return iq
def _undefined_condition(self, iq):
payload = iq.get_payload()
iq.reply().error().set_payload(payload)
iq['error']['code'] = '500'
iq['error']['type'] = 'cancel'
iq['error']['condition'] = 'undefined-condition'
return iq
def _forbidden(self, iq):
payload = iq.get_payload()
iq.reply().error().set_payload(payload)
iq['error']['code'] = '403'
iq['error']['type'] = 'auth'
iq['error']['condition'] = 'forbidden'
return iq
def _recipient_unvailable(self, iq):
payload = iq.get_payload()
iq.reply().error().set_payload(payload)
iq['error']['code'] = '404'
iq['error']['type'] = 'wait'
iq['error']['condition'] = 'recipient-unavailable'
return iq
def _handle_method_call(self, iq):
type = iq['type']
if type == 'set':
log.debug("Incoming Jabber-RPC call from %s", iq['from'])
self.xmpp.event('jabber_rpc_method_call', iq)
else:
if type == 'error' and ['rpc_query'] is None:
self.handle_error(iq)
else:
log.debug("Incoming Jabber-RPC error from %s", iq['from'])
self.xmpp.event('jabber_rpc_error', iq)
def _handle_method_response(self, iq):
if iq['rpc_query']['method_response']['fault'] is not None:
log.debug("Incoming Jabber-RPC fault from %s", iq['from'])
#self._on_jabber_rpc_method_fault(iq)
self.xmpp.event('jabber_rpc_method_fault', iq)
else:
log.debug("Incoming Jabber-RPC response from %s", iq['from'])
self.xmpp.event('jabber_rpc_method_response', iq)
def _handle_error(self, iq):
print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq)
print("#######################")
print("### NOT IMPLEMENTED ###")
print("#######################")
def _on_jabber_rpc_method_call(self, iq, forwarded=False):
"""
A default handler for Jabber-RPC method call. If another
handler is registered, this one will defer and not run.
If this handler is called by your own custom handler with
forwarded set to True, then it will run as normal.
"""
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_call') > 1:
return
# Reply with error by default
error = self.client.plugin['xep_0009']._item_not_found(iq)
error.send()
def _on_jabber_rpc_method_response(self, iq, forwarded=False):
"""
A default handler for Jabber-RPC method response. If another
handler is registered, this one will defer and not run.
If this handler is called by your own custom handler with
forwarded set to True, then it will run as normal.
"""
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_response') > 1:
return
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
error.send()
def _on_jabber_rpc_method_fault(self, iq, forwarded=False):
"""
A default handler for Jabber-RPC fault response. If another
handler is registered, this one will defer and not run.
If this handler is called by your own custom handler with
forwarded set to True, then it will run as normal.
"""
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_fault') > 1:
return
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
error.send()
def _on_jabber_rpc_error(self, iq, forwarded=False):
"""
A default handler for Jabber-RPC error response. If another
handler is registered, this one will defer and not run.
If this handler is called by your own custom handler with
forwarded set to True, then it will run as normal.
"""
if not forwarded and self.xmpp.event_handled('jabber_rpc_error') > 1:
return
error = self.client.plugin['xep_0009']._recpient_unavailable(iq, iq.get_payload())
error.send()
def _send_fault(self, iq, fault_xml): #
fault = self.make_iq_method_response_fault(iq['id'], iq['from'], fault_xml)
fault.send()
def _send_error(self, iq):
print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq)
print("#######################")
print("### NOT IMPLEMENTED ###")
print("#######################")
def _extract_method(self, stanza):
xml = ET.fromstring("%s" % stanza)
return xml.find("./methodCall/methodName").text
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON).
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from slixmpp import Iq
from slixmpp.xmlstream import ET, register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import MatchXPath
from slixmpp.plugins import BasePlugin
from slixmpp.plugins.xep_0009 import stanza
from slixmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse
log = logging.getLogger(__name__)
class XEP_0009(BasePlugin):
name = 'xep_0009'
description = 'XEP-0009: Jabber-RPC'
dependencies = set(['xep_0030'])
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Iq, RPCQuery)
register_stanza_plugin(RPCQuery, MethodCall)
register_stanza_plugin(RPCQuery, MethodResponse)
self.xmpp.register_handler(
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
self._handle_method_call)
)
self.xmpp.register_handler(
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
self._handle_method_response)
)
self.xmpp.register_handler(
Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)),
self._handle_error)
)
self.xmpp.add_event_handler('jabber_rpc_method_call', self._on_jabber_rpc_method_call)
self.xmpp.add_event_handler('jabber_rpc_method_response', self._on_jabber_rpc_method_response)
self.xmpp.add_event_handler('jabber_rpc_method_fault', self._on_jabber_rpc_method_fault)
self.xmpp.add_event_handler('jabber_rpc_error', self._on_jabber_rpc_error)
self.xmpp.add_event_handler('error', self._handle_error)
#self.activeCalls = []
self.xmpp['xep_0030'].add_feature('jabber:iq:rpc')
self.xmpp['xep_0030'].add_identity('automation','rpc')
def make_iq_method_call(self, pto, pmethod, params):
iq = self.xmpp.makeIqSet()
iq.attrib['to'] = pto
iq.attrib['from'] = self.xmpp.boundjid.full
iq.enable('rpc_query')
iq['rpc_query']['method_call']['method_name'] = pmethod
iq['rpc_query']['method_call']['params'] = params
return iq;
def make_iq_method_response(self, pid, pto, params):
iq = self.xmpp.makeIqResult(pid)
iq.attrib['to'] = pto
iq.attrib['from'] = self.xmpp.boundjid.full
iq.enable('rpc_query')
iq['rpc_query']['method_response']['params'] = params
return iq
def make_iq_method_response_fault(self, pid, pto, params):
iq = self.xmpp.makeIqResult(pid)
iq.attrib['to'] = pto
iq.attrib['from'] = self.xmpp.boundjid.full
iq.enable('rpc_query')
iq['rpc_query']['method_response']['params'] = None
iq['rpc_query']['method_response']['fault'] = params
return iq
# def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition):
# iq = self.xmpp.makeIqError(pid)
# iq.attrib['to'] = pto
# iq.attrib['from'] = self.xmpp.boundjid.full
# iq['error']['code'] = code
# iq['error']['type'] = type
# iq['error']['condition'] = condition
# iq['rpc_query']['method_call']['method_name'] = pmethod
# iq['rpc_query']['method_call']['params'] = params
# return iq
def _item_not_found(self, iq):
payload = iq.get_payload()
iq.reply().error().set_payload(payload);
iq['error']['code'] = '404'
iq['error']['type'] = 'cancel'
iq['error']['condition'] = 'item-not-found'
return iq
def _undefined_condition(self, iq):
payload = iq.get_payload()
iq.reply().error().set_payload(payload)
iq['error']['code'] = '500'
iq['error']['type'] = 'cancel'
iq['error']['condition'] = 'undefined-condition'
return iq
def _forbidden(self, iq):
payload = iq.get_payload()
iq.reply().error().set_payload(payload)
iq['error']['code'] = '403'
iq['error']['type'] = 'auth'
iq['error']['condition'] = 'forbidden'
return iq
def _recipient_unvailable(self, iq):
payload = iq.get_payload()
iq.reply().error().set_payload(payload)
iq['error']['code'] = '404'
iq['error']['type'] = 'wait'
iq['error']['condition'] = 'recipient-unavailable'
return iq
def _handle_method_call(self, iq):
type = iq['type']
if type == 'set':
log.debug("Incoming Jabber-RPC call from %s", iq['from'])
self.xmpp.event('jabber_rpc_method_call', iq)
else:
if type == 'error' and ['rpc_query'] is None:
self.handle_error(iq)
else:
log.debug("Incoming Jabber-RPC error from %s", iq['from'])
self.xmpp.event('jabber_rpc_error', iq)
def _handle_method_response(self, iq):
if iq['rpc_query']['method_response']['fault'] is not None:
log.debug("Incoming Jabber-RPC fault from %s", iq['from'])
#self._on_jabber_rpc_method_fault(iq)
self.xmpp.event('jabber_rpc_method_fault', iq)
else:
log.debug("Incoming Jabber-RPC response from %s", iq['from'])
self.xmpp.event('jabber_rpc_method_response', iq)
def _handle_error(self, iq):
print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq)
print("#######################")
print("### NOT IMPLEMENTED ###")
print("#######################")
def _on_jabber_rpc_method_call(self, iq, forwarded=False):
"""
A default handler for Jabber-RPC method call. If another
handler is registered, this one will defer and not run.
If this handler is called by your own custom handler with
forwarded set to True, then it will run as normal.
"""
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_call') > 1:
return
# Reply with error by default
error = self.client.plugin['xep_0009']._item_not_found(iq)
error.send()
def _on_jabber_rpc_method_response(self, iq, forwarded=False):
"""
A default handler for Jabber-RPC method response. If another
handler is registered, this one will defer and not run.
If this handler is called by your own custom handler with
forwarded set to True, then it will run as normal.
"""
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_response') > 1:
return
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
error.send()
def _on_jabber_rpc_method_fault(self, iq, forwarded=False):
"""
A default handler for Jabber-RPC fault response. If another
handler is registered, this one will defer and not run.
If this handler is called by your own custom handler with
forwarded set to True, then it will run as normal.
"""
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_fault') > 1:
return
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
error.send()
def _on_jabber_rpc_error(self, iq, forwarded=False):
"""
A default handler for Jabber-RPC error response. If another
handler is registered, this one will defer and not run.
If this handler is called by your own custom handler with
forwarded set to True, then it will run as normal.
"""
if not forwarded and self.xmpp.event_handled('jabber_rpc_error') > 1:
return
error = self.client.plugin['xep_0009']._recpient_unavailable(iq, iq.get_payload())
error.send()
def _send_fault(self, iq, fault_xml): #
fault = self.make_iq_method_response_fault(iq['id'], iq['from'], fault_xml)
fault.send()
def _send_error(self, iq):
print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq)
print("#######################")
print("### NOT IMPLEMENTED ###")
print("#######################")
def _extract_method(self, stanza):
xml = ET.fromstring("%s" % stanza)
return xml.find("./methodCall/methodName").text

View File

@ -1,156 +1,156 @@
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from datetime import datetime, timedelta
from slixmpp.plugins import BasePlugin, register_plugin
from slixmpp import Iq
from slixmpp.exceptions import XMPPError
from slixmpp.xmlstream import JID, register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
from slixmpp.plugins.xep_0012 import stanza, LastActivity
log = logging.getLogger(__name__)
class XEP_0012(BasePlugin):
"""
XEP-0012 Last Activity
"""
name = 'xep_0012'
description = 'XEP-0012: Last Activity'
dependencies = set(['xep_0030'])
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Iq, LastActivity)
self._last_activities = {}
self.xmpp.register_handler(
Callback('Last Activity',
StanzaPath('iq@type=get/last_activity'),
self._handle_get_last_activity))
self.api.register(self._default_get_last_activity,
'get_last_activity',
default=True)
self.api.register(self._default_set_last_activity,
'set_last_activity',
default=True)
self.api.register(self._default_del_last_activity,
'del_last_activity',
default=True)
def plugin_end(self):
self.xmpp.remove_handler('Last Activity')
self.xmpp['xep_0030'].del_feature(feature='jabber:iq:last')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('jabber:iq:last')
def begin_idle(self, jid=None, status=None):
self.set_last_activity(jid, 0, status)
def end_idle(self, jid=None):
self.del_last_activity(jid)
def start_uptime(self, status=None):
self.set_last_activity(jid, 0, status)
def set_last_activity(self, jid=None, seconds=None, status=None):
self.api['set_last_activity'](jid, args={
'seconds': seconds,
'status': status})
def del_last_activity(self, jid):
self.api['del_last_activity'](jid)
def get_last_activity(self, jid, local=False, ifrom=None, timeout=None,
callback=None, timeout_callback=None):
if jid is not None and not isinstance(jid, JID):
jid = JID(jid)
if self.xmpp.is_component:
if jid.domain == self.xmpp.boundjid.domain:
local = True
else:
if str(jid) == str(self.xmpp.boundjid):
local = True
jid = jid.full
if local or jid in (None, ''):
log.debug("Looking up local last activity data for %s", jid)
return self.api['get_last_activity'](jid, None, ifrom, None)
iq = self.xmpp.Iq()
iq['from'] = ifrom
iq['to'] = jid
iq['type'] = 'get'
iq.enable('last_activity')
return iq.send(timeout=timeout, callback=callback,
timeout_callback=timeout_callback)
def _handle_get_last_activity(self, iq):
log.debug("Received last activity query from " + \
"<%s> to <%s>.", iq['from'], iq['to'])
reply = self.api['get_last_activity'](iq['to'], None, iq['from'], iq)
reply.send()
# =================================================================
# Default in-memory implementations for storing last activity data.
# =================================================================
def _default_set_last_activity(self, jid, node, ifrom, data):
seconds = data.get('seconds', None)
if seconds is None:
seconds = 0
status = data.get('status', None)
if status is None:
status = ''
self._last_activities[jid] = {
'seconds': datetime.now() - timedelta(seconds=seconds),
'status': status}
def _default_del_last_activity(self, jid, node, ifrom, data):
if jid in self._last_activities:
del self._last_activities[jid]
def _default_get_last_activity(self, jid, node, ifrom, iq):
if not isinstance(iq, Iq):
reply = self.xmpp.Iq()
else:
iq.reply()
reply = iq
if jid not in self._last_activities:
raise XMPPError('service-unavailable')
bare = JID(jid).bare
if bare != self.xmpp.boundjid.bare:
if bare in self.xmpp.roster[jid]:
sub = self.xmpp.roster[jid][bare]['subscription']
if sub not in ('from', 'both'):
raise XMPPError('forbidden')
td = datetime.now() - self._last_activities[jid]['seconds']
seconds = td.seconds + td.days * 24 * 3600
status = self._last_activities[jid]['status']
reply['last_activity']['seconds'] = seconds
reply['last_activity']['status'] = status
return reply
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from datetime import datetime, timedelta
from slixmpp.plugins import BasePlugin, register_plugin
from slixmpp import Iq
from slixmpp.exceptions import XMPPError
from slixmpp.xmlstream import JID, register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
from slixmpp.plugins.xep_0012 import stanza, LastActivity
log = logging.getLogger(__name__)
class XEP_0012(BasePlugin):
"""
XEP-0012 Last Activity
"""
name = 'xep_0012'
description = 'XEP-0012: Last Activity'
dependencies = set(['xep_0030'])
stanza = stanza
def plugin_init(self):
register_stanza_plugin(Iq, LastActivity)
self._last_activities = {}
self.xmpp.register_handler(
Callback('Last Activity',
StanzaPath('iq@type=get/last_activity'),
self._handle_get_last_activity))
self.api.register(self._default_get_last_activity,
'get_last_activity',
default=True)
self.api.register(self._default_set_last_activity,
'set_last_activity',
default=True)
self.api.register(self._default_del_last_activity,
'del_last_activity',
default=True)
def plugin_end(self):
self.xmpp.remove_handler('Last Activity')
self.xmpp['xep_0030'].del_feature(feature='jabber:iq:last')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('jabber:iq:last')
def begin_idle(self, jid=None, status=None):
self.set_last_activity(jid, 0, status)
def end_idle(self, jid=None):
self.del_last_activity(jid)
def start_uptime(self, status=None):
self.set_last_activity(jid, 0, status)
def set_last_activity(self, jid=None, seconds=None, status=None):
self.api['set_last_activity'](jid, args={
'seconds': seconds,
'status': status})
def del_last_activity(self, jid):
self.api['del_last_activity'](jid)
def get_last_activity(self, jid, local=False, ifrom=None, timeout=None,
callback=None, timeout_callback=None):
if jid is not None and not isinstance(jid, JID):
jid = JID(jid)
if self.xmpp.is_component:
if jid.domain == self.xmpp.boundjid.domain:
local = True
else:
if str(jid) == str(self.xmpp.boundjid):
local = True
jid = jid.full
if local or jid in (None, ''):
log.debug("Looking up local last activity data for %s", jid)
return self.api['get_last_activity'](jid, None, ifrom, None)
iq = self.xmpp.Iq()
iq['from'] = ifrom
iq['to'] = jid
iq['type'] = 'get'
iq.enable('last_activity')
return iq.send(timeout=timeout, callback=callback,
timeout_callback=timeout_callback)
def _handle_get_last_activity(self, iq):
log.debug("Received last activity query from " + \
"<%s> to <%s>.", iq['from'], iq['to'])
reply = self.api['get_last_activity'](iq['to'], None, iq['from'], iq)
reply.send()
# =================================================================
# Default in-memory implementations for storing last activity data.
# =================================================================
def _default_set_last_activity(self, jid, node, ifrom, data):
seconds = data.get('seconds', None)
if seconds is None:
seconds = 0
status = data.get('status', None)
if status is None:
status = ''
self._last_activities[jid] = {
'seconds': datetime.now() - timedelta(seconds=seconds),
'status': status}
def _default_del_last_activity(self, jid, node, ifrom, data):
if jid in self._last_activities:
del self._last_activities[jid]
def _default_get_last_activity(self, jid, node, ifrom, iq):
if not isinstance(iq, Iq):
reply = self.xmpp.Iq()
else:
iq.reply()
reply = iq
if jid not in self._last_activities:
raise XMPPError('service-unavailable')
bare = JID(jid).bare
if bare != self.xmpp.boundjid.bare:
if bare in self.xmpp.roster[jid]:
sub = self.xmpp.roster[jid][bare]['subscription']
if sub not in ('from', 'both'):
raise XMPPError('forbidden')
td = datetime.now() - self._last_activities[jid]['seconds']
seconds = td.seconds + td.days * 24 * 3600
status = self._last_activities[jid]['status']
reply['last_activity']['seconds'] = seconds
reply['last_activity']['status'] = status
return reply

View File

@ -307,7 +307,7 @@ class XEP_0045(BasePlugin):
if role not in ('moderator', 'participant', 'visitor', 'none'):
raise TypeError
query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
item = ET.Element('item', {'role':role, 'nick':nick})
item = ET.Element('item', {'role':role, 'nick':nick})
query.append(item)
iq = self.xmpp.makeIqSet(query)
iq['to'] = room

View File

@ -206,7 +206,7 @@ class XEP_0065(base_plugin):
# Though this should not be neccessary remove the closed session anyway
with self._sessions_lock:
if sid in self._sessions:
log.warn(('SOCKS5 session with sid = "%s" was not ' +
log.warn(('SOCKS5 session with sid = "%s" was not ' +
'removed from _sessions by sock.close()') % sid)
del self._sessions[sid]

View File

@ -1,46 +1,46 @@
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
from slixmpp.stanza import Error
from slixmpp.xmlstream import register_stanza_plugin
from slixmpp.plugins import BasePlugin
from slixmpp.plugins.xep_0086 import stanza, LegacyError
class XEP_0086(BasePlugin):
"""
XEP-0086: Error Condition Mappings
Older XMPP implementations used code based error messages, similar
to HTTP response codes. Since then, error condition elements have
been introduced. XEP-0086 provides a mapping between the new
condition elements and a combination of error types and the older
response codes.
Also see <http://xmpp.org/extensions/xep-0086.html>.
Configuration Values:
override -- Indicates if applying legacy error codes should
be done automatically. Defaults to True.
If False, then inserting legacy error codes can
be done using:
iq['error']['legacy']['condition'] = ...
"""
name = 'xep_0086'
description = 'XEP-0086: Error Condition Mappings'
dependencies = set()
stanza = stanza
default_config = {
'override': True
}
def plugin_init(self):
register_stanza_plugin(Error, LegacyError,
overrides=self.override)
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
from slixmpp.stanza import Error
from slixmpp.xmlstream import register_stanza_plugin
from slixmpp.plugins import BasePlugin
from slixmpp.plugins.xep_0086 import stanza, LegacyError
class XEP_0086(BasePlugin):
"""
XEP-0086: Error Condition Mappings
Older XMPP implementations used code based error messages, similar
to HTTP response codes. Since then, error condition elements have
been introduced. XEP-0086 provides a mapping between the new
condition elements and a combination of error types and the older
response codes.
Also see <http://xmpp.org/extensions/xep-0086.html>.
Configuration Values:
override -- Indicates if applying legacy error codes should
be done automatically. Defaults to True.
If False, then inserting legacy error codes can
be done using:
iq['error']['legacy']['condition'] = ...
"""
name = 'xep_0086'
description = 'XEP-0086: Error Condition Mappings'
dependencies = set()
stanza = stanza
default_config = {
'override': True
}
def plugin_init(self):
register_stanza_plugin(Error, LegacyError,
overrides=self.override)

View File

@ -129,7 +129,7 @@ class XEP_0153(BasePlugin):
# Don't process vCard avatars for MUC occupants
# since they all share the same bare JID.
return
except: pass
except: pass
if not pres.match('presence/vcard_temp_update'):
self.api['set_hash'](pres['from'], args=None)

View File

@ -1,98 +1,98 @@
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from slixmpp.stanza.iq import Iq
from slixmpp.xmlstream import register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
from slixmpp.plugins import BasePlugin
from slixmpp.plugins import xep_0082
from slixmpp.plugins.xep_0202 import stanza
log = logging.getLogger(__name__)
class XEP_0202(BasePlugin):
"""
XEP-0202: Entity Time
"""
name = 'xep_0202'
description = 'XEP-0202: Entity Time'
dependencies = set(['xep_0030', 'xep_0082'])
stanza = stanza
default_config = {
#: As a default, respond to time requests with the
#: local time returned by XEP-0082. However, a
#: custom function can be supplied which accepts
#: the JID of the entity to query for the time.
'local_time': None,
'tz_offset': 0
}
def plugin_init(self):
"""Start the XEP-0203 plugin."""
if not self.local_time:
def default_local_time(jid):
return xep_0082.datetime(offset=self.tz_offset)
self.local_time = default_local_time
self.xmpp.register_handler(
Callback('Entity Time',
StanzaPath('iq/entity_time'),
self._handle_time_request))
register_stanza_plugin(Iq, stanza.EntityTime)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:time')
self.xmpp.remove_handler('Entity Time')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('urn:xmpp:time')
def _handle_time_request(self, iq):
"""
Respond to a request for the local time.
The time is taken from self.local_time(), which may be replaced
during plugin configuration with a function that maps JIDs to
times.
Arguments:
iq -- The Iq time request stanza.
"""
iq.reply()
iq['entity_time']['time'] = self.local_time(iq['to'])
iq.send()
def get_entity_time(self, to, ifrom=None, **iqargs):
"""
Request the time from another entity.
Arguments:
to -- JID of the entity to query.
ifrom -- Specifiy the sender's JID.
block -- If true, block and wait for the stanzas' reply.
timeout -- The time in seconds to block while waiting for
a reply. If None, then wait indefinitely.
callback -- Optional callback to execute when a reply is
received instead of blocking and waiting for
the reply.
"""
iq = self.xmpp.Iq()
iq['type'] = 'get'
iq['to'] = to
iq['from'] = ifrom
iq.enable('entity_time')
return iq.send(**iqargs)
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of Slixmpp.
See the file LICENSE for copying permission.
"""
import logging
from slixmpp.stanza.iq import Iq
from slixmpp.xmlstream import register_stanza_plugin
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
from slixmpp.plugins import BasePlugin
from slixmpp.plugins import xep_0082
from slixmpp.plugins.xep_0202 import stanza
log = logging.getLogger(__name__)
class XEP_0202(BasePlugin):
"""
XEP-0202: Entity Time
"""
name = 'xep_0202'
description = 'XEP-0202: Entity Time'
dependencies = set(['xep_0030', 'xep_0082'])
stanza = stanza
default_config = {
#: As a default, respond to time requests with the
#: local time returned by XEP-0082. However, a
#: custom function can be supplied which accepts
#: the JID of the entity to query for the time.
'local_time': None,
'tz_offset': 0
}
def plugin_init(self):
"""Start the XEP-0203 plugin."""
if not self.local_time:
def default_local_time(jid):
return xep_0082.datetime(offset=self.tz_offset)
self.local_time = default_local_time
self.xmpp.register_handler(
Callback('Entity Time',
StanzaPath('iq/entity_time'),
self._handle_time_request))
register_stanza_plugin(Iq, stanza.EntityTime)
def plugin_end(self):
self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:time')
self.xmpp.remove_handler('Entity Time')
def session_bind(self, jid):
self.xmpp['xep_0030'].add_feature('urn:xmpp:time')
def _handle_time_request(self, iq):
"""
Respond to a request for the local time.
The time is taken from self.local_time(), which may be replaced
during plugin configuration with a function that maps JIDs to
times.
Arguments:
iq -- The Iq time request stanza.
"""
iq.reply()
iq['entity_time']['time'] = self.local_time(iq['to'])
iq.send()
def get_entity_time(self, to, ifrom=None, **iqargs):
"""
Request the time from another entity.
Arguments:
to -- JID of the entity to query.
ifrom -- Specifiy the sender's JID.
block -- If true, block and wait for the stanzas' reply.
timeout -- The time in seconds to block while waiting for
a reply. If None, then wait indefinitely.
callback -- Optional callback to execute when a reply is
received instead of blocking and waiting for
the reply.
"""
iq = self.xmpp.Iq()
iq['type'] = 'get'
iq['to'] = to
iq['from'] = ifrom
iq.enable('entity_time')
return iq.send(**iqargs)

View File

@ -13,9 +13,9 @@ import logging
class Device(object):
"""
Example implementation of a device readout object.
Example implementation of a device readout object.
Is registered in the XEP_0323.register_node call
The device object may be any custom implementation to support
The device object may be any custom implementation to support
specific devices, but it must implement the functions:
has_field
request_fields
@ -38,19 +38,19 @@ class Device(object):
Returns true if the supplied field name exists in this device.
Arguments:
field -- The field name
field -- The field name
"""
if field in self.fields.keys():
return True;
return False;
def refresh(self, fields):
"""
override method to do the refresh work
refresh values from hardware or other
"""
pass
def request_fields(self, fields, flags, session, callback):
"""
@ -65,7 +65,7 @@ class Device(object):
Formatted as a dictionary like { "flag name": "flag value" ... }
session -- Session id, only used in the callback as identifier
callback -- Callback function to call when data is available.
The callback function must support the following arguments:
session -- Session id, as supplied in the request_fields call
@ -73,11 +73,11 @@ class Device(object):
result -- The current result status of the readout. Valid values are:
"error" - Readout failed.
"fields" - Contains readout data.
"done" - Indicates that the readout is complete. May contain
"done" - Indicates that the readout is complete. May contain
readout data.
timestamp_block -- [optional] Only applies when result != "error"
timestamp_block -- [optional] Only applies when result != "error"
The readout data. Structured as a dictionary:
{
{
timestamp: timestamp for this datablock,
fields: list of field dictionary (one per readout field).
readout field dictionary format:
@ -89,10 +89,10 @@ class Device(object):
dataType: The datatype of the field. Only applies to type enum.
flags: [optional] data classifier flags for the field, e.g. momentary
Formatted as a dictionary like { "flag name": "flag value" ... }
}
}
}
error_msg -- [optional] Only applies when result == "error".
Error details when a request failed.
Error details when a request failed.
"""
logging.debug("request_fields called looking for fields %s",fields)
@ -125,11 +125,11 @@ class Device(object):
field_block = [];
for f in self.momentary_data:
if f in fields:
field_block.append({"name": f,
"type": self.fields[f]["type"],
field_block.append({"name": f,
"type": self.fields[f]["type"],
"unit": self.fields[f]["unit"],
"dataType": self.fields[f]["dataType"],
"value": self.momentary_data[f]["value"],
"value": self.momentary_data[f]["value"],
"flags": self.momentary_data[f]["flags"]});
ts_block["timestamp"] = timestamp;
ts_block["fields"] = field_block;
@ -142,25 +142,25 @@ class Device(object):
for ts in sorted(self.timestamp_data.keys()):
tsdt = datetime.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%S")
if not from_flag is None:
if tsdt < from_flag:
if not from_flag is None:
if tsdt < from_flag:
#print (str(tsdt) + " < " + str(from_flag))
continue
if not to_flag is None:
if tsdt > to_flag:
if not to_flag is None:
if tsdt > to_flag:
#print (str(tsdt) + " > " + str(to_flag))
continue
ts_block = {};
field_block = [];
for f in self.timestamp_data[ts]:
if f in fields:
field_block.append({"name": f,
"type": self.fields[f]["type"],
field_block.append({"name": f,
"type": self.fields[f]["type"],
"unit": self.fields[f]["unit"],
"dataType": self.fields[f]["dataType"],
"value": self.timestamp_data[ts][f]["value"],
"value": self.timestamp_data[ts][f]["value"],
"flags": self.timestamp_data[ts][f]["flags"]});
ts_block["timestamp"] = ts;
@ -171,7 +171,7 @@ class Device(object):
def _datetime_flag_parser(self, flags, flagname):
if not flagname in flags:
return None
dt = None
try:
dt = datetime.datetime.strptime(flags[flagname], "%Y-%m-%dT%H:%M:%S")
@ -242,7 +242,7 @@ class Device(object):
return False;
if flags is None:
flags = {};
flags["momentary"] = "true"
self.momentary_data[name] = {"value": value, "flags": flags};
return True;

View File

@ -29,12 +29,12 @@ log = logging.getLogger(__name__)
class XEP_0323(BasePlugin):
"""
XEP-0323: IoT Sensor Data
XEP-0323: IoT Sensor Data
This XEP provides the underlying architecture, basic operations and data
structures for sensor data communication over XMPP networks. It includes
a hardware abstraction model, removing any technical detail implemented
a hardware abstraction model, removing any technical detail implemented
in underlying technologies.
Also see <http://xmpp.org/extensions/xep-0323.html>
@ -55,10 +55,10 @@ class XEP_0323(BasePlugin):
Sensordata Event:Rejected -- Received a reject from sensor for a request
Sensordata Event:Cancelled -- Received a cancel confirm from sensor
Sensordata Event:Fields -- Received fields from sensor for a request
This may be triggered multiple times since
This may be triggered multiple times since
the sensor can split up its response in
multiple messages.
Sensordata Event:Failure -- Received a failure indication from sensor
Sensordata Event:Failure -- Received a failure indication from sensor
for a request. Typically a comm timeout.
Attributes:
@ -69,7 +69,7 @@ class XEP_0323(BasePlugin):
relevant to a request's session. This dictionary is used
both by the client and sensor side. On client side, seqnr
is used as key, while on sensor side, a session_id is used
as key. This ensures that the two will not collide, so
as key. This ensures that the two will not collide, so
one instance can be both client and sensor.
Sensor side
-----------
@ -89,12 +89,12 @@ class XEP_0323(BasePlugin):
Sensor side
-----------
register_node -- Register a sensor as available from this XMPP
register_node -- Register a sensor as available from this XMPP
instance.
Client side
-----------
request_data -- Initiates a request for data from one or more
request_data -- Initiates a request for data from one or more
sensors. Non-blocking, a callback function will
be called when data is available.
@ -102,7 +102,7 @@ class XEP_0323(BasePlugin):
name = 'xep_0323'
description = 'XEP-0323 Internet of Things - Sensor Data'
dependencies = set(['xep_0030'])
dependencies = set(['xep_0030'])
stanza = stanza
@ -198,9 +198,9 @@ class XEP_0323(BasePlugin):
def register_node(self, nodeId, device, commTimeout, sourceId=None, cacheType=None):
"""
Register a sensor/device as available for serving of data through this XMPP
instance.
instance.
The device object may by any custom implementation to support
The device object may by any custom implementation to support
specific devices, but it must implement the functions:
has_field
request_fields
@ -212,11 +212,11 @@ class XEP_0323(BasePlugin):
commTimeout -- Time in seconds to wait between each callback from device during
a data readout. Float.
sourceId -- [optional] identifying the data source controlling the device
cacheType -- [optional] narrowing down the search to a specific kind of node
cacheType -- [optional] narrowing down the search to a specific kind of node
"""
self.nodes[nodeId] = {"device": device,
self.nodes[nodeId] = {"device": device,
"commTimeout": commTimeout,
"sourceId": sourceId,
"sourceId": sourceId,
"cacheType": cacheType};
def _set_authenticated(self, auth=''):
@ -228,9 +228,9 @@ class XEP_0323(BasePlugin):
"""
Event handler for reception of an Iq with req - this is a request.
Verifies that
Verifies that
- all the requested nodes are available
- at least one of the requested fields is available from at least
- at least one of the requested fields is available from at least
one of the nodes
If the request passes verification, an accept response is sent, and
@ -331,12 +331,12 @@ class XEP_0323(BasePlugin):
iq['type'] = 'error';
iq['rejected']['seqnr'] = seqnr;
iq['rejected']['error'] = error_msg;
iq.send(block=False);
iq.send(block=False);
def _threaded_node_request(self, session, process_fields, flags):
"""
"""
Helper function to handle the device readouts in a separate thread.
Arguments:
session -- The request session id
process_fields -- The fields to request from the devices
@ -344,7 +344,7 @@ class XEP_0323(BasePlugin):
Formatted as a dictionary like { "flag name": "flag value" ... }
"""
for node in self.sessions[session]["node_list"]:
self.sessions[session]["nodeDone"][node] = False;
self.sessions[session]["nodeDone"][node] = False;
for node in self.sessions[session]["node_list"]:
timer = TimerReset(self.nodes[node]['commTimeout'], self._event_comm_timeout, args=(session, node));
@ -354,11 +354,11 @@ class XEP_0323(BasePlugin):
self.nodes[node]['device'].request_fields(process_fields, flags=flags, session=session, callback=self._device_field_request_callback);
def _event_comm_timeout(self, session, nodeId):
"""
"""
Triggered if any of the readout operations timeout.
Sends a failure message back to the client, stops communicating
with the failing device.
Arguments:
session -- The request session id
nodeId -- The id of the device which timed out
@ -366,7 +366,7 @@ class XEP_0323(BasePlugin):
msg = self.xmpp.Message();
msg['from'] = self.sessions[session]['to'];
msg['to'] = self.sessions[session]['from'];
msg['failure']['seqnr'] = self.sessions[session]['seqnr'];
msg['failure']['seqnr'] = self.sessions[session]['seqnr'];
msg['failure']['error']['text'] = "Timeout";
msg['failure']['error']['nodeId'] = nodeId;
msg['failure']['error']['timestamp'] = datetime.datetime.now().replace(microsecond=0).isoformat();
@ -403,9 +403,9 @@ class XEP_0323(BasePlugin):
self._threaded_node_request(session, process_fields, req_flags);
def _all_nodes_done(self, session):
"""
"""
Checks wheter all devices are done replying to the readout.
Arguments:
session -- The request session id
"""
@ -415,22 +415,22 @@ class XEP_0323(BasePlugin):
return True;
def _device_field_request_callback(self, session, nodeId, result, timestamp_block, error_msg=None):
"""
"""
Callback function called by the devices when they have any additional data.
Composes a message with the data and sends it back to the client, and resets
Composes a message with the data and sends it back to the client, and resets
the timeout timer for the device.
Arguments:
session -- The request session id
nodeId -- The device id which initiated the callback
result -- The current result status of the readout. Valid values are:
"error" - Readout failed.
"fields" - Contains readout data.
"done" - Indicates that the readout is complete. May contain
"done" - Indicates that the readout is complete. May contain
readout data.
timestamp_block -- [optional] Only applies when result != "error"
timestamp_block -- [optional] Only applies when result != "error"
The readout data. Structured as a dictionary:
{
{
timestamp: timestamp for this datablock,
fields: list of field dictionary (one per readout field).
readout field dictionary format:
@ -442,7 +442,7 @@ class XEP_0323(BasePlugin):
dataType: The datatype of the field. Only applies to type enum.
flags: [optional] data classifier flags for the field, e.g. momentary
Formatted as a dictionary like { "flag name": "flag value" ... }
}
}
}
error_msg -- [optional] Only applies when result == "error".
Error details when a request failed.
@ -463,7 +463,7 @@ class XEP_0323(BasePlugin):
msg['failure']['error']['timestamp'] = datetime.datetime.now().replace(microsecond=0).isoformat();
# Drop communication with this device and check if we are done
self.sessions[session]["nodeDone"][nodeId] = True;
self.sessions[session]["nodeDone"][nodeId] = True;
if (self._all_nodes_done(session)):
msg['failure']['done'] = 'true';
# The session is complete, delete it
@ -481,11 +481,11 @@ class XEP_0323(BasePlugin):
ts = node.add_timestamp(timestamp_block["timestamp"]);
for f in timestamp_block["fields"]:
data = ts.add_data( typename=f['type'],
name=f['name'],
value=f['value'],
unit=f['unit'],
dataType=f['dataType'],
data = ts.add_data( typename=f['type'],
name=f['name'],
value=f['value'],
unit=f['unit'],
dataType=f['dataType'],
flags=f['flags']);
if result == "done":
@ -503,7 +503,7 @@ class XEP_0323(BasePlugin):
msg.send();
def _handle_event_cancel(self, iq):
""" Received Iq with cancel - this is a cancel request.
""" Received Iq with cancel - this is a cancel request.
Delete the session and confirm. """
seqnr = iq['cancel']['seqnr'];
@ -518,8 +518,8 @@ class XEP_0323(BasePlugin):
iq.reply();
iq['type'] = 'result';
iq['cancelled']['seqnr'] = seqnr;
iq.send(block=False);
iq.send(block=False);
# Delete session
del self.sessions[s]
return
@ -529,22 +529,22 @@ class XEP_0323(BasePlugin):
iq['type'] = 'error';
iq['rejected']['seqnr'] = seqnr;
iq['rejected']['error'] = "Cancel request received, no matching request is active.";
iq.send(block=False);
iq.send(block=False);
# =================================================================
# Client side (data retriever) API
def request_data(self, from_jid, to_jid, callback, nodeIds=None, fields=None, flags=None):
"""
"""
Called on the client side to initiade a data readout.
Composes a message with the request and sends it to the device(s).
Does not block, the callback will be called when data is available.
Arguments:
from_jid -- The jid of the requester
to_jid -- The jid of the device(s)
callback -- The callback function to call when data is availble.
callback -- The callback function to call when data is availble.
The callback function must support the following arguments:
from_jid -- The jid of the responding device(s)
@ -565,7 +565,7 @@ class XEP_0323(BasePlugin):
The timestamp of data in this callback. One callback will only
contain data from one timestamp.
fields -- [optional] Mandatory when result == "fields".
List of field dictionaries representing the readout data.
List of field dictionaries representing the readout data.
Dictionary format:
{
typename: The field type (numeric, boolean, dateTime, timeSpan, string, enum)
@ -575,11 +575,11 @@ class XEP_0323(BasePlugin):
dataType: The datatype of the field. Only applies to type enum.
flags: [optional] data classifier flags for the field, e.g. momentary.
Formatted as a dictionary like { "flag name": "flag value" ... }
}
}
error_msg -- [optional] Mandatory when result == "rejected" or "failure".
Details about why the request is rejected or failed.
"rejected" means that the request is stopped, but note that the
Details about why the request is rejected or failed.
"rejected" means that the request is stopped, but note that the
request will continue even after a "failure". "failure" only means
that communication was stopped to that specific device, other
device(s) (if any) will continue their readout.
@ -610,17 +610,17 @@ class XEP_0323(BasePlugin):
iq['req']._set_flags(flags);
self.sessions[seqnr] = {"from": iq['from'], "to": iq['to'], "seqnr": seqnr, "callback": callback};
iq.send(block=False);
iq.send(block=False);
return seqnr;
def cancel_request(self, session):
"""
"""
Called on the client side to cancel a request for data readout.
Composes a message with the cancellation and sends it to the device(s).
Does not block, the callback will be called when cancellation is
Does not block, the callback will be called when cancellation is
confirmed.
Arguments:
session -- The session id of the request to cancel
"""
@ -651,7 +651,7 @@ class XEP_0323(BasePlugin):
callback(from_jid=iq['from'], result=result);
def _handle_event_rejected(self, iq):
""" Received Iq with rejected - this is a reject.
""" Received Iq with rejected - this is a reject.
Delete the session. """
seqnr = iq['rejected']['seqnr'];
callback = self.sessions[seqnr]["callback"];
@ -660,9 +660,9 @@ class XEP_0323(BasePlugin):
del self.sessions[seqnr];
def _handle_event_cancelled(self, iq):
"""
Received Iq with cancelled - this is a cancel confirm.
Delete the session.
"""
Received Iq with cancelled - this is a cancel confirm.
Delete the session.
"""
#print("Got cancelled")
seqnr = iq['cancelled']['seqnr'];
@ -672,7 +672,7 @@ class XEP_0323(BasePlugin):
del self.sessions[seqnr];
def _handle_event_fields(self, msg):
"""
"""
Received Msg with fields - this is a data reponse to a request.
If this is the last data block, issue a "done" callback.
"""
@ -694,16 +694,16 @@ class XEP_0323(BasePlugin):
fields.append(field_block);
callback(from_jid=msg['from'], result="fields", nodeId=node['nodeId'], timestamp=ts['value'], fields=fields);
if msg['fields']['done'] == "true":
callback(from_jid=msg['from'], result="done");
# Session done
del self.sessions[seqnr];
def _handle_event_failure(self, msg):
"""
"""
Received Msg with failure - our request failed
Delete the session.
Delete the session.
"""
seqnr = msg['failure']['seqnr'];
callback = self.sessions[seqnr]["callback"];
@ -713,11 +713,11 @@ class XEP_0323(BasePlugin):
del self.sessions[seqnr];
def _handle_event_started(self, msg):
"""
Received Msg with started - our request was queued and is now started.
"""
Received Msg with started - our request was queued and is now started.
"""
seqnr = msg['started']['seqnr'];
callback = self.sessions[seqnr]["callback"];
callback(from_jid=msg['from'], result="started");

View File

@ -20,14 +20,14 @@ class Sensordata(ElementBase):
interfaces = set(tuple())
class FieldTypes():
"""
"""
All field types are optional booleans that default to False
"""
field_types = set([ 'momentary','peak','status','computed','identity','historicalSecond','historicalMinute','historicalHour', \
'historicalDay','historicalWeek','historicalMonth','historicalQuarter','historicalYear','historicalOther'])
class FieldStatus():
"""
"""
All field statuses are optional booleans that default to False
"""
field_status = set([ 'missing','automaticEstimate','manualEstimate','manualReadout','automaticReadout','timeOffset','warning','error', \
@ -41,7 +41,7 @@ class Request(ElementBase):
interfaces.update(FieldTypes.field_types);
_flags = set(['serviceToken','deviceToken','userToken','from','to','when','historical','all']);
_flags.update(FieldTypes.field_types);
def __init__(self, xml=None, parent=None):
ElementBase.__init__(self, xml, parent);
self._nodes = set()
@ -64,8 +64,8 @@ class Request(ElementBase):
def _get_flags(self):
"""
Helper function for getting of flags. Returns all flags in
dictionary format: { "flag name": "flag value" ... }
Helper function for getting of flags. Returns all flags in
dictionary format: { "flag name": "flag value" ... }
"""
flags = {};
for f in self._flags:
@ -75,10 +75,10 @@ class Request(ElementBase):
def _set_flags(self, flags):
"""
Helper function for setting of flags.
Helper function for setting of flags.
Arguments:
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
"""
for f in self._flags:
if flags is not None and f in flags:
@ -94,7 +94,7 @@ class Request(ElementBase):
Arguments:
nodeId -- The ID for the node.
sourceId -- [optional] identifying the data source controlling the device
cacheType -- [optional] narrowing down the search to a specific kind of node
cacheType -- [optional] narrowing down the search to a specific kind of node
"""
if nodeId not in self._nodes:
self._nodes.add((nodeId))
@ -318,7 +318,7 @@ class Fields(ElementBase):
Arguments:
nodeId -- The ID for the node.
sourceId -- [optional] identifying the data source controlling the device
cacheType -- [optional] narrowing down the search to a specific kind of node
cacheType -- [optional] narrowing down the search to a specific kind of node
"""
if nodeId not in self._nodes:
self._nodes.add((nodeId))
@ -411,7 +411,7 @@ class FieldsNode(ElementBase):
def add_timestamp(self, timestamp, substanzas=None):
"""
Add a new timestamp element.
Add a new timestamp element.
Arguments:
timestamp -- The timestamp in ISO format.
@ -485,7 +485,7 @@ class FieldsNode(ElementBase):
self.iterables.remove(timestamp)
class Field(ElementBase):
"""
"""
Field element in response Timestamp. This is a base class,
all instances of fields added to Timestamp must be of types:
DataNumeric
@ -494,7 +494,7 @@ class Field(ElementBase):
DataDateTime
DataTimeSpan
DataEnum
"""
"""
namespace = 'urn:xmpp:iot:sensordata'
name = 'field'
plugin_attrib = name
@ -523,8 +523,8 @@ class Field(ElementBase):
def _get_flags(self):
"""
Helper function for getting of flags. Returns all flags in
dictionary format: { "flag name": "flag value" ... }
Helper function for getting of flags. Returns all flags in
dictionary format: { "flag name": "flag value" ... }
"""
flags = {};
for f in self._flags:
@ -534,10 +534,10 @@ class Field(ElementBase):
def _set_flags(self, flags):
"""
Helper function for setting of flags.
Helper function for setting of flags.
Arguments:
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
"""
for f in self._flags:
if flags is not None and f in flags:
@ -576,7 +576,7 @@ class Timestamp(ElementBase):
def add_data(self, typename, name, value, module=None, stringIds=None, unit=None, dataType=None, flags=None):
"""
Add a new data element.
Add a new data element.
Arguments:
typename -- The type of data element (numeric, string, boolean, dateTime, timeSpan or enum)
@ -661,9 +661,9 @@ class Timestamp(ElementBase):
self.iterables.remove(data)
class DataNumeric(Field):
"""
Field data of type numeric.
Note that the value is expressed as a string.
"""
Field data of type numeric.
Note that the value is expressed as a string.
"""
namespace = 'urn:xmpp:iot:sensordata'
name = 'numeric'
@ -672,11 +672,11 @@ class DataNumeric(Field):
interfaces.update(Field.interfaces);
def _get_typename(self):
return "numeric"
return "numeric"
class DataString(Field):
"""
Field data of type string
"""
Field data of type string
"""
namespace = 'urn:xmpp:iot:sensordata'
name = 'string'
@ -685,12 +685,12 @@ class DataString(Field):
interfaces.update(Field.interfaces);
def _get_typename(self):
return "string"
return "string"
class DataBoolean(Field):
"""
"""
Field data of type boolean.
Note that the value is expressed as a string.
Note that the value is expressed as a string.
"""
namespace = 'urn:xmpp:iot:sensordata'
name = 'boolean'
@ -699,12 +699,12 @@ class DataBoolean(Field):
interfaces.update(Field.interfaces);
def _get_typename(self):
return "boolean"
return "boolean"
class DataDateTime(Field):
"""
"""
Field data of type dateTime.
Note that the value is expressed as a string.
Note that the value is expressed as a string.
"""
namespace = 'urn:xmpp:iot:sensordata'
name = 'dateTime'
@ -713,12 +713,12 @@ class DataDateTime(Field):
interfaces.update(Field.interfaces);
def _get_typename(self):
return "dateTime"
return "dateTime"
class DataTimeSpan(Field):
"""
"""
Field data of type timeSpan.
Note that the value is expressed as a string.
Note that the value is expressed as a string.
"""
namespace = 'urn:xmpp:iot:sensordata'
name = 'timeSpan'
@ -727,12 +727,12 @@ class DataTimeSpan(Field):
interfaces.update(Field.interfaces);
def _get_typename(self):
return "timeSpan"
return "timeSpan"
class DataEnum(Field):
"""
"""
Field data of type enum.
Note that the value is expressed as a string.
Note that the value is expressed as a string.
"""
namespace = 'urn:xmpp:iot:sensordata'
name = 'enum'
@ -741,7 +741,7 @@ class DataEnum(Field):
interfaces.update(Field.interfaces);
def _get_typename(self):
return "enum"
return "enum"
class Done(ElementBase):
""" Done element used to signal that all data has been transferred """

View File

@ -26,16 +26,16 @@ log = logging.getLogger(__name__)
class XEP_0325(BasePlugin):
"""
XEP-0325: IoT Control
XEP-0325: IoT Control
Actuators are devices in sensor networks that can be controlled through
the network and act with the outside world. In sensor networks and
Internet of Things applications, actuators make it possible to automate
real-world processes.
This plugin implements a mechanism whereby actuators can be controlled
in XMPP-based sensor networks, making it possible to integrate sensors
and actuators of different brands, makes and models into larger
Actuators are devices in sensor networks that can be controlled through
the network and act with the outside world. In sensor networks and
Internet of Things applications, actuators make it possible to automate
real-world processes.
This plugin implements a mechanism whereby actuators can be controlled
in XMPP-based sensor networks, making it possible to integrate sensors
and actuators of different brands, makes and models into larger
Internet of Things applications.
Also see <http://xmpp.org/extensions/xep-0325.html>
@ -52,9 +52,9 @@ class XEP_0325(BasePlugin):
Client side
-----------
Control Event:SetResponse -- Received a response to a
Control Event:SetResponse -- Received a response to a
control request, type result
Control Event:SetResponseError -- Received a response to a
Control Event:SetResponseError -- Received a response to a
control request, type error
Attributes:
@ -65,7 +65,7 @@ class XEP_0325(BasePlugin):
relevant to a request's session. This dictionary is used
both by the client and sensor side. On client side, seqnr
is used as key, while on sensor side, a session_id is used
as key. This ensures that the two will not collide, so
as key. This ensures that the two will not collide, so
one instance can be both client and sensor.
Sensor side
-----------
@ -85,15 +85,15 @@ class XEP_0325(BasePlugin):
Sensor side
-----------
register_node -- Register a sensor as available from this XMPP
register_node -- Register a sensor as available from this XMPP
instance.
Client side
-----------
set_request -- Initiates a control request to modify data in
set_request -- Initiates a control request to modify data in
sensor(s). Non-blocking, a callback function will
be called when the sensor has responded.
set_command -- Initiates a control command to modify data in
set_command -- Initiates a control command to modify data in
sensor(s). Non-blocking. The sensor(s) will not
respond regardless of the result of the command,
so no callback is made.
@ -102,7 +102,7 @@ class XEP_0325(BasePlugin):
name = 'xep_0325'
description = 'XEP-0325 Internet of Things - Control'
dependencies = set(['xep_0030'])
dependencies = set(['xep_0030'])
stanza = stanza
@ -170,10 +170,10 @@ class XEP_0325(BasePlugin):
def register_node(self, nodeId, device, commTimeout, sourceId=None, cacheType=None):
"""
Register a sensor/device as available for control requests/commands
through this XMPP instance.
Register a sensor/device as available for control requests/commands
through this XMPP instance.
The device object may by any custom implementation to support
The device object may by any custom implementation to support
specific devices, but it must implement the functions:
has_control_field
set_control_fields
@ -185,11 +185,11 @@ class XEP_0325(BasePlugin):
commTimeout -- Time in seconds to wait between each callback from device during
a data readout. Float.
sourceId -- [optional] identifying the data source controlling the device
cacheType -- [optional] narrowing down the search to a specific kind of node
cacheType -- [optional] narrowing down the search to a specific kind of node
"""
self.nodes[nodeId] = {"device": device,
self.nodes[nodeId] = {"device": device,
"commTimeout": commTimeout,
"sourceId": sourceId,
"sourceId": sourceId,
"cacheType": cacheType};
def _set_authenticated(self, auth=''):
@ -205,10 +205,10 @@ class XEP_0325(BasePlugin):
def _handle_set_req(self, iq):
"""
Event handler for reception of an Iq with set req - this is a
Event handler for reception of an Iq with set req - this is a
control request.
Verifies that
Verifies that
- all the requested nodes are available
(if no nodes are specified in the request, assume all nodes)
- all the control fields are available from all requested nodes
@ -216,7 +216,7 @@ class XEP_0325(BasePlugin):
If the request passes verification, the control request is passed
to the devices (in a separate thread).
If the verification fails, a setResponse with error indication
If the verification fails, a setResponse with error indication
is sent.
"""
@ -279,17 +279,17 @@ class XEP_0325(BasePlugin):
if missing_node is not None:
iq['setResponse'].add_node(missing_node);
if missing_field is not None:
iq['setResponse'].add_data(missing_field);
iq['setResponse'].add_data(missing_field);
iq['setResponse']['error']['var'] = "Output";
iq['setResponse']['error']['text'] = error_msg;
iq.send(block=False);
iq.send(block=False);
def _handle_direct_set(self, msg):
"""
Event handler for reception of a Message with set command - this is a
Event handler for reception of a Message with set command - this is a
direct control command.
Verifies that
Verifies that
- all the requested nodes are available
(if no nodes are specified in the request, assume all nodes)
- all the control fields are available from all requested nodes
@ -342,9 +342,9 @@ class XEP_0325(BasePlugin):
def _threaded_node_request(self, session, process_fields):
"""
"""
Helper function to handle the device control in a separate thread.
Arguments:
session -- The request session id
process_fields -- The fields to set in the devices. List of tuple format:
@ -360,12 +360,12 @@ class XEP_0325(BasePlugin):
self.nodes[node]['device'].set_control_fields(process_fields, session=session, callback=self._device_set_command_callback);
def _event_comm_timeout(self, session, nodeId):
"""
"""
Triggered if any of the control operations timeout.
Stop communicating with the failing device.
If the control command was an Iq request, sends a failure
message back to the client.
If the control command was an Iq request, sends a failure
message back to the client.
Arguments:
session -- The request session id
nodeId -- The id of the device which timed out
@ -380,7 +380,7 @@ class XEP_0325(BasePlugin):
iq['id'] = self.sessions[session]['seqnr'];
iq['setResponse']['responseCode'] = "OtherError";
iq['setResponse'].add_node(nodeId);
iq['setResponse']['error']['var'] = "Output";
iq['setResponse']['error']['var'] = "Output";
iq['setResponse']['error']['text'] = "Timeout.";
iq.send(block=False);
@ -393,9 +393,9 @@ class XEP_0325(BasePlugin):
del self.sessions[session];
def _all_nodes_done(self, session):
"""
"""
Checks wheter all devices are done replying to the control command.
Arguments:
session -- The request session id
"""
@ -405,19 +405,19 @@ class XEP_0325(BasePlugin):
return True;
def _device_set_command_callback(self, session, nodeId, result, error_field=None, error_msg=None):
"""
Callback function called by the devices when the control command is
"""
Callback function called by the devices when the control command is
complete or failed.
If needed, composes a message with the result and sends it back to the
If needed, composes a message with the result and sends it back to the
client.
Arguments:
session -- The request session id
nodeId -- The device id which initiated the callback
result -- The current result status of the control command. Valid values are:
"error" - Set fields failed.
"ok" - All fields were set.
error_field -- [optional] Only applies when result == "error"
error_field -- [optional] Only applies when result == "error"
The field name that failed (usually means it is missing)
error_msg -- [optional] Only applies when result == "error".
Error details when a request failed.
@ -441,12 +441,12 @@ class XEP_0325(BasePlugin):
iq['setResponse'].add_node(nodeId);
if error_field is not None:
iq['setResponse'].add_data(error_field);
iq['setResponse']['error']['var'] = error_field;
iq['setResponse']['error']['var'] = error_field;
iq['setResponse']['error']['text'] = error_msg;
iq.send(block=False);
# Drop communication with this device and check if we are done
self.sessions[session]["nodeDone"][nodeId] = True;
self.sessions[session]["nodeDone"][nodeId] = True;
if (self._all_nodes_done(session)):
# The session is complete, delete it
del self.sessions[session];
@ -473,17 +473,17 @@ class XEP_0325(BasePlugin):
# Client side (data controller) API
def set_request(self, from_jid, to_jid, callback, fields, nodeIds=None):
"""
"""
Called on the client side to initiade a control request.
Composes a message with the request and sends it to the device(s).
Does not block, the callback will be called when the device(s)
Does not block, the callback will be called when the device(s)
has responded.
Arguments:
from_jid -- The jid of the requester
to_jid -- The jid of the device(s)
callback -- The callback function to call when data is availble.
callback -- The callback function to call when data is availble.
The callback function must support the following arguments:
from_jid -- The jid of the responding device(s)
@ -494,20 +494,20 @@ class XEP_0325(BasePlugin):
"Locked" - Field(s) is locked and cannot
be changed at the moment.
"NotImplemented" - Request feature not implemented.
"FormError" - Error while setting with
"FormError" - Error while setting with
a form (not implemented).
"OtherError" - Indicates other types of
errors, such as timeout.
"OtherError" - Indicates other types of
errors, such as timeout.
Details in the error_msg.
nodeId -- [optional] Only applicable when result == "error"
List of node Ids of failing device(s).
fields -- [optional] Only applicable when result == "error"
nodeId -- [optional] Only applicable when result == "error"
List of node Ids of failing device(s).
fields -- [optional] Only applicable when result == "error"
List of fields that failed.[optional] Mandatory when result == "rejected" or "failure".
error_msg -- Details about why the request failed.
error_msg -- Details about why the request failed.
fields -- Fields to set. List of tuple format: (name, typename, value).
nodeIds -- [optional] Limits the request to the node Ids in this list.
@ -526,14 +526,14 @@ class XEP_0325(BasePlugin):
iq['set'].add_data(name=name, typename=typename, value=value);
self.sessions[seqnr] = {"from": iq['from'], "to": iq['to'], "callback": callback};
iq.send(block=False);
iq.send(block=False);
def set_command(self, from_jid, to_jid, fields, nodeIds=None):
"""
"""
Called on the client side to initiade a control command.
Composes a message with the set commandand sends it to the device(s).
Does not block. Device(s) will not respond, regardless of result.
Arguments:
from_jid -- The jid of the requester
to_jid -- The jid of the device(s)
@ -553,7 +553,7 @@ class XEP_0325(BasePlugin):
msg['set'].add_data(name, typename, value);
# We won't get any reply, so don't create a session
msg.send();
msg.send();
def _handle_set_response(self, iq):
""" Received response from device(s) """
@ -571,4 +571,4 @@ class XEP_0325(BasePlugin):
callback = self.sessions[seqnr]["callback"];
callback(from_jid=from_jid, result=result, nodeIds=nodeIds, fields=fields, error_msg=error_msg);

View File

@ -13,8 +13,8 @@ import datetime
class Device(object):
"""
Example implementation of a device control object.
The device object may by any custom implementation to support
The device object may by any custom implementation to support
specific devices, but it must implement the functions:
has_control_field
set_control_fields
@ -30,7 +30,7 @@ class Device(object):
and the type matches for control in this device.
Arguments:
field -- The field name
field -- The field name
typename -- The expected type
"""
if field in self.control_fields and self.control_fields[field]["type"] == typename:
@ -43,22 +43,22 @@ class Device(object):
sets the data and (if needed) and calls the callback.
Arguments:
fields -- List of control fields in tuple format:
fields -- List of control fields in tuple format:
(name, typename, value)
session -- Session id, only used in the callback as identifier
callback -- Callback function to call when control set is complete.
The callback function must support the following arguments:
session -- Session id, as supplied in the
session -- Session id, as supplied in the
request_fields call
nodeId -- Identifier for this device
result -- The current result status of the readout.
result -- The current result status of the readout.
Valid values are:
"error" - Set fields failed.
"ok" - All fields were set.
error_field -- [optional] Only applies when result == "error"
The field name that failed
error_field -- [optional] Only applies when result == "error"
The field name that failed
(usually means it is missing)
error_msg -- [optional] Only applies when result == "error".
Error details when a request failed.
@ -82,9 +82,9 @@ class Device(object):
Sends a reject to the caller
Arguments:
session -- Session id, see definition in
session -- Session id, see definition in
set_control_fields function
callback -- Callback function, see definition in
callback -- Callback function, see definition in
set_control_fields function
"""
callback(session, result="error", nodeId=self.nodeId, error_field=field, error_msg=message);
@ -95,8 +95,8 @@ class Device(object):
Arguments:
name -- Name of the field
typename -- Type of the field, one of:
(boolean, color, string, date, dateTime,
typename -- Type of the field, one of:
(boolean, color, string, date, dateTime,
double, duration, int, long, time)
value -- Field value
"""

View File

@ -53,7 +53,7 @@ class ControlSet(ElementBase):
Arguments:
nodeId -- The ID for the node.
sourceId -- [optional] identifying the data source controlling the device
cacheType -- [optional] narrowing down the search to a specific kind of node
cacheType -- [optional] narrowing down the search to a specific kind of node
"""
if nodeId not in self._nodes:
self._nodes.add((nodeId))
@ -117,12 +117,12 @@ class ControlSet(ElementBase):
def add_data(self, name, typename, value):
"""
Add a new data element.
Add a new data element.
Arguments:
name -- The name of the data element
typename -- The type of data element
(boolean, color, string, date, dateTime,
typename -- The type of data element
(boolean, color, string, date, dateTime,
double, duration, int, long, time)
value -- The value of the data element
"""
@ -244,7 +244,7 @@ class ControlSetResponse(ElementBase):
Arguments:
nodeId -- The ID for the node.
sourceId -- [optional] identifying the data source controlling the device
cacheType -- [optional] narrowing down the search to a specific kind of node
cacheType -- [optional] narrowing down the search to a specific kind of node
"""
if nodeId not in self._nodes:
self._nodes.add(nodeId)
@ -308,7 +308,7 @@ class ControlSetResponse(ElementBase):
def add_data(self, name):
"""
Add a new ResponseParameter element.
Add a new ResponseParameter element.
Arguments:
name -- Name of the parameter
@ -389,12 +389,12 @@ class Error(ElementBase):
def del_text(self):
"""Remove the contents inside the XML tag."""
self.xml.text = ""
return self
return self
class ResponseParameter(ElementBase):
"""
Parameter element in ControlSetResponse.
"""
"""
Parameter element in ControlSetResponse.
"""
namespace = 'urn:xmpp:iot:control'
name = 'parameter'
plugin_attrib = name
@ -402,7 +402,7 @@ class ResponseParameter(ElementBase):
class BaseParameter(ElementBase):
"""
"""
Parameter element in SetCommand. This is a base class,
all instances of parameters added to SetCommand must be of types:
BooleanParameter
@ -415,7 +415,7 @@ class BaseParameter(ElementBase):
IntParameter
LongParameter
TimeParameter
"""
"""
namespace = 'urn:xmpp:iot:control'
name = 'baseParameter'
plugin_attrib = name
@ -425,80 +425,80 @@ class BaseParameter(ElementBase):
return self.name;
class BooleanParameter(BaseParameter):
"""
Field data of type boolean.
Note that the value is expressed as a string.
"""
Field data of type boolean.
Note that the value is expressed as a string.
"""
name = 'boolean'
plugin_attrib = name
class ColorParameter(BaseParameter):
"""
Field data of type color.
Note that the value is expressed as a string.
"""
Field data of type color.
Note that the value is expressed as a string.
"""
name = 'color'
plugin_attrib = name
class StringParameter(BaseParameter):
"""
Field data of type string.
"""
Field data of type string.
"""
name = 'string'
plugin_attrib = name
class DateParameter(BaseParameter):
"""
Field data of type date.
Note that the value is expressed as a string.
"""
Field data of type date.
Note that the value is expressed as a string.
"""
name = 'date'
plugin_attrib = name
class DateTimeParameter(BaseParameter):
"""
Field data of type dateTime.
Note that the value is expressed as a string.
"""
Field data of type dateTime.
Note that the value is expressed as a string.
"""
name = 'dateTime'
plugin_attrib = name
class DoubleParameter(BaseParameter):
"""
Field data of type double.
Note that the value is expressed as a string.
"""
Field data of type double.
Note that the value is expressed as a string.
"""
name = 'double'
plugin_attrib = name
class DurationParameter(BaseParameter):
"""
Field data of type duration.
Note that the value is expressed as a string.
"""
Field data of type duration.
Note that the value is expressed as a string.
"""
name = 'duration'
plugin_attrib = name
class IntParameter(BaseParameter):
"""
Field data of type int.
Note that the value is expressed as a string.
"""
Field data of type int.
Note that the value is expressed as a string.
"""
name = 'int'
plugin_attrib = name
class LongParameter(BaseParameter):
"""
Field data of type long (64-bit int).
Note that the value is expressed as a string.
"""
Field data of type long (64-bit int).
Note that the value is expressed as a string.
"""
name = 'long'
plugin_attrib = name
class TimeParameter(BaseParameter):
"""
Field data of type time.
Note that the value is expressed as a string.
"""
Field data of type time.
Note that the value is expressed as a string.
"""
name = 'time'
plugin_attrib = name

View File

@ -133,7 +133,7 @@ def resolve(host, port=None, service=None, proto='tcp',
if not service:
hosts = [(host, port)]
else:
hosts = get_SRV(host, port, service, proto,
hosts = get_SRV(host, port, service, proto,
resolver=resolver,
use_dnspython=use_dnspython)
@ -144,7 +144,7 @@ def resolve(host, port=None, service=None, proto='tcp',
results.append((host, '::1', port))
results.append((host, '127.0.0.1', port))
if use_ipv6:
for address in get_AAAA(host, resolver=resolver,
for address in get_AAAA(host, resolver=resolver,
use_dnspython=use_dnspython):
results.append((host, address, port))
for address in get_A(host, resolver=resolver,

View File

@ -77,7 +77,7 @@ class TestPlugins(unittest.TestCase):
p.disable('a')
self.assertEqual(len(p), 0, "Wrong number of enabled plugins.")
self.assertEqual(events, ['init', 'end'],
self.assertEqual(events, ['init', 'end'],
"Plugin lifecycle methods not called.")
def test_enable_dependencies(self):

View File

@ -6,7 +6,7 @@ import slixmpp.plugins.xep_0323 as xep_0323
namespace='sn'
class TestSensorDataStanzas(SlixTest):
def setUp(self):
pass
@ -171,7 +171,7 @@ class TestSensorDataStanzas(SlixTest):
iq['accepted']['seqnr'] = '2'
self.check(iq,"""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='2'>
@ -193,7 +193,7 @@ class TestSensorDataStanzas(SlixTest):
iq['rejected']['error'] = 'Access denied.'
self.check(iq,"""
<iq type='error'
<iq type='error'
from='device@clayster.com'
to='master@clayster.com/amr'
id='4'>
@ -250,7 +250,7 @@ class TestSensorDataStanzas(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
<node nodeId='Device02'>
<timestamp value='2013-03-07T16:24:30'>
<numeric name='Temperature' momentary='true' automaticReadout='true' value='-12.42' unit='K'/>
<numeric name='Temperature' momentary='true' automaticReadout='true' value='-12.42' unit='K'/>
</timestamp>
</node>
</fields>
@ -269,7 +269,7 @@ class TestSensorDataStanzas(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
<node nodeId='Device02'>
<timestamp value='2013-03-07T16:24:30'>
<numeric name='Temperature' momentary='true' automaticReadout='true' value='-12.42' unit='K'/>
<numeric name='Temperature' momentary='true' automaticReadout='true' value='-12.42' unit='K'/>
</timestamp>
</node>
<node nodeId='EmptyDevice'/>
@ -314,7 +314,7 @@ class TestSensorDataStanzas(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
<node nodeId='Device02'>
<timestamp value='2013-03-07T16:24:30'>
<numeric name='Temperature' momentary='true' automaticReadout='true' value='-12.42' unit='K'/>
<numeric name='Temperature' momentary='true' automaticReadout='true' value='-12.42' unit='K'/>
</timestamp>
</node>
<node nodeId='EmptyDevice'/>
@ -323,18 +323,18 @@ class TestSensorDataStanzas(SlixTest):
</node>
<node nodeId='Device77'>
<timestamp value='2013-05-03T12:00:01'>
<numeric name='Temperature' historicalDay='true' value='-12.42' unit='K'/>
<numeric name='Speed' historicalWeek='false' value='312.42' unit='km/h'/>
<string name='Temperature name' historicalMonth='true' value='Bottom oil'/>
<string name='Speed name' historicalQuarter='false' value='Top speed'/>
<dateTime name='T1' historicalYear='true' value='1979-01-01T00:00:00'/>
<dateTime name='T2' historicalOther='false' value='2000-01-01T01:02:03'/>
<timeSpan name='TS1' missing='true' value='P5Y'/>
<timeSpan name='TS2' manualEstimate='false' value='PT2M1S'/>
<enum name='top color' invoiced='true' value='red' dataType='string'/>
<enum name='bottom color' powerFailure='false' value='black' dataType='string'/>
<boolean name='Temperature real' historicalDay='true' value='false'/>
<boolean name='Speed real' historicalWeek='false' value='true'/>
<numeric name='Temperature' historicalDay='true' value='-12.42' unit='K'/>
<numeric name='Speed' historicalWeek='false' value='312.42' unit='km/h'/>
<string name='Temperature name' historicalMonth='true' value='Bottom oil'/>
<string name='Speed name' historicalQuarter='false' value='Top speed'/>
<dateTime name='T1' historicalYear='true' value='1979-01-01T00:00:00'/>
<dateTime name='T2' historicalOther='false' value='2000-01-01T01:02:03'/>
<timeSpan name='TS1' missing='true' value='P5Y'/>
<timeSpan name='TS2' manualEstimate='false' value='PT2M1S'/>
<enum name='top color' invoiced='true' value='red' dataType='string'/>
<enum name='bottom color' powerFailure='false' value='black' dataType='string'/>
<boolean name='Temperature real' historicalDay='true' value='false'/>
<boolean name='Speed real' historicalWeek='false' value='true'/>
</timestamp>
</node>
</fields>
@ -342,7 +342,7 @@ class TestSensorDataStanzas(SlixTest):
"""
)
def testTimestamp(self):
msg = self.Message();
@ -386,8 +386,8 @@ class TestSensorDataStanzas(SlixTest):
self.check(msg,emptyStringIdXML)
msg['fields']['stringIds'] = "1"
self.check(msg,emptyStringIdXML)
suite = unittest.TestLoader().loadTestsFromTestCase(TestSensorDataStanzas)

View File

@ -15,7 +15,7 @@ import slixmpp.plugins.xep_0325 as xep_0325
namespace='sn'
class TestControlStanzas(SlixTest):
def setUp(self):
pass
@ -89,7 +89,7 @@ class TestControlStanzas(SlixTest):
msg['set'].add_data("Tjohej", "boolean", "true")
self.check(msg,"""
<message
<message
from='master@clayster.com/amr'
to='device@clayster.com'>
<set xmlns='urn:xmpp:iot:control'>
@ -244,5 +244,5 @@ class TestControlStanzas(SlixTest):
</iq>
"""
)
suite = unittest.TestLoader().loadTestsFromTestCase(TestControlStanzas)

View File

@ -46,7 +46,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='1'>
@ -60,11 +60,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
<node nodeId='Device22'>
<timestamp value='2013-03-07T16:24:30'>
<numeric name='Temperature' momentary='true' automaticReadout='true' value='23.4' unit='°C'/>
<numeric name='Temperature' momentary='true' automaticReadout='true' value='23.4' unit='°C'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
def testRequestRejectAuth(self):
@ -85,7 +85,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='error'
<iq type='error'
from='device@clayster.com'
to='master@clayster.com/amr'
id='4'>
@ -118,7 +118,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='error'
<iq type='error'
from='device@clayster.com'
to='master@clayster.com/amr'
id='77'>
@ -142,7 +142,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='8'>
@ -177,7 +177,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='error'
<iq type='error'
from='device@clayster.com'
to='master@clayster.com/amr'
id='7'>
@ -201,7 +201,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='8'>
@ -215,11 +215,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
<node nodeId='Device44'>
<timestamp value='2000-01-01T00:01:02'>
<numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
<numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.send("""
@ -227,7 +227,7 @@ class TestStreamSensorData(SlixTest):
to='master@clayster.com/amr'>
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
</fields>
</message>
</message>
""")
def testRequestMultiTimestampSingleField(self):
@ -260,7 +260,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='8'>
@ -274,11 +274,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
<node nodeId='Device44'>
<timestamp value='2000-01-01T00:01:02'>
<numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
<numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.send("""
@ -287,11 +287,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
<node nodeId='Device44'>
<timestamp value='2000-01-01T01:01:02'>
<numeric name='Voltage' value='230.6' unit='V'/>
<numeric name='Voltage' value='230.6' unit='V'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.send("""
@ -299,7 +299,7 @@ class TestStreamSensorData(SlixTest):
to='master@clayster.com/amr'>
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
</fields>
</message>
</message>
""")
def testRequestMultiTimestampAllFields(self):
@ -330,7 +330,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='8'>
@ -344,11 +344,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
<node nodeId='Device44'>
<timestamp value='2000-01-01T00:01:02'>
<numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
<numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.send("""
@ -357,12 +357,12 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
<node nodeId='Device44'>
<timestamp value='2000-01-01T01:01:02'>
<numeric name='Voltage' value='230.6' unit='V'/>
<string name='Height' invoiced='true' value='115 m'/>
<numeric name='Voltage' value='230.6' unit='V'/>
<string name='Height' invoiced='true' value='115 m'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.send("""
@ -370,7 +370,7 @@ class TestStreamSensorData(SlixTest):
to='master@clayster.com/amr'>
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
</fields>
</message>
</message>
""")
def testRequestAPI(self):
@ -424,7 +424,7 @@ class TestStreamSensorData(SlixTest):
plugins=['xep_0030',
'xep_0323'])
results = [];
results = [];
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
if (result == "rejected") and (error_msg == "Invalid device Device22"):
@ -445,19 +445,19 @@ class TestStreamSensorData(SlixTest):
""")
self.recv("""
<iq type='error'
<iq type='error'
from='you@google.com'
to='tester@localhost'
id='1'>
<rejected xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
<error>Invalid device Device22</error>
</rejected>
</iq>
</iq>
""")
time.sleep(.1)
self.failUnless(results == ["rejected"],
self.failUnless(results == ["rejected"],
"Rejected callback was not properly executed");
def testRequestAcceptedAPI(self):
@ -466,7 +466,7 @@ class TestStreamSensorData(SlixTest):
plugins=['xep_0030',
'xep_0323'])
results = [];
results = [];
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
results.append(result);
@ -486,17 +486,17 @@ class TestStreamSensorData(SlixTest):
""")
self.recv("""
<iq type='result'
<iq type='result'
from='you@google.com'
to='tester@localhost'
id='1'>
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
</iq>
</iq>
""")
time.sleep(.1)
self.failUnless(results == ["accepted"],
self.failUnless(results == ["accepted"],
"Accepted callback was not properly executed");
def testRequestFieldsAPI(self):
@ -505,8 +505,8 @@ class TestStreamSensorData(SlixTest):
plugins=['xep_0030',
'xep_0323'])
results = [];
callback_data = {};
results = [];
callback_data = {};
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
results.append(result);
@ -519,9 +519,9 @@ class TestStreamSensorData(SlixTest):
t1= threading.Thread(name="request_data",
target=self.xmpp['xep_0323'].request_data,
kwargs={"from_jid": "tester@localhost",
"to_jid": "you@google.com",
"nodeIds": ['Device33'],
kwargs={"from_jid": "tester@localhost",
"to_jid": "you@google.com",
"nodeIds": ['Device33'],
"callback": my_callback});
t1.start();
#self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback);
@ -538,12 +538,12 @@ class TestStreamSensorData(SlixTest):
""")
self.recv("""
<iq type='result'
<iq type='result'
from='you@google.com'
to='tester@localhost'
id='1'>
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
</iq>
</iq>
""")
self.recv("""
@ -552,19 +552,19 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
<node nodeId='Device33'>
<timestamp value='2000-01-01T00:01:02'>
<numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
<boolean name='TestBool' value='true'/>
<numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
<boolean name='TestBool' value='true'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.recv("""
<message from='you@google.com'
to='tester@localhost'>
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'/>
</message>
</message>
""")
t1.join();
@ -605,8 +605,8 @@ class TestStreamSensorData(SlixTest):
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity category='client' type='bot'/>
<feature var='urn:xmpp:iot:sensordata'/>
</query>
</iq>
</query>
</iq>
""")
def testServiceDiscoveryComponent(self):
@ -631,8 +631,8 @@ class TestStreamSensorData(SlixTest):
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity category='component' type='generic'/>
<feature var='urn:xmpp:iot:sensordata'/>
</query>
</iq>
</query>
</iq>
""")
def testRequestTimeout(self):
@ -642,7 +642,7 @@ class TestStreamSensorData(SlixTest):
'xep_0323'])
results = [];
callback_data = {};
callback_data = {};
def my_callback(from_jid, result, nodeId=None, timestamp=None, error_msg=None):
results.append(result);
@ -653,9 +653,9 @@ class TestStreamSensorData(SlixTest):
t1= threading.Thread(name="request_data",
target=self.xmpp['xep_0323'].request_data,
kwargs={"from_jid": "tester@localhost",
"to_jid": "you@google.com",
"nodeIds": ['Device33'],
kwargs={"from_jid": "tester@localhost",
"to_jid": "you@google.com",
"nodeIds": ['Device33'],
"callback": my_callback});
t1.start();
@ -671,12 +671,12 @@ class TestStreamSensorData(SlixTest):
""")
self.recv("""
<iq type='result'
<iq type='result'
from='you@google.com'
to='tester@localhost'
id='1'>
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
</iq>
</iq>
""")
self.recv("""
@ -729,7 +729,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='1'>
@ -743,7 +743,7 @@ class TestStreamSensorData(SlixTest):
<message from='device@clayster.com'
to='master@clayster.com/amr'>
<started xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
</message>
</message>
""")
self.send("""
@ -752,11 +752,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
<node nodeId='Device22'>
<timestamp value='2013-03-07T16:24:30'>
<numeric name='Temperature' momentary='true' automaticReadout='true' value='23.4' unit='°C'/>
<numeric name='Temperature' momentary='true' automaticReadout='true' value='23.4' unit='°C'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
def testDelayedRequestFail(self):
@ -792,7 +792,7 @@ class TestStreamSensorData(SlixTest):
xml_stanza['rejected']['error'] = error_text
self._filtered_stanza_check("""
<iq type='error'
<iq type='error'
from='device@clayster.com'
to='master@clayster.com/amr'
id='1'>
@ -847,7 +847,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='6'>
@ -861,11 +861,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
<node nodeId='Device44'>
<timestamp value='2000-02-01T00:01:02'>
<numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
<numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.send("""
@ -874,11 +874,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
<node nodeId='Device44'>
<timestamp value='2000-03-01T00:01:02'>
<numeric name='Voltage' invoiced='true' value='230.3' unit='V'/>
<numeric name='Voltage' invoiced='true' value='230.3' unit='V'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.send("""
@ -886,7 +886,7 @@ class TestStreamSensorData(SlixTest):
to='master@clayster.com/amr'>
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
</fields>
</message>
</message>
""")
def testRequestFieldTo(self):
@ -917,7 +917,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='6'>
@ -931,11 +931,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
<node nodeId='Device44'>
<timestamp value='2000-01-01T00:01:02'>
<numeric name='Voltage' invoiced='true' value='230.1' unit='V'/>
<numeric name='Voltage' invoiced='true' value='230.1' unit='V'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.send("""
@ -944,11 +944,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
<node nodeId='Device44'>
<timestamp value='2000-02-01T00:01:02'>
<numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
<numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.send("""
@ -956,7 +956,7 @@ class TestStreamSensorData(SlixTest):
to='master@clayster.com/amr'>
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
</fields>
</message>
</message>
""")
def testRequestFieldFromTo(self):
@ -987,7 +987,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='6'>
@ -1001,11 +1001,11 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
<node nodeId='Device44'>
<timestamp value='2000-02-01T00:01:02'>
<numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
<numeric name='Voltage' invoiced='true' value='230.2' unit='V'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.send("""
@ -1013,7 +1013,7 @@ class TestStreamSensorData(SlixTest):
to='master@clayster.com/amr'>
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
</fields>
</message>
</message>
""")
def testDelayedRequestClient(self):
@ -1021,8 +1021,8 @@ class TestStreamSensorData(SlixTest):
plugins=['xep_0030',
'xep_0323'])
results = [];
callback_data = {};
results = [];
callback_data = {};
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
results.append(result);
@ -1035,9 +1035,9 @@ class TestStreamSensorData(SlixTest):
t1= threading.Thread(name="request_data",
target=self.xmpp['xep_0323'].request_data,
kwargs={"from_jid": "tester@localhost",
"to_jid": "you@google.com",
"nodeIds": ['Device33'],
kwargs={"from_jid": "tester@localhost",
"to_jid": "you@google.com",
"nodeIds": ['Device33'],
"callback": my_callback});
t1.start();
#self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback);
@ -1054,20 +1054,20 @@ class TestStreamSensorData(SlixTest):
""")
self.recv("""
<iq type='result'
<iq type='result'
from='you@google.com'
to='tester@localhost'
id='1'>
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1' queued='true'/>
</iq>
</iq>
""")
self.recv("""
<message from='device@clayster.com'
to='master@clayster.com/amr'>
<started xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
</message>
""")
</message>
""")
self.recv("""
<message from='you@google.com'
@ -1075,19 +1075,19 @@ class TestStreamSensorData(SlixTest):
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
<node nodeId='Device33'>
<timestamp value='2000-01-01T00:01:02'>
<numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
<boolean name='TestBool' value='true'/>
<numeric name='Voltage' invoiced='true' value='230.4' unit='V'/>
<boolean name='TestBool' value='true'/>
</timestamp>
</node>
</fields>
</message>
</message>
""")
self.recv("""
<message from='you@google.com'
to='tester@localhost'>
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'/>
</message>
</message>
""")
t1.join();
@ -1114,7 +1114,7 @@ class TestStreamSensorData(SlixTest):
plugins=['xep_0030',
'xep_0323'])
results = [];
results = [];
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
results.append(result);
@ -1133,12 +1133,12 @@ class TestStreamSensorData(SlixTest):
""")
self.recv("""
<iq type='result'
<iq type='result'
from='you@google.com'
to='tester@localhost'
id='1'>
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
</iq>
</iq>
""")
self.xmpp['xep_0323'].cancel_request(session=session);
@ -1192,7 +1192,7 @@ class TestStreamSensorData(SlixTest):
""")
self.send("""
<iq type='result'
<iq type='result'
from='device@clayster.com'
to='master@clayster.com/amr'
id='1'>

View File

@ -60,7 +60,7 @@ class TestStreamControl(SlixTest):
to='master@clayster.com/amr'
id='1'>
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
</iq>
</iq>
""")
self.assertEqual(myDevice._get_field_value("Temperature"), "17");
@ -99,7 +99,7 @@ class TestStreamControl(SlixTest):
to='master@clayster.com/amr'
id='1'>
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
</iq>
</iq>
""")
self.assertEqual(myDevice._get_field_value("Temperature"), "17");
@ -125,7 +125,7 @@ class TestStreamControl(SlixTest):
to='master@clayster.com/amr'
id='2'>
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
</iq>
</iq>
""")
self.assertEqual(myDevice._get_field_value("Temperature"), "20");
@ -163,7 +163,7 @@ class TestStreamControl(SlixTest):
<parameter name='Voltage' />
<error var='Output'>Invalid field Voltage</error>
</setResponse>
</iq>
</iq>
""")
self.assertEqual(myDevice._get_field_value("Temperature"), "15");
@ -180,7 +180,7 @@ class TestStreamControl(SlixTest):
self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
self.recv("""
<message
<message
from='master@clayster.com/amr'
to='device@clayster.com'>
<set xmlns='urn:xmpp:iot:control'>
@ -204,7 +204,7 @@ class TestStreamControl(SlixTest):
self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
self.recv("""
<message
<message
from='master@clayster.com/amr'
to='device@clayster.com'>
<set xmlns='urn:xmpp:iot:control'>
@ -225,7 +225,7 @@ class TestStreamControl(SlixTest):
plugins=['xep_0030',
'xep_0325'])
results = [];
results = [];
def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
results.append(result);
@ -256,7 +256,7 @@ class TestStreamControl(SlixTest):
to='tester@localhost'
id='1'>
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
</iq>
</iq>
""")
time.sleep(.5)
@ -269,7 +269,7 @@ class TestStreamControl(SlixTest):
plugins=['xep_0030',
'xep_0325'])
results = [];
results = [];
def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
results.append(result);
@ -302,7 +302,7 @@ class TestStreamControl(SlixTest):
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OtherError" >
<error var='Temperature'>Sensor error</error>
</setResponse>
</iq>
</iq>
""")
time.sleep(.5)
@ -330,8 +330,8 @@ class TestStreamControl(SlixTest):
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity category='client' type='bot'/>
<feature var='urn:xmpp:iot:control'/>
</query>
</iq>
</query>
</iq>
""")
def testServiceDiscoveryComponent(self):
@ -356,8 +356,8 @@ class TestStreamControl(SlixTest):
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity category='component' type='generic'/>
<feature var='urn:xmpp:iot:control'/>
</query>
</iq>
</query>
</iq>
""")