From c4b1212c44e0758c6361ca46c6c3a90e27ac876f Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Fri, 11 Feb 2011 00:30:45 -0500 Subject: Updated XEP-0199 plugin. Now has docs and uses the new plugin format. --- sleekxmpp/plugins/xep_0199.py | 63 ------------- sleekxmpp/plugins/xep_0199/__init__.py | 10 ++ sleekxmpp/plugins/xep_0199/ping.py | 162 +++++++++++++++++++++++++++++++++ sleekxmpp/plugins/xep_0199/stanza.py | 36 ++++++++ 4 files changed, 208 insertions(+), 63 deletions(-) delete mode 100644 sleekxmpp/plugins/xep_0199.py create mode 100644 sleekxmpp/plugins/xep_0199/__init__.py create mode 100644 sleekxmpp/plugins/xep_0199/ping.py create mode 100644 sleekxmpp/plugins/xep_0199/stanza.py (limited to 'sleekxmpp') diff --git a/sleekxmpp/plugins/xep_0199.py b/sleekxmpp/plugins/xep_0199.py deleted file mode 100644 index e7ec5c46..00000000 --- a/sleekxmpp/plugins/xep_0199.py +++ /dev/null @@ -1,63 +0,0 @@ -""" - SleekXMPP: The Sleek XMPP Library - Copyright (C) 2010 Nathanael C. Fritz - This file is part of SleekXMPP. - - See the file LICENSE for copying permission. -""" -from xml.etree import cElementTree as ET -from . import base -import time -import logging - - -log = logging.getLogger(__name__) - - -class xep_0199(base.base_plugin): - """XEP-0199 XMPP Ping""" - - def plugin_init(self): - self.description = "XMPP Ping" - self.xep = "0199" - self.xmpp.add_handler("" % self.xmpp.default_ns, self.handler_ping, name='XMPP Ping') - if self.config.get('keepalive', True): - self.xmpp.add_event_handler('session_start', self.handler_pingserver, threaded=True) - - def post_init(self): - base.base_plugin.post_init(self) - self.xmpp.plugin['xep_0030'].add_feature('urn:xmpp:ping') - - def handler_pingserver(self, xml): - self.xmpp.schedule("xep-0119 ping", float(self.config.get('frequency', 300)), self.scheduled_ping, repeat=True) - - def scheduled_ping(self): - log.debug("pinging...") - if self.sendPing(self.xmpp.boundjid.host, self.config.get('timeout', 30)) is False: - log.debug("Did not recieve ping back in time. Requesting Reconnect.") - self.xmpp.reconnect() - - def handler_ping(self, xml): - iq = self.xmpp.makeIqResult(xml.get('id', 'unknown')) - iq.attrib['to'] = xml.get('from', self.xmpp.boundjid.domain) - self.xmpp.send(iq) - - def sendPing(self, jid, timeout = 30, errorfalse=False): - """ sendPing(jid, timeout) - Sends a ping to the specified jid, returning the time (in seconds) - to receive a reply, or None if no reply is received in timeout seconds. - """ - id = self.xmpp.getNewId() - iq = self.xmpp.makeIq(id) - iq.attrib['type'] = 'get' - iq.attrib['to'] = jid - ping = ET.Element('{urn:xmpp:ping}ping') - iq.append(ping) - startTime = time.clock() - #pingresult = self.xmpp.send(iq, self.xmpp.makeIq(id), timeout) - pingresult = iq.send() - endTime = time.clock() - if pingresult == False or (errorfalse and pingresult['type'] == 'error'): - #self.xmpp.disconnect(reconnect=True) - return False - return endTime - startTime diff --git a/sleekxmpp/plugins/xep_0199/__init__.py b/sleekxmpp/plugins/xep_0199/__init__.py new file mode 100644 index 00000000..3444fe94 --- /dev/null +++ b/sleekxmpp/plugins/xep_0199/__init__.py @@ -0,0 +1,10 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2010 Nathanael C. Fritz + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.plugins.xep_0199.stanza import Ping +from sleekxmpp.plugins.xep_0199.ping import xep_0199 diff --git a/sleekxmpp/plugins/xep_0199/ping.py b/sleekxmpp/plugins/xep_0199/ping.py new file mode 100644 index 00000000..cde2f822 --- /dev/null +++ b/sleekxmpp/plugins/xep_0199/ping.py @@ -0,0 +1,162 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2010 Nathanael C. Fritz + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +import time +import logging + +import sleekxmpp +from sleekxmpp import Iq +from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.xmlstream.matcher import StanzaPath +from sleekxmpp.xmlstream.handler import Callback +from sleekxmpp.plugins.base import base_plugin +from sleekxmpp.plugins.xep_0199 import stanza, Ping + + +log = logging.getLogger(__name__) + + +class xep_0199(base_plugin): + + """ + XEP-0199: XMPP Ping + + Given that XMPP is based on TCP connections, it is possible for the + underlying connection to be terminated without the application's + awareness. Ping stanzas provide an alternative to whitespace based + keepalive methods for detecting lost connections. + + Also see . + + Attributes: + keepalive -- If True, periodically send ping requests + to the server. If a ping is not answered, + the connection will be reset. + frequency -- Time in seconds between keepalive pings. + Defaults to 300 seconds. + timeout -- Time in seconds to wait for a ping response. + Defaults to 30 seconds. + Methods: + send_ping -- Send a ping to a given JID, returning the + round trip time. + """ + + def plugin_init(self): + """ + Start the XEP-0199 plugin. + """ + self.description = 'XMPP Ping' + self.xep = '0199' + self.stanza = stanza + + # Backwards compatibility for names + self.sendPing = self.send_ping + + self.keepalive = self.config.get('keepalive', True) + self.frequency = float(self.config.get('frequency', 300)) + self.timeout = self.config.get('timeout', 30) + + register_stanza_plugin(Iq, Ping) + + self.xmpp.register_handler( + Callback('Ping', + StanzaPath('iq@type=get/ping'), + self._handle_ping)) + + if self.keepalive: + self.xmpp.add_event_handler('session_start', + self._handle_keepalive, + threaded=True) + + def post_init(self): + """Handle cross-plugin dependencies.""" + base_plugin.post_init(self) + self.xmpp['xep_0030'].add_feature(Ping.namespace) + + def _handle_keepalive(self, event): + """ + Begin periodic pinging of the server. If a ping is not + answered, the connection will be restarted. + + The pinging interval can be adjused using self.frequency + before beginning processing. + + Arguments: + event -- The session_start event. + """ + def scheduled_ping(): + """Send ping request to the server.""" + log.debug("Pinging...") + resp = self.send_ping(self.xmpp.boundjid.host, self.timeout) + if not resp: + log.debug("Did not recieve ping back in time." + \ + "Requesting Reconnect.") + self.xmpp.reconnect() + + self.xmpp.schedule('Ping Keep Alive', + self.frequency, + scheduled_ping, + repeat=True) + + def _handle_ping(self, iq): + """ + Automatically reply to ping requests. + + Arguments: + iq -- The ping request. + """ + log.debug("Pinged by %s" % iq['from']) + iq.reply().enable('ping').send() + + def send_ping(self, jid, timeout=None, errorfalse=False, + ifrom=None, block=True, callback=None): + """ + Send a ping request and calculate the response time. + + Arguments: + jid -- The JID that will receive the ping. + timeout -- Time in seconds to wait for a response. + Defaults to self.timeout. + errorfalse -- Indicates if False should be returned + if an error stanza is received. Defaults + to False. + ifrom -- Specifiy the sender JID. + block -- Indicate if execution should block until + a pong response is received. Defaults + to True. + callback -- Optional handler to execute when a pong + is received. Useful in conjunction with + the option block=False. + """ + log.debug("Pinging %s" % jid) + if timeout is None: + timeout = self.timeout + + iq = self.xmpp.Iq() + iq['type'] = 'get' + iq['to'] = jid + if ifrom: + iq['from'] = ifrom + iq.enable('ping') + + start_time = time.clock() + resp = iq.send(block=block, + timeout=timeout, + callback=callback) + end_time = time.clock() + + delay = end_time - start_time + + if not block: + return None + + if not resp or resp['type'] == 'error': + return False + + log.debug("Pong: %s %f" % (jid, delay)) + return delay diff --git a/sleekxmpp/plugins/xep_0199/stanza.py b/sleekxmpp/plugins/xep_0199/stanza.py new file mode 100644 index 00000000..6586a763 --- /dev/null +++ b/sleekxmpp/plugins/xep_0199/stanza.py @@ -0,0 +1,36 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2010 Nathanael C. Fritz + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +import sleekxmpp +from sleekxmpp.xmlstream import ElementBase + + +class Ping(ElementBase): + + """ + Given that XMPP is based on TCP connections, it is possible for the + underlying connection to be terminated without the application's + awareness. Ping stanzas provide an alternative to whitespace based + keepalive methods for detecting lost connections. + + Example ping stanza: + + + + + Stanza Interface: + None + + Methods: + None + """ + + name = 'ping' + namespace = 'urn:xmpp:ping' + plugin_attrib = 'ping' + interfaces = set() -- cgit v1.2.3