diff options
-rw-r--r-- | bot_backend.py | 99 | ||||
-rw-r--r-- | subbot.py | 127 |
2 files changed, 129 insertions, 97 deletions
diff --git a/bot_backend.py b/bot_backend.py new file mode 100644 index 0000000..6a2adfa --- /dev/null +++ b/bot_backend.py @@ -0,0 +1,99 @@ +import liblo +import urllib2 + +# Known lights, terminal symbols +lights_terminal = {} + +for i in range(1,5): + ident = '%02d' % i + lights_terminal[ident] = 'osc.udp://172.22.83.5:4243/dali/lamps/%s/bright' % ident + +# Production Rules/Aliases +lights_production = { + u'lounge-stage': [u'01'], + u'lounge-office': [u'02'], + u'lounge-bar': [u'03'], + u'lounge-clock': [u'04'], + u'lounge-west': [u'lounge-bar', u'lounge-clock'], + u'lounge-east': [u'lounge-stage', u'lounge-office'], + u'lounge': [u'lounge-east', u'lounge-west'], +} + +class OSCMessage(object): + def __init__(self, url): + parsed = urllib2.urlparse.urlparse(url) + self.path = parsed.path + self.url = urllib2.urlparse.urlunparse((parsed.scheme, parsed.netloc, '', '', '', '')) + + self.msg = liblo.Message(self.path) + + def __getattr__(self, name): + return getattr(self.msg, name) + + def send(self): + liblo.send(self.url, self.msg) + +def on_pubmsg(self, c, e): + message = e.arguments[0] + + light_command_prefix = '!light' + if message.startswith(light_command_prefix): + nick = e.source.nick + on_light_command(self, nick, message[len(light_command_prefix) + 1:]) + +def on_light_command(self, nick, commandline): + tokens = commandline.split(' ') + if len(tokens) < 1: + self.light_usage() + return + + if tokens[0].lower() == 'set': + on_light_set(self, tokens[1:]) + elif tokens[0].lower() == 'list': + on_light_list(self, tokens[1:]) + else: + light_usage(self) + +def on_light_list(self, tokens): + self.connection.privmsg(self.channel, + "The following ids are currently known: %s" % ', '.join(sorted(lights_production.keys()))) + +def on_light_set(self, tokens): + if len(tokens) != 2: + return False + + lights = tokens[0].split(',') + for i in range(32): + for i in range(len(lights)): + light = lights[i] + if light in lights_terminal: + continue + if light not in lights_production: + self.connection.privmsg(self.channel, "Unknown Alias: '%s'" % light) + return + lights = lights[:i] + lights_production[light] + lights[i+1:] + break + + status = tokens[1] + if status.lower() == 'on': + status = 255 + elif status.lower() == 'off': + status = 0 + else: + try: + status = int(status, 0) + if status not in range(256): + raise ValueError + except ValueError: + self.connection.privmsg(self.channel, "Invalid light value: '%s'" % status) + return + + for light in lights: + msg = OSCMessage(lights_terminal[light]) + msg.add(status) + msg.send() + self.connection.privmsg(self.channel, "Light command processed.") + +def light_usage(self): + self.connection.privmsg(self.channel, "Usage: !light list") + self.connection.privmsg(self.channel, "Usage: !light set <id>[,...] <on|off|0..255>") @@ -2,47 +2,26 @@ import irc.bot import json, time -import traceback -import liblo import urllib2 import sys import contextlib - +import signal import settings +import select +import errno svcpw = settings.bot_svcpw -# Known lights, terminal symbols -lights_terminal = {} - -for i in range(1,5): - ident = '%02d' % i - lights_terminal[ident] = 'osc.udp://172.22.83.5:4243/dali/lamps/%s/bright' % ident - -# Production Rules/Aliases -lights_production = { - u'lounge-stage': [u'01'], - u'lounge-office': [u'02'], - u'lounge-bar': [u'03'], - u'lounge-clock': [u'04'], - u'lounge-west': [u'lounge-bar', u'lounge-clock'], - u'lounge-east': [u'lounge-stage', u'lounge-office'], - u'lounge': [u'lounge-east', u'lounge-west'], -} - -class OSCMessage(object): - def __init__(self, url): - parsed = urllib2.urlparse.urlparse(url) - self.path = parsed.path - self.url = urllib2.urlparse.urlunparse((parsed.scheme, parsed.netloc, '', '', '', '')) - - self.msg = liblo.Message(self.path) - - def __getattr__(self, name): - return getattr(self.msg, name) - - def send(self): - liblo.send(self.url, self.msg) +import bot_backend +def reload_backend(signum, frame): + try: + reload(bot_backend) + except Exception: + print >>sys.stderr, "Error reloading bot backend:" + sys.excepthook(*sys.exc_info()) + else: + print >>sys.stderr, "Reloaded backend." +signal.signal(signal.SIGUSR1, reload_backend) class TestBot(irc.bot.SingleServerIRCBot): def __init__(self, channel, nickname, server, port=6667): @@ -53,6 +32,16 @@ class TestBot(irc.bot.SingleServerIRCBot): irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], self.nickname, self.nickname) self.channel = channel + def start(self): + self._connect() + while True: + try: + self.ircobj.process_forever(30) + except select.error, e: + if e.args[0] == errno.EINTR: + continue + raise + def on_nicknameinuse(self, c, e): self.nickname_base += '_' self.update_nick() @@ -63,68 +52,11 @@ class TestBot(irc.bot.SingleServerIRCBot): c.join(self.channel) def on_pubmsg(self, c, e): - message = e.arguments[0] - - light_command_prefix = '!light' - if message.startswith(light_command_prefix): - nick = e.source.nick - self.on_light_command(nick, message[len(light_command_prefix) + 1:]) - - def on_light_command(self, nick, commandline): - tokens = commandline.split(' ') - if len(tokens) < 1: - self.light_usage() - return - - if tokens[0].lower() == 'set': - self.on_light_set(tokens[1:]) - elif tokens[0].lower() == 'list': - self.on_light_list(tokens[1:]) - else: - self.light_usage() - - def on_light_list(self, tokens): - self.connection.privmsg(self.channel, - "The following ids are currently known: %s" % ', '.join(sorted(lights_production.keys()))) - - def on_light_set(self, tokens): - if len(tokens) != 2: - return False - - lights = tokens[0].split(',') - for i in range(32): - for i in range(len(lights)): - light = lights[i] - if light in lights_terminal: - continue - if light not in lights_production: - self.connection.privmsg(self.channel, "Unknown Alias: '%s'" % light) - return - lights = lights[:i] + lights_production[light] + lights[i+1:] - break - - status = tokens[1] - if status.lower() == 'on': - status = 255 - elif status.lower() == 'off': - status = 0 - else: - try: - status = int(status, 0) - if status not in range(256): - raise ValueError - except ValueError: - self.connection.privmsg(self.channel, "Invalid light value: '%s'" % status) - return - - for light in lights: - msg = OSCMessage(lights_terminal[light]) - msg.add(status) - msg.send() - - def light_usage(self): - self.connection.privmsg(self.channel, "Usage: !light list") - self.connection.privmsg(self.channel, "Usage: !light set <id>[,...] <on|off|0..255>") + try: + bot_backend.on_pubmsg(self, c, e) + except Exception: + print >>sys.stderr, "Error in backend processing message:" + sys.excepthook(*sys.exc_info()) def update_nick(self, server_interaction=True): """Set new nickname from nickname base and current status""" @@ -161,7 +93,8 @@ class TestBot(irc.bot.SingleServerIRCBot): else: self.status = 'error' except Exception, e: - traceback.print_exc() + print >>sys.stderr, "Error in door status retrieval:" + sys.excepthook(*sys.exc_info()) self.status = 'error' self.update_nick() |