From e284ed75ba54b258137d880361ab15b2aa4eafa1 Mon Sep 17 00:00:00 2001 From: Ryan Hitchman Date: Sun, 19 Apr 2009 05:18:27 -0600 Subject: [PATCH] split core into more reloadable chunks, more log work, beginning of hook.queue --- bot.py | 130 ++++-------------------------------------------- core/main.py | 70 ++++++++++++++++++++++++++ core/reload.py | 55 ++++++++++++++++++++ irc.py | 8 ++- plugins/hook.py | 8 +++ plugins/log.py | 7 ++- 6 files changed, 152 insertions(+), 126 deletions(-) create mode 100644 core/main.py create mode 100644 core/reload.py diff --git a/bot.py b/bot.py index d72b8b8..a79fc7b 100755 --- a/bot.py +++ b/bot.py @@ -21,140 +21,30 @@ os.chdir(sys.path[0]) # do stuff relative to the installation directory class Bot(object): + pass - def __init__(self, nick, channel, network): - self.nick = nick - self.channel = channel - self.network = network - -bot = Bot(nick, channel, network) +bot = Bot() print 'Loading plugins' -plugin_mtimes = {} - - -def reload_plugins(): - - if not hasattr(bot, 'plugs'): - bot.plugs = collections.defaultdict(lambda: []) - - for filename in glob.glob("core/*.py") + glob.glob("plugins/*.py"): - mtime = os.stat(filename).st_mtime - if mtime != plugin_mtimes.get(filename): - try: - code = compile(open(filename, 'U').read(), filename, 'exec') - namespace = {} - eval(code, namespace) - except Exception, e: - print ' error:', e - continue - - # remove plugins already loaded from this filename - for name, data in bot.plugs.iteritems(): - bot.plugs[name] = filter(lambda x: x[0][0] != filename, data) - - for obj in namespace.itervalues(): - if hasattr(obj, '_skybot_hook'): #check for magic - for type, data in obj._skybot_hook: - bot.plugs[type] += [data] - - plugin_mtimes[filename] = mtime - -reload_plugins() - -print ' plugin listing:' -for type, plugs in sorted(bot.plugs.iteritems()): - print ' %s:' % type - for plug in plugs: - out = ' %s:%s:%s' % (plug[0]) - print out, - if len(plug) == 3 and 'hook' in plug[2]: - print '%s%s' % (' ' * (40 - len(out)), plug[2]['hook']) - else: - print -print +# bootstrap the reloader +eval(compile(open('core/reload.py', 'U').read(), 'core/reload.py', 'exec')) print 'Connecting to IRC' + +bot.nick = nick +bot.channel = channel +bot.network = network bot.irc = irc.irc(network, nick) bot.irc.join(channel) bot.persist_dir = os.path.abspath('persist') print 'Running main loop' - -class Input(object): - - def __init__(self, raw, prefix, command, - params, nick, user, host, paraml, msg): - self.raw = raw - self.prefix = prefix - self.command = command - self.params = params - self.nick = nick - self.user = user - self.host = host - self.paraml = paraml - self.msg = msg - self.chan = paraml[0] - if self.chan == bot.nick: - self.chan = nick - elif command =='JOIN': - self.chan = msg - - -class FakeBot(object): - - def __init__(self, bot, input, func): - self.bot = bot - self.persist_dir = bot.persist_dir - self.network = bot.network - self.input = input - self.msg = bot.irc.msg - self.cmd = bot.irc.cmd - self.join = bot.irc.join - self.func = func - self.doreply = True - self.chan = input.chan - - def say(self, msg): - self.bot.irc.msg(self.chan, msg) - - def reply(self, msg): - self.say(self.input.nick + ': ' + msg) - - def run(self): - ac = self.func.func_code.co_argcount - if ac == 2: - out = self.func(self, self.input) - elif ac == 1: - out = self.func(self.input.inp) - if out is not None: - if self.doreply: - self.reply(unicode(out)) - else: - self.say(unicode(out)) - while True: try: out = bot.irc.out.get(timeout=1) - reload_plugins() - printed = False - for csig, func, args in (bot.plugs['command'] + bot.plugs['event']): - input = Input(*out) - for fsig, sieve in bot.plugs['sieve']: - try: - input = sieve(bot, input, func, args) - except Exception, e: - print 'sieve error:', e - input = None - if input == None: - break - if input == None: - continue - if not printed: - print '<<<', input.raw - printed = True - thread.start_new_thread(FakeBot(bot, input, func).run, ()) + reload() + main(out) except Queue.Empty: pass diff --git a/core/main.py b/core/main.py new file mode 100644 index 0000000..147c7e2 --- /dev/null +++ b/core/main.py @@ -0,0 +1,70 @@ +class Input(object): + + def __init__(self, raw, prefix, command, + params, nick, user, host, paraml, msg): + self.raw = raw + self.prefix = prefix + self.command = command + self.params = params + self.nick = nick + self.user = user + self.host = host + self.paraml = paraml + self.msg = msg + self.chan = paraml[0] + if self.chan == bot.nick: + self.chan = nick + elif command =='JOIN': + self.chan = msg + + +class FakeBot(object): + + def __init__(self, bot, input, func): + self.bot = bot + self.persist_dir = bot.persist_dir + self.network = bot.network + self.input = input + self.msg = bot.irc.msg + self.cmd = bot.irc.cmd + self.join = bot.irc.join + self.func = func + self.doreply = True + self.chan = input.chan + + def say(self, msg): + self.bot.irc.msg(self.chan, msg) + + def reply(self, msg): + self.say(self.input.nick + ': ' + msg) + + def run(self): + ac = self.func.func_code.co_argcount + if ac == 2: + out = self.func(self, self.input) + elif ac == 1: + out = self.func(self.input.inp) + if out is not None: + if self.doreply: + self.reply(unicode(out)) + else: + self.say(unicode(out)) + +def main(out): + printed = False + for csig, func, args in (bot.plugs['command'] + bot.plugs['event']): + input = Input(*out) + for fsig, sieve in bot.plugs['sieve']: + try: + input = sieve(bot, input, func, args) + except Exception, e: + print 'sieve error:', e + input = None + if input == None: + break + if input == None: + continue + if not printed: + print '<<<', input.raw + printed = True + thread.start_new_thread(FakeBot(bot, input, func).run, ()) diff --git a/core/reload.py b/core/reload.py new file mode 100644 index 0000000..40066bd --- /dev/null +++ b/core/reload.py @@ -0,0 +1,55 @@ +if 'plugin_mtimes' not in globals(): + mtimes = {} + +def reload(): + init = False + if not hasattr(bot, 'plugs'): + bot.plugs = collections.defaultdict(lambda: []) + init = True + + for filename in glob.glob("core/*.py"): + mtime = os.stat(filename).st_mtime + if mtime != mtimes.get(filename): + try: + eval(compile(open(filename, 'U').read(), filename, 'exec'), + globals()) + mtimes[filename] = mtime + except Exception, e: + print ' core error:', e + continue + + for filename in glob.glob("plugins/*.py"): + mtime = os.stat(filename).st_mtime + if mtime != mtimes.get(filename): + try: + code = compile(open(filename, 'U').read(), filename, 'exec') + namespace = {} + eval(code, namespace) + except Exception, e: + print ' error:', e + continue + + # remove plugins already loaded from this filename + for name, data in bot.plugs.iteritems(): + bot.plugs[name] = filter(lambda x: x[0][0] != filename, data) + + for obj in namespace.itervalues(): + if hasattr(obj, '_skybot_hook'): #check for magic + for type, data in obj._skybot_hook: + bot.plugs[type] += [data] + + mtimes[filename] = mtime + + if init: + print ' plugin listing:' + for type, plugs in sorted(bot.plugs.iteritems()): + print ' %s:' % type + for plug in plugs: + out = ' %s:%s:%s' % (plug[0]) + print out, + if len(plug) == 3 and 'hook' in plug[2]: + print '%s%s' % (' ' * (40 - len(out)), plug[2]['hook']) + else: + print + print + diff --git a/irc.py b/irc.py index 9f3446e..0a3144e 100644 --- a/irc.py +++ b/irc.py @@ -6,8 +6,6 @@ import asyncore import asynchat import Queue -queue = Queue.Queue - def decode(txt): for codec in ('utf-8', 'iso-8859-1', 'shift_jis', 'cp1252'): @@ -26,8 +24,8 @@ class crlf_tcp(asynchat.async_chat): self.set_terminator('\r\n') self.buffer = "" self.obuffer = "" - self.oqueue = queue() #where we stick things that need to be sent - self.iqueue = queue() #where we stick things that were received + self.oqueue = Queue.Queue() #where we stick things that need to be sent + self.iqueue = Queue.Queue() #where we stick things that were received self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 0) self.host = host @@ -67,7 +65,7 @@ class irc(object): def __init__(self, network, nick, port=6667): self.conn = crlf_tcp(network, port) thread.start_new_thread(self.conn.run, ()) - self.out = queue() #responses from the server are placed here + self.out = Queue.Queue() #responses from the server are placed here # format: [rawline, prefix, command, params, # nick, user, host, paramlist, msg] self.nick(nick) diff --git a/plugins/hook.py b/plugins/hook.py index 6210f61..e27bc23 100644 --- a/plugins/hook.py +++ b/plugins/hook.py @@ -1,3 +1,11 @@ +import Queue + +class queue(Queue.Queue): + + def __init__(self, maxsize=0): + Queue.Queue.__init__(self, maxsize) + self._skybot_hook = [['queue', self]] + def _isfunc(x): if type(x) == type(_isfunc): return True diff --git a/plugins/log.py b/plugins/log.py index 7df957e..1aa5ed4 100644 --- a/plugins/log.py +++ b/plugins/log.py @@ -21,11 +21,13 @@ formats = {'PRIVMSG': '<%(nick)s> %(msg)s', 'JOIN': '-!- %(nick)s [%(user)s@%(host)s] has joined %(chan)s', 'MODE': '-!- mode/%(chan)s [%(param_tail)s] by %(nick)s', 'KICK': '-!- %(param1)s was kicked from %(chan)s by %(nick)s [%(msg)s]', - 'TOPIC': '-!- %(nick)s changed the topic of %(chan)s to: %(msg)s' + 'TOPIC': '-!- %(nick)s changed the topic of %(chan)s to: %(msg)s', + 'QUIT': '-!- %(nick)s has quit [%(msg)s]' } ctcp_formats = {'ACTION': '* %(nick)s %(ctcpmsg)s'} + def get_log_filename(dir, network, chan): return os.path.join(dir, 'log', gmtime('%Y'), network, gmtime('%%s.%m-%d.log') % chan).lower() @@ -85,6 +87,9 @@ def log(bot, input): fd = get_log_fd(bot.persist_dir, bot.network, 'raw') fd.write(timestamp + ' ' + input.raw + '\n') + if input.command == 'QUIT': + input.chan = 'quit' + if input.chan: fd = get_log_fd(bot.persist_dir, bot.network, input.chan) fd.write(timestamp + ' ' + beautify(input) + '\n')