summaryrefslogtreecommitdiff
path: root/poezio/events.py
blob: a846d38d25a563629e59ffca216b0f94d2899bc7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#
# This file is part of Poezio.
#
# Poezio is free software: you can redistribute it and/or modify
# it under the terms of the zlib license. See the COPYING file.
"""
Defines the EventHandler class.
The list of available events is here:
http://poezio.eu/doc/en/plugins.html#_poezio_events
"""
import logging

from collections import OrderedDict
from inspect import iscoroutinefunction
from typing import Callable, Dict, List

log = logging.getLogger(__name__)


class EventHandler:
    """
    A class keeping a list of possible events that are triggered
    by poezio. You (a plugin for example) can add an event handler
    associated with an event name, and whenever that event is triggered,
    the callback is called.
    """

    def __init__(self):
        events = [
            'highlight',
            'muc_say',
            'muc_say_after',
            'conversation_say',
            'conversation_say_after',
            'private_say',
            'private_say_after',
            'conversation_msg',
            'private_msg',
            'muc_msg',
            'conversation_chatstate',
            'muc_chatstate',
            'private_chatstate',
            'normal_presence',
            'muc_presence',
            'muc_join',
            'joining_muc',
            'changing_nick',
            'muc_kick',
            'muc_nickchange',
            'muc_ban',
            'send_normal_presence',
            'ignored_private',
            'tab_change',
        ]
        self.events: Dict[str, OrderedDict[int, List[Callable]]] = {}
        for event in events:
            self.events[event] = OrderedDict()

    def add_event_handler(self, name: str, callback: Callable,
                          priority: int = 50) -> bool:
        """
        Add a callback to a given event.
        Note that if that event name doesn’t exist, it just returns False.
        If it was successfully added, it returns True
        priority is a integer between 0 and 100. 0 is the highest priority and
        will be called first. 100 is the lowest.
        """

        if name not in self.events:
            return False

        callbacks = self.events[name]

        # Clamp priority
        priority = max(0, min(priority, 100))

        entry = callbacks.setdefault(priority, [])
        entry.append(callback)

        return True

    async def trigger_async(self, name: str, *args, **kwargs):
        """
        Call all the callbacks associated to the given event name.
        """
        callbacks = self.events.get(name, None)
        if callbacks is None:
            return
        for priority in callbacks.values():
            for callback in priority:
                if iscoroutinefunction(callback):
                    await callback(*args, **kwargs)
                else:
                    callback(*args, **kwargs)

    def trigger(self, name: str, *args, **kwargs):
        """
        Call all the callbacks associated to the given event name.
        """
        callbacks = self.events.get(name, None)
        if callbacks is None:
            return
        for priority in callbacks.values():
            for callback in priority:
                if not iscoroutinefunction(callback):
                    callback(*args, **kwargs)
                else:
                    log.error(f'async event handler {callback} '
                               'called in sync trigger!')

    def del_event_handler(self, name: str, callback: Callable):
        """
        Remove the callback from the list of callbacks of the given event
        """
        if not name:
            for callbacks in self.events.values():
                for priority in callbacks.values():
                    for entry in priority[:]:
                        if entry == callback:
                            priority.remove(callback)
        else:
            callbacks = self.events[name]
            for priority in callbacks.values():
                for entry in priority[:]:
                    if entry == callback:
                        priority.remove(callback)