#!/usr/bin/python
+# vim: fileencoding=utf-8
# Erebus IRC bot - Author: John Runyon
# main startup code
numhandlers = {}
msghandlers = {}
chanhandlers = {}
+ exceptionhandlers = [] # list of (Exception_class, handler_function) tuples
users = {}
chans = {}
class User(object):
def __init__(self, nick, auth=None):
self.nick = nick
- self.auth = auth
+ if auth is None:
+ self.auth = None
+ else:
+ self.auth = auth.lower()
self.checklevel()
self.chans = []
self.glevel = 0
return self.glevel
+ def setlevel(self, level, savetodb=True):
+ if savetodb:
+ if level != 0:
+ c = main.query("REPLACE INTO users (auth, level) VALUES (%s, %s)", (self.auth, level))
+ else:
+ c = main.query("DELETE FROM users WHERE auth = %s", (self.auth,))
+ if c == 0: # no rows affected
+ c = True # is fine
+ if c:
+ self.glevel = level
+ return True
+ else:
+ return False
+ else:
+ self.glevel = level
+ return True
+
def join(self, chan):
if chan not in self.chans: self.chans.append(chan)
def part(self, chan):
return True
else:
return False
+ else:
+ self.levels[auth] = level
+ return True
def userjoin(self, user, level=None):
if user not in self.users: self.users.append(user)
def __repr__(self): return "<Channel %r>" % (self.name)
def __init__(self, cfg):
+ self.mustquit = None
+ self.starttime = time.time()
self.cfg = cfg
self.trigger = cfg.trigger
if os.name == "posix":
self.fdlist = []
def query(self, *args, **kwargs):
- if 'norecurse' in kwargs:
- norecurse = kwargs['norecurse']
- del kwargs['norecurse']
+ if 'noretry' in kwargs:
+ noretry = kwargs['noretry']
+ del kwargs['noretry']
else:
- norecurse = False
+ noretry = False
self.log("[SQL]", "?", "query(%s, %s)" % (', '.join([repr(i) for i in args]), ', '.join([str(key)+"="+repr(kwargs[key]) for key in kwargs])))
try:
return res
except MySQLdb.MySQLError as e:
self.log("[SQL]", "!", "MySQL error! %r" % (e))
- if not norecurse:
+ if not noretry:
dbsetup()
- return self.query(*args, norecurse=True, **kwargs)
+ return self.query(*args, noretry=True, **kwargs)
else:
raise e
+ def querycb(self, cb, *args, **kwargs):
+ def run_query():
+ cb(self.query(*args, **kwargs))
+ threading.Thread(target=run_query).start()
+
def newbot(self, nick, user, bind, authname, authpass, server, port, realname):
if bind is None: bind = ''
obj = bot.Bot(self, nick, user, bind, authname, authpass, server, port, realname)
return chan
def poll(self):
+ timeout_seconds = 30
if self.potype == "poll":
- return [fd for (fd, ev) in self.po.poll()]
+ pollres = self.po.poll(timeout_seconds * 1000)
+ return [fd for (fd, ev) in pollres]
elif self.potype == "select":
- return select.select(self.fdlist, [], [])[0]
+ return select.select(self.fdlist, [], [], timeout_seconds)[0]
def connectall(self):
for bot in self.bots.values():
def getuserbyauth(self, auth):
return [u for u in self.users.values() if u.auth == auth.lower()]
+ def getdb(self):
+ """Get a DB object. The object must be returned to the pool after us, using returndb()."""
+ return self.dbs.pop()
+
+ def returndb(self, db):
+ self.dbs.append(db)
+
#bind functions
def hook(self, word, handler):
try:
def getchanhook(self, chan):
return self.chanhandlers[chan]
+ def hookexception(self, exc, handler):
+ self.exceptionhandlers.append((exc, handler))
+ def unhookexception(self, exc, handler):
+ self.exceptionhandlers.remove((exc, handler))
+ def hasexceptionhook(self, exc):
+ return any((True for x,h in self.exceptionhandlers if isinstance(exc, x)))
+ def getexceptionhook(self, exc):
+ return (h for x,h in self.exceptionhandlers if isinstance(exc, x))
+
def dbsetup():
main.db = None
+ main.dbs = []
+ for i in range(cfg.get('erebus', 'num_db_connections', 2)-1):
+ main.dbs.append(MySQLdb.connect(host=cfg.dbhost, user=cfg.dbuser, passwd=cfg.dbpass, db=cfg.dbname, cursorclass=MySQLdb.cursors.DictCursor))
main.db = MySQLdb.connect(host=cfg.dbhost, user=cfg.dbuser, passwd=cfg.dbpass, db=cfg.dbname, cursorclass=MySQLdb.cursors.DictCursor)
def setup():
global cfg, main
- cfg = config.setup('bot.config')
+ cfg = config.Config('bot.config')
if cfg.getboolean('debug', 'gc'):
gc.set_debug(gc.DEBUG_LEAK)
pidfile.close()
main = Erebus(cfg)
+ dbsetup()
autoloads = [mod for mod, yes in cfg.items('autoloads') if int(yes) == 1]
for mod in autoloads:
ctlmod.load(main, mod)
- dbsetup()
c = main.query("SELECT nick, user, bind, authname, authpass FROM bots WHERE active = 1")
if c:
rows = c.fetchall()
for fileno in poready:
for line in main.fd(fileno).getdata():
main.fd(fileno).parse(line)
+ if main.mustquit is not None:
+ main.log('*', '!', 'Core exiting due to: %s' % (main.mustquit))
+ raise main.mustquit
if __name__ == '__main__':
try: os.rename('logfile', 'oldlogs/%s' % (time.time()))