split core into more reloadable chunks, more log work, beginning of hook.queue
This commit is contained in:
parent
db1997d529
commit
e284ed75ba
130
bot.py
130
bot.py
|
@ -21,140 +21,30 @@ os.chdir(sys.path[0]) # do stuff relative to the installation directory
|
||||||
|
|
||||||
|
|
||||||
class Bot(object):
|
class Bot(object):
|
||||||
|
pass
|
||||||
|
|
||||||
def __init__(self, nick, channel, network):
|
bot = Bot()
|
||||||
self.nick = nick
|
|
||||||
self.channel = channel
|
|
||||||
self.network = network
|
|
||||||
|
|
||||||
bot = Bot(nick, channel, network)
|
|
||||||
|
|
||||||
print 'Loading plugins'
|
print 'Loading plugins'
|
||||||
|
|
||||||
plugin_mtimes = {}
|
# bootstrap the reloader
|
||||||
|
eval(compile(open('core/reload.py', 'U').read(), 'core/reload.py', 'exec'))
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
print 'Connecting to IRC'
|
print 'Connecting to IRC'
|
||||||
|
|
||||||
|
bot.nick = nick
|
||||||
|
bot.channel = channel
|
||||||
|
bot.network = network
|
||||||
bot.irc = irc.irc(network, nick)
|
bot.irc = irc.irc(network, nick)
|
||||||
bot.irc.join(channel)
|
bot.irc.join(channel)
|
||||||
bot.persist_dir = os.path.abspath('persist')
|
bot.persist_dir = os.path.abspath('persist')
|
||||||
|
|
||||||
print 'Running main loop'
|
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:
|
while True:
|
||||||
try:
|
try:
|
||||||
out = bot.irc.out.get(timeout=1)
|
out = bot.irc.out.get(timeout=1)
|
||||||
reload_plugins()
|
reload()
|
||||||
printed = False
|
main(out)
|
||||||
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, ())
|
|
||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -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, ())
|
|
@ -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
|
||||||
|
|
8
irc.py
8
irc.py
|
@ -6,8 +6,6 @@ import asyncore
|
||||||
import asynchat
|
import asynchat
|
||||||
import Queue
|
import Queue
|
||||||
|
|
||||||
queue = Queue.Queue
|
|
||||||
|
|
||||||
|
|
||||||
def decode(txt):
|
def decode(txt):
|
||||||
for codec in ('utf-8', 'iso-8859-1', 'shift_jis', 'cp1252'):
|
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.set_terminator('\r\n')
|
||||||
self.buffer = ""
|
self.buffer = ""
|
||||||
self.obuffer = ""
|
self.obuffer = ""
|
||||||
self.oqueue = queue() #where we stick things that need to be sent
|
self.oqueue = Queue.Queue() #where we stick things that need to be sent
|
||||||
self.iqueue = queue() #where we stick things that were received
|
self.iqueue = Queue.Queue() #where we stick things that were received
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.socket.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 0)
|
self.socket.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 0)
|
||||||
self.host = host
|
self.host = host
|
||||||
|
@ -67,7 +65,7 @@ class irc(object):
|
||||||
def __init__(self, network, nick, port=6667):
|
def __init__(self, network, nick, port=6667):
|
||||||
self.conn = crlf_tcp(network, port)
|
self.conn = crlf_tcp(network, port)
|
||||||
thread.start_new_thread(self.conn.run, ())
|
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,
|
# format: [rawline, prefix, command, params,
|
||||||
# nick, user, host, paramlist, msg]
|
# nick, user, host, paramlist, msg]
|
||||||
self.nick(nick)
|
self.nick(nick)
|
||||||
|
|
|
@ -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):
|
def _isfunc(x):
|
||||||
if type(x) == type(_isfunc):
|
if type(x) == type(_isfunc):
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -21,11 +21,13 @@ formats = {'PRIVMSG': '<%(nick)s> %(msg)s',
|
||||||
'JOIN': '-!- %(nick)s [%(user)s@%(host)s] has joined %(chan)s',
|
'JOIN': '-!- %(nick)s [%(user)s@%(host)s] has joined %(chan)s',
|
||||||
'MODE': '-!- mode/%(chan)s [%(param_tail)s] by %(nick)s',
|
'MODE': '-!- mode/%(chan)s [%(param_tail)s] by %(nick)s',
|
||||||
'KICK': '-!- %(param1)s was kicked from %(chan)s by %(nick)s [%(msg)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'}
|
ctcp_formats = {'ACTION': '* %(nick)s %(ctcpmsg)s'}
|
||||||
|
|
||||||
|
|
||||||
def get_log_filename(dir, network, chan):
|
def get_log_filename(dir, network, chan):
|
||||||
return os.path.join(dir, 'log', gmtime('%Y'), network,
|
return os.path.join(dir, 'log', gmtime('%Y'), network,
|
||||||
gmtime('%%s.%m-%d.log') % chan).lower()
|
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 = get_log_fd(bot.persist_dir, bot.network, 'raw')
|
||||||
fd.write(timestamp + ' ' + input.raw + '\n')
|
fd.write(timestamp + ' ' + input.raw + '\n')
|
||||||
|
|
||||||
|
if input.command == 'QUIT':
|
||||||
|
input.chan = 'quit'
|
||||||
|
|
||||||
if input.chan:
|
if input.chan:
|
||||||
fd = get_log_fd(bot.persist_dir, bot.network, input.chan)
|
fd = get_log_fd(bot.persist_dir, bot.network, input.chan)
|
||||||
fd.write(timestamp + ' ' + beautify(input) + '\n')
|
fd.write(timestamp + ' ' + beautify(input) + '\n')
|
||||||
|
|
Loading…
Reference in New Issue