diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core.py | 27 | ||||
-rw-r--r-- | src/plugin.py | 33 | ||||
-rw-r--r-- | src/plugin_manager.py | 25 |
3 files changed, 85 insertions, 0 deletions
diff --git a/src/core.py b/src/core.py index 3cdc7592..d644c19b 100644 --- a/src/core.py +++ b/src/core.py @@ -36,6 +36,8 @@ import windows import connection import timed_events +from plugin_manager import PluginManager + from data_forms import DataFormsTab from config import config, options from logger import logger @@ -125,6 +127,8 @@ class Core(object): 'server_cycle': (self.command_server_cycle, _('Usage: /server_cycle [domain] [message]\nServer Cycle: disconnect and reconnects in all the rooms in domain.'), None), 'bind': (self.command_bind, _('Usage: /bind <key> <equ>\nBind: bind a key to an other key or to a “command”. For example "/bind ^H KEY_UP" makes Control + h do the same same than the Up key.'), None), 'pubsub': (self.command_pubsub, _('Usage: /pubsub <domain>\nPubsub: Open a pubsub browser on the given domain'), None), + 'load': (self.command_load, _('Usage: /load <script.py>\nLoad: Load the specified python script'), None), + 'unload': (self.command_unload, _('Usage: /unload <script.py>\nUnload: Unload the specified python script'), None), } self.key_func = { @@ -169,6 +173,7 @@ class Core(object): self.xmpp.add_event_handler("chatstate_inactive", self.on_chatstate_inactive) self.timed_events = set() + self.plugin_manager = PluginManager(self) def coucou(self): self.command_pubsub('pubsub.louiz.org') @@ -1121,6 +1126,28 @@ class Core(object): def completion_status(self, the_input): return the_input.auto_completion([status for status in possible_show], ' ') + def command_load(self, arg): + """ + /load <script.py> + """ + args = arg.split() + if len(args) != 1: + self.command_help('load') + return + filename = args[0] + self.plugin_manager.load(filename) + + def command_unload(self, arg): + """ + /unload <script.py> + """ + args = arg.split() + if len(args) != 1: + self.command_help('unload') + return + filename = args[0] + self.plugin_manager.unload(filename) + def command_message(self, arg): """ /message <jid> [message] diff --git a/src/plugin.py b/src/plugin.py new file mode 100644 index 00000000..e8386d16 --- /dev/null +++ b/src/plugin.py @@ -0,0 +1,33 @@ +import inspect + +class BasePlugin(object): + """ + Class that all plugins derive from. Any methods beginning with command_ + are interpreted as a command and beginning with on_ are interpreted as + event handlers + """ + + def __init__(self, core): + self.core = core + for k, v in inspect.getmembers(self, inspect.ismethod): + if k.startswith('on_'): + core.xmpp.add_event_handler(k[3:], v) + elif k.startswith('command_'): + command = k[len('command_'):] + core.commands[command] = (v, v.__doc__, None) + self.init() + + def init(self): + pass + + def cleanup(self): + pass + + def unload(self): + for k, v in inspect.getmembers(self, inspect.ismethod): + if k.startswith('on_'): + self.core.xmpp.del_event_handler(k[3:], v) + elif k.startswith('command_'): + command = k[len('command_'):] + del self.core.commands[command] + self.cleanup() diff --git a/src/plugin_manager.py b/src/plugin_manager.py new file mode 100644 index 00000000..3f900e39 --- /dev/null +++ b/src/plugin_manager.py @@ -0,0 +1,25 @@ +class PluginManager(object): + def __init__(self, core): + self.core = core + self.plugins = {} + + def load(self, name): + if name in self.plugins: + self.plugins[name].unload() + + try: + code = compile(open(name).read(), name, 'exec') + from plugin import BasePlugin + globals = { 'BasePlugin' : BasePlugin } + exec(code, globals) + self.plugins[name] = globals['Plugin'](self.core) + except Exception as e: + self.core.information("Could not load plugin: %s" % (e,)) + + def unload(self, name): + if name in self.plugins: + try: + self.plugins[name].unload() + del self.plugins[name] + except Exception as e: + self.core.information("Could not unload plugin (may not be safe to try again): %s" % (e,)) |