]> jfr.im git - erebus.git/blobdiff - erebus.py
move responsibility for input logging to the core
[erebus.git] / erebus.py
index 0377d92ded68ae4014a3546e917048ec4303bb2d..5ebb39ea548edb67ce3ba50cff0390e5d5580a85 100644 (file)
--- a/erebus.py
+++ b/erebus.py
@@ -6,7 +6,7 @@
 
 from __future__ import print_function
 
-import os, sys, select, MySQLdb, MySQLdb.cursors, time, random, gc
+import os, sys, select, MySQLdb, MySQLdb.cursors, time, traceback, random, gc
 import bot, config, ctlmod
 
 class Erebus(object): #singleton to pass around
@@ -18,13 +18,17 @@ class Erebus(object): #singleton to pass around
        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 = []
@@ -59,6 +63,23 @@ class Erebus(object): #singleton to pass around
                                        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):
@@ -117,6 +138,9 @@ class Erebus(object): #singleton to pass around
                                        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)
@@ -190,6 +214,12 @@ class Erebus(object): #singleton to pass around
                        self.po.register(fileno, select.POLLIN)
                elif self.potype == "select":
                        self.fdlist.append(fileno)
+       def delfd(self, fileno):
+               del self.fds[fileno]
+               if self.potype == "poll":
+                       self.po.unregister(fileno)
+               elif self.potype == "select":
+                       self.fdlist.remove(fileno)
 
        def bot(self, name): #get Bot() by name (nick)
                return self.bots[name.lower()]
@@ -198,17 +228,17 @@ class Erebus(object): #singleton to pass around
        def randbot(self): #get Bot() randomly
                return self.bots[random.choice(list(self.bots.keys()))]
 
-       def user(self, _nick, justjoined=False, create=True):
+       def user(self, _nick, send_who=False, create=True):
                nick = _nick.lower()
+
+               if send_who and (nick not in self.users or not self.users[nick].isauthed()):
+                       self.randbot().conn.send("WHO %s n%%ant,1" % (nick))
+
                if nick in self.users:
                        return self.users[nick]
                elif create:
                        user = self.User(_nick)
                        self.users[nick] = user
-
-                       if justjoined:
-                               self.randbot().conn.send("WHO %s n%%ant,1" % (nick))
-
                        return user
                else:
                        return None
@@ -292,6 +322,15 @@ class Erebus(object): #singleton to pass around
        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
@@ -330,8 +369,23 @@ def setup():
 def loop():
        poready = main.poll()
        for fileno in poready:
-               for line in main.fd(fileno).getdata():
-                       main.fd(fileno).parse(line)
+               try:
+                       data = main.fd(fileno).getdata()
+               except:
+                       main.log('*', '!', 'Super-mega-emergency: getdata raised exception for socket %d' % (fileno))
+                       traceback.print_exc()
+                       data = None
+               if data is None:
+                       main.fd(fileno).close()
+               else:
+                       for line in data:
+                               if cfg.getboolean('debug', 'io'):
+                                       main.log(str(main.fd(fileno)), 'I', line)
+                               try:
+                                       main.fd(fileno).parse(line)
+                               except:
+                                       main.log('*', '!', 'Super-mega-emergency: parse raised exception for socket %d data %r' % (fileno, line))
+                                       traceback.print_exc()
        if main.mustquit is not None:
                main.log('*', '!', 'Core exiting due to: %s' % (main.mustquit))
                raise main.mustquit