1
# gozerbot/redispatcher.py
5
""" implement RE (regular expression) dispatcher. """
7
__copyright__ = 'this file is in the public domain'
12
from config import config
13
from utils.log import rlog
14
from utils.trace import calledfrom
15
from utils.exception import handle_exception
16
from utils.locking import lockdec
17
from runner import cmndrunners
18
import threads.thr as thr
21
import sys, re, copy, types, thread
28
relock = thread.allocate_lock()
29
locked = lockdec(relock)
33
class RECallback(object):
36
a regular expression callback.
38
:param index: index into the callback list
40
:param regex: the regex to match
42
:param func: the callback function
44
:param perm: permissions of the callback
45
:type perm: list .. list of permissions
46
:param speed: speed at which the callback should be executed
48
:param threaded: whether the callback should executed in its own thread
49
:type threaded: boolean
50
:param allowqueue: whether this command is allowed in pipelines
51
:type allowqueue: boolean
52
:param options: options allowed for this command
57
def __init__(self, index, regex, func, perm, plugname, speed=5, \
58
threaded=True, allowqueue=True, options={}):
59
self.name = thr.getname(func) # name of the callback
60
self.index = index # index into the list
61
self.regex = regex # the RE to match
62
self.compiled = re.compile(regex) # compiled RE
63
self.func = func # the function to call if RE matches
64
# make sure perms is a list
65
if type(perm) == types.ListType:
66
self.perms = list(perm)
70
self.plugname = plugname # plugname where RE callbacks is registered
71
self.speed = copy.deepcopy(speed) # speed at which the function runs
72
self.threaded = copy.deepcopy(threaded) # set when run threaade
73
self.allowqueue = copy.deepcopy(allowqueue) # set when pipeline is allowed
74
self.options = dict(options) # options set on the callback
77
class REDispatcher(object):
80
this is were the regexs callbacks live.
94
return len(self.relist)
96
def activate(self, plugname):
98
if i.plugname == plugname:
101
def disable(self, plugname):
102
for i in self.relist:
103
if i.plugname == plugname:
109
return possible permissions.
111
:rtype: list .. list of possible permissions
113
.. literalinclude:: ../../gozerbot/redispatcher.py
114
:pyobject: REDispatcher.whatperms
120
for i in self.relist:
127
def list(self, perm):
130
list RECallbacks with permission perm.
132
:param perm: permission to check for
134
:rtype: list .. list of RECallbacks
136
.. literalinclude:: ../../gozerbot/redispatcher.py
137
:pyobject: REDispatcher.list
143
for recom in self.relist:
144
if perm in recom.perms:
149
def getfuncnames(self, plug):
152
return function names in plugin.
154
:param plug: name of the plugin to get callbacks of
156
:rtype: list .. list of function names
158
.. literalinclude:: ../../gozerbot/redispatcher.py
159
:pyobject: REDispatcher.getfuncnames
164
for i in self.relist:
165
if i.plugname == plug:
166
result.append(i.func.func_name)
169
def permoverload(self, funcname, perms):
172
overload permission of function with funcname.
174
:param funcname: name of the function to overload
175
:type funcname: string
176
:param perms: permission to overload
178
:rtype: boolean .. whether the overload succeeded
180
.. literalinclude:: ../../gozerbot/redispatcher.py
181
:pyobject: REDispatcher.permoverload
185
perms = [perm.upper() for perm in perms]
188
for nr in range(len(self.relist)):
191
if self.relist[nr].func.func_name == funcname:
192
self.relist[nr].perms = list(perms)
193
rlog(0, 'redispatcher', '%s function overloaded with %s' \
197
except AttributeError:
198
rlog(10, 'redispatcher', 'permoverload: no %s function' % \
205
def add(self, index, regex, func, perm, speed=5, threaded=True, allowqueue=True, options={}):
208
add a regular expression command.
210
:param index: index into the callback list
212
:param regex: the regex to match
214
:param func: the callback function
216
:param perm: permissions of the callback
217
:type perm: list .. list of permissions
218
:param speed: speed at which the callback should be executed
220
:param threaded: whether the callback should executed in its own thread
221
:type threaded: boolean
222
:param allowqueue: whether this command is allowed in pipelines
223
:type allowqueue: boolean
224
:param options: options allowed for this command
227
.. literalinclude:: ../../gozerbot/redispatcher.py
228
:pyobject: REDispatcher.add
233
# get plugin name from where callback is added
234
plugname = calledfrom(sys._getframe())
236
if config['loadlist'] and plugname not in config['loadlist']:
240
self.relist.append(RECallback(index, regex, func, perm, plugname, \
241
speed, threaded, allowqueue, options))
242
# sort of index number
243
self.relist.sort(lambda a, b: cmp(a.index, b.index))
244
rlog(0, 'redispatcher', 'added %s (%s) ' % (regex, plugname))
249
def unload(self, plugname):
252
unload regex commands.
254
:param plugname: name of the plugins to unload callbacks from
255
:type plugname: string
256
:rtype: boolean .. whether the unloading succeeded
258
.. literalinclude:: ../../gozerbot/redispatcher.py
259
:pyobject: REDispatcher.unload
266
for i in range(len(self.relist)-1, -1 , -1):
267
if self.relist[i].plugname == plugname:
268
rlog(1, 'redispatcher', 'unloading %s (%s)' % \
269
(self.relist[i].regex, plugname))
276
def getcallback(self, txt):
279
get re callback if txt matches.
281
:param txt: txt to match against the regular expressions
284
.. literalinclude:: ../../gozerbot/redispatcher.py
285
:pyobject: REDispatcher.getcallback
288
for i in self.relist:
291
result = re.search(i.compiled, txt)
299
def dispatch(self, callback, txt, wait=False):
302
try to dispatch callback on txt.
304
:param callback: the callback to fire
305
:type callback: RECallback
306
:param txt: txt to match the regular expression
308
:param wait: whether to wait for the result
311
.. literalinclude:: ../../gozerbot/redispatcher.py
312
:pyobject: REDispatcher.dispatch
317
result = re.search(callback.compiled, txt)
321
if callback.threaded:
322
thread = thr.start_new_thread(callback.func, (txt, result.groups()))
328
cmndrunners.put(callback.plugname, callback.func, txt, \
333
except Exception, ex:
336
class BotREDispatcher(REDispatcher):
343
def dispatch(self, callback, bot, ievent, wait=False):
346
dispatch callback on ircevent.
348
:param callback: the callback to fire
349
:type callback: RECallback
350
:param bot: the bot on which the callback was triggered
351
:type bot: gozerbot.botbase.BotBase
352
:param ievent: the event that triggered the callback
353
:type ievent: gozerbot.eventbase.EventBase
354
:rtype: boolean .. whether the dispatch was succesful
356
.. literalinclude:: ../../gozerbot/redispatcher.py
357
:pyobject: BotREDispatcher.dispatch
361
if not self.activate:
365
result = re.search(callback.compiled, ievent.txt.strip())
368
ievent.groups = list(result.groups())
370
if callback.threaded or ievent.threaded:
371
thread = thr.start_bot_command(callback.func, (bot, ievent))
377
cmndrunners.put(callback.plugname, callback.func, bot, \
381
except Exception, ex:
382
handle_exception(ievent)
388
# dispatcher before commands are checked
389
rebefore = BotREDispatcher()
391
# dispatcher after commands are checked
392
reafter = BotREDispatcher()