Merge remote-tracking branch 'origin/develop' into xep_0332

This commit is contained in:
Sangeeth Saravanaraj 2015-04-28 16:53:40 +05:30
commit 80b60fc048
40 changed files with 1353 additions and 1102 deletions

10
.travis.yml Normal file
View File

@ -0,0 +1,10 @@
language: python
python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"
- "3.4"
install:
- "pip install ."
script: testall.py

View File

@ -52,7 +52,7 @@ The latest source code for SleekXMPP may be found on `Github
Installing DNSPython Installing DNSPython
--------------------- --------------------
If you are using Python3 and wish to use dnspython, you will have to checkout and If you are using Python3 and wish to use dnspython, you will have to checkout and
install the ``python3`` branch:: install the ``python3`` branch::

View File

@ -179,13 +179,13 @@ if __name__ == '__main__':
# node=opts.nodeid, # node=opts.nodeid,
# jid=xmpp.boundjid.full) # jid=xmpp.boundjid.full)
myDevice = TheDevice(opts.nodeid); myDevice = TheDevice(opts.nodeid)
# myDevice._add_field(name="Relay", typename="numeric", unit="Bool"); # myDevice._add_field(name="Relay", typename="numeric", unit="Bool");
myDevice._add_field(name="Temperature", typename="numeric", unit="C"); myDevice._add_field(name="Temperature", typename="numeric", unit="C")
myDevice._set_momentary_timestamp("2013-03-07T16:24:30") myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"}); myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
xmpp['xep_0323'].register_node(nodeId=opts.nodeid, device=myDevice, commTimeout=10); xmpp['xep_0323'].register_node(nodeId=opts.nodeid, device=myDevice, commTimeout=10)
xmpp.beClientOrServer(server=True) xmpp.beClientOrServer(server=True)
while not(xmpp.testForRelease()): while not(xmpp.testForRelease()):
xmpp.connect() xmpp.connect()

View File

@ -68,7 +68,7 @@ class RosterBrowser(sleekxmpp.ClientXMPP):
try: try:
self.get_roster() self.get_roster()
except IqError as err: except IqError as err:
print('Error: %' % err.iq['error']['condition']) print('Error: %s' % err.iq['error']['condition'])
except IqTimeout: except IqTimeout:
print('Error: Request timed out') print('Error: Request timed out')
self.send_presence() self.send_presence()

View File

@ -63,7 +63,7 @@ class AvatarSetter(sleekxmpp.ClientXMPP):
avatar_file = None avatar_file = None
try: try:
avatar_file = open(os.path.expanduser(self.filepath)) avatar_file = open(os.path.expanduser(self.filepath), 'rb')
except IOError: except IOError:
print('Could not find file: %s' % self.filepath) print('Could not find file: %s' % self.filepath)
return self.disconnect() return self.disconnect()

View File

@ -25,7 +25,6 @@ from sleekxmpp.exceptions import IqError, IqTimeout
from sleekxmpp.stanza import Message, Presence, Iq, StreamError from sleekxmpp.stanza import Message, Presence, Iq, StreamError
from sleekxmpp.stanza.roster import Roster from sleekxmpp.stanza.roster import Roster
from sleekxmpp.stanza.nick import Nick from sleekxmpp.stanza.nick import Nick
from sleekxmpp.stanza.htmlim import HTMLIM
from sleekxmpp.xmlstream import XMLStream, JID from sleekxmpp.xmlstream import XMLStream, JID
from sleekxmpp.xmlstream import ET, register_stanza_plugin from sleekxmpp.xmlstream import ET, register_stanza_plugin
@ -245,7 +244,7 @@ class BaseXMPP(XMLStream):
self.plugin[name].post_inited = True self.plugin[name].post_inited = True
return XMLStream.process(self, *args, **kwargs) return XMLStream.process(self, *args, **kwargs)
def register_plugin(self, plugin, pconfig={}, module=None): def register_plugin(self, plugin, pconfig=None, module=None):
"""Register and configure a plugin for use in this stream. """Register and configure a plugin for use in this stream.
:param plugin: The name of the plugin class. Plugin names must :param plugin: The name of the plugin class. Plugin names must

View File

@ -49,8 +49,13 @@ class ComponentXMPP(BaseXMPP):
Defaults to ``False``. Defaults to ``False``.
""" """
def __init__(self, jid, secret, host=None, port=None, def __init__(self, jid, secret, host=None, port=None, plugin_config=None, plugin_whitelist=None, use_jc_ns=False):
plugin_config={}, plugin_whitelist=[], use_jc_ns=False):
if not plugin_whitelist:
plugin_whitelist = []
if not plugin_config:
plugin_config = {}
if use_jc_ns: if use_jc_ns:
default_ns = 'jabber:client' default_ns = 'jabber:client'
else: else:

View File

@ -187,14 +187,14 @@ class FeatureMechanisms(BasePlugin):
except sasl.SASLCancelled: except sasl.SASLCancelled:
self.attempted_mechs.add(self.mech.name) self.attempted_mechs.add(self.mech.name)
self._send_auth() self._send_auth()
except sasl.SASLFailed:
self.attempted_mechs.add(self.mech.name)
self._send_auth()
except sasl.SASLMutualAuthFailed: except sasl.SASLMutualAuthFailed:
log.error("Mutual authentication failed! " + \ log.error("Mutual authentication failed! " + \
"A security breach is possible.") "A security breach is possible.")
self.attempted_mechs.add(self.mech.name) self.attempted_mechs.add(self.mech.name)
self.xmpp.disconnect() self.xmpp.disconnect()
except sasl.SASLFailed:
self.attempted_mechs.add(self.mech.name)
self._send_auth()
else: else:
resp.send(now=True) resp.send(now=True)
@ -207,13 +207,13 @@ class FeatureMechanisms(BasePlugin):
resp['value'] = self.mech.process(stanza['value']) resp['value'] = self.mech.process(stanza['value'])
except sasl.SASLCancelled: except sasl.SASLCancelled:
self.stanza.Abort(self.xmpp).send() self.stanza.Abort(self.xmpp).send()
except sasl.SASLFailed:
self.stanza.Abort(self.xmpp).send()
except sasl.SASLMutualAuthFailed: except sasl.SASLMutualAuthFailed:
log.error("Mutual authentication failed! " + \ log.error("Mutual authentication failed! " + \
"A security breach is possible.") "A security breach is possible.")
self.attempted_mechs.add(self.mech.name) self.attempted_mechs.add(self.mech.name)
self.xmpp.disconnect() self.xmpp.disconnect()
except sasl.SASLFailed:
self.stanza.Abort(self.xmpp).send()
else: else:
if resp.get_value() == '': if resp.get_value() == '':
resp.del_value() resp.del_value()

View File

@ -24,7 +24,7 @@ class GoogleAuth(ElementBase):
print('setting up google extension') print('setting up google extension')
def get_client_uses_full_bind_result(self): def get_client_uses_full_bind_result(self):
return self.parent()._get_attr(self.disovery_attr) == 'true' return self.parent()._get_attr(self.discovery_attr) == 'true'
def set_client_uses_full_bind_result(self, value): def set_client_uses_full_bind_result(self, value):
print('>>>', value) print('>>>', value)

View File

@ -52,7 +52,7 @@ class Item(ElementBase):
def get_source(self): def get_source(self):
return JID(self._get_attr('source', '')) return JID(self._get_attr('source', ''))
def set_source(self): def set_source(self, value):
self._set_attr('source', str(value)) self._set_attr('source', str(value))

View File

@ -6,8 +6,6 @@
See the file LICENSE for copying permission. See the file LICENSE for copying permission.
""" """
import logging
from sleekxmpp.stanza import Iq from sleekxmpp.stanza import Iq
from sleekxmpp.xmlstream.handler import Callback from sleekxmpp.xmlstream.handler import Callback
from sleekxmpp.xmlstream.matcher import StanzaPath from sleekxmpp.xmlstream.matcher import StanzaPath

View File

@ -151,7 +151,6 @@ class Form(ElementBase):
return fields return fields
def get_instructions(self): def get_instructions(self):
instructions = ''
instsXML = self.xml.findall('{%s}instructions' % self.namespace) instsXML = self.xml.findall('{%s}instructions' % self.namespace)
return "\n".join([instXML.text for instXML in instsXML]) return "\n".join([instXML.text for instXML in instsXML])

View File

@ -6,7 +6,7 @@
See the file LICENSE for copying permission. See the file LICENSE for copying permission.
""" """
from binding import py2xml, xml2py, xml2fault, fault2xml from sleekxmpp.plugins.xep_0009.binding import py2xml, xml2py, xml2fault, fault2xml
from threading import RLock from threading import RLock
import abc import abc
import inspect import inspect
@ -18,6 +18,45 @@ import traceback
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# Define a function _isstr() to check if an object is a string in a way
# compatible with Python 2 and Python 3 (basestring does not exists in Python 3).
try:
basestring # This evaluation will throw an exception if basestring does not exists (Python 3).
def _isstr(obj):
return isinstance(obj, basestring)
except NameError:
def _isstr(obj):
return isinstance(obj, str)
# Class decorator to declare a metaclass to a class in a way compatible with Python 2 and 3.
# This decorator is copied from 'six' (https://bitbucket.org/gutworth/six):
#
# Copyright (c) 2010-2015 Benjamin Peterson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
def _add_metaclass(metaclass):
def wrapper(cls):
orig_vars = cls.__dict__.copy()
slots = orig_vars.get('__slots__')
if slots is not None:
if isinstance(slots, str):
slots = [slots]
for slots_var in slots:
orig_vars.pop(slots_var)
orig_vars.pop('__dict__', None)
orig_vars.pop('__weakref__', None)
return metaclass(cls.__name__, cls.__bases__, orig_vars)
return wrapper
def _intercept(method, name, public): def _intercept(method, name, public):
def _resolver(instance, *args, **kwargs): def _resolver(instance, *args, **kwargs):
log.debug("Locally calling %s.%s with arguments %s.", instance.FQN(), method.__name__, args) log.debug("Locally calling %s.%s with arguments %s.", instance.FQN(), method.__name__, args)
@ -68,7 +107,7 @@ def remote(function_argument, public = True):
if hasattr(function_argument, '__call__'): if hasattr(function_argument, '__call__'):
return _intercept(function_argument, None, public) return _intercept(function_argument, None, public)
else: else:
if not isinstance(function_argument, basestring): if not _isstr(function_argument):
if not isinstance(function_argument, bool): if not isinstance(function_argument, bool):
raise Exception('Expected an RPC method name or visibility modifier!') raise Exception('Expected an RPC method name or visibility modifier!')
else: else:
@ -222,12 +261,11 @@ class TimeoutException(Exception):
pass pass
@_add_metaclass(abc.ABCMeta)
class Callback(object): class Callback(object):
''' '''
A base class for callback handlers. A base class for callback handlers.
''' '''
__metaclass__ = abc.ABCMeta
@abc.abstractproperty @abc.abstractproperty
def set_value(self, value): def set_value(self, value):
@ -291,7 +329,7 @@ class Future(Callback):
self._event.set() self._event.set()
@_add_metaclass(abc.ABCMeta)
class Endpoint(object): class Endpoint(object):
''' '''
The Endpoint class is an abstract base class for all objects The Endpoint class is an abstract base class for all objects
@ -303,8 +341,6 @@ class Endpoint(object):
which specifies which object an RPC call refers to. It is the which specifies which object an RPC call refers to. It is the
first part in a RPC method name '<fqn>.<method>'. first part in a RPC method name '<fqn>.<method>'.
''' '''
__metaclass__ = abc.ABCMeta
def __init__(self, session, target_jid): def __init__(self, session, target_jid):
''' '''
@ -491,7 +527,7 @@ class RemoteSession(object):
def _find_key(self, dict, value): def _find_key(self, dict, value):
"""return the key of dictionary dic given the value""" """return the key of dictionary dic given the value"""
search = [k for k, v in dict.iteritems() if v == value] search = [k for k, v in dict.items() if v == value]
if len(search) == 0: if len(search) == 0:
return None return None
else: else:
@ -547,7 +583,7 @@ class RemoteSession(object):
result = handler_cls(*args, **kwargs) result = handler_cls(*args, **kwargs)
Endpoint.__init__(result, self, self._client.boundjid.full) Endpoint.__init__(result, self, self._client.boundjid.full)
method_dict = result.get_methods() method_dict = result.get_methods()
for method_name, method in method_dict.iteritems(): for method_name, method in method_dict.items():
#!!! self._client.plugin['xep_0009'].register_call(result.FQN(), method, method_name) #!!! self._client.plugin['xep_0009'].register_call(result.FQN(), method, method_name)
self._register_call(result.FQN(), method, method_name) self._register_call(result.FQN(), method, method_name)
self._register_acl(result.FQN(), acl) self._register_acl(result.FQN(), acl)
@ -697,7 +733,8 @@ class Remote(object):
if(client.boundjid.bare in cls._sessions): if(client.boundjid.bare in cls._sessions):
raise RemoteException("There already is a session associated with these credentials!") raise RemoteException("There already is a session associated with these credentials!")
else: else:
cls._sessions[client.boundjid.bare] = client; cls._sessions[client.boundjid.bare] = client
def _session_close_callback(): def _session_close_callback():
with Remote._lock: with Remote._lock:
del cls._sessions[client.boundjid.bare] del cls._sessions[client.boundjid.bare]

View File

@ -61,7 +61,7 @@ class XEP_0009(BasePlugin):
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)
@ -93,7 +93,7 @@ class XEP_0009(BasePlugin):
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'

View File

@ -604,7 +604,7 @@ class XEP_0030(BasePlugin):
""" """
self.api['del_features'](jid, node, None, kwargs) self.api['del_features'](jid, node, None, kwargs)
def _run_node_handler(self, htype, jid, node=None, ifrom=None, data={}): def _run_node_handler(self, htype, jid, node=None, ifrom=None, data=None):
""" """
Execute the most specific node handler for the given Execute the most specific node handler for the given
JID/node combination. JID/node combination.
@ -615,6 +615,9 @@ class XEP_0030(BasePlugin):
node -- The node requested. node -- The node requested.
data -- Optional, custom data to pass to the handler. data -- Optional, custom data to pass to the handler.
""" """
if not data:
data = {}
return self.api[htype](jid, node, ifrom, data) return self.api[htype](jid, node, ifrom, data)
def _handle_disco_info(self, iq): def _handle_disco_info(self, iq):

View File

@ -240,9 +240,9 @@ class XEP_0065(base_plugin):
# The hostname MUST be SHA1(SID + Requester JID + Target JID) # The hostname MUST be SHA1(SID + Requester JID + Target JID)
# where the output is hexadecimal-encoded (not binary). # where the output is hexadecimal-encoded (not binary).
digest = sha1() digest = sha1()
digest.update(sid) digest.update(sid.encode('utf-8'))
digest.update(str(requester)) digest.update(str(requester).encode('utf-8'))
digest.update(str(target)) digest.update(str(target).encode('utf-8'))
dest = digest.hexdigest() dest = digest.hexdigest()

View File

@ -8,7 +8,7 @@
from base64 import b64encode, b64decode from base64 import b64encode, b64decode
from sleekxmpp.util import bytes from sleekxmpp.util import bytes as sbytes
from sleekxmpp.xmlstream import ET, ElementBase, register_stanza_plugin from sleekxmpp.xmlstream import ET, ElementBase, register_stanza_plugin
@ -20,12 +20,15 @@ class Data(ElementBase):
def get_value(self): def get_value(self):
if self.xml.text: if self.xml.text:
return b64decode(bytes(self.xml.text)) return b64decode(sbytes(self.xml.text))
return '' return ''
def set_value(self, value): def set_value(self, value):
if value: if value:
self.xml.text = b64encode(bytes(value)) self.xml.text = b64encode(sbytes(value))
# Python3 base64 encoded is bytes and needs to be decoded to string
if isinstance(self.xml.text, bytes):
self.xml.text = self.xml.text.decode()
else: else:
self.xml.text = '' self.xml.text = ''

View File

@ -0,0 +1,148 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2011 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import logging
import socket
import zlib
from sleekxmpp.thirdparty.suelta.util import bytes
from sleekxmpp.stanza import StreamFeatures
from sleekxmpp.xmlstream import RestartStream, register_stanza_plugin, ElementBase, StanzaBase
from sleekxmpp.xmlstream.matcher import *
from sleekxmpp.xmlstream.handler import *
from sleekxmpp.plugins import BasePlugin, register_plugin
log = logging.getLogger(__name__)
class Compression(ElementBase):
name = 'compression'
namespace = 'http://jabber.org/features/compress'
interfaces = set(('methods',))
plugin_attrib = 'compression'
plugin_tag_map = {}
plugin_attrib_map = {}
def get_methods(self):
methods = []
for method in self.xml.findall('{%s}method' % self.namespace):
methods.append(method.text)
return methods
class Compress(StanzaBase):
name = 'compress'
namespace = 'http://jabber.org/protocol/compress'
interfaces = set(('method',))
sub_interfaces = interfaces
plugin_attrib = 'compress'
plugin_tag_map = {}
plugin_attrib_map = {}
def setup(self, xml):
StanzaBase.setup(self, xml)
self.xml.tag = self.tag_name()
class Compressed(StanzaBase):
name = 'compressed'
namespace = 'http://jabber.org/protocol/compress'
interfaces = set()
plugin_tag_map = {}
plugin_attrib_map = {}
def setup(self, xml):
StanzaBase.setup(self, xml)
self.xml.tag = self.tag_name()
class ZlibSocket(object):
def __init__(self, socketobj):
self.__socket = socketobj
self.compressor = zlib.compressobj()
self.decompressor = zlib.decompressobj(zlib.MAX_WBITS)
def __getattr__(self, name):
return getattr(self.__socket, name)
def send(self, data):
sentlen = len(data)
data = self.compressor.compress(data)
data += self.compressor.flush(zlib.Z_SYNC_FLUSH)
log.debug(b'>>> (compressed)' + (data.encode("hex")))
#return self.__socket.send(data)
sentactuallen = self.__socket.send(data)
assert(sentactuallen == len(data))
return sentlen
def recv(self, *args, **kwargs):
data = self.__socket.recv(*args, **kwargs)
log.debug(b'<<< (compressed)' + data.encode("hex"))
return self.decompressor.decompress(self.decompressor.unconsumed_tail + data)
class XEP_0138(BasePlugin):
"""
XEP-0138: Compression
"""
name = "xep_0138"
description = "XEP-0138: Compression"
dependencies = set(["xep_0030"])
def plugin_init(self):
self.xep = '0138'
self.description = 'Stream Compression (Generic)'
self.compression_methods = {'zlib': True}
register_stanza_plugin(StreamFeatures, Compression)
self.xmpp.register_stanza(Compress)
self.xmpp.register_stanza(Compressed)
self.xmpp.register_handler(
Callback('Compressed',
StanzaPath('compressed'),
self._handle_compressed,
instream=True))
self.xmpp.register_feature('compression',
self._handle_compression,
restart=True,
order=self.config.get('order', 5))
def register_compression_method(self, name, handler):
self.compression_methods[name] = handler
def _handle_compression(self, features):
for method in features['compression']['methods']:
if method in self.compression_methods:
log.info('Attempting to use %s compression' % method)
c = Compress(self.xmpp)
c['method'] = method
c.send(now=True)
return True
return False
def _handle_compressed(self, stanza):
self.xmpp.features.add('compression')
log.debug('Stream Compressed!')
compressed_socket = ZlibSocket(self.xmpp.socket)
self.xmpp.set_socket(compressed_socket)
raise RestartStream()
def _handle_failure(self, stanza):
pass
xep_0138 = XEP_0138
register_plugin(XEP_0138)

View File

@ -10,7 +10,7 @@ from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin
class Certs(ElementBase): class Certs(ElementBase):
name = 'query' name = 'items'
namespace = 'urn:xmpp:saslcert:1' namespace = 'urn:xmpp:saslcert:1'
plugin_attrib = 'sasl_certs' plugin_attrib = 'sasl_certs'
interfaces = set() interfaces = set()

View File

@ -21,7 +21,10 @@ class Device(object):
request_fields request_fields
""" """
def __init__(self, nodeId, fields={}): def __init__(self, nodeId, fields=None):
if not fields:
fields = {}
self.nodeId = nodeId self.nodeId = nodeId
self.fields = fields # see fields described below self.fields = fields # see fields described below
# {'type':'numeric', # {'type':'numeric',
@ -41,8 +44,8 @@ class Device(object):
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):
""" """
@ -101,10 +104,10 @@ class Device(object):
for f in fields: for f in fields:
if f not in self.fields.keys(): if f not in self.fields.keys():
self._send_reject(session, callback) self._send_reject(session, callback)
return False; return False
else: else:
# Request all fields # Request all fields
fields = self.fields.keys(); fields = self.fields.keys()
# Refresh data from device # Refresh data from device
@ -114,15 +117,15 @@ class Device(object):
if "momentary" in flags and flags['momentary'] == "true" or \ if "momentary" in flags and flags['momentary'] == "true" or \
"all" in flags and flags['all'] == "true": "all" in flags and flags['all'] == "true":
ts_block = {}; ts_block = {}
timestamp = ""; timestamp = ""
if len(self.momentary_timestamp) > 0: if len(self.momentary_timestamp) > 0:
timestamp = self.momentary_timestamp; timestamp = self.momentary_timestamp
else: else:
timestamp = self._get_timestamp(); timestamp = self._get_timestamp()
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,
@ -130,11 +133,11 @@ class Device(object):
"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
callback(session, result="done", nodeId=self.nodeId, timestamp_block=ts_block); callback(session, result="done", nodeId=self.nodeId, timestamp_block=ts_block)
return return
from_flag = self._datetime_flag_parser(flags, 'from') from_flag = self._datetime_flag_parser(flags, 'from')
@ -151,8 +154,8 @@ class Device(object):
#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:
@ -161,12 +164,12 @@ class Device(object):
"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
ts_block["fields"] = field_block; ts_block["fields"] = field_block
callback(session, result="fields", nodeId=self.nodeId, timestamp_block=ts_block); callback(session, result="fields", nodeId=self.nodeId, timestamp_block=ts_block)
callback(session, result="done", nodeId=self.nodeId, timestamp_block=None); callback(session, result="done", nodeId=self.nodeId, timestamp_block=None)
def _datetime_flag_parser(self, flags, flagname): def _datetime_flag_parser(self, flags, flagname):
if not flagname in flags: if not flagname in flags:
@ -195,7 +198,7 @@ class Device(object):
session -- Session id, see definition in request_fields function session -- Session id, see definition in request_fields function
callback -- Callback function, see definition in request_fields function callback -- Callback function, see definition in request_fields function
""" """
callback(session, result="error", nodeId=self.nodeId, timestamp_block=None, error_msg="Reject"); callback(session, result="error", nodeId=self.nodeId, timestamp_block=None, error_msg="Reject")
def _add_field(self, name, typename, unit=None, dataType=None): def _add_field(self, name, typename, unit=None, dataType=None):
""" """
@ -207,7 +210,7 @@ class Device(object):
unit -- [optional] only applies to "numeric". Unit for the field. unit -- [optional] only applies to "numeric". Unit for the field.
dataType -- [optional] only applies to "enum". Datatype for the field. dataType -- [optional] only applies to "enum". Datatype for the field.
""" """
self.fields[name] = {"type": typename, "unit": unit, "dataType": dataType}; self.fields[name] = {"type": typename, "unit": unit, "dataType": dataType}
def _add_field_timestamp_data(self, name, timestamp, value, flags=None): def _add_field_timestamp_data(self, name, timestamp, value, flags=None):
""" """
@ -221,12 +224,12 @@ class Device(object):
Formatted as a dictionary like { "flag name": "flag value" ... } Formatted as a dictionary like { "flag name": "flag value" ... }
""" """
if not name in self.fields.keys(): if not name in self.fields.keys():
return False; return False
if not timestamp in self.timestamp_data: if not timestamp in self.timestamp_data:
self.timestamp_data[timestamp] = {}; self.timestamp_data[timestamp] = {}
self.timestamp_data[timestamp][name] = {"value": value, "flags": flags}; self.timestamp_data[timestamp][name] = {"value": value, "flags": flags}
return True; return True
def _add_field_momentary_data(self, name, value, flags=None): def _add_field_momentary_data(self, name, value, flags=None):
""" """
@ -239,17 +242,17 @@ class Device(object):
Formatted as a dictionary like { "flag name": "flag value" ... } Formatted as a dictionary like { "flag name": "flag value" ... }
""" """
if name not in self.fields: if name not in self.fields:
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
def _set_momentary_timestamp(self, timestamp): def _set_momentary_timestamp(self, timestamp):
""" """
This function is only for unit testing to produce predictable results. This function is only for unit testing to produce predictable results.
""" """
self.momentary_timestamp = timestamp; self.momentary_timestamp = timestamp

View File

@ -155,11 +155,11 @@ class XEP_0323(BasePlugin):
self._handle_event_started)) self._handle_event_started))
# Server side dicts # Server side dicts
self.nodes = {}; self.nodes = {}
self.sessions = {}; self.sessions = {}
self.last_seqnr = 0; self.last_seqnr = 0
self.seqnr_lock = Lock(); self.seqnr_lock = Lock()
## For testning only ## For testning only
self.test_authenticated_from = "" self.test_authenticated_from = ""
@ -182,7 +182,7 @@ class XEP_0323(BasePlugin):
def plugin_end(self): def plugin_end(self):
""" Stop the XEP-0323 plugin """ """ Stop the XEP-0323 plugin """
self.sessions.clear(); self.sessions.clear()
self.xmpp.remove_handler('Sensordata Event:Req') self.xmpp.remove_handler('Sensordata Event:Req')
self.xmpp.remove_handler('Sensordata Event:Accepted') self.xmpp.remove_handler('Sensordata Event:Accepted')
self.xmpp.remove_handler('Sensordata Event:Rejected') self.xmpp.remove_handler('Sensordata Event:Rejected')
@ -217,11 +217,11 @@ class XEP_0323(BasePlugin):
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=''):
""" Internal testing function """ """ Internal testing function """
self.test_authenticated_from = auth; self.test_authenticated_from = auth
def _handle_event_req(self, iq): def _handle_event_req(self, iq):
@ -238,42 +238,42 @@ class XEP_0323(BasePlugin):
If the verification fails, a reject message is sent. If the verification fails, a reject message is sent.
""" """
seqnr = iq['req']['seqnr']; seqnr = iq['req']['seqnr']
error_msg = ''; error_msg = ''
req_ok = True; req_ok = True
# Authentication # Authentication
if len(self.test_authenticated_from) > 0 and not iq['from'] == self.test_authenticated_from: if len(self.test_authenticated_from) > 0 and not iq['from'] == self.test_authenticated_from:
# Invalid authentication # Invalid authentication
req_ok = False; req_ok = False
error_msg = "Access denied"; error_msg = "Access denied"
# Nodes # Nodes
process_nodes = []; process_nodes = []
if len(iq['req']['nodes']) > 0: if len(iq['req']['nodes']) > 0:
for n in iq['req']['nodes']: for n in iq['req']['nodes']:
if not n['nodeId'] in self.nodes: if not n['nodeId'] in self.nodes:
req_ok = False; req_ok = False
error_msg = "Invalid nodeId " + n['nodeId']; error_msg = "Invalid nodeId " + n['nodeId']
process_nodes = [n['nodeId'] for n in iq['req']['nodes']]; process_nodes = [n['nodeId'] for n in iq['req']['nodes']]
else: else:
process_nodes = self.nodes.keys(); process_nodes = self.nodes.keys()
# Fields - if we just find one we are happy, otherwise we reject # Fields - if we just find one we are happy, otherwise we reject
process_fields = []; process_fields = []
if len(iq['req']['fields']) > 0: if len(iq['req']['fields']) > 0:
found = False found = False
for f in iq['req']['fields']: for f in iq['req']['fields']:
for node in self.nodes: for node in self.nodes:
if self.nodes[node]["device"].has_field(f['name']): if self.nodes[node]["device"].has_field(f['name']):
found = True; found = True
break; break
if not found: if not found:
req_ok = False; req_ok = False
error_msg = "Invalid field " + f['name']; error_msg = "Invalid field " + f['name']
process_fields = [f['name'] for n in iq['req']['fields']]; process_fields = [f['name'] for n in iq['req']['fields']]
req_flags = iq['req']._get_flags(); req_flags = iq['req']._get_flags()
request_delay_sec = None request_delay_sec = None
if 'when' in req_flags: if 'when' in req_flags:
@ -283,7 +283,7 @@ class XEP_0323(BasePlugin):
try: try:
dt = datetime.datetime.strptime(req_flags['when'], "%Y-%m-%dT%H:%M:%S") dt = datetime.datetime.strptime(req_flags['when'], "%Y-%m-%dT%H:%M:%S")
except ValueError: except ValueError:
req_ok = False; req_ok = False
error_msg = "Invalid datetime in 'when' flag, please use ISO format (i.e. 2013-04-05T15:00:03)." error_msg = "Invalid datetime in 'when' flag, please use ISO format (i.e. 2013-04-05T15:00:03)."
if not dt is None: if not dt is None:
@ -292,30 +292,30 @@ class XEP_0323(BasePlugin):
dtdiff = dt - dtnow dtdiff = dt - dtnow
request_delay_sec = dtdiff.seconds + dtdiff.days * 24 * 3600 request_delay_sec = dtdiff.seconds + dtdiff.days * 24 * 3600
if request_delay_sec <= 0: if request_delay_sec <= 0:
req_ok = False; req_ok = False
error_msg = "Invalid datetime in 'when' flag, cannot set a time in the past. Current time: " + dtnow.isoformat(); error_msg = "Invalid datetime in 'when' flag, cannot set a time in the past. Current time: " + dtnow.isoformat()
if req_ok: if req_ok:
session = self._new_session(); session = self._new_session()
self.sessions[session] = {"from": iq['from'], "to": iq['to'], "seqnr": seqnr}; self.sessions[session] = {"from": iq['from'], "to": iq['to'], "seqnr": seqnr}
self.sessions[session]["commTimers"] = {}; self.sessions[session]["commTimers"] = {}
self.sessions[session]["nodeDone"] = {}; self.sessions[session]["nodeDone"] = {}
#print("added session: " + str(self.sessions)) #print("added session: " + str(self.sessions))
iq.reply(); iq.reply()
iq['accepted']['seqnr'] = seqnr; iq['accepted']['seqnr'] = seqnr
if not request_delay_sec is None: if not request_delay_sec is None:
iq['accepted']['queued'] = "true" iq['accepted']['queued'] = "true"
iq.send(block=False); iq.send(block=False)
self.sessions[session]["node_list"] = process_nodes; self.sessions[session]["node_list"] = process_nodes
if not request_delay_sec is None: if not request_delay_sec is None:
# Delay request to requested time # Delay request to requested time
timer = Timer(request_delay_sec, self._event_delayed_req, args=(session, process_fields, req_flags)) timer = Timer(request_delay_sec, self._event_delayed_req, args=(session, process_fields, req_flags))
self.sessions[session]["commTimers"]["delaytimer"] = timer; self.sessions[session]["commTimers"]["delaytimer"] = timer
timer.start(); timer.start()
return return
if self.threaded: if self.threaded:
@ -324,14 +324,14 @@ class XEP_0323(BasePlugin):
tr_req.start() tr_req.start()
#print("started thread") #print("started thread")
else: else:
self._threaded_node_request(session, process_fields, req_flags); self._threaded_node_request(session, process_fields, req_flags)
else: else:
iq.reply(); iq.reply()
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):
""" """
@ -344,14 +344,14 @@ 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))
self.sessions[session]["commTimers"][node] = timer; self.sessions[session]["commTimers"][node] = timer
#print("Starting timer " + str(timer) + ", timeout: " + str(self.nodes[node]['commTimeout'])) #print("Starting timer " + str(timer) + ", timeout: " + str(self.nodes[node]['commTimeout']))
timer.start(); timer.start()
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):
""" """
@ -363,22 +363,22 @@ class XEP_0323(BasePlugin):
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
""" """
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()
# 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'
msg.send(); msg.send()
# The session is complete, delete it # The session is complete, delete it
#print("del session " + session + " due to timeout") #print("del session " + session + " due to timeout")
del self.sessions[session]; del self.sessions[session]
def _event_delayed_req(self, session, process_fields, req_flags): def _event_delayed_req(self, session, process_fields, req_flags):
""" """
@ -390,17 +390,17 @@ class XEP_0323(BasePlugin):
flags -- [optional] flags to pass to the devices, e.g. momentary flags -- [optional] flags to pass to the devices, e.g. momentary
Formatted as a dictionary like { "flag name": "flag value" ... } Formatted as a dictionary like { "flag name": "flag value" ... }
""" """
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['started']['seqnr'] = self.sessions[session]['seqnr']; msg['started']['seqnr'] = self.sessions[session]['seqnr']
msg.send(); msg.send()
if self.threaded: if self.threaded:
tr_req = Thread(target=self._threaded_node_request, args=(session, process_fields, req_flags)) tr_req = Thread(target=self._threaded_node_request, args=(session, process_fields, req_flags))
tr_req.start() tr_req.start()
else: else:
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):
""" """
@ -411,8 +411,8 @@ class XEP_0323(BasePlugin):
""" """
for n in self.sessions[session]["nodeDone"]: for n in self.sessions[session]["nodeDone"]:
if not self.sessions[session]["nodeDone"][n]: if not self.sessions[session]["nodeDone"][n]:
return False; return False
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):
""" """
@ -452,33 +452,33 @@ class XEP_0323(BasePlugin):
return return
if result == "error": if result == "error":
self.sessions[session]["commTimers"][nodeId].cancel(); self.sessions[session]["commTimers"][nodeId].cancel()
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'] = error_msg; msg['failure']['error']['text'] = error_msg
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()
# 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
# print("del session " + session + " due to error") # print("del session " + session + " due to error")
del self.sessions[session]; del self.sessions[session]
msg.send(); msg.send()
else: else:
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['fields']['seqnr'] = self.sessions[session]['seqnr']; msg['fields']['seqnr'] = self.sessions[session]['seqnr']
if timestamp_block is not None and len(timestamp_block) > 0: if timestamp_block is not None and len(timestamp_block) > 0:
node = msg['fields'].add_node(nodeId); node = msg['fields'].add_node(nodeId)
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'],
@ -486,52 +486,52 @@ class XEP_0323(BasePlugin):
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":
self.sessions[session]["commTimers"][nodeId].cancel(); self.sessions[session]["commTimers"][nodeId].cancel()
self.sessions[session]["nodeDone"][nodeId] = True; self.sessions[session]["nodeDone"][nodeId] = True
msg['fields']['done'] = 'true'; msg['fields']['done'] = '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
# print("del session " + session + " due to complete") # print("del session " + session + " due to complete")
del self.sessions[session]; del self.sessions[session]
else: else:
# Restart comm timer # Restart comm timer
self.sessions[session]["commTimers"][nodeId].reset(); self.sessions[session]["commTimers"][nodeId].reset()
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']
# Find the session # Find the session
for s in self.sessions: for s in self.sessions:
if self.sessions[s]['from'] == iq['from'] and self.sessions[s]['to'] == iq['to'] and self.sessions[s]['seqnr'] == seqnr: if self.sessions[s]['from'] == iq['from'] and self.sessions[s]['to'] == iq['to'] and self.sessions[s]['seqnr'] == seqnr:
# found it. Cancel all timers # found it. Cancel all timers
for n in self.sessions[s]["commTimers"]: for n in self.sessions[s]["commTimers"]:
self.sessions[s]["commTimers"][n].cancel(); self.sessions[s]["commTimers"][n].cancel()
# Confirm # Confirm
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
# Could not find session, send reject # Could not find session, send reject
iq.reply(); iq.reply()
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):
@ -593,26 +593,26 @@ class XEP_0323(BasePlugin):
session -- Session identifier. Client can use this as a reference to cancel session -- Session identifier. Client can use this as a reference to cancel
the request. the request.
""" """
iq = self.xmpp.Iq(); iq = self.xmpp.Iq()
iq['from'] = from_jid; iq['from'] = from_jid
iq['to'] = to_jid; iq['to'] = to_jid
iq['type'] = "get"; iq['type'] = "get"
seqnr = self._get_new_seqnr(); seqnr = self._get_new_seqnr()
iq['id'] = seqnr; iq['id'] = seqnr
iq['req']['seqnr'] = seqnr; iq['req']['seqnr'] = seqnr
if nodeIds is not None: if nodeIds is not None:
for nodeId in nodeIds: for nodeId in nodeIds:
iq['req'].add_node(nodeId); iq['req'].add_node(nodeId)
if fields is not None: if fields is not None:
for field in fields: for field in fields:
iq['req'].add_field(field); iq['req'].add_field(field)
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):
""" """
@ -625,39 +625,39 @@ class XEP_0323(BasePlugin):
session -- The session id of the request to cancel session -- The session id of the request to cancel
""" """
seqnr = session seqnr = session
iq = self.xmpp.Iq(); iq = self.xmpp.Iq()
iq['from'] = self.sessions[seqnr]['from'] iq['from'] = self.sessions[seqnr]['from']
iq['to'] = self.sessions[seqnr]['to']; iq['to'] = self.sessions[seqnr]['to']
iq['type'] = "get"; iq['type'] = "get"
iq['id'] = seqnr; iq['id'] = seqnr
iq['cancel']['seqnr'] = seqnr; iq['cancel']['seqnr'] = seqnr
iq.send(block=False); iq.send(block=False)
def _get_new_seqnr(self): def _get_new_seqnr(self):
""" Returns a unique sequence number (unique across threads) """ """ Returns a unique sequence number (unique across threads) """
self.seqnr_lock.acquire(); self.seqnr_lock.acquire()
self.last_seqnr = self.last_seqnr + 1; self.last_seqnr += 1
self.seqnr_lock.release(); self.seqnr_lock.release()
return str(self.last_seqnr); return str(self.last_seqnr)
def _handle_event_accepted(self, iq): def _handle_event_accepted(self, iq):
""" Received Iq with accepted - request was accepted """ """ Received Iq with accepted - request was accepted """
seqnr = iq['accepted']['seqnr']; seqnr = iq['accepted']['seqnr']
result = "accepted" result = "accepted"
if iq['accepted']['queued'] == 'true': if iq['accepted']['queued'] == 'true':
result = "queued" result = "queued"
callback = self.sessions[seqnr]["callback"]; callback = self.sessions[seqnr]["callback"]
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"]
callback(from_jid=iq['from'], result="rejected", error_msg=iq['rejected']['error']); callback(from_jid=iq['from'], result="rejected", error_msg=iq['rejected']['error'])
# Session terminated # Session terminated
del self.sessions[seqnr]; del self.sessions[seqnr]
def _handle_event_cancelled(self, iq): def _handle_event_cancelled(self, iq):
""" """
@ -665,59 +665,59 @@ class XEP_0323(BasePlugin):
Delete the session. Delete the session.
""" """
#print("Got cancelled") #print("Got cancelled")
seqnr = iq['cancelled']['seqnr']; seqnr = iq['cancelled']['seqnr']
callback = self.sessions[seqnr]["callback"]; callback = self.sessions[seqnr]["callback"]
callback(from_jid=iq['from'], result="cancelled"); callback(from_jid=iq['from'], result="cancelled")
# Session cancelled # Session cancelled
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.
""" """
seqnr = msg['fields']['seqnr']; seqnr = msg['fields']['seqnr']
callback = self.sessions[seqnr]["callback"]; callback = self.sessions[seqnr]["callback"]
for node in msg['fields']['nodes']: for node in msg['fields']['nodes']:
for ts in node['timestamps']: for ts in node['timestamps']:
fields = []; fields = []
for d in ts['datas']: for d in ts['datas']:
field_block = {}; field_block = {}
field_block["name"] = d['name']; field_block["name"] = d['name']
field_block["typename"] = d._get_typename(); field_block["typename"] = d._get_typename()
field_block["value"] = d['value']; field_block["value"] = d['value']
if not d['unit'] == "": field_block["unit"] = d['unit']; if not d['unit'] == "": field_block["unit"] = d['unit'];
if not d['dataType'] == "": field_block["dataType"] = d['dataType']; if not d['dataType'] == "": field_block["dataType"] = d['dataType'];
flags = d._get_flags(); flags = d._get_flags()
if not len(flags) == 0: if not len(flags) == 0:
field_block["flags"] = flags; field_block["flags"] = flags
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"]
callback(from_jid=msg['from'], result="failure", nodeId=msg['failure']['error']['nodeId'], timestamp=msg['failure']['error']['timestamp'], error_msg=msg['failure']['error']['text']); callback(from_jid=msg['from'], result="failure", nodeId=msg['failure']['error']['nodeId'], timestamp=msg['failure']['error']['timestamp'], error_msg=msg['failure']['error']['text'])
# Session failed # Session failed
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")

View File

@ -38,12 +38,12 @@ class Request(ElementBase):
name = 'req' name = 'req'
plugin_attrib = name plugin_attrib = name
interfaces = set(['seqnr','nodes','fields','serviceToken','deviceToken','userToken','from','to','when','historical','all']) interfaces = set(['seqnr','nodes','fields','serviceToken','deviceToken','userToken','from','to','when','historical','all'])
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()
self._fields = set() self._fields = set()
@ -67,11 +67,11 @@ class Request(ElementBase):
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:
if not self[f] == "": if not self[f] == "":
flags[f] = self[f]; flags[f] = self[f]
return flags; return flags
def _set_flags(self, flags): def _set_flags(self, flags):
""" """
@ -82,9 +82,9 @@ class Request(ElementBase):
""" """
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:
self[f] = flags[f]; self[f] = flags[f]
else: else:
self[f] = None; self[f] = None
def add_node(self, nodeId, sourceId=None, cacheType=None): def add_node(self, nodeId, sourceId=None, cacheType=None):
""" """
@ -269,7 +269,7 @@ class Error(ElementBase):
:param value: string :param value: string
""" """
self.xml.text = value; self.xml.text = value
return self return self
def del_text(self): def del_text(self):
@ -292,7 +292,7 @@ class Fields(ElementBase):
interfaces = set(['seqnr','done','nodes']) interfaces = set(['seqnr','done','nodes'])
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()
def setup(self, xml=None): def setup(self, xml=None):
@ -392,7 +392,7 @@ class FieldsNode(ElementBase):
interfaces = set(['nodeId','sourceId','cacheType','timestamps']) interfaces = set(['nodeId','sourceId','cacheType','timestamps'])
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._timestamps = set() self._timestamps = set()
def setup(self, xml=None): def setup(self, xml=None):
@ -423,7 +423,7 @@ class FieldsNode(ElementBase):
ts = Timestamp(parent=self) ts = Timestamp(parent=self)
ts['value'] = timestamp ts['value'] = timestamp
if not substanzas is None: if not substanzas is None:
ts.set_datas(substanzas); ts.set_datas(substanzas)
#print("add_timestamp with substanzas: " + str(substanzas)) #print("add_timestamp with substanzas: " + str(substanzas))
self.iterables.append(ts) self.iterables.append(ts)
#print(str(id(self)) + " added_timestamp: " + str(id(ts))) #print(str(id(self)) + " added_timestamp: " + str(id(ts)))
@ -498,13 +498,13 @@ class Field(ElementBase):
namespace = 'urn:xmpp:iot:sensordata' namespace = 'urn:xmpp:iot:sensordata'
name = 'field' name = 'field'
plugin_attrib = name plugin_attrib = name
interfaces = set(['name','module','stringIds']); interfaces = set(['name','module','stringIds'])
interfaces.update(FieldTypes.field_types); interfaces.update(FieldTypes.field_types)
interfaces.update(FieldStatus.field_status); interfaces.update(FieldStatus.field_status)
_flags = set(); _flags = set()
_flags.update(FieldTypes.field_types); _flags.update(FieldTypes.field_types)
_flags.update(FieldStatus.field_status); _flags.update(FieldStatus.field_status)
def set_stringIds(self, value): def set_stringIds(self, value):
"""Verifies stringIds according to regexp from specification XMPP-0323. """Verifies stringIds according to regexp from specification XMPP-0323.
@ -514,7 +514,7 @@ class Field(ElementBase):
pattern = re.compile("^\d+([|]\w+([.]\w+)*([|][^,]*)?)?(,\d+([|]\w+([.]\w+)*([|][^,]*)?)?)*$") pattern = re.compile("^\d+([|]\w+([.]\w+)*([|][^,]*)?)?(,\d+([|]\w+([.]\w+)*([|][^,]*)?)?)*$")
if pattern.match(value) is not None: if pattern.match(value) is not None:
self.xml.stringIds = value; self.xml.stringIds = value
else: else:
# Bad content, add nothing # Bad content, add nothing
pass pass
@ -526,11 +526,11 @@ class Field(ElementBase):
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:
if not self[f] == "": if not self[f] == "":
flags[f] = self[f]; flags[f] = self[f]
return flags; return flags
def _set_flags(self, flags): def _set_flags(self, flags):
""" """
@ -541,12 +541,12 @@ class Field(ElementBase):
""" """
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:
self[f] = flags[f]; self[f] = flags[f]
else: else:
self[f] = None; self[f] = None
def _get_typename(self): def _get_typename(self):
return "invalid type, use subclasses!"; return "invalid type, use subclasses!"
class Timestamp(ElementBase): class Timestamp(ElementBase):
@ -557,7 +557,7 @@ class Timestamp(ElementBase):
interfaces = set(['value','datas']) interfaces = set(['value','datas'])
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._datas = set() self._datas = set()
def setup(self, xml=None): def setup(self, xml=None):
@ -587,29 +587,29 @@ class Timestamp(ElementBase):
dataType -- [optional] The dataType. Only applicable for type enum dataType -- [optional] The dataType. Only applicable for type enum
""" """
if name not in self._datas: if name not in self._datas:
dataObj = None; dataObj = None
if typename == "numeric": if typename == "numeric":
dataObj = DataNumeric(parent=self); dataObj = DataNumeric(parent=self)
dataObj['unit'] = unit; dataObj['unit'] = unit
elif typename == "string": elif typename == "string":
dataObj = DataString(parent=self); dataObj = DataString(parent=self)
elif typename == "boolean": elif typename == "boolean":
dataObj = DataBoolean(parent=self); dataObj = DataBoolean(parent=self)
elif typename == "dateTime": elif typename == "dateTime":
dataObj = DataDateTime(parent=self); dataObj = DataDateTime(parent=self)
elif typename == "timeSpan": elif typename == "timeSpan":
dataObj = DataTimeSpan(parent=self); dataObj = DataTimeSpan(parent=self)
elif typename == "enum": elif typename == "enum":
dataObj = DataEnum(parent=self); dataObj = DataEnum(parent=self)
dataObj['dataType'] = dataType; dataObj['dataType'] = dataType
dataObj['name'] = name; dataObj['name'] = name
dataObj['value'] = value; dataObj['value'] = value
dataObj['module'] = module; dataObj['module'] = module
dataObj['stringIds'] = stringIds; dataObj['stringIds'] = stringIds
if flags is not None: if flags is not None:
dataObj._set_flags(flags); dataObj._set_flags(flags)
self._datas.add(name) self._datas.add(name)
self.iterables.append(dataObj) self.iterables.append(dataObj)
@ -668,8 +668,8 @@ class DataNumeric(Field):
namespace = 'urn:xmpp:iot:sensordata' namespace = 'urn:xmpp:iot:sensordata'
name = 'numeric' name = 'numeric'
plugin_attrib = name plugin_attrib = name
interfaces = set(['value', 'unit']); interfaces = set(['value', 'unit'])
interfaces.update(Field.interfaces); interfaces.update(Field.interfaces)
def _get_typename(self): def _get_typename(self):
return "numeric" return "numeric"
@ -681,8 +681,8 @@ class DataString(Field):
namespace = 'urn:xmpp:iot:sensordata' namespace = 'urn:xmpp:iot:sensordata'
name = 'string' name = 'string'
plugin_attrib = name plugin_attrib = name
interfaces = set(['value']); interfaces = set(['value'])
interfaces.update(Field.interfaces); interfaces.update(Field.interfaces)
def _get_typename(self): def _get_typename(self):
return "string" return "string"
@ -695,8 +695,8 @@ class DataBoolean(Field):
namespace = 'urn:xmpp:iot:sensordata' namespace = 'urn:xmpp:iot:sensordata'
name = 'boolean' name = 'boolean'
plugin_attrib = name plugin_attrib = name
interfaces = set(['value']); interfaces = set(['value'])
interfaces.update(Field.interfaces); interfaces.update(Field.interfaces)
def _get_typename(self): def _get_typename(self):
return "boolean" return "boolean"
@ -709,8 +709,8 @@ class DataDateTime(Field):
namespace = 'urn:xmpp:iot:sensordata' namespace = 'urn:xmpp:iot:sensordata'
name = 'dateTime' name = 'dateTime'
plugin_attrib = name plugin_attrib = name
interfaces = set(['value']); interfaces = set(['value'])
interfaces.update(Field.interfaces); interfaces.update(Field.interfaces)
def _get_typename(self): def _get_typename(self):
return "dateTime" return "dateTime"
@ -723,8 +723,8 @@ class DataTimeSpan(Field):
namespace = 'urn:xmpp:iot:sensordata' namespace = 'urn:xmpp:iot:sensordata'
name = 'timeSpan' name = 'timeSpan'
plugin_attrib = name plugin_attrib = name
interfaces = set(['value']); interfaces = set(['value'])
interfaces.update(Field.interfaces); interfaces.update(Field.interfaces)
def _get_typename(self): def _get_typename(self):
return "timeSpan" return "timeSpan"
@ -737,8 +737,8 @@ class DataEnum(Field):
namespace = 'urn:xmpp:iot:sensordata' namespace = 'urn:xmpp:iot:sensordata'
name = 'enum' name = 'enum'
plugin_attrib = name plugin_attrib = name
interfaces = set(['value', 'dataType']); interfaces = set(['value', 'dataType'])
interfaces.update(Field.interfaces); interfaces.update(Field.interfaces)
def _get_typename(self): def _get_typename(self):
return "enum" return "enum"

View File

@ -23,7 +23,12 @@ class _TimerReset(Thread):
t.cancel() # stop the timer's action if it's still waiting t.cancel() # stop the timer's action if it's still waiting
""" """
def __init__(self, interval, function, args=[], kwargs={}): def __init__(self, interval, function, args=None, kwargs=None):
if not kwargs:
kwargs = {}
if not args:
args = []
Thread.__init__(self) Thread.__init__(self)
self.interval = interval self.interval = interval
self.function = function self.function = function

View File

@ -12,7 +12,6 @@ import logging
import time import time
from threading import Thread, Timer, Lock from threading import Thread, Timer, Lock
from sleekxmpp.xmlstream import JID
from sleekxmpp.xmlstream.handler import Callback from sleekxmpp.xmlstream.handler import Callback
from sleekxmpp.xmlstream.matcher import StanzaPath from sleekxmpp.xmlstream.matcher import StanzaPath
from sleekxmpp.plugins.base import BasePlugin from sleekxmpp.plugins.base import BasePlugin
@ -135,11 +134,11 @@ class XEP_0325(BasePlugin):
self._handle_set_response)) self._handle_set_response))
# Server side dicts # Server side dicts
self.nodes = {}; self.nodes = {}
self.sessions = {}; self.sessions = {}
self.last_seqnr = 0; self.last_seqnr = 0
self.seqnr_lock = Lock(); self.seqnr_lock = Lock()
## For testning only ## For testning only
self.test_authenticated_from = "" self.test_authenticated_from = ""
@ -156,13 +155,13 @@ class XEP_0325(BasePlugin):
def plugin_end(self): def plugin_end(self):
""" Stop the XEP-0325 plugin """ """ Stop the XEP-0325 plugin """
self.sessions.clear(); self.sessions.clear()
self.xmpp.remove_handler('Control Event:DirectSet') self.xmpp.remove_handler('Control Event:DirectSet')
self.xmpp.remove_handler('Control Event:SetReq') self.xmpp.remove_handler('Control Event:SetReq')
self.xmpp.remove_handler('Control Event:SetResponse') self.xmpp.remove_handler('Control Event:SetResponse')
self.xmpp.remove_handler('Control Event:SetResponseError') self.xmpp.remove_handler('Control Event:SetResponseError')
self.xmpp['xep_0030'].del_feature(feature=Control.namespace) self.xmpp['xep_0030'].del_feature(feature=Control.namespace)
self.xmpp['xep_0030'].set_items(node=Control.namespace, items=tuple()); self.xmpp['xep_0030'].set_items(node=Control.namespace, items=tuple())
# ================================================================= # =================================================================
@ -190,18 +189,18 @@ class XEP_0325(BasePlugin):
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=''):
""" Internal testing function """ """ Internal testing function """
self.test_authenticated_from = auth; self.test_authenticated_from = auth
def _get_new_seqnr(self): def _get_new_seqnr(self):
""" Returns a unique sequence number (unique across threads) """ """ Returns a unique sequence number (unique across threads) """
self.seqnr_lock.acquire(); self.seqnr_lock.acquire()
self.last_seqnr = self.last_seqnr + 1; self.last_seqnr += 1
self.seqnr_lock.release(); self.seqnr_lock.release()
return str(self.last_seqnr); return str(self.last_seqnr)
def _handle_set_req(self, iq): def _handle_set_req(self, iq):
""" """
@ -220,69 +219,68 @@ class XEP_0325(BasePlugin):
is sent. is sent.
""" """
error_msg = ''; error_msg = ''
req_ok = True; req_ok = True
missing_node = None; missing_node = None
missing_field = None; missing_field = None
# Authentication # Authentication
if len(self.test_authenticated_from) > 0 and not iq['from'] == self.test_authenticated_from: if len(self.test_authenticated_from) > 0 and not iq['from'] == self.test_authenticated_from:
# Invalid authentication # Invalid authentication
req_ok = False; req_ok = False
error_msg = "Access denied"; error_msg = "Access denied"
# Nodes # Nodes
process_nodes = [];
if len(iq['set']['nodes']) > 0: if len(iq['set']['nodes']) > 0:
for n in iq['set']['nodes']: for n in iq['set']['nodes']:
if not n['nodeId'] in self.nodes: if not n['nodeId'] in self.nodes:
req_ok = False; req_ok = False
missing_node = n['nodeId']; missing_node = n['nodeId']
error_msg = "Invalid nodeId " + n['nodeId']; error_msg = "Invalid nodeId " + n['nodeId']
process_nodes = [n['nodeId'] for n in iq['set']['nodes']]; process_nodes = [n['nodeId'] for n in iq['set']['nodes']]
else: else:
process_nodes = self.nodes.keys(); process_nodes = self.nodes.keys()
# Fields - for control we need to find all in all devices, otherwise we reject # Fields - for control we need to find all in all devices, otherwise we reject
process_fields = []; process_fields = []
if len(iq['set']['datas']) > 0: if len(iq['set']['datas']) > 0:
for f in iq['set']['datas']: for f in iq['set']['datas']:
for node in self.nodes: for node in self.nodes:
if not self.nodes[node]["device"].has_control_field(f['name'], f._get_typename()): if not self.nodes[node]["device"].has_control_field(f['name'], f._get_typename()):
req_ok = False; req_ok = False
missing_field = f['name']; missing_field = f['name']
error_msg = "Invalid field " + f['name']; error_msg = "Invalid field " + f['name']
break; break
process_fields = [(f['name'], f._get_typename(), f['value']) for f in iq['set']['datas']]; process_fields = [(f['name'], f._get_typename(), f['value']) for f in iq['set']['datas']]
if req_ok: if req_ok:
session = self._new_session(); session = self._new_session()
self.sessions[session] = {"from": iq['from'], "to": iq['to'], "seqnr": iq['id']}; self.sessions[session] = {"from": iq['from'], "to": iq['to'], "seqnr": iq['id']}
self.sessions[session]["commTimers"] = {}; self.sessions[session]["commTimers"] = {}
self.sessions[session]["nodeDone"] = {}; self.sessions[session]["nodeDone"] = {}
# Flag that a reply is exected when we are done # Flag that a reply is exected when we are done
self.sessions[session]["reply"] = True; self.sessions[session]["reply"] = True
self.sessions[session]["node_list"] = process_nodes; self.sessions[session]["node_list"] = process_nodes
if self.threaded: if self.threaded:
#print("starting thread") #print("starting thread")
tr_req = Thread(target=self._threaded_node_request, args=(session, process_fields)) tr_req = Thread(target=self._threaded_node_request, args=(session, process_fields))
tr_req.start() tr_req.start()
#print("started thread") #print("started thread")
else: else:
self._threaded_node_request(session, process_fields); self._threaded_node_request(session, process_fields)
else: else:
iq.reply(); iq.reply()
iq['type'] = 'error'; iq['type'] = 'error'
iq['setResponse']['responseCode'] = "NotFound"; iq['setResponse']['responseCode'] = "NotFound"
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):
""" """
@ -299,46 +297,45 @@ class XEP_0325(BasePlugin):
to the devices (in a separate thread). to the devices (in a separate thread).
If the verification fails, do nothing. If the verification fails, do nothing.
""" """
req_ok = True; req_ok = True
# Nodes # Nodes
process_nodes = [];
if len(msg['set']['nodes']) > 0: if len(msg['set']['nodes']) > 0:
for n in msg['set']['nodes']: for n in msg['set']['nodes']:
if not n['nodeId'] in self.nodes: if not n['nodeId'] in self.nodes:
req_ok = False; req_ok = False
error_msg = "Invalid nodeId " + n['nodeId']; error_msg = "Invalid nodeId " + n['nodeId']
process_nodes = [n['nodeId'] for n in msg['set']['nodes']]; process_nodes = [n['nodeId'] for n in msg['set']['nodes']]
else: else:
process_nodes = self.nodes.keys(); process_nodes = self.nodes.keys()
# Fields - for control we need to find all in all devices, otherwise we reject # Fields - for control we need to find all in all devices, otherwise we reject
process_fields = []; process_fields = []
if len(msg['set']['datas']) > 0: if len(msg['set']['datas']) > 0:
for f in msg['set']['datas']: for f in msg['set']['datas']:
for node in self.nodes: for node in self.nodes:
if not self.nodes[node]["device"].has_control_field(f['name'], f._get_typename()): if not self.nodes[node]["device"].has_control_field(f['name'], f._get_typename()):
req_ok = False; req_ok = False
missing_field = f['name']; missing_field = f['name']
error_msg = "Invalid field " + f['name']; error_msg = "Invalid field " + f['name']
break; break
process_fields = [(f['name'], f._get_typename(), f['value']) for f in msg['set']['datas']]; process_fields = [(f['name'], f._get_typename(), f['value']) for f in msg['set']['datas']]
if req_ok: if req_ok:
session = self._new_session(); session = self._new_session()
self.sessions[session] = {"from": msg['from'], "to": msg['to']}; self.sessions[session] = {"from": msg['from'], "to": msg['to']}
self.sessions[session]["commTimers"] = {}; self.sessions[session]["commTimers"] = {}
self.sessions[session]["nodeDone"] = {}; self.sessions[session]["nodeDone"] = {}
self.sessions[session]["reply"] = False; self.sessions[session]["reply"] = False
self.sessions[session]["node_list"] = process_nodes; self.sessions[session]["node_list"] = process_nodes
if self.threaded: if self.threaded:
#print("starting thread") #print("starting thread")
tr_req = Thread(target=self._threaded_node_request, args=(session, process_fields)) tr_req = Thread(target=self._threaded_node_request, args=(session, process_fields))
tr_req.start() tr_req.start()
#print("started thread") #print("started thread")
else: else:
self._threaded_node_request(session, process_fields); self._threaded_node_request(session, process_fields)
def _threaded_node_request(self, session, process_fields): def _threaded_node_request(self, session, process_fields):
@ -351,13 +348,13 @@ class XEP_0325(BasePlugin):
(name, datatype, value) (name, datatype, 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 = Timer(self.nodes[node]['commTimeout'], self._event_comm_timeout, args=(session, node)); timer = Timer(self.nodes[node]['commTimeout'], self._event_comm_timeout, args=(session, node))
self.sessions[session]["commTimers"][node] = timer; self.sessions[session]["commTimers"][node] = timer
timer.start(); timer.start()
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):
""" """
@ -373,24 +370,24 @@ class XEP_0325(BasePlugin):
if self.sessions[session]["reply"]: if self.sessions[session]["reply"]:
# Reply is exected when we are done # Reply is exected when we are done
iq = self.xmpp.Iq(); iq = self.xmpp.Iq()
iq['from'] = self.sessions[session]['to']; iq['from'] = self.sessions[session]['to']
iq['to'] = self.sessions[session]['from']; iq['to'] = self.sessions[session]['from']
iq['type'] = "error"; iq['type'] = "error"
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)
## TODO - should we send one timeout per node?? ## TODO - should we send one timeout per node??
# 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]
def _all_nodes_done(self, session): def _all_nodes_done(self, session):
""" """
@ -401,8 +398,8 @@ class XEP_0325(BasePlugin):
""" """
for n in self.sessions[session]["nodeDone"]: for n in self.sessions[session]["nodeDone"]:
if not self.sessions[session]["nodeDone"][n]: if not self.sessions[session]["nodeDone"][n]:
return False; return False
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):
""" """
@ -428,45 +425,45 @@ class XEP_0325(BasePlugin):
return return
if result == "error": if result == "error":
self.sessions[session]["commTimers"][nodeId].cancel(); self.sessions[session]["commTimers"][nodeId].cancel()
if self.sessions[session]["reply"]: if self.sessions[session]["reply"]:
# Reply is exected when we are done # Reply is exected when we are done
iq = self.xmpp.Iq(); iq = self.xmpp.Iq()
iq['from'] = self.sessions[session]['to']; iq['from'] = self.sessions[session]['to']
iq['to'] = self.sessions[session]['from']; iq['to'] = self.sessions[session]['from']
iq['type'] = "error"; iq['type'] = "error"
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)
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]
else: else:
self.sessions[session]["commTimers"][nodeId].cancel(); self.sessions[session]["commTimers"][nodeId].cancel()
self.sessions[session]["nodeDone"][nodeId] = True; self.sessions[session]["nodeDone"][nodeId] = True
if (self._all_nodes_done(session)): if (self._all_nodes_done(session)):
if self.sessions[session]["reply"]: if self.sessions[session]["reply"]:
# Reply is exected when we are done # Reply is exected when we are done
iq = self.xmpp.Iq(); iq = self.xmpp.Iq()
iq['from'] = self.sessions[session]['to']; iq['from'] = self.sessions[session]['to']
iq['to'] = self.sessions[session]['from']; iq['to'] = self.sessions[session]['from']
iq['type'] = "result"; iq['type'] = "result"
iq['id'] = self.sessions[session]['seqnr']; iq['id'] = self.sessions[session]['seqnr']
iq['setResponse']['responseCode'] = "OK"; iq['setResponse']['responseCode'] = "OK"
iq.send(block=False); iq.send(block=False)
# The session is complete, delete it # The session is complete, delete it
del self.sessions[session]; del self.sessions[session]
# ================================================================= # =================================================================
@ -512,21 +509,21 @@ class XEP_0325(BasePlugin):
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.
""" """
iq = self.xmpp.Iq(); iq = self.xmpp.Iq()
iq['from'] = from_jid; iq['from'] = from_jid
iq['to'] = to_jid; iq['to'] = to_jid
seqnr = self._get_new_seqnr(); seqnr = self._get_new_seqnr()
iq['id'] = seqnr; iq['id'] = seqnr
iq['type'] = "set"; iq['type'] = "set"
if nodeIds is not None: if nodeIds is not None:
for nodeId in nodeIds: for nodeId in nodeIds:
iq['set'].add_node(nodeId); iq['set'].add_node(nodeId)
if fields is not None: if fields is not None:
for name, typename, value in fields: for name, typename, value in fields:
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):
""" """
@ -541,34 +538,32 @@ class XEP_0325(BasePlugin):
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.
""" """
msg = self.xmpp.Message(); msg = self.xmpp.Message()
msg['from'] = from_jid; msg['from'] = from_jid
msg['to'] = to_jid; msg['to'] = to_jid
msg['type'] = "set"; msg['type'] = "set"
if nodeIds is not None: if nodeIds is not None:
for nodeId in nodeIds: for nodeId in nodeIds:
msg['set'].add_node(nodeId); msg['set'].add_node(nodeId)
if fields is not None: if fields is not None:
for name, typename, value in fields: for name, typename, value in fields:
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) """
#print("ooh") #print("ooh")
seqnr = iq['id']; seqnr = iq['id']
from_jid = str(iq['from']); from_jid = str(iq['from'])
result = iq['setResponse']['responseCode']; result = iq['setResponse']['responseCode']
nodeIds = [n['name'] for n in iq['setResponse']['nodes']]; nodeIds = [n['name'] for n in iq['setResponse']['nodes']]
fields = [f['name'] for f in iq['setResponse']['datas']]; fields = [f['name'] for f in iq['setResponse']['datas']]
error_msg = None; error_msg = None
if not iq['setResponse'].find('error') is None and not iq['setResponse']['error']['text'] == "": if not iq['setResponse'].find('error') is None and not iq['setResponse']['error']['text'] == "":
error_msg = iq['setResponse']['error']['text']; error_msg = iq['setResponse']['error']['text']
callback = self.sessions[seqnr]["callback"];
callback(from_jid=from_jid, result=result, nodeIds=nodeIds, fields=fields, error_msg=error_msg);
callback = self.sessions[seqnr]["callback"]
callback(from_jid=from_jid, result=result, nodeIds=nodeIds, fields=fields, error_msg=error_msg)

View File

@ -21,8 +21,8 @@ class Device(object):
""" """
def __init__(self, nodeId): def __init__(self, nodeId):
self.nodeId = nodeId; self.nodeId = nodeId
self.control_fields = {}; self.control_fields = {}
def has_control_field(self, field, typename): def has_control_field(self, field, typename):
""" """
@ -34,8 +34,8 @@ class Device(object):
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:
return True; return True
return False; return False
def set_control_fields(self, fields, session, callback): def set_control_fields(self, fields, session, callback):
""" """
@ -69,12 +69,12 @@ class Device(object):
for name, typename, value in fields: for name, typename, value in fields:
if not self.has_control_field(name, typename): if not self.has_control_field(name, typename):
self._send_control_reject(session, name, "NotFound", callback) self._send_control_reject(session, name, "NotFound", callback)
return False; return False
for name, typename, value in fields: for name, typename, value in fields:
self._set_field_value(name, value) self._set_field_value(name, value)
callback(session, result="ok", nodeId=self.nodeId); callback(session, result="ok", nodeId=self.nodeId)
return True return True
def _send_control_reject(self, session, field, message, callback): def _send_control_reject(self, session, field, message, callback):
@ -87,7 +87,7 @@ class Device(object):
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)
def _add_control_field(self, name, typename, value): def _add_control_field(self, name, typename, value):
""" """
@ -100,7 +100,7 @@ class Device(object):
double, duration, int, long, time) double, duration, int, long, time)
value -- Field value value -- Field value
""" """
self.control_fields[name] = {"type": typename, "value": value}; self.control_fields[name] = {"type": typename, "value": value}
def _set_field_value(self, name, value): def _set_field_value(self, name, value):
""" """
@ -111,7 +111,7 @@ class Device(object):
value -- New value for the field value -- New value for the field
""" """
if name in self.control_fields: if name in self.control_fields:
self.control_fields[name]["value"] = value; self.control_fields[name]["value"] = value
def _get_field_value(self, name): def _get_field_value(self, name):
""" """
@ -121,5 +121,5 @@ class Device(object):
name -- Name of the field name -- Name of the field
""" """
if name in self.control_fields: if name in self.control_fields:
return self.control_fields[name]["value"]; return self.control_fields[name]["value"]
return None; return None

View File

@ -26,7 +26,7 @@ class ControlSet(ElementBase):
interfaces = set(['nodes','datas']) interfaces = set(['nodes','datas'])
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()
self._datas = set() self._datas = set()
@ -127,30 +127,30 @@ class ControlSet(ElementBase):
value -- The value of the data element value -- The value of the data element
""" """
if name not in self._datas: if name not in self._datas:
dataObj = None; dataObj = None
if typename == "boolean": if typename == "boolean":
dataObj = BooleanParameter(parent=self); dataObj = BooleanParameter(parent=self)
elif typename == "color": elif typename == "color":
dataObj = ColorParameter(parent=self); dataObj = ColorParameter(parent=self)
elif typename == "string": elif typename == "string":
dataObj = StringParameter(parent=self); dataObj = StringParameter(parent=self)
elif typename == "date": elif typename == "date":
dataObj = DateParameter(parent=self); dataObj = DateParameter(parent=self)
elif typename == "dateTime": elif typename == "dateTime":
dataObj = DateTimeParameter(parent=self); dataObj = DateTimeParameter(parent=self)
elif typename == "double": elif typename == "double":
dataObj = DoubleParameter(parent=self); dataObj = DoubleParameter(parent=self)
elif typename == "duration": elif typename == "duration":
dataObj = DurationParameter(parent=self); dataObj = DurationParameter(parent=self)
elif typename == "int": elif typename == "int":
dataObj = IntParameter(parent=self); dataObj = IntParameter(parent=self)
elif typename == "long": elif typename == "long":
dataObj = LongParameter(parent=self); dataObj = LongParameter(parent=self)
elif typename == "time": elif typename == "time":
dataObj = TimeParameter(parent=self); dataObj = TimeParameter(parent=self)
dataObj['name'] = name; dataObj['name'] = name
dataObj['value'] = value; dataObj['value'] = value
self._datas.add(name) self._datas.add(name)
self.iterables.append(dataObj) self.iterables.append(dataObj)
@ -217,7 +217,7 @@ class ControlSetResponse(ElementBase):
interfaces = set(['responseCode']) interfaces = set(['responseCode'])
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()
self._datas = set() self._datas = set()
@ -316,7 +316,7 @@ class ControlSetResponse(ElementBase):
if name not in self._datas: if name not in self._datas:
self._datas.add(name) self._datas.add(name)
data = ResponseParameter(parent=self) data = ResponseParameter(parent=self)
data['name'] = name; data['name'] = name
self.iterables.append(data) self.iterables.append(data)
return data return data
return None return None
@ -383,7 +383,7 @@ class Error(ElementBase):
value -- string value -- string
""" """
self.xml.text = value; self.xml.text = value
return self return self
def del_text(self): def del_text(self):
@ -398,7 +398,7 @@ class ResponseParameter(ElementBase):
namespace = 'urn:xmpp:iot:control' namespace = 'urn:xmpp:iot:control'
name = 'parameter' name = 'parameter'
plugin_attrib = name plugin_attrib = name
interfaces = set(['name']); interfaces = set(['name'])
class BaseParameter(ElementBase): class BaseParameter(ElementBase):
@ -419,10 +419,11 @@ class BaseParameter(ElementBase):
namespace = 'urn:xmpp:iot:control' namespace = 'urn:xmpp:iot:control'
name = 'baseParameter' name = 'baseParameter'
plugin_attrib = name plugin_attrib = name
interfaces = set(['name','value']); interfaces = set(['name','value'])
def _get_typename(self): def _get_typename(self):
return self.name; return self.name
class BooleanParameter(BaseParameter): class BooleanParameter(BaseParameter):
""" """

View File

@ -237,8 +237,7 @@ class RosterNode(object):
if not self.xmpp.is_component: if not self.xmpp.is_component:
return self.update(jid, subscription='remove') return self.update(jid, subscription='remove')
def update(self, jid, name=None, subscription=None, groups=[], def update(self, jid, name=None, subscription=None, groups=None, block=True, timeout=None, callback=None):
block=True, timeout=None, callback=None):
""" """
Update a JID's subscription information. Update a JID's subscription information.
@ -258,6 +257,9 @@ class RosterNode(object):
Will be executed when the roster is received. Will be executed when the roster is received.
Implies block=False. Implies block=False.
""" """
if not groups:
groups = []
self[jid]['name'] = name self[jid]['name'] = name
self[jid]['groups'] = groups self[jid]['groups'] = groups
self[jid].save() self[jid].save()

View File

@ -6,8 +6,7 @@
See the file LICENSE for copying permission. See the file LICENSE for copying permission.
""" """
from sleekxmpp.xmlstream import ElementBase from sleekxmpp.xmlstream import register_stanza_plugin, ElementBase
class AtomEntry(ElementBase): class AtomEntry(ElementBase):
@ -22,5 +21,23 @@ class AtomEntry(ElementBase):
namespace = 'http://www.w3.org/2005/Atom' namespace = 'http://www.w3.org/2005/Atom'
name = 'entry' name = 'entry'
plugin_attrib = 'entry' plugin_attrib = 'entry'
interfaces = set(('title', 'summary')) interfaces = set(('title', 'summary', 'id', 'published', 'updated'))
sub_interfaces = set(('title', 'summary')) sub_interfaces = set(('title', 'summary', 'id', 'published',
'updated'))
class AtomAuthor(ElementBase):
"""
An Atom author.
Stanza Interface:
name -- The printable author name
uri -- The bare jid of the author
"""
name = 'author'
plugin_attrib = 'author'
interfaces = set(('name', 'uri'))
sub_interfaces = set(('name', 'uri'))
register_stanza_plugin(AtomEntry, AtomAuthor)

View File

@ -288,11 +288,8 @@ class SleekTest(unittest.TestCase):
if self.xmpp: if self.xmpp:
self.xmpp.socket.disconnect_error() self.xmpp.socket.disconnect_error()
def stream_start(self, mode='client', skip=True, header=None, def stream_start(self, mode='client', skip=True, header=None, socket='mock', jid='tester@localhost',
socket='mock', jid='tester@localhost', password='test', server='localhost', port=5222, sasl_mech=None, plugins=None, plugin_config=None):
password='test', server='localhost',
port=5222, sasl_mech=None,
plugins=None, plugin_config={}):
""" """
Initialize an XMPP client or component using a dummy XML stream. Initialize an XMPP client or component using a dummy XML stream.
@ -315,6 +312,9 @@ class SleekTest(unittest.TestCase):
plugins -- List of plugins to register. By default, all plugins plugins -- List of plugins to register. By default, all plugins
are loaded. are loaded.
""" """
if not plugin_config:
plugin_config = {}
if mode == 'client': if mode == 'client':
self.xmpp = ClientXMPP(jid, password, self.xmpp = ClientXMPP(jid, password,
sasl_mech=sasl_mech, sasl_mech=sasl_mech,
@ -425,8 +425,7 @@ class SleekTest(unittest.TestCase):
parts.append('xmlns="%s"' % default_ns) parts.append('xmlns="%s"' % default_ns)
return header % ' '.join(parts) return header % ' '.join(parts)
def recv(self, data, defaults=[], method='exact', def recv(self, data, defaults=None, method='exact', use_values=True, timeout=1):
use_values=True, timeout=1):
""" """
Pass data to the dummy XMPP client as if it came from an XMPP server. Pass data to the dummy XMPP client as if it came from an XMPP server.
@ -447,6 +446,9 @@ class SleekTest(unittest.TestCase):
timeout -- Time to wait in seconds for data to be received by timeout -- Time to wait in seconds for data to be received by
a live connection. a live connection.
""" """
if not defaults:
defaults = []
if self.xmpp.socket.is_live: if self.xmpp.socket.is_live:
# we are working with a live connection, so we should # we are working with a live connection, so we should
# verify what has been received instead of simulating # verify what has been received instead of simulating

View File

@ -28,6 +28,9 @@ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE.
This module provides a standard socket-like interface for Python This module provides a standard socket-like interface for Python
for tunneling connections through SOCKS proxies. for tunneling connections through SOCKS proxies.
"""
"""
Minor modifications made by Christopher Gilbert (http://motomastyle.com/) Minor modifications made by Christopher Gilbert (http://motomastyle.com/)
for use in PyLoris (http://pyloris.sourceforge.net/) for use in PyLoris (http://pyloris.sourceforge.net/)
@ -35,10 +38,13 @@ for use in PyLoris (http://pyloris.sourceforge.net/)
Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/) Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/)
mainly to merge bug fixes found in Sourceforge mainly to merge bug fixes found in Sourceforge
Minor modifications made by Eugene Dementiev (http://www.dementiev.eu/)
""" """
import socket import socket
import struct import struct
import sys
PROXY_TYPE_SOCKS4 = 1 PROXY_TYPE_SOCKS4 = 1
PROXY_TYPE_SOCKS5 = 2 PROXY_TYPE_SOCKS5 = 2
@ -208,12 +214,12 @@ class socksocket(socket.socket):
if self.__proxy[3]: if self.__proxy[3]:
# Resolve remotely # Resolve remotely
ipaddr = None ipaddr = None
req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr req = req + chr(0x03).encode() + chr(len(destaddr)).encode() + destaddr.encode()
else: else:
# Resolve locally # Resolve locally
ipaddr = socket.inet_aton(socket.gethostbyname(destaddr)) ipaddr = socket.inet_aton(socket.gethostbyname(destaddr))
req = req + chr(0x01).encode() + ipaddr req = req + chr(0x01).encode() + ipaddr
req = req + struct.pack(">H", destport) req += struct.pack(">H", destport)
self.sendall(req) self.sendall(req)
# Get the response # Get the response
resp = self.__recvall(4) resp = self.__recvall(4)
@ -282,7 +288,7 @@ class socksocket(socket.socket):
# The username parameter is considered userid for SOCKS4 # The username parameter is considered userid for SOCKS4
if self.__proxy[4] != None: if self.__proxy[4] != None:
req = req + self.__proxy[4] req = req + self.__proxy[4]
req = req + chr(0x00).encode() req += chr(0x00).encode()
# DNS name if remote resolving is required # DNS name if remote resolving is required
# NOTE: This is actually an extension to the SOCKS4 protocol # NOTE: This is actually an extension to the SOCKS4 protocol
# called SOCKS4A and may not be supported in all cases. # called SOCKS4A and may not be supported in all cases.
@ -323,7 +329,10 @@ class socksocket(socket.socket):
# We read the response until we get the string "\r\n\r\n" # We read the response until we get the string "\r\n\r\n"
resp = self.recv(1) resp = self.recv(1)
while resp.find("\r\n\r\n".encode()) == -1: while resp.find("\r\n\r\n".encode()) == -1:
resp = resp + self.recv(1) recv = self.recv(1)
if not recv:
raise GeneralProxyError((1, _generalerrors[1]))
resp = resp + recv
# We just need the first line to check if the connection # We just need the first line to check if the connection
# was successful # was successful
statusline = resp.splitlines()[0].split(" ".encode(), 2) statusline = resp.splitlines()[0].split(" ".encode(), 2)

View File

@ -34,7 +34,7 @@ class StateMachine(object):
self.lock.release() self.lock.release()
def transition(self, from_state, to_state, wait=0.0, func=None, args=[], kwargs={}): def transition(self, from_state, to_state, wait=0.0, func=None, args=None, kwargs=None):
''' '''
Transition from the given `from_state` to the given `to_state`. Transition from the given `from_state` to the given `to_state`.
This method will return `True` if the state machine is now in `to_state`. It This method will return `True` if the state machine is now in `to_state`. It
@ -65,15 +65,23 @@ class StateMachine(object):
values for `args` and `kwargs` are provided, they are expanded and passed like so: values for `args` and `kwargs` are provided, they are expanded and passed like so:
`func( *args, **kwargs )`. `func( *args, **kwargs )`.
''' '''
if not args:
args = []
if not kwargs:
kwargs = {}
return self.transition_any((from_state,), to_state, wait=wait, return self.transition_any((from_state,), to_state, wait=wait,
func=func, args=args, kwargs=kwargs) func=func, args=args, kwargs=kwargs)
def transition_any(self, from_states, to_state, wait=0.0, func=None, args=[], kwargs={}): def transition_any(self, from_states, to_state, wait=0.0, func=None, args=None, kwargs=None):
''' '''
Transition from any of the given `from_states` to the given `to_state`. Transition from any of the given `from_states` to the given `to_state`.
''' '''
if not args:
args = []
if not kwargs:
kwargs = {}
if not isinstance(from_states, (tuple, list, set)): if not isinstance(from_states, (tuple, list, set)):
raise ValueError("from_states should be a list, tuple, or set") raise ValueError("from_states should be a list, tuple, or set")

View File

@ -32,12 +32,17 @@ def _gevent_threads_enabled():
if _gevent_threads_enabled(): if _gevent_threads_enabled():
import gevent.queue as queue import gevent.queue as queue
Queue = queue.JoinableQueue _queue = queue.JoinableQueue
else: else:
try: try:
import queue import queue
except ImportError: except ImportError:
import Queue as queue import Queue as queue
Queue = queue.Queue _queue = queue.Queue
class Queue(_queue):
def put(self, item, block=True, timeout=None):
if _queue.full(self):
_queue.get(self)
return _queue.put(self, item, block, timeout)
QueueEmpty = queue.Empty QueueEmpty = queue.Empty

View File

@ -9,5 +9,5 @@
# We don't want to have to import the entire library # We don't want to have to import the entire library
# just to get the version info for setup.py # just to get the version info for setup.py
__version__ = '1.3.1' __version__ = '1.4.0'
__version_info__ = (1, 3, 1, '', 0) __version_info__ = (1, 4, 0, '', 0)

View File

@ -291,7 +291,7 @@ class XMLStream(object):
self.event_queue = Queue() self.event_queue = Queue()
#: A queue of string data to be sent over the stream. #: A queue of string data to be sent over the stream.
self.send_queue = Queue() self.send_queue = Queue(maxsize=256)
self.send_queue_lock = threading.Lock() self.send_queue_lock = threading.Lock()
self.send_lock = threading.RLock() self.send_lock = threading.RLock()
@ -460,9 +460,11 @@ class XMLStream(object):
def _connect(self, reattempt=True): def _connect(self, reattempt=True):
self.scheduler.remove('Session timeout check') self.scheduler.remove('Session timeout check')
if self.reconnect_delay is None or not reattempt: if self.reconnect_delay is None:
delay = 1.0 delay = 1.0
else: self.reconnect_delay = delay
if reattempt:
delay = min(self.reconnect_delay * 2, self.reconnect_max_delay) delay = min(self.reconnect_delay * 2, self.reconnect_max_delay)
delay = random.normalvariate(delay, delay * 0.1) delay = random.normalvariate(delay, delay * 0.1)
log.debug('Waiting %s seconds before connecting.', delay) log.debug('Waiting %s seconds before connecting.', delay)
@ -523,7 +525,8 @@ class XMLStream(object):
'keyfile': self.keyfile, 'keyfile': self.keyfile,
'ca_certs': self.ca_certs, 'ca_certs': self.ca_certs,
'cert_reqs': cert_policy, 'cert_reqs': cert_policy,
'do_handshake_on_connect': False 'do_handshake_on_connect': False,
"ssl_version": self.ssl_version
}) })
if sys.version_info >= (2, 7): if sys.version_info >= (2, 7):
@ -847,13 +850,14 @@ class XMLStream(object):
'keyfile': self.keyfile, 'keyfile': self.keyfile,
'ca_certs': self.ca_certs, 'ca_certs': self.ca_certs,
'cert_reqs': cert_policy, 'cert_reqs': cert_policy,
'do_handshake_on_connect': False 'do_handshake_on_connect': False,
"ssl_version": self.ssl_version
}) })
if sys.version_info >= (2, 7): if sys.version_info >= (2, 7):
ssl_args['ciphers'] = self.ciphers ssl_args['ciphers'] = self.ciphers
ssl_socket = ssl.wrap_socket(self.socket, **ssl_args); ssl_socket = ssl.wrap_socket(self.socket, **ssl_args)
if hasattr(self.socket, 'socket'): if hasattr(self.socket, 'socket'):
# We are using a testing socket, so preserve the top # We are using a testing socket, so preserve the top
@ -1149,7 +1153,7 @@ class XMLStream(object):
""" """
return len(self.__event_handlers.get(name, [])) return len(self.__event_handlers.get(name, []))
def event(self, name, data={}, direct=False): def event(self, name, data=None, direct=False):
"""Manually trigger a custom event. """Manually trigger a custom event.
:param name: The name of the event to trigger. :param name: The name of the event to trigger.
@ -1160,6 +1164,9 @@ class XMLStream(object):
event queue. All event handlers will run in the event queue. All event handlers will run in the
same thread. same thread.
""" """
if not data:
data = {}
log.debug("Event triggered: " + name) log.debug("Event triggered: " + name)
handlers = self.__event_handlers.get(name, []) handlers = self.__event_handlers.get(name, [])
@ -1319,9 +1326,6 @@ class XMLStream(object):
try: try:
sent += self.socket.send(data[sent:]) sent += self.socket.send(data[sent:])
count += 1 count += 1
except Socket.error as serr:
if serr.errno != errno.EINTR:
raise
except ssl.SSLError as serr: except ssl.SSLError as serr:
if tries >= self.ssl_retry_max: if tries >= self.ssl_retry_max:
log.debug('SSL error: max retries reached') log.debug('SSL error: max retries reached')
@ -1336,6 +1340,9 @@ class XMLStream(object):
if not self.stop.is_set(): if not self.stop.is_set():
time.sleep(self.ssl_retry_delay) time.sleep(self.ssl_retry_delay)
tries += 1 tries += 1
except Socket.error as serr:
if serr.errno != errno.EINTR:
raise
if count > 1: if count > 1:
log.debug('SENT: %d chunks', count) log.debug('SENT: %d chunks', count)
except (Socket.error, ssl.SSLError) as serr: except (Socket.error, ssl.SSLError) as serr:
@ -1745,9 +1752,6 @@ class XMLStream(object):
try: try:
sent += self.socket.send(enc_data[sent:]) sent += self.socket.send(enc_data[sent:])
count += 1 count += 1
except Socket.error as serr:
if serr.errno != errno.EINTR:
raise
except ssl.SSLError as serr: except ssl.SSLError as serr:
if tries >= self.ssl_retry_max: if tries >= self.ssl_retry_max:
log.debug('SSL error: max retries reached') log.debug('SSL error: max retries reached')
@ -1760,6 +1764,9 @@ class XMLStream(object):
if not self.stop.is_set(): if not self.stop.is_set():
time.sleep(self.ssl_retry_delay) time.sleep(self.ssl_retry_delay)
tries += 1 tries += 1
except Socket.error as serr:
if serr.errno != errno.EINTR:
raise
if count > 1: if count > 1:
log.debug('SENT: %d chunks', count) log.debug('SENT: %d chunks', count)
self.send_queue.task_done() self.send_queue.task_done()

View File

@ -385,7 +385,7 @@ class TestElementBase(SleekTest):
interfaces = set(('bar', 'baz')) interfaces = set(('bar', 'baz'))
def setBar(self, value): def setBar(self, value):
self._set_sub_text("path/to/only/bar", value); self._set_sub_text("path/to/only/bar", value)
def getBar(self): def getBar(self):
return self._get_sub_text("path/to/only/bar") return self._get_sub_text("path/to/only/bar")
@ -394,7 +394,7 @@ class TestElementBase(SleekTest):
self._del_sub("path/to/only/bar") self._del_sub("path/to/only/bar")
def setBaz(self, value): def setBaz(self, value):
self._set_sub_text("path/to/just/baz", value); self._set_sub_text("path/to/just/baz", value)
def getBaz(self): def getBaz(self):
return self._get_sub_text("path/to/just/baz") return self._get_sub_text("path/to/just/baz")

View File

@ -59,8 +59,8 @@ class TestSensorDataStanzas(SleekTest):
iq['req']['momentary'] = 'true' iq['req']['momentary'] = 'true'
iq['req'].add_node("Device02", "Source02", "CacheType"); iq['req'].add_node("Device02", "Source02", "CacheType")
iq['req'].add_node("Device44"); iq['req'].add_node("Device44")
self.check(iq,""" self.check(iq,"""
<iq type='get' <iq type='get'
@ -75,7 +75,7 @@ class TestSensorDataStanzas(SleekTest):
""" """
) )
iq['req'].del_node("Device02"); iq['req'].del_node("Device02")
self.check(iq,""" self.check(iq,"""
<iq type='get' <iq type='get'
@ -89,7 +89,7 @@ class TestSensorDataStanzas(SleekTest):
""" """
) )
iq['req'].del_nodes(); iq['req'].del_nodes()
self.check(iq,""" self.check(iq,"""
<iq type='get' <iq type='get'
@ -115,8 +115,8 @@ class TestSensorDataStanzas(SleekTest):
iq['req']['momentary'] = 'true' iq['req']['momentary'] = 'true'
iq['req'].add_field("Top temperature"); iq['req'].add_field("Top temperature")
iq['req'].add_field("Bottom temperature"); iq['req'].add_field("Bottom temperature")
self.check(iq,""" self.check(iq,"""
<iq type='get' <iq type='get'
@ -237,12 +237,12 @@ class TestSensorDataStanzas(SleekTest):
msg['to'] = 'master@clayster.com/amr' msg['to'] = 'master@clayster.com/amr'
msg['fields']['seqnr'] = '1' msg['fields']['seqnr'] = '1'
node = msg['fields'].add_node("Device02"); node = msg['fields'].add_node("Device02")
ts = node.add_timestamp("2013-03-07T16:24:30"); ts = node.add_timestamp("2013-03-07T16:24:30")
data = ts.add_data(typename="numeric", name="Temperature", value="-12.42", unit='K'); data = ts.add_data(typename="numeric", name="Temperature", value="-12.42", unit='K')
data['momentary'] = 'true'; data['momentary'] = 'true'
data['automaticReadout'] = 'true'; data['automaticReadout'] = 'true'
self.check(msg,""" self.check(msg,"""
<message from='device@clayster.com' <message from='device@clayster.com'
@ -258,10 +258,9 @@ class TestSensorDataStanzas(SleekTest):
""" """
) )
node = msg['fields'].add_node("EmptyDevice"); node = msg['fields'].add_node("EmptyDevice")
node = msg['fields'].add_node("Device04"); node = msg['fields'].add_node("Device04")
ts = node.add_timestamp("EmptyTimestamp"); ts = node.add_timestamp("EmptyTimestamp")
self.check(msg,""" self.check(msg,"""
<message from='device@clayster.com' <message from='device@clayster.com'
@ -281,32 +280,32 @@ class TestSensorDataStanzas(SleekTest):
""" """
) )
node = msg['fields'].add_node("Device77"); node = msg['fields'].add_node("Device77")
ts = node.add_timestamp("2013-05-03T12:00:01"); ts = node.add_timestamp("2013-05-03T12:00:01")
data = ts.add_data(typename="numeric", name="Temperature", value="-12.42", unit='K'); data = ts.add_data(typename="numeric", name="Temperature", value="-12.42", unit='K')
data['historicalDay'] = 'true'; data['historicalDay'] = 'true'
data = ts.add_data(typename="numeric", name="Speed", value="312.42", unit='km/h'); data = ts.add_data(typename="numeric", name="Speed", value="312.42", unit='km/h')
data['historicalWeek'] = 'false'; data['historicalWeek'] = 'false'
data = ts.add_data(typename="string", name="Temperature name", value="Bottom oil"); data = ts.add_data(typename="string", name="Temperature name", value="Bottom oil")
data['historicalMonth'] = 'true'; data['historicalMonth'] = 'true'
data = ts.add_data(typename="string", name="Speed name", value="Top speed"); data = ts.add_data(typename="string", name="Speed name", value="Top speed")
data['historicalQuarter'] = 'false'; data['historicalQuarter'] = 'false'
data = ts.add_data(typename="dateTime", name="T1", value="1979-01-01T00:00:00"); data = ts.add_data(typename="dateTime", name="T1", value="1979-01-01T00:00:00")
data['historicalYear'] = 'true'; data['historicalYear'] = 'true'
data = ts.add_data(typename="dateTime", name="T2", value="2000-01-01T01:02:03"); data = ts.add_data(typename="dateTime", name="T2", value="2000-01-01T01:02:03")
data['historicalOther'] = 'false'; data['historicalOther'] = 'false'
data = ts.add_data(typename="timeSpan", name="TS1", value="P5Y"); data = ts.add_data(typename="timeSpan", name="TS1", value="P5Y")
data['missing'] = 'true'; data['missing'] = 'true'
data = ts.add_data(typename="timeSpan", name="TS2", value="PT2M1S"); data = ts.add_data(typename="timeSpan", name="TS2", value="PT2M1S")
data['manualEstimate'] = 'false'; data['manualEstimate'] = 'false'
data = ts.add_data(typename="enum", name="top color", value="red", dataType="string"); data = ts.add_data(typename="enum", name="top color", value="red", dataType="string")
data['invoiced'] = 'true'; data['invoiced'] = 'true'
data = ts.add_data(typename="enum", name="bottom color", value="black", dataType="string"); data = ts.add_data(typename="enum", name="bottom color", value="black", dataType="string")
data['powerFailure'] = 'false'; data['powerFailure'] = 'false'
data = ts.add_data(typename="boolean", name="Temperature real", value="false"); data = ts.add_data(typename="boolean", name="Temperature real", value="false")
data['historicalDay'] = 'true'; data['historicalDay'] = 'true'
data = ts.add_data(typename="boolean", name="Speed real", value="true"); data = ts.add_data(typename="boolean", name="Speed real", value="true")
data['historicalWeek'] = 'false'; data['historicalWeek'] = 'false'
self.check(msg,""" self.check(msg,"""
<message from='device@clayster.com' <message from='device@clayster.com'
@ -344,19 +343,17 @@ class TestSensorDataStanzas(SleekTest):
def testTimestamp(self): def testTimestamp(self):
msg = self.Message(); msg = self.Message()
msg['from'] = 'device@clayster.com' msg['from'] = 'device@clayster.com'
msg['to'] = 'master@clayster.com/amr' msg['to'] = 'master@clayster.com/amr'
msg['fields']['seqnr'] = '1' msg['fields']['seqnr'] = '1'
node = msg['fields'].add_node("Device02"); node = msg['fields'].add_node("Device02")
node = msg['fields'].add_node("Device03"); node = msg['fields'].add_node("Device03")
ts = node.add_timestamp("2013-03-07T16:24:30");
ts = node.add_timestamp("2013-03-07T16:24:31");
ts = node.add_timestamp("2013-03-07T16:24:30")
ts = node.add_timestamp("2013-03-07T16:24:31")
self.check(msg,""" self.check(msg,"""
<message from='device@clayster.com' <message from='device@clayster.com'

View File

@ -29,8 +29,8 @@ class TestControlStanzas(SleekTest):
iq['from'] = 'master@clayster.com/amr' iq['from'] = 'master@clayster.com/amr'
iq['to'] = 'device@clayster.com' iq['to'] = 'device@clayster.com'
iq['id'] = '1' iq['id'] = '1'
iq['set'].add_node("Device02", "Source02", "MyCacheType"); iq['set'].add_node("Device02", "Source02", "MyCacheType")
iq['set'].add_node("Device15"); iq['set'].add_node("Device15")
iq['set'].add_data("Tjohej", "boolean", "true") iq['set'].add_data("Tjohej", "boolean", "true")
self.check(iq,""" self.check(iq,"""
@ -47,7 +47,7 @@ class TestControlStanzas(SleekTest):
""" """
) )
iq['set'].del_node("Device02"); iq['set'].del_node("Device02")
self.check(iq,""" self.check(iq,"""
<iq type='set' <iq type='set'
@ -62,7 +62,7 @@ class TestControlStanzas(SleekTest):
""" """
) )
iq['set'].del_nodes(); iq['set'].del_nodes()
self.check(iq,""" self.check(iq,"""
<iq type='set' <iq type='set'
@ -84,8 +84,8 @@ class TestControlStanzas(SleekTest):
msg = self.Message() msg = self.Message()
msg['from'] = 'master@clayster.com/amr' msg['from'] = 'master@clayster.com/amr'
msg['to'] = 'device@clayster.com' msg['to'] = 'device@clayster.com'
msg['set'].add_node("Device02"); msg['set'].add_node("Device02")
msg['set'].add_node("Device15"); msg['set'].add_node("Device15")
msg['set'].add_data("Tjohej", "boolean", "true") msg['set'].add_data("Tjohej", "boolean", "true")
self.check(msg,""" self.check(msg,"""
@ -111,7 +111,7 @@ class TestControlStanzas(SleekTest):
iq['from'] = 'master@clayster.com/amr' iq['from'] = 'master@clayster.com/amr'
iq['to'] = 'device@clayster.com' iq['to'] = 'device@clayster.com'
iq['id'] = '8' iq['id'] = '8'
iq['setResponse']['responseCode'] = "OK"; iq['setResponse']['responseCode'] = "OK"
self.check(iq,""" self.check(iq,"""
<iq type='result' <iq type='result'
@ -128,10 +128,9 @@ class TestControlStanzas(SleekTest):
iq['from'] = 'master@clayster.com/amr' iq['from'] = 'master@clayster.com/amr'
iq['to'] = 'device@clayster.com' iq['to'] = 'device@clayster.com'
iq['id'] = '9' iq['id'] = '9'
iq['setResponse']['responseCode'] = "OtherError"; iq['setResponse']['responseCode'] = "OtherError"
iq['setResponse']['error']['var'] = "Output"; iq['setResponse']['error']['var'] = "Output"
iq['setResponse']['error']['text'] = "Test of other error.!"; iq['setResponse']['error']['text'] = "Test of other error.!"
self.check(iq,""" self.check(iq,"""
<iq type='error' <iq type='error'
@ -150,11 +149,10 @@ class TestControlStanzas(SleekTest):
iq['from'] = 'master@clayster.com/amr' iq['from'] = 'master@clayster.com/amr'
iq['to'] = 'device@clayster.com' iq['to'] = 'device@clayster.com'
iq['id'] = '9' iq['id'] = '9'
iq['setResponse']['responseCode'] = "NotFound"; iq['setResponse']['responseCode'] = "NotFound"
iq['setResponse'].add_node("Device17", "Source09"); iq['setResponse'].add_node("Device17", "Source09")
iq['setResponse'].add_node("Device18", "Source09"); iq['setResponse'].add_node("Device18", "Source09")
iq['setResponse'].add_data("Tjohopp"); iq['setResponse'].add_data("Tjohopp")
self.check(iq,""" self.check(iq,"""
<iq type='error' <iq type='error'
@ -179,38 +177,38 @@ class TestControlStanzas(SleekTest):
iq['from'] = 'master@clayster.com/amr' iq['from'] = 'master@clayster.com/amr'
iq['to'] = 'device@clayster.com' iq['to'] = 'device@clayster.com'
iq['id'] = '1' iq['id'] = '1'
iq['set'].add_node("Device02", "Source02", "MyCacheType"); iq['set'].add_node("Device02", "Source02", "MyCacheType")
iq['set'].add_node("Device15"); iq['set'].add_node("Device15")
iq['set'].add_data("Tjohej", "boolean", "true"); iq['set'].add_data("Tjohej", "boolean", "true")
iq['set'].add_data("Tjohej2", "boolean", "false"); iq['set'].add_data("Tjohej2", "boolean", "false")
iq['set'].add_data("TjohejC", "color", "FF00FF"); iq['set'].add_data("TjohejC", "color", "FF00FF")
iq['set'].add_data("TjohejC2", "color", "00FF00"); iq['set'].add_data("TjohejC2", "color", "00FF00")
iq['set'].add_data("TjohejS", "string", "String1"); iq['set'].add_data("TjohejS", "string", "String1")
iq['set'].add_data("TjohejS2", "string", "String2"); iq['set'].add_data("TjohejS2", "string", "String2")
iq['set'].add_data("TjohejDate", "date", "2012-01-01"); iq['set'].add_data("TjohejDate", "date", "2012-01-01")
iq['set'].add_data("TjohejDate2", "date", "1900-12-03"); iq['set'].add_data("TjohejDate2", "date", "1900-12-03")
iq['set'].add_data("TjohejDateT4", "dateTime", "1900-12-03 12:30"); iq['set'].add_data("TjohejDateT4", "dateTime", "1900-12-03 12:30")
iq['set'].add_data("TjohejDateT2", "dateTime", "1900-12-03 11:22"); iq['set'].add_data("TjohejDateT2", "dateTime", "1900-12-03 11:22")
iq['set'].add_data("TjohejDouble2", "double", "200.22"); iq['set'].add_data("TjohejDouble2", "double", "200.22")
iq['set'].add_data("TjohejDouble3", "double", "-12232131.3333"); iq['set'].add_data("TjohejDouble3", "double", "-12232131.3333")
iq['set'].add_data("TjohejDur", "duration", "P5Y"); iq['set'].add_data("TjohejDur", "duration", "P5Y")
iq['set'].add_data("TjohejDur2", "duration", "PT2M1S"); iq['set'].add_data("TjohejDur2", "duration", "PT2M1S")
iq['set'].add_data("TjohejInt", "int", "1"); iq['set'].add_data("TjohejInt", "int", "1")
iq['set'].add_data("TjohejInt2", "int", "-42"); iq['set'].add_data("TjohejInt2", "int", "-42")
iq['set'].add_data("TjohejLong", "long", "123456789098"); iq['set'].add_data("TjohejLong", "long", "123456789098")
iq['set'].add_data("TjohejLong2", "long", "-90983243827489374"); iq['set'].add_data("TjohejLong2", "long", "-90983243827489374")
iq['set'].add_data("TjohejTime", "time", "23:59"); iq['set'].add_data("TjohejTime", "time", "23:59")
iq['set'].add_data("TjohejTime2", "time", "12:00"); iq['set'].add_data("TjohejTime2", "time", "12:00")
self.check(iq,""" self.check(iq,"""
<iq type='set' <iq type='set'

View File

@ -19,7 +19,7 @@ class TestStreamSensorData(SleekTest):
pass pass
def _time_now(self): def _time_now(self):
return datetime.datetime.now().replace(microsecond=0).isoformat(); return datetime.datetime.now().replace(microsecond=0).isoformat()
def tearDown(self): def tearDown(self):
self.stream_close() self.stream_close()
@ -29,12 +29,12 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device22"); myDevice = Device("Device22")
myDevice._add_field(name="Temperature", typename="numeric", unit="°C"); myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
myDevice._set_momentary_timestamp("2013-03-07T16:24:30") myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"}); myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
self.recv(""" self.recv("""
<iq type='get' <iq type='get'
@ -73,7 +73,7 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
self.xmpp['xep_0323']._set_authenticated("darth@deathstar.com"); self.xmpp['xep_0323']._set_authenticated("darth@deathstar.com")
self.recv(""" self.recv("""
<iq type='get' <iq type='get'
@ -101,8 +101,8 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device44"); myDevice = Device("Device44")
self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
print("."), print("."),
@ -157,11 +157,11 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device44"); myDevice = Device("Device44")
myDevice._add_field(name='Voltage', typename="numeric", unit="V"); myDevice._add_field(name='Voltage', typename="numeric", unit="V")
myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
print("."), print("."),
@ -236,15 +236,15 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device44"); myDevice = Device("Device44")
myDevice._add_field(name='Voltage', typename="numeric", unit="V"); myDevice._add_field(name='Voltage', typename="numeric", unit="V")
myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
myDevice._add_field(name='Current', typename="numeric", unit="A"); myDevice._add_field(name='Current', typename="numeric", unit="A")
myDevice._add_field(name='Height', typename="string"); myDevice._add_field(name='Height', typename="string")
myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02"); myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02")
myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"})
self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
print("."), print("."),
@ -308,15 +308,15 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device44"); myDevice = Device("Device44")
myDevice._add_field(name='Voltage', typename="numeric", unit="V"); myDevice._add_field(name='Voltage', typename="numeric", unit="V")
myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
myDevice._add_field(name='Current', typename="numeric", unit="A"); myDevice._add_field(name='Current', typename="numeric", unit="A")
myDevice._add_field(name='Height', typename="string"); myDevice._add_field(name='Height', typename="string")
myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02"); myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02")
myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"})
self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
print("."), print("."),
@ -379,7 +379,7 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", callback=None); self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", callback=None)
self.send(""" self.send("""
<iq type='get' <iq type='get'
@ -390,7 +390,7 @@ class TestStreamSensorData(SleekTest):
</iq> </iq>
""") """)
self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=None); self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=None)
self.send(""" self.send("""
<iq type='get' <iq type='get'
@ -404,7 +404,7 @@ class TestStreamSensorData(SleekTest):
</iq> </iq>
""") """)
self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", fields=['Temperature', 'Voltage'], callback=None); self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", fields=['Temperature', 'Voltage'], callback=None)
self.send(""" self.send("""
<iq type='get' <iq type='get'
@ -424,13 +424,13 @@ class TestStreamSensorData(SleekTest):
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"):
results.append("rejected"); results.append("rejected")
self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback); self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback)
self.send(""" self.send("""
<iq type='get' <iq type='get'
@ -458,7 +458,7 @@ class TestStreamSensorData(SleekTest):
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,12 +466,12 @@ class TestStreamSensorData(SleekTest):
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)
self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback); self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback)
self.send(""" self.send("""
<iq type='get' <iq type='get'
@ -497,7 +497,7 @@ class TestStreamSensorData(SleekTest):
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,25 +505,25 @@ class TestStreamSensorData(SleekTest):
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)
if result == "fields": if result == "fields":
callback_data["nodeId"] = nodeId; callback_data["nodeId"] = nodeId
callback_data["timestamp"] = timestamp; callback_data["timestamp"] = timestamp
callback_data["error_msg"] = error_msg; callback_data["error_msg"] = error_msg
for f in fields: for f in fields:
callback_data["field_" + f['name']] = f; callback_data["field_" + f['name']] = f
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);
self.send(""" self.send("""
@ -567,27 +567,27 @@ class TestStreamSensorData(SleekTest):
</message> </message>
""") """)
t1.join(); t1.join()
time.sleep(.5) time.sleep(.5)
self.failUnlessEqual(results, ["accepted","fields","done"]); self.failUnlessEqual(results, ["accepted","fields","done"])
# self.assertIn("nodeId", callback_data); # self.assertIn("nodeId", callback_data);
self.assertTrue("nodeId" in callback_data) self.assertTrue("nodeId" in callback_data)
self.failUnlessEqual(callback_data["nodeId"], "Device33"); self.failUnlessEqual(callback_data["nodeId"], "Device33")
# self.assertIn("timestamp", callback_data); # self.assertIn("timestamp", callback_data);
self.assertTrue("timestamp" in callback_data); self.assertTrue("timestamp" in callback_data)
self.failUnlessEqual(callback_data["timestamp"], "2000-01-01T00:01:02"); self.failUnlessEqual(callback_data["timestamp"], "2000-01-01T00:01:02")
#self.assertIn("field_Voltage", callback_data); #self.assertIn("field_Voltage", callback_data);
self.assertTrue("field_Voltage" in callback_data); self.assertTrue("field_Voltage" in callback_data)
self.failUnlessEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}}); self.failUnlessEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}})
#self.assertIn("field_TestBool", callback_data); #self.assertIn("field_TestBool", callback_data);
self.assertTrue("field_TestBool" in callback_data); self.assertTrue("field_TestBool" in callback_data)
self.failUnlessEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" }); self.failUnlessEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" })
def testServiceDiscoveryClient(self): def testServiceDiscoveryClient(self):
self.stream_start(mode='client', self.stream_start(mode='client',
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']); 'xep_0323'])
self.recv(""" self.recv("""
<iq type='get' <iq type='get'
@ -612,7 +612,7 @@ class TestStreamSensorData(SleekTest):
def testServiceDiscoveryComponent(self): def testServiceDiscoveryComponent(self):
self.stream_start(mode='component', self.stream_start(mode='component',
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']); 'xep_0323'])
self.recv(""" self.recv("""
<iq type='get' <iq type='get'
@ -641,23 +641,23 @@ class TestStreamSensorData(SleekTest):
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, error_msg=None): def my_callback(from_jid, result, nodeId=None, timestamp=None, error_msg=None):
results.append(result); results.append(result)
if result == "failure": if result == "failure":
callback_data["nodeId"] = nodeId; callback_data["nodeId"] = nodeId
callback_data["timestamp"] = timestamp; callback_data["timestamp"] = timestamp
callback_data["error_msg"] = error_msg; callback_data["error_msg"] = error_msg
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.send(""" self.send("""
<iq type='get' <iq type='get'
@ -688,31 +688,31 @@ class TestStreamSensorData(SleekTest):
</message> </message>
""") """)
t1.join(); t1.join()
time.sleep(.5) time.sleep(.5)
self.failUnlessEqual(results, ["accepted","failure"]); self.failUnlessEqual(results, ["accepted","failure"])
# self.assertIn("nodeId", callback_data); # self.assertIn("nodeId", callback_data);
self.assertTrue("nodeId" in callback_data); self.assertTrue("nodeId" in callback_data)
self.failUnlessEqual(callback_data["nodeId"], "Device33"); self.failUnlessEqual(callback_data["nodeId"], "Device33")
# self.assertIn("timestamp", callback_data); # self.assertIn("timestamp", callback_data);
self.assertTrue("timestamp" in callback_data); self.assertTrue("timestamp" in callback_data)
self.failUnlessEqual(callback_data["timestamp"], "2013-03-07T17:13:30"); self.failUnlessEqual(callback_data["timestamp"], "2013-03-07T17:13:30")
# self.assertIn("error_msg", callback_data); # self.assertIn("error_msg", callback_data);
self.assertTrue("error_msg" in callback_data); self.assertTrue("error_msg" in callback_data)
self.failUnlessEqual(callback_data["error_msg"], "Timeout."); self.failUnlessEqual(callback_data["error_msg"], "Timeout.")
def testDelayedRequest(self): def testDelayedRequest(self):
self.stream_start(mode='component', self.stream_start(mode='component',
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device22"); myDevice = Device("Device22")
myDevice._add_field(name="Temperature", typename="numeric", unit="°C"); myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
myDevice._set_momentary_timestamp("2013-03-07T16:24:30") myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"}); myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
dtnow = datetime.datetime.now() dtnow = datetime.datetime.now()
ts_2sec = datetime.timedelta(0,2) ts_2sec = datetime.timedelta(0,2)
@ -764,12 +764,12 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device22"); myDevice = Device("Device22")
myDevice._add_field(name="Temperature", typename="numeric", unit="°C"); myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
myDevice._set_momentary_timestamp("2013-03-07T16:24:30") myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"}); myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
dtnow = datetime.datetime.now() dtnow = datetime.datetime.now()
ts_2sec = datetime.timedelta(0,2) ts_2sec = datetime.timedelta(0,2)
@ -825,13 +825,13 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device44"); myDevice = Device("Device44")
myDevice._add_field(name='Voltage', typename="numeric", unit="V"); myDevice._add_field(name='Voltage', typename="numeric", unit="V")
myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"})
myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"})
self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
print("."), print("."),
@ -895,13 +895,13 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device44"); myDevice = Device("Device44")
myDevice._add_field(name='Voltage', typename="numeric", unit="V"); myDevice._add_field(name='Voltage', typename="numeric", unit="V")
myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"})
myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"})
self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
print("."), print("."),
@ -965,13 +965,13 @@ class TestStreamSensorData(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device44"); myDevice = Device("Device44")
myDevice._add_field(name='Voltage', typename="numeric", unit="V"); myDevice._add_field(name='Voltage', typename="numeric", unit="V")
myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"})
myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"}); myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"})
self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
print("."), print("."),
@ -1021,25 +1021,25 @@ class TestStreamSensorData(SleekTest):
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)
if result == "fields": if result == "fields":
callback_data["nodeId"] = nodeId; callback_data["nodeId"] = nodeId
callback_data["timestamp"] = timestamp; callback_data["timestamp"] = timestamp
callback_data["error_msg"] = error_msg; callback_data["error_msg"] = error_msg
for f in fields: for f in fields:
callback_data["field_" + f['name']] = f; callback_data["field_" + f['name']] = f
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);
self.send(""" self.send("""
@ -1090,22 +1090,22 @@ class TestStreamSensorData(SleekTest):
</message> </message>
""") """)
t1.join(); t1.join()
time.sleep(.5) time.sleep(.5)
self.failUnlessEqual(results, ["queued","started","fields","done"]); self.failUnlessEqual(results, ["queued","started","fields","done"])
# self.assertIn("nodeId", callback_data); # self.assertIn("nodeId", callback_data);
self.assertTrue("nodeId" in callback_data); self.assertTrue("nodeId" in callback_data)
self.failUnlessEqual(callback_data["nodeId"], "Device33"); self.failUnlessEqual(callback_data["nodeId"], "Device33")
# self.assertIn("timestamp", callback_data); # self.assertIn("timestamp", callback_data);
self.assertTrue("timestamp" in callback_data); self.assertTrue("timestamp" in callback_data)
self.failUnlessEqual(callback_data["timestamp"], "2000-01-01T00:01:02"); self.failUnlessEqual(callback_data["timestamp"], "2000-01-01T00:01:02")
# self.assertIn("field_Voltage", callback_data); # self.assertIn("field_Voltage", callback_data);
self.assertTrue("field_Voltage" in callback_data); self.assertTrue("field_Voltage" in callback_data)
self.failUnlessEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}}); self.failUnlessEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}})
# self.assertIn("field_TestBool", callback_data); # self.assertIn("field_TestBool", callback_data);
self.assertTrue("field_TestBool" in callback_data); self.assertTrue("field_TestBool" in callback_data)
self.failUnlessEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" }); self.failUnlessEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" })
def testRequestFieldsCancelAPI(self): def testRequestFieldsCancelAPI(self):
@ -1114,12 +1114,12 @@ class TestStreamSensorData(SleekTest):
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)
session = self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback); session = self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback)
self.send(""" self.send("""
<iq type='get' <iq type='get'
@ -1141,7 +1141,7 @@ class TestStreamSensorData(SleekTest):
</iq> </iq>
""") """)
self.xmpp['xep_0323'].cancel_request(session=session); self.xmpp['xep_0323'].cancel_request(session=session)
self.send(""" self.send("""
<iq type='get' <iq type='get'
@ -1163,19 +1163,19 @@ class TestStreamSensorData(SleekTest):
time.sleep(.5) time.sleep(.5)
self.failUnlessEqual(results, ["accepted","cancelled"]); self.failUnlessEqual(results, ["accepted","cancelled"])
def testDelayedRequestCancel(self): def testDelayedRequestCancel(self):
self.stream_start(mode='component', self.stream_start(mode='component',
plugins=['xep_0030', plugins=['xep_0030',
'xep_0323']) 'xep_0323'])
myDevice = Device("Device22"); myDevice = Device("Device22")
myDevice._add_field(name="Temperature", typename="numeric", unit="°C"); myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
myDevice._set_momentary_timestamp("2013-03-07T16:24:30") myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"}); myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5); self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
dtnow = datetime.datetime.now() dtnow = datetime.datetime.now()
ts_2sec = datetime.timedelta(0,2) ts_2sec = datetime.timedelta(0,2)

View File

@ -28,7 +28,7 @@ class TestStreamControl(SleekTest):
pass pass
def _time_now(self): def _time_now(self):
return datetime.datetime.now().replace(microsecond=0).isoformat(); return datetime.datetime.now().replace(microsecond=0).isoformat()
def tearDown(self): def tearDown(self):
self.stream_close() self.stream_close()
@ -38,10 +38,10 @@ class TestStreamControl(SleekTest):
plugins=['xep_0030', plugins=['xep_0030',
'xep_0325']) 'xep_0325'])
myDevice = Device("Device22"); myDevice = Device("Device22")
myDevice._add_control_field(name="Temperature", typename="int", value="15"); myDevice._add_control_field(name="Temperature", typename="int", value="15")
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("""
<iq type='set' <iq type='set'
@ -63,23 +63,23 @@ class TestStreamControl(SleekTest):
</iq> </iq>
""") """)
self.assertEqual(myDevice._get_field_value("Temperature"), "17"); self.assertEqual(myDevice._get_field_value("Temperature"), "17")
def testRequestSetMulti(self): def testRequestSetMulti(self):
self.stream_start(mode='component', self.stream_start(mode='component',
plugins=['xep_0030', plugins=['xep_0030',
'xep_0325']) 'xep_0325'])
myDevice = Device("Device22"); myDevice = Device("Device22")
myDevice._add_control_field(name="Temperature", typename="int", value="15"); myDevice._add_control_field(name="Temperature", typename="int", value="15")
myDevice._add_control_field(name="Startup", typename="date", value="2013-01-03"); myDevice._add_control_field(name="Startup", typename="date", value="2013-01-03")
myDevice2 = Device("Device23"); myDevice2 = Device("Device23")
myDevice2._add_control_field(name="Temperature", typename="int", value="19"); myDevice2._add_control_field(name="Temperature", typename="int", value="19")
myDevice2._add_control_field(name="Startup", typename="date", value="2013-01-09"); myDevice2._add_control_field(name="Startup", typename="date", value="2013-01-09")
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.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice2, commTimeout=0.5); self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice2, commTimeout=0.5)
self.recv(""" self.recv("""
<iq type='set' <iq type='set'
@ -102,8 +102,8 @@ class TestStreamControl(SleekTest):
</iq> </iq>
""") """)
self.assertEqual(myDevice._get_field_value("Temperature"), "17"); self.assertEqual(myDevice._get_field_value("Temperature"), "17")
self.assertEqual(myDevice2._get_field_value("Temperature"), "19"); self.assertEqual(myDevice2._get_field_value("Temperature"), "19")
self.recv(""" self.recv("""
<iq type='set' <iq type='set'
@ -128,20 +128,20 @@ class TestStreamControl(SleekTest):
</iq> </iq>
""") """)
self.assertEqual(myDevice._get_field_value("Temperature"), "20"); self.assertEqual(myDevice._get_field_value("Temperature"), "20")
self.assertEqual(myDevice2._get_field_value("Temperature"), "20"); self.assertEqual(myDevice2._get_field_value("Temperature"), "20")
self.assertEqual(myDevice._get_field_value("Startup"), "2013-02-01"); self.assertEqual(myDevice._get_field_value("Startup"), "2013-02-01")
self.assertEqual(myDevice2._get_field_value("Startup"), "2013-02-01"); self.assertEqual(myDevice2._get_field_value("Startup"), "2013-02-01")
def testRequestSetFail(self): def testRequestSetFail(self):
self.stream_start(mode='component', self.stream_start(mode='component',
plugins=['xep_0030', plugins=['xep_0030',
'xep_0325']) 'xep_0325'])
myDevice = Device("Device23"); myDevice = Device("Device23")
myDevice._add_control_field(name="Temperature", typename="int", value="15"); myDevice._add_control_field(name="Temperature", typename="int", value="15")
self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice, commTimeout=0.5); self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice, commTimeout=0.5)
self.recv(""" self.recv("""
<iq type='set' <iq type='set'
@ -166,18 +166,18 @@ class TestStreamControl(SleekTest):
</iq> </iq>
""") """)
self.assertEqual(myDevice._get_field_value("Temperature"), "15"); self.assertEqual(myDevice._get_field_value("Temperature"), "15")
self.assertFalse(myDevice.has_control_field("Voltage", "int")); self.assertFalse(myDevice.has_control_field("Voltage", "int"))
def testDirectSetOk(self): def testDirectSetOk(self):
self.stream_start(mode='component', self.stream_start(mode='component',
plugins=['xep_0030', plugins=['xep_0030',
'xep_0325']) 'xep_0325'])
myDevice = Device("Device22"); myDevice = Device("Device22")
myDevice._add_control_field(name="Temperature", typename="int", value="15"); myDevice._add_control_field(name="Temperature", typename="int", value="15")
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
@ -191,17 +191,17 @@ class TestStreamControl(SleekTest):
time.sleep(.5) time.sleep(.5)
self.assertEqual(myDevice._get_field_value("Temperature"), "17"); self.assertEqual(myDevice._get_field_value("Temperature"), "17")
def testDirectSetFail(self): def testDirectSetFail(self):
self.stream_start(mode='component', self.stream_start(mode='component',
plugins=['xep_0030', plugins=['xep_0030',
'xep_0325']) 'xep_0325'])
myDevice = Device("Device22"); myDevice = Device("Device22")
myDevice._add_control_field(name="Temperature", typename="int", value="15"); myDevice._add_control_field(name="Temperature", typename="int", value="15")
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
@ -215,8 +215,8 @@ class TestStreamControl(SleekTest):
time.sleep(.5) time.sleep(.5)
self.assertEqual(myDevice._get_field_value("Temperature"), "15"); self.assertEqual(myDevice._get_field_value("Temperature"), "15")
self.assertFalse(myDevice.has_control_field("Voltage", "int")); self.assertFalse(myDevice.has_control_field("Voltage", "int"))
def testRequestSetOkAPI(self): def testRequestSetOkAPI(self):
@ -225,16 +225,16 @@ class TestStreamControl(SleekTest):
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)
fields = [] fields = []
fields.append(("Temperature", "double", "20.5")) fields.append(("Temperature", "double", "20.5"))
fields.append(("TemperatureAlarmSetting", "string", "High")) fields.append(("TemperatureAlarmSetting", "string", "High"))
self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback); self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback)
self.send(""" self.send("""
<iq type='set' <iq type='set'
@ -261,7 +261,7 @@ class TestStreamControl(SleekTest):
time.sleep(.5) time.sleep(.5)
self.assertEqual(results, ["OK"]); self.assertEqual(results, ["OK"])
def testRequestSetErrorAPI(self): def testRequestSetErrorAPI(self):
@ -269,16 +269,16 @@ class TestStreamControl(SleekTest):
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)
fields = [] fields = []
fields.append(("Temperature", "double", "20.5")) fields.append(("Temperature", "double", "20.5"))
fields.append(("TemperatureAlarmSetting", "string", "High")) fields.append(("TemperatureAlarmSetting", "string", "High"))
self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback); self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback)
self.send(""" self.send("""
<iq type='set' <iq type='set'
@ -307,12 +307,12 @@ class TestStreamControl(SleekTest):
time.sleep(.5) time.sleep(.5)
self.assertEqual(results, ["OtherError"]); self.assertEqual(results, ["OtherError"])
def testServiceDiscoveryClient(self): def testServiceDiscoveryClient(self):
self.stream_start(mode='client', self.stream_start(mode='client',
plugins=['xep_0030', plugins=['xep_0030',
'xep_0325']); 'xep_0325'])
self.recv(""" self.recv("""
<iq type='get' <iq type='get'
@ -337,7 +337,7 @@ class TestStreamControl(SleekTest):
def testServiceDiscoveryComponent(self): def testServiceDiscoveryComponent(self):
self.stream_start(mode='component', self.stream_start(mode='component',
plugins=['xep_0030', plugins=['xep_0030',
'xep_0325']); 'xep_0325'])
self.recv(""" self.recv("""
<iq type='get' <iq type='get'

View File

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py26,py27,py31,py32,py33 envlist = py26,py27,py34
[testenv] [testenv]
deps = nose deps = nose
commands = nosetests --where=tests --exclude=live -i sleektest.py commands = nosetests --where=tests --exclude=live -i sleektest.py