started removing bullshit magic

This commit is contained in:
Luke Rogers 2013-10-02 13:33:17 +13:00
parent c6fd9e1f55
commit 7e4ea3a9ff
6 changed files with 44 additions and 59 deletions

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python
# we import bot as _bot for now, for legacy reasons
from core import bot as _bot
from core import loader, main
import os
import Queue
@ -16,20 +17,14 @@ print 'CloudBot REFRESH <http://git.io/cloudbotirc>'
bot = _bot.Bot("cloudbot")
bot.logger.debug("Bot initalized.")
# bootstrap the reloader
bot.logger.debug("Bootstrapping reloader.")
eval(compile(open(os.path.join('core', 'reload.py'), 'U').read(),
os.path.join('core', 'reload.py'), 'exec'))
reload(init=True)
bot.logger.debug("Starting main loop.")
while True:
reload() # these functions only do things
loader.reload(bot) # these functions only do things
for connection in bot.connections.itervalues():
try:
out = connection.out.get_nowait()
main(connection, out)
main.main(bot, connection, out)
except Queue.Empty:
pass
while all(connection.out.empty() for connection in bot.connections.itervalues()):

View file

@ -9,7 +9,7 @@
"ssl": false,
"ignore_cert": true
},
"nick": "MyCloudBot",
"nick": "MyCloueqerdBot",
"user": "cloudbot",
"real_name": "CloudBot - http://git.io/cloudbotirc",
"channels": ["#cloudbot", "#cloudbot2"],
@ -52,5 +52,6 @@
"rdio_key": "",
"rdio_secret": "",
"steam_key": ""
}
},
"disabled_plugins": []
}

View file

@ -3,7 +3,7 @@ import logging
import re
import os
from core import config, irc
from core import config, irc, loader
def clean_name(n):
@ -25,6 +25,11 @@ class Bot(object):
self.connections = {}
self.connect()
# run plugin loader
self.logger.debug("Bootstrapping reloader.")
loader.reload(self, init=True)
def connect(self):
"""connect to all the networks defined in the bot config"""
for conf in self.config['connections']:

49
core/reload.py → core/loader.py Executable file → Normal file
View file

@ -3,8 +3,11 @@ import glob
import os
import re
import sys
import Queue
import traceback
from core import main
if 'mtimes' not in globals():
mtimes = {}
@ -31,40 +34,18 @@ def format_plug(plug, kind='', lpad=0):
return out
def reload(init=False):
def reload(bot, init=False):
changed = False
if init:
bot.plugs = collections.defaultdict(list)
bot.plugins = collections.defaultdict(list)
bot.threads = {}
core_fileset = set(glob.glob(os.path.join("core", "*.py")))
for filename in core_fileset:
mtime = os.stat(filename).st_mtime
if mtime != mtimes.get(filename):
mtimes[filename] = mtime
changed = True
try:
eval(compile(open(filename, 'U').read(), filename, 'exec'),
globals())
except Exception:
traceback.print_exc()
if init: # stop if there's an error (syntax?) in a core
sys.exit() # script on startup
continue
if filename == os.path.join('core', 'reload.py'):
reload(init=init)
return
fileset = set(glob.glob(os.path.join('plugins', '*.py')))
# remove deleted/moved plugins
for name, data in bot.plugs.iteritems():
bot.plugs[name] = [x for x in data if x[0]._filename in fileset]
for name, data in bot.plugins.iteritems():
bot.plugins[name] = [x for x in data if x[0]._filename in fileset]
for filename in list(mtimes):
if filename not in fileset and filename not in core_fileset:
@ -72,7 +53,7 @@ def reload(init=False):
for func, handler in list(bot.threads.iteritems()):
if func._filename not in fileset:
handler.stop()
main.handler.stop()
del bot.threads[func]
# compile new plugins
@ -92,8 +73,8 @@ def reload(init=False):
continue
# remove plugins already loaded from this filename
for name, data in bot.plugs.iteritems():
bot.plugs[name] = [x for x in data
for name, data in bot.plugins.iteritems():
bot.plugins[name] = [x for x in data
if x[0]._filename != filename]
for func, handler in list(bot.threads.iteritems()):
@ -104,10 +85,10 @@ def reload(init=False):
for obj in namespace.itervalues():
if hasattr(obj, '_hook'): # check for magic
if obj._thread:
bot.threads[obj] = Handler(obj)
bot.threads[obj] = main.Handler(bot, obj)
for type, data in obj._hook:
bot.plugs[type] += [data]
bot.plugins[type] += [data]
if not init:
print '### new plugin (type: %s) loaded:' % \
@ -115,7 +96,7 @@ def reload(init=False):
if changed:
bot.commands = {}
for plug in bot.plugs['command']:
for plug in bot.plugins['command']:
name = plug[1]['name'].lower()
if not re.match(r'^\w+$', name):
print '### ERROR: invalid command name "{}" ({})'.format(name, format_plug(plug))
@ -128,7 +109,7 @@ def reload(init=False):
bot.commands[name] = plug
bot.events = collections.defaultdict(list)
for func, args in bot.plugs['event']:
for func, args in bot.plugins['event']:
for event in args['events']:
bot.events[event].append((func, args))
@ -151,7 +132,7 @@ def reload(init=False):
out += ' ' * (50 - len(out)) + ', '.join(names)
print out
for kind, plugs in sorted(bot.plugs.iteritems()):
for kind, plugs in sorted(bot.plugins.iteritems()):
if kind == 'command':
continue
print ' {}:'.format(kind)

View file

@ -1,12 +1,14 @@
import thread
import traceback
import Queue
import re
thread.stack_size(1024 * 512) # reduce vm size
class Input(dict):
def __init__(self, conn, raw, prefix, command, params,
def __init__(self, bot, conn, raw, prefix, command, params,
nick, user, host, mask, paraml, msg):
chan = paraml[0].lower()
@ -84,8 +86,9 @@ def do_sieve(sieve, bot, input, func, type, args):
class Handler(object):
"""Runs plugins in their own threads (ensures order)"""
def __init__(self, func):
def __init__(self, func, bot):
self.func = func
self.bot = bot
self.input_queue = Queue.Queue()
thread.start_new_thread(self.start, ())
@ -101,7 +104,7 @@ class Handler(object):
if uses_db:
db = db_conns.get(input.conn)
if db is None:
db = bot.get_db_connection(input.conn)
db = self.bot.get_db_connection(input.conn)
db_conns[input.conn] = db
input.db = db
@ -119,8 +122,8 @@ class Handler(object):
self.input_queue.put(value)
def dispatch(input, kind, func, args, autohelp=False):
for sieve, in bot.plugs['sieve']:
def dispatch(bot, input, kind, func, args, autohelp=False):
for sieve, in bot.plugins['sieve']:
input = do_sieve(sieve, bot, input, func, kind, args)
if input is None:
return
@ -135,7 +138,7 @@ def dispatch(input, kind, func, args, autohelp=False):
thread.start_new_thread(run, (func, input))
def match_command(command):
def match_command(bot, command):
commands = list(bot.commands)
# do some fuzzy matching
@ -148,13 +151,13 @@ def match_command(command):
return command
def main(conn, out):
inp = Input(conn, *out)
def main(bot, conn, out):
inp = Input(bot, conn, *out)
command_prefix = conn.conf.get('command_prefix', '.')
# EVENTS
for func, args in bot.events[inp.command] + bot.events['*']:
dispatch(Input(conn, *out), "event", func, args)
dispatch(bot, Input(bot, conn, *out), "event", func, args)
if inp.command == 'PRIVMSG':
# COMMANDS
@ -170,23 +173,23 @@ def main(conn, out):
if m:
trigger = m.group(1).lower()
command = match_command(trigger)
command = match_command(bot, trigger)
if isinstance(command, list): # multiple potential matches
input = Input(conn, *out)
input.notice("Did you mean {} or {}?".format
(', '.join(command[:-1]), command[-1]))
elif command in bot.commands:
input = Input(conn, *out)
input = Input(bot, conn, *out)
input.trigger = trigger
input.inp_unstripped = m.group(2)
input.inp = input.inp_unstripped.strip()
func, args = bot.commands[command]
dispatch(input, "command", func, args, autohelp=True)
dispatch(bot, input, "command", func, args, autohelp=True)
# REGEXES
for func, args in bot.plugs['regex']:
for func, args in bot.plugins['regex']:
m = args['re'].search(inp.lastparam)
if m:
input = Input(conn, *out)

View file

@ -1,6 +1,6 @@
from util import hook, http
from lib import pygeoip
import os.path
import pygeoip
import json
import gzip
from StringIO import StringIO