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
This commit is contained in:
Brian S. Stephan 2015-06-13 13:06:10 -05:00
parent 65a03ced03
commit 56b495e8fb
2 changed files with 53 additions and 0 deletions

View File

@ -131,6 +131,11 @@ IRCBOT_SSL = False
IRCBOT_IPV6 = False IRCBOT_IPV6 = False
# XML-RPC settings
IRCBOT_XMLRPC_HOST = 'localhost'
IRCBOT_XMLRPC_PORT = 13132
# IRC module stuff # IRC module stuff
# weather # weather

View File

@ -7,9 +7,11 @@ import collections
import copy import copy
import logging import logging
import re import re
from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler
import socket import socket
import ssl import ssl
import sys import sys
import thread
from django.conf import settings from django.conf import settings
@ -25,6 +27,15 @@ from ircbot.models import Alias, IrcChannel, IrcPlugin
log = logging.getLogger('ircbot.bot') 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'))): class PrioritizedRegexHandler(collections.namedtuple('Base', ('priority', 'regex', 'callback'))):
def __lt__(self, other): def __lt__(self, other):
"when sorting prioritized handlers, only use the priority" "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]+)$', self.connection.reactor.add_global_regex_handler('privmsg', r'^!unload\s+([\S]+)$',
getattr(self, 'handle_unload'), -20) 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): def _connected_checker(self):
if not self.connection.is_connected(): if not self.connection.is_connected():
self.connection.execute_delayed(self.reconnection_interval, self.connection.execute_delayed(self.reconnection_interval,
@ -468,6 +489,7 @@ class IRCBot(irc.client.SimpleIRCClient):
msg -- Quit message. msg -- Quit message.
""" """
self._xmlrpc_shutdown()
self.connection.disconnect(msg) self.connection.disconnect(msg)
sys.exit(0) sys.exit(0)
@ -682,6 +704,32 @@ class IRCBot(irc.client.SimpleIRCClient):
if stop: if stop:
return "NO MORE" 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): def start(self):
"""Start the bot.""" """Start the bot."""