pyircbot/pyircbot/rpc.py

184 lines
6.3 KiB
Python

"""
.. module:: BotRPC
:synopsis: RPC server
.. moduleauthor:: Dave Pedu <dave@davepedu.com>
"""
import logging
from pyircbot import jsonrpc
from threading import Thread
class BotRPC(Thread):
""":param main: A reference to the PyIRCBot instance this instance will control
:type main: PyIRCBot
"""
def __init__(self, main):
Thread.__init__(self, daemon=True)
self.bot = main
self.log = logging.getLogger('RPC')
self.server = jsonrpc.Server(
jsonrpc.JsonRpc20(),
jsonrpc.TransportTcpIp(
addr=(
self.bot.botconfig["bot"]["rpcbind"],
self.bot.botconfig["bot"]["rpcport"]
)
)
)
self.server.register_function(self.importModule)
self.server.register_function(self.deportModule)
self.server.register_function(self.loadModule)
self.server.register_function(self.unloadModule)
self.server.register_function(self.reloadModule)
self.server.register_function(self.redoModule)
self.server.register_function(self.getLoadedModules)
self.server.register_function(self.pluginCommand)
self.server.register_function(self.setPluginVar)
self.server.register_function(self.getPluginVar)
self.server.register_function(self.quit)
self.server.register_function(self.eval)
self.server.register_function(self.exec)
self.start()
def run(self):
"""Internal, starts the RPC server"""
self.server.serve()
def importModule(self, moduleName):
"""Import a module
:param moduleName: Name of the module to import
:type moduleName: str"""
self.log.info("RPC: calling importModule(%s)" % moduleName)
return self.bot.importmodule(moduleName)
def deportModule(self, moduleName):
"""Remove a module's code from memory. If the module is loaded it will be unloaded silently.
:param moduleName: Name of the module to import
:type moduleName: str"""
self.log.info("RPC: calling deportModule(%s)" % moduleName)
self.bot.deportmodule(moduleName)
def loadModule(self, moduleName):
"""Activate a module.
:param moduleName: Name of the module to activate
:type moduleName: str"""
self.log.info("RPC: calling loadModule(%s)" % moduleName)
return self.bot.loadmodule(moduleName)
def unloadModule(self, moduleName):
"""Deactivate a module.
:param moduleName: Name of the module to deactivate
:type moduleName: str"""
self.log.info("RPC: calling unloadModule(%s)" % moduleName)
self.bot.unloadmodule(moduleName)
def reloadModule(self, moduleName):
"""Deactivate and activate a module.
:param moduleName: Name of the target module
:type moduleName: str"""
self.log.info("RPC: calling reloadModule(%s)" % moduleName)
self.bot.unloadmodule(moduleName)
return self.bot.loadmodule(moduleName)
def redoModule(self, moduleName):
"""Reload a running module from disk
:param moduleName: Name of the target module
:type moduleName: str"""
self.log.info("RPC: calling redoModule(%s)" % moduleName)
return self.bot.redomodule(moduleName)
def getLoadedModules(self):
"""Return a list of active modules
:returns: list -- ['ModuleName1', 'ModuleName2']"""
self.log.info("RPC: calling getLoadedModules()")
return list(self.bot.moduleInstances.keys())
def pluginCommand(self, moduleName, methodName, argList):
"""Run a method of an active module
:param moduleName: Name of the target module
:type moduleName: str
:param methodName: Name of the target method
:type methodName: str
:param argList: List of positional arguments to call the method with
:type argList: list
:returns: mixed -- Any basic type the target method may return"""
plugin = self.bot.getmodulebyname(moduleName)
if not plugin:
return (False, "Plugin not found")
method = getattr(plugin, methodName)
if not method:
return (False, "Method not found")
self.log.info("RPC: calling %s.%s(%s)" % (moduleName, methodName, argList))
return (True, method(*argList))
def getPluginVar(self, moduleName, moduleVarName):
"""Extract a property from an active module and return it
:param moduleName: Name of the target module
:type moduleName: str
:param moduleVarName: Name of the target property
:type moduleVarName: str
:returns: mixed -- Any basic type extracted from an active module"""
plugin = self.bot.getmodulebyname(moduleName)
if moduleName == "_core":
plugin = self.bot
if not plugin:
return (False, "Plugin not found")
self.log.info("RPC: getting %s.%s" % (moduleName, moduleVarName))
return (True, getattr(plugin, moduleVarName))
def setPluginVar(self, moduleName, moduleVarName, value):
"""Set a property of an active module
:param moduleName: Name of the target module
:type moduleName: str
:param moduleVarName: Name of the target property
:type moduleVarName: str
:param value: Value the target property will be set to
:type value: str"""
plugin = self.bot.getmodulebyname(moduleName)
if moduleName == "_core":
plugin = self.bot
if not plugin:
return (False, "Plugin not found")
self.log.info("RPC: setting %s.%s = %s )" % (moduleName, moduleVarName, value))
setattr(plugin, moduleVarName, value)
return (True, "Var set")
def eval(self, code):
"""Execute arbitrary python code on the bot
:param code: Python code to pass to eval
:type code: str"""
return (True, eval(code))
def exec(self, code):
"""Execute arbitrary python code on the bot
:param code: Python code to pass to exec
:type code: str"""
return (True, exec(code))
def quit(self, message):
"""Tell the bot to quit IRC and exit
:param message: Quit message
:type moduleName: str"""
self.bot.kill(message=message)
return (True, "Shutdown ordered")