From 4df2b77fdf42046fe19bd371be7c7255986b5980 Mon Sep 17 00:00:00 2001 From: RaNaN Date: Tue, 6 Mar 2012 13:36:39 +0100 Subject: renamed hooks to addons, new filemanager and database, many new api methods you will loose ALL your LINKS, webinterface will NOT work --- module/AddonManager.py | 253 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 module/AddonManager.py (limited to 'module/AddonManager.py') diff --git a/module/AddonManager.py b/module/AddonManager.py new file mode 100644 index 000000000..cec650c92 --- /dev/null +++ b/module/AddonManager.py @@ -0,0 +1,253 @@ +# -*- coding: utf-8 -*- + +""" + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + @author: RaNaN, mkaay +""" +import __builtin__ + +from traceback import print_exc +from thread import start_new_thread +from threading import RLock + +from types import MethodType + +from module.threads.AddonThread import AddonThread +from module.plugins.PluginManager import literal_eval +from utils import lock, to_string + +class AddonManager: + """ Manages addons, loading, unloading. """ + + def __init__(self, core): + self.core = core + self.config = self.core.config + + __builtin__.addonManager = self #needed to let addons register themself + + self.log = self.core.log + self.plugins = {} + self.methods = {} # dict of names and list of methods usable by rpc + self.events = {} # Contains event that will be registred + + self.lock = RLock() + self.createIndex() + + #registering callback for config event + self.config.changeCB = MethodType(self.dispatchEvent, "configChanged", basestring) + + # manage addons an config change + self.addEvent("configChanged", self.manageAddons) + + @lock + def callInHooks(self, event, *args): + """ Calls a method in all addons and catch / log errors""" + for plugin in self.plugins.itervalues(): + self.call(plugin, event, *args) + self.dispatchEvent(event, *args) + + def call(self, addon, f, *args): + try: + func = getattr(addon, f) + return func(*args) + except Exception, e: + addon.logError(_("Error when executing %s" % f), e) + if self.core.debug: + print_exc() + + def addRPC(self, plugin, func, doc): + doc = doc.strip() if doc else "" + + if plugin in self.methods: + self.methods[plugin][func] = doc + else: + self.methods[plugin] = {func: doc} + + def callRPC(self, plugin, func, args): + if not args: args = [] + else: + args = literal_eval(args) + + plugin = self.plugins[plugin] + f = getattr(plugin, func) + return f(*args) + + @lock + def createIndex(self): + active = [] + deactive = [] + + for pluginname in self.core.pluginManager.getPlugins("addons"): + try: + # check first for builtin plugin + attrs = self.core.pluginManager.loadAttributes("addons", pluginname) + internal = attrs.get("internal", False) + + if internal or self.core.config.get(pluginname, "activated"): + pluginClass = self.core.pluginManager.loadClass("addons", pluginname) + + if not pluginClass: continue + + plugin = pluginClass(self.core, self) + self.plugins[pluginClass.__name__] = plugin + + # hide internals from printing + if not internal and plugin.isActivated(): + active.append(pluginClass.__name__) + else: + self.log.debug("Loaded internal plugin: %s" % pluginClass.__name__) + else: + deactive.append(pluginname) + + + except: + self.log.warning(_("Failed activating %(name)s") % {"name": pluginname}) + if self.core.debug: + print_exc() + + self.log.info(_("Activated addons: %s") % ", ".join(sorted(active))) + self.log.info(_("Deactivate addons: %s") % ", ".join(sorted(deactive))) + + def manageAddons(self, plugin, name, value): + # check if section was a plugin + if plugin not in self.core.pluginManager.getPlugins("addons"): + return + + if name == "activated" and value: + self.activateAddon(plugin) + elif name == "activated" and not value: + self.deactivateAddon(plugin) + + @lock + def activateAddon(self, plugin): + #check if already loaded + if plugin in self.plugins: + return + + pluginClass = self.core.pluginManager.loadClass("addons", plugin) + + if not pluginClass: return + + self.log.debug("Plugin loaded: %s" % plugin) + + plugin = pluginClass(self.core, self) + self.plugins[pluginClass.__name__] = plugin + + # active the addon in new thread + start_new_thread(plugin.activate, tuple()) + self.registerEvents() + + @lock + def deactivateAddon(self, plugin): + if plugin not in self.plugins: + return + else: + addon = self.plugins[plugin] + + if addon.__internal__: return + + self.call(addon, "deactivate") + self.log.debug("Plugin deactivated: %s" % plugin) + + #remove periodic call + self.log.debug("Removed callback %s" % self.core.scheduler.removeJob(addon.cb)) + del self.plugins[addon.__name__] + + #remove event listener + for f in dir(addon): + if f.startswith("__") or type(getattr(addon, f)) != MethodType: + continue + self.core.eventManager.removeFromEvents(getattr(addon, f)) + + def activateAddons(self): + self.log.info(_("Activating Plugins...")) + for plugin in self.plugins.itervalues(): + if plugin.isActivated(): + self.call(plugin, "activate") + + self.registerEvents() + + def deactivateAddons(self): + """ Called when core is shutting down """ + self.log.info(_("Deactivating Plugins...")) + for plugin in self.plugins.itervalues(): + self.call(plugin, "deactivate") + + def downloadPreparing(self, pyfile): + self.callInHooks("downloadPreparing", pyfile) + + def downloadFinished(self, pyfile): + self.callInHooks("downloadFinished", pyfile) + + def downloadFailed(self, pyfile): + self.callInHooks("downloadFailed", pyfile) + + def packageFinished(self, package): + self.callInHooks("packageFinished", package) + + def beforeReconnecting(self, ip): + self.callInHooks("beforeReconnecting", ip) + + def afterReconnecting(self, ip): + self.callInHooks("afterReconnecting", ip) + + @lock + def startThread(self, function, *args, **kwargs): + AddonThread(self.core.threadManager, function, args, kwargs) + + def activePlugins(self): + """ returns all active plugins """ + return [x for x in self.plugins.itervalues() if x.isActivated()] + + def getAllInfo(self): + """returns info stored by addon plugins""" + info = {} + for name, plugin in self.plugins.iteritems(): + if plugin.info: + #copy and convert so str + info[name] = dict( + [(x, to_string(y)) for x, y in plugin.info.iteritems()]) + return info + + def getInfo(self, plugin): + info = {} + if plugin in self.plugins and self.plugins[plugin].info: + info = dict([(x, to_string(y)) + for x, y in self.plugins[plugin].info.iteritems()]) + + return info + + def addEventListener(self, plugin, func, event): + if plugin not in self.events: + self.events[plugin] = [] + self.events[plugin].append((func, event)) + + def registerEvents(self): + for name, plugin in self.plugins.iteritems(): + if name in self.events: + for func, event in self.events[name]: + self.addEvent(event, getattr(plugin, func)) + # clean up + del self.events[name] + + def addConfigHandler(self, plugin, func): + pass #TODO + + def addEvent(self, *args): + self.core.eventManager.addEvent(*args) + + def dispatchEvent(self, *args): + self.core.eventManager.dispatchEvent(*args) + -- cgit v1.2.3 From 2a74f88fcaf3d3baac24397de81a967c0b8c73e2 Mon Sep 17 00:00:00 2001 From: RaNaN Date: Thu, 17 May 2012 20:06:11 +0200 Subject: small typo fixes and TODOs --- module/AddonManager.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'module/AddonManager.py') diff --git a/module/AddonManager.py b/module/AddonManager.py index cec650c92..ef5c52149 100644 --- a/module/AddonManager.py +++ b/module/AddonManager.py @@ -35,12 +35,12 @@ class AddonManager: self.core = core self.config = self.core.config - __builtin__.addonManager = self #needed to let addons register themself + __builtin__.addonManager = self #needed to let addons register themselves self.log = self.core.log self.plugins = {} self.methods = {} # dict of names and list of methods usable by rpc - self.events = {} # Contains event that will be registred + self.events = {} # Contains event that will be registered self.lock = RLock() self.createIndex() @@ -147,7 +147,7 @@ class AddonManager: # active the addon in new thread start_new_thread(plugin.activate, tuple()) - self.registerEvents() + self.registerEvents() # TODO: BUG: events will be destroyed and not re-registered @lock def deactivateAddon(self, plugin): @@ -230,11 +230,15 @@ class AddonManager: return info def addEventListener(self, plugin, func, event): + """ add the event to the list """ + + if plugin not in self.events: self.events[plugin] = [] self.events[plugin].append((func, event)) def registerEvents(self): + """ actually register all saved events """ for name, plugin in self.plugins.iteritems(): if name in self.events: for func, event in self.events[name]: -- cgit v1.2.3 From 2c88c9f9b6e1360ca0712bbd4d6a27cc285f0db6 Mon Sep 17 00:00:00 2001 From: RaNaN Date: Fri, 10 Aug 2012 20:17:39 +0200 Subject: fixed import --- module/AddonManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'module/AddonManager.py') diff --git a/module/AddonManager.py b/module/AddonManager.py index ef5c52149..4283b4652 100644 --- a/module/AddonManager.py +++ b/module/AddonManager.py @@ -25,7 +25,7 @@ from threading import RLock from types import MethodType from module.threads.AddonThread import AddonThread -from module.plugins.PluginManager import literal_eval +from module.PluginManager import literal_eval from utils import lock, to_string class AddonManager: -- cgit v1.2.3