h/bot.py

152 lines
4.4 KiB
Python
Raw Normal View History

2008-06-09 11:59:56 +00:00
#!/usr/bin/python
2009-03-15 06:51:39 +00:00
network = "irc.synirc.net"
nick = "skybot"
channel = "#cobol"
2008-06-09 11:59:56 +00:00
2009-03-15 03:06:36 +00:00
import sys
import os
import glob
import imp
import re
import thread
import Queue
import copy
2008-06-09 11:59:56 +00:00
2009-03-15 03:06:36 +00:00
import irc
import yaml
2008-06-09 11:59:56 +00:00
2009-03-15 03:06:36 +00:00
os.chdir(sys.path[0]) #do stuff relative to the installation directory
2008-06-09 11:59:56 +00:00
class Bot(object):
2009-03-15 20:04:02 +00:00
def __init__(self, nick, channel, network):
2009-03-15 03:06:36 +00:00
self.commands = [] # fn, name, func, args
self.filters = [] #fn, name, func
2009-03-15 20:04:02 +00:00
self.nick = nick
self.channel = channel
self.network = network
2008-06-09 11:59:56 +00:00
2009-03-15 20:04:02 +00:00
bot = Bot(nick, channel, network)
2008-06-09 11:59:56 +00:00
print 'Loading plugins'
2009-03-15 06:51:39 +00:00
typs = '|'.join('command filter event'.split())
magic_re = re.compile(r'^\s*#(%s)(?:: +(\S+) *(\S.*)?)?\s*$' % typs)
2009-03-15 04:14:07 +00:00
def reload_plugins(mtime=[0]):
new_mtime = os.stat('plugins')
if new_mtime == mtime[0]:
return
bot.commands = []
bot.filters = []
for filename in glob.glob("plugins/*.py"):
shortname = os.path.splitext(os.path.basename(filename))[0]
try:
plugin = imp.load_source(shortname, filename)
source = open(filename).read().split('\n')
#this is a nasty hack, but it simplifies registration
funcs = [x for x in dir(plugin)
if str(type(getattr(plugin,x))) == "<type 'function'>"]
for func in funcs:
#read the line before the function definition, looking for a
# comment that tells the bot about what it does
func = getattr(plugin, func)
lineno = func.func_code.co_firstlineno
if lineno == 1:
continue #can't have a line before the first line...
m = magic_re.match(source[lineno-2])
if m:
typ, nam, rest = m.groups()
if nam is None:
nam = func.__name__
if rest is None:
rest = '\s*(.*)'
if typ == 'command':
args = {'name': nam, 'hook': nam + rest}
bot.commands.append((filename, nam, func, args))
2009-03-15 06:51:39 +00:00
elif typ == 'filter':
2009-03-15 04:14:07 +00:00
bot.filters.append((filename, nam, func))
2009-03-15 06:51:39 +00:00
elif typ == 'event':
args = {'name': nam, 'prefix':False,
'events': [nam] + rest.split()}
bot.commands.append((filename, nam, func, args))
2009-03-15 04:14:07 +00:00
except Exception, e:
print e
mtime[0] = new_mtime
reload_plugins()
2008-06-09 11:59:56 +00:00
print 'Connecting to IRC'
2009-03-15 06:51:39 +00:00
bot.irc = irc.irc(network, nick)
2008-06-09 11:59:56 +00:00
bot.irc.join(channel)
2009-03-15 06:51:39 +00:00
bot.commandprefix = '^(?:\.|'+nick+'[:,]*\s*)'
2008-06-09 11:59:56 +00:00
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
class FakeBot(object):
2009-03-15 04:14:07 +00:00
def __init__(self, bot, input, fn, func):
2008-06-09 11:59:56 +00:00
self.bot = bot
self.input = input
2009-03-15 03:06:36 +00:00
self.msg = bot.irc.msg
self.cmd = bot.irc.cmd
2009-03-15 06:51:39 +00:00
self.join = bot.irc.join
2009-03-15 04:14:07 +00:00
self.fn = func
2009-03-15 03:06:36 +00:00
self.func = func
2009-03-15 06:51:39 +00:00
self.doreply = True
2009-03-15 03:06:36 +00:00
if input.command == "PRIVMSG":
self.chan = input.paraml[0]
2009-03-15 06:51:39 +00:00
2008-06-09 11:59:56 +00:00
def say(self, msg):
2009-03-15 04:14:07 +00:00
self.bot.irc.msg(self.input.paraml[0], msg)
2008-06-09 11:59:56 +00:00
def reply(self, msg):
2009-03-15 04:14:07 +00:00
self.say(self.input.nick + ': ' + msg)
2008-06-09 11:59:56 +00:00
2009-03-15 03:06:36 +00:00
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)
2009-03-15 03:06:36 +00:00
if out is not None:
2009-03-15 04:14:07 +00:00
if self.doreply:
self.reply(unicode(out))
else:
self.say(unicode(out))
2009-03-15 03:06:36 +00:00
2008-06-09 11:59:56 +00:00
print bot.commands
2009-03-15 03:06:36 +00:00
print bot.filters
2008-06-09 11:59:56 +00:00
while True:
try:
out = bot.irc.out.get(timeout=1)
2009-03-15 04:14:07 +00:00
reload_plugins()
2009-03-15 03:06:36 +00:00
for fn, name, func, args in bot.commands:
2008-06-09 11:59:56 +00:00
input = Input(*out)
2009-03-15 03:06:36 +00:00
for fn, nam, filt in bot.filters:
2008-06-09 11:59:56 +00:00
input = filt(bot, func, args, input)
2009-03-15 03:06:36 +00:00
if input == None:
2008-06-09 11:59:56 +00:00
break
2009-03-15 03:06:36 +00:00
if input == None:
2009-03-15 04:14:07 +00:00
continue
2009-03-15 06:51:39 +00:00
print '<<<', input.raw
2009-03-15 04:14:07 +00:00
thread.start_new_thread(FakeBot(bot, input, fn, func).run, ())
2008-06-09 11:59:56 +00:00
except Queue.Empty:
pass