diff options
Diffstat (limited to 'sleekxmpp/xmlstream/handler')
-rw-r--r-- | sleekxmpp/xmlstream/handler/__init__.py | 14 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/handler/base.py | 84 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/handler/callback.py | 79 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/handler/waiter.py | 87 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/handler/xmlcallback.py | 36 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/handler/xmlwaiter.py | 33 |
6 files changed, 333 insertions, 0 deletions
diff --git a/sleekxmpp/xmlstream/handler/__init__.py b/sleekxmpp/xmlstream/handler/__init__.py new file mode 100644 index 00000000..7bcf0b71 --- /dev/null +++ b/sleekxmpp/xmlstream/handler/__init__.py @@ -0,0 +1,14 @@ +""" + 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.xmlstream.handler.callback import Callback +from sleekxmpp.xmlstream.handler.waiter import Waiter +from sleekxmpp.xmlstream.handler.xmlcallback import XMLCallback +from sleekxmpp.xmlstream.handler.xmlwaiter import XMLWaiter + +__all__ = ['Callback', 'Waiter', 'XMLCallback', 'XMLWaiter'] diff --git a/sleekxmpp/xmlstream/handler/base.py b/sleekxmpp/xmlstream/handler/base.py new file mode 100644 index 00000000..59dcb306 --- /dev/null +++ b/sleekxmpp/xmlstream/handler/base.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +""" + sleekxmpp.xmlstream.handler.base + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Part of SleekXMPP: The Sleek XMPP Library + + :copyright: (c) 2011 Nathanael C. Fritz + :license: MIT, see LICENSE for more details +""" + +import weakref + + +class BaseHandler(object): + + """ + Base class for stream handlers. Stream handlers are matched with + incoming stanzas so that the stanza may be processed in some way. + Stanzas may be matched with multiple handlers. + + Handler execution may take place in two phases: during the incoming + stream processing, and in the main event loop. The :meth:`prerun()` + method is executed in the first case, and :meth:`run()` is called + during the second. + + :param string name: The name of the handler. + :param matcher: A :class:`~sleekxmpp.xmlstream.matcher.base.MatcherBase` + derived object that will be used to determine if a + stanza should be accepted by this handler. + :param stream: The :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` + instance that the handle will respond to. + """ + + def __init__(self, name, matcher, stream=None): + #: The name of the handler + self.name = name + + #: The XML stream this handler is assigned to + self.stream = None + if stream is not None: + self.stream = weakref.ref(stream) + stream.register_handler(self) + + self._destroy = False + self._payload = None + self._matcher = matcher + + def match(self, xml): + """Compare a stanza or XML object with the handler's matcher. + + :param xml: An XML or + :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` object + """ + return self._matcher.match(xml) + + def prerun(self, payload): + """Prepare the handler for execution while the XML + stream is being processed. + + :param payload: A :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` + object. + """ + self._payload = payload + + def run(self, payload): + """Execute the handler after XML stream processing and during the + main event loop. + + :param payload: A :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` + object. + """ + self._payload = payload + + def check_delete(self): + """Check if the handler should be removed from the list + of stream handlers. + """ + return self._destroy + + +# To comply with PEP8, method names now use underscores. +# Deprecated method names are re-mapped for backwards compatibility. +BaseHandler.checkDelete = BaseHandler.check_delete diff --git a/sleekxmpp/xmlstream/handler/callback.py b/sleekxmpp/xmlstream/handler/callback.py new file mode 100644 index 00000000..37f53335 --- /dev/null +++ b/sleekxmpp/xmlstream/handler/callback.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +""" + sleekxmpp.xmlstream.handler.callback + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Part of SleekXMPP: The Sleek XMPP Library + + :copyright: (c) 2011 Nathanael C. Fritz + :license: MIT, see LICENSE for more details +""" + +from sleekxmpp.xmlstream.handler.base import BaseHandler + + +class Callback(BaseHandler): + + """ + The Callback handler will execute a callback function with + matched stanzas. + + The handler may execute the callback either during stream + processing or during the main event loop. + + Callback functions are all executed in the same thread, so be aware if + you are executing functions that will block for extended periods of + time. Typically, you should signal your own events using the SleekXMPP + object's :meth:`~sleekxmpp.xmlstream.xmlstream.XMLStream.event()` + method to pass the stanza off to a threaded event handler for further + processing. + + + :param string name: The name of the handler. + :param matcher: A :class:`~sleekxmpp.xmlstream.matcher.base.MatcherBase` + derived object for matching stanza objects. + :param pointer: The function to execute during callback. + :param bool thread: **DEPRECATED.** Remains only for + backwards compatibility. + :param bool once: Indicates if the handler should be used only + once. Defaults to False. + :param bool instream: Indicates if the callback should be executed + during stream processing instead of in the + main event loop. + :param stream: The :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` + instance this handler should monitor. + """ + + def __init__(self, name, matcher, pointer, thread=False, + once=False, instream=False, stream=None): + BaseHandler.__init__(self, name, matcher, stream) + self._pointer = pointer + self._once = once + self._instream = instream + + def prerun(self, payload): + """Execute the callback during stream processing, if + the callback was created with ``instream=True``. + + :param payload: The matched + :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` object. + """ + if self._once: + self._destroy = True + if self._instream: + self.run(payload, True) + + def run(self, payload, instream=False): + """Execute the callback function with the matched stanza payload. + + :param payload: The matched + :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` object. + :param bool instream: Force the handler to execute during stream + processing. This should only be used by + :meth:`prerun()`. Defaults to ``False``. + """ + if not self._instream or instream: + self._pointer(payload) + if self._once: + self._destroy = True + del self._pointer diff --git a/sleekxmpp/xmlstream/handler/waiter.py b/sleekxmpp/xmlstream/handler/waiter.py new file mode 100644 index 00000000..01ff5d67 --- /dev/null +++ b/sleekxmpp/xmlstream/handler/waiter.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +""" + sleekxmpp.xmlstream.handler.waiter + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Part of SleekXMPP: The Sleek XMPP Library + + :copyright: (c) 2011 Nathanael C. Fritz + :license: MIT, see LICENSE for more details +""" + +import logging +try: + import queue +except ImportError: + import Queue as queue + +from sleekxmpp.xmlstream import StanzaBase +from sleekxmpp.xmlstream.handler.base import BaseHandler + + +log = logging.getLogger(__name__) + + +class Waiter(BaseHandler): + + """ + The Waiter handler allows an event handler to block until a + particular stanza has been received. The handler will either be + given the matched stanza, or ``False`` if the waiter has timed out. + + :param string name: The name of the handler. + :param matcher: A :class:`~sleekxmpp.xmlstream.matcher.base.MatcherBase` + derived object for matching stanza objects. + :param stream: The :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream` + instance this handler should monitor. + """ + + def __init__(self, name, matcher, stream=None): + BaseHandler.__init__(self, name, matcher, stream=stream) + self._payload = queue.Queue() + + def prerun(self, payload): + """Store the matched stanza when received during processing. + + :param payload: The matched + :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` object. + """ + self._payload.put(payload) + + def run(self, payload): + """Do not process this handler during the main event loop.""" + pass + + def wait(self, timeout=None): + """Block an event handler while waiting for a stanza to arrive. + + Be aware that this will impact performance if called from a + non-threaded event handler. + + Will return either the received stanza, or ``False`` if the + waiter timed out. + + :param int timeout: The number of seconds to wait for the stanza + to arrive. Defaults to the the stream's + :class:`~sleekxmpp.xmlstream.xmlstream.XMLStream.response_timeout` + value. + """ + if timeout is None: + timeout = self.stream().response_timeout + + elapsed_time = 0 + stanza = False + while elapsed_time < timeout and not self.stream().stop.is_set(): + try: + stanza = self._payload.get(True, 1) + break + except queue.Empty: + elapsed_time += 1 + if elapsed_time >= timeout: + log.warning("Timed out waiting for %s", self.name) + self.stream().remove_handler(self.name) + return stanza + + def check_delete(self): + """Always remove waiters after use.""" + return True diff --git a/sleekxmpp/xmlstream/handler/xmlcallback.py b/sleekxmpp/xmlstream/handler/xmlcallback.py new file mode 100644 index 00000000..11607ffb --- /dev/null +++ b/sleekxmpp/xmlstream/handler/xmlcallback.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. +""" + +from sleekxmpp.xmlstream.handler import Callback + + +class XMLCallback(Callback): + + """ + The XMLCallback class is identical to the normal Callback class, + except that XML contents of matched stanzas will be processed instead + of the stanza objects themselves. + + Methods: + run -- Overrides Callback.run + """ + + def run(self, payload, instream=False): + """ + Execute the callback function with the matched stanza's + XML contents, instead of the stanza itself. + + Overrides BaseHandler.run + + Arguments: + payload -- The matched stanza object. + instream -- Force the handler to execute during + stream processing. Used only by prerun. + Defaults to False. + """ + Callback.run(self, payload.xml, instream) diff --git a/sleekxmpp/xmlstream/handler/xmlwaiter.py b/sleekxmpp/xmlstream/handler/xmlwaiter.py new file mode 100644 index 00000000..5201caf3 --- /dev/null +++ b/sleekxmpp/xmlstream/handler/xmlwaiter.py @@ -0,0 +1,33 @@ +""" + 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.xmlstream.handler import Waiter + + +class XMLWaiter(Waiter): + + """ + The XMLWaiter class is identical to the normal Waiter class + except that it returns the XML contents of the stanza instead + of the full stanza object itself. + + Methods: + prerun -- Overrides Waiter.prerun + """ + + def prerun(self, payload): + """ + Store the XML contents of the stanza to return to the + waiting event handler. + + Overrides Waiter.prerun + + Arguments: + payload -- The matched stanza object. + """ + Waiter.prerun(self, payload.xml) |