Remove all trailing whitespaces.
This commit is contained in:
committed by
Florent Le Coz
parent
ed37174a2b
commit
17174016ec
@@ -1,218 +1,218 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON).
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from slixmpp import Iq
|
||||
from slixmpp.xmlstream import ET, register_stanza_plugin
|
||||
from slixmpp.xmlstream.handler import Callback
|
||||
from slixmpp.xmlstream.matcher import MatchXPath
|
||||
from slixmpp.plugins import BasePlugin
|
||||
from slixmpp.plugins.xep_0009 import stanza
|
||||
from slixmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XEP_0009(BasePlugin):
|
||||
|
||||
name = 'xep_0009'
|
||||
description = 'XEP-0009: Jabber-RPC'
|
||||
dependencies = set(['xep_0030'])
|
||||
stanza = stanza
|
||||
|
||||
def plugin_init(self):
|
||||
register_stanza_plugin(Iq, RPCQuery)
|
||||
register_stanza_plugin(RPCQuery, MethodCall)
|
||||
register_stanza_plugin(RPCQuery, MethodResponse)
|
||||
|
||||
self.xmpp.register_handler(
|
||||
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
|
||||
self._handle_method_call)
|
||||
)
|
||||
self.xmpp.register_handler(
|
||||
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
|
||||
self._handle_method_response)
|
||||
)
|
||||
self.xmpp.register_handler(
|
||||
Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)),
|
||||
self._handle_error)
|
||||
)
|
||||
self.xmpp.add_event_handler('jabber_rpc_method_call', self._on_jabber_rpc_method_call)
|
||||
self.xmpp.add_event_handler('jabber_rpc_method_response', self._on_jabber_rpc_method_response)
|
||||
self.xmpp.add_event_handler('jabber_rpc_method_fault', self._on_jabber_rpc_method_fault)
|
||||
self.xmpp.add_event_handler('jabber_rpc_error', self._on_jabber_rpc_error)
|
||||
self.xmpp.add_event_handler('error', self._handle_error)
|
||||
#self.activeCalls = []
|
||||
|
||||
self.xmpp['xep_0030'].add_feature('jabber:iq:rpc')
|
||||
self.xmpp['xep_0030'].add_identity('automation','rpc')
|
||||
|
||||
def make_iq_method_call(self, pto, pmethod, params):
|
||||
iq = self.xmpp.makeIqSet()
|
||||
iq.attrib['to'] = pto
|
||||
iq.attrib['from'] = self.xmpp.boundjid.full
|
||||
iq.enable('rpc_query')
|
||||
iq['rpc_query']['method_call']['method_name'] = pmethod
|
||||
iq['rpc_query']['method_call']['params'] = params
|
||||
return iq;
|
||||
|
||||
def make_iq_method_response(self, pid, pto, params):
|
||||
iq = self.xmpp.makeIqResult(pid)
|
||||
iq.attrib['to'] = pto
|
||||
iq.attrib['from'] = self.xmpp.boundjid.full
|
||||
iq.enable('rpc_query')
|
||||
iq['rpc_query']['method_response']['params'] = params
|
||||
return iq
|
||||
|
||||
def make_iq_method_response_fault(self, pid, pto, params):
|
||||
iq = self.xmpp.makeIqResult(pid)
|
||||
iq.attrib['to'] = pto
|
||||
iq.attrib['from'] = self.xmpp.boundjid.full
|
||||
iq.enable('rpc_query')
|
||||
iq['rpc_query']['method_response']['params'] = None
|
||||
iq['rpc_query']['method_response']['fault'] = params
|
||||
return iq
|
||||
|
||||
# def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition):
|
||||
# iq = self.xmpp.makeIqError(pid)
|
||||
# iq.attrib['to'] = pto
|
||||
# iq.attrib['from'] = self.xmpp.boundjid.full
|
||||
# iq['error']['code'] = code
|
||||
# iq['error']['type'] = type
|
||||
# iq['error']['condition'] = condition
|
||||
# iq['rpc_query']['method_call']['method_name'] = pmethod
|
||||
# iq['rpc_query']['method_call']['params'] = params
|
||||
# return iq
|
||||
|
||||
def _item_not_found(self, iq):
|
||||
payload = iq.get_payload()
|
||||
iq.reply().error().set_payload(payload);
|
||||
iq['error']['code'] = '404'
|
||||
iq['error']['type'] = 'cancel'
|
||||
iq['error']['condition'] = 'item-not-found'
|
||||
return iq
|
||||
|
||||
def _undefined_condition(self, iq):
|
||||
payload = iq.get_payload()
|
||||
iq.reply().error().set_payload(payload)
|
||||
iq['error']['code'] = '500'
|
||||
iq['error']['type'] = 'cancel'
|
||||
iq['error']['condition'] = 'undefined-condition'
|
||||
return iq
|
||||
|
||||
def _forbidden(self, iq):
|
||||
payload = iq.get_payload()
|
||||
iq.reply().error().set_payload(payload)
|
||||
iq['error']['code'] = '403'
|
||||
iq['error']['type'] = 'auth'
|
||||
iq['error']['condition'] = 'forbidden'
|
||||
return iq
|
||||
|
||||
def _recipient_unvailable(self, iq):
|
||||
payload = iq.get_payload()
|
||||
iq.reply().error().set_payload(payload)
|
||||
iq['error']['code'] = '404'
|
||||
iq['error']['type'] = 'wait'
|
||||
iq['error']['condition'] = 'recipient-unavailable'
|
||||
return iq
|
||||
|
||||
def _handle_method_call(self, iq):
|
||||
type = iq['type']
|
||||
if type == 'set':
|
||||
log.debug("Incoming Jabber-RPC call from %s", iq['from'])
|
||||
self.xmpp.event('jabber_rpc_method_call', iq)
|
||||
else:
|
||||
if type == 'error' and ['rpc_query'] is None:
|
||||
self.handle_error(iq)
|
||||
else:
|
||||
log.debug("Incoming Jabber-RPC error from %s", iq['from'])
|
||||
self.xmpp.event('jabber_rpc_error', iq)
|
||||
|
||||
def _handle_method_response(self, iq):
|
||||
if iq['rpc_query']['method_response']['fault'] is not None:
|
||||
log.debug("Incoming Jabber-RPC fault from %s", iq['from'])
|
||||
#self._on_jabber_rpc_method_fault(iq)
|
||||
self.xmpp.event('jabber_rpc_method_fault', iq)
|
||||
else:
|
||||
log.debug("Incoming Jabber-RPC response from %s", iq['from'])
|
||||
self.xmpp.event('jabber_rpc_method_response', iq)
|
||||
|
||||
def _handle_error(self, iq):
|
||||
print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq)
|
||||
print("#######################")
|
||||
print("### NOT IMPLEMENTED ###")
|
||||
print("#######################")
|
||||
|
||||
def _on_jabber_rpc_method_call(self, iq, forwarded=False):
|
||||
"""
|
||||
A default handler for Jabber-RPC method call. If another
|
||||
handler is registered, this one will defer and not run.
|
||||
|
||||
If this handler is called by your own custom handler with
|
||||
forwarded set to True, then it will run as normal.
|
||||
"""
|
||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_call') > 1:
|
||||
return
|
||||
# Reply with error by default
|
||||
error = self.client.plugin['xep_0009']._item_not_found(iq)
|
||||
error.send()
|
||||
|
||||
def _on_jabber_rpc_method_response(self, iq, forwarded=False):
|
||||
"""
|
||||
A default handler for Jabber-RPC method response. If another
|
||||
handler is registered, this one will defer and not run.
|
||||
|
||||
If this handler is called by your own custom handler with
|
||||
forwarded set to True, then it will run as normal.
|
||||
"""
|
||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_response') > 1:
|
||||
return
|
||||
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
|
||||
error.send()
|
||||
|
||||
def _on_jabber_rpc_method_fault(self, iq, forwarded=False):
|
||||
"""
|
||||
A default handler for Jabber-RPC fault response. If another
|
||||
handler is registered, this one will defer and not run.
|
||||
|
||||
If this handler is called by your own custom handler with
|
||||
forwarded set to True, then it will run as normal.
|
||||
"""
|
||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_fault') > 1:
|
||||
return
|
||||
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
|
||||
error.send()
|
||||
|
||||
def _on_jabber_rpc_error(self, iq, forwarded=False):
|
||||
"""
|
||||
A default handler for Jabber-RPC error response. If another
|
||||
handler is registered, this one will defer and not run.
|
||||
|
||||
If this handler is called by your own custom handler with
|
||||
forwarded set to True, then it will run as normal.
|
||||
"""
|
||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_error') > 1:
|
||||
return
|
||||
error = self.client.plugin['xep_0009']._recpient_unavailable(iq, iq.get_payload())
|
||||
error.send()
|
||||
|
||||
def _send_fault(self, iq, fault_xml): #
|
||||
fault = self.make_iq_method_response_fault(iq['id'], iq['from'], fault_xml)
|
||||
fault.send()
|
||||
|
||||
def _send_error(self, iq):
|
||||
print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq)
|
||||
print("#######################")
|
||||
print("### NOT IMPLEMENTED ###")
|
||||
print("#######################")
|
||||
|
||||
def _extract_method(self, stanza):
|
||||
xml = ET.fromstring("%s" % stanza)
|
||||
return xml.find("./methodCall/methodName").text
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Nathanael C. Fritz, Dann Martens (TOMOTON).
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from slixmpp import Iq
|
||||
from slixmpp.xmlstream import ET, register_stanza_plugin
|
||||
from slixmpp.xmlstream.handler import Callback
|
||||
from slixmpp.xmlstream.matcher import MatchXPath
|
||||
from slixmpp.plugins import BasePlugin
|
||||
from slixmpp.plugins.xep_0009 import stanza
|
||||
from slixmpp.plugins.xep_0009.stanza.RPC import RPCQuery, MethodCall, MethodResponse
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XEP_0009(BasePlugin):
|
||||
|
||||
name = 'xep_0009'
|
||||
description = 'XEP-0009: Jabber-RPC'
|
||||
dependencies = set(['xep_0030'])
|
||||
stanza = stanza
|
||||
|
||||
def plugin_init(self):
|
||||
register_stanza_plugin(Iq, RPCQuery)
|
||||
register_stanza_plugin(RPCQuery, MethodCall)
|
||||
register_stanza_plugin(RPCQuery, MethodResponse)
|
||||
|
||||
self.xmpp.register_handler(
|
||||
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodCall' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
|
||||
self._handle_method_call)
|
||||
)
|
||||
self.xmpp.register_handler(
|
||||
Callback('RPC Call', MatchXPath('{%s}iq/{%s}query/{%s}methodResponse' % (self.xmpp.default_ns, RPCQuery.namespace, RPCQuery.namespace)),
|
||||
self._handle_method_response)
|
||||
)
|
||||
self.xmpp.register_handler(
|
||||
Callback('RPC Call', MatchXPath('{%s}iq/{%s}error' % (self.xmpp.default_ns, self.xmpp.default_ns)),
|
||||
self._handle_error)
|
||||
)
|
||||
self.xmpp.add_event_handler('jabber_rpc_method_call', self._on_jabber_rpc_method_call)
|
||||
self.xmpp.add_event_handler('jabber_rpc_method_response', self._on_jabber_rpc_method_response)
|
||||
self.xmpp.add_event_handler('jabber_rpc_method_fault', self._on_jabber_rpc_method_fault)
|
||||
self.xmpp.add_event_handler('jabber_rpc_error', self._on_jabber_rpc_error)
|
||||
self.xmpp.add_event_handler('error', self._handle_error)
|
||||
#self.activeCalls = []
|
||||
|
||||
self.xmpp['xep_0030'].add_feature('jabber:iq:rpc')
|
||||
self.xmpp['xep_0030'].add_identity('automation','rpc')
|
||||
|
||||
def make_iq_method_call(self, pto, pmethod, params):
|
||||
iq = self.xmpp.makeIqSet()
|
||||
iq.attrib['to'] = pto
|
||||
iq.attrib['from'] = self.xmpp.boundjid.full
|
||||
iq.enable('rpc_query')
|
||||
iq['rpc_query']['method_call']['method_name'] = pmethod
|
||||
iq['rpc_query']['method_call']['params'] = params
|
||||
return iq;
|
||||
|
||||
def make_iq_method_response(self, pid, pto, params):
|
||||
iq = self.xmpp.makeIqResult(pid)
|
||||
iq.attrib['to'] = pto
|
||||
iq.attrib['from'] = self.xmpp.boundjid.full
|
||||
iq.enable('rpc_query')
|
||||
iq['rpc_query']['method_response']['params'] = params
|
||||
return iq
|
||||
|
||||
def make_iq_method_response_fault(self, pid, pto, params):
|
||||
iq = self.xmpp.makeIqResult(pid)
|
||||
iq.attrib['to'] = pto
|
||||
iq.attrib['from'] = self.xmpp.boundjid.full
|
||||
iq.enable('rpc_query')
|
||||
iq['rpc_query']['method_response']['params'] = None
|
||||
iq['rpc_query']['method_response']['fault'] = params
|
||||
return iq
|
||||
|
||||
# def make_iq_method_error(self, pto, pid, pmethod, params, code, type, condition):
|
||||
# iq = self.xmpp.makeIqError(pid)
|
||||
# iq.attrib['to'] = pto
|
||||
# iq.attrib['from'] = self.xmpp.boundjid.full
|
||||
# iq['error']['code'] = code
|
||||
# iq['error']['type'] = type
|
||||
# iq['error']['condition'] = condition
|
||||
# iq['rpc_query']['method_call']['method_name'] = pmethod
|
||||
# iq['rpc_query']['method_call']['params'] = params
|
||||
# return iq
|
||||
|
||||
def _item_not_found(self, iq):
|
||||
payload = iq.get_payload()
|
||||
iq.reply().error().set_payload(payload);
|
||||
iq['error']['code'] = '404'
|
||||
iq['error']['type'] = 'cancel'
|
||||
iq['error']['condition'] = 'item-not-found'
|
||||
return iq
|
||||
|
||||
def _undefined_condition(self, iq):
|
||||
payload = iq.get_payload()
|
||||
iq.reply().error().set_payload(payload)
|
||||
iq['error']['code'] = '500'
|
||||
iq['error']['type'] = 'cancel'
|
||||
iq['error']['condition'] = 'undefined-condition'
|
||||
return iq
|
||||
|
||||
def _forbidden(self, iq):
|
||||
payload = iq.get_payload()
|
||||
iq.reply().error().set_payload(payload)
|
||||
iq['error']['code'] = '403'
|
||||
iq['error']['type'] = 'auth'
|
||||
iq['error']['condition'] = 'forbidden'
|
||||
return iq
|
||||
|
||||
def _recipient_unvailable(self, iq):
|
||||
payload = iq.get_payload()
|
||||
iq.reply().error().set_payload(payload)
|
||||
iq['error']['code'] = '404'
|
||||
iq['error']['type'] = 'wait'
|
||||
iq['error']['condition'] = 'recipient-unavailable'
|
||||
return iq
|
||||
|
||||
def _handle_method_call(self, iq):
|
||||
type = iq['type']
|
||||
if type == 'set':
|
||||
log.debug("Incoming Jabber-RPC call from %s", iq['from'])
|
||||
self.xmpp.event('jabber_rpc_method_call', iq)
|
||||
else:
|
||||
if type == 'error' and ['rpc_query'] is None:
|
||||
self.handle_error(iq)
|
||||
else:
|
||||
log.debug("Incoming Jabber-RPC error from %s", iq['from'])
|
||||
self.xmpp.event('jabber_rpc_error', iq)
|
||||
|
||||
def _handle_method_response(self, iq):
|
||||
if iq['rpc_query']['method_response']['fault'] is not None:
|
||||
log.debug("Incoming Jabber-RPC fault from %s", iq['from'])
|
||||
#self._on_jabber_rpc_method_fault(iq)
|
||||
self.xmpp.event('jabber_rpc_method_fault', iq)
|
||||
else:
|
||||
log.debug("Incoming Jabber-RPC response from %s", iq['from'])
|
||||
self.xmpp.event('jabber_rpc_method_response', iq)
|
||||
|
||||
def _handle_error(self, iq):
|
||||
print("['XEP-0009']._handle_error -> ERROR! Iq is '%s'" % iq)
|
||||
print("#######################")
|
||||
print("### NOT IMPLEMENTED ###")
|
||||
print("#######################")
|
||||
|
||||
def _on_jabber_rpc_method_call(self, iq, forwarded=False):
|
||||
"""
|
||||
A default handler for Jabber-RPC method call. If another
|
||||
handler is registered, this one will defer and not run.
|
||||
|
||||
If this handler is called by your own custom handler with
|
||||
forwarded set to True, then it will run as normal.
|
||||
"""
|
||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_call') > 1:
|
||||
return
|
||||
# Reply with error by default
|
||||
error = self.client.plugin['xep_0009']._item_not_found(iq)
|
||||
error.send()
|
||||
|
||||
def _on_jabber_rpc_method_response(self, iq, forwarded=False):
|
||||
"""
|
||||
A default handler for Jabber-RPC method response. If another
|
||||
handler is registered, this one will defer and not run.
|
||||
|
||||
If this handler is called by your own custom handler with
|
||||
forwarded set to True, then it will run as normal.
|
||||
"""
|
||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_response') > 1:
|
||||
return
|
||||
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
|
||||
error.send()
|
||||
|
||||
def _on_jabber_rpc_method_fault(self, iq, forwarded=False):
|
||||
"""
|
||||
A default handler for Jabber-RPC fault response. If another
|
||||
handler is registered, this one will defer and not run.
|
||||
|
||||
If this handler is called by your own custom handler with
|
||||
forwarded set to True, then it will run as normal.
|
||||
"""
|
||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_method_fault') > 1:
|
||||
return
|
||||
error = self.client.plugin['xep_0009']._recpient_unavailable(iq)
|
||||
error.send()
|
||||
|
||||
def _on_jabber_rpc_error(self, iq, forwarded=False):
|
||||
"""
|
||||
A default handler for Jabber-RPC error response. If another
|
||||
handler is registered, this one will defer and not run.
|
||||
|
||||
If this handler is called by your own custom handler with
|
||||
forwarded set to True, then it will run as normal.
|
||||
"""
|
||||
if not forwarded and self.xmpp.event_handled('jabber_rpc_error') > 1:
|
||||
return
|
||||
error = self.client.plugin['xep_0009']._recpient_unavailable(iq, iq.get_payload())
|
||||
error.send()
|
||||
|
||||
def _send_fault(self, iq, fault_xml): #
|
||||
fault = self.make_iq_method_response_fault(iq['id'], iq['from'], fault_xml)
|
||||
fault.send()
|
||||
|
||||
def _send_error(self, iq):
|
||||
print("['XEP-0009']._send_error -> ERROR! Iq is '%s'" % iq)
|
||||
print("#######################")
|
||||
print("### NOT IMPLEMENTED ###")
|
||||
print("#######################")
|
||||
|
||||
def _extract_method(self, stanza):
|
||||
xml = ET.fromstring("%s" % stanza)
|
||||
return xml.find("./methodCall/methodName").text
|
||||
|
||||
@@ -1,156 +1,156 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from slixmpp.plugins import BasePlugin, register_plugin
|
||||
from slixmpp import Iq
|
||||
from slixmpp.exceptions import XMPPError
|
||||
from slixmpp.xmlstream import JID, register_stanza_plugin
|
||||
from slixmpp.xmlstream.handler import Callback
|
||||
from slixmpp.xmlstream.matcher import StanzaPath
|
||||
from slixmpp.plugins.xep_0012 import stanza, LastActivity
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XEP_0012(BasePlugin):
|
||||
|
||||
"""
|
||||
XEP-0012 Last Activity
|
||||
"""
|
||||
|
||||
name = 'xep_0012'
|
||||
description = 'XEP-0012: Last Activity'
|
||||
dependencies = set(['xep_0030'])
|
||||
stanza = stanza
|
||||
|
||||
def plugin_init(self):
|
||||
register_stanza_plugin(Iq, LastActivity)
|
||||
|
||||
self._last_activities = {}
|
||||
|
||||
self.xmpp.register_handler(
|
||||
Callback('Last Activity',
|
||||
StanzaPath('iq@type=get/last_activity'),
|
||||
self._handle_get_last_activity))
|
||||
|
||||
self.api.register(self._default_get_last_activity,
|
||||
'get_last_activity',
|
||||
default=True)
|
||||
self.api.register(self._default_set_last_activity,
|
||||
'set_last_activity',
|
||||
default=True)
|
||||
self.api.register(self._default_del_last_activity,
|
||||
'del_last_activity',
|
||||
default=True)
|
||||
|
||||
def plugin_end(self):
|
||||
self.xmpp.remove_handler('Last Activity')
|
||||
self.xmpp['xep_0030'].del_feature(feature='jabber:iq:last')
|
||||
|
||||
def session_bind(self, jid):
|
||||
self.xmpp['xep_0030'].add_feature('jabber:iq:last')
|
||||
|
||||
def begin_idle(self, jid=None, status=None):
|
||||
self.set_last_activity(jid, 0, status)
|
||||
|
||||
def end_idle(self, jid=None):
|
||||
self.del_last_activity(jid)
|
||||
|
||||
def start_uptime(self, status=None):
|
||||
self.set_last_activity(jid, 0, status)
|
||||
|
||||
def set_last_activity(self, jid=None, seconds=None, status=None):
|
||||
self.api['set_last_activity'](jid, args={
|
||||
'seconds': seconds,
|
||||
'status': status})
|
||||
|
||||
def del_last_activity(self, jid):
|
||||
self.api['del_last_activity'](jid)
|
||||
|
||||
def get_last_activity(self, jid, local=False, ifrom=None, timeout=None,
|
||||
callback=None, timeout_callback=None):
|
||||
if jid is not None and not isinstance(jid, JID):
|
||||
jid = JID(jid)
|
||||
|
||||
if self.xmpp.is_component:
|
||||
if jid.domain == self.xmpp.boundjid.domain:
|
||||
local = True
|
||||
else:
|
||||
if str(jid) == str(self.xmpp.boundjid):
|
||||
local = True
|
||||
jid = jid.full
|
||||
|
||||
if local or jid in (None, ''):
|
||||
log.debug("Looking up local last activity data for %s", jid)
|
||||
return self.api['get_last_activity'](jid, None, ifrom, None)
|
||||
|
||||
iq = self.xmpp.Iq()
|
||||
iq['from'] = ifrom
|
||||
iq['to'] = jid
|
||||
iq['type'] = 'get'
|
||||
iq.enable('last_activity')
|
||||
return iq.send(timeout=timeout, callback=callback,
|
||||
timeout_callback=timeout_callback)
|
||||
|
||||
def _handle_get_last_activity(self, iq):
|
||||
log.debug("Received last activity query from " + \
|
||||
"<%s> to <%s>.", iq['from'], iq['to'])
|
||||
reply = self.api['get_last_activity'](iq['to'], None, iq['from'], iq)
|
||||
reply.send()
|
||||
|
||||
# =================================================================
|
||||
# Default in-memory implementations for storing last activity data.
|
||||
# =================================================================
|
||||
|
||||
def _default_set_last_activity(self, jid, node, ifrom, data):
|
||||
seconds = data.get('seconds', None)
|
||||
if seconds is None:
|
||||
seconds = 0
|
||||
|
||||
status = data.get('status', None)
|
||||
if status is None:
|
||||
status = ''
|
||||
|
||||
self._last_activities[jid] = {
|
||||
'seconds': datetime.now() - timedelta(seconds=seconds),
|
||||
'status': status}
|
||||
|
||||
def _default_del_last_activity(self, jid, node, ifrom, data):
|
||||
if jid in self._last_activities:
|
||||
del self._last_activities[jid]
|
||||
|
||||
def _default_get_last_activity(self, jid, node, ifrom, iq):
|
||||
if not isinstance(iq, Iq):
|
||||
reply = self.xmpp.Iq()
|
||||
else:
|
||||
iq.reply()
|
||||
reply = iq
|
||||
|
||||
if jid not in self._last_activities:
|
||||
raise XMPPError('service-unavailable')
|
||||
|
||||
bare = JID(jid).bare
|
||||
|
||||
if bare != self.xmpp.boundjid.bare:
|
||||
if bare in self.xmpp.roster[jid]:
|
||||
sub = self.xmpp.roster[jid][bare]['subscription']
|
||||
if sub not in ('from', 'both'):
|
||||
raise XMPPError('forbidden')
|
||||
|
||||
td = datetime.now() - self._last_activities[jid]['seconds']
|
||||
seconds = td.seconds + td.days * 24 * 3600
|
||||
status = self._last_activities[jid]['status']
|
||||
|
||||
reply['last_activity']['seconds'] = seconds
|
||||
reply['last_activity']['status'] = status
|
||||
|
||||
return reply
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from slixmpp.plugins import BasePlugin, register_plugin
|
||||
from slixmpp import Iq
|
||||
from slixmpp.exceptions import XMPPError
|
||||
from slixmpp.xmlstream import JID, register_stanza_plugin
|
||||
from slixmpp.xmlstream.handler import Callback
|
||||
from slixmpp.xmlstream.matcher import StanzaPath
|
||||
from slixmpp.plugins.xep_0012 import stanza, LastActivity
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XEP_0012(BasePlugin):
|
||||
|
||||
"""
|
||||
XEP-0012 Last Activity
|
||||
"""
|
||||
|
||||
name = 'xep_0012'
|
||||
description = 'XEP-0012: Last Activity'
|
||||
dependencies = set(['xep_0030'])
|
||||
stanza = stanza
|
||||
|
||||
def plugin_init(self):
|
||||
register_stanza_plugin(Iq, LastActivity)
|
||||
|
||||
self._last_activities = {}
|
||||
|
||||
self.xmpp.register_handler(
|
||||
Callback('Last Activity',
|
||||
StanzaPath('iq@type=get/last_activity'),
|
||||
self._handle_get_last_activity))
|
||||
|
||||
self.api.register(self._default_get_last_activity,
|
||||
'get_last_activity',
|
||||
default=True)
|
||||
self.api.register(self._default_set_last_activity,
|
||||
'set_last_activity',
|
||||
default=True)
|
||||
self.api.register(self._default_del_last_activity,
|
||||
'del_last_activity',
|
||||
default=True)
|
||||
|
||||
def plugin_end(self):
|
||||
self.xmpp.remove_handler('Last Activity')
|
||||
self.xmpp['xep_0030'].del_feature(feature='jabber:iq:last')
|
||||
|
||||
def session_bind(self, jid):
|
||||
self.xmpp['xep_0030'].add_feature('jabber:iq:last')
|
||||
|
||||
def begin_idle(self, jid=None, status=None):
|
||||
self.set_last_activity(jid, 0, status)
|
||||
|
||||
def end_idle(self, jid=None):
|
||||
self.del_last_activity(jid)
|
||||
|
||||
def start_uptime(self, status=None):
|
||||
self.set_last_activity(jid, 0, status)
|
||||
|
||||
def set_last_activity(self, jid=None, seconds=None, status=None):
|
||||
self.api['set_last_activity'](jid, args={
|
||||
'seconds': seconds,
|
||||
'status': status})
|
||||
|
||||
def del_last_activity(self, jid):
|
||||
self.api['del_last_activity'](jid)
|
||||
|
||||
def get_last_activity(self, jid, local=False, ifrom=None, timeout=None,
|
||||
callback=None, timeout_callback=None):
|
||||
if jid is not None and not isinstance(jid, JID):
|
||||
jid = JID(jid)
|
||||
|
||||
if self.xmpp.is_component:
|
||||
if jid.domain == self.xmpp.boundjid.domain:
|
||||
local = True
|
||||
else:
|
||||
if str(jid) == str(self.xmpp.boundjid):
|
||||
local = True
|
||||
jid = jid.full
|
||||
|
||||
if local or jid in (None, ''):
|
||||
log.debug("Looking up local last activity data for %s", jid)
|
||||
return self.api['get_last_activity'](jid, None, ifrom, None)
|
||||
|
||||
iq = self.xmpp.Iq()
|
||||
iq['from'] = ifrom
|
||||
iq['to'] = jid
|
||||
iq['type'] = 'get'
|
||||
iq.enable('last_activity')
|
||||
return iq.send(timeout=timeout, callback=callback,
|
||||
timeout_callback=timeout_callback)
|
||||
|
||||
def _handle_get_last_activity(self, iq):
|
||||
log.debug("Received last activity query from " + \
|
||||
"<%s> to <%s>.", iq['from'], iq['to'])
|
||||
reply = self.api['get_last_activity'](iq['to'], None, iq['from'], iq)
|
||||
reply.send()
|
||||
|
||||
# =================================================================
|
||||
# Default in-memory implementations for storing last activity data.
|
||||
# =================================================================
|
||||
|
||||
def _default_set_last_activity(self, jid, node, ifrom, data):
|
||||
seconds = data.get('seconds', None)
|
||||
if seconds is None:
|
||||
seconds = 0
|
||||
|
||||
status = data.get('status', None)
|
||||
if status is None:
|
||||
status = ''
|
||||
|
||||
self._last_activities[jid] = {
|
||||
'seconds': datetime.now() - timedelta(seconds=seconds),
|
||||
'status': status}
|
||||
|
||||
def _default_del_last_activity(self, jid, node, ifrom, data):
|
||||
if jid in self._last_activities:
|
||||
del self._last_activities[jid]
|
||||
|
||||
def _default_get_last_activity(self, jid, node, ifrom, iq):
|
||||
if not isinstance(iq, Iq):
|
||||
reply = self.xmpp.Iq()
|
||||
else:
|
||||
iq.reply()
|
||||
reply = iq
|
||||
|
||||
if jid not in self._last_activities:
|
||||
raise XMPPError('service-unavailable')
|
||||
|
||||
bare = JID(jid).bare
|
||||
|
||||
if bare != self.xmpp.boundjid.bare:
|
||||
if bare in self.xmpp.roster[jid]:
|
||||
sub = self.xmpp.roster[jid][bare]['subscription']
|
||||
if sub not in ('from', 'both'):
|
||||
raise XMPPError('forbidden')
|
||||
|
||||
td = datetime.now() - self._last_activities[jid]['seconds']
|
||||
seconds = td.seconds + td.days * 24 * 3600
|
||||
status = self._last_activities[jid]['status']
|
||||
|
||||
reply['last_activity']['seconds'] = seconds
|
||||
reply['last_activity']['status'] = status
|
||||
|
||||
return reply
|
||||
|
||||
@@ -307,7 +307,7 @@ class XEP_0045(BasePlugin):
|
||||
if role not in ('moderator', 'participant', 'visitor', 'none'):
|
||||
raise TypeError
|
||||
query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
|
||||
item = ET.Element('item', {'role':role, 'nick':nick})
|
||||
item = ET.Element('item', {'role':role, 'nick':nick})
|
||||
query.append(item)
|
||||
iq = self.xmpp.makeIqSet(query)
|
||||
iq['to'] = room
|
||||
|
||||
@@ -206,7 +206,7 @@ class XEP_0065(base_plugin):
|
||||
# Though this should not be neccessary remove the closed session anyway
|
||||
with self._sessions_lock:
|
||||
if sid in self._sessions:
|
||||
log.warn(('SOCKS5 session with sid = "%s" was not ' +
|
||||
log.warn(('SOCKS5 session with sid = "%s" was not ' +
|
||||
'removed from _sessions by sock.close()') % sid)
|
||||
del self._sessions[sid]
|
||||
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.stanza import Error
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.plugins import BasePlugin
|
||||
from slixmpp.plugins.xep_0086 import stanza, LegacyError
|
||||
|
||||
|
||||
class XEP_0086(BasePlugin):
|
||||
|
||||
"""
|
||||
XEP-0086: Error Condition Mappings
|
||||
|
||||
Older XMPP implementations used code based error messages, similar
|
||||
to HTTP response codes. Since then, error condition elements have
|
||||
been introduced. XEP-0086 provides a mapping between the new
|
||||
condition elements and a combination of error types and the older
|
||||
response codes.
|
||||
|
||||
Also see <http://xmpp.org/extensions/xep-0086.html>.
|
||||
|
||||
Configuration Values:
|
||||
override -- Indicates if applying legacy error codes should
|
||||
be done automatically. Defaults to True.
|
||||
If False, then inserting legacy error codes can
|
||||
be done using:
|
||||
iq['error']['legacy']['condition'] = ...
|
||||
"""
|
||||
|
||||
name = 'xep_0086'
|
||||
description = 'XEP-0086: Error Condition Mappings'
|
||||
dependencies = set()
|
||||
stanza = stanza
|
||||
default_config = {
|
||||
'override': True
|
||||
}
|
||||
|
||||
def plugin_init(self):
|
||||
register_stanza_plugin(Error, LegacyError,
|
||||
overrides=self.override)
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from slixmpp.stanza import Error
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.plugins import BasePlugin
|
||||
from slixmpp.plugins.xep_0086 import stanza, LegacyError
|
||||
|
||||
|
||||
class XEP_0086(BasePlugin):
|
||||
|
||||
"""
|
||||
XEP-0086: Error Condition Mappings
|
||||
|
||||
Older XMPP implementations used code based error messages, similar
|
||||
to HTTP response codes. Since then, error condition elements have
|
||||
been introduced. XEP-0086 provides a mapping between the new
|
||||
condition elements and a combination of error types and the older
|
||||
response codes.
|
||||
|
||||
Also see <http://xmpp.org/extensions/xep-0086.html>.
|
||||
|
||||
Configuration Values:
|
||||
override -- Indicates if applying legacy error codes should
|
||||
be done automatically. Defaults to True.
|
||||
If False, then inserting legacy error codes can
|
||||
be done using:
|
||||
iq['error']['legacy']['condition'] = ...
|
||||
"""
|
||||
|
||||
name = 'xep_0086'
|
||||
description = 'XEP-0086: Error Condition Mappings'
|
||||
dependencies = set()
|
||||
stanza = stanza
|
||||
default_config = {
|
||||
'override': True
|
||||
}
|
||||
|
||||
def plugin_init(self):
|
||||
register_stanza_plugin(Error, LegacyError,
|
||||
overrides=self.override)
|
||||
|
||||
@@ -129,7 +129,7 @@ class XEP_0153(BasePlugin):
|
||||
# Don't process vCard avatars for MUC occupants
|
||||
# since they all share the same bare JID.
|
||||
return
|
||||
except: pass
|
||||
except: pass
|
||||
|
||||
if not pres.match('presence/vcard_temp_update'):
|
||||
self.api['set_hash'](pres['from'], args=None)
|
||||
|
||||
@@ -1,98 +1,98 @@
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from slixmpp.stanza.iq import Iq
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.xmlstream.handler import Callback
|
||||
from slixmpp.xmlstream.matcher import StanzaPath
|
||||
from slixmpp.plugins import BasePlugin
|
||||
from slixmpp.plugins import xep_0082
|
||||
from slixmpp.plugins.xep_0202 import stanza
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XEP_0202(BasePlugin):
|
||||
|
||||
"""
|
||||
XEP-0202: Entity Time
|
||||
"""
|
||||
|
||||
name = 'xep_0202'
|
||||
description = 'XEP-0202: Entity Time'
|
||||
dependencies = set(['xep_0030', 'xep_0082'])
|
||||
stanza = stanza
|
||||
default_config = {
|
||||
#: As a default, respond to time requests with the
|
||||
#: local time returned by XEP-0082. However, a
|
||||
#: custom function can be supplied which accepts
|
||||
#: the JID of the entity to query for the time.
|
||||
'local_time': None,
|
||||
'tz_offset': 0
|
||||
}
|
||||
|
||||
def plugin_init(self):
|
||||
"""Start the XEP-0203 plugin."""
|
||||
|
||||
if not self.local_time:
|
||||
def default_local_time(jid):
|
||||
return xep_0082.datetime(offset=self.tz_offset)
|
||||
|
||||
self.local_time = default_local_time
|
||||
|
||||
self.xmpp.register_handler(
|
||||
Callback('Entity Time',
|
||||
StanzaPath('iq/entity_time'),
|
||||
self._handle_time_request))
|
||||
register_stanza_plugin(Iq, stanza.EntityTime)
|
||||
|
||||
def plugin_end(self):
|
||||
self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:time')
|
||||
self.xmpp.remove_handler('Entity Time')
|
||||
|
||||
def session_bind(self, jid):
|
||||
self.xmpp['xep_0030'].add_feature('urn:xmpp:time')
|
||||
|
||||
def _handle_time_request(self, iq):
|
||||
"""
|
||||
Respond to a request for the local time.
|
||||
|
||||
The time is taken from self.local_time(), which may be replaced
|
||||
during plugin configuration with a function that maps JIDs to
|
||||
times.
|
||||
|
||||
Arguments:
|
||||
iq -- The Iq time request stanza.
|
||||
"""
|
||||
iq.reply()
|
||||
iq['entity_time']['time'] = self.local_time(iq['to'])
|
||||
iq.send()
|
||||
|
||||
def get_entity_time(self, to, ifrom=None, **iqargs):
|
||||
"""
|
||||
Request the time from another entity.
|
||||
|
||||
Arguments:
|
||||
to -- JID of the entity to query.
|
||||
ifrom -- Specifiy the sender's JID.
|
||||
block -- If true, block and wait for the stanzas' reply.
|
||||
timeout -- The time in seconds to block while waiting for
|
||||
a reply. If None, then wait indefinitely.
|
||||
callback -- Optional callback to execute when a reply is
|
||||
received instead of blocking and waiting for
|
||||
the reply.
|
||||
"""
|
||||
iq = self.xmpp.Iq()
|
||||
iq['type'] = 'get'
|
||||
iq['to'] = to
|
||||
iq['from'] = ifrom
|
||||
iq.enable('entity_time')
|
||||
return iq.send(**iqargs)
|
||||
"""
|
||||
Slixmpp: The Slick XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of Slixmpp.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from slixmpp.stanza.iq import Iq
|
||||
from slixmpp.xmlstream import register_stanza_plugin
|
||||
from slixmpp.xmlstream.handler import Callback
|
||||
from slixmpp.xmlstream.matcher import StanzaPath
|
||||
from slixmpp.plugins import BasePlugin
|
||||
from slixmpp.plugins import xep_0082
|
||||
from slixmpp.plugins.xep_0202 import stanza
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XEP_0202(BasePlugin):
|
||||
|
||||
"""
|
||||
XEP-0202: Entity Time
|
||||
"""
|
||||
|
||||
name = 'xep_0202'
|
||||
description = 'XEP-0202: Entity Time'
|
||||
dependencies = set(['xep_0030', 'xep_0082'])
|
||||
stanza = stanza
|
||||
default_config = {
|
||||
#: As a default, respond to time requests with the
|
||||
#: local time returned by XEP-0082. However, a
|
||||
#: custom function can be supplied which accepts
|
||||
#: the JID of the entity to query for the time.
|
||||
'local_time': None,
|
||||
'tz_offset': 0
|
||||
}
|
||||
|
||||
def plugin_init(self):
|
||||
"""Start the XEP-0203 plugin."""
|
||||
|
||||
if not self.local_time:
|
||||
def default_local_time(jid):
|
||||
return xep_0082.datetime(offset=self.tz_offset)
|
||||
|
||||
self.local_time = default_local_time
|
||||
|
||||
self.xmpp.register_handler(
|
||||
Callback('Entity Time',
|
||||
StanzaPath('iq/entity_time'),
|
||||
self._handle_time_request))
|
||||
register_stanza_plugin(Iq, stanza.EntityTime)
|
||||
|
||||
def plugin_end(self):
|
||||
self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:time')
|
||||
self.xmpp.remove_handler('Entity Time')
|
||||
|
||||
def session_bind(self, jid):
|
||||
self.xmpp['xep_0030'].add_feature('urn:xmpp:time')
|
||||
|
||||
def _handle_time_request(self, iq):
|
||||
"""
|
||||
Respond to a request for the local time.
|
||||
|
||||
The time is taken from self.local_time(), which may be replaced
|
||||
during plugin configuration with a function that maps JIDs to
|
||||
times.
|
||||
|
||||
Arguments:
|
||||
iq -- The Iq time request stanza.
|
||||
"""
|
||||
iq.reply()
|
||||
iq['entity_time']['time'] = self.local_time(iq['to'])
|
||||
iq.send()
|
||||
|
||||
def get_entity_time(self, to, ifrom=None, **iqargs):
|
||||
"""
|
||||
Request the time from another entity.
|
||||
|
||||
Arguments:
|
||||
to -- JID of the entity to query.
|
||||
ifrom -- Specifiy the sender's JID.
|
||||
block -- If true, block and wait for the stanzas' reply.
|
||||
timeout -- The time in seconds to block while waiting for
|
||||
a reply. If None, then wait indefinitely.
|
||||
callback -- Optional callback to execute when a reply is
|
||||
received instead of blocking and waiting for
|
||||
the reply.
|
||||
"""
|
||||
iq = self.xmpp.Iq()
|
||||
iq['type'] = 'get'
|
||||
iq['to'] = to
|
||||
iq['from'] = ifrom
|
||||
iq.enable('entity_time')
|
||||
return iq.send(**iqargs)
|
||||
|
||||
@@ -13,9 +13,9 @@ import logging
|
||||
|
||||
class Device(object):
|
||||
"""
|
||||
Example implementation of a device readout object.
|
||||
Example implementation of a device readout object.
|
||||
Is registered in the XEP_0323.register_node call
|
||||
The device object may be any custom implementation to support
|
||||
The device object may be any custom implementation to support
|
||||
specific devices, but it must implement the functions:
|
||||
has_field
|
||||
request_fields
|
||||
@@ -38,19 +38,19 @@ class Device(object):
|
||||
Returns true if the supplied field name exists in this device.
|
||||
|
||||
Arguments:
|
||||
field -- The field name
|
||||
field -- The field name
|
||||
"""
|
||||
if field in self.fields.keys():
|
||||
return True;
|
||||
return False;
|
||||
|
||||
|
||||
def refresh(self, fields):
|
||||
"""
|
||||
override method to do the refresh work
|
||||
refresh values from hardware or other
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def request_fields(self, fields, flags, session, callback):
|
||||
"""
|
||||
@@ -65,7 +65,7 @@ class Device(object):
|
||||
Formatted as a dictionary like { "flag name": "flag value" ... }
|
||||
session -- Session id, only used in the callback as identifier
|
||||
callback -- Callback function to call when data is available.
|
||||
|
||||
|
||||
The callback function must support the following arguments:
|
||||
|
||||
session -- Session id, as supplied in the request_fields call
|
||||
@@ -73,11 +73,11 @@ class Device(object):
|
||||
result -- The current result status of the readout. Valid values are:
|
||||
"error" - Readout failed.
|
||||
"fields" - Contains readout data.
|
||||
"done" - Indicates that the readout is complete. May contain
|
||||
"done" - Indicates that the readout is complete. May contain
|
||||
readout data.
|
||||
timestamp_block -- [optional] Only applies when result != "error"
|
||||
timestamp_block -- [optional] Only applies when result != "error"
|
||||
The readout data. Structured as a dictionary:
|
||||
{
|
||||
{
|
||||
timestamp: timestamp for this datablock,
|
||||
fields: list of field dictionary (one per readout field).
|
||||
readout field dictionary format:
|
||||
@@ -89,10 +89,10 @@ class Device(object):
|
||||
dataType: The datatype of the field. Only applies to type enum.
|
||||
flags: [optional] data classifier flags for the field, e.g. momentary
|
||||
Formatted as a dictionary like { "flag name": "flag value" ... }
|
||||
}
|
||||
}
|
||||
}
|
||||
error_msg -- [optional] Only applies when result == "error".
|
||||
Error details when a request failed.
|
||||
Error details when a request failed.
|
||||
|
||||
"""
|
||||
logging.debug("request_fields called looking for fields %s",fields)
|
||||
@@ -125,11 +125,11 @@ class Device(object):
|
||||
field_block = [];
|
||||
for f in self.momentary_data:
|
||||
if f in fields:
|
||||
field_block.append({"name": f,
|
||||
"type": self.fields[f]["type"],
|
||||
field_block.append({"name": f,
|
||||
"type": self.fields[f]["type"],
|
||||
"unit": self.fields[f]["unit"],
|
||||
"dataType": self.fields[f]["dataType"],
|
||||
"value": self.momentary_data[f]["value"],
|
||||
"value": self.momentary_data[f]["value"],
|
||||
"flags": self.momentary_data[f]["flags"]});
|
||||
ts_block["timestamp"] = timestamp;
|
||||
ts_block["fields"] = field_block;
|
||||
@@ -142,25 +142,25 @@ class Device(object):
|
||||
|
||||
for ts in sorted(self.timestamp_data.keys()):
|
||||
tsdt = datetime.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%S")
|
||||
if not from_flag is None:
|
||||
if tsdt < from_flag:
|
||||
if not from_flag is None:
|
||||
if tsdt < from_flag:
|
||||
#print (str(tsdt) + " < " + str(from_flag))
|
||||
continue
|
||||
if not to_flag is None:
|
||||
if tsdt > to_flag:
|
||||
if not to_flag is None:
|
||||
if tsdt > to_flag:
|
||||
#print (str(tsdt) + " > " + str(to_flag))
|
||||
continue
|
||||
|
||||
|
||||
ts_block = {};
|
||||
field_block = [];
|
||||
|
||||
for f in self.timestamp_data[ts]:
|
||||
if f in fields:
|
||||
field_block.append({"name": f,
|
||||
"type": self.fields[f]["type"],
|
||||
field_block.append({"name": f,
|
||||
"type": self.fields[f]["type"],
|
||||
"unit": self.fields[f]["unit"],
|
||||
"dataType": self.fields[f]["dataType"],
|
||||
"value": self.timestamp_data[ts][f]["value"],
|
||||
"value": self.timestamp_data[ts][f]["value"],
|
||||
"flags": self.timestamp_data[ts][f]["flags"]});
|
||||
|
||||
ts_block["timestamp"] = ts;
|
||||
@@ -171,7 +171,7 @@ class Device(object):
|
||||
def _datetime_flag_parser(self, flags, flagname):
|
||||
if not flagname in flags:
|
||||
return None
|
||||
|
||||
|
||||
dt = None
|
||||
try:
|
||||
dt = datetime.datetime.strptime(flags[flagname], "%Y-%m-%dT%H:%M:%S")
|
||||
@@ -242,7 +242,7 @@ class Device(object):
|
||||
return False;
|
||||
if flags is None:
|
||||
flags = {};
|
||||
|
||||
|
||||
flags["momentary"] = "true"
|
||||
self.momentary_data[name] = {"value": value, "flags": flags};
|
||||
return True;
|
||||
|
||||
@@ -29,12 +29,12 @@ log = logging.getLogger(__name__)
|
||||
class XEP_0323(BasePlugin):
|
||||
|
||||
"""
|
||||
XEP-0323: IoT Sensor Data
|
||||
XEP-0323: IoT Sensor Data
|
||||
|
||||
|
||||
This XEP provides the underlying architecture, basic operations and data
|
||||
structures for sensor data communication over XMPP networks. It includes
|
||||
a hardware abstraction model, removing any technical detail implemented
|
||||
a hardware abstraction model, removing any technical detail implemented
|
||||
in underlying technologies.
|
||||
|
||||
Also see <http://xmpp.org/extensions/xep-0323.html>
|
||||
@@ -55,10 +55,10 @@ class XEP_0323(BasePlugin):
|
||||
Sensordata Event:Rejected -- Received a reject from sensor for a request
|
||||
Sensordata Event:Cancelled -- Received a cancel confirm from sensor
|
||||
Sensordata Event:Fields -- Received fields from sensor for a request
|
||||
This may be triggered multiple times since
|
||||
This may be triggered multiple times since
|
||||
the sensor can split up its response in
|
||||
multiple messages.
|
||||
Sensordata Event:Failure -- Received a failure indication from sensor
|
||||
Sensordata Event:Failure -- Received a failure indication from sensor
|
||||
for a request. Typically a comm timeout.
|
||||
|
||||
Attributes:
|
||||
@@ -69,7 +69,7 @@ class XEP_0323(BasePlugin):
|
||||
relevant to a request's session. This dictionary is used
|
||||
both by the client and sensor side. On client side, seqnr
|
||||
is used as key, while on sensor side, a session_id is used
|
||||
as key. This ensures that the two will not collide, so
|
||||
as key. This ensures that the two will not collide, so
|
||||
one instance can be both client and sensor.
|
||||
Sensor side
|
||||
-----------
|
||||
@@ -89,12 +89,12 @@ class XEP_0323(BasePlugin):
|
||||
|
||||
Sensor side
|
||||
-----------
|
||||
register_node -- Register a sensor as available from this XMPP
|
||||
register_node -- Register a sensor as available from this XMPP
|
||||
instance.
|
||||
|
||||
Client side
|
||||
-----------
|
||||
request_data -- Initiates a request for data from one or more
|
||||
request_data -- Initiates a request for data from one or more
|
||||
sensors. Non-blocking, a callback function will
|
||||
be called when data is available.
|
||||
|
||||
@@ -102,7 +102,7 @@ class XEP_0323(BasePlugin):
|
||||
|
||||
name = 'xep_0323'
|
||||
description = 'XEP-0323 Internet of Things - Sensor Data'
|
||||
dependencies = set(['xep_0030'])
|
||||
dependencies = set(['xep_0030'])
|
||||
stanza = stanza
|
||||
|
||||
|
||||
@@ -198,9 +198,9 @@ class XEP_0323(BasePlugin):
|
||||
def register_node(self, nodeId, device, commTimeout, sourceId=None, cacheType=None):
|
||||
"""
|
||||
Register a sensor/device as available for serving of data through this XMPP
|
||||
instance.
|
||||
instance.
|
||||
|
||||
The device object may by any custom implementation to support
|
||||
The device object may by any custom implementation to support
|
||||
specific devices, but it must implement the functions:
|
||||
has_field
|
||||
request_fields
|
||||
@@ -212,11 +212,11 @@ class XEP_0323(BasePlugin):
|
||||
commTimeout -- Time in seconds to wait between each callback from device during
|
||||
a data readout. Float.
|
||||
sourceId -- [optional] identifying the data source controlling the device
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
"""
|
||||
self.nodes[nodeId] = {"device": device,
|
||||
self.nodes[nodeId] = {"device": device,
|
||||
"commTimeout": commTimeout,
|
||||
"sourceId": sourceId,
|
||||
"sourceId": sourceId,
|
||||
"cacheType": cacheType};
|
||||
|
||||
def _set_authenticated(self, auth=''):
|
||||
@@ -228,9 +228,9 @@ class XEP_0323(BasePlugin):
|
||||
"""
|
||||
Event handler for reception of an Iq with req - this is a request.
|
||||
|
||||
Verifies that
|
||||
Verifies that
|
||||
- all the requested nodes are available
|
||||
- at least one of the requested fields is available from at least
|
||||
- at least one of the requested fields is available from at least
|
||||
one of the nodes
|
||||
|
||||
If the request passes verification, an accept response is sent, and
|
||||
@@ -331,12 +331,12 @@ class XEP_0323(BasePlugin):
|
||||
iq['type'] = 'error';
|
||||
iq['rejected']['seqnr'] = seqnr;
|
||||
iq['rejected']['error'] = error_msg;
|
||||
iq.send(block=False);
|
||||
iq.send(block=False);
|
||||
|
||||
def _threaded_node_request(self, session, process_fields, flags):
|
||||
"""
|
||||
"""
|
||||
Helper function to handle the device readouts in a separate thread.
|
||||
|
||||
|
||||
Arguments:
|
||||
session -- The request session id
|
||||
process_fields -- The fields to request from the devices
|
||||
@@ -344,7 +344,7 @@ class XEP_0323(BasePlugin):
|
||||
Formatted as a dictionary like { "flag name": "flag value" ... }
|
||||
"""
|
||||
for node in self.sessions[session]["node_list"]:
|
||||
self.sessions[session]["nodeDone"][node] = False;
|
||||
self.sessions[session]["nodeDone"][node] = False;
|
||||
|
||||
for node in self.sessions[session]["node_list"]:
|
||||
timer = TimerReset(self.nodes[node]['commTimeout'], self._event_comm_timeout, args=(session, node));
|
||||
@@ -354,11 +354,11 @@ class XEP_0323(BasePlugin):
|
||||
self.nodes[node]['device'].request_fields(process_fields, flags=flags, session=session, callback=self._device_field_request_callback);
|
||||
|
||||
def _event_comm_timeout(self, session, nodeId):
|
||||
"""
|
||||
"""
|
||||
Triggered if any of the readout operations timeout.
|
||||
Sends a failure message back to the client, stops communicating
|
||||
with the failing device.
|
||||
|
||||
|
||||
Arguments:
|
||||
session -- The request session id
|
||||
nodeId -- The id of the device which timed out
|
||||
@@ -366,7 +366,7 @@ class XEP_0323(BasePlugin):
|
||||
msg = self.xmpp.Message();
|
||||
msg['from'] = self.sessions[session]['to'];
|
||||
msg['to'] = self.sessions[session]['from'];
|
||||
msg['failure']['seqnr'] = self.sessions[session]['seqnr'];
|
||||
msg['failure']['seqnr'] = self.sessions[session]['seqnr'];
|
||||
msg['failure']['error']['text'] = "Timeout";
|
||||
msg['failure']['error']['nodeId'] = nodeId;
|
||||
msg['failure']['error']['timestamp'] = datetime.datetime.now().replace(microsecond=0).isoformat();
|
||||
@@ -403,9 +403,9 @@ class XEP_0323(BasePlugin):
|
||||
self._threaded_node_request(session, process_fields, req_flags);
|
||||
|
||||
def _all_nodes_done(self, session):
|
||||
"""
|
||||
"""
|
||||
Checks wheter all devices are done replying to the readout.
|
||||
|
||||
|
||||
Arguments:
|
||||
session -- The request session id
|
||||
"""
|
||||
@@ -415,22 +415,22 @@ class XEP_0323(BasePlugin):
|
||||
return True;
|
||||
|
||||
def _device_field_request_callback(self, session, nodeId, result, timestamp_block, error_msg=None):
|
||||
"""
|
||||
"""
|
||||
Callback function called by the devices when they have any additional data.
|
||||
Composes a message with the data and sends it back to the client, and resets
|
||||
Composes a message with the data and sends it back to the client, and resets
|
||||
the timeout timer for the device.
|
||||
|
||||
|
||||
Arguments:
|
||||
session -- The request session id
|
||||
nodeId -- The device id which initiated the callback
|
||||
result -- The current result status of the readout. Valid values are:
|
||||
"error" - Readout failed.
|
||||
"fields" - Contains readout data.
|
||||
"done" - Indicates that the readout is complete. May contain
|
||||
"done" - Indicates that the readout is complete. May contain
|
||||
readout data.
|
||||
timestamp_block -- [optional] Only applies when result != "error"
|
||||
timestamp_block -- [optional] Only applies when result != "error"
|
||||
The readout data. Structured as a dictionary:
|
||||
{
|
||||
{
|
||||
timestamp: timestamp for this datablock,
|
||||
fields: list of field dictionary (one per readout field).
|
||||
readout field dictionary format:
|
||||
@@ -442,7 +442,7 @@ class XEP_0323(BasePlugin):
|
||||
dataType: The datatype of the field. Only applies to type enum.
|
||||
flags: [optional] data classifier flags for the field, e.g. momentary
|
||||
Formatted as a dictionary like { "flag name": "flag value" ... }
|
||||
}
|
||||
}
|
||||
}
|
||||
error_msg -- [optional] Only applies when result == "error".
|
||||
Error details when a request failed.
|
||||
@@ -463,7 +463,7 @@ class XEP_0323(BasePlugin):
|
||||
msg['failure']['error']['timestamp'] = datetime.datetime.now().replace(microsecond=0).isoformat();
|
||||
|
||||
# Drop communication with this device and check if we are done
|
||||
self.sessions[session]["nodeDone"][nodeId] = True;
|
||||
self.sessions[session]["nodeDone"][nodeId] = True;
|
||||
if (self._all_nodes_done(session)):
|
||||
msg['failure']['done'] = 'true';
|
||||
# The session is complete, delete it
|
||||
@@ -481,11 +481,11 @@ class XEP_0323(BasePlugin):
|
||||
ts = node.add_timestamp(timestamp_block["timestamp"]);
|
||||
|
||||
for f in timestamp_block["fields"]:
|
||||
data = ts.add_data( typename=f['type'],
|
||||
name=f['name'],
|
||||
value=f['value'],
|
||||
unit=f['unit'],
|
||||
dataType=f['dataType'],
|
||||
data = ts.add_data( typename=f['type'],
|
||||
name=f['name'],
|
||||
value=f['value'],
|
||||
unit=f['unit'],
|
||||
dataType=f['dataType'],
|
||||
flags=f['flags']);
|
||||
|
||||
if result == "done":
|
||||
@@ -503,7 +503,7 @@ class XEP_0323(BasePlugin):
|
||||
msg.send();
|
||||
|
||||
def _handle_event_cancel(self, iq):
|
||||
""" Received Iq with cancel - this is a cancel request.
|
||||
""" Received Iq with cancel - this is a cancel request.
|
||||
Delete the session and confirm. """
|
||||
|
||||
seqnr = iq['cancel']['seqnr'];
|
||||
@@ -518,8 +518,8 @@ class XEP_0323(BasePlugin):
|
||||
iq.reply();
|
||||
iq['type'] = 'result';
|
||||
iq['cancelled']['seqnr'] = seqnr;
|
||||
iq.send(block=False);
|
||||
|
||||
iq.send(block=False);
|
||||
|
||||
# Delete session
|
||||
del self.sessions[s]
|
||||
return
|
||||
@@ -529,22 +529,22 @@ class XEP_0323(BasePlugin):
|
||||
iq['type'] = 'error';
|
||||
iq['rejected']['seqnr'] = seqnr;
|
||||
iq['rejected']['error'] = "Cancel request received, no matching request is active.";
|
||||
iq.send(block=False);
|
||||
iq.send(block=False);
|
||||
|
||||
# =================================================================
|
||||
# Client side (data retriever) API
|
||||
|
||||
def request_data(self, from_jid, to_jid, callback, nodeIds=None, fields=None, flags=None):
|
||||
"""
|
||||
"""
|
||||
Called on the client side to initiade a data readout.
|
||||
Composes a message with the request and sends it to the device(s).
|
||||
Does not block, the callback will be called when data is available.
|
||||
|
||||
|
||||
Arguments:
|
||||
from_jid -- The jid of the requester
|
||||
to_jid -- The jid of the device(s)
|
||||
callback -- The callback function to call when data is availble.
|
||||
|
||||
callback -- The callback function to call when data is availble.
|
||||
|
||||
The callback function must support the following arguments:
|
||||
|
||||
from_jid -- The jid of the responding device(s)
|
||||
@@ -565,7 +565,7 @@ class XEP_0323(BasePlugin):
|
||||
The timestamp of data in this callback. One callback will only
|
||||
contain data from one timestamp.
|
||||
fields -- [optional] Mandatory when result == "fields".
|
||||
List of field dictionaries representing the readout data.
|
||||
List of field dictionaries representing the readout data.
|
||||
Dictionary format:
|
||||
{
|
||||
typename: The field type (numeric, boolean, dateTime, timeSpan, string, enum)
|
||||
@@ -575,11 +575,11 @@ class XEP_0323(BasePlugin):
|
||||
dataType: The datatype of the field. Only applies to type enum.
|
||||
flags: [optional] data classifier flags for the field, e.g. momentary.
|
||||
Formatted as a dictionary like { "flag name": "flag value" ... }
|
||||
}
|
||||
}
|
||||
|
||||
error_msg -- [optional] Mandatory when result == "rejected" or "failure".
|
||||
Details about why the request is rejected or failed.
|
||||
"rejected" means that the request is stopped, but note that the
|
||||
Details about why the request is rejected or failed.
|
||||
"rejected" means that the request is stopped, but note that the
|
||||
request will continue even after a "failure". "failure" only means
|
||||
that communication was stopped to that specific device, other
|
||||
device(s) (if any) will continue their readout.
|
||||
@@ -610,17 +610,17 @@ class XEP_0323(BasePlugin):
|
||||
iq['req']._set_flags(flags);
|
||||
|
||||
self.sessions[seqnr] = {"from": iq['from'], "to": iq['to'], "seqnr": seqnr, "callback": callback};
|
||||
iq.send(block=False);
|
||||
iq.send(block=False);
|
||||
|
||||
return seqnr;
|
||||
|
||||
def cancel_request(self, session):
|
||||
"""
|
||||
"""
|
||||
Called on the client side to cancel a request for data readout.
|
||||
Composes a message with the cancellation and sends it to the device(s).
|
||||
Does not block, the callback will be called when cancellation is
|
||||
Does not block, the callback will be called when cancellation is
|
||||
confirmed.
|
||||
|
||||
|
||||
Arguments:
|
||||
session -- The session id of the request to cancel
|
||||
"""
|
||||
@@ -651,7 +651,7 @@ class XEP_0323(BasePlugin):
|
||||
callback(from_jid=iq['from'], result=result);
|
||||
|
||||
def _handle_event_rejected(self, iq):
|
||||
""" Received Iq with rejected - this is a reject.
|
||||
""" Received Iq with rejected - this is a reject.
|
||||
Delete the session. """
|
||||
seqnr = iq['rejected']['seqnr'];
|
||||
callback = self.sessions[seqnr]["callback"];
|
||||
@@ -660,9 +660,9 @@ class XEP_0323(BasePlugin):
|
||||
del self.sessions[seqnr];
|
||||
|
||||
def _handle_event_cancelled(self, iq):
|
||||
"""
|
||||
Received Iq with cancelled - this is a cancel confirm.
|
||||
Delete the session.
|
||||
"""
|
||||
Received Iq with cancelled - this is a cancel confirm.
|
||||
Delete the session.
|
||||
"""
|
||||
#print("Got cancelled")
|
||||
seqnr = iq['cancelled']['seqnr'];
|
||||
@@ -672,7 +672,7 @@ class XEP_0323(BasePlugin):
|
||||
del self.sessions[seqnr];
|
||||
|
||||
def _handle_event_fields(self, msg):
|
||||
"""
|
||||
"""
|
||||
Received Msg with fields - this is a data reponse to a request.
|
||||
If this is the last data block, issue a "done" callback.
|
||||
"""
|
||||
@@ -694,16 +694,16 @@ class XEP_0323(BasePlugin):
|
||||
fields.append(field_block);
|
||||
|
||||
callback(from_jid=msg['from'], result="fields", nodeId=node['nodeId'], timestamp=ts['value'], fields=fields);
|
||||
|
||||
|
||||
if msg['fields']['done'] == "true":
|
||||
callback(from_jid=msg['from'], result="done");
|
||||
# Session done
|
||||
del self.sessions[seqnr];
|
||||
|
||||
def _handle_event_failure(self, msg):
|
||||
"""
|
||||
"""
|
||||
Received Msg with failure - our request failed
|
||||
Delete the session.
|
||||
Delete the session.
|
||||
"""
|
||||
seqnr = msg['failure']['seqnr'];
|
||||
callback = self.sessions[seqnr]["callback"];
|
||||
@@ -713,11 +713,11 @@ class XEP_0323(BasePlugin):
|
||||
del self.sessions[seqnr];
|
||||
|
||||
def _handle_event_started(self, msg):
|
||||
"""
|
||||
Received Msg with started - our request was queued and is now started.
|
||||
"""
|
||||
Received Msg with started - our request was queued and is now started.
|
||||
"""
|
||||
seqnr = msg['started']['seqnr'];
|
||||
callback = self.sessions[seqnr]["callback"];
|
||||
callback(from_jid=msg['from'], result="started");
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -20,14 +20,14 @@ class Sensordata(ElementBase):
|
||||
interfaces = set(tuple())
|
||||
|
||||
class FieldTypes():
|
||||
"""
|
||||
"""
|
||||
All field types are optional booleans that default to False
|
||||
"""
|
||||
field_types = set([ 'momentary','peak','status','computed','identity','historicalSecond','historicalMinute','historicalHour', \
|
||||
'historicalDay','historicalWeek','historicalMonth','historicalQuarter','historicalYear','historicalOther'])
|
||||
|
||||
class FieldStatus():
|
||||
"""
|
||||
"""
|
||||
All field statuses are optional booleans that default to False
|
||||
"""
|
||||
field_status = set([ 'missing','automaticEstimate','manualEstimate','manualReadout','automaticReadout','timeOffset','warning','error', \
|
||||
@@ -41,7 +41,7 @@ class Request(ElementBase):
|
||||
interfaces.update(FieldTypes.field_types);
|
||||
_flags = set(['serviceToken','deviceToken','userToken','from','to','when','historical','all']);
|
||||
_flags.update(FieldTypes.field_types);
|
||||
|
||||
|
||||
def __init__(self, xml=None, parent=None):
|
||||
ElementBase.__init__(self, xml, parent);
|
||||
self._nodes = set()
|
||||
@@ -64,8 +64,8 @@ class Request(ElementBase):
|
||||
|
||||
def _get_flags(self):
|
||||
"""
|
||||
Helper function for getting of flags. Returns all flags in
|
||||
dictionary format: { "flag name": "flag value" ... }
|
||||
Helper function for getting of flags. Returns all flags in
|
||||
dictionary format: { "flag name": "flag value" ... }
|
||||
"""
|
||||
flags = {};
|
||||
for f in self._flags:
|
||||
@@ -75,10 +75,10 @@ class Request(ElementBase):
|
||||
|
||||
def _set_flags(self, flags):
|
||||
"""
|
||||
Helper function for setting of flags.
|
||||
Helper function for setting of flags.
|
||||
|
||||
Arguments:
|
||||
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
|
||||
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
|
||||
"""
|
||||
for f in self._flags:
|
||||
if flags is not None and f in flags:
|
||||
@@ -94,7 +94,7 @@ class Request(ElementBase):
|
||||
Arguments:
|
||||
nodeId -- The ID for the node.
|
||||
sourceId -- [optional] identifying the data source controlling the device
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
"""
|
||||
if nodeId not in self._nodes:
|
||||
self._nodes.add((nodeId))
|
||||
@@ -318,7 +318,7 @@ class Fields(ElementBase):
|
||||
Arguments:
|
||||
nodeId -- The ID for the node.
|
||||
sourceId -- [optional] identifying the data source controlling the device
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
"""
|
||||
if nodeId not in self._nodes:
|
||||
self._nodes.add((nodeId))
|
||||
@@ -411,7 +411,7 @@ class FieldsNode(ElementBase):
|
||||
|
||||
def add_timestamp(self, timestamp, substanzas=None):
|
||||
"""
|
||||
Add a new timestamp element.
|
||||
Add a new timestamp element.
|
||||
|
||||
Arguments:
|
||||
timestamp -- The timestamp in ISO format.
|
||||
@@ -485,7 +485,7 @@ class FieldsNode(ElementBase):
|
||||
self.iterables.remove(timestamp)
|
||||
|
||||
class Field(ElementBase):
|
||||
"""
|
||||
"""
|
||||
Field element in response Timestamp. This is a base class,
|
||||
all instances of fields added to Timestamp must be of types:
|
||||
DataNumeric
|
||||
@@ -494,7 +494,7 @@ class Field(ElementBase):
|
||||
DataDateTime
|
||||
DataTimeSpan
|
||||
DataEnum
|
||||
"""
|
||||
"""
|
||||
namespace = 'urn:xmpp:iot:sensordata'
|
||||
name = 'field'
|
||||
plugin_attrib = name
|
||||
@@ -523,8 +523,8 @@ class Field(ElementBase):
|
||||
|
||||
def _get_flags(self):
|
||||
"""
|
||||
Helper function for getting of flags. Returns all flags in
|
||||
dictionary format: { "flag name": "flag value" ... }
|
||||
Helper function for getting of flags. Returns all flags in
|
||||
dictionary format: { "flag name": "flag value" ... }
|
||||
"""
|
||||
flags = {};
|
||||
for f in self._flags:
|
||||
@@ -534,10 +534,10 @@ class Field(ElementBase):
|
||||
|
||||
def _set_flags(self, flags):
|
||||
"""
|
||||
Helper function for setting of flags.
|
||||
Helper function for setting of flags.
|
||||
|
||||
Arguments:
|
||||
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
|
||||
flags -- Flags in dictionary format: { "flag name": "flag value" ... }
|
||||
"""
|
||||
for f in self._flags:
|
||||
if flags is not None and f in flags:
|
||||
@@ -576,7 +576,7 @@ class Timestamp(ElementBase):
|
||||
|
||||
def add_data(self, typename, name, value, module=None, stringIds=None, unit=None, dataType=None, flags=None):
|
||||
"""
|
||||
Add a new data element.
|
||||
Add a new data element.
|
||||
|
||||
Arguments:
|
||||
typename -- The type of data element (numeric, string, boolean, dateTime, timeSpan or enum)
|
||||
@@ -661,9 +661,9 @@ class Timestamp(ElementBase):
|
||||
self.iterables.remove(data)
|
||||
|
||||
class DataNumeric(Field):
|
||||
"""
|
||||
Field data of type numeric.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
Field data of type numeric.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
namespace = 'urn:xmpp:iot:sensordata'
|
||||
name = 'numeric'
|
||||
@@ -672,11 +672,11 @@ class DataNumeric(Field):
|
||||
interfaces.update(Field.interfaces);
|
||||
|
||||
def _get_typename(self):
|
||||
return "numeric"
|
||||
return "numeric"
|
||||
|
||||
class DataString(Field):
|
||||
"""
|
||||
Field data of type string
|
||||
"""
|
||||
Field data of type string
|
||||
"""
|
||||
namespace = 'urn:xmpp:iot:sensordata'
|
||||
name = 'string'
|
||||
@@ -685,12 +685,12 @@ class DataString(Field):
|
||||
interfaces.update(Field.interfaces);
|
||||
|
||||
def _get_typename(self):
|
||||
return "string"
|
||||
return "string"
|
||||
|
||||
class DataBoolean(Field):
|
||||
"""
|
||||
"""
|
||||
Field data of type boolean.
|
||||
Note that the value is expressed as a string.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
namespace = 'urn:xmpp:iot:sensordata'
|
||||
name = 'boolean'
|
||||
@@ -699,12 +699,12 @@ class DataBoolean(Field):
|
||||
interfaces.update(Field.interfaces);
|
||||
|
||||
def _get_typename(self):
|
||||
return "boolean"
|
||||
return "boolean"
|
||||
|
||||
class DataDateTime(Field):
|
||||
"""
|
||||
"""
|
||||
Field data of type dateTime.
|
||||
Note that the value is expressed as a string.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
namespace = 'urn:xmpp:iot:sensordata'
|
||||
name = 'dateTime'
|
||||
@@ -713,12 +713,12 @@ class DataDateTime(Field):
|
||||
interfaces.update(Field.interfaces);
|
||||
|
||||
def _get_typename(self):
|
||||
return "dateTime"
|
||||
return "dateTime"
|
||||
|
||||
class DataTimeSpan(Field):
|
||||
"""
|
||||
"""
|
||||
Field data of type timeSpan.
|
||||
Note that the value is expressed as a string.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
namespace = 'urn:xmpp:iot:sensordata'
|
||||
name = 'timeSpan'
|
||||
@@ -727,12 +727,12 @@ class DataTimeSpan(Field):
|
||||
interfaces.update(Field.interfaces);
|
||||
|
||||
def _get_typename(self):
|
||||
return "timeSpan"
|
||||
return "timeSpan"
|
||||
|
||||
class DataEnum(Field):
|
||||
"""
|
||||
"""
|
||||
Field data of type enum.
|
||||
Note that the value is expressed as a string.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
namespace = 'urn:xmpp:iot:sensordata'
|
||||
name = 'enum'
|
||||
@@ -741,7 +741,7 @@ class DataEnum(Field):
|
||||
interfaces.update(Field.interfaces);
|
||||
|
||||
def _get_typename(self):
|
||||
return "enum"
|
||||
return "enum"
|
||||
|
||||
class Done(ElementBase):
|
||||
""" Done element used to signal that all data has been transferred """
|
||||
|
||||
@@ -26,16 +26,16 @@ log = logging.getLogger(__name__)
|
||||
class XEP_0325(BasePlugin):
|
||||
|
||||
"""
|
||||
XEP-0325: IoT Control
|
||||
XEP-0325: IoT Control
|
||||
|
||||
|
||||
Actuators are devices in sensor networks that can be controlled through
|
||||
the network and act with the outside world. In sensor networks and
|
||||
Internet of Things applications, actuators make it possible to automate
|
||||
real-world processes.
|
||||
This plugin implements a mechanism whereby actuators can be controlled
|
||||
in XMPP-based sensor networks, making it possible to integrate sensors
|
||||
and actuators of different brands, makes and models into larger
|
||||
Actuators are devices in sensor networks that can be controlled through
|
||||
the network and act with the outside world. In sensor networks and
|
||||
Internet of Things applications, actuators make it possible to automate
|
||||
real-world processes.
|
||||
This plugin implements a mechanism whereby actuators can be controlled
|
||||
in XMPP-based sensor networks, making it possible to integrate sensors
|
||||
and actuators of different brands, makes and models into larger
|
||||
Internet of Things applications.
|
||||
|
||||
Also see <http://xmpp.org/extensions/xep-0325.html>
|
||||
@@ -52,9 +52,9 @@ class XEP_0325(BasePlugin):
|
||||
|
||||
Client side
|
||||
-----------
|
||||
Control Event:SetResponse -- Received a response to a
|
||||
Control Event:SetResponse -- Received a response to a
|
||||
control request, type result
|
||||
Control Event:SetResponseError -- Received a response to a
|
||||
Control Event:SetResponseError -- Received a response to a
|
||||
control request, type error
|
||||
|
||||
Attributes:
|
||||
@@ -65,7 +65,7 @@ class XEP_0325(BasePlugin):
|
||||
relevant to a request's session. This dictionary is used
|
||||
both by the client and sensor side. On client side, seqnr
|
||||
is used as key, while on sensor side, a session_id is used
|
||||
as key. This ensures that the two will not collide, so
|
||||
as key. This ensures that the two will not collide, so
|
||||
one instance can be both client and sensor.
|
||||
Sensor side
|
||||
-----------
|
||||
@@ -85,15 +85,15 @@ class XEP_0325(BasePlugin):
|
||||
|
||||
Sensor side
|
||||
-----------
|
||||
register_node -- Register a sensor as available from this XMPP
|
||||
register_node -- Register a sensor as available from this XMPP
|
||||
instance.
|
||||
|
||||
Client side
|
||||
-----------
|
||||
set_request -- Initiates a control request to modify data in
|
||||
set_request -- Initiates a control request to modify data in
|
||||
sensor(s). Non-blocking, a callback function will
|
||||
be called when the sensor has responded.
|
||||
set_command -- Initiates a control command to modify data in
|
||||
set_command -- Initiates a control command to modify data in
|
||||
sensor(s). Non-blocking. The sensor(s) will not
|
||||
respond regardless of the result of the command,
|
||||
so no callback is made.
|
||||
@@ -102,7 +102,7 @@ class XEP_0325(BasePlugin):
|
||||
|
||||
name = 'xep_0325'
|
||||
description = 'XEP-0325 Internet of Things - Control'
|
||||
dependencies = set(['xep_0030'])
|
||||
dependencies = set(['xep_0030'])
|
||||
stanza = stanza
|
||||
|
||||
|
||||
@@ -170,10 +170,10 @@ class XEP_0325(BasePlugin):
|
||||
|
||||
def register_node(self, nodeId, device, commTimeout, sourceId=None, cacheType=None):
|
||||
"""
|
||||
Register a sensor/device as available for control requests/commands
|
||||
through this XMPP instance.
|
||||
Register a sensor/device as available for control requests/commands
|
||||
through this XMPP instance.
|
||||
|
||||
The device object may by any custom implementation to support
|
||||
The device object may by any custom implementation to support
|
||||
specific devices, but it must implement the functions:
|
||||
has_control_field
|
||||
set_control_fields
|
||||
@@ -185,11 +185,11 @@ class XEP_0325(BasePlugin):
|
||||
commTimeout -- Time in seconds to wait between each callback from device during
|
||||
a data readout. Float.
|
||||
sourceId -- [optional] identifying the data source controlling the device
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
"""
|
||||
self.nodes[nodeId] = {"device": device,
|
||||
self.nodes[nodeId] = {"device": device,
|
||||
"commTimeout": commTimeout,
|
||||
"sourceId": sourceId,
|
||||
"sourceId": sourceId,
|
||||
"cacheType": cacheType};
|
||||
|
||||
def _set_authenticated(self, auth=''):
|
||||
@@ -205,10 +205,10 @@ class XEP_0325(BasePlugin):
|
||||
|
||||
def _handle_set_req(self, iq):
|
||||
"""
|
||||
Event handler for reception of an Iq with set req - this is a
|
||||
Event handler for reception of an Iq with set req - this is a
|
||||
control request.
|
||||
|
||||
Verifies that
|
||||
Verifies that
|
||||
- all the requested nodes are available
|
||||
(if no nodes are specified in the request, assume all nodes)
|
||||
- all the control fields are available from all requested nodes
|
||||
@@ -216,7 +216,7 @@ class XEP_0325(BasePlugin):
|
||||
|
||||
If the request passes verification, the control request is passed
|
||||
to the devices (in a separate thread).
|
||||
If the verification fails, a setResponse with error indication
|
||||
If the verification fails, a setResponse with error indication
|
||||
is sent.
|
||||
"""
|
||||
|
||||
@@ -279,17 +279,17 @@ class XEP_0325(BasePlugin):
|
||||
if missing_node is not None:
|
||||
iq['setResponse'].add_node(missing_node);
|
||||
if missing_field is not None:
|
||||
iq['setResponse'].add_data(missing_field);
|
||||
iq['setResponse'].add_data(missing_field);
|
||||
iq['setResponse']['error']['var'] = "Output";
|
||||
iq['setResponse']['error']['text'] = error_msg;
|
||||
iq.send(block=False);
|
||||
iq.send(block=False);
|
||||
|
||||
def _handle_direct_set(self, msg):
|
||||
"""
|
||||
Event handler for reception of a Message with set command - this is a
|
||||
Event handler for reception of a Message with set command - this is a
|
||||
direct control command.
|
||||
|
||||
Verifies that
|
||||
Verifies that
|
||||
- all the requested nodes are available
|
||||
(if no nodes are specified in the request, assume all nodes)
|
||||
- all the control fields are available from all requested nodes
|
||||
@@ -342,9 +342,9 @@ class XEP_0325(BasePlugin):
|
||||
|
||||
|
||||
def _threaded_node_request(self, session, process_fields):
|
||||
"""
|
||||
"""
|
||||
Helper function to handle the device control in a separate thread.
|
||||
|
||||
|
||||
Arguments:
|
||||
session -- The request session id
|
||||
process_fields -- The fields to set in the devices. List of tuple format:
|
||||
@@ -360,12 +360,12 @@ class XEP_0325(BasePlugin):
|
||||
self.nodes[node]['device'].set_control_fields(process_fields, session=session, callback=self._device_set_command_callback);
|
||||
|
||||
def _event_comm_timeout(self, session, nodeId):
|
||||
"""
|
||||
"""
|
||||
Triggered if any of the control operations timeout.
|
||||
Stop communicating with the failing device.
|
||||
If the control command was an Iq request, sends a failure
|
||||
message back to the client.
|
||||
|
||||
If the control command was an Iq request, sends a failure
|
||||
message back to the client.
|
||||
|
||||
Arguments:
|
||||
session -- The request session id
|
||||
nodeId -- The id of the device which timed out
|
||||
@@ -380,7 +380,7 @@ class XEP_0325(BasePlugin):
|
||||
iq['id'] = self.sessions[session]['seqnr'];
|
||||
iq['setResponse']['responseCode'] = "OtherError";
|
||||
iq['setResponse'].add_node(nodeId);
|
||||
iq['setResponse']['error']['var'] = "Output";
|
||||
iq['setResponse']['error']['var'] = "Output";
|
||||
iq['setResponse']['error']['text'] = "Timeout.";
|
||||
iq.send(block=False);
|
||||
|
||||
@@ -393,9 +393,9 @@ class XEP_0325(BasePlugin):
|
||||
del self.sessions[session];
|
||||
|
||||
def _all_nodes_done(self, session):
|
||||
"""
|
||||
"""
|
||||
Checks wheter all devices are done replying to the control command.
|
||||
|
||||
|
||||
Arguments:
|
||||
session -- The request session id
|
||||
"""
|
||||
@@ -405,19 +405,19 @@ class XEP_0325(BasePlugin):
|
||||
return True;
|
||||
|
||||
def _device_set_command_callback(self, session, nodeId, result, error_field=None, error_msg=None):
|
||||
"""
|
||||
Callback function called by the devices when the control command is
|
||||
"""
|
||||
Callback function called by the devices when the control command is
|
||||
complete or failed.
|
||||
If needed, composes a message with the result and sends it back to the
|
||||
If needed, composes a message with the result and sends it back to the
|
||||
client.
|
||||
|
||||
|
||||
Arguments:
|
||||
session -- The request session id
|
||||
nodeId -- The device id which initiated the callback
|
||||
result -- The current result status of the control command. Valid values are:
|
||||
"error" - Set fields failed.
|
||||
"ok" - All fields were set.
|
||||
error_field -- [optional] Only applies when result == "error"
|
||||
error_field -- [optional] Only applies when result == "error"
|
||||
The field name that failed (usually means it is missing)
|
||||
error_msg -- [optional] Only applies when result == "error".
|
||||
Error details when a request failed.
|
||||
@@ -441,12 +441,12 @@ class XEP_0325(BasePlugin):
|
||||
iq['setResponse'].add_node(nodeId);
|
||||
if error_field is not None:
|
||||
iq['setResponse'].add_data(error_field);
|
||||
iq['setResponse']['error']['var'] = error_field;
|
||||
iq['setResponse']['error']['var'] = error_field;
|
||||
iq['setResponse']['error']['text'] = error_msg;
|
||||
iq.send(block=False);
|
||||
|
||||
# Drop communication with this device and check if we are done
|
||||
self.sessions[session]["nodeDone"][nodeId] = True;
|
||||
self.sessions[session]["nodeDone"][nodeId] = True;
|
||||
if (self._all_nodes_done(session)):
|
||||
# The session is complete, delete it
|
||||
del self.sessions[session];
|
||||
@@ -473,17 +473,17 @@ class XEP_0325(BasePlugin):
|
||||
# Client side (data controller) API
|
||||
|
||||
def set_request(self, from_jid, to_jid, callback, fields, nodeIds=None):
|
||||
"""
|
||||
"""
|
||||
Called on the client side to initiade a control request.
|
||||
Composes a message with the request and sends it to the device(s).
|
||||
Does not block, the callback will be called when the device(s)
|
||||
Does not block, the callback will be called when the device(s)
|
||||
has responded.
|
||||
|
||||
|
||||
Arguments:
|
||||
from_jid -- The jid of the requester
|
||||
to_jid -- The jid of the device(s)
|
||||
callback -- The callback function to call when data is availble.
|
||||
|
||||
callback -- The callback function to call when data is availble.
|
||||
|
||||
The callback function must support the following arguments:
|
||||
|
||||
from_jid -- The jid of the responding device(s)
|
||||
@@ -494,20 +494,20 @@ class XEP_0325(BasePlugin):
|
||||
"Locked" - Field(s) is locked and cannot
|
||||
be changed at the moment.
|
||||
"NotImplemented" - Request feature not implemented.
|
||||
"FormError" - Error while setting with
|
||||
"FormError" - Error while setting with
|
||||
a form (not implemented).
|
||||
"OtherError" - Indicates other types of
|
||||
errors, such as timeout.
|
||||
"OtherError" - Indicates other types of
|
||||
errors, such as timeout.
|
||||
Details in the error_msg.
|
||||
|
||||
|
||||
nodeId -- [optional] Only applicable when result == "error"
|
||||
List of node Ids of failing device(s).
|
||||
|
||||
fields -- [optional] Only applicable when result == "error"
|
||||
nodeId -- [optional] Only applicable when result == "error"
|
||||
List of node Ids of failing device(s).
|
||||
|
||||
fields -- [optional] Only applicable when result == "error"
|
||||
List of fields that failed.[optional] Mandatory when result == "rejected" or "failure".
|
||||
|
||||
error_msg -- Details about why the request failed.
|
||||
|
||||
error_msg -- Details about why the request failed.
|
||||
|
||||
fields -- Fields to set. List of tuple format: (name, typename, value).
|
||||
nodeIds -- [optional] Limits the request to the node Ids in this list.
|
||||
@@ -526,14 +526,14 @@ class XEP_0325(BasePlugin):
|
||||
iq['set'].add_data(name=name, typename=typename, value=value);
|
||||
|
||||
self.sessions[seqnr] = {"from": iq['from'], "to": iq['to'], "callback": callback};
|
||||
iq.send(block=False);
|
||||
iq.send(block=False);
|
||||
|
||||
def set_command(self, from_jid, to_jid, fields, nodeIds=None):
|
||||
"""
|
||||
"""
|
||||
Called on the client side to initiade a control command.
|
||||
Composes a message with the set commandand sends it to the device(s).
|
||||
Does not block. Device(s) will not respond, regardless of result.
|
||||
|
||||
|
||||
Arguments:
|
||||
from_jid -- The jid of the requester
|
||||
to_jid -- The jid of the device(s)
|
||||
@@ -553,7 +553,7 @@ class XEP_0325(BasePlugin):
|
||||
msg['set'].add_data(name, typename, value);
|
||||
|
||||
# We won't get any reply, so don't create a session
|
||||
msg.send();
|
||||
msg.send();
|
||||
|
||||
def _handle_set_response(self, iq):
|
||||
""" Received response from device(s) """
|
||||
@@ -571,4 +571,4 @@ class XEP_0325(BasePlugin):
|
||||
callback = self.sessions[seqnr]["callback"];
|
||||
callback(from_jid=from_jid, result=result, nodeIds=nodeIds, fields=fields, error_msg=error_msg);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ import datetime
|
||||
class Device(object):
|
||||
"""
|
||||
Example implementation of a device control object.
|
||||
|
||||
The device object may by any custom implementation to support
|
||||
|
||||
The device object may by any custom implementation to support
|
||||
specific devices, but it must implement the functions:
|
||||
has_control_field
|
||||
set_control_fields
|
||||
@@ -30,7 +30,7 @@ class Device(object):
|
||||
and the type matches for control in this device.
|
||||
|
||||
Arguments:
|
||||
field -- The field name
|
||||
field -- The field name
|
||||
typename -- The expected type
|
||||
"""
|
||||
if field in self.control_fields and self.control_fields[field]["type"] == typename:
|
||||
@@ -43,22 +43,22 @@ class Device(object):
|
||||
sets the data and (if needed) and calls the callback.
|
||||
|
||||
Arguments:
|
||||
fields -- List of control fields in tuple format:
|
||||
fields -- List of control fields in tuple format:
|
||||
(name, typename, value)
|
||||
session -- Session id, only used in the callback as identifier
|
||||
callback -- Callback function to call when control set is complete.
|
||||
|
||||
The callback function must support the following arguments:
|
||||
|
||||
session -- Session id, as supplied in the
|
||||
session -- Session id, as supplied in the
|
||||
request_fields call
|
||||
nodeId -- Identifier for this device
|
||||
result -- The current result status of the readout.
|
||||
result -- The current result status of the readout.
|
||||
Valid values are:
|
||||
"error" - Set fields failed.
|
||||
"ok" - All fields were set.
|
||||
error_field -- [optional] Only applies when result == "error"
|
||||
The field name that failed
|
||||
error_field -- [optional] Only applies when result == "error"
|
||||
The field name that failed
|
||||
(usually means it is missing)
|
||||
error_msg -- [optional] Only applies when result == "error".
|
||||
Error details when a request failed.
|
||||
@@ -82,9 +82,9 @@ class Device(object):
|
||||
Sends a reject to the caller
|
||||
|
||||
Arguments:
|
||||
session -- Session id, see definition in
|
||||
session -- Session id, see definition in
|
||||
set_control_fields function
|
||||
callback -- Callback function, see definition in
|
||||
callback -- Callback function, see definition in
|
||||
set_control_fields function
|
||||
"""
|
||||
callback(session, result="error", nodeId=self.nodeId, error_field=field, error_msg=message);
|
||||
@@ -95,8 +95,8 @@ class Device(object):
|
||||
|
||||
Arguments:
|
||||
name -- Name of the field
|
||||
typename -- Type of the field, one of:
|
||||
(boolean, color, string, date, dateTime,
|
||||
typename -- Type of the field, one of:
|
||||
(boolean, color, string, date, dateTime,
|
||||
double, duration, int, long, time)
|
||||
value -- Field value
|
||||
"""
|
||||
|
||||
@@ -53,7 +53,7 @@ class ControlSet(ElementBase):
|
||||
Arguments:
|
||||
nodeId -- The ID for the node.
|
||||
sourceId -- [optional] identifying the data source controlling the device
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
"""
|
||||
if nodeId not in self._nodes:
|
||||
self._nodes.add((nodeId))
|
||||
@@ -117,12 +117,12 @@ class ControlSet(ElementBase):
|
||||
|
||||
def add_data(self, name, typename, value):
|
||||
"""
|
||||
Add a new data element.
|
||||
Add a new data element.
|
||||
|
||||
Arguments:
|
||||
name -- The name of the data element
|
||||
typename -- The type of data element
|
||||
(boolean, color, string, date, dateTime,
|
||||
typename -- The type of data element
|
||||
(boolean, color, string, date, dateTime,
|
||||
double, duration, int, long, time)
|
||||
value -- The value of the data element
|
||||
"""
|
||||
@@ -244,7 +244,7 @@ class ControlSetResponse(ElementBase):
|
||||
Arguments:
|
||||
nodeId -- The ID for the node.
|
||||
sourceId -- [optional] identifying the data source controlling the device
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
cacheType -- [optional] narrowing down the search to a specific kind of node
|
||||
"""
|
||||
if nodeId not in self._nodes:
|
||||
self._nodes.add(nodeId)
|
||||
@@ -308,7 +308,7 @@ class ControlSetResponse(ElementBase):
|
||||
|
||||
def add_data(self, name):
|
||||
"""
|
||||
Add a new ResponseParameter element.
|
||||
Add a new ResponseParameter element.
|
||||
|
||||
Arguments:
|
||||
name -- Name of the parameter
|
||||
@@ -389,12 +389,12 @@ class Error(ElementBase):
|
||||
def del_text(self):
|
||||
"""Remove the contents inside the XML tag."""
|
||||
self.xml.text = ""
|
||||
return self
|
||||
return self
|
||||
|
||||
class ResponseParameter(ElementBase):
|
||||
"""
|
||||
Parameter element in ControlSetResponse.
|
||||
"""
|
||||
"""
|
||||
Parameter element in ControlSetResponse.
|
||||
"""
|
||||
namespace = 'urn:xmpp:iot:control'
|
||||
name = 'parameter'
|
||||
plugin_attrib = name
|
||||
@@ -402,7 +402,7 @@ class ResponseParameter(ElementBase):
|
||||
|
||||
|
||||
class BaseParameter(ElementBase):
|
||||
"""
|
||||
"""
|
||||
Parameter element in SetCommand. This is a base class,
|
||||
all instances of parameters added to SetCommand must be of types:
|
||||
BooleanParameter
|
||||
@@ -415,7 +415,7 @@ class BaseParameter(ElementBase):
|
||||
IntParameter
|
||||
LongParameter
|
||||
TimeParameter
|
||||
"""
|
||||
"""
|
||||
namespace = 'urn:xmpp:iot:control'
|
||||
name = 'baseParameter'
|
||||
plugin_attrib = name
|
||||
@@ -425,80 +425,80 @@ class BaseParameter(ElementBase):
|
||||
return self.name;
|
||||
|
||||
class BooleanParameter(BaseParameter):
|
||||
"""
|
||||
Field data of type boolean.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
Field data of type boolean.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
name = 'boolean'
|
||||
plugin_attrib = name
|
||||
|
||||
class ColorParameter(BaseParameter):
|
||||
"""
|
||||
Field data of type color.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
Field data of type color.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
name = 'color'
|
||||
plugin_attrib = name
|
||||
|
||||
class StringParameter(BaseParameter):
|
||||
"""
|
||||
Field data of type string.
|
||||
"""
|
||||
Field data of type string.
|
||||
"""
|
||||
name = 'string'
|
||||
plugin_attrib = name
|
||||
|
||||
class DateParameter(BaseParameter):
|
||||
"""
|
||||
Field data of type date.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
Field data of type date.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
name = 'date'
|
||||
plugin_attrib = name
|
||||
|
||||
class DateTimeParameter(BaseParameter):
|
||||
"""
|
||||
Field data of type dateTime.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
Field data of type dateTime.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
name = 'dateTime'
|
||||
plugin_attrib = name
|
||||
|
||||
class DoubleParameter(BaseParameter):
|
||||
"""
|
||||
Field data of type double.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
Field data of type double.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
name = 'double'
|
||||
plugin_attrib = name
|
||||
|
||||
class DurationParameter(BaseParameter):
|
||||
"""
|
||||
Field data of type duration.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
Field data of type duration.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
name = 'duration'
|
||||
plugin_attrib = name
|
||||
|
||||
class IntParameter(BaseParameter):
|
||||
"""
|
||||
Field data of type int.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
Field data of type int.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
name = 'int'
|
||||
plugin_attrib = name
|
||||
|
||||
class LongParameter(BaseParameter):
|
||||
"""
|
||||
Field data of type long (64-bit int).
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
Field data of type long (64-bit int).
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
name = 'long'
|
||||
plugin_attrib = name
|
||||
|
||||
class TimeParameter(BaseParameter):
|
||||
"""
|
||||
Field data of type time.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
Field data of type time.
|
||||
Note that the value is expressed as a string.
|
||||
"""
|
||||
name = 'time'
|
||||
plugin_attrib = name
|
||||
|
||||
@@ -133,7 +133,7 @@ def resolve(host, port=None, service=None, proto='tcp',
|
||||
if not service:
|
||||
hosts = [(host, port)]
|
||||
else:
|
||||
hosts = get_SRV(host, port, service, proto,
|
||||
hosts = get_SRV(host, port, service, proto,
|
||||
resolver=resolver,
|
||||
use_dnspython=use_dnspython)
|
||||
|
||||
@@ -144,7 +144,7 @@ def resolve(host, port=None, service=None, proto='tcp',
|
||||
results.append((host, '::1', port))
|
||||
results.append((host, '127.0.0.1', port))
|
||||
if use_ipv6:
|
||||
for address in get_AAAA(host, resolver=resolver,
|
||||
for address in get_AAAA(host, resolver=resolver,
|
||||
use_dnspython=use_dnspython):
|
||||
results.append((host, address, port))
|
||||
for address in get_A(host, resolver=resolver,
|
||||
|
||||
Reference in New Issue
Block a user