From 56b495e8fb0d4536d7cbc5579e612e6517d2cf4f Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Sat, 13 Jun 2015 13:06:10 -0500 Subject: [PATCH] add an XML-RPC interface to the irc bot this allows plugins to register methods that can be called over XML-RPC the old bot used this interface behind apache for a web service, but i think in this version it will only be for django -> ircbot, and django will have a rest API for other things --- dr_botzo/dr_botzo/settings.py | 5 ++++ dr_botzo/ircbot/bot.py | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/dr_botzo/dr_botzo/settings.py b/dr_botzo/dr_botzo/settings.py index 2a6c8cb..9fb9c17 100644 --- a/dr_botzo/dr_botzo/settings.py +++ b/dr_botzo/dr_botzo/settings.py @@ -131,6 +131,11 @@ IRCBOT_SSL = False IRCBOT_IPV6 = False +# XML-RPC settings +IRCBOT_XMLRPC_HOST = 'localhost' +IRCBOT_XMLRPC_PORT = 13132 + + # IRC module stuff # weather diff --git a/dr_botzo/ircbot/bot.py b/dr_botzo/ircbot/bot.py index f9ccd12..a970435 100644 --- a/dr_botzo/ircbot/bot.py +++ b/dr_botzo/ircbot/bot.py @@ -7,9 +7,11 @@ import collections import copy import logging import re +from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler import socket import ssl import sys +import thread from django.conf import settings @@ -25,6 +27,15 @@ from ircbot.models import Alias, IrcChannel, IrcPlugin log = logging.getLogger('ircbot.bot') +class IrcBotXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): + + """Override the basic request handler to change the logging.""" + + def log_message(self, format, *args): + """Use a logger rather than stderr.""" + log.debug("XML-RPC - %s - %s", self.client_address[0], format%args) + + class PrioritizedRegexHandler(collections.namedtuple('Base', ('priority', 'regex', 'callback'))): def __lt__(self, other): "when sorting prioritized handlers, only use the priority" @@ -325,6 +336,16 @@ class IRCBot(irc.client.SimpleIRCClient): self.connection.reactor.add_global_regex_handler('privmsg', r'^!unload\s+([\S]+)$', getattr(self, 'handle_unload'), -20) + # load XML-RPC server + self.xmlrpc = SimpleXMLRPCServer((settings.IRCBOT_XMLRPC_HOST, settings.IRCBOT_XMLRPC_PORT), + requestHandler=IrcBotXMLRPCRequestHandler, allow_none=True) + self.xmlrpc.register_introspection_functions() + + thread.start_new_thread(self._xmlrpc_listen, ()) + + # register XML-RPC stuff + self.xmlrpc.register_function(self.privmsg, 'privmsg') + def _connected_checker(self): if not self.connection.is_connected(): self.connection.execute_delayed(self.reconnection_interval, @@ -468,6 +489,7 @@ class IRCBot(irc.client.SimpleIRCClient): msg -- Quit message. """ + self._xmlrpc_shutdown() self.connection.disconnect(msg) sys.exit(0) @@ -682,6 +704,32 @@ class IRCBot(irc.client.SimpleIRCClient): if stop: return "NO MORE" + def xmlrpc_register_function(self, func, name): + """Add a method to the XML-RPC interface. + + :param func: the method to register + :type func: a method + :param name: the name to expose the method as + :type name: str + """ + + if func and self.xmlrpc: + if hasattr(func, '__call__'): + self.xmlrpc.register_function(func, name) + + def _xmlrpc_listen(self): + """Begin listening. Hopefully this was called in a new thread.""" + + self.xmlrpc.serve_forever() + + def _xmlrpc_shutdown(self): + """Shut down the XML-RPC server.""" + + if self.xmlrpc is not None: + self.xmlrpc.shutdown() + self.xmlrpc.server_close() + + def start(self): """Start the bot."""