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

« back to all changes in this revision

Viewing changes to build/lib/gozerbot/redispatcher.py

  • Committer: Package Import Robot
  • Author(s): Jeremy Malcolm
  • Date: 2012-04-03 21:58:28 UTC
  • mfrom: (3.1.11 sid)
  • Revision ID: package-import@ubuntu.com-20120403215828-6mik0tzug5na93la
Tags: 0.99.1-2
* Removes logfiles on purge (Closes: #668767)
* Reverted location of installed files back to /usr/lib/gozerbot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# gozerbot/redispatcher.py
 
2
#
 
3
#
 
4
 
 
5
""" implement RE (regular expression) dispatcher. """
 
6
 
 
7
__copyright__ = 'this file is in the public domain'
 
8
 
 
9
## IMPORT SECTION
 
10
 
 
11
# gozerbot imports
 
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
 
19
 
 
20
# basic imports
 
21
import sys, re, copy, types, thread
 
22
 
 
23
## END IMPORT
 
24
 
 
25
## LOCK SECTION
 
26
 
 
27
# locks
 
28
relock = thread.allocate_lock()
 
29
locked = lockdec(relock)
 
30
 
 
31
## END LOCK
 
32
 
 
33
class RECallback(object):
 
34
 
 
35
    """
 
36
         a regular expression callback.
 
37
 
 
38
         :param index: index into the callback list
 
39
         :type index: integer
 
40
         :param regex: the regex to match
 
41
         :type regex: string
 
42
         :param func: the callback function
 
43
         :type func: 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
 
47
         :type speed: integer
 
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
 
53
         :type options: dict
 
54
 
 
55
    """
 
56
 
 
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)
 
67
        else:
 
68
            self.perms = [perm, ]
 
69
        # plug name
 
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
 
75
        self.activate = True
 
76
 
 
77
class REDispatcher(object):
 
78
 
 
79
    """
 
80
        this is were the regexs callbacks live.
 
81
 
 
82
    """
 
83
 
 
84
    def __init__(self):
 
85
        self.relist = []
 
86
        
 
87
    def size(self):
 
88
 
 
89
        """
 
90
            nr of callbacks.
 
91
 
 
92
        """
 
93
 
 
94
        return len(self.relist)
 
95
 
 
96
    def activate(self, plugname):
 
97
        for i in self.relist:
 
98
            if i.plugname == plugname:
 
99
                i.activate = True
 
100
 
 
101
    def disable(self, plugname):
 
102
        for i in self.relist:
 
103
            if i.plugname == plugname:
 
104
                i.activate = False
 
105
 
 
106
    def whatperms(self):
 
107
 
 
108
        """
 
109
            return possible permissions.
 
110
 
 
111
            :rtype: list .. list of possible permissions
 
112
 
 
113
            .. literalinclude:: ../../gozerbot/redispatcher.py
 
114
                :pyobject: REDispatcher.whatperms
 
115
 
 
116
        """
 
117
 
 
118
        result = []
 
119
 
 
120
        for i in self.relist:
 
121
            for j in i.perms:
 
122
                if j not in result:
 
123
                    result.append(j)
 
124
 
 
125
        return result
 
126
 
 
127
    def list(self, perm):
 
128
 
 
129
        """
 
130
            list RECallbacks with permission perm.
 
131
 
 
132
            :param perm: permission to check for
 
133
            :type perm: string
 
134
            :rtype: list .. list of RECallbacks 
 
135
 
 
136
            .. literalinclude:: ../../gozerbot/redispatcher.py
 
137
                :pyobject: REDispatcher.list
 
138
        """
 
139
 
 
140
        result = []
 
141
        perm = perm.upper()
 
142
 
 
143
        for recom in self.relist:
 
144
            if perm in recom.perms:
 
145
                result.append(recom)
 
146
 
 
147
        return result
 
148
 
 
149
    def getfuncnames(self, plug):
 
150
 
 
151
        """
 
152
            return function names in plugin.
 
153
 
 
154
            :param plug: name of the plugin to get callbacks of
 
155
            :type plug: string
 
156
            :rtype: list .. list of function names
 
157
 
 
158
            .. literalinclude:: ../../gozerbot/redispatcher.py
 
159
                :pyobject: REDispatcher.getfuncnames
 
160
 
 
161
        """
 
162
 
 
163
        result = []
 
164
        for i in self.relist:
 
165
            if i.plugname == plug:
 
166
                result.append(i.func.func_name)
 
167
        return result
 
168
        
 
169
    def permoverload(self, funcname, perms):
 
170
 
 
171
        """
 
172
            overload permission of function with funcname.
 
173
 
 
174
            :param funcname: name of the function to overload
 
175
            :type funcname: string
 
176
            :param perms: permission to overload
 
177
            :type perms: list
 
178
            :rtype: boolean .. whether the overload succeeded
 
179
 
 
180
            .. literalinclude:: ../../gozerbot/redispatcher.py
 
181
                :pyobject: REDispatcher.permoverload
 
182
 
 
183
        """
 
184
 
 
185
        perms = [perm.upper() for perm in perms]
 
186
        got = 0
 
187
 
 
188
        for nr in range(len(self.relist)):
 
189
 
 
190
            try:
 
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' \
 
194
% (funcname, perms))
 
195
                    got = 1
 
196
 
 
197
            except AttributeError:
 
198
                rlog(10, 'redispatcher', 'permoverload: no %s function' % \
 
199
funcname)
 
200
        if got:
 
201
            return True
 
202
 
 
203
        return False
 
204
 
 
205
    def add(self, index, regex, func, perm, speed=5, threaded=True, allowqueue=True, options={}):
 
206
 
 
207
        """
 
208
            add a regular expression command.
 
209
 
 
210
           :param index: index into the callback list
 
211
           :type index: integer
 
212
           :param regex: the regex to match
 
213
           :type regex: string
 
214
           :param func: the callback function
 
215
           :type func: 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
 
219
           :type speed: integer
 
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
 
225
           :type options: dict
 
226
 
 
227
           .. literalinclude:: ../../gozerbot/redispatcher.py
 
228
               :pyobject: REDispatcher.add
 
229
 
 
230
        """
 
231
 
 
232
        try:
 
233
            # get plugin name from where callback is added
 
234
            plugname = calledfrom(sys._getframe())
 
235
 
 
236
            if config['loadlist'] and plugname not in config['loadlist']:
 
237
                return
 
238
            # add Recallback
 
239
 
 
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))
 
245
 
 
246
        finally:
 
247
            pass
 
248
 
 
249
    def unload(self, plugname):
 
250
 
 
251
        """
 
252
            unload regex commands.
 
253
 
 
254
            :param plugname: name of the plugins to unload callbacks from
 
255
            :type plugname: string
 
256
            :rtype: boolean .. whether the unloading succeeded
 
257
 
 
258
            .. literalinclude:: ../../gozerbot/redispatcher.py
 
259
                :pyobject: REDispatcher.unload
 
260
 
 
261
        """
 
262
 
 
263
        got = False
 
264
        try:
 
265
 
 
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))
 
270
                    del self.relist[i]
 
271
                    got = True
 
272
        finally:    
 
273
            pass
 
274
        return got
 
275
 
 
276
    def getcallback(self, txt):
 
277
 
 
278
        """
 
279
            get re callback if txt matches.
 
280
 
 
281
            :param txt: txt to match against the regular expressions
 
282
            :type txt: string
 
283
 
 
284
            .. literalinclude:: ../../gozerbot/redispatcher.py
 
285
                :pyobject: REDispatcher.getcallback
 
286
        """
 
287
 
 
288
        for i in self.relist:
 
289
 
 
290
            try:
 
291
                result = re.search(i.compiled, txt)
 
292
 
 
293
                if result:
 
294
                    return i
 
295
 
 
296
            except:
 
297
                pass
 
298
 
 
299
    def dispatch(self, callback, txt, wait=False):
 
300
 
 
301
        """
 
302
            try to dispatch callback on txt.
 
303
 
 
304
            :param callback: the callback to fire
 
305
            :type callback: RECallback
 
306
            :param txt: txt to match the regular expression
 
307
            :type txt: string
 
308
            :param wait: whether to wait for the result
 
309
            :type wait: boolean
 
310
 
 
311
            .. literalinclude:: ../../gozerbot/redispatcher.py
 
312
                :pyobject: REDispatcher.dispatch
 
313
 
 
314
        """
 
315
 
 
316
        try:
 
317
            result = re.search(callback.compiled, txt)
 
318
 
 
319
            if result:
 
320
 
 
321
                if callback.threaded:
 
322
                    thread = thr.start_new_thread(callback.func, (txt, result.groups()))
 
323
 
 
324
                    if wait:
 
325
                        thread.join()
 
326
 
 
327
                else:
 
328
                    cmndrunners.put(callback.plugname, callback.func, txt, \
 
329
result.groups())
 
330
 
 
331
                    return 1
 
332
 
 
333
        except Exception, ex:
 
334
            handle_exception()
 
335
 
 
336
class BotREDispatcher(REDispatcher):
 
337
 
 
338
    """
 
339
        dispatcher on Event.
 
340
 
 
341
    """
 
342
 
 
343
    def dispatch(self, callback, bot, ievent, wait=False):
 
344
 
 
345
        """
 
346
            dispatch callback on ircevent.
 
347
 
 
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
 
355
 
 
356
            .. literalinclude:: ../../gozerbot/redispatcher.py
 
357
                :pyobject: BotREDispatcher.dispatch
 
358
 
 
359
        """
 
360
 
 
361
        if not self.activate:
 
362
            return False
 
363
 
 
364
        try:
 
365
            result = re.search(callback.compiled, ievent.txt.strip())
 
366
 
 
367
            if result:
 
368
                ievent.groups = list(result.groups())                
 
369
 
 
370
                if callback.threaded or ievent.threaded:
 
371
                    thread = thr.start_bot_command(callback.func, (bot, ievent))
 
372
 
 
373
                    if thread and wait:
 
374
                        thread.join()
 
375
 
 
376
                else:
 
377
                    cmndrunners.put(callback.plugname, callback.func, bot, \
 
378
ievent)
 
379
                return True
 
380
 
 
381
        except Exception, ex:
 
382
            handle_exception(ievent)
 
383
 
 
384
        return False
 
385
 
 
386
## INIT SECTION
 
387
 
 
388
# dispatcher before commands are checked
 
389
rebefore = BotREDispatcher()
 
390
 
 
391
# dispatcher after commands are checked
 
392
reafter = BotREDispatcher()
 
393
 
 
394
## END INIT