5
""" callbacks triggered by ircevent CMND """
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
7
13
__copyright__ = 'this file is in the public domain'
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
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
31
import sys, copy, thread
38
callbacklock = thread.allocate_lock()
39
locked = lockdec(callbacklock)
16
43
class Callback(object):
18
""" class representing a callback """
20
def __init__(self, func, prereq, plugname, kwargs, threaded=False):
21
# the callback function
23
# pre condition function
26
self.plugname = plugname
27
# kwargs to pass on to function
29
# flag to see if callback has to run in thread or in the mainloop
30
self.threaded = copy.deepcopy(threaded)
46
class representing a callback.
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
57
def __init__(self, func, prereq, plugname, kwargs, threaded=False, \
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
66
stats.up('callbacks', 'created')
32
68
class Callbacks(object):
34
""" dict of lists containing callbacks """
71
dict of lists containing callbacks. Callbacks object take care of
72
dispatching the callbacks based on incoming events. see Callbacks.check()
36
76
def __init__(self):
37
# cbs are the callbacks which is a dict of lists .. 1 list per
78
# self.cbs holds the dict of list. entry value is the event (string)
42
""" return nr of callbacks """
83
""" return number of callbacks. """
43
85
return len(self.cbs)
45
def add(self, what, func, prereq=None, kwargs=None, threaded=False, \
47
""" add a callback """
87
def add(self, what, func, prereq=None, kwargs=None, threaded=False, nr=False, speed=5):
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
48
102
what = what.upper()
49
104
# get the plugin this callback was registered from
50
plugname = calledfrom(sys._getframe())
105
plugname = calledfrom(sys._getframe(0))
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')
51
112
# see if kwargs is set if not init to {}
54
116
# add callback to the dict of lists
56
self.cbs.insert(nr, what, Callback(func, prereq, plugname, \
118
self.cbs.insert(nr, what, Callback(func, prereq, plugname, kwargs, threaded, speed))
59
self.cbs.add(what, Callback(func, prereq, plugname, kwargs, \
61
rlog(-3, 'callbacks', 'added %s (%s)' % (what, plugname))
63
def unload(self, plug):
120
self.cbs.add(what, Callback(func, prereq, plugname, kwargs, threaded, speed))
122
rlog(0, 'callbacks', 'added %s (%s)' % (what, plugname))
124
def unload(self, plugname):
126
""" unload all callbacks registered in a plugin. """
66
130
# look for all callbacks in a plugin
67
131
for name, cblist in self.cbs.iteritems():
69
133
for item in cblist:
70
if item.plugname == plug:
134
if item.plugname == plugname:
71
135
unload.append((name, index))
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])
78
def whereis(self, what):
143
def disable(self, plugname):
145
""" disable all callbacks registered in a plugin. """
149
# look for all callbacks in a plugin
150
for name, cblist in self.cbs.iteritems():
153
if item.plugname == plugname:
154
item.activate = False
156
def activate(self, plugname):
158
""" activate all callbacks registered in a plugin. """
162
# look for all callbacks in a plugin
163
for name, cblist in self.cbs.iteritems():
166
if item.plugname == plugname:
169
def whereis(self, cmnd):
79
171
""" show where ircevent.CMND callbacks are registered """
82
for cmnd, callback in self.cbs.iteritems():
176
# locate callbacks for CMND
177
for c, callback in self.cbs.iteritems():
84
179
for item in callback:
85
180
if not item.plugname in result:
86
181
result.append(item.plugname)
89
class Botcallbacks(Callbacks):
91
""" callback on ircevent """
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)
105
def callback(self, cb, bot, ievent):
106
""" callback cb with bot and ievent as arguments """
109
if ievent.nick and ievent.nick == bot.nick:
112
# set ievent bot and socket
115
ievent.sock = bot.sock
119
# see if the callback pre requirement succeeds
121
rlog(-10, 'callback', 'excecuting in loop %s' % \
123
if not cb.prereq(bot, ievent):
125
# check if callback function is there
128
# start callback in its own thread
129
rlog(-10, 'callback', 'excecuting callback %s' % \
132
start_new_thread(cb.func, (bot, ievent), cb.kwargs)
134
runner.put("cb-%s" % cb.plugname, cb.func, bot, ievent, \
136
#cb.func(bot, ievent, **cb.kwargs)
137
except Exception, ex:
140
class Jabbercallbacks(Callbacks):
142
""" callback on ircevent """
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)
156
def callback(self, cb, bot, ievent):
157
""" callback cb with bot and ievent as arguments """
160
if str(bot.jid) in str(ievent.getFrom()):
163
# see if the callback pre requirement succeeds
165
rlog(-10, 'callback', 'excecuting in loop %s' % \
167
if not cb.prereq(bot, ievent):
169
# check if callback function is there
172
# start callback in its own thread
173
rlog(-10, 'callback', 'excecuting callback %s' % \
176
start_new_thread(cb.func, (bot, ievent), cb.kwargs)
178
runner.put("cb-%s" % cb.plugname, cb.func, bot, ievent, \
180
#cb.func(bot, ievent, **cb.kwargs)
181
except Exception, ex:
184
callbacks = Botcallbacks()
185
jcallbacks = Jabbercallbacks()
187
""" show all callbacks. """
191
# loop over callbacks and collect callback functions
192
for cmnd, callbacks in self.cbs.iteritems():
194
result.append(getname(cb.func))
198
def check(self, bot, ievent):
201
check for callbacks to be fired.
203
:param bot: bot where event originates from
204
:param ievent: event that needs to be checked
206
.. literalinclude:: ../../gozerbot/callbacks.py
207
:pyobject: Callbacks.check
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)
217
cmnd = ievent.cmnd.upper()
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)
225
def callback(self, cb, bot, ievent):
228
do the actual callback with provided bot and ievent as arguments.
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
234
.. literalinclude:: ../../gozerbot/callbacks.py
235
:pyobject: Callbacks.callback
242
# see if the callback pre requirement succeeds
244
rlog(0, 'callbacks', 'excecuting in loop %s' % str(cb.prereq))
245
if not cb.prereq(bot, ievent):
248
# check if callback function is there
253
rlog(0, 'callbacks', 'excecuting callback %s' % str(cb.func))
254
stats.up('callbacks', getname(cb.func))
255
stats.up('callbacks', cb.plugname)
257
# launcn the callback .. either threaded or dispatched at runners
259
start_new_thread(cb.func, (bot, ievent), cb.kwargs)
261
cbrunners[10-cb.speed].put("cb-%s" % cb.plugname, cb.func, bot, ievent, **cb.kwargs)
263
except Exception, ex:
268
# callbacks object is the same for ICR and Jabber
269
callbacks = jcallbacks = Callbacks()