started removing bullshit magic
This commit is contained in:
parent
c6fd9e1f55
commit
7e4ea3a9ff
6 changed files with 44 additions and 59 deletions
11
cloudbot.py
11
cloudbot.py
|
@ -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()):
|
||||
|
|
|
@ -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": []
|
||||
}
|
||||
|
|
|
@ -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
49
core/reload.py → core/loader.py
Executable file → Normal 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)
|
29
core/main.py
29
core/main.py
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Reference in a new issue