/usr/share/pyshared/jsb/lib/eventbase.py is in jsonbot 0.84.4-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | # jsb/lib/eventbase.py
#
#
""" base class of all events. """
## jsb imports
from channelbase import ChannelBase
from jsb.utils.lazydict import LazyDict
from jsb.utils.generic import splittxt, stripped, waitforqueue
from errors import NoSuchUser, NoSuchCommand, RequireError
from jsb.utils.opts import makeeventopts
from jsb.utils.trace import whichmodule
from jsb.utils.exception import handle_exception
from jsb.utils.locking import lockdec
from jsb.lib.config import Config, getmainconfig
from jsb.lib.users import getusers
from jsb.lib.commands import cmnds
from jsb.lib.floodcontrol import floodcontrol
## basic imports
from collections import deque
from xml.sax.saxutils import unescape
import copy
import logging
import Queue
import types
import socket
import threading
import time
import thread
import urllib
import uuid
## defines
cpy = copy.deepcopy
lock = thread.allocate_lock()
locked = lockdec(lock)
## classes
class EventBase(LazyDict):
""" basic event class. """
def __init__(self, input={}, bot=None):
LazyDict.__init__(self)
if bot: self.bot = bot
self.ctime = time.time()
self.speed = self.speed or 5
self.nrout = self.nrout or 0
if input: self.copyin(input)
if not self.token: self.setup()
def copyin(self, eventin):
""" copy in an event. """
self.update(eventin)
return self
def setup(self):
self.token = self.token or str(uuid.uuid4().hex)
self.finished = threading.Condition()
self.busy = deque()
self.inqueue = deque()
self.outqueue = deque()
self.resqueue = deque()
self.ok = threading.Event()
return self
def __deepcopy__(self, a):
""" deepcopy an event. """
e = EventBase(self)
return e
def launched(self):
logging.info(str(self))
self.ok.set()
def startout(self):
if not self.nodispatch and not self.token in self.busy: self.busy.append(self.token)
def ready(self, what=None, force=False):
""" signal the event as ready - push None to all queues. """
if self.nodispatch: return
if not "TICK" in self.cbtype: logging.info(self.busy)
try: self.busy.remove(self.token)
except ValueError: pass
if not self.busy or force: self.notify()
def notify(self, p=None):
self.finished.acquire()
self.finished.notifyAll()
self.finished.release()
if not "TICK" in self.cbtype: logging.info("notified %s" % str(self))
def execwait(self, direct=False):
from jsb.lib.commands import cmnds
e = self.bot.put(self)
if e: return e.wait()
else: logging.info("no response for %s" % self.txt) ; return
logging.info("%s wont dispatch" % self.txt)
def wait(self, nr=1000):
nr = int(nr)
result = []
#if self.nodispatch: return
if not self.busy: self.startout()
self.finished.acquire()
while nr > 0 and (self.busy and not self.dostop): self.finished.wait(0.1) ; nr -= 100
self.finished.release()
if self.wait and self.thread: logging.warn("joining thread %s" % self.thread) ; self.thread.join(nr/1000)
if not "TICK" in self.cbtype: logging.info(self.busy)
if not self.resqueue: res = waitforqueue(self.resqueue, nr)
else: res = self.resqueue
return list(res)
def waitandout(self, nr=1000):
res = self.wait(nr)
if res:
for r in res: self.reply(r)
def execute(self, direct=False, *args, **kwargs):
""" dispatch event onto the cmnds object. this method needs both event.nodispatch = False amd event.iscommand = True set. """
logging.debug("execute %s" % self.cbtype)
from jsb.lib.commands import cmnds
res = self
self.startout()
self.bind(self.bot, force=True, dolog=True)
if not self.pipelined and ' ! ' in self.txt: res = self.dopipe(direct, *args, **kwargs)
else:
try: res = cmnds.dispatch(self.bot, self, direct=direct, *args, **kwargs)
except RequireError, ex: logging.error(str(ex))
except NoSuchCommand, ex: logging.error("we don't have a %s command" % str(ex))
except NoSuchUser, ex: logging.error("we don't have user for %s" % str(ex))
except Exception , ex: handle_exception()
return res
def dopipe(self, direct=False, *args, **kwargs):
""" split cmnds, create events for them, chain the queues and dispatch. """
direct = True
logging.warn("starting pipeline")
origout = self.outqueue
events = []
self.pipelined = True
splitted = self.txt.split(" ! ")
for i in range(len(splitted)):
t = splitted[i].strip()
if not t: continue
if t[0] != ";": t = ";" + t
e = self.bot.make_event(self.userhost, self.channel, t)
e.outqueue = deque()
e.busy = deque()
e.prev = None
e.pipelined = True
e.dontbind = False
if not e.woulddispatch(): raise NoSuchCommand(e.txt)
events.append(e)
prev = None
for i in range(len(events)):
if i > 0:
events[i].inqueue = events[i-1].outqueue
events[i].prev = events[i-1]
events[-1].pipelined = False
events[-1].dontclose = False
for i in range(len(events)):
if not self.bot.isgae and not direct: self.bot.put(events[i])
else: events[i].execute(direct)
return events[-1]
def prepare(self, bot=None):
""" prepare the event for dispatch. """
if bot: self.bot = bot or self.bot
assert(self.bot)
self.origin = self.channel
self.bloh()
self.makeargs()
if not self.nolog: logging.debug("%s - prepared event - %s" % (self.auth, self.cbtype))
return self
def bind(self, bot=None, user=None, chan=None, force=False, dolog=None):
""" bind event.bot event.user and event.chan to execute a command on it. """
#if self.nodispatch: logging.debug("nodispatch is set on event . .not binding"); return
dolog = dolog or 'TICK' not in self.cbtype
if dolog and not force and self.dontbind: logging.debug("dontbind is set on event . .not binding"); return
if not force and self.bonded and (bot and not bot.isgae): logging.debug("already bonded") ; return
dolog and logging.debug("starting bind on %s - %s" % (self.userhost, self.txt))
target = self.auth or self.userhost
bot = bot or self.bot
if not self.chan:
if chan: self.chan = chan
elif self.channel: self.chan = ChannelBase(self.channel, bot.cfg.name)
elif self.userhost: self.chan = ChannelBase(self.userhost, bot.cfg.name)
if self.chan:
#self.debug = self.chan.data.debug or False
dolog and logging.debug("channel bonded - %s" % self.chan.data.id)
self.prepare(bot)
if not target: self.bonded = True ; return
if not self.user and target and not self.nodispatch:
if user: u = user
else: u = bot.users.getuser(target)
if not u:
cfg = getmainconfig()
if cfg.auto_register and self.iscommand:
u = bot.users.addguest(target, self.nick)
if u: logging.warn("auto_register applied")
else: logging.error("can't add %s to users database" % target)
if u:
msg = "!! %s -=- %s -=- %s -=- (%s) !!" % (u.data.name, self.usercmnd or "none", self.cbtype, self.bot.cfg.name)
dolog and logging.warn(msg)
self.user = u
if self.user: dolog and logging.debug("user bonded from %s" % whichmodule())
if not self.user and target: dolog and self.iscommand and logging.warn("no %s user found" % target) ; self.nodispatch = True
if self.bot: self.inchan = self.channel in self.bot.state.data.joinedchannels
self.bonded = True
return self
def bloh(self, bot=None, *args, **kwargs):
""" overload this. """
if not self.txt: return
self.bot = bot or self.bot
self.execstr = self.iscmnd()
if self.execstr:
self.usercmnd = self.execstr.split()[0]
self.nodispatch = False
self.iscommand = True
else: logging.debug("can't detect a command on %s (%s)" % (self.txt, self.cbtype))
def reply(self, txt, result=[], event=None, origin="", dot=u", ", nr=375, extend=0, showall=False, *args, **kwargs):
""" reply to this event """
try: target = self.channel or self.arguments[1]
except (IndexError, TypeError): target = self.channel or "nochannel"
if self.silent:
self.msg = True
self.bot.say(self.nick, txt, result, self.userhost, extend=extend, event=self, dot=dot, nr=nr, showall=showall, *args, **kwargs)
elif self.isdcc: self.bot.say(self.sock, txt, result, self.userhost, extend=extend, event=self, dot=dot, nr=nr, showall=showall, *args, **kwargs)
else: self.bot.say(target, txt, result, self.userhost, extend=extend, event=self, dot=dot, nr=nr, showall=showall, *args, **kwargs)
return self
def missing(self, txt):
""" display missing arguments. """
if self.alias: l = len(self.alias.split()) - 1
else: l = 0
t = ' '.join(txt.split()[l:])
self.reply("%s %s" % (self.aliased or self.usercmnd, t), event=self)
return self
def done(self):
""" tell the user we are done. """
self.reply('<b>done</b> - %s' % (self.usercmnd or self.alias or selt.txt), event=self)
return self
def leave(self):
""" lower the time to leave. """
self.ttl -= 1
if self.ttl <= 0 : self.status = "done"
def makeoptions(self):
""" check the given txt for options. """
try: self.options = makeeventopts(self.txt)
except: handle_exception() ; return
if not self.options: return
if self.options.channel: self.target = self.options.channel
logging.debug("options - %s" % unicode(self.options))
self.txt = ' '.join(self.options.args)
self.makeargs()
def makeargs(self):
""" make arguments and rest attributes from self.txt. """
if not self.execstr:
self.args = []
self.rest = ""
else:
args = self.execstr.split()
self.chantag = args[0]
if len(args) > 1:
self.args = args[1:]
self.rest = ' '.join(self.args)
else:
self.args = []
self.rest = ""
def makeresponse(self, txt, result, dot=u", ", *args, **kwargs):
""" create a response from a string and result list. """
return self.bot.makeresponse(txt, result, dot, *args, **kwargs)
def less(self, what, nr=365):
""" split up in parts of <nr> chars overflowing on word boundaries. """
return self.bot.less(what, nr)
def isremote(self):
""" check whether the event is off remote origin. """
return self.txt.startswith('{"') or self.txt.startswith("{&")
def iscmnd(self):
""" check if event is a command. """
if not self.txt: return ""
if not self.bot: return ""
if self.txt[0] in self.getcc(): return self.txt[1:]
matchnick = unicode(self.bot.cfg.nick + u":")
if self.txt.startswith(matchnick): return self.txt[len(matchnick):]
matchnick = unicode(self.bot.cfg.nick + u",")
if self.txt.startswith(matchnick): return self.txt[len(matchnick):]
if self.iscommand and self.execstr: return self.execstr
return ""
hascc = stripcc = iscmnd
def gotcc(self):
if not self.txt: return False
return self.txt[0] in self.getcc()
def getcc(self):
if self.chan: cc = self.chan.data.cc
else: cc = ""
if not cc:
cfg = getmainconfig()
if cfg.globalcc and not cfg.globalcc in cc: cc += cfg.globalcc
if not cc: cc = "!;"
if not ";" in cc: cc += ";"
logging.info("cc is %s" % cc)
return cc
def blocked(self):
return floodcontrol.checkevent(self)
def woulddispatch(self):
cmnds.reloadcheck(self.bot, self)
return cmnds.woulddispatch(self.bot, self)
def wouldmatchre(self):
return cmnds.wouldmatchre(self.bot, self)
|