From 798fb6d5728b8ec243e7f41189694a8e6352ce19 Mon Sep 17 00:00:00 2001 From: urlbot Date: Sat, 27 Sep 2014 03:40:27 +0200 Subject: [PATCH] first try with plugins. untested, might crash --- eventlooper.py | 106 ++--------------- local_config.py.skel | 3 + plugins.py | 277 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+), 97 deletions(-) create mode 100644 plugins.py diff --git a/eventlooper.py b/eventlooper.py index 2872f00..5602f08 100755 --- a/eventlooper.py +++ b/eventlooper.py @@ -6,7 +6,6 @@ from local_config import conf BUFSIZ = 8192 delay = 0.100 # seconds -bot_user = 'urlbot' basedir = '.' if 2 == len(sys.argv): basedir = sys.argv[1] @@ -132,7 +131,7 @@ def chat_write(message, prefix='/say '): except IOError: logger('err', "couldn't print to fifo " + fifo_path) -def ratelimit_exceeded(): +def ratelimit_exceeded(ignored=None): # FIXME: separate counters global hist_flag now = time.time() @@ -180,35 +179,6 @@ def extract_url(data): ret = True return ret -def mental_ill(data): - min_ill = 3 - c = 0 - - # return True for min_ill '!' in a row - for d in data: - if '!' == d or '?' == d: - c += 1 - else: - c = 0 - if (min_ill <= c): - return True - - return False - -def parse_other(data): - reply_user = data.split(' ')[0].strip('<>') - - if True == mental_ill(data): - if ratelimit_exceeded(): - return False - chat_write('''Multiple exclamation/question marks are a sure sign of mental disease, with %s as a living example.''' % reply_user) - elif 'skynet' in data.lower(): - if ratelimit_exceeded(): - return False - chat_write('''I'm an independent bot and have nothing to do with other artificial intelligence systems!''') - - return True - def parse_pn(data): ## reply_user = data.split(' ')[0].strip('<>') # since we can't determine if a user named 'foo> ' just wrote ' > bar' @@ -216,70 +186,6 @@ def parse_pn(data): logger('warn', 'received PN: ' + data) return False -def parse_commands(data): - words = data.split(' ') - - if 2 > len(words): # need at least two words - return None - - # reply if beginning of the text matches bot_user - if words[1][0:len(bot_user)] == bot_user: - reply_user = words[0].strip('<>') - - if 'hangup' in data: - chat_write('', prefix='/quit') - logger('warn', 'received hangup: ' + data) - return None - - if ratelimit_exceeded(): - return False - - if 'command' in data: - chat_write(reply_user + (""": known commands: 'command', 'dice', 'info', 'hangup', 'nospoiler', 'ping', 'uptime', 'source', 'version'""")) - elif 'version' in data: - chat_write(reply_user + (''': I'm running ''' + VERSION)) - elif 'unikot' in data: - chat_write(reply_user + (u''': ┌────────┐''')) - chat_write(reply_user + (u''': │Unicode!│''')) - chat_write(reply_user + (u''': └────────┘''')) - elif 'source' in data: - chat_write('My source code can be found at %s' % conf('src-url')) - elif 'dice' in data: - if reply_user in conf('enhanced-random-user'): - rnd = 0 # this might confuse users. good. - else: - rnd = random.randint(1, 6) - - dice_char = [u'◇', u'⚀', u'⚁', u'⚂', u'⚃', u'⚄', u'⚅'] - chat_write('rolling a dice for %s: %s (%d)' %(reply_user, dice_char[rnd], rnd)) - elif 'uptime' in data: - u = int(uptime + time.time()) - plural_uptime = 's' - plural_request = 's' - - if 1 == u: plural_uptime = '' - if 1 == request_counter: plural_request = '' - - chat_write(reply_user + (''': happily serving for %d second%s, %d request%s so far.''' %(u, plural_uptime, request_counter, plural_request))) - logger('info', 'sent statistics') - elif 'ping' in data: - rnd = random.randint(0, 3) # 1:4 - if 0 == rnd: - chat_write(reply_user + ''': peng (You're dead now.)''') - logger('info', 'sent pong (variant)') - elif 1 == rnd: - chat_write(reply_user + ''': I don't like you, leave me alone.''') - logger('info', 'sent pong (dontlike)') - else: - chat_write(reply_user + ''': pong''') - logger('info', 'sent pong') - elif 'info' in data: - chat_write(reply_user + (''': I'm a bot, my job is to extract tags from posted URLs. In case I'm annoying or for further questions, please talk to my master Cae. I'm rate limited and shouldn't post more than %d messages per %d seconds. To make me exit immediately, highlight me with 'hangup' in the message (emergency only, please). For other commands, highlight me with 'command'.''' %(hist_max_count, hist_max_time))) - logger('info', 'sent long info') - else: - chat_write(reply_user + (''': I'm a bot (highlight me with 'info' for more information).''')) - logger('info', 'sent short info') - def parse_delete(filepath): try: fd = open(filepath, 'rb') @@ -306,8 +212,8 @@ def parse_delete(filepath): return if True != extract_url(content): - parse_commands(content) - parse_other(content) + plugins.parse_commands(content) + plugins.parse_other(content) return def get_version_git(): @@ -323,6 +229,12 @@ def get_version_git(): else: return "(unknown version)" +import plugins +plugins.chat_write = chat_write +plugins.conf = conf +plugins.logger = logger +plugins.ratelimit_exceeded = ratelimit_exceeded + if '__main__' == __name__: VERSION = get_version_git() print sys.argv[0] + ' ' + VERSION diff --git a/local_config.py.skel b/local_config.py.skel index 5dede38..df19565 100644 --- a/local_config.py.skel +++ b/local_config.py.skel @@ -7,6 +7,9 @@ if '__main__' == __name__: config = {} config['src-url'] = 'FIXME' +config['bot_user'] = 'urlbot' +config['bot_owner'] = 'FIXME' + # the "dice" feature will use more efficient random data (0) for given users config['enhanced-random-user'] = ( 'FIXME', 'FIXME' ) diff --git a/plugins.py b/plugins.py new file mode 100644 index 0000000..baf2ff2 --- /dev/null +++ b/plugins.py @@ -0,0 +1,277 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +if '__main__' == __name__: + print '''this is a plugin file, which is not meant to be executed''' + exit(-1) + +RATE_GLOBAL = 1 +RATE_NO_SILENCE = 2 +RATE_INTERACTIVE = 4 + +def get_reply_user(data): + # FIXME: we can't determine if a user named 'foo> ' just wrote ' > bar' + # or a user 'foo' just wrote '> > bar' + return data.split(' ')[0].strip('<>') + +def parse_mental_ill(args): + min_ill = 3 + c = 0 + flag = False + + # return True for min_ill '!' in a row + for d in args['data']: + if '!' == d or '?' == d: + c += 1 + else: + c = 0 + if (min_ill <= c): + flag = True + break + + if True == flag: + return { + 'msg': '''Multiple exclamation/question marks are a sure sign of mental disease, with %s as a living example.''' % args['reply_user'], + 'ratelimit_class': RATE_NO_SILENCE | RATE_GLOBAL + } + +def parse_skynet(args): + if 'skynet' in args['data'].lower(): + return { + 'msg': '''I'm an independent bot and have nothing to do with other artificial intelligence systems!''', + 'ratelimit_class': RATE_GLOBAL + } + + +def parse_other(data): + reply_user = get_reply_user(data) + + plugins = ( + { + 'name': 'parse mental illness', + 'func': parse_mental_ill, + 'param': { + 'data': data, + 'reply_user': reply_user + } + }, + { + 'name': 'parse skynet', + 'func': parse_skynet, + 'param': { + 'data': data + } + } + ) + + for p in plugins: + ret = p['func'](p['param']) + + if None != ret: + if ratelimit_exceeded(ret['ratelimit_class']): + return False + + if 'msg' in ret.keys(): + chat_write(ret['msg']) + + return True + +def command_help(args): + if 'command' in args['data']: + return { + 'msg': args['reply_user'] + (""": known commands: 'command', 'dice', 'info', 'hangup', 'nospoiler', 'ping', 'uptime', 'source', 'version'"""), + 'ratelimit_class': RATE_GLOBAL + } + +def command_version(args): + if 'version' in args['data']: + return { + 'msg': args['reply_user'] + (''': I'm running ''' + VERSION), + 'ratelimit_class': RATE_GLOBAL + } + +def command_unicode(args): + if 'unikot' in args['data']: + return { + 'msg': + args['reply_user'] + u''': ┌────────┐''' + '\n' + + args['reply_user'] + u''': │Unicode!│''' + '\n' + + args['reply_user'] + u''': └────────┘''', + 'ratelimit_class': RATE_GLOBAL + } + +def command_source(args): + if 'source' in args['data']: + return { + 'msg': 'My source code can be found at %s' % conf('src-url'), + 'ratelimit_class': RATE_GLOBAL + } + +def command_dice(args): + if 'dice' in args['data']: + if args['reply_user'] in conf('enhanced-random-user'): + rnd = 0 # this might confuse users. good. + else: + rnd = random.randint(1, 6) + + dice_char = [u'◇', u'⚀', u'⚁', u'⚂', u'⚃', u'⚄', u'⚅'] + return { + 'msg': 'rolling a dice for %s: %s (%d)' %(args['reply_user'], dice_char[rnd], rnd), + 'ratelimit_class': RATE_INTERACTIVE + } + +def command_uptime(args): + if 'uptime' in args['data']: + u = int(uptime + time.time()) + plural_uptime = 's' + plural_request = 's' + + if 1 == u: plural_uptime = '' + if 1 == request_counter: plural_request = '' + + logger('info', 'sent statistics') + return { + 'msg': args['reply_user'] + (''': happily serving for %d second%s, %d request%s so far.''' %(u, plural_uptime, request_counter, plural_request)), + 'ratelimit_class': RATE_GLOBAL + } + +def command_ping(args): + if 'ping' in args['data']: + rnd = random.randint(0, 3) # 1:4 + if 0 == rnd: + msg = args['reply_user'] + ''': peng (You're dead now.)''' + logger('info', 'sent pong (variant)') + elif 1 == rnd: + msg = args['reply_user'] + ''': I don't like you, leave me alone.''' + logger('info', 'sent pong (dontlike)') + else: + msg = args['reply_user'] + ''': pong''' + logger('info', 'sent pong') + + return { + 'msg': msg, + 'ratelimit_class': RATE_INTERACTIVE + } + +def command_info(args): + if 'info' in args['data']: + logger('info', 'sent long info') + return { + 'msg': args['reply_user'] + (''': I'm a bot, my job is to extract <title> tags from posted URLs. In case I'm annoying or for further questions, please talk to my master %s. I'm rate limited and shouldn't post more than %d messages per %d seconds. To make me exit immediately, highlight me with 'hangup' in the message (emergency only, please). For other commands, highlight me with 'command'.''' %(conf('bot_owner'), hist_max_count, hist_max_time)), + 'ratelimit_class': RATE_GLOBAL + } + +def command_else(args): + logger('info', 'sent short info') + return { + 'msg': args['reply_user'] + ''': I'm a bot (highlight me with 'info' for more information).''', + 'ratelimit_class': RATE_GLOBAL + } + +def parse_commands(data): + words = data.split(' ') + + if 2 > len(words): # need at least two words + return None + + # don't reply if beginning of the text matches bot_user + if words[1][0:len(conf('bot_user'))] != conf('bot_user'): + return None + + if 'hangup' in data: + chat_write('', prefix='/quit') + logger('warn', 'received hangup: ' + data) + return None + + reply_user = get_reply_user(data) + + plugins = ( + { + 'name': 'prints help', + 'func': command_help, + 'param': { + 'data': data, + 'reply_user': reply_user + } + }, + { + 'name': 'prints version', + 'func': command_version, + 'param': { + 'data': data, + 'reply_user': reply_user + } + }, + { + 'name': 'prints an unicode string', + 'func': command_unicode, + 'param': { + 'data': data, + 'reply_user': reply_user + } + }, + { + 'name': 'prints git URL', + 'func': command_source, + 'param': { + 'data': data, + 'reply_user': reply_user + } + }, + { + 'name': 'rolls a dice', + 'func': command_dice, + 'param': { + 'data': data, + 'reply_user': reply_user + } + }, + { + 'name': 'prints uptime', + 'func': command_uptime, + 'param': { + 'data': data, + 'reply_user': reply_user + } + }, + { + 'name': 'pong', + 'func': command_ping, + 'param': { + 'data': data, + 'reply_user': reply_user + } + }, + { + 'name': 'prints info message', + 'func': command_info, + 'param': { + 'data': data, + 'reply_user': reply_user + } + } + ) + + flag = False + + for p in plugins: + ret = p['func'](p['param']) + if None != ret: + flag = True + + if ratelimit_exceeded(ret['ratelimit_class']): + return False + + if 'msg' in ret.keys(): + chat_write(ret['msg']) + + if False != flag: + return None + + ret = command_else({'reply_user': reply_user}) + if None != ret: + if ratelimit_exceeded(RATE_GLOBAL): + return False + + if 'msg' in ret.keys(): + chat_write(ret['msg'])