From 924172291f9cd9bc15d58810d94afb51dccbee57 Mon Sep 17 00:00:00 2001 From: James Lu Date: Sat, 14 May 2016 10:17:40 -0700 Subject: [PATCH] ServiceBot: work out basic command handling This copies callCommand from the IRC object into ServiceBot.call_cmd. The former will be removed once the main PyLink client is migrated to a service bot. --- coreplugin.py | 18 +++++++++++++----- utils.py | 42 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/coreplugin.py b/coreplugin.py index 781341e..c097837 100644 --- a/coreplugin.py +++ b/coreplugin.py @@ -53,9 +53,17 @@ utils.add_hook(handle_kick, 'KICK') def handle_commands(irc, source, command, args): """Handle commands sent to the PyLink client (PRIVMSG).""" - if args['target'] == irc.pseudoclient.uid and not irc.isInternalClient(source): + target = args['target'] + text = args['text'] + + if target == irc.pseudoclient.uid and not irc.isInternalClient(source): irc.called_by = source - irc.callCommand(source, args['text']) + irc.callCommand(source, text) + else: + for sbot in world.services.values(): + if target == sbot.uids.get(irc.name): + sbot.call_cmd(irc, source, text) + return utils.add_hook(handle_commands, 'PRIVMSG') @@ -204,12 +212,12 @@ def handle_newservice(irc, source, command, args): # Track the service's UIDs on each network. service = world.services[name] service.uids[irc.name] = u = irc.proto.spawnClient(name, name, - irc.serverdata['hostname'], modes=modes, opertype="PyLink Service") + irc.serverdata['hostname'], modes=modes, opertype="PyLink Service").uid # TODO: channels should be tracked in a central database, not hardcoded # in conf. for chan in irc.serverdata['channels']: - irc.proto.join(u.uid, chan) + irc.proto.join(u, chan) utils.add_hook(handle_newservice, 'PYLINK_NEW_SERVICE') @@ -227,7 +235,7 @@ utils.add_hook(handle_disconnect, 'PYLINK_DISCONNECT') def handle_endburst(irc, source, command, args): """Handles network bursts.""" if source == irc.uplink: - log.debug('(%s): spawning service bots now.') + log.debug('(%s): spawning service bots now.', irc.name) # We just connected. Burst all our registered services. for name, sbot in world.services.items(): diff --git a/utils.py b/utils.py index 78b7540..fe7aaac 100644 --- a/utils.py +++ b/utils.py @@ -153,6 +153,7 @@ def getDatabaseName(dbname): class ServiceBot(): def __init__(self, name, default_help=True, default_request=True, default_list=True): self.name = name + # We make the command definitions a dict of lists of functions. Multiple # plugins are actually allowed to bind to one function name; this just causes # them to be called in the order that they are bound. @@ -181,6 +182,39 @@ class ServiceBot(): else: raise NotImplementedError("Network specific plugins not supported yet.") + def reply(self, irc, text, notice=True): + """Replies to a message using the right service UID.""" + servuid = self.uids.get(irc.name) + if not servuid: + log.warning("(%s) Possible desync? UID for service %s doesn't exist!", irc.name, self.name) + return + + irc.reply(text, notice=notice, source=servuid) + + def call_cmd(self, irc, source, text): + """ + Calls a PyLink bot command. source is the caller's UID, and text is the + full, unparsed text of the message. + """ + irc.called_by = source + + cmd_args = text.strip().split(' ') + cmd = cmd_args[0].lower() + cmd_args = cmd_args[1:] + if cmd not in self.commands: + self.reply(irc, 'Error: Unknown command %r.' % cmd) + log.info('(%s/%s) Received unknown command %r from %s', irc.name, self.name, cmd, irc.getHostmask(source)) + return + + log.info('(%s/%s) Calling command %r for %s', irc.name, self.name, cmd, irc.getHostmask(source)) + for func in self.commands[cmd]: + try: + func(irc, source, cmd_args) + except NotAuthenticatedError: + self.reply(irc, 'Error: You are not authorized to perform this operation.') + except Exception as e: + log.exception('Unhandled exception caught in command %r', cmd) + self.reply(irc, 'Uncaught exception in command %r: %s: %s' % (cmd, type(e).__name__, str(e))) def add_cmd(self, func, name=None): """Binds an IRC command function to the given command name.""" @@ -192,16 +226,16 @@ class ServiceBot(): return func def help(self, irc, source, args): - irc.reply("Help command stub called.") + self.reply(irc, "Help command stub called.") def request(self, irc, source, args): - irc.reply("Request command stub called.") + self.reply(irc, "Request command stub called.") def remove(self, irc, source, args): - irc.reply("Remove command stub called.") + self.reply(irc, "Remove command stub called.") def listcommands(self, irc, source, args): - irc.reply("List command stub called.") + self.reply(irc, "List command stub called.") def registerService(name, *args, **kwargs): name = name.lower()