You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
6.3 KiB
183 lines
6.3 KiB
""" |
|
.. 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") |
|
|
|
|