coroutine_callback.py 3.5 KB
Newer Older
1

2 3 4 5 6
# slixmpp.xmlstream.handler.callback
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Part of Slixmpp: The Slick XMPP Library
# :copyright: (c) 2011 Nathanael C. Fritz
# :license: MIT, see LICENSE for more details
mathieui's avatar
mathieui committed
7 8 9 10 11 12
from __future__ import annotations

from asyncio import iscoroutinefunction, ensure_future
from typing import Optional, Callable, Awaitable, TYPE_CHECKING

from slixmpp.xmlstream.stanzabase import StanzaBase
13
from slixmpp.xmlstream.handler.base import BaseHandler
mathieui's avatar
mathieui committed
14 15 16 17 18 19
from slixmpp.xmlstream.matcher.base import MatcherBase

CoroutineFunction = Callable[[StanzaBase], Awaitable[None]]

if TYPE_CHECKING:
    from slixmpp.xmlstream.xmlstream import XMLStream
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47


class CoroutineCallback(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.

    The event will be scheduled to be run soon in the event loop instead
    of immediately.

    :param string name: The name of the handler.
    :param matcher: A :class:`~slixmpp.xmlstream.matcher.base.MatcherBase`
                    derived object for matching stanza objects.
    :param pointer: The function to execute during callback. If ``pointer``
                    is not a coroutine, this function will raise a ValueError.
    :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:`~slixmpp.xmlstream.xmlstream.XMLStream`
                   instance this handler should monitor.
    """

mathieui's avatar
mathieui committed
48 49 50 51 52 53 54
    _once: bool
    _instream: bool
    _pointer: CoroutineFunction

    def __init__(self, name: str, matcher: MatcherBase,
                 pointer: CoroutineFunction, once: bool = False,
                 instream: bool = False, stream: Optional[XMLStream] = None):
55
        BaseHandler.__init__(self, name, matcher, stream)
mathieui's avatar
mathieui committed
56
        if not iscoroutinefunction(pointer):
57 58
            raise ValueError("Given function is not a coroutine")

mathieui's avatar
mathieui committed
59
        async def pointer_wrapper(stanza: StanzaBase) -> None:
60
            try:
mathieui's avatar
mathieui committed
61
                await pointer(stanza)
62 63 64 65 66 67 68
            except Exception as e:
                stanza.exception(e)

        self._pointer = pointer_wrapper
        self._once = once
        self._instream = instream

mathieui's avatar
mathieui committed
69
    def prerun(self, payload: StanzaBase) -> None:
70 71 72 73
        """Execute the callback during stream processing, if
        the callback was created with ``instream=True``.

        :param payload: The matched
mathieui's avatar
mathieui committed
74
            :class:`~slixmpp.xmlstream.stanzabase.StanzaBase` object.
75 76 77 78 79 80
        """
        if self._once:
            self._destroy = True
        if self._instream:
            self.run(payload, True)

mathieui's avatar
mathieui committed
81
    def run(self, payload: StanzaBase, instream: bool = False) -> None:
82 83 84
        """Execute the callback function with the matched stanza payload.

        :param payload: The matched
mathieui's avatar
mathieui committed
85
            :class:`~slixmpp.xmlstream.stanzabase.StanzaBase` object.
86 87 88 89 90
        :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:
mathieui's avatar
mathieui committed
91
            ensure_future(self._pointer(payload))
92 93 94
            if self._once:
                self._destroy = True
                del self._pointer