~ubuntu-branches/ubuntu/utopic/gozerbot/utopic

« back to all changes in this revision

Viewing changes to gozerbot/callbacks.py

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Malcolm
  • Date: 2009-09-14 09:00:29 UTC
  • mfrom: (1.1.4 upstream) (3.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20090914090029-uval0ekt72kmklxw
Tags: 0.9.1.3-3
Changed dependency on python-setuptools to python-pkg-resources
(Closes: #546435) 

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
#
3
3
#
4
4
 
5
 
""" callbacks triggered by ircevent CMND """
 
5
""" 
 
6
    bot callbacks .. callbacks occure on registered events. a precondition 
 
7
    function can optionaly be provided to see if the callback should fire. 
 
8
    callback can be executed in a Runner (1 thread that executes more jobs)
 
9
    or in a seperate thread. callbacks are now unified for bot irc and jabber 
 
10
    events.
 
11
"""
6
12
 
7
13
__copyright__ = 'this file is in the public domain'
8
14
 
9
 
from gozerbot.generic import rlog, handle_exception, calledfrom
10
 
from gozerbot.ircevent import makeargrest
11
 
from gozerbot.dol import Dol
12
 
from gozerbot.thr import start_new_thread
13
 
from gozerbot.runner import runner
14
 
import sys, copy
 
15
# IMPORT SECTION
 
16
 
 
17
# gozerbot imports
 
18
from gozerbot.stats import stats
 
19
from gozerbot.threads.thr import getname 
 
20
from config import config
 
21
from utils.log import rlog
 
22
from utils.exception import handle_exception
 
23
from utils.trace import calledfrom
 
24
from utils.generic import makeargrest
 
25
from utils.locking import lockdec
 
26
from utils.dol import Dol
 
27
from threads.thr import start_new_thread, getname
 
28
from runner import cbrunners
 
29
 
 
30
# basic imports
 
31
import sys, copy, thread
 
32
 
 
33
# END IMPORT
 
34
 
 
35
# LOCK SECTION
 
36
 
 
37
# locks
 
38
callbacklock = thread.allocate_lock()
 
39
locked = lockdec(callbacklock)
 
40
 
 
41
# END LOCKS
15
42
 
16
43
class Callback(object):
17
44
 
18
 
    """ class representing a callback """
19
 
 
20
 
    def __init__(self, func, prereq, plugname, kwargs, threaded=False):
21
 
        # the callback function
22
 
        self.func = func
23
 
        # pre condition function
24
 
        self.prereq = prereq
25
 
        # plugin name
26
 
        self.plugname = plugname
27
 
        # kwargs to pass on to function
28
 
        self.kwargs = kwargs
29
 
        # flag to see if callback has to run in thread or in the mainloop
30
 
        self.threaded = copy.deepcopy(threaded)
 
45
    """ 
 
46
        class representing a callback.
 
47
 
 
48
        :param func: function to execute
 
49
        :param prereq: prerequisite function 
 
50
        :param plugname: plugin to register this callback with 
 
51
        :param kwargs: dict to pass on to the callback 
 
52
        :param threaded: whether the callback should be executed in its own thread
 
53
        :param speed: determines which runnerspool to run this callback on
 
54
 
 
55
    """
 
56
 
 
57
    def __init__(self, func, prereq, plugname, kwargs, threaded=False, \
 
58
speed=5):
 
59
        self.func = func # the callback function
 
60
        self.prereq = prereq # pre condition function
 
61
        self.plugname = plugname # plugin name
 
62
        self.kwargs = kwargs # kwargs to pass on to function
 
63
        self.threaded = copy.deepcopy(threaded) # run callback in thread
 
64
        self.speed = copy.deepcopy(speed) # speed to execute callback with
 
65
        self.activate = False
 
66
        stats.up('callbacks', 'created')
31
67
 
32
68
class Callbacks(object):
33
69
 
34
 
    """ dict of lists containing callbacks """
 
70
    """ 
 
71
        dict of lists containing callbacks.  Callbacks object take care of 
 
72
        dispatching the callbacks based on incoming events. see Callbacks.check()
 
73
 
 
74
    """
35
75
 
36
76
    def __init__(self):
37
 
        # cbs are the callbacks which is a dict of lists .. 1 list per 
38
 
        # ievent.CMND
 
77
 
 
78
        # self.cbs holds the dict of list. entry value is the event (string)
39
79
        self.cbs = Dol()
40
80
 
41
81
    def size(self):
42
 
        """ return nr of callbacks """
 
82
 
 
83
        """ return number of callbacks. """
 
84
 
43
85
        return len(self.cbs)
44
86
 
45
 
    def add(self, what, func, prereq=None, kwargs=None, threaded=False, \
46
 
nr=False):
47
 
        """ add a callback """
 
87
    def add(self, what, func, prereq=None, kwargs=None, threaded=False, nr=False, speed=5):
 
88
 
 
89
        """ 
 
90
            add a callback. 
 
91
 
 
92
            :param what: event to fire callback for
 
93
            :param func: function to execute
 
94
            :param prereq: prerequisite function 
 
95
            :param plugname: plugin to register this callback with 
 
96
            :param kwargs: dict to pass on to the callback 
 
97
            :param threaded: whether the callback should be executed in its own thread
 
98
            :param speed: determines which runnerspool to run this callback on
 
99
 
 
100
        """
 
101
 
48
102
        what = what.upper()
 
103
 
49
104
        # get the plugin this callback was registered from
50
 
        plugname = calledfrom(sys._getframe())
 
105
        plugname = calledfrom(sys._getframe(0))
 
106
 
 
107
        # check if plugname is in loadlist .. if not don't add callback
 
108
        if config['loadlist'] and not plugname in config['loadlist']:
 
109
            rlog(-1, plugname, 'not in loadlist .. not adding callback')
 
110
            return
 
111
 
51
112
        # see if kwargs is set if not init to {}
52
113
        if not kwargs:
53
114
            kwargs = {}
 
115
 
54
116
        # add callback to the dict of lists
55
117
        if nr != False:
56
 
            self.cbs.insert(nr, what, Callback(func, prereq, plugname, \
57
 
kwargs, threaded))
 
118
            self.cbs.insert(nr, what, Callback(func, prereq, plugname, kwargs, threaded, speed))
58
119
        else:
59
 
            self.cbs.add(what, Callback(func, prereq, plugname, kwargs, \
60
 
threaded))
61
 
        rlog(-3, 'callbacks', 'added %s (%s)' % (what, plugname))
62
 
 
63
 
    def unload(self, plug):
64
 
        """ unload plugin """
 
120
            self.cbs.add(what, Callback(func, prereq, plugname, kwargs, threaded, speed))
 
121
 
 
122
        rlog(0, 'callbacks', 'added %s (%s)' % (what, plugname))
 
123
 
 
124
    def unload(self, plugname):
 
125
 
 
126
        """ unload all callbacks registered in a plugin. """
 
127
 
65
128
        unload = []
 
129
 
66
130
        # look for all callbacks in a plugin
67
131
        for name, cblist in self.cbs.iteritems():
68
132
            index = 0
69
133
            for item in cblist:
70
 
                if item.plugname == plug:
 
134
                if item.plugname == plugname:
71
135
                    unload.append((name, index))
72
136
                index += 1
 
137
 
73
138
        # delete callbacks
74
139
        for callback in unload[::-1]:
75
140
            self.cbs.delete(callback[0], callback[1])
76
141
            rlog(1, 'callbacks', 'unloaded %s' % callback[0])
77
142
 
78
 
    def whereis(self, what):
 
143
    def disable(self, plugname):
 
144
 
 
145
        """ disable all callbacks registered in a plugin. """
 
146
 
 
147
        unload = []
 
148
 
 
149
        # look for all callbacks in a plugin
 
150
        for name, cblist in self.cbs.iteritems():
 
151
            index = 0
 
152
            for item in cblist:
 
153
                if item.plugname == plugname:
 
154
                    item.activate = False
 
155
 
 
156
    def activate(self, plugname):
 
157
 
 
158
        """ activate all callbacks registered in a plugin. """
 
159
 
 
160
        unload = []
 
161
 
 
162
        # look for all callbacks in a plugin
 
163
        for name, cblist in self.cbs.iteritems():
 
164
            index = 0
 
165
            for item in cblist:
 
166
                if item.plugname == plugname:
 
167
                    item.activate = True
 
168
 
 
169
    def whereis(self, cmnd):
 
170
 
79
171
        """ show where ircevent.CMND callbacks are registered """
 
172
 
80
173
        result = []
81
 
        what = what.upper()
82
 
        for cmnd, callback in self.cbs.iteritems():
83
 
            if cmnd == what:
 
174
        cmnd = cmnd.upper()
 
175
 
 
176
        # locate callbacks for CMND
 
177
        for c, callback in self.cbs.iteritems():
 
178
            if c == cmnd:
84
179
                for item in callback:
85
180
                    if not item.plugname in result:
86
181
                        result.append(item.plugname)
87
 
        return result
88
 
 
89
 
class Botcallbacks(Callbacks):
90
 
 
91
 
    """ callback on ircevent """
92
 
 
93
 
    def check(self, bot, ievent):
94
 
        """ check for callbacks to be fired """
95
 
        # check for "ALL" callbacks
96
 
        if self.cbs.has_key('ALL'):
97
 
            for cb in self.cbs['ALL']:
98
 
                self.callback(cb, bot, ievent)
99
 
        cmnd = ievent.cmnd.upper()
100
 
        # check for CMND callbacks
101
 
        if self.cbs.has_key(cmnd):
102
 
            for cb in self.cbs[cmnd]:
103
 
                self.callback(cb, bot, ievent)
104
 
 
105
 
    def callback(self, cb, bot, ievent):
106
 
        """ callback cb with bot and ievent as arguments """
107
 
        if not bot:
108
 
            return
109
 
        if ievent.nick and ievent.nick == bot.nick:
110
 
            return
111
 
        try:
112
 
            # set ievent bot and socket
113
 
            try:
114
 
                ievent.bot = bot
115
 
                ievent.sock = bot.sock
116
 
                makeargrest(ievent)
117
 
            except:
118
 
                pass
119
 
            # see if the callback pre requirement succeeds
120
 
            if cb.prereq:
121
 
                rlog(-10, 'callback', 'excecuting in loop %s' % \
122
 
str(cb.prereq))
123
 
                if not cb.prereq(bot, ievent):
124
 
                    return
125
 
            # check if callback function is there
126
 
            if not cb.func:
127
 
                return
128
 
            # start callback in its own thread
129
 
            rlog(-10, 'callback', 'excecuting callback %s' % \
130
 
str(cb.func))
131
 
            if cb.threaded:
132
 
                start_new_thread(cb.func, (bot, ievent), cb.kwargs)
133
 
            else:
134
 
                runner.put("cb-%s" % cb.plugname, cb.func, bot, ievent, \
135
 
**cb.kwargs)
136
 
                #cb.func(bot, ievent, **cb.kwargs)
137
 
        except Exception, ex:
138
 
            handle_exception()
139
 
 
140
 
class Jabbercallbacks(Callbacks):
141
 
 
142
 
    """ callback on ircevent """
143
 
 
144
 
    def check(self, bot, ievent):
145
 
        """ check for callbacks to be fired """
146
 
        # check for "ALL" callbacks
147
 
        if self.cbs.has_key('ALL'):
148
 
            for cb in self.cbs['ALL']:
149
 
                self.callback(cb, bot, ievent)
150
 
        cmnd = ievent.cmnd.upper()
151
 
        # check for CMND callbacks
152
 
        if self.cbs.has_key(cmnd):
153
 
            for cb in self.cbs[cmnd]:
154
 
                self.callback(cb, bot, ievent)
155
 
 
156
 
    def callback(self, cb, bot, ievent):
157
 
        """ callback cb with bot and ievent as arguments """
158
 
        if not bot:
159
 
            return
160
 
        if str(bot.jid) in str(ievent.getFrom()):
161
 
            return
162
 
        try:
163
 
            # see if the callback pre requirement succeeds
164
 
            if cb.prereq:
165
 
                rlog(-10, 'callback', 'excecuting in loop %s' % \
166
 
str(cb.prereq))
167
 
                if not cb.prereq(bot, ievent):
168
 
                    return
169
 
            # check if callback function is there
170
 
            if not cb.func:
171
 
                return
172
 
            # start callback in its own thread
173
 
            rlog(-10, 'callback', 'excecuting callback %s' % \
174
 
str(cb.func))
175
 
            if cb.threaded:
176
 
                start_new_thread(cb.func, (bot, ievent), cb.kwargs)
177
 
            else:
178
 
                runner.put("cb-%s" % cb.plugname, cb.func, bot, ievent, \
179
 
**cb.kwargs)
180
 
                #cb.func(bot, ievent, **cb.kwargs)
181
 
        except Exception, ex:
182
 
            handle_exception()
183
 
 
184
 
callbacks = Botcallbacks()
185
 
jcallbacks = Jabbercallbacks()
 
182
 
 
183
        return result
 
184
 
 
185
    def list(self):
 
186
 
 
187
        """ show all callbacks. """
 
188
 
 
189
        result = []
 
190
 
 
191
        # loop over callbacks and collect callback functions
 
192
        for cmnd, callbacks in self.cbs.iteritems():
 
193
            for cb in callbacks:
 
194
                result.append(getname(cb.func))
 
195
 
 
196
        return result
 
197
 
 
198
    def check(self, bot, ievent):
 
199
 
 
200
        """ 
 
201
            check for callbacks to be fired. 
 
202
 
 
203
            :param bot: bot where event originates from
 
204
            :param ievent: event that needs to be checked
 
205
 
 
206
            .. literalinclude:: ../../gozerbot/callbacks.py
 
207
                :pyobject: Callbacks.check
 
208
 
 
209
        """
 
210
 
 
211
        # check for "ALL" callbacks
 
212
        if self.cbs.has_key('ALL'):
 
213
            for cb in self.cbs['ALL']:
 
214
                stats.up('callbacks', 'ALL')
 
215
                self.callback(cb, bot, ievent)
 
216
 
 
217
        cmnd = ievent.cmnd.upper()
 
218
 
 
219
        # check for CMND callbacks
 
220
        if self.cbs.has_key(cmnd):
 
221
            for cb in self.cbs[cmnd]:
 
222
                stats.up('callbacks', cmnd)
 
223
                self.callback(cb, bot, ievent)
 
224
 
 
225
    def callback(self, cb, bot, ievent):
 
226
 
 
227
        """ 
 
228
            do the actual callback with provided bot and ievent as arguments.
 
229
 
 
230
            :param cb: the callback to fire
 
231
            :param bot: bot to call the callback on
 
232
            :param ievent: the ievent that triggered the callback
 
233
 
 
234
            .. literalinclude:: ../../gozerbot/callbacks.py
 
235
                :pyobject: Callbacks.callback
 
236
 
 
237
        """
 
238
 
 
239
        try:
 
240
            if not cb.activate:
 
241
                return
 
242
            # see if the callback pre requirement succeeds
 
243
            if cb.prereq:
 
244
                rlog(0, 'callbacks', 'excecuting in loop %s' % str(cb.prereq))
 
245
                if not cb.prereq(bot, ievent):
 
246
                    return
 
247
 
 
248
            # check if callback function is there
 
249
            if not cb.func:
 
250
                return
 
251
 
 
252
            # log and stats
 
253
            rlog(0, 'callbacks', 'excecuting callback %s' % str(cb.func))
 
254
            stats.up('callbacks', getname(cb.func))
 
255
            stats.up('callbacks', cb.plugname)
 
256
 
 
257
            # launcn the callback .. either threaded or dispatched at runners
 
258
            if cb.threaded:
 
259
                start_new_thread(cb.func, (bot, ievent), cb.kwargs)
 
260
            else:
 
261
                cbrunners[10-cb.speed].put("cb-%s" % cb.plugname, cb.func, bot, ievent, **cb.kwargs)
 
262
 
 
263
        except Exception, ex:
 
264
            handle_exception()
 
265
 
 
266
# INIT SECTION
 
267
 
 
268
# callbacks object is the same for ICR and Jabber
 
269
callbacks = jcallbacks = Callbacks()
 
270
 
 
271
# END INIT