Remove all trailing whitespaces.
This commit is contained in:
parent
ed37174a2b
commit
17174016ec
@ -80,7 +80,7 @@ Slixmpp projects::
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Ideally use optparse or argparse to get JID,
|
# Ideally use optparse or argparse to get JID,
|
||||||
# password, and log level.
|
# password, and log level.
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG,
|
logging.basicConfig(level=logging.DEBUG,
|
||||||
@ -101,15 +101,15 @@ Credits
|
|||||||
-------
|
-------
|
||||||
|
|
||||||
**Main Author:** Nathan Fritz
|
**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>`_
|
`@fritzy <http://twitter.com/fritzy>`_
|
||||||
|
|
||||||
Nathan is also the author of XMPPHP and `Seesmic-AS3-XMPP
|
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.
|
the XMPP Council.
|
||||||
|
|
||||||
**Co-Author:** Lance Stout
|
**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>`_
|
`@lancestout <http://twitter.com/lancestout>`_
|
||||||
|
|
||||||
**Contributors:**
|
**Contributors:**
|
||||||
|
68
docs/_static/nature.css
vendored
68
docs/_static/nature.css
vendored
@ -8,11 +8,11 @@
|
|||||||
* :license: BSD, see LICENSE for details.
|
* :license: BSD, see LICENSE for details.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@import url("basic.css");
|
@import url("basic.css");
|
||||||
|
|
||||||
/* -- page layout ----------------------------------------------------------- */
|
/* -- page layout ----------------------------------------------------------- */
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
@ -34,18 +34,18 @@ div.bodywrapper {
|
|||||||
hr {
|
hr {
|
||||||
border: 1px solid #B1B4B6;
|
border: 1px solid #B1B4B6;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.document {
|
div.document {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.body {
|
div.body {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
color: #3E4349;
|
color: #3E4349;
|
||||||
padding: 0 30px 30px 30px;
|
padding: 0 30px 30px 30px;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.footer {
|
div.footer {
|
||||||
color: #555;
|
color: #555;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -53,12 +53,12 @@ div.footer {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.footer a {
|
div.footer a {
|
||||||
color: #444;
|
color: #444;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.related {
|
div.related {
|
||||||
background-color: #6BA81E;
|
background-color: #6BA81E;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
@ -66,11 +66,11 @@ div.related {
|
|||||||
text-shadow: 0px 1px 0 #444;
|
text-shadow: 0px 1px 0 #444;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.related a {
|
div.related a {
|
||||||
color: #E2F3CC;
|
color: #E2F3CC;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar {
|
div.sphinxsidebar {
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
@ -79,7 +79,7 @@ div.sphinxsidebar {
|
|||||||
div.sphinxsidebarwrapper{
|
div.sphinxsidebarwrapper{
|
||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar h3,
|
div.sphinxsidebar h3,
|
||||||
div.sphinxsidebar h4 {
|
div.sphinxsidebar h4 {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
@ -95,30 +95,30 @@ div.sphinxsidebar h4 {
|
|||||||
div.sphinxsidebar h4{
|
div.sphinxsidebar h4{
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar h3 a {
|
div.sphinxsidebar h3 a {
|
||||||
color: #444;
|
color: #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
div.sphinxsidebar p {
|
div.sphinxsidebar p {
|
||||||
color: #888;
|
color: #888;
|
||||||
padding: 5px 20px;
|
padding: 5px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar p.topless {
|
div.sphinxsidebar p.topless {
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar ul {
|
div.sphinxsidebar ul {
|
||||||
margin: 10px 20px;
|
margin: 10px 20px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar a {
|
div.sphinxsidebar a {
|
||||||
color: #444;
|
color: #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.sphinxsidebar input {
|
div.sphinxsidebar input {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
@ -128,19 +128,19 @@ div.sphinxsidebar input {
|
|||||||
div.sphinxsidebar input[type=text]{
|
div.sphinxsidebar input[type=text]{
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- body styles ----------------------------------------------------------- */
|
/* -- body styles ----------------------------------------------------------- */
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #005B81;
|
color: #005B81;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
color: #E32E00;
|
color: #E32E00;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.body h1,
|
div.body h1,
|
||||||
div.body h2,
|
div.body h2,
|
||||||
div.body h3,
|
div.body h3,
|
||||||
@ -155,30 +155,30 @@ div.body h6 {
|
|||||||
padding: 5px 0 5px 10px;
|
padding: 5px 0 5px 10px;
|
||||||
text-shadow: 0px 1px 0 white
|
text-shadow: 0px 1px 0 white
|
||||||
}
|
}
|
||||||
|
|
||||||
div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
|
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 h2 { font-size: 150%; background-color: #C8D5E3; }
|
||||||
div.body h3 { font-size: 120%; background-color: #D8DEE3; }
|
div.body h3 { font-size: 120%; background-color: #D8DEE3; }
|
||||||
div.body h4 { font-size: 110%; background-color: #D8DEE3; }
|
div.body h4 { font-size: 110%; background-color: #D8DEE3; }
|
||||||
div.body h5 { font-size: 100%; background-color: #D8DEE3; }
|
div.body h5 { font-size: 100%; background-color: #D8DEE3; }
|
||||||
div.body h6 { font-size: 100%; background-color: #D8DEE3; }
|
div.body h6 { font-size: 100%; background-color: #D8DEE3; }
|
||||||
|
|
||||||
a.headerlink {
|
a.headerlink {
|
||||||
color: #c60f0f;
|
color: #c60f0f;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
padding: 0 4px 0 4px;
|
padding: 0 4px 0 4px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.headerlink:hover {
|
a.headerlink:hover {
|
||||||
background-color: #c60f0f;
|
background-color: #c60f0f;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.body p, div.body dd, div.body li {
|
div.body p, div.body dd, div.body li {
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.admonition p.admonition-title + p {
|
div.admonition p.admonition-title + p {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
@ -191,29 +191,29 @@ div.note {
|
|||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.seealso {
|
div.seealso {
|
||||||
background-color: #ffc;
|
background-color: #ffc;
|
||||||
border: 1px solid #ff6;
|
border: 1px solid #ff6;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.topic {
|
div.topic {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.warning {
|
div.warning {
|
||||||
background-color: #ffe4e4;
|
background-color: #ffe4e4;
|
||||||
border: 1px solid #f66;
|
border: 1px solid #f66;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.admonition-title {
|
p.admonition-title {
|
||||||
display: inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.admonition-title:after {
|
p.admonition-title:after {
|
||||||
content: ":";
|
content: ":";
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: White;
|
background-color: White;
|
||||||
@ -225,7 +225,7 @@ pre {
|
|||||||
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
|
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
|
||||||
-moz-box-shadow: 1px 1px 1px #d8d8d8;
|
-moz-box-shadow: 1px 1px 1px #d8d8d8;
|
||||||
}
|
}
|
||||||
|
|
||||||
tt {
|
tt {
|
||||||
background-color: #ecf0f3;
|
background-color: #ecf0f3;
|
||||||
color: #222;
|
color: #222;
|
||||||
|
2
docs/_static/sphinxdoc.css
vendored
2
docs/_static/sphinxdoc.css
vendored
@ -134,7 +134,7 @@ div.footer a {
|
|||||||
|
|
||||||
/* -- body styles ----------------------------------------------------------- */
|
/* -- body styles ----------------------------------------------------------- */
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin: 0.8em 0 0.5em 0;
|
margin: 0.8em 0 0.5em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ Exceptions
|
|||||||
|
|
||||||
.. module:: slixmpp.exceptions
|
.. module:: slixmpp.exceptions
|
||||||
|
|
||||||
|
|
||||||
.. autoexception:: XMPPError
|
.. autoexception:: XMPPError
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ of an interface defined by the parent.
|
|||||||
- :ref:`create-stanza-plugins`
|
- :ref:`create-stanza-plugins`
|
||||||
- :ref:`create-extension-plugins`
|
- :ref:`create-extension-plugins`
|
||||||
- :ref:`override-parent-interfaces`
|
- :ref:`override-parent-interfaces`
|
||||||
|
|
||||||
|
|
||||||
Registering Stanza Plugins
|
Registering Stanza Plugins
|
||||||
--------------------------
|
--------------------------
|
||||||
|
@ -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
|
callback, the callback function is executed with the stanza as its only
|
||||||
parameter.
|
parameter.
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
The callback, aka :term:`stream handler`, is executed in the main event
|
The callback, aka :term:`stream handler`, is executed in the main event
|
||||||
processing thread. If the handler blocks, event processing will also
|
processing thread. If the handler blocks, event processing will also
|
||||||
block.
|
block.
|
||||||
@ -117,7 +117,7 @@ when this bit of XML is received (with an assumed namespace of
|
|||||||
paired with an :term:`event handler`::
|
paired with an :term:`event handler`::
|
||||||
|
|
||||||
('event', 'message', msg_copy1, custom_event_handler_1)
|
('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**
|
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.
|
will be spawned for it.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Events may be raised without needing :term:`stanza objects <stanza object>`.
|
Events may be raised without needing :term:`stanza objects <stanza object>`.
|
||||||
For example, you could use ``self.event('custom', {'a': 'b'})``.
|
For example, you could use ``self.event('custom', {'a': 'b'})``.
|
||||||
You don't even need any arguments: ``self.event('no_parameters')``.
|
You don't even need any arguments: ``self.event('no_parameters')``.
|
||||||
However, every event handler MUST accept at least one argument.
|
However, every event handler MUST accept at least one argument.
|
||||||
|
|
||||||
Finally, after a long trek, our message is handed off to the user's
|
Finally, after a long trek, our message is handed off to the user's
|
||||||
|
@ -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)
|
self.register_plugin('myplugin', module=mod_containing_my_plugin)
|
||||||
|
|
||||||
The plugin name must be the same as the plugin's class name.
|
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
|
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
|
``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
|
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'
|
namespace = 'jabber:iq:register'
|
||||||
name = 'query'
|
name = 'query'
|
||||||
plugin_attrib = 'register'
|
plugin_attrib = 'register'
|
||||||
interfaces = set(('username', 'password', 'email', 'nick', 'name',
|
interfaces = set(('username', 'password', 'email', 'nick', 'name',
|
||||||
'first', 'last', 'address', 'city', 'state', 'zip',
|
'first', 'last', 'address', 'city', 'state', 'zip',
|
||||||
'phone', 'url', 'date', 'misc', 'text', 'key',
|
'phone', 'url', 'date', 'misc', 'text', 'key',
|
||||||
'registered', 'remove', 'instructions'))
|
'registered', 'remove', 'instructions'))
|
||||||
sub_interfaces = interfaces
|
sub_interfaces = interfaces
|
||||||
|
|
||||||
|
@ -60,13 +60,13 @@ Event Index
|
|||||||
disco_info
|
disco_info
|
||||||
- **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoInfo`
|
- **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoInfo`
|
||||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030`
|
- **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030`
|
||||||
|
|
||||||
Triggered whenever a ``disco#info`` result stanza is received.
|
Triggered whenever a ``disco#info`` result stanza is received.
|
||||||
|
|
||||||
disco_items
|
disco_items
|
||||||
- **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoItems`
|
- **Data:** :py:class:`~slixmpp.plugins.xep_0030.stanza.DiscoItems`
|
||||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030`
|
- **Source:** :py:class:`~slixmpp.plugins.xep_0030.disco.xep_0030`
|
||||||
|
|
||||||
Triggered whenever a ``disco#items`` result stanza is received.
|
Triggered whenever a ``disco#items`` result stanza is received.
|
||||||
|
|
||||||
disconnected
|
disconnected
|
||||||
@ -88,13 +88,13 @@ Event Index
|
|||||||
gmail_notify
|
gmail_notify
|
||||||
- **Data:** ``{}``
|
- **Data:** ``{}``
|
||||||
- **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify`
|
- **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify`
|
||||||
|
|
||||||
Signal that there are unread emails for the Gmail account associated with the current XMPP account.
|
Signal that there are unread emails for the Gmail account associated with the current XMPP account.
|
||||||
|
|
||||||
gmail_messages
|
gmail_messages
|
||||||
- **Data:** :py:class:`~slixmpp.Iq`
|
- **Data:** :py:class:`~slixmpp.Iq`
|
||||||
- **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify`
|
- **Source:** :py:class:`~slixmpp.plugins.gmail_notify.gmail_notify`
|
||||||
|
|
||||||
Signal that there are unread emails for the Gmail account associated with the current XMPP account.
|
Signal that there are unread emails for the Gmail account associated with the current XMPP account.
|
||||||
|
|
||||||
got_online
|
got_online
|
||||||
@ -122,19 +122,19 @@ Event Index
|
|||||||
groupchat_message
|
groupchat_message
|
||||||
- **Data:** :py:class:`~slixmpp.Message`
|
- **Data:** :py:class:`~slixmpp.Message`
|
||||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045`
|
- **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045`
|
||||||
|
|
||||||
Triggered whenever a message is received from a multi-user chat room.
|
Triggered whenever a message is received from a multi-user chat room.
|
||||||
|
|
||||||
groupchat_presence
|
groupchat_presence
|
||||||
- **Data:** :py:class:`~slixmpp.Presence`
|
- **Data:** :py:class:`~slixmpp.Presence`
|
||||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045`
|
- **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.
|
Triggered whenever a presence stanza is received from a user in a multi-user chat room.
|
||||||
|
|
||||||
groupchat_subject
|
groupchat_subject
|
||||||
- **Data:** :py:class:`~slixmpp.Message`
|
- **Data:** :py:class:`~slixmpp.Message`
|
||||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0045.xep_0045`
|
- **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.
|
Triggered whenever the subject of a multi-user chat room is changed, or announced when joining a room.
|
||||||
|
|
||||||
killed
|
killed
|
||||||
@ -148,7 +148,7 @@ Event Index
|
|||||||
message
|
message
|
||||||
- **Data:** :py:class:`~slixmpp.Message`
|
- **Data:** :py:class:`~slixmpp.Message`
|
||||||
- **Source:** :py:class:`BaseXMPP <slixmpp.BaseXMPP>`
|
- **Source:** :py:class:`BaseXMPP <slixmpp.BaseXMPP>`
|
||||||
|
|
||||||
Makes the contents of message stanzas available whenever one is received. Be
|
Makes the contents of message stanzas available whenever one is received. Be
|
||||||
sure to check the message type in order to handle error messages.
|
sure to check the message type in order to handle error messages.
|
||||||
|
|
||||||
@ -183,67 +183,67 @@ Event Index
|
|||||||
presence_available
|
presence_available
|
||||||
- **Data:** :py:class:`~slixmpp.Presence`
|
- **Data:** :py:class:`~slixmpp.Presence`
|
||||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||||
|
|
||||||
A presence stanza with a type of '``available``' is received.
|
A presence stanza with a type of '``available``' is received.
|
||||||
|
|
||||||
presence_error
|
presence_error
|
||||||
- **Data:** :py:class:`~slixmpp.Presence`
|
- **Data:** :py:class:`~slixmpp.Presence`
|
||||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||||
|
|
||||||
A presence stanza with a type of '``error``' is received.
|
A presence stanza with a type of '``error``' is received.
|
||||||
|
|
||||||
presence_form
|
presence_form
|
||||||
- **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form`
|
- **Data:** :py:class:`~slixmpp.plugins.xep_0004.Form`
|
||||||
- **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004`
|
- **Source:** :py:class:`~slixmpp.plugins.xep_0004.xep_0004`
|
||||||
|
|
||||||
This event is present in the XEP-0004 plugin code, but is currently not used.
|
This event is present in the XEP-0004 plugin code, but is currently not used.
|
||||||
|
|
||||||
presence_probe
|
presence_probe
|
||||||
- **Data:** :py:class:`~slixmpp.Presence`
|
- **Data:** :py:class:`~slixmpp.Presence`
|
||||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||||
|
|
||||||
A presence stanza with a type of '``probe``' is received.
|
A presence stanza with a type of '``probe``' is received.
|
||||||
|
|
||||||
presence_subscribe
|
presence_subscribe
|
||||||
- **Data:** :py:class:`~slixmpp.Presence`
|
- **Data:** :py:class:`~slixmpp.Presence`
|
||||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||||
|
|
||||||
A presence stanza with a type of '``subscribe``' is received.
|
A presence stanza with a type of '``subscribe``' is received.
|
||||||
|
|
||||||
presence_subscribed
|
presence_subscribed
|
||||||
- **Data:** :py:class:`~slixmpp.Presence`
|
- **Data:** :py:class:`~slixmpp.Presence`
|
||||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||||
|
|
||||||
A presence stanza with a type of '``subscribed``' is received.
|
A presence stanza with a type of '``subscribed``' is received.
|
||||||
|
|
||||||
presence_unavailable
|
presence_unavailable
|
||||||
- **Data:** :py:class:`~slixmpp.Presence`
|
- **Data:** :py:class:`~slixmpp.Presence`
|
||||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||||
|
|
||||||
A presence stanza with a type of '``unavailable``' is received.
|
A presence stanza with a type of '``unavailable``' is received.
|
||||||
|
|
||||||
presence_unsubscribe
|
presence_unsubscribe
|
||||||
- **Data:** :py:class:`~slixmpp.Presence`
|
- **Data:** :py:class:`~slixmpp.Presence`
|
||||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||||
|
|
||||||
A presence stanza with a type of '``unsubscribe``' is received.
|
A presence stanza with a type of '``unsubscribe``' is received.
|
||||||
|
|
||||||
presence_unsubscribed
|
presence_unsubscribed
|
||||||
- **Data:** :py:class:`~slixmpp.Presence`
|
- **Data:** :py:class:`~slixmpp.Presence`
|
||||||
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
- **Source:** :py:class:`~slixmpp.BaseXMPP`
|
||||||
|
|
||||||
A presence stanza with a type of '``unsubscribed``' is received.
|
A presence stanza with a type of '``unsubscribed``' is received.
|
||||||
|
|
||||||
roster_update
|
roster_update
|
||||||
- **Data:** :py:class:`~slixmpp.stanza.Roster`
|
- **Data:** :py:class:`~slixmpp.stanza.Roster`
|
||||||
- **Source:** :py:class:`~slixmpp.ClientXMPP`
|
- **Source:** :py:class:`~slixmpp.ClientXMPP`
|
||||||
|
|
||||||
An IQ result containing roster entries is received.
|
An IQ result containing roster entries is received.
|
||||||
|
|
||||||
sent_presence
|
sent_presence
|
||||||
- **Data:** ``{}``
|
- **Data:** ``{}``
|
||||||
- **Source:** :py:class:`~slixmpp.roster.multi.Roster`
|
- **Source:** :py:class:`~slixmpp.roster.multi.Roster`
|
||||||
|
|
||||||
Signal that an initial presence stanza has been written to the XML stream.
|
Signal that an initial presence stanza has been written to the XML stream.
|
||||||
|
|
||||||
session_end
|
session_end
|
||||||
|
@ -5,7 +5,7 @@ Create and Run a Server Component
|
|||||||
=================================
|
=================================
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
If you have any issues working through this quickstart guide
|
If you have any issues working through this quickstart guide
|
||||||
or the other tutorials here, please either send a message to the
|
or the other tutorials here, please either send a message to the
|
||||||
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
||||||
@ -21,8 +21,8 @@ or ``easy_install``.
|
|||||||
pip install slixmpp # Or: easy_install slixmpp
|
pip install slixmpp # Or: easy_install slixmpp
|
||||||
|
|
||||||
|
|
||||||
Many XMPP applications eventually graduate to requiring to run as a server
|
Many XMPP applications eventually graduate to requiring to run as a server
|
||||||
component in order to meet scalability requirements. To demonstrate how to
|
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
|
turn an XMPP client bot into a component, we'll turn the echobot example
|
||||||
(:ref:`echobot`) into a component version.
|
(:ref:`echobot`) into a component version.
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ Slixmpp Quickstart - Echo Bot
|
|||||||
===============================
|
===============================
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
If you have any issues working through this quickstart guide
|
If you have any issues working through this quickstart guide
|
||||||
or the other tutorials here, please either send a message to the
|
or the other tutorials here, please either send a message to the
|
||||||
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
||||||
@ -93,7 +93,7 @@ as well.
|
|||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
class EchoBot(slixmpp.ClientXMPP):
|
class EchoBot(slixmpp.ClientXMPP):
|
||||||
|
|
||||||
def __init__(self, jid, password):
|
def __init__(self, jid, password):
|
||||||
super(EchoBot, self).__init__(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
|
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,
|
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
|
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.
|
started. To do that, we will register an event handler for the :term:`session_start` event.
|
||||||
|
|
||||||
.. code-block:: python
|
.. 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,
|
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),
|
``.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()``.
|
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>`,
|
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
|
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
|
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
|
.. code-block:: python
|
||||||
|
|
||||||
@ -303,21 +303,21 @@ the ``EchoBot.__init__`` method instead.
|
|||||||
|
|
||||||
.. note::
|
.. 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
|
configuration step. OpenFire supports a different version of SSL than what
|
||||||
most servers and Slixmpp support.
|
most servers and Slixmpp support.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
import ssl
|
import ssl
|
||||||
xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||||
|
|
||||||
Now we're ready to connect and begin echoing messages. If you have the package
|
Now we're ready to connect and begin echoing messages. If you have the package
|
||||||
``dnspython`` installed, then the :meth:`slixmpp.clientxmpp.ClientXMPP` method
|
``dnspython`` installed, then the :meth:`slixmpp.clientxmpp.ClientXMPP` method
|
||||||
will perform a DNS query to find the appropriate server to connect to for the
|
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
|
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
|
.. 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`
|
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
|
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
|
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`
|
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
|
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.
|
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
|
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
|
done via the ``threaded`` argument. This arrangement was a source of confusion because some users
|
||||||
|
@ -36,7 +36,7 @@ stanzas this way. The relevant methods are:
|
|||||||
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_error`
|
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_error`
|
||||||
* :meth:`~slixmpp.basexmpp.BaseXMPP.make_iq_query`
|
* :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
|
:class:`~slixmpp.stanza.iq.Iq` stanza, set the ``'type'`` value based
|
||||||
on the method name, and finally add a ``<query />`` element with the given
|
on the method name, and finally add a ``<query />`` element with the given
|
||||||
namespace. For example, to produce the query above, you would use:
|
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:
|
To change the timeout for a single call, the ``timeout`` parameter works:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
iq.send(timeout=60)
|
iq.send(timeout=60)
|
||||||
|
|
||||||
* ``callback``: When not using a blocking call, using the ``callback``
|
* ``callback``: When not using a blocking call, using the ``callback``
|
||||||
@ -85,7 +85,7 @@ These options are:
|
|||||||
|
|
||||||
.. code-block:: python
|
.. 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
|
# ... later if we need to cancel
|
||||||
self.remove_handler(cb_name)
|
self.remove_handler(cb_name)
|
||||||
@ -133,7 +133,7 @@ interfacting with the :class:`~slixmpp.stanza.iq.Iq` payload.
|
|||||||
* :ref:`create-plugin`
|
* :ref:`create-plugin`
|
||||||
* :ref:`work-with-stanzas`
|
* :ref:`work-with-stanzas`
|
||||||
* :ref:`using-handlers-matchers`
|
* :ref:`using-handlers-matchers`
|
||||||
|
|
||||||
|
|
||||||
The typical way to respond to :class:`~slixmpp.stanza.iq.Iq` requests is
|
The typical way to respond to :class:`~slixmpp.stanza.iq.Iq` requests is
|
||||||
to register stream handlers. As an example, suppose we create a stanza class
|
to register stream handlers. As an example, suppose we create a stanza class
|
||||||
|
@ -5,7 +5,7 @@ Enable HTTP Proxy Support
|
|||||||
=========================
|
=========================
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
If you have any issues working through this quickstart guide
|
If you have any issues working through this quickstart guide
|
||||||
or the other tutorials here, please either send a message to the
|
or the other tutorials here, please either send a message to the
|
||||||
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
||||||
|
@ -2,7 +2,7 @@ Sign in, Send a Message, and Disconnect
|
|||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
If you have any issues working through this quickstart guide
|
If you have any issues working through this quickstart guide
|
||||||
or the other tutorials here, please either send a message to the
|
or the other tutorials here, please either send a message to the
|
||||||
`mailing list <http://groups.google.com/group/slixmpp-discussion>`_
|
`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>`_.
|
<xmpp:sleek@conference.jabber.org?join>`_.
|
||||||
|
|
||||||
A common use case for Slixmpp is to send one-off messages from
|
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.
|
a shell script finishes a task.
|
||||||
|
|
||||||
We will create our one-shot bot based on the pattern explained in :ref:`echobot`. To
|
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):
|
class SendMsgBot(slixmpp.ClientXMPP):
|
||||||
|
|
||||||
def __init__(self, jid, password, recipient, msg):
|
def __init__(self, jid, password, recipient, msg):
|
||||||
super(SendMsgBot, self).__init__(jid, password)
|
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
|
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
|
: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
|
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>`.
|
:meth:`disconnect(wait=True) <slixmpp.xmlstream.XMLStream.disconnect>`.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
@ -159,7 +159,7 @@ item itself, and the JID and node that will own the item.
|
|||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
In this case, the owning JID and node are provided with the
|
In this case, the owning JID and node are provided with the
|
||||||
parameters ``ijid`` and ``node``.
|
parameters ``ijid`` and ``node``.
|
||||||
|
|
||||||
Peforming Disco Queries
|
Peforming Disco Queries
|
||||||
-----------------------
|
-----------------------
|
||||||
@ -197,5 +197,5 @@ a full Iq stanza.
|
|||||||
|
|
||||||
info = self['xep_0030'].get_info(node='foo', local=True)
|
info = self['xep_0030'].get_info(node='foo', local=True)
|
||||||
items = self['xep_0030'].get_items(jid='somejid@mycomponent.example.com',
|
items = self['xep_0030'].get_items(jid='somejid@mycomponent.example.com',
|
||||||
node='bar',
|
node='bar',
|
||||||
local=True)
|
local=True)
|
||||||
|
@ -31,7 +31,7 @@ Slixmpp
|
|||||||
|
|
||||||
Slixmpp is an :ref:`MIT licensed <license>` XMPP library for Python 2.6/3.1+,
|
Slixmpp is an :ref:`MIT licensed <license>` XMPP library for Python 2.6/3.1+,
|
||||||
and is featured in examples in
|
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
|
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
|
here from reading the Definitive Guide, please see the notes on updating
|
||||||
the examples to the latest version of Slixmpp.
|
the examples to the latest version of Slixmpp.
|
||||||
@ -113,7 +113,7 @@ Here's your first Slixmpp Bot:
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Ideally use optparse or argparse to get JID,
|
# Ideally use optparse or argparse to get JID,
|
||||||
# password, and log level.
|
# password, and log level.
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG,
|
logging.basicConfig(level=logging.DEBUG,
|
||||||
@ -129,7 +129,7 @@ Getting Started (with Examples)
|
|||||||
-------------------------------
|
-------------------------------
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
getting_started/echobot
|
getting_started/echobot
|
||||||
getting_started/sendlogout
|
getting_started/sendlogout
|
||||||
getting_started/component
|
getting_started/component
|
||||||
@ -144,7 +144,7 @@ Tutorials, FAQs, and How To Guides
|
|||||||
----------------------------------
|
----------------------------------
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
faq
|
faq
|
||||||
xeps
|
xeps
|
||||||
xmpp_tdg
|
xmpp_tdg
|
||||||
@ -156,7 +156,7 @@ Tutorials, FAQs, and How To Guides
|
|||||||
|
|
||||||
Plugin Guides
|
Plugin Guides
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
guide_xep_0030
|
guide_xep_0030
|
||||||
@ -173,7 +173,7 @@ API Reference
|
|||||||
-------------
|
-------------
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
event_index
|
event_index
|
||||||
api/clientxmpp
|
api/clientxmpp
|
||||||
api/componentxmpp
|
api/componentxmpp
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.. _license:
|
.. _license:
|
||||||
|
|
||||||
License (MIT)
|
License (MIT)
|
||||||
=============
|
=============
|
||||||
|
@ -4,9 +4,9 @@ Supported XEPS
|
|||||||
======= ============================= ================
|
======= ============================= ================
|
||||||
XEP Description Notes
|
XEP Description Notes
|
||||||
======= ============================= ================
|
======= ============================= ================
|
||||||
`0004`_ Data forms
|
`0004`_ Data forms
|
||||||
`0009`_ Jabber RPC
|
`0009`_ Jabber RPC
|
||||||
`0012`_ Last Activity
|
`0012`_ Last Activity
|
||||||
`0030`_ Service Discovery
|
`0030`_ Service Discovery
|
||||||
`0033`_ Extended Stanza Addressing
|
`0033`_ Extended Stanza Addressing
|
||||||
`0045`_ Multi-User Chat (MUC) Client-side only
|
`0045`_ Multi-User Chat (MUC) Client-side only
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Following *XMPP: The Definitive Guide*
|
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/>`_
|
`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271/>`_
|
||||||
by Peter Saint-Andre, Kevin Smith, and Remko Tronçon. The original source code
|
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
|
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)
|
user = self.backend.getUserFromJID(event["from"].jid)
|
||||||
if user is not None:
|
if user is not None:
|
||||||
self.backend.addMessageFromUser(message, user)
|
self.backend.addMessageFromUser(message, user)
|
||||||
|
|
||||||
def handleMessageAddedToBackend(self, message) :
|
def handleMessageAddedToBackend(self, message) :
|
||||||
body = message.user + ": " + message.text
|
body = message.user + ": " + message.text
|
||||||
htmlBody = "<p><a href='%(uri)s'>%(user)s</a>: %(message)s</p>" % {
|
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.**
|
**Extended CheshiR IM server component implementation.**
|
||||||
|
|
||||||
.. note::
|
.. 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
|
sections for corrections to code that is not marked as new in the book
|
||||||
example.
|
example.
|
||||||
|
|
||||||
@ -246,4 +246,4 @@ Updated Code
|
|||||||
self.sendAllContactSubscriptionRequestsToUser(userJID)
|
self.sendAllContactSubscriptionRequestsToUser(userJID)
|
||||||
|
|
||||||
`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_ |
|
`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>`_
|
||||||
|
@ -82,7 +82,7 @@ class ActionUserBot(slixmpp.ClientXMPP):
|
|||||||
iq2['type'] = 'set'
|
iq2['type'] = 'set'
|
||||||
iq2['action']['method'] = 'bye'
|
iq2['action']['method'] = 'bye'
|
||||||
iq2.send(block=False)
|
iq2.send(block=False)
|
||||||
|
|
||||||
# The wait=True delays the disconnect until the queue
|
# The wait=True delays the disconnect until the queue
|
||||||
# of stanzas to be sent becomes empty.
|
# of stanzas to be sent becomes empty.
|
||||||
self.disconnect(wait=True)
|
self.disconnect(wait=True)
|
||||||
|
@ -11,7 +11,7 @@ class Action(ElementBase):
|
|||||||
<status>X</status>
|
<status>X</status>
|
||||||
</action>
|
</action>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#: The `name` field refers to the basic XML tag name of the
|
#: The `name` field refers to the basic XML tag name of the
|
||||||
#: stanza. Here, the tag name will be 'action'.
|
#: stanza. Here, the tag name will be 'action'.
|
||||||
name = 'action'
|
name = 'action'
|
||||||
@ -22,9 +22,9 @@ class Action(ElementBase):
|
|||||||
#: The `plugin_attrib` value is the name that can be used
|
#: The `plugin_attrib` value is the name that can be used
|
||||||
#: with a parent stanza to access this stanza. For example
|
#: with a parent stanza to access this stanza. For example
|
||||||
#: from an Iq stanza object, accessing:
|
#: from an Iq stanza object, accessing:
|
||||||
#:
|
#:
|
||||||
#: iq['action']
|
#: iq['action']
|
||||||
#:
|
#:
|
||||||
#: would reference an Action object, and will even create
|
#: would reference an Action object, and will even create
|
||||||
#: an Action object and append it to the Iq stanza if
|
#: an Action object and append it to the Iq stanza if
|
||||||
#: one doesn't already exist.
|
#: one doesn't already exist.
|
||||||
@ -49,7 +49,7 @@ class Action(ElementBase):
|
|||||||
#: the sub_interfaces set. For example, here all interfaces
|
#: the sub_interfaces set. For example, here all interfaces
|
||||||
#: are marked as sub_interfaces, and so the XML produced will
|
#: are marked as sub_interfaces, and so the XML produced will
|
||||||
#: look like:
|
#: look like:
|
||||||
#:
|
#:
|
||||||
#: <action xmlns="slixmpp:custom:actions">
|
#: <action xmlns="slixmpp:custom:actions">
|
||||||
#: <method>foo</method>
|
#: <method>foo</method>
|
||||||
#: </action>
|
#: </action>
|
||||||
|
@ -121,7 +121,7 @@ if __name__ == '__main__':
|
|||||||
if args.password is None:
|
if args.password is None:
|
||||||
args.password = getpass("Password: ")
|
args.password = getpass("Password: ")
|
||||||
|
|
||||||
|
|
||||||
access_token = None
|
access_token = None
|
||||||
|
|
||||||
# Since documentation on how to work with Google tokens
|
# Since documentation on how to work with Google tokens
|
||||||
@ -147,7 +147,7 @@ if __name__ == '__main__':
|
|||||||
'Passwd': args.password
|
'Passwd': args.password
|
||||||
})
|
})
|
||||||
headers = {
|
headers = {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
conn.request('POST', '/accounts/ClientLogin', params, headers)
|
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
|
# We're using an access token instead of a password, so we'll use `''` as
|
||||||
# a password argument filler.
|
# a password argument filler.
|
||||||
|
|
||||||
xmpp = ThirdPartyAuthBot(args.jid, '')
|
xmpp = ThirdPartyAuthBot(args.jid, '')
|
||||||
xmpp.credentials['access_token'] = access_token
|
xmpp.credentials['access_token'] = access_token
|
||||||
|
|
||||||
# The credentials dictionary is used to provide additional authentication
|
# The credentials dictionary is used to provide additional authentication
|
||||||
# information beyond just a password.
|
# information beyond just a password.
|
||||||
|
|
||||||
xmpp.register_plugin('xep_0030') # Service Discovery
|
xmpp.register_plugin('xep_0030') # Service Discovery
|
||||||
xmpp.register_plugin('xep_0004') # Data Forms
|
xmpp.register_plugin('xep_0004') # Data Forms
|
||||||
xmpp.register_plugin('xep_0060') # PubSub
|
xmpp.register_plugin('xep_0060') # PubSub
|
||||||
@ -218,7 +218,7 @@ if __name__ == '__main__':
|
|||||||
# xmpp.ca_certs = "path/to/ca/cert"
|
# xmpp.ca_certs = "path/to/ca/cert"
|
||||||
|
|
||||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
# 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.
|
# enable the X-GOOGLE-TOKEN mechanism, we'll disable TLS.
|
||||||
xmpp.connect()
|
xmpp.connect()
|
||||||
xmpp.process()
|
xmpp.process()
|
||||||
|
@ -25,7 +25,7 @@ class LocationBot(ClientXMPP):
|
|||||||
super(LocationBot, self).__init__(jid, password)
|
super(LocationBot, self).__init__(jid, password)
|
||||||
|
|
||||||
self.add_event_handler('session_start', self.start)
|
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.user_location_publish)
|
||||||
|
|
||||||
self.register_plugin('xep_0004')
|
self.register_plugin('xep_0004')
|
||||||
|
@ -1,218 +1,218 @@
|
|||||||
"""
|
"""
|
||||||
Slixmpp: The Slick XMPP Library
|
Slixmpp: The Slick XMPP Library
|
||||||
Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON).
|
Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON).
|
||||||
This file is part of Slixmpp.
|
This file is part of Slixmpp.
|
||||||
|
|
||||||
See the file LICENSE for copying permission.
|
See the file LICENSE for copying permission.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from slixmpp import Iq
|
from slixmpp import Iq
|
||||||
from slixmpp.xmlstream import ET, register_stanza_plugin
|
from slixmpp.xmlstream import ET, register_stanza_plugin
|
||||||
from slixmpp.xmlstream.handler import Callback
|
from slixmpp.xmlstream.handler import Callback
|
||||||
from slixmpp.xmlstream.matcher import MatchXPath
|
from slixmpp.xmlstream.matcher import MatchXPath
|
||||||
from slixmpp.plugins import BasePlugin
|
from slixmpp.plugins import BasePlugin
|
||||||
from slixmpp.plugins.xep_0009 import stanza
|
from slixmpp.plugins.xep_0009 import stanza
|
||||||
from slixmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse
|
from slixmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class XEP_0009(BasePlugin):
|
class XEP_0009(BasePlugin):
|
||||||
|
|
||||||
name = 'xep_0009'
|
name = 'xep_0009'
|
||||||
description = 'XEP-0009: Jabber-RPC'
|
description = 'XEP-0009: Jabber-RPC'
|
||||||
dependencies = set(['xep_0030'])
|
dependencies = set(['xep_0030'])
|
||||||
stanza = stanza
|
stanza = stanza
|
||||||
|
|
||||||
def plugin_init(self):
|
def plugin_init(self):
|
||||||
register_stanza_plugin(Iq, RPCQuery)
|
register_stanza_plugin(Iq, RPCQuery)
|
||||||
register_stanza_plugin(RPCQuery, MethodCall)
|
register_stanza_plugin(RPCQuery, MethodCall)
|
||||||
register_stanza_plugin(RPCQuery, MethodResponse)
|
register_stanza_plugin(RPCQuery, MethodResponse)
|
||||||
|
|
||||||
self.xmpp.register_handler(
|
self.xmpp.register_handler(
|
||||||
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
|
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
|
||||||
self._handle_method_call)
|
self._handle_method_call)
|
||||||
)
|
)
|
||||||
self.xmpp.register_handler(
|
self.xmpp.register_handler(
|
||||||
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
|
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
|
||||||
self._handle_method_response)
|
self._handle_method_response)
|
||||||
)
|
)
|
||||||
self.xmpp.register_handler(
|
self.xmpp.register_handler(
|
||||||
Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)),
|
Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)),
|
||||||
self._handle_error)
|
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_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_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_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('jabber_rpc_error', self._on_jabber_rpc_error)
|
||||||
self.xmpp.add_event_handler('error', self._handle_error)
|
self.xmpp.add_event_handler('error', self._handle_error)
|
||||||
#self.activeCalls = []
|
#self.activeCalls = []
|
||||||
|
|
||||||
self.xmpp['xep_0030'].add_feature('jabber:iq:rpc')
|
self.xmpp['xep_0030'].add_feature('jabber:iq:rpc')
|
||||||
self.xmpp['xep_0030'].add_identity('automation','rpc')
|
self.xmpp['xep_0030'].add_identity('automation','rpc')
|
||||||
|
|
||||||
def make_iq_method_call(self, pto, pmethod, params):
|
def make_iq_method_call(self, pto, pmethod, params):
|
||||||
iq = self.xmpp.makeIqSet()
|
iq = self.xmpp.makeIqSet()
|
||||||
iq.attrib['to'] = pto
|
iq.attrib['to'] = pto
|
||||||
iq.attrib['from'] = self.xmpp.boundjid.full
|
iq.attrib['from'] = self.xmpp.boundjid.full
|
||||||
iq.enable('rpc_query')
|
iq.enable('rpc_query')
|
||||||
iq['rpc_query']['method_call']['method_name'] = pmethod
|
iq['rpc_query']['method_call']['method_name'] = pmethod
|
||||||
iq['rpc_query']['method_call']['params'] = params
|
iq['rpc_query']['method_call']['params'] = params
|
||||||
return iq;
|
return iq;
|
||||||
|
|
||||||
def make_iq_method_response(self, pid, pto, params):
|
def make_iq_method_response(self, pid, pto, params):
|
||||||
iq = self.xmpp.makeIqResult(pid)
|
iq = self.xmpp.makeIqResult(pid)
|
||||||
iq.attrib['to'] = pto
|
iq.attrib['to'] = pto
|
||||||
iq.attrib['from'] = self.xmpp.boundjid.full
|
iq.attrib['from'] = self.xmpp.boundjid.full
|
||||||
iq.enable('rpc_query')
|
iq.enable('rpc_query')
|
||||||
iq['rpc_query']['method_response']['params'] = params
|
iq['rpc_query']['method_response']['params'] = params
|
||||||
return iq
|
return iq
|
||||||
|
|
||||||
def make_iq_method_response_fault(self, pid, pto, params):
|
def make_iq_method_response_fault(self, pid, pto, params):
|
||||||
iq = self.xmpp.makeIqResult(pid)
|
iq = self.xmpp.makeIqResult(pid)
|
||||||
iq.attrib['to'] = pto
|
iq.attrib['to'] = pto
|
||||||
iq.attrib['from'] = self.xmpp.boundjid.full
|
iq.attrib['from'] = self.xmpp.boundjid.full
|
||||||
iq.enable('rpc_query')
|
iq.enable('rpc_query')
|
||||||
iq['rpc_query']['method_response']['params'] = None
|
iq['rpc_query']['method_response']['params'] = None
|
||||||
iq['rpc_query']['method_response']['fault'] = params
|
iq['rpc_query']['method_response']['fault'] = params
|
||||||
return iq
|
return iq
|
||||||
|
|
||||||
# def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition):
|
# def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition):
|
||||||
# iq = self.xmpp.makeIqError(pid)
|
# iq = self.xmpp.makeIqError(pid)
|
||||||
# iq.attrib['to'] = pto
|
# iq.attrib['to'] = pto
|
||||||
# iq.attrib['from'] = self.xmpp.boundjid.full
|
# iq.attrib['from'] = self.xmpp.boundjid.full
|
||||||
# iq['error']['code'] = code
|
# iq['error']['code'] = code
|
||||||
# iq['error']['type'] = type
|
# iq['error']['type'] = type
|
||||||
# iq['error']['condition'] = condition
|
# iq['error']['condition'] = condition
|
||||||
# iq['rpc_query']['method_call']['method_name'] = pmethod
|
# iq['rpc_query']['method_call']['method_name'] = pmethod
|
||||||
# iq['rpc_query']['method_call']['params'] = params
|
# iq['rpc_query']['method_call']['params'] = params
|
||||||
# return iq
|
# return iq
|
||||||
|
|
||||||
def _item_not_found(self, iq):
|
def _item_not_found(self, iq):
|
||||||
payload = iq.get_payload()
|
payload = iq.get_payload()
|
||||||
iq.reply().error().set_payload(payload);
|
iq.reply().error().set_payload(payload);
|
||||||
iq['error']['code'] = '404'
|
iq['error']['code'] = '404'
|
||||||
iq['error']['type'] = 'cancel'
|
iq['error']['type'] = 'cancel'
|
||||||
iq['error']['condition'] = 'item-not-found'
|
iq['error']['condition'] = 'item-not-found'
|
||||||
return iq
|
return iq
|
||||||
|
|
||||||
def _undefined_condition(self, iq):
|
def _undefined_condition(self, iq):
|
||||||
payload = iq.get_payload()
|
payload = iq.get_payload()
|
||||||
iq.reply().error().set_payload(payload)
|
iq.reply().error().set_payload(payload)
|
||||||
iq['error']['code'] = '500'
|
iq['error']['code'] = '500'
|
||||||
iq['error']['type'] = 'cancel'
|
iq['error']['type'] = 'cancel'
|
||||||
iq['error']['condition'] = 'undefined-condition'
|
iq['error']['condition'] = 'undefined-condition'
|
||||||
return iq
|
return iq
|
||||||
|
|
||||||
def _forbidden(self, iq):
|
def _forbidden(self, iq):
|
||||||
payload = iq.get_payload()
|
payload = iq.get_payload()
|
||||||
iq.reply().error().set_payload(payload)
|
iq.reply().error().set_payload(payload)
|
||||||
iq['error']['code'] = '403'
|
iq['error']['code'] = '403'
|
||||||
iq['error']['type'] = 'auth'
|
iq['error']['type'] = 'auth'
|
||||||
iq['error']['condition'] = 'forbidden'
|
iq['error']['condition'] = 'forbidden'
|
||||||
return iq
|
return iq
|
||||||
|
|
||||||
def _recipient_unvailable(self, iq):
|
def _recipient_unvailable(self, iq):
|
||||||
payload = iq.get_payload()
|
payload = iq.get_payload()
|
||||||
iq.reply().error().set_payload(payload)
|
iq.reply().error().set_payload(payload)
|
||||||
iq['error']['code'] = '404'
|
iq['error']['code'] = '404'
|
||||||
iq['error']['type'] = 'wait'
|
iq['error']['type'] = 'wait'
|
||||||
iq['error']['condition'] = 'recipient-unavailable'
|
iq['error']['condition'] = 'recipient-unavailable'
|
||||||
return iq
|
return iq
|
||||||
|
|
||||||
def _handle_method_call(self, iq):
|
def _handle_method_call(self, iq):
|
||||||
type = iq['type']
|
type = iq['type']
|
||||||
if type == 'set':
|
if type == 'set':
|
||||||
log.debug("Incoming Jabber-RPC call from %s", iq['from'])
|
log.debug("Incoming Jabber-RPC call from %s", iq['from'])
|
||||||
self.xmpp.event('jabber_rpc_method_call', iq)
|
self.xmpp.event('jabber_rpc_method_call', iq)
|
||||||
else:
|
else:
|
||||||
if type == 'error' and ['rpc_query'] is None:
|
if type == 'error' and ['rpc_query'] is None:
|
||||||
self.handle_error(iq)
|
self.handle_error(iq)
|
||||||
else:
|
else:
|
||||||
log.debug("Incoming Jabber-RPC error from %s", iq['from'])
|
log.debug("Incoming Jabber-RPC error from %s", iq['from'])
|
||||||
self.xmpp.event('jabber_rpc_error', iq)
|
self.xmpp.event('jabber_rpc_error', iq)
|
||||||
|
|
||||||
def _handle_method_response(self, iq):
|
def _handle_method_response(self, iq):
|
||||||
if iq['rpc_query']['method_response']['fault'] is not None:
|
if iq['rpc_query']['method_response']['fault'] is not None:
|
||||||
log.debug("Incoming Jabber-RPC fault from %s", iq['from'])
|
log.debug("Incoming Jabber-RPC fault from %s", iq['from'])
|
||||||
#self._on_jabber_rpc_method_fault(iq)
|
#self._on_jabber_rpc_method_fault(iq)
|
||||||
self.xmpp.event('jabber_rpc_method_fault', iq)
|
self.xmpp.event('jabber_rpc_method_fault', iq)
|
||||||
else:
|
else:
|
||||||
log.debug("Incoming Jabber-RPC response from %s", iq['from'])
|
log.debug("Incoming Jabber-RPC response from %s", iq['from'])
|
||||||
self.xmpp.event('jabber_rpc_method_response', iq)
|
self.xmpp.event('jabber_rpc_method_response', iq)
|
||||||
|
|
||||||
def _handle_error(self, iq):
|
def _handle_error(self, iq):
|
||||||
print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq)
|
print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq)
|
||||||
print("#######################")
|
print("#######################")
|
||||||
print("### NOT IMPLEMENTED ###")
|
print("### NOT IMPLEMENTED ###")
|
||||||
print("#######################")
|
print("#######################")
|
||||||
|
|
||||||
def _on_jabber_rpc_method_call(self, iq, forwarded=False):
|
def _on_jabber_rpc_method_call(self, iq, forwarded=False):
|
||||||
"""
|
"""
|
||||||
A default handler for Jabber-RPC method call. If another
|
A default handler for Jabber-RPC method call. If another
|
||||||
handler is registered, this one will defer and not run.
|
handler is registered, this one will defer and not run.
|
||||||
|
|
||||||
If this handler is called by your own custom handler with
|
If this handler is called by your own custom handler with
|
||||||
forwarded set to True, then it will run as normal.
|
forwarded set to True, then it will run as normal.
|
||||||
"""
|
"""
|
||||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_call') > 1:
|
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_call') > 1:
|
||||||
return
|
return
|
||||||
# Reply with error by default
|
# Reply with error by default
|
||||||
error = self.client.plugin['xep_0009']._item_not_found(iq)
|
error = self.client.plugin['xep_0009']._item_not_found(iq)
|
||||||
error.send()
|
error.send()
|
||||||
|
|
||||||
def _on_jabber_rpc_method_response(self, iq, forwarded=False):
|
def _on_jabber_rpc_method_response(self, iq, forwarded=False):
|
||||||
"""
|
"""
|
||||||
A default handler for Jabber-RPC method response. If another
|
A default handler for Jabber-RPC method response. If another
|
||||||
handler is registered, this one will defer and not run.
|
handler is registered, this one will defer and not run.
|
||||||
|
|
||||||
If this handler is called by your own custom handler with
|
If this handler is called by your own custom handler with
|
||||||
forwarded set to True, then it will run as normal.
|
forwarded set to True, then it will run as normal.
|
||||||
"""
|
"""
|
||||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_response') > 1:
|
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_response') > 1:
|
||||||
return
|
return
|
||||||
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
|
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
|
||||||
error.send()
|
error.send()
|
||||||
|
|
||||||
def _on_jabber_rpc_method_fault(self, iq, forwarded=False):
|
def _on_jabber_rpc_method_fault(self, iq, forwarded=False):
|
||||||
"""
|
"""
|
||||||
A default handler for Jabber-RPC fault response. If another
|
A default handler for Jabber-RPC fault response. If another
|
||||||
handler is registered, this one will defer and not run.
|
handler is registered, this one will defer and not run.
|
||||||
|
|
||||||
If this handler is called by your own custom handler with
|
If this handler is called by your own custom handler with
|
||||||
forwarded set to True, then it will run as normal.
|
forwarded set to True, then it will run as normal.
|
||||||
"""
|
"""
|
||||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_fault') > 1:
|
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_fault') > 1:
|
||||||
return
|
return
|
||||||
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
|
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
|
||||||
error.send()
|
error.send()
|
||||||
|
|
||||||
def _on_jabber_rpc_error(self, iq, forwarded=False):
|
def _on_jabber_rpc_error(self, iq, forwarded=False):
|
||||||
"""
|
"""
|
||||||
A default handler for Jabber-RPC error response. If another
|
A default handler for Jabber-RPC error response. If another
|
||||||
handler is registered, this one will defer and not run.
|
handler is registered, this one will defer and not run.
|
||||||
|
|
||||||
If this handler is called by your own custom handler with
|
If this handler is called by your own custom handler with
|
||||||
forwarded set to True, then it will run as normal.
|
forwarded set to True, then it will run as normal.
|
||||||
"""
|
"""
|
||||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_error') > 1:
|
if not forwarded and self.xmpp.event_handled('jabber_rpc_error') > 1:
|
||||||
return
|
return
|
||||||
error = self.client.plugin['xep_0009']._recpient_unavailable(iq, iq.get_payload())
|
error = self.client.plugin['xep_0009']._recpient_unavailable(iq, iq.get_payload())
|
||||||
error.send()
|
error.send()
|
||||||
|
|
||||||
def _send_fault(self, iq, fault_xml): #
|
def _send_fault(self, iq, fault_xml): #
|
||||||
fault = self.make_iq_method_response_fault(iq['id'], iq['from'], fault_xml)
|
fault = self.make_iq_method_response_fault(iq['id'], iq['from'], fault_xml)
|
||||||
fault.send()
|
fault.send()
|
||||||
|
|
||||||
def _send_error(self, iq):
|
def _send_error(self, iq):
|
||||||
print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq)
|
print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq)
|
||||||
print("#######################")
|
print("#######################")
|
||||||
print("### NOT IMPLEMENTED ###")
|
print("### NOT IMPLEMENTED ###")
|
||||||
print("#######################")
|
print("#######################")
|
||||||
|
|
||||||
def _extract_method(self, stanza):
|
def _extract_method(self, stanza):
|
||||||
xml = ET.fromstring("%s" % stanza)
|
xml = ET.fromstring("%s" % stanza)
|
||||||
return xml.find("./methodCall/methodName").text
|
return xml.find("./methodCall/methodName").text
|
||||||
|
@ -1,156 +1,156 @@
|
|||||||
"""
|
"""
|
||||||
Slixmpp: The Slick XMPP Library
|
Slixmpp: The Slick XMPP Library
|
||||||
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
This file is part of Slixmpp.
|
This file is part of Slixmpp.
|
||||||
|
|
||||||
See the file LICENSE for copying permission.
|
See the file LICENSE for copying permission.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from slixmpp.plugins import BasePlugin, register_plugin
|
from slixmpp.plugins import BasePlugin, register_plugin
|
||||||
from slixmpp import Iq
|
from slixmpp import Iq
|
||||||
from slixmpp.exceptions import XMPPError
|
from slixmpp.exceptions import XMPPError
|
||||||
from slixmpp.xmlstream import JID, register_stanza_plugin
|
from slixmpp.xmlstream import JID, register_stanza_plugin
|
||||||
from slixmpp.xmlstream.handler import Callback
|
from slixmpp.xmlstream.handler import Callback
|
||||||
from slixmpp.xmlstream.matcher import StanzaPath
|
from slixmpp.xmlstream.matcher import StanzaPath
|
||||||
from slixmpp.plugins.xep_0012 import stanza, LastActivity
|
from slixmpp.plugins.xep_0012 import stanza, LastActivity
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class XEP_0012(BasePlugin):
|
class XEP_0012(BasePlugin):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
XEP-0012 Last Activity
|
XEP-0012 Last Activity
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = 'xep_0012'
|
name = 'xep_0012'
|
||||||
description = 'XEP-0012: Last Activity'
|
description = 'XEP-0012: Last Activity'
|
||||||
dependencies = set(['xep_0030'])
|
dependencies = set(['xep_0030'])
|
||||||
stanza = stanza
|
stanza = stanza
|
||||||
|
|
||||||
def plugin_init(self):
|
def plugin_init(self):
|
||||||
register_stanza_plugin(Iq, LastActivity)
|
register_stanza_plugin(Iq, LastActivity)
|
||||||
|
|
||||||
self._last_activities = {}
|
self._last_activities = {}
|
||||||
|
|
||||||
self.xmpp.register_handler(
|
self.xmpp.register_handler(
|
||||||
Callback('Last Activity',
|
Callback('Last Activity',
|
||||||
StanzaPath('iq@type=get/last_activity'),
|
StanzaPath('iq@type=get/last_activity'),
|
||||||
self._handle_get_last_activity))
|
self._handle_get_last_activity))
|
||||||
|
|
||||||
self.api.register(self._default_get_last_activity,
|
self.api.register(self._default_get_last_activity,
|
||||||
'get_last_activity',
|
'get_last_activity',
|
||||||
default=True)
|
default=True)
|
||||||
self.api.register(self._default_set_last_activity,
|
self.api.register(self._default_set_last_activity,
|
||||||
'set_last_activity',
|
'set_last_activity',
|
||||||
default=True)
|
default=True)
|
||||||
self.api.register(self._default_del_last_activity,
|
self.api.register(self._default_del_last_activity,
|
||||||
'del_last_activity',
|
'del_last_activity',
|
||||||
default=True)
|
default=True)
|
||||||
|
|
||||||
def plugin_end(self):
|
def plugin_end(self):
|
||||||
self.xmpp.remove_handler('Last Activity')
|
self.xmpp.remove_handler('Last Activity')
|
||||||
self.xmpp['xep_0030'].del_feature(feature='jabber:iq:last')
|
self.xmpp['xep_0030'].del_feature(feature='jabber:iq:last')
|
||||||
|
|
||||||
def session_bind(self, jid):
|
def session_bind(self, jid):
|
||||||
self.xmpp['xep_0030'].add_feature('jabber:iq:last')
|
self.xmpp['xep_0030'].add_feature('jabber:iq:last')
|
||||||
|
|
||||||
def begin_idle(self, jid=None, status=None):
|
def begin_idle(self, jid=None, status=None):
|
||||||
self.set_last_activity(jid, 0, status)
|
self.set_last_activity(jid, 0, status)
|
||||||
|
|
||||||
def end_idle(self, jid=None):
|
def end_idle(self, jid=None):
|
||||||
self.del_last_activity(jid)
|
self.del_last_activity(jid)
|
||||||
|
|
||||||
def start_uptime(self, status=None):
|
def start_uptime(self, status=None):
|
||||||
self.set_last_activity(jid, 0, status)
|
self.set_last_activity(jid, 0, status)
|
||||||
|
|
||||||
def set_last_activity(self, jid=None, seconds=None, status=None):
|
def set_last_activity(self, jid=None, seconds=None, status=None):
|
||||||
self.api['set_last_activity'](jid, args={
|
self.api['set_last_activity'](jid, args={
|
||||||
'seconds': seconds,
|
'seconds': seconds,
|
||||||
'status': status})
|
'status': status})
|
||||||
|
|
||||||
def del_last_activity(self, jid):
|
def del_last_activity(self, jid):
|
||||||
self.api['del_last_activity'](jid)
|
self.api['del_last_activity'](jid)
|
||||||
|
|
||||||
def get_last_activity(self, jid, local=False, ifrom=None, timeout=None,
|
def get_last_activity(self, jid, local=False, ifrom=None, timeout=None,
|
||||||
callback=None, timeout_callback=None):
|
callback=None, timeout_callback=None):
|
||||||
if jid is not None and not isinstance(jid, JID):
|
if jid is not None and not isinstance(jid, JID):
|
||||||
jid = JID(jid)
|
jid = JID(jid)
|
||||||
|
|
||||||
if self.xmpp.is_component:
|
if self.xmpp.is_component:
|
||||||
if jid.domain == self.xmpp.boundjid.domain:
|
if jid.domain == self.xmpp.boundjid.domain:
|
||||||
local = True
|
local = True
|
||||||
else:
|
else:
|
||||||
if str(jid) == str(self.xmpp.boundjid):
|
if str(jid) == str(self.xmpp.boundjid):
|
||||||
local = True
|
local = True
|
||||||
jid = jid.full
|
jid = jid.full
|
||||||
|
|
||||||
if local or jid in (None, ''):
|
if local or jid in (None, ''):
|
||||||
log.debug("Looking up local last activity data for %s", jid)
|
log.debug("Looking up local last activity data for %s", jid)
|
||||||
return self.api['get_last_activity'](jid, None, ifrom, None)
|
return self.api['get_last_activity'](jid, None, ifrom, None)
|
||||||
|
|
||||||
iq = self.xmpp.Iq()
|
iq = self.xmpp.Iq()
|
||||||
iq['from'] = ifrom
|
iq['from'] = ifrom
|
||||||
iq['to'] = jid
|
iq['to'] = jid
|
||||||
iq['type'] = 'get'
|
iq['type'] = 'get'
|
||||||
iq.enable('last_activity')
|
iq.enable('last_activity')
|
||||||
return iq.send(timeout=timeout, callback=callback,
|
return iq.send(timeout=timeout, callback=callback,
|
||||||
timeout_callback=timeout_callback)
|
timeout_callback=timeout_callback)
|
||||||
|
|
||||||
def _handle_get_last_activity(self, iq):
|
def _handle_get_last_activity(self, iq):
|
||||||
log.debug("Received last activity query from " + \
|
log.debug("Received last activity query from " + \
|
||||||
"<%s> to <%s>.", iq['from'], iq['to'])
|
"<%s> to <%s>.", iq['from'], iq['to'])
|
||||||
reply = self.api['get_last_activity'](iq['to'], None, iq['from'], iq)
|
reply = self.api['get_last_activity'](iq['to'], None, iq['from'], iq)
|
||||||
reply.send()
|
reply.send()
|
||||||
|
|
||||||
# =================================================================
|
# =================================================================
|
||||||
# Default in-memory implementations for storing last activity data.
|
# Default in-memory implementations for storing last activity data.
|
||||||
# =================================================================
|
# =================================================================
|
||||||
|
|
||||||
def _default_set_last_activity(self, jid, node, ifrom, data):
|
def _default_set_last_activity(self, jid, node, ifrom, data):
|
||||||
seconds = data.get('seconds', None)
|
seconds = data.get('seconds', None)
|
||||||
if seconds is None:
|
if seconds is None:
|
||||||
seconds = 0
|
seconds = 0
|
||||||
|
|
||||||
status = data.get('status', None)
|
status = data.get('status', None)
|
||||||
if status is None:
|
if status is None:
|
||||||
status = ''
|
status = ''
|
||||||
|
|
||||||
self._last_activities[jid] = {
|
self._last_activities[jid] = {
|
||||||
'seconds': datetime.now() - timedelta(seconds=seconds),
|
'seconds': datetime.now() - timedelta(seconds=seconds),
|
||||||
'status': status}
|
'status': status}
|
||||||
|
|
||||||
def _default_del_last_activity(self, jid, node, ifrom, data):
|
def _default_del_last_activity(self, jid, node, ifrom, data):
|
||||||
if jid in self._last_activities:
|
if jid in self._last_activities:
|
||||||
del self._last_activities[jid]
|
del self._last_activities[jid]
|
||||||
|
|
||||||
def _default_get_last_activity(self, jid, node, ifrom, iq):
|
def _default_get_last_activity(self, jid, node, ifrom, iq):
|
||||||
if not isinstance(iq, Iq):
|
if not isinstance(iq, Iq):
|
||||||
reply = self.xmpp.Iq()
|
reply = self.xmpp.Iq()
|
||||||
else:
|
else:
|
||||||
iq.reply()
|
iq.reply()
|
||||||
reply = iq
|
reply = iq
|
||||||
|
|
||||||
if jid not in self._last_activities:
|
if jid not in self._last_activities:
|
||||||
raise XMPPError('service-unavailable')
|
raise XMPPError('service-unavailable')
|
||||||
|
|
||||||
bare = JID(jid).bare
|
bare = JID(jid).bare
|
||||||
|
|
||||||
if bare != self.xmpp.boundjid.bare:
|
if bare != self.xmpp.boundjid.bare:
|
||||||
if bare in self.xmpp.roster[jid]:
|
if bare in self.xmpp.roster[jid]:
|
||||||
sub = self.xmpp.roster[jid][bare]['subscription']
|
sub = self.xmpp.roster[jid][bare]['subscription']
|
||||||
if sub not in ('from', 'both'):
|
if sub not in ('from', 'both'):
|
||||||
raise XMPPError('forbidden')
|
raise XMPPError('forbidden')
|
||||||
|
|
||||||
td = datetime.now() - self._last_activities[jid]['seconds']
|
td = datetime.now() - self._last_activities[jid]['seconds']
|
||||||
seconds = td.seconds + td.days * 24 * 3600
|
seconds = td.seconds + td.days * 24 * 3600
|
||||||
status = self._last_activities[jid]['status']
|
status = self._last_activities[jid]['status']
|
||||||
|
|
||||||
reply['last_activity']['seconds'] = seconds
|
reply['last_activity']['seconds'] = seconds
|
||||||
reply['last_activity']['status'] = status
|
reply['last_activity']['status'] = status
|
||||||
|
|
||||||
return reply
|
return reply
|
||||||
|
@ -307,7 +307,7 @@ class XEP_0045(BasePlugin):
|
|||||||
if role not in ('moderator', 'participant', 'visitor', 'none'):
|
if role not in ('moderator', 'participant', 'visitor', 'none'):
|
||||||
raise TypeError
|
raise TypeError
|
||||||
query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
|
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)
|
query.append(item)
|
||||||
iq = self.xmpp.makeIqSet(query)
|
iq = self.xmpp.makeIqSet(query)
|
||||||
iq['to'] = room
|
iq['to'] = room
|
||||||
|
@ -206,7 +206,7 @@ class XEP_0065(base_plugin):
|
|||||||
# Though this should not be neccessary remove the closed session anyway
|
# Though this should not be neccessary remove the closed session anyway
|
||||||
with self._sessions_lock:
|
with self._sessions_lock:
|
||||||
if sid in self._sessions:
|
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)
|
'removed from _sessions by sock.close()') % sid)
|
||||||
del self._sessions[sid]
|
del self._sessions[sid]
|
||||||
|
|
||||||
|
@ -1,46 +1,46 @@
|
|||||||
"""
|
"""
|
||||||
Slixmpp: The Slick XMPP Library
|
Slixmpp: The Slick XMPP Library
|
||||||
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
This file is part of Slixmpp.
|
This file is part of Slixmpp.
|
||||||
|
|
||||||
See the file LICENSE for copying permission.
|
See the file LICENSE for copying permission.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from slixmpp.stanza import Error
|
from slixmpp.stanza import Error
|
||||||
from slixmpp.xmlstream import register_stanza_plugin
|
from slixmpp.xmlstream import register_stanza_plugin
|
||||||
from slixmpp.plugins import BasePlugin
|
from slixmpp.plugins import BasePlugin
|
||||||
from slixmpp.plugins.xep_0086 import stanza, LegacyError
|
from slixmpp.plugins.xep_0086 import stanza, LegacyError
|
||||||
|
|
||||||
|
|
||||||
class XEP_0086(BasePlugin):
|
class XEP_0086(BasePlugin):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
XEP-0086: Error Condition Mappings
|
XEP-0086: Error Condition Mappings
|
||||||
|
|
||||||
Older XMPP implementations used code based error messages, similar
|
Older XMPP implementations used code based error messages, similar
|
||||||
to HTTP response codes. Since then, error condition elements have
|
to HTTP response codes. Since then, error condition elements have
|
||||||
been introduced. XEP-0086 provides a mapping between the new
|
been introduced. XEP-0086 provides a mapping between the new
|
||||||
condition elements and a combination of error types and the older
|
condition elements and a combination of error types and the older
|
||||||
response codes.
|
response codes.
|
||||||
|
|
||||||
Also see <http://xmpp.org/extensions/xep-0086.html>.
|
Also see <http://xmpp.org/extensions/xep-0086.html>.
|
||||||
|
|
||||||
Configuration Values:
|
Configuration Values:
|
||||||
override -- Indicates if applying legacy error codes should
|
override -- Indicates if applying legacy error codes should
|
||||||
be done automatically. Defaults to True.
|
be done automatically. Defaults to True.
|
||||||
If False, then inserting legacy error codes can
|
If False, then inserting legacy error codes can
|
||||||
be done using:
|
be done using:
|
||||||
iq['error']['legacy']['condition'] = ...
|
iq['error']['legacy']['condition'] = ...
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = 'xep_0086'
|
name = 'xep_0086'
|
||||||
description = 'XEP-0086: Error Condition Mappings'
|
description = 'XEP-0086: Error Condition Mappings'
|
||||||
dependencies = set()
|
dependencies = set()
|
||||||
stanza = stanza
|
stanza = stanza
|
||||||
default_config = {
|
default_config = {
|
||||||
'override': True
|
'override': True
|
||||||
}
|
}
|
||||||
|
|
||||||
def plugin_init(self):
|
def plugin_init(self):
|
||||||
register_stanza_plugin(Error, LegacyError,
|
register_stanza_plugin(Error, LegacyError,
|
||||||
overrides=self.override)
|
overrides=self.override)
|
||||||
|
@ -129,7 +129,7 @@ class XEP_0153(BasePlugin):
|
|||||||
# Don't process vCard avatars for MUC occupants
|
# Don't process vCard avatars for MUC occupants
|
||||||
# since they all share the same bare JID.
|
# since they all share the same bare JID.
|
||||||
return
|
return
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
if not pres.match('presence/vcard_temp_update'):
|
if not pres.match('presence/vcard_temp_update'):
|
||||||
self.api['set_hash'](pres['from'], args=None)
|
self.api['set_hash'](pres['from'], args=None)
|
||||||
|
@ -1,98 +1,98 @@
|
|||||||
"""
|
"""
|
||||||
Slixmpp: The Slick XMPP Library
|
Slixmpp: The Slick XMPP Library
|
||||||
Copyright (C) 2010 Nathanael C. Fritz
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
This file is part of Slixmpp.
|
This file is part of Slixmpp.
|
||||||
|
|
||||||
See the file LICENSE for copying permission.
|
See the file LICENSE for copying permission.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from slixmpp.stanza.iq import Iq
|
from slixmpp.stanza.iq import Iq
|
||||||
from slixmpp.xmlstream import register_stanza_plugin
|
from slixmpp.xmlstream import register_stanza_plugin
|
||||||
from slixmpp.xmlstream.handler import Callback
|
from slixmpp.xmlstream.handler import Callback
|
||||||
from slixmpp.xmlstream.matcher import StanzaPath
|
from slixmpp.xmlstream.matcher import StanzaPath
|
||||||
from slixmpp.plugins import BasePlugin
|
from slixmpp.plugins import BasePlugin
|
||||||
from slixmpp.plugins import xep_0082
|
from slixmpp.plugins import xep_0082
|
||||||
from slixmpp.plugins.xep_0202 import stanza
|
from slixmpp.plugins.xep_0202 import stanza
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class XEP_0202(BasePlugin):
|
class XEP_0202(BasePlugin):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
XEP-0202: Entity Time
|
XEP-0202: Entity Time
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = 'xep_0202'
|
name = 'xep_0202'
|
||||||
description = 'XEP-0202: Entity Time'
|
description = 'XEP-0202: Entity Time'
|
||||||
dependencies = set(['xep_0030', 'xep_0082'])
|
dependencies = set(['xep_0030', 'xep_0082'])
|
||||||
stanza = stanza
|
stanza = stanza
|
||||||
default_config = {
|
default_config = {
|
||||||
#: As a default, respond to time requests with the
|
#: As a default, respond to time requests with the
|
||||||
#: local time returned by XEP-0082. However, a
|
#: local time returned by XEP-0082. However, a
|
||||||
#: custom function can be supplied which accepts
|
#: custom function can be supplied which accepts
|
||||||
#: the JID of the entity to query for the time.
|
#: the JID of the entity to query for the time.
|
||||||
'local_time': None,
|
'local_time': None,
|
||||||
'tz_offset': 0
|
'tz_offset': 0
|
||||||
}
|
}
|
||||||
|
|
||||||
def plugin_init(self):
|
def plugin_init(self):
|
||||||
"""Start the XEP-0203 plugin."""
|
"""Start the XEP-0203 plugin."""
|
||||||
|
|
||||||
if not self.local_time:
|
if not self.local_time:
|
||||||
def default_local_time(jid):
|
def default_local_time(jid):
|
||||||
return xep_0082.datetime(offset=self.tz_offset)
|
return xep_0082.datetime(offset=self.tz_offset)
|
||||||
|
|
||||||
self.local_time = default_local_time
|
self.local_time = default_local_time
|
||||||
|
|
||||||
self.xmpp.register_handler(
|
self.xmpp.register_handler(
|
||||||
Callback('Entity Time',
|
Callback('Entity Time',
|
||||||
StanzaPath('iq/entity_time'),
|
StanzaPath('iq/entity_time'),
|
||||||
self._handle_time_request))
|
self._handle_time_request))
|
||||||
register_stanza_plugin(Iq, stanza.EntityTime)
|
register_stanza_plugin(Iq, stanza.EntityTime)
|
||||||
|
|
||||||
def plugin_end(self):
|
def plugin_end(self):
|
||||||
self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:time')
|
self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:time')
|
||||||
self.xmpp.remove_handler('Entity Time')
|
self.xmpp.remove_handler('Entity Time')
|
||||||
|
|
||||||
def session_bind(self, jid):
|
def session_bind(self, jid):
|
||||||
self.xmpp['xep_0030'].add_feature('urn:xmpp:time')
|
self.xmpp['xep_0030'].add_feature('urn:xmpp:time')
|
||||||
|
|
||||||
def _handle_time_request(self, iq):
|
def _handle_time_request(self, iq):
|
||||||
"""
|
"""
|
||||||
Respond to a request for the local time.
|
Respond to a request for the local time.
|
||||||
|
|
||||||
The time is taken from self.local_time(), which may be replaced
|
The time is taken from self.local_time(), which may be replaced
|
||||||
during plugin configuration with a function that maps JIDs to
|
during plugin configuration with a function that maps JIDs to
|
||||||
times.
|
times.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
iq -- The Iq time request stanza.
|
iq -- The Iq time request stanza.
|
||||||
"""
|
"""
|
||||||
iq.reply()
|
iq.reply()
|
||||||
iq['entity_time']['time'] = self.local_time(iq['to'])
|
iq['entity_time']['time'] = self.local_time(iq['to'])
|
||||||
iq.send()
|
iq.send()
|
||||||
|
|
||||||
def get_entity_time(self, to, ifrom=None, **iqargs):
|
def get_entity_time(self, to, ifrom=None, **iqargs):
|
||||||
"""
|
"""
|
||||||
Request the time from another entity.
|
Request the time from another entity.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
to -- JID of the entity to query.
|
to -- JID of the entity to query.
|
||||||
ifrom -- Specifiy the sender's JID.
|
ifrom -- Specifiy the sender's JID.
|
||||||
block -- If true, block and wait for the stanzas' reply.
|
block -- If true, block and wait for the stanzas' reply.
|
||||||
timeout -- The time in seconds to block while waiting for
|
timeout -- The time in seconds to block while waiting for
|
||||||
a reply. If None, then wait indefinitely.
|
a reply. If None, then wait indefinitely.
|
||||||
callback -- Optional callback to execute when a reply is
|
callback -- Optional callback to execute when a reply is
|
||||||
received instead of blocking and waiting for
|
received instead of blocking and waiting for
|
||||||
the reply.
|
the reply.
|
||||||
"""
|
"""
|
||||||
iq = self.xmpp.Iq()
|
iq = self.xmpp.Iq()
|
||||||
iq['type'] = 'get'
|
iq['type'] = 'get'
|
||||||
iq['to'] = to
|
iq['to'] = to
|
||||||
iq['from'] = ifrom
|
iq['from'] = ifrom
|
||||||
iq.enable('entity_time')
|
iq.enable('entity_time')
|
||||||
return iq.send(**iqargs)
|
return iq.send(**iqargs)
|
||||||
|
@ -13,9 +13,9 @@ import logging
|
|||||||
|
|
||||||
class Device(object):
|
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
|
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:
|
specific devices, but it must implement the functions:
|
||||||
has_field
|
has_field
|
||||||
request_fields
|
request_fields
|
||||||
@ -38,19 +38,19 @@ class Device(object):
|
|||||||
Returns true if the supplied field name exists in this device.
|
Returns true if the supplied field name exists in this device.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
field -- The field name
|
field -- The field name
|
||||||
"""
|
"""
|
||||||
if field in self.fields.keys():
|
if field in self.fields.keys():
|
||||||
return True;
|
return True;
|
||||||
return False;
|
return False;
|
||||||
|
|
||||||
def refresh(self, fields):
|
def refresh(self, fields):
|
||||||
"""
|
"""
|
||||||
override method to do the refresh work
|
override method to do the refresh work
|
||||||
refresh values from hardware or other
|
refresh values from hardware or other
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def request_fields(self, fields, flags, session, callback):
|
def request_fields(self, fields, flags, session, callback):
|
||||||
"""
|
"""
|
||||||
@ -65,7 +65,7 @@ class Device(object):
|
|||||||
Formatted as a dictionary like { "flag name": "flag value" ... }
|
Formatted as a dictionary like { "flag name": "flag value" ... }
|
||||||
session -- Session id, only used in the callback as identifier
|
session -- Session id, only used in the callback as identifier
|
||||||
callback -- Callback function to call when data is available.
|
callback -- Callback function to call when data is available.
|
||||||
|
|
||||||
The callback function must support the following arguments:
|
The callback function must support the following arguments:
|
||||||
|
|
||||||
session -- Session id, as supplied in the request_fields call
|
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:
|
result -- The current result status of the readout. Valid values are:
|
||||||
"error" - Readout failed.
|
"error" - Readout failed.
|
||||||
"fields" - Contains readout data.
|
"fields" - Contains readout data.
|
||||||
"done" - Indicates that the readout is complete. May contain
|
"done" - Indicates that the readout is complete. May contain
|
||||||
readout data.
|
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:
|
The readout data. Structured as a dictionary:
|
||||||
{
|
{
|
||||||
timestamp: timestamp for this datablock,
|
timestamp: timestamp for this datablock,
|
||||||
fields: list of field dictionary (one per readout field).
|
fields: list of field dictionary (one per readout field).
|
||||||
readout field dictionary format:
|
readout field dictionary format:
|
||||||
@ -89,10 +89,10 @@ class Device(object):
|
|||||||
dataType: The datatype of the field. Only applies to type enum.
|
dataType: The datatype of the field. Only applies to type enum.
|
||||||
flags: [optional] data classifier flags for the field, e.g. momentary
|
flags: [optional] data classifier flags for the field, e.g. momentary
|
||||||
Formatted as a dictionary like { "flag name": "flag value" ... }
|
Formatted as a dictionary like { "flag name": "flag value" ... }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error_msg -- [optional] Only applies when result == "error".
|
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)
|
logging.debug("request_fields called looking for fields %s",fields)
|
||||||
@ -125,11 +125,11 @@ class Device(object):
|
|||||||
field_block = [];
|
field_block = [];
|
||||||
for f in self.momentary_data:
|
for f in self.momentary_data:
|
||||||
if f in fields:
|
if f in fields:
|
||||||
field_block.append({"name": f,
|
field_block.append({"name": f,
|
||||||
"type": self.fields[f]["type"],
|
"type": self.fields[f]["type"],
|
||||||
"unit": self.fields[f]["unit"],
|
"unit": self.fields[f]["unit"],
|
||||||
"dataType": self.fields[f]["dataType"],
|
"dataType": self.fields[f]["dataType"],
|
||||||
"value": self.momentary_data[f]["value"],
|
"value": self.momentary_data[f]["value"],
|
||||||
"flags": self.momentary_data[f]["flags"]});
|
"flags": self.momentary_data[f]["flags"]});
|
||||||
ts_block["timestamp"] = timestamp;
|
ts_block["timestamp"] = timestamp;
|
||||||
ts_block["fields"] = field_block;
|
ts_block["fields"] = field_block;
|
||||||
@ -142,25 +142,25 @@ class Device(object):
|
|||||||
|
|
||||||
for ts in sorted(self.timestamp_data.keys()):
|
for ts in sorted(self.timestamp_data.keys()):
|
||||||
tsdt = datetime.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%S")
|
tsdt = datetime.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%S")
|
||||||
if not from_flag is None:
|
if not from_flag is None:
|
||||||
if tsdt < from_flag:
|
if tsdt < from_flag:
|
||||||
#print (str(tsdt) + " < " + str(from_flag))
|
#print (str(tsdt) + " < " + str(from_flag))
|
||||||
continue
|
continue
|
||||||
if not to_flag is None:
|
if not to_flag is None:
|
||||||
if tsdt > to_flag:
|
if tsdt > to_flag:
|
||||||
#print (str(tsdt) + " > " + str(to_flag))
|
#print (str(tsdt) + " > " + str(to_flag))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ts_block = {};
|
ts_block = {};
|
||||||
field_block = [];
|
field_block = [];
|
||||||
|
|
||||||
for f in self.timestamp_data[ts]:
|
for f in self.timestamp_data[ts]:
|
||||||
if f in fields:
|
if f in fields:
|
||||||
field_block.append({"name": f,
|
field_block.append({"name": f,
|
||||||
"type": self.fields[f]["type"],
|
"type": self.fields[f]["type"],
|
||||||
"unit": self.fields[f]["unit"],
|
"unit": self.fields[f]["unit"],
|
||||||
"dataType": self.fields[f]["dataType"],
|
"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"]});
|
"flags": self.timestamp_data[ts][f]["flags"]});
|
||||||
|
|
||||||
ts_block["timestamp"] = ts;
|
ts_block["timestamp"] = ts;
|
||||||
@ -171,7 +171,7 @@ class Device(object):
|
|||||||
def _datetime_flag_parser(self, flags, flagname):
|
def _datetime_flag_parser(self, flags, flagname):
|
||||||
if not flagname in flags:
|
if not flagname in flags:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
dt = None
|
dt = None
|
||||||
try:
|
try:
|
||||||
dt = datetime.datetime.strptime(flags[flagname], "%Y-%m-%dT%H:%M:%S")
|
dt = datetime.datetime.strptime(flags[flagname], "%Y-%m-%dT%H:%M:%S")
|
||||||
@ -242,7 +242,7 @@ class Device(object):
|
|||||||
return False;
|
return False;
|
||||||
if flags is None:
|
if flags is None:
|
||||||
flags = {};
|
flags = {};
|
||||||
|
|
||||||
flags["momentary"] = "true"
|
flags["momentary"] = "true"
|
||||||
self.momentary_data[name] = {"value": value, "flags": flags};
|
self.momentary_data[name] = {"value": value, "flags": flags};
|
||||||
return True;
|
return True;
|
||||||
|
@ -29,12 +29,12 @@ log = logging.getLogger(__name__)
|
|||||||
class XEP_0323(BasePlugin):
|
class XEP_0323(BasePlugin):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
XEP-0323: IoT Sensor Data
|
XEP-0323: IoT Sensor Data
|
||||||
|
|
||||||
|
|
||||||
This XEP provides the underlying architecture, basic operations and data
|
This XEP provides the underlying architecture, basic operations and data
|
||||||
structures for sensor data communication over XMPP networks. It includes
|
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.
|
in underlying technologies.
|
||||||
|
|
||||||
Also see <http://xmpp.org/extensions/xep-0323.html>
|
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:Rejected -- Received a reject from sensor for a request
|
||||||
Sensordata Event:Cancelled -- Received a cancel confirm from sensor
|
Sensordata Event:Cancelled -- Received a cancel confirm from sensor
|
||||||
Sensordata Event:Fields -- Received fields from sensor for a request
|
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
|
the sensor can split up its response in
|
||||||
multiple messages.
|
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.
|
for a request. Typically a comm timeout.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@ -69,7 +69,7 @@ class XEP_0323(BasePlugin):
|
|||||||
relevant to a request's session. This dictionary is used
|
relevant to a request's session. This dictionary is used
|
||||||
both by the client and sensor side. On client side, seqnr
|
both by the client and sensor side. On client side, seqnr
|
||||||
is used as key, while on sensor side, a session_id is used
|
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.
|
one instance can be both client and sensor.
|
||||||
Sensor side
|
Sensor side
|
||||||
-----------
|
-----------
|
||||||
@ -89,12 +89,12 @@ class XEP_0323(BasePlugin):
|
|||||||
|
|
||||||
Sensor side
|
Sensor side
|
||||||
-----------
|
-----------
|
||||||
register_node -- Register a sensor as available from this XMPP
|
register_node -- Register a sensor as available from this XMPP
|
||||||
instance.
|
instance.
|
||||||
|
|
||||||
Client side
|
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
|
sensors. Non-blocking, a callback function will
|
||||||
be called when data is available.
|
be called when data is available.
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ class XEP_0323(BasePlugin):
|
|||||||
|
|
||||||
name = 'xep_0323'
|
name = 'xep_0323'
|
||||||
description = 'XEP-0323 Internet of Things - Sensor Data'
|
description = 'XEP-0323 Internet of Things - Sensor Data'
|
||||||
dependencies = set(['xep_0030'])
|
dependencies = set(['xep_0030'])
|
||||||
stanza = stanza
|
stanza = stanza
|
||||||
|
|
||||||
|
|
||||||
@ -198,9 +198,9 @@ class XEP_0323(BasePlugin):
|
|||||||
def register_node(self, nodeId, device, commTimeout, sourceId=None, cacheType=None):
|
def register_node(self, nodeId, device, commTimeout, sourceId=None, cacheType=None):
|
||||||
"""
|
"""
|
||||||
Register a sensor/device as available for serving of data through this XMPP
|
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:
|
specific devices, but it must implement the functions:
|
||||||
has_field
|
has_field
|
||||||
request_fields
|
request_fields
|
||||||
@ -212,11 +212,11 @@ class XEP_0323(BasePlugin):
|
|||||||
commTimeout -- Time in seconds to wait between each callback from device during
|
commTimeout -- Time in seconds to wait between each callback from device during
|
||||||
a data readout. Float.
|
a data readout. Float.
|
||||||
sourceId -- [optional] identifying the data source controlling the device
|
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,
|
"commTimeout": commTimeout,
|
||||||
"sourceId": sourceId,
|
"sourceId": sourceId,
|
||||||
"cacheType": cacheType};
|
"cacheType": cacheType};
|
||||||
|
|
||||||
def _set_authenticated(self, auth=''):
|
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.
|
Event handler for reception of an Iq with req - this is a request.
|
||||||
|
|
||||||
Verifies that
|
Verifies that
|
||||||
- all the requested nodes are available
|
- 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
|
one of the nodes
|
||||||
|
|
||||||
If the request passes verification, an accept response is sent, and
|
If the request passes verification, an accept response is sent, and
|
||||||
@ -331,12 +331,12 @@ class XEP_0323(BasePlugin):
|
|||||||
iq['type'] = 'error';
|
iq['type'] = 'error';
|
||||||
iq['rejected']['seqnr'] = seqnr;
|
iq['rejected']['seqnr'] = seqnr;
|
||||||
iq['rejected']['error'] = error_msg;
|
iq['rejected']['error'] = error_msg;
|
||||||
iq.send(block=False);
|
iq.send(block=False);
|
||||||
|
|
||||||
def _threaded_node_request(self, session, process_fields, flags):
|
def _threaded_node_request(self, session, process_fields, flags):
|
||||||
"""
|
"""
|
||||||
Helper function to handle the device readouts in a separate thread.
|
Helper function to handle the device readouts in a separate thread.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
session -- The request session id
|
session -- The request session id
|
||||||
process_fields -- The fields to request from the devices
|
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" ... }
|
Formatted as a dictionary like { "flag name": "flag value" ... }
|
||||||
"""
|
"""
|
||||||
for node in self.sessions[session]["node_list"]:
|
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"]:
|
for node in self.sessions[session]["node_list"]:
|
||||||
timer = TimerReset(self.nodes[node]['commTimeout'], self._event_comm_timeout, args=(session, node));
|
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);
|
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):
|
def _event_comm_timeout(self, session, nodeId):
|
||||||
"""
|
"""
|
||||||
Triggered if any of the readout operations timeout.
|
Triggered if any of the readout operations timeout.
|
||||||
Sends a failure message back to the client, stops communicating
|
Sends a failure message back to the client, stops communicating
|
||||||
with the failing device.
|
with the failing device.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
session -- The request session id
|
session -- The request session id
|
||||||
nodeId -- The id of the device which timed out
|
nodeId -- The id of the device which timed out
|
||||||
@ -366,7 +366,7 @@ class XEP_0323(BasePlugin):
|
|||||||
msg = self.xmpp.Message();
|
msg = self.xmpp.Message();
|
||||||
msg['from'] = self.sessions[session]['to'];
|
msg['from'] = self.sessions[session]['to'];
|
||||||
msg['to'] = self.sessions[session]['from'];
|
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']['text'] = "Timeout";
|
||||||
msg['failure']['error']['nodeId'] = nodeId;
|
msg['failure']['error']['nodeId'] = nodeId;
|
||||||
msg['failure']['error']['timestamp'] = datetime.datetime.now().replace(microsecond=0).isoformat();
|
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);
|
self._threaded_node_request(session, process_fields, req_flags);
|
||||||
|
|
||||||
def _all_nodes_done(self, session):
|
def _all_nodes_done(self, session):
|
||||||
"""
|
"""
|
||||||
Checks wheter all devices are done replying to the readout.
|
Checks wheter all devices are done replying to the readout.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
session -- The request session id
|
session -- The request session id
|
||||||
"""
|
"""
|
||||||
@ -415,22 +415,22 @@ class XEP_0323(BasePlugin):
|
|||||||
return True;
|
return True;
|
||||||
|
|
||||||
def _device_field_request_callback(self, session, nodeId, result, timestamp_block, error_msg=None):
|
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.
|
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.
|
the timeout timer for the device.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
session -- The request session id
|
session -- The request session id
|
||||||
nodeId -- The device id which initiated the callback
|
nodeId -- The device id which initiated the callback
|
||||||
result -- The current result status of the readout. Valid values are:
|
result -- The current result status of the readout. Valid values are:
|
||||||
"error" - Readout failed.
|
"error" - Readout failed.
|
||||||
"fields" - Contains readout data.
|
"fields" - Contains readout data.
|
||||||
"done" - Indicates that the readout is complete. May contain
|
"done" - Indicates that the readout is complete. May contain
|
||||||
readout data.
|
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:
|
The readout data. Structured as a dictionary:
|
||||||
{
|
{
|
||||||
timestamp: timestamp for this datablock,
|
timestamp: timestamp for this datablock,
|
||||||
fields: list of field dictionary (one per readout field).
|
fields: list of field dictionary (one per readout field).
|
||||||
readout field dictionary format:
|
readout field dictionary format:
|
||||||
@ -442,7 +442,7 @@ class XEP_0323(BasePlugin):
|
|||||||
dataType: The datatype of the field. Only applies to type enum.
|
dataType: The datatype of the field. Only applies to type enum.
|
||||||
flags: [optional] data classifier flags for the field, e.g. momentary
|
flags: [optional] data classifier flags for the field, e.g. momentary
|
||||||
Formatted as a dictionary like { "flag name": "flag value" ... }
|
Formatted as a dictionary like { "flag name": "flag value" ... }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error_msg -- [optional] Only applies when result == "error".
|
error_msg -- [optional] Only applies when result == "error".
|
||||||
Error details when a request failed.
|
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();
|
msg['failure']['error']['timestamp'] = datetime.datetime.now().replace(microsecond=0).isoformat();
|
||||||
|
|
||||||
# Drop communication with this device and check if we are done
|
# 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)):
|
if (self._all_nodes_done(session)):
|
||||||
msg['failure']['done'] = 'true';
|
msg['failure']['done'] = 'true';
|
||||||
# The session is complete, delete it
|
# The session is complete, delete it
|
||||||
@ -481,11 +481,11 @@ class XEP_0323(BasePlugin):
|
|||||||
ts = node.add_timestamp(timestamp_block["timestamp"]);
|
ts = node.add_timestamp(timestamp_block["timestamp"]);
|
||||||
|
|
||||||
for f in timestamp_block["fields"]:
|
for f in timestamp_block["fields"]:
|
||||||
data = ts.add_data( typename=f['type'],
|
data = ts.add_data( typename=f['type'],
|
||||||
name=f['name'],
|
name=f['name'],
|
||||||
value=f['value'],
|
value=f['value'],
|
||||||
unit=f['unit'],
|
unit=f['unit'],
|
||||||
dataType=f['dataType'],
|
dataType=f['dataType'],
|
||||||
flags=f['flags']);
|
flags=f['flags']);
|
||||||
|
|
||||||
if result == "done":
|
if result == "done":
|
||||||
@ -503,7 +503,7 @@ class XEP_0323(BasePlugin):
|
|||||||
msg.send();
|
msg.send();
|
||||||
|
|
||||||
def _handle_event_cancel(self, iq):
|
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. """
|
Delete the session and confirm. """
|
||||||
|
|
||||||
seqnr = iq['cancel']['seqnr'];
|
seqnr = iq['cancel']['seqnr'];
|
||||||
@ -518,8 +518,8 @@ class XEP_0323(BasePlugin):
|
|||||||
iq.reply();
|
iq.reply();
|
||||||
iq['type'] = 'result';
|
iq['type'] = 'result';
|
||||||
iq['cancelled']['seqnr'] = seqnr;
|
iq['cancelled']['seqnr'] = seqnr;
|
||||||
iq.send(block=False);
|
iq.send(block=False);
|
||||||
|
|
||||||
# Delete session
|
# Delete session
|
||||||
del self.sessions[s]
|
del self.sessions[s]
|
||||||
return
|
return
|
||||||
@ -529,22 +529,22 @@ class XEP_0323(BasePlugin):
|
|||||||
iq['type'] = 'error';
|
iq['type'] = 'error';
|
||||||
iq['rejected']['seqnr'] = seqnr;
|
iq['rejected']['seqnr'] = seqnr;
|
||||||
iq['rejected']['error'] = "Cancel request received, no matching request is active.";
|
iq['rejected']['error'] = "Cancel request received, no matching request is active.";
|
||||||
iq.send(block=False);
|
iq.send(block=False);
|
||||||
|
|
||||||
# =================================================================
|
# =================================================================
|
||||||
# Client side (data retriever) API
|
# Client side (data retriever) API
|
||||||
|
|
||||||
def request_data(self, from_jid, to_jid, callback, nodeIds=None, fields=None, flags=None):
|
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.
|
Called on the client side to initiade a data readout.
|
||||||
Composes a message with the request and sends it to the device(s).
|
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.
|
Does not block, the callback will be called when data is available.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
from_jid -- The jid of the requester
|
from_jid -- The jid of the requester
|
||||||
to_jid -- The jid of the device(s)
|
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:
|
The callback function must support the following arguments:
|
||||||
|
|
||||||
from_jid -- The jid of the responding device(s)
|
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
|
The timestamp of data in this callback. One callback will only
|
||||||
contain data from one timestamp.
|
contain data from one timestamp.
|
||||||
fields -- [optional] Mandatory when result == "fields".
|
fields -- [optional] Mandatory when result == "fields".
|
||||||
List of field dictionaries representing the readout data.
|
List of field dictionaries representing the readout data.
|
||||||
Dictionary format:
|
Dictionary format:
|
||||||
{
|
{
|
||||||
typename: The field type (numeric, boolean, dateTime, timeSpan, string, enum)
|
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.
|
dataType: The datatype of the field. Only applies to type enum.
|
||||||
flags: [optional] data classifier flags for the field, e.g. momentary.
|
flags: [optional] data classifier flags for the field, e.g. momentary.
|
||||||
Formatted as a dictionary like { "flag name": "flag value" ... }
|
Formatted as a dictionary like { "flag name": "flag value" ... }
|
||||||
}
|
}
|
||||||
|
|
||||||
error_msg -- [optional] Mandatory when result == "rejected" or "failure".
|
error_msg -- [optional] Mandatory when result == "rejected" or "failure".
|
||||||
Details about why the request is rejected or failed.
|
Details about why the request is rejected or failed.
|
||||||
"rejected" means that the request is stopped, but note that the
|
"rejected" means that the request is stopped, but note that the
|
||||||
request will continue even after a "failure". "failure" only means
|
request will continue even after a "failure". "failure" only means
|
||||||
that communication was stopped to that specific device, other
|
that communication was stopped to that specific device, other
|
||||||
device(s) (if any) will continue their readout.
|
device(s) (if any) will continue their readout.
|
||||||
@ -610,17 +610,17 @@ class XEP_0323(BasePlugin):
|
|||||||
iq['req']._set_flags(flags);
|
iq['req']._set_flags(flags);
|
||||||
|
|
||||||
self.sessions[seqnr] = {"from": iq['from'], "to": iq['to'], "seqnr": seqnr, "callback": callback};
|
self.sessions[seqnr] = {"from": iq['from'], "to": iq['to'], "seqnr": seqnr, "callback": callback};
|
||||||
iq.send(block=False);
|
iq.send(block=False);
|
||||||
|
|
||||||
return seqnr;
|
return seqnr;
|
||||||
|
|
||||||
def cancel_request(self, session):
|
def cancel_request(self, session):
|
||||||
"""
|
"""
|
||||||
Called on the client side to cancel a request for data readout.
|
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).
|
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.
|
confirmed.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
session -- The session id of the request to cancel
|
session -- The session id of the request to cancel
|
||||||
"""
|
"""
|
||||||
@ -651,7 +651,7 @@ class XEP_0323(BasePlugin):
|
|||||||
callback(from_jid=iq['from'], result=result);
|
callback(from_jid=iq['from'], result=result);
|
||||||
|
|
||||||
def _handle_event_rejected(self, iq):
|
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. """
|
Delete the session. """
|
||||||
seqnr = iq['rejected']['seqnr'];
|
seqnr = iq['rejected']['seqnr'];
|
||||||
callback = self.sessions[seqnr]["callback"];
|
callback = self.sessions[seqnr]["callback"];
|
||||||
@ -660,9 +660,9 @@ class XEP_0323(BasePlugin):
|
|||||||
del self.sessions[seqnr];
|
del self.sessions[seqnr];
|
||||||
|
|
||||||
def _handle_event_cancelled(self, iq):
|
def _handle_event_cancelled(self, iq):
|
||||||
"""
|
"""
|
||||||
Received Iq with cancelled - this is a cancel confirm.
|
Received Iq with cancelled - this is a cancel confirm.
|
||||||
Delete the session.
|
Delete the session.
|
||||||
"""
|
"""
|
||||||
#print("Got cancelled")
|
#print("Got cancelled")
|
||||||
seqnr = iq['cancelled']['seqnr'];
|
seqnr = iq['cancelled']['seqnr'];
|
||||||
@ -672,7 +672,7 @@ class XEP_0323(BasePlugin):
|
|||||||
del self.sessions[seqnr];
|
del self.sessions[seqnr];
|
||||||
|
|
||||||
def _handle_event_fields(self, msg):
|
def _handle_event_fields(self, msg):
|
||||||
"""
|
"""
|
||||||
Received Msg with fields - this is a data reponse to a request.
|
Received Msg with fields - this is a data reponse to a request.
|
||||||
If this is the last data block, issue a "done" callback.
|
If this is the last data block, issue a "done" callback.
|
||||||
"""
|
"""
|
||||||
@ -694,16 +694,16 @@ class XEP_0323(BasePlugin):
|
|||||||
fields.append(field_block);
|
fields.append(field_block);
|
||||||
|
|
||||||
callback(from_jid=msg['from'], result="fields", nodeId=node['nodeId'], timestamp=ts['value'], fields=fields);
|
callback(from_jid=msg['from'], result="fields", nodeId=node['nodeId'], timestamp=ts['value'], fields=fields);
|
||||||
|
|
||||||
if msg['fields']['done'] == "true":
|
if msg['fields']['done'] == "true":
|
||||||
callback(from_jid=msg['from'], result="done");
|
callback(from_jid=msg['from'], result="done");
|
||||||
# Session done
|
# Session done
|
||||||
del self.sessions[seqnr];
|
del self.sessions[seqnr];
|
||||||
|
|
||||||
def _handle_event_failure(self, msg):
|
def _handle_event_failure(self, msg):
|
||||||
"""
|
"""
|
||||||
Received Msg with failure - our request failed
|
Received Msg with failure - our request failed
|
||||||
Delete the session.
|
Delete the session.
|
||||||
"""
|
"""
|
||||||
seqnr = msg['failure']['seqnr'];
|
seqnr = msg['failure']['seqnr'];
|
||||||
callback = self.sessions[seqnr]["callback"];
|
callback = self.sessions[seqnr]["callback"];
|
||||||
@ -713,11 +713,11 @@ class XEP_0323(BasePlugin):
|
|||||||
del self.sessions[seqnr];
|
del self.sessions[seqnr];
|
||||||
|
|
||||||
def _handle_event_started(self, msg):
|
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'];
|
seqnr = msg['started']['seqnr'];
|
||||||
callback = self.sessions[seqnr]["callback"];
|
callback = self.sessions[seqnr]["callback"];
|
||||||
callback(from_jid=msg['from'], result="started");
|
callback(from_jid=msg['from'], result="started");
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,14 +20,14 @@ class Sensordata(ElementBase):
|
|||||||
interfaces = set(tuple())
|
interfaces = set(tuple())
|
||||||
|
|
||||||
class FieldTypes():
|
class FieldTypes():
|
||||||
"""
|
"""
|
||||||
All field types are optional booleans that default to False
|
All field types are optional booleans that default to False
|
||||||
"""
|
"""
|
||||||
field_types = set([ 'momentary','peak','status','computed','identity','historicalSecond','historicalMinute','historicalHour', \
|
field_types = set([ 'momentary','peak','status','computed','identity','historicalSecond','historicalMinute','historicalHour', \
|
||||||
'historicalDay','historicalWeek','historicalMonth','historicalQuarter','historicalYear','historicalOther'])
|
'historicalDay','historicalWeek','historicalMonth','historicalQuarter','historicalYear','historicalOther'])
|
||||||
|
|
||||||
class FieldStatus():
|
class FieldStatus():
|
||||||
"""
|
"""
|
||||||
All field statuses are optional booleans that default to False
|
All field statuses are optional booleans that default to False
|
||||||
"""
|
"""
|
||||||
field_status = set([ 'missing','automaticEstimate','manualEstimate','manualReadout','automaticReadout','timeOffset','warning','error', \
|
field_status = set([ 'missing','automaticEstimate','manualEstimate','manualReadout','automaticReadout','timeOffset','warning','error', \
|
||||||
@ -41,7 +41,7 @@ class Request(ElementBase):
|
|||||||
interfaces.update(FieldTypes.field_types);
|
interfaces.update(FieldTypes.field_types);
|
||||||
_flags = set(['serviceToken','deviceToken','userToken','from','to','when','historical','all']);
|
_flags = set(['serviceToken','deviceToken','userToken','from','to','when','historical','all']);
|
||||||
_flags.update(FieldTypes.field_types);
|
_flags.update(FieldTypes.field_types);
|
||||||
|
|
||||||
def __init__(self, xml=None, parent=None):
|
def __init__(self, xml=None, parent=None):
|
||||||
ElementBase.__init__(self, xml, parent);
|
ElementBase.__init__(self, xml, parent);
|
||||||
self._nodes = set()
|
self._nodes = set()
|
||||||
@ -64,8 +64,8 @@ class Request(ElementBase):
|
|||||||
|
|
||||||
def _get_flags(self):
|
def _get_flags(self):
|
||||||
"""
|
"""
|
||||||
Helper function for getting of flags. Returns all flags in
|
Helper function for getting of flags. Returns all flags in
|
||||||
dictionary format: { "flag name": "flag value" ... }
|
dictionary format: { "flag name": "flag value" ... }
|
||||||
"""
|
"""
|
||||||
flags = {};
|
flags = {};
|
||||||
for f in self._flags:
|
for f in self._flags:
|
||||||
@ -75,10 +75,10 @@ class Request(ElementBase):
|
|||||||
|
|
||||||
def _set_flags(self, flags):
|
def _set_flags(self, flags):
|
||||||
"""
|
"""
|
||||||
Helper function for setting of flags.
|
Helper function for setting of flags.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
|
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
|
||||||
"""
|
"""
|
||||||
for f in self._flags:
|
for f in self._flags:
|
||||||
if flags is not None and f in flags:
|
if flags is not None and f in flags:
|
||||||
@ -94,7 +94,7 @@ class Request(ElementBase):
|
|||||||
Arguments:
|
Arguments:
|
||||||
nodeId -- The ID for the node.
|
nodeId -- The ID for the node.
|
||||||
sourceId -- [optional] identifying the data source controlling the device
|
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:
|
if nodeId not in self._nodes:
|
||||||
self._nodes.add((nodeId))
|
self._nodes.add((nodeId))
|
||||||
@ -318,7 +318,7 @@ class Fields(ElementBase):
|
|||||||
Arguments:
|
Arguments:
|
||||||
nodeId -- The ID for the node.
|
nodeId -- The ID for the node.
|
||||||
sourceId -- [optional] identifying the data source controlling the device
|
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:
|
if nodeId not in self._nodes:
|
||||||
self._nodes.add((nodeId))
|
self._nodes.add((nodeId))
|
||||||
@ -411,7 +411,7 @@ class FieldsNode(ElementBase):
|
|||||||
|
|
||||||
def add_timestamp(self, timestamp, substanzas=None):
|
def add_timestamp(self, timestamp, substanzas=None):
|
||||||
"""
|
"""
|
||||||
Add a new timestamp element.
|
Add a new timestamp element.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
timestamp -- The timestamp in ISO format.
|
timestamp -- The timestamp in ISO format.
|
||||||
@ -485,7 +485,7 @@ class FieldsNode(ElementBase):
|
|||||||
self.iterables.remove(timestamp)
|
self.iterables.remove(timestamp)
|
||||||
|
|
||||||
class Field(ElementBase):
|
class Field(ElementBase):
|
||||||
"""
|
"""
|
||||||
Field element in response Timestamp. This is a base class,
|
Field element in response Timestamp. This is a base class,
|
||||||
all instances of fields added to Timestamp must be of types:
|
all instances of fields added to Timestamp must be of types:
|
||||||
DataNumeric
|
DataNumeric
|
||||||
@ -494,7 +494,7 @@ class Field(ElementBase):
|
|||||||
DataDateTime
|
DataDateTime
|
||||||
DataTimeSpan
|
DataTimeSpan
|
||||||
DataEnum
|
DataEnum
|
||||||
"""
|
"""
|
||||||
namespace = 'urn:xmpp:iot:sensordata'
|
namespace = 'urn:xmpp:iot:sensordata'
|
||||||
name = 'field'
|
name = 'field'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
@ -523,8 +523,8 @@ class Field(ElementBase):
|
|||||||
|
|
||||||
def _get_flags(self):
|
def _get_flags(self):
|
||||||
"""
|
"""
|
||||||
Helper function for getting of flags. Returns all flags in
|
Helper function for getting of flags. Returns all flags in
|
||||||
dictionary format: { "flag name": "flag value" ... }
|
dictionary format: { "flag name": "flag value" ... }
|
||||||
"""
|
"""
|
||||||
flags = {};
|
flags = {};
|
||||||
for f in self._flags:
|
for f in self._flags:
|
||||||
@ -534,10 +534,10 @@ class Field(ElementBase):
|
|||||||
|
|
||||||
def _set_flags(self, flags):
|
def _set_flags(self, flags):
|
||||||
"""
|
"""
|
||||||
Helper function for setting of flags.
|
Helper function for setting of flags.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
|
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
|
||||||
"""
|
"""
|
||||||
for f in self._flags:
|
for f in self._flags:
|
||||||
if flags is not None and f in 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):
|
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:
|
Arguments:
|
||||||
typename -- The type of data element (numeric, string, boolean, dateTime, timeSpan or enum)
|
typename -- The type of data element (numeric, string, boolean, dateTime, timeSpan or enum)
|
||||||
@ -661,9 +661,9 @@ class Timestamp(ElementBase):
|
|||||||
self.iterables.remove(data)
|
self.iterables.remove(data)
|
||||||
|
|
||||||
class DataNumeric(Field):
|
class DataNumeric(Field):
|
||||||
"""
|
"""
|
||||||
Field data of type numeric.
|
Field data of type numeric.
|
||||||
Note that the value is expressed as a string.
|
Note that the value is expressed as a string.
|
||||||
"""
|
"""
|
||||||
namespace = 'urn:xmpp:iot:sensordata'
|
namespace = 'urn:xmpp:iot:sensordata'
|
||||||
name = 'numeric'
|
name = 'numeric'
|
||||||
@ -672,11 +672,11 @@ class DataNumeric(Field):
|
|||||||
interfaces.update(Field.interfaces);
|
interfaces.update(Field.interfaces);
|
||||||
|
|
||||||
def _get_typename(self):
|
def _get_typename(self):
|
||||||
return "numeric"
|
return "numeric"
|
||||||
|
|
||||||
class DataString(Field):
|
class DataString(Field):
|
||||||
"""
|
"""
|
||||||
Field data of type string
|
Field data of type string
|
||||||
"""
|
"""
|
||||||
namespace = 'urn:xmpp:iot:sensordata'
|
namespace = 'urn:xmpp:iot:sensordata'
|
||||||
name = 'string'
|
name = 'string'
|
||||||
@ -685,12 +685,12 @@ class DataString(Field):
|
|||||||
interfaces.update(Field.interfaces);
|
interfaces.update(Field.interfaces);
|
||||||
|
|
||||||
def _get_typename(self):
|
def _get_typename(self):
|
||||||
return "string"
|
return "string"
|
||||||
|
|
||||||
class DataBoolean(Field):
|
class DataBoolean(Field):
|
||||||
"""
|
"""
|
||||||
Field data of type boolean.
|
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'
|
namespace = 'urn:xmpp:iot:sensordata'
|
||||||
name = 'boolean'
|
name = 'boolean'
|
||||||
@ -699,12 +699,12 @@ class DataBoolean(Field):
|
|||||||
interfaces.update(Field.interfaces);
|
interfaces.update(Field.interfaces);
|
||||||
|
|
||||||
def _get_typename(self):
|
def _get_typename(self):
|
||||||
return "boolean"
|
return "boolean"
|
||||||
|
|
||||||
class DataDateTime(Field):
|
class DataDateTime(Field):
|
||||||
"""
|
"""
|
||||||
Field data of type dateTime.
|
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'
|
namespace = 'urn:xmpp:iot:sensordata'
|
||||||
name = 'dateTime'
|
name = 'dateTime'
|
||||||
@ -713,12 +713,12 @@ class DataDateTime(Field):
|
|||||||
interfaces.update(Field.interfaces);
|
interfaces.update(Field.interfaces);
|
||||||
|
|
||||||
def _get_typename(self):
|
def _get_typename(self):
|
||||||
return "dateTime"
|
return "dateTime"
|
||||||
|
|
||||||
class DataTimeSpan(Field):
|
class DataTimeSpan(Field):
|
||||||
"""
|
"""
|
||||||
Field data of type timeSpan.
|
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'
|
namespace = 'urn:xmpp:iot:sensordata'
|
||||||
name = 'timeSpan'
|
name = 'timeSpan'
|
||||||
@ -727,12 +727,12 @@ class DataTimeSpan(Field):
|
|||||||
interfaces.update(Field.interfaces);
|
interfaces.update(Field.interfaces);
|
||||||
|
|
||||||
def _get_typename(self):
|
def _get_typename(self):
|
||||||
return "timeSpan"
|
return "timeSpan"
|
||||||
|
|
||||||
class DataEnum(Field):
|
class DataEnum(Field):
|
||||||
"""
|
"""
|
||||||
Field data of type enum.
|
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'
|
namespace = 'urn:xmpp:iot:sensordata'
|
||||||
name = 'enum'
|
name = 'enum'
|
||||||
@ -741,7 +741,7 @@ class DataEnum(Field):
|
|||||||
interfaces.update(Field.interfaces);
|
interfaces.update(Field.interfaces);
|
||||||
|
|
||||||
def _get_typename(self):
|
def _get_typename(self):
|
||||||
return "enum"
|
return "enum"
|
||||||
|
|
||||||
class Done(ElementBase):
|
class Done(ElementBase):
|
||||||
""" Done element used to signal that all data has been transferred """
|
""" Done element used to signal that all data has been transferred """
|
||||||
|
@ -26,16 +26,16 @@ log = logging.getLogger(__name__)
|
|||||||
class XEP_0325(BasePlugin):
|
class XEP_0325(BasePlugin):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
XEP-0325: IoT Control
|
XEP-0325: IoT Control
|
||||||
|
|
||||||
|
|
||||||
Actuators are devices in sensor networks that can be controlled through
|
Actuators are devices in sensor networks that can be controlled through
|
||||||
the network and act with the outside world. In sensor networks and
|
the network and act with the outside world. In sensor networks and
|
||||||
Internet of Things applications, actuators make it possible to automate
|
Internet of Things applications, actuators make it possible to automate
|
||||||
real-world processes.
|
real-world processes.
|
||||||
This plugin implements a mechanism whereby actuators can be controlled
|
This plugin implements a mechanism whereby actuators can be controlled
|
||||||
in XMPP-based sensor networks, making it possible to integrate sensors
|
in XMPP-based sensor networks, making it possible to integrate sensors
|
||||||
and actuators of different brands, makes and models into larger
|
and actuators of different brands, makes and models into larger
|
||||||
Internet of Things applications.
|
Internet of Things applications.
|
||||||
|
|
||||||
Also see <http://xmpp.org/extensions/xep-0325.html>
|
Also see <http://xmpp.org/extensions/xep-0325.html>
|
||||||
@ -52,9 +52,9 @@ class XEP_0325(BasePlugin):
|
|||||||
|
|
||||||
Client side
|
Client side
|
||||||
-----------
|
-----------
|
||||||
Control Event:SetResponse -- Received a response to a
|
Control Event:SetResponse -- Received a response to a
|
||||||
control request, type result
|
control request, type result
|
||||||
Control Event:SetResponseError -- Received a response to a
|
Control Event:SetResponseError -- Received a response to a
|
||||||
control request, type error
|
control request, type error
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
@ -65,7 +65,7 @@ class XEP_0325(BasePlugin):
|
|||||||
relevant to a request's session. This dictionary is used
|
relevant to a request's session. This dictionary is used
|
||||||
both by the client and sensor side. On client side, seqnr
|
both by the client and sensor side. On client side, seqnr
|
||||||
is used as key, while on sensor side, a session_id is used
|
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.
|
one instance can be both client and sensor.
|
||||||
Sensor side
|
Sensor side
|
||||||
-----------
|
-----------
|
||||||
@ -85,15 +85,15 @@ class XEP_0325(BasePlugin):
|
|||||||
|
|
||||||
Sensor side
|
Sensor side
|
||||||
-----------
|
-----------
|
||||||
register_node -- Register a sensor as available from this XMPP
|
register_node -- Register a sensor as available from this XMPP
|
||||||
instance.
|
instance.
|
||||||
|
|
||||||
Client side
|
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
|
sensor(s). Non-blocking, a callback function will
|
||||||
be called when the sensor has responded.
|
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
|
sensor(s). Non-blocking. The sensor(s) will not
|
||||||
respond regardless of the result of the command,
|
respond regardless of the result of the command,
|
||||||
so no callback is made.
|
so no callback is made.
|
||||||
@ -102,7 +102,7 @@ class XEP_0325(BasePlugin):
|
|||||||
|
|
||||||
name = 'xep_0325'
|
name = 'xep_0325'
|
||||||
description = 'XEP-0325 Internet of Things - Control'
|
description = 'XEP-0325 Internet of Things - Control'
|
||||||
dependencies = set(['xep_0030'])
|
dependencies = set(['xep_0030'])
|
||||||
stanza = stanza
|
stanza = stanza
|
||||||
|
|
||||||
|
|
||||||
@ -170,10 +170,10 @@ class XEP_0325(BasePlugin):
|
|||||||
|
|
||||||
def register_node(self, nodeId, device, commTimeout, sourceId=None, cacheType=None):
|
def register_node(self, nodeId, device, commTimeout, sourceId=None, cacheType=None):
|
||||||
"""
|
"""
|
||||||
Register a sensor/device as available for control requests/commands
|
Register a sensor/device as available for control requests/commands
|
||||||
through this XMPP instance.
|
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:
|
specific devices, but it must implement the functions:
|
||||||
has_control_field
|
has_control_field
|
||||||
set_control_fields
|
set_control_fields
|
||||||
@ -185,11 +185,11 @@ class XEP_0325(BasePlugin):
|
|||||||
commTimeout -- Time in seconds to wait between each callback from device during
|
commTimeout -- Time in seconds to wait between each callback from device during
|
||||||
a data readout. Float.
|
a data readout. Float.
|
||||||
sourceId -- [optional] identifying the data source controlling the device
|
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,
|
"commTimeout": commTimeout,
|
||||||
"sourceId": sourceId,
|
"sourceId": sourceId,
|
||||||
"cacheType": cacheType};
|
"cacheType": cacheType};
|
||||||
|
|
||||||
def _set_authenticated(self, auth=''):
|
def _set_authenticated(self, auth=''):
|
||||||
@ -205,10 +205,10 @@ class XEP_0325(BasePlugin):
|
|||||||
|
|
||||||
def _handle_set_req(self, iq):
|
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.
|
control request.
|
||||||
|
|
||||||
Verifies that
|
Verifies that
|
||||||
- all the requested nodes are available
|
- all the requested nodes are available
|
||||||
(if no nodes are specified in the request, assume all nodes)
|
(if no nodes are specified in the request, assume all nodes)
|
||||||
- all the control fields are available from all requested 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
|
If the request passes verification, the control request is passed
|
||||||
to the devices (in a separate thread).
|
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.
|
is sent.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -279,17 +279,17 @@ class XEP_0325(BasePlugin):
|
|||||||
if missing_node is not None:
|
if missing_node is not None:
|
||||||
iq['setResponse'].add_node(missing_node);
|
iq['setResponse'].add_node(missing_node);
|
||||||
if missing_field is not None:
|
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']['var'] = "Output";
|
||||||
iq['setResponse']['error']['text'] = error_msg;
|
iq['setResponse']['error']['text'] = error_msg;
|
||||||
iq.send(block=False);
|
iq.send(block=False);
|
||||||
|
|
||||||
def _handle_direct_set(self, msg):
|
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.
|
direct control command.
|
||||||
|
|
||||||
Verifies that
|
Verifies that
|
||||||
- all the requested nodes are available
|
- all the requested nodes are available
|
||||||
(if no nodes are specified in the request, assume all nodes)
|
(if no nodes are specified in the request, assume all nodes)
|
||||||
- all the control fields are available from all requested 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):
|
def _threaded_node_request(self, session, process_fields):
|
||||||
"""
|
"""
|
||||||
Helper function to handle the device control in a separate thread.
|
Helper function to handle the device control in a separate thread.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
session -- The request session id
|
session -- The request session id
|
||||||
process_fields -- The fields to set in the devices. List of tuple format:
|
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);
|
self.nodes[node]['device'].set_control_fields(process_fields, session=session, callback=self._device_set_command_callback);
|
||||||
|
|
||||||
def _event_comm_timeout(self, session, nodeId):
|
def _event_comm_timeout(self, session, nodeId):
|
||||||
"""
|
"""
|
||||||
Triggered if any of the control operations timeout.
|
Triggered if any of the control operations timeout.
|
||||||
Stop communicating with the failing device.
|
Stop communicating with the failing device.
|
||||||
If the control command was an Iq request, sends a failure
|
If the control command was an Iq request, sends a failure
|
||||||
message back to the client.
|
message back to the client.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
session -- The request session id
|
session -- The request session id
|
||||||
nodeId -- The id of the device which timed out
|
nodeId -- The id of the device which timed out
|
||||||
@ -380,7 +380,7 @@ class XEP_0325(BasePlugin):
|
|||||||
iq['id'] = self.sessions[session]['seqnr'];
|
iq['id'] = self.sessions[session]['seqnr'];
|
||||||
iq['setResponse']['responseCode'] = "OtherError";
|
iq['setResponse']['responseCode'] = "OtherError";
|
||||||
iq['setResponse'].add_node(nodeId);
|
iq['setResponse'].add_node(nodeId);
|
||||||
iq['setResponse']['error']['var'] = "Output";
|
iq['setResponse']['error']['var'] = "Output";
|
||||||
iq['setResponse']['error']['text'] = "Timeout.";
|
iq['setResponse']['error']['text'] = "Timeout.";
|
||||||
iq.send(block=False);
|
iq.send(block=False);
|
||||||
|
|
||||||
@ -393,9 +393,9 @@ class XEP_0325(BasePlugin):
|
|||||||
del self.sessions[session];
|
del self.sessions[session];
|
||||||
|
|
||||||
def _all_nodes_done(self, session):
|
def _all_nodes_done(self, session):
|
||||||
"""
|
"""
|
||||||
Checks wheter all devices are done replying to the control command.
|
Checks wheter all devices are done replying to the control command.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
session -- The request session id
|
session -- The request session id
|
||||||
"""
|
"""
|
||||||
@ -405,19 +405,19 @@ class XEP_0325(BasePlugin):
|
|||||||
return True;
|
return True;
|
||||||
|
|
||||||
def _device_set_command_callback(self, session, nodeId, result, error_field=None, error_msg=None):
|
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.
|
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.
|
client.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
session -- The request session id
|
session -- The request session id
|
||||||
nodeId -- The device id which initiated the callback
|
nodeId -- The device id which initiated the callback
|
||||||
result -- The current result status of the control command. Valid values are:
|
result -- The current result status of the control command. Valid values are:
|
||||||
"error" - Set fields failed.
|
"error" - Set fields failed.
|
||||||
"ok" - All fields were set.
|
"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)
|
The field name that failed (usually means it is missing)
|
||||||
error_msg -- [optional] Only applies when result == "error".
|
error_msg -- [optional] Only applies when result == "error".
|
||||||
Error details when a request failed.
|
Error details when a request failed.
|
||||||
@ -441,12 +441,12 @@ class XEP_0325(BasePlugin):
|
|||||||
iq['setResponse'].add_node(nodeId);
|
iq['setResponse'].add_node(nodeId);
|
||||||
if error_field is not None:
|
if error_field is not None:
|
||||||
iq['setResponse'].add_data(error_field);
|
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['setResponse']['error']['text'] = error_msg;
|
||||||
iq.send(block=False);
|
iq.send(block=False);
|
||||||
|
|
||||||
# Drop communication with this device and check if we are done
|
# 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)):
|
if (self._all_nodes_done(session)):
|
||||||
# The session is complete, delete it
|
# The session is complete, delete it
|
||||||
del self.sessions[session];
|
del self.sessions[session];
|
||||||
@ -473,17 +473,17 @@ class XEP_0325(BasePlugin):
|
|||||||
# Client side (data controller) API
|
# Client side (data controller) API
|
||||||
|
|
||||||
def set_request(self, from_jid, to_jid, callback, fields, nodeIds=None):
|
def set_request(self, from_jid, to_jid, callback, fields, nodeIds=None):
|
||||||
"""
|
"""
|
||||||
Called on the client side to initiade a control request.
|
Called on the client side to initiade a control request.
|
||||||
Composes a message with the request and sends it to the device(s).
|
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.
|
has responded.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
from_jid -- The jid of the requester
|
from_jid -- The jid of the requester
|
||||||
to_jid -- The jid of the device(s)
|
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:
|
The callback function must support the following arguments:
|
||||||
|
|
||||||
from_jid -- The jid of the responding device(s)
|
from_jid -- The jid of the responding device(s)
|
||||||
@ -494,20 +494,20 @@ class XEP_0325(BasePlugin):
|
|||||||
"Locked" - Field(s) is locked and cannot
|
"Locked" - Field(s) is locked and cannot
|
||||||
be changed at the moment.
|
be changed at the moment.
|
||||||
"NotImplemented" - Request feature not implemented.
|
"NotImplemented" - Request feature not implemented.
|
||||||
"FormError" - Error while setting with
|
"FormError" - Error while setting with
|
||||||
a form (not implemented).
|
a form (not implemented).
|
||||||
"OtherError" - Indicates other types of
|
"OtherError" - Indicates other types of
|
||||||
errors, such as timeout.
|
errors, such as timeout.
|
||||||
Details in the error_msg.
|
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".
|
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).
|
fields -- Fields to set. List of tuple format: (name, typename, value).
|
||||||
nodeIds -- [optional] Limits the request to the node Ids in this list.
|
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);
|
iq['set'].add_data(name=name, typename=typename, value=value);
|
||||||
|
|
||||||
self.sessions[seqnr] = {"from": iq['from'], "to": iq['to'], "callback": callback};
|
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):
|
def set_command(self, from_jid, to_jid, fields, nodeIds=None):
|
||||||
"""
|
"""
|
||||||
Called on the client side to initiade a control command.
|
Called on the client side to initiade a control command.
|
||||||
Composes a message with the set commandand sends it to the device(s).
|
Composes a message with the set commandand sends it to the device(s).
|
||||||
Does not block. Device(s) will not respond, regardless of result.
|
Does not block. Device(s) will not respond, regardless of result.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
from_jid -- The jid of the requester
|
from_jid -- The jid of the requester
|
||||||
to_jid -- The jid of the device(s)
|
to_jid -- The jid of the device(s)
|
||||||
@ -553,7 +553,7 @@ class XEP_0325(BasePlugin):
|
|||||||
msg['set'].add_data(name, typename, value);
|
msg['set'].add_data(name, typename, value);
|
||||||
|
|
||||||
# We won't get any reply, so don't create a session
|
# We won't get any reply, so don't create a session
|
||||||
msg.send();
|
msg.send();
|
||||||
|
|
||||||
def _handle_set_response(self, iq):
|
def _handle_set_response(self, iq):
|
||||||
""" Received response from device(s) """
|
""" Received response from device(s) """
|
||||||
@ -571,4 +571,4 @@ class XEP_0325(BasePlugin):
|
|||||||
callback = self.sessions[seqnr]["callback"];
|
callback = self.sessions[seqnr]["callback"];
|
||||||
callback(from_jid=from_jid, result=result, nodeIds=nodeIds, fields=fields, error_msg=error_msg);
|
callback(from_jid=from_jid, result=result, nodeIds=nodeIds, fields=fields, error_msg=error_msg);
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ import datetime
|
|||||||
class Device(object):
|
class Device(object):
|
||||||
"""
|
"""
|
||||||
Example implementation of a device control 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:
|
specific devices, but it must implement the functions:
|
||||||
has_control_field
|
has_control_field
|
||||||
set_control_fields
|
set_control_fields
|
||||||
@ -30,7 +30,7 @@ class Device(object):
|
|||||||
and the type matches for control in this device.
|
and the type matches for control in this device.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
field -- The field name
|
field -- The field name
|
||||||
typename -- The expected type
|
typename -- The expected type
|
||||||
"""
|
"""
|
||||||
if field in self.control_fields and self.control_fields[field]["type"] == typename:
|
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.
|
sets the data and (if needed) and calls the callback.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
fields -- List of control fields in tuple format:
|
fields -- List of control fields in tuple format:
|
||||||
(name, typename, value)
|
(name, typename, value)
|
||||||
session -- Session id, only used in the callback as identifier
|
session -- Session id, only used in the callback as identifier
|
||||||
callback -- Callback function to call when control set is complete.
|
callback -- Callback function to call when control set is complete.
|
||||||
|
|
||||||
The callback function must support the following arguments:
|
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
|
request_fields call
|
||||||
nodeId -- Identifier for this device
|
nodeId -- Identifier for this device
|
||||||
result -- The current result status of the readout.
|
result -- The current result status of the readout.
|
||||||
Valid values are:
|
Valid values are:
|
||||||
"error" - Set fields failed.
|
"error" - Set fields failed.
|
||||||
"ok" - All fields were set.
|
"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
|
The field name that failed
|
||||||
(usually means it is missing)
|
(usually means it is missing)
|
||||||
error_msg -- [optional] Only applies when result == "error".
|
error_msg -- [optional] Only applies when result == "error".
|
||||||
Error details when a request failed.
|
Error details when a request failed.
|
||||||
@ -82,9 +82,9 @@ class Device(object):
|
|||||||
Sends a reject to the caller
|
Sends a reject to the caller
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
session -- Session id, see definition in
|
session -- Session id, see definition in
|
||||||
set_control_fields function
|
set_control_fields function
|
||||||
callback -- Callback function, see definition in
|
callback -- Callback function, see definition in
|
||||||
set_control_fields function
|
set_control_fields function
|
||||||
"""
|
"""
|
||||||
callback(session, result="error", nodeId=self.nodeId, error_field=field, error_msg=message);
|
callback(session, result="error", nodeId=self.nodeId, error_field=field, error_msg=message);
|
||||||
@ -95,8 +95,8 @@ class Device(object):
|
|||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
name -- Name of the field
|
name -- Name of the field
|
||||||
typename -- Type of the field, one of:
|
typename -- Type of the field, one of:
|
||||||
(boolean, color, string, date, dateTime,
|
(boolean, color, string, date, dateTime,
|
||||||
double, duration, int, long, time)
|
double, duration, int, long, time)
|
||||||
value -- Field value
|
value -- Field value
|
||||||
"""
|
"""
|
||||||
|
@ -53,7 +53,7 @@ class ControlSet(ElementBase):
|
|||||||
Arguments:
|
Arguments:
|
||||||
nodeId -- The ID for the node.
|
nodeId -- The ID for the node.
|
||||||
sourceId -- [optional] identifying the data source controlling the device
|
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:
|
if nodeId not in self._nodes:
|
||||||
self._nodes.add((nodeId))
|
self._nodes.add((nodeId))
|
||||||
@ -117,12 +117,12 @@ class ControlSet(ElementBase):
|
|||||||
|
|
||||||
def add_data(self, name, typename, value):
|
def add_data(self, name, typename, value):
|
||||||
"""
|
"""
|
||||||
Add a new data element.
|
Add a new data element.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
name -- The name of the data element
|
name -- The name of the data element
|
||||||
typename -- The type of data element
|
typename -- The type of data element
|
||||||
(boolean, color, string, date, dateTime,
|
(boolean, color, string, date, dateTime,
|
||||||
double, duration, int, long, time)
|
double, duration, int, long, time)
|
||||||
value -- The value of the data element
|
value -- The value of the data element
|
||||||
"""
|
"""
|
||||||
@ -244,7 +244,7 @@ class ControlSetResponse(ElementBase):
|
|||||||
Arguments:
|
Arguments:
|
||||||
nodeId -- The ID for the node.
|
nodeId -- The ID for the node.
|
||||||
sourceId -- [optional] identifying the data source controlling the device
|
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:
|
if nodeId not in self._nodes:
|
||||||
self._nodes.add(nodeId)
|
self._nodes.add(nodeId)
|
||||||
@ -308,7 +308,7 @@ class ControlSetResponse(ElementBase):
|
|||||||
|
|
||||||
def add_data(self, name):
|
def add_data(self, name):
|
||||||
"""
|
"""
|
||||||
Add a new ResponseParameter element.
|
Add a new ResponseParameter element.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
name -- Name of the parameter
|
name -- Name of the parameter
|
||||||
@ -389,12 +389,12 @@ class Error(ElementBase):
|
|||||||
def del_text(self):
|
def del_text(self):
|
||||||
"""Remove the contents inside the XML tag."""
|
"""Remove the contents inside the XML tag."""
|
||||||
self.xml.text = ""
|
self.xml.text = ""
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class ResponseParameter(ElementBase):
|
class ResponseParameter(ElementBase):
|
||||||
"""
|
"""
|
||||||
Parameter element in ControlSetResponse.
|
Parameter element in ControlSetResponse.
|
||||||
"""
|
"""
|
||||||
namespace = 'urn:xmpp:iot:control'
|
namespace = 'urn:xmpp:iot:control'
|
||||||
name = 'parameter'
|
name = 'parameter'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
@ -402,7 +402,7 @@ class ResponseParameter(ElementBase):
|
|||||||
|
|
||||||
|
|
||||||
class BaseParameter(ElementBase):
|
class BaseParameter(ElementBase):
|
||||||
"""
|
"""
|
||||||
Parameter element in SetCommand. This is a base class,
|
Parameter element in SetCommand. This is a base class,
|
||||||
all instances of parameters added to SetCommand must be of types:
|
all instances of parameters added to SetCommand must be of types:
|
||||||
BooleanParameter
|
BooleanParameter
|
||||||
@ -415,7 +415,7 @@ class BaseParameter(ElementBase):
|
|||||||
IntParameter
|
IntParameter
|
||||||
LongParameter
|
LongParameter
|
||||||
TimeParameter
|
TimeParameter
|
||||||
"""
|
"""
|
||||||
namespace = 'urn:xmpp:iot:control'
|
namespace = 'urn:xmpp:iot:control'
|
||||||
name = 'baseParameter'
|
name = 'baseParameter'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
@ -425,80 +425,80 @@ class BaseParameter(ElementBase):
|
|||||||
return self.name;
|
return self.name;
|
||||||
|
|
||||||
class BooleanParameter(BaseParameter):
|
class BooleanParameter(BaseParameter):
|
||||||
"""
|
"""
|
||||||
Field data of type boolean.
|
Field data of type boolean.
|
||||||
Note that the value is expressed as a string.
|
Note that the value is expressed as a string.
|
||||||
"""
|
"""
|
||||||
name = 'boolean'
|
name = 'boolean'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
|
|
||||||
class ColorParameter(BaseParameter):
|
class ColorParameter(BaseParameter):
|
||||||
"""
|
"""
|
||||||
Field data of type color.
|
Field data of type color.
|
||||||
Note that the value is expressed as a string.
|
Note that the value is expressed as a string.
|
||||||
"""
|
"""
|
||||||
name = 'color'
|
name = 'color'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
|
|
||||||
class StringParameter(BaseParameter):
|
class StringParameter(BaseParameter):
|
||||||
"""
|
"""
|
||||||
Field data of type string.
|
Field data of type string.
|
||||||
"""
|
"""
|
||||||
name = 'string'
|
name = 'string'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
|
|
||||||
class DateParameter(BaseParameter):
|
class DateParameter(BaseParameter):
|
||||||
"""
|
"""
|
||||||
Field data of type date.
|
Field data of type date.
|
||||||
Note that the value is expressed as a string.
|
Note that the value is expressed as a string.
|
||||||
"""
|
"""
|
||||||
name = 'date'
|
name = 'date'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
|
|
||||||
class DateTimeParameter(BaseParameter):
|
class DateTimeParameter(BaseParameter):
|
||||||
"""
|
"""
|
||||||
Field data of type dateTime.
|
Field data of type dateTime.
|
||||||
Note that the value is expressed as a string.
|
Note that the value is expressed as a string.
|
||||||
"""
|
"""
|
||||||
name = 'dateTime'
|
name = 'dateTime'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
|
|
||||||
class DoubleParameter(BaseParameter):
|
class DoubleParameter(BaseParameter):
|
||||||
"""
|
"""
|
||||||
Field data of type double.
|
Field data of type double.
|
||||||
Note that the value is expressed as a string.
|
Note that the value is expressed as a string.
|
||||||
"""
|
"""
|
||||||
name = 'double'
|
name = 'double'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
|
|
||||||
class DurationParameter(BaseParameter):
|
class DurationParameter(BaseParameter):
|
||||||
"""
|
"""
|
||||||
Field data of type duration.
|
Field data of type duration.
|
||||||
Note that the value is expressed as a string.
|
Note that the value is expressed as a string.
|
||||||
"""
|
"""
|
||||||
name = 'duration'
|
name = 'duration'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
|
|
||||||
class IntParameter(BaseParameter):
|
class IntParameter(BaseParameter):
|
||||||
"""
|
"""
|
||||||
Field data of type int.
|
Field data of type int.
|
||||||
Note that the value is expressed as a string.
|
Note that the value is expressed as a string.
|
||||||
"""
|
"""
|
||||||
name = 'int'
|
name = 'int'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
|
|
||||||
class LongParameter(BaseParameter):
|
class LongParameter(BaseParameter):
|
||||||
"""
|
"""
|
||||||
Field data of type long (64-bit int).
|
Field data of type long (64-bit int).
|
||||||
Note that the value is expressed as a string.
|
Note that the value is expressed as a string.
|
||||||
"""
|
"""
|
||||||
name = 'long'
|
name = 'long'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
|
|
||||||
class TimeParameter(BaseParameter):
|
class TimeParameter(BaseParameter):
|
||||||
"""
|
"""
|
||||||
Field data of type time.
|
Field data of type time.
|
||||||
Note that the value is expressed as a string.
|
Note that the value is expressed as a string.
|
||||||
"""
|
"""
|
||||||
name = 'time'
|
name = 'time'
|
||||||
plugin_attrib = name
|
plugin_attrib = name
|
||||||
|
@ -133,7 +133,7 @@ def resolve(host, port=None, service=None, proto='tcp',
|
|||||||
if not service:
|
if not service:
|
||||||
hosts = [(host, port)]
|
hosts = [(host, port)]
|
||||||
else:
|
else:
|
||||||
hosts = get_SRV(host, port, service, proto,
|
hosts = get_SRV(host, port, service, proto,
|
||||||
resolver=resolver,
|
resolver=resolver,
|
||||||
use_dnspython=use_dnspython)
|
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, '::1', port))
|
||||||
results.append((host, '127.0.0.1', port))
|
results.append((host, '127.0.0.1', port))
|
||||||
if use_ipv6:
|
if use_ipv6:
|
||||||
for address in get_AAAA(host, resolver=resolver,
|
for address in get_AAAA(host, resolver=resolver,
|
||||||
use_dnspython=use_dnspython):
|
use_dnspython=use_dnspython):
|
||||||
results.append((host, address, port))
|
results.append((host, address, port))
|
||||||
for address in get_A(host, resolver=resolver,
|
for address in get_A(host, resolver=resolver,
|
||||||
|
@ -77,7 +77,7 @@ class TestPlugins(unittest.TestCase):
|
|||||||
p.disable('a')
|
p.disable('a')
|
||||||
|
|
||||||
self.assertEqual(len(p), 0, "Wrong number of enabled plugins.")
|
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.")
|
"Plugin lifecycle methods not called.")
|
||||||
|
|
||||||
def test_enable_dependencies(self):
|
def test_enable_dependencies(self):
|
||||||
|
@ -6,7 +6,7 @@ import slixmpp.plugins.xep_0323 as xep_0323
|
|||||||
namespace='sn'
|
namespace='sn'
|
||||||
|
|
||||||
class TestSensorDataStanzas(SlixTest):
|
class TestSensorDataStanzas(SlixTest):
|
||||||
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
pass
|
pass
|
||||||
@ -171,7 +171,7 @@ class TestSensorDataStanzas(SlixTest):
|
|||||||
iq['accepted']['seqnr'] = '2'
|
iq['accepted']['seqnr'] = '2'
|
||||||
|
|
||||||
self.check(iq,"""
|
self.check(iq,"""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='2'>
|
id='2'>
|
||||||
@ -193,7 +193,7 @@ class TestSensorDataStanzas(SlixTest):
|
|||||||
iq['rejected']['error'] = 'Access denied.'
|
iq['rejected']['error'] = 'Access denied.'
|
||||||
|
|
||||||
self.check(iq,"""
|
self.check(iq,"""
|
||||||
<iq type='error'
|
<iq type='error'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='4'>
|
id='4'>
|
||||||
@ -250,7 +250,7 @@ class TestSensorDataStanzas(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
||||||
<node nodeId='Device02'>
|
<node nodeId='Device02'>
|
||||||
<timestamp value='2013-03-07T16:24:30'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
@ -269,7 +269,7 @@ class TestSensorDataStanzas(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
||||||
<node nodeId='Device02'>
|
<node nodeId='Device02'>
|
||||||
<timestamp value='2013-03-07T16:24:30'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
<node nodeId='EmptyDevice'/>
|
<node nodeId='EmptyDevice'/>
|
||||||
@ -314,7 +314,7 @@ class TestSensorDataStanzas(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
||||||
<node nodeId='Device02'>
|
<node nodeId='Device02'>
|
||||||
<timestamp value='2013-03-07T16:24:30'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
<node nodeId='EmptyDevice'/>
|
<node nodeId='EmptyDevice'/>
|
||||||
@ -323,18 +323,18 @@ class TestSensorDataStanzas(SlixTest):
|
|||||||
</node>
|
</node>
|
||||||
<node nodeId='Device77'>
|
<node nodeId='Device77'>
|
||||||
<timestamp value='2013-05-03T12:00:01'>
|
<timestamp value='2013-05-03T12:00:01'>
|
||||||
<numeric name='Temperature' historicalDay='true' value='-12.42' unit='K'/>
|
<numeric name='Temperature' historicalDay='true' value='-12.42' unit='K'/>
|
||||||
<numeric name='Speed' historicalWeek='false' value='312.42' unit='km/h'/>
|
<numeric name='Speed' historicalWeek='false' value='312.42' unit='km/h'/>
|
||||||
<string name='Temperature name' historicalMonth='true' value='Bottom oil'/>
|
<string name='Temperature name' historicalMonth='true' value='Bottom oil'/>
|
||||||
<string name='Speed name' historicalQuarter='false' value='Top speed'/>
|
<string name='Speed name' historicalQuarter='false' value='Top speed'/>
|
||||||
<dateTime name='T1' historicalYear='true' value='1979-01-01T00:00:00'/>
|
<dateTime name='T1' historicalYear='true' value='1979-01-01T00:00:00'/>
|
||||||
<dateTime name='T2' historicalOther='false' value='2000-01-01T01:02:03'/>
|
<dateTime name='T2' historicalOther='false' value='2000-01-01T01:02:03'/>
|
||||||
<timeSpan name='TS1' missing='true' value='P5Y'/>
|
<timeSpan name='TS1' missing='true' value='P5Y'/>
|
||||||
<timeSpan name='TS2' manualEstimate='false' value='PT2M1S'/>
|
<timeSpan name='TS2' manualEstimate='false' value='PT2M1S'/>
|
||||||
<enum name='top color' invoiced='true' value='red' dataType='string'/>
|
<enum name='top color' invoiced='true' value='red' dataType='string'/>
|
||||||
<enum name='bottom color' powerFailure='false' value='black' dataType='string'/>
|
<enum name='bottom color' powerFailure='false' value='black' dataType='string'/>
|
||||||
<boolean name='Temperature real' historicalDay='true' value='false'/>
|
<boolean name='Temperature real' historicalDay='true' value='false'/>
|
||||||
<boolean name='Speed real' historicalWeek='false' value='true'/>
|
<boolean name='Speed real' historicalWeek='false' value='true'/>
|
||||||
</timestamp>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
@ -342,7 +342,7 @@ class TestSensorDataStanzas(SlixTest):
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def testTimestamp(self):
|
def testTimestamp(self):
|
||||||
msg = self.Message();
|
msg = self.Message();
|
||||||
|
|
||||||
@ -386,8 +386,8 @@ class TestSensorDataStanzas(SlixTest):
|
|||||||
self.check(msg,emptyStringIdXML)
|
self.check(msg,emptyStringIdXML)
|
||||||
msg['fields']['stringIds'] = "1"
|
msg['fields']['stringIds'] = "1"
|
||||||
self.check(msg,emptyStringIdXML)
|
self.check(msg,emptyStringIdXML)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestSensorDataStanzas)
|
suite = unittest.TestLoader().loadTestsFromTestCase(TestSensorDataStanzas)
|
||||||
|
@ -15,7 +15,7 @@ import slixmpp.plugins.xep_0325 as xep_0325
|
|||||||
namespace='sn'
|
namespace='sn'
|
||||||
|
|
||||||
class TestControlStanzas(SlixTest):
|
class TestControlStanzas(SlixTest):
|
||||||
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
pass
|
pass
|
||||||
@ -89,7 +89,7 @@ class TestControlStanzas(SlixTest):
|
|||||||
msg['set'].add_data("Tjohej", "boolean", "true")
|
msg['set'].add_data("Tjohej", "boolean", "true")
|
||||||
|
|
||||||
self.check(msg,"""
|
self.check(msg,"""
|
||||||
<message
|
<message
|
||||||
from='master@clayster.com/amr'
|
from='master@clayster.com/amr'
|
||||||
to='device@clayster.com'>
|
to='device@clayster.com'>
|
||||||
<set xmlns='urn:xmpp:iot:control'>
|
<set xmlns='urn:xmpp:iot:control'>
|
||||||
@ -244,5 +244,5 @@ class TestControlStanzas(SlixTest):
|
|||||||
</iq>
|
</iq>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestControlStanzas)
|
suite = unittest.TestLoader().loadTestsFromTestCase(TestControlStanzas)
|
||||||
|
@ -46,7 +46,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='1'>
|
id='1'>
|
||||||
@ -60,11 +60,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
|
||||||
<node nodeId='Device22'>
|
<node nodeId='Device22'>
|
||||||
<timestamp value='2013-03-07T16:24:30'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testRequestRejectAuth(self):
|
def testRequestRejectAuth(self):
|
||||||
@ -85,7 +85,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='error'
|
<iq type='error'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='4'>
|
id='4'>
|
||||||
@ -118,7 +118,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='error'
|
<iq type='error'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='77'>
|
id='77'>
|
||||||
@ -142,7 +142,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='8'>
|
id='8'>
|
||||||
@ -177,7 +177,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='error'
|
<iq type='error'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='7'>
|
id='7'>
|
||||||
@ -201,7 +201,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='8'>
|
id='8'>
|
||||||
@ -215,11 +215,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
|
||||||
<node nodeId='Device44'>
|
<node nodeId='Device44'>
|
||||||
<timestamp value='2000-01-01T00:01:02'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -227,7 +227,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
to='master@clayster.com/amr'>
|
to='master@clayster.com/amr'>
|
||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testRequestMultiTimestampSingleField(self):
|
def testRequestMultiTimestampSingleField(self):
|
||||||
@ -260,7 +260,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='8'>
|
id='8'>
|
||||||
@ -274,11 +274,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
|
||||||
<node nodeId='Device44'>
|
<node nodeId='Device44'>
|
||||||
<timestamp value='2000-01-01T00:01:02'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -287,11 +287,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
|
||||||
<node nodeId='Device44'>
|
<node nodeId='Device44'>
|
||||||
<timestamp value='2000-01-01T01:01:02'>
|
<timestamp value='2000-01-01T01:01:02'>
|
||||||
<numeric name='Voltage' value='230.6' unit='V'/>
|
<numeric name='Voltage' value='230.6' unit='V'/>
|
||||||
</timestamp>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -299,7 +299,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
to='master@clayster.com/amr'>
|
to='master@clayster.com/amr'>
|
||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testRequestMultiTimestampAllFields(self):
|
def testRequestMultiTimestampAllFields(self):
|
||||||
@ -330,7 +330,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='8'>
|
id='8'>
|
||||||
@ -344,11 +344,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
|
||||||
<node nodeId='Device44'>
|
<node nodeId='Device44'>
|
||||||
<timestamp value='2000-01-01T00:01:02'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -357,12 +357,12 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7'>
|
||||||
<node nodeId='Device44'>
|
<node nodeId='Device44'>
|
||||||
<timestamp value='2000-01-01T01:01:02'>
|
<timestamp value='2000-01-01T01:01:02'>
|
||||||
<numeric name='Voltage' value='230.6' unit='V'/>
|
<numeric name='Voltage' value='230.6' unit='V'/>
|
||||||
<string name='Height' invoiced='true' value='115 m'/>
|
<string name='Height' invoiced='true' value='115 m'/>
|
||||||
</timestamp>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -370,7 +370,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
to='master@clayster.com/amr'>
|
to='master@clayster.com/amr'>
|
||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='7' done='true'>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testRequestAPI(self):
|
def testRequestAPI(self):
|
||||||
@ -424,7 +424,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
plugins=['xep_0030',
|
plugins=['xep_0030',
|
||||||
'xep_0323'])
|
'xep_0323'])
|
||||||
|
|
||||||
results = [];
|
results = [];
|
||||||
|
|
||||||
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
|
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
|
||||||
if (result == "rejected") and (error_msg == "Invalid device Device22"):
|
if (result == "rejected") and (error_msg == "Invalid device Device22"):
|
||||||
@ -445,19 +445,19 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
<iq type='error'
|
<iq type='error'
|
||||||
from='you@google.com'
|
from='you@google.com'
|
||||||
to='tester@localhost'
|
to='tester@localhost'
|
||||||
id='1'>
|
id='1'>
|
||||||
<rejected xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
<rejected xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
||||||
<error>Invalid device Device22</error>
|
<error>Invalid device Device22</error>
|
||||||
</rejected>
|
</rejected>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
time.sleep(.1)
|
time.sleep(.1)
|
||||||
|
|
||||||
self.failUnless(results == ["rejected"],
|
self.failUnless(results == ["rejected"],
|
||||||
"Rejected callback was not properly executed");
|
"Rejected callback was not properly executed");
|
||||||
|
|
||||||
def testRequestAcceptedAPI(self):
|
def testRequestAcceptedAPI(self):
|
||||||
@ -466,7 +466,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
plugins=['xep_0030',
|
plugins=['xep_0030',
|
||||||
'xep_0323'])
|
'xep_0323'])
|
||||||
|
|
||||||
results = [];
|
results = [];
|
||||||
|
|
||||||
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
|
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
|
||||||
results.append(result);
|
results.append(result);
|
||||||
@ -486,17 +486,17 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='you@google.com'
|
from='you@google.com'
|
||||||
to='tester@localhost'
|
to='tester@localhost'
|
||||||
id='1'>
|
id='1'>
|
||||||
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
|
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
time.sleep(.1)
|
time.sleep(.1)
|
||||||
|
|
||||||
self.failUnless(results == ["accepted"],
|
self.failUnless(results == ["accepted"],
|
||||||
"Accepted callback was not properly executed");
|
"Accepted callback was not properly executed");
|
||||||
|
|
||||||
def testRequestFieldsAPI(self):
|
def testRequestFieldsAPI(self):
|
||||||
@ -505,8 +505,8 @@ class TestStreamSensorData(SlixTest):
|
|||||||
plugins=['xep_0030',
|
plugins=['xep_0030',
|
||||||
'xep_0323'])
|
'xep_0323'])
|
||||||
|
|
||||||
results = [];
|
results = [];
|
||||||
callback_data = {};
|
callback_data = {};
|
||||||
|
|
||||||
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
|
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
|
||||||
results.append(result);
|
results.append(result);
|
||||||
@ -519,9 +519,9 @@ class TestStreamSensorData(SlixTest):
|
|||||||
|
|
||||||
t1= threading.Thread(name="request_data",
|
t1= threading.Thread(name="request_data",
|
||||||
target=self.xmpp['xep_0323'].request_data,
|
target=self.xmpp['xep_0323'].request_data,
|
||||||
kwargs={"from_jid": "tester@localhost",
|
kwargs={"from_jid": "tester@localhost",
|
||||||
"to_jid": "you@google.com",
|
"to_jid": "you@google.com",
|
||||||
"nodeIds": ['Device33'],
|
"nodeIds": ['Device33'],
|
||||||
"callback": my_callback});
|
"callback": my_callback});
|
||||||
t1.start();
|
t1.start();
|
||||||
#self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback);
|
#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("""
|
self.recv("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='you@google.com'
|
from='you@google.com'
|
||||||
to='tester@localhost'
|
to='tester@localhost'
|
||||||
id='1'>
|
id='1'>
|
||||||
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
|
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
@ -552,19 +552,19 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
||||||
<node nodeId='Device33'>
|
<node nodeId='Device33'>
|
||||||
<timestamp value='2000-01-01T00:01:02'>
|
<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'/>
|
||||||
<boolean name='TestBool' value='true'/>
|
<boolean name='TestBool' value='true'/>
|
||||||
</timestamp>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
<message from='you@google.com'
|
<message from='you@google.com'
|
||||||
to='tester@localhost'>
|
to='tester@localhost'>
|
||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'/>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'/>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
t1.join();
|
t1.join();
|
||||||
@ -605,8 +605,8 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<query xmlns='http://jabber.org/protocol/disco#info'>
|
<query xmlns='http://jabber.org/protocol/disco#info'>
|
||||||
<identity category='client' type='bot'/>
|
<identity category='client' type='bot'/>
|
||||||
<feature var='urn:xmpp:iot:sensordata'/>
|
<feature var='urn:xmpp:iot:sensordata'/>
|
||||||
</query>
|
</query>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testServiceDiscoveryComponent(self):
|
def testServiceDiscoveryComponent(self):
|
||||||
@ -631,8 +631,8 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<query xmlns='http://jabber.org/protocol/disco#info'>
|
<query xmlns='http://jabber.org/protocol/disco#info'>
|
||||||
<identity category='component' type='generic'/>
|
<identity category='component' type='generic'/>
|
||||||
<feature var='urn:xmpp:iot:sensordata'/>
|
<feature var='urn:xmpp:iot:sensordata'/>
|
||||||
</query>
|
</query>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testRequestTimeout(self):
|
def testRequestTimeout(self):
|
||||||
@ -642,7 +642,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
'xep_0323'])
|
'xep_0323'])
|
||||||
|
|
||||||
results = [];
|
results = [];
|
||||||
callback_data = {};
|
callback_data = {};
|
||||||
|
|
||||||
def my_callback(from_jid, result, nodeId=None, timestamp=None, error_msg=None):
|
def my_callback(from_jid, result, nodeId=None, timestamp=None, error_msg=None):
|
||||||
results.append(result);
|
results.append(result);
|
||||||
@ -653,9 +653,9 @@ class TestStreamSensorData(SlixTest):
|
|||||||
|
|
||||||
t1= threading.Thread(name="request_data",
|
t1= threading.Thread(name="request_data",
|
||||||
target=self.xmpp['xep_0323'].request_data,
|
target=self.xmpp['xep_0323'].request_data,
|
||||||
kwargs={"from_jid": "tester@localhost",
|
kwargs={"from_jid": "tester@localhost",
|
||||||
"to_jid": "you@google.com",
|
"to_jid": "you@google.com",
|
||||||
"nodeIds": ['Device33'],
|
"nodeIds": ['Device33'],
|
||||||
"callback": my_callback});
|
"callback": my_callback});
|
||||||
t1.start();
|
t1.start();
|
||||||
|
|
||||||
@ -671,12 +671,12 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='you@google.com'
|
from='you@google.com'
|
||||||
to='tester@localhost'
|
to='tester@localhost'
|
||||||
id='1'>
|
id='1'>
|
||||||
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
|
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
@ -729,7 +729,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='1'>
|
id='1'>
|
||||||
@ -743,7 +743,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<message from='device@clayster.com'
|
<message from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'>
|
to='master@clayster.com/amr'>
|
||||||
<started xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
|
<started xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -752,11 +752,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'>
|
||||||
<node nodeId='Device22'>
|
<node nodeId='Device22'>
|
||||||
<timestamp value='2013-03-07T16:24:30'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testDelayedRequestFail(self):
|
def testDelayedRequestFail(self):
|
||||||
@ -792,7 +792,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
xml_stanza['rejected']['error'] = error_text
|
xml_stanza['rejected']['error'] = error_text
|
||||||
|
|
||||||
self._filtered_stanza_check("""
|
self._filtered_stanza_check("""
|
||||||
<iq type='error'
|
<iq type='error'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='1'>
|
id='1'>
|
||||||
@ -847,7 +847,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='6'>
|
id='6'>
|
||||||
@ -861,11 +861,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
|
||||||
<node nodeId='Device44'>
|
<node nodeId='Device44'>
|
||||||
<timestamp value='2000-02-01T00:01:02'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -874,11 +874,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
|
||||||
<node nodeId='Device44'>
|
<node nodeId='Device44'>
|
||||||
<timestamp value='2000-03-01T00:01:02'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -886,7 +886,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
to='master@clayster.com/amr'>
|
to='master@clayster.com/amr'>
|
||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testRequestFieldTo(self):
|
def testRequestFieldTo(self):
|
||||||
@ -917,7 +917,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='6'>
|
id='6'>
|
||||||
@ -931,11 +931,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
|
||||||
<node nodeId='Device44'>
|
<node nodeId='Device44'>
|
||||||
<timestamp value='2000-01-01T00:01:02'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -944,11 +944,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
|
||||||
<node nodeId='Device44'>
|
<node nodeId='Device44'>
|
||||||
<timestamp value='2000-02-01T00:01:02'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -956,7 +956,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
to='master@clayster.com/amr'>
|
to='master@clayster.com/amr'>
|
||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testRequestFieldFromTo(self):
|
def testRequestFieldFromTo(self):
|
||||||
@ -987,7 +987,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='6'>
|
id='6'>
|
||||||
@ -1001,11 +1001,11 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6'>
|
||||||
<node nodeId='Device44'>
|
<node nodeId='Device44'>
|
||||||
<timestamp value='2000-02-01T00:01:02'>
|
<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>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
@ -1013,7 +1013,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
to='master@clayster.com/amr'>
|
to='master@clayster.com/amr'>
|
||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='6' done='true'>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testDelayedRequestClient(self):
|
def testDelayedRequestClient(self):
|
||||||
@ -1021,8 +1021,8 @@ class TestStreamSensorData(SlixTest):
|
|||||||
plugins=['xep_0030',
|
plugins=['xep_0030',
|
||||||
'xep_0323'])
|
'xep_0323'])
|
||||||
|
|
||||||
results = [];
|
results = [];
|
||||||
callback_data = {};
|
callback_data = {};
|
||||||
|
|
||||||
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
|
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
|
||||||
results.append(result);
|
results.append(result);
|
||||||
@ -1035,9 +1035,9 @@ class TestStreamSensorData(SlixTest):
|
|||||||
|
|
||||||
t1= threading.Thread(name="request_data",
|
t1= threading.Thread(name="request_data",
|
||||||
target=self.xmpp['xep_0323'].request_data,
|
target=self.xmpp['xep_0323'].request_data,
|
||||||
kwargs={"from_jid": "tester@localhost",
|
kwargs={"from_jid": "tester@localhost",
|
||||||
"to_jid": "you@google.com",
|
"to_jid": "you@google.com",
|
||||||
"nodeIds": ['Device33'],
|
"nodeIds": ['Device33'],
|
||||||
"callback": my_callback});
|
"callback": my_callback});
|
||||||
t1.start();
|
t1.start();
|
||||||
#self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback);
|
#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("""
|
self.recv("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='you@google.com'
|
from='you@google.com'
|
||||||
to='tester@localhost'
|
to='tester@localhost'
|
||||||
id='1'>
|
id='1'>
|
||||||
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1' queued='true'/>
|
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1' queued='true'/>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
<message from='device@clayster.com'
|
<message from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'>
|
to='master@clayster.com/amr'>
|
||||||
<started xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
|
<started xmlns='urn:xmpp:iot:sensordata' seqnr='1' />
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
<message from='you@google.com'
|
<message from='you@google.com'
|
||||||
@ -1075,19 +1075,19 @@ class TestStreamSensorData(SlixTest):
|
|||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1'>
|
||||||
<node nodeId='Device33'>
|
<node nodeId='Device33'>
|
||||||
<timestamp value='2000-01-01T00:01:02'>
|
<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'/>
|
||||||
<boolean name='TestBool' value='true'/>
|
<boolean name='TestBool' value='true'/>
|
||||||
</timestamp>
|
</timestamp>
|
||||||
</node>
|
</node>
|
||||||
</fields>
|
</fields>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
<message from='you@google.com'
|
<message from='you@google.com'
|
||||||
to='tester@localhost'>
|
to='tester@localhost'>
|
||||||
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'/>
|
<fields xmlns='urn:xmpp:iot:sensordata' seqnr='1' done='true'/>
|
||||||
</message>
|
</message>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
t1.join();
|
t1.join();
|
||||||
@ -1114,7 +1114,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
plugins=['xep_0030',
|
plugins=['xep_0030',
|
||||||
'xep_0323'])
|
'xep_0323'])
|
||||||
|
|
||||||
results = [];
|
results = [];
|
||||||
|
|
||||||
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
|
def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
|
||||||
results.append(result);
|
results.append(result);
|
||||||
@ -1133,12 +1133,12 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='you@google.com'
|
from='you@google.com'
|
||||||
to='tester@localhost'
|
to='tester@localhost'
|
||||||
id='1'>
|
id='1'>
|
||||||
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
|
<accepted xmlns='urn:xmpp:iot:sensordata' seqnr='1'/>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.xmpp['xep_0323'].cancel_request(session=session);
|
self.xmpp['xep_0323'].cancel_request(session=session);
|
||||||
@ -1192,7 +1192,7 @@ class TestStreamSensorData(SlixTest):
|
|||||||
""")
|
""")
|
||||||
|
|
||||||
self.send("""
|
self.send("""
|
||||||
<iq type='result'
|
<iq type='result'
|
||||||
from='device@clayster.com'
|
from='device@clayster.com'
|
||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='1'>
|
id='1'>
|
||||||
|
@ -60,7 +60,7 @@ class TestStreamControl(SlixTest):
|
|||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='1'>
|
id='1'>
|
||||||
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
|
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.assertEqual(myDevice._get_field_value("Temperature"), "17");
|
self.assertEqual(myDevice._get_field_value("Temperature"), "17");
|
||||||
@ -99,7 +99,7 @@ class TestStreamControl(SlixTest):
|
|||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='1'>
|
id='1'>
|
||||||
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
|
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.assertEqual(myDevice._get_field_value("Temperature"), "17");
|
self.assertEqual(myDevice._get_field_value("Temperature"), "17");
|
||||||
@ -125,7 +125,7 @@ class TestStreamControl(SlixTest):
|
|||||||
to='master@clayster.com/amr'
|
to='master@clayster.com/amr'
|
||||||
id='2'>
|
id='2'>
|
||||||
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
|
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.assertEqual(myDevice._get_field_value("Temperature"), "20");
|
self.assertEqual(myDevice._get_field_value("Temperature"), "20");
|
||||||
@ -163,7 +163,7 @@ class TestStreamControl(SlixTest):
|
|||||||
<parameter name='Voltage' />
|
<parameter name='Voltage' />
|
||||||
<error var='Output'>Invalid field Voltage</error>
|
<error var='Output'>Invalid field Voltage</error>
|
||||||
</setResponse>
|
</setResponse>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
self.assertEqual(myDevice._get_field_value("Temperature"), "15");
|
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.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
<message
|
<message
|
||||||
from='master@clayster.com/amr'
|
from='master@clayster.com/amr'
|
||||||
to='device@clayster.com'>
|
to='device@clayster.com'>
|
||||||
<set xmlns='urn:xmpp:iot:control'>
|
<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.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
|
||||||
|
|
||||||
self.recv("""
|
self.recv("""
|
||||||
<message
|
<message
|
||||||
from='master@clayster.com/amr'
|
from='master@clayster.com/amr'
|
||||||
to='device@clayster.com'>
|
to='device@clayster.com'>
|
||||||
<set xmlns='urn:xmpp:iot:control'>
|
<set xmlns='urn:xmpp:iot:control'>
|
||||||
@ -225,7 +225,7 @@ class TestStreamControl(SlixTest):
|
|||||||
plugins=['xep_0030',
|
plugins=['xep_0030',
|
||||||
'xep_0325'])
|
'xep_0325'])
|
||||||
|
|
||||||
results = [];
|
results = [];
|
||||||
|
|
||||||
def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
|
def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
|
||||||
results.append(result);
|
results.append(result);
|
||||||
@ -256,7 +256,7 @@ class TestStreamControl(SlixTest):
|
|||||||
to='tester@localhost'
|
to='tester@localhost'
|
||||||
id='1'>
|
id='1'>
|
||||||
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
|
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OK" />
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
time.sleep(.5)
|
time.sleep(.5)
|
||||||
@ -269,7 +269,7 @@ class TestStreamControl(SlixTest):
|
|||||||
plugins=['xep_0030',
|
plugins=['xep_0030',
|
||||||
'xep_0325'])
|
'xep_0325'])
|
||||||
|
|
||||||
results = [];
|
results = [];
|
||||||
|
|
||||||
def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
|
def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
|
||||||
results.append(result);
|
results.append(result);
|
||||||
@ -302,7 +302,7 @@ class TestStreamControl(SlixTest):
|
|||||||
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OtherError" >
|
<setResponse xmlns='urn:xmpp:iot:control' responseCode="OtherError" >
|
||||||
<error var='Temperature'>Sensor error</error>
|
<error var='Temperature'>Sensor error</error>
|
||||||
</setResponse>
|
</setResponse>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
time.sleep(.5)
|
time.sleep(.5)
|
||||||
@ -330,8 +330,8 @@ class TestStreamControl(SlixTest):
|
|||||||
<query xmlns='http://jabber.org/protocol/disco#info'>
|
<query xmlns='http://jabber.org/protocol/disco#info'>
|
||||||
<identity category='client' type='bot'/>
|
<identity category='client' type='bot'/>
|
||||||
<feature var='urn:xmpp:iot:control'/>
|
<feature var='urn:xmpp:iot:control'/>
|
||||||
</query>
|
</query>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def testServiceDiscoveryComponent(self):
|
def testServiceDiscoveryComponent(self):
|
||||||
@ -356,8 +356,8 @@ class TestStreamControl(SlixTest):
|
|||||||
<query xmlns='http://jabber.org/protocol/disco#info'>
|
<query xmlns='http://jabber.org/protocol/disco#info'>
|
||||||
<identity category='component' type='generic'/>
|
<identity category='component' type='generic'/>
|
||||||
<feature var='urn:xmpp:iot:control'/>
|
<feature var='urn:xmpp:iot:control'/>
|
||||||
</query>
|
</query>
|
||||||
</iq>
|
</iq>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user