summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--module/Api.py2
-rw-r--r--module/HookManager.py191
-rw-r--r--module/interaction/EventManager.py151
-rw-r--r--module/plugins/Crypter.py4
-rw-r--r--module/plugins/Hook.py32
-rw-r--r--module/plugins/internal/MultiHoster.py2
-rw-r--r--module/threads/DecrypterThread.py2
-rw-r--r--module/threads/HookThread.py9
-rw-r--r--module/threads/InfoThread.py48
-rw-r--r--module/utils/__init__.py19
-rw-r--r--module/web/pyload_app.py1
-rwxr-xr-xpyLoadCore.py8
12 files changed, 216 insertions, 253 deletions
diff --git a/module/Api.py b/module/Api.py
index bafb69408..769fcdf0d 100644
--- a/module/Api.py
+++ b/module/Api.py
@@ -810,7 +810,7 @@ class Api(Iface):
def getEvents(self, uuid):
"""Lists occured events, may be affected to changes in future.
- :param uuid:
+ :param uuid: self assigned string uuid which has to be unique
:return: list of `Events`
"""
# TODO
diff --git a/module/HookManager.py b/module/HookManager.py
index 7057b6ee6..41908bc47 100644
--- a/module/HookManager.py
+++ b/module/HookManager.py
@@ -18,7 +18,7 @@
"""
import __builtin__
-import traceback
+from traceback import print_exc
from thread import start_new_thread
from threading import RLock
@@ -38,11 +38,9 @@ class HookManager:
__builtin__.hookManager = self #needed to let hooks register themself
self.log = self.core.log
- self.plugins = []
- self.pluginMap = {}
- self.methods = {} #dict of names and list of methods usable by rpc
-
- self.events = {} # contains events
+ 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()
@@ -53,17 +51,19 @@ class HookManager:
# manage hooks an config change
self.addEvent("configChanged", self.manageHooks)
- def try_catch(func):
- def new(*args):
+ @lock
+ def callInHooks(self, event, *args):
+ """ Calls a method in hook and catch / log errors"""
+ for plugin in self.plugins.itervalues():
try:
+ func = getattr(plugin, event)
return func(*args)
except Exception, e:
- args[0].log.error(_("Error executing hooks: %s") % str(e))
- if args[0].core.debug:
- traceback.print_exc()
-
- return new
+ plugin.logError(_("Error executing %s" % event), e)
+ if self.core.debug:
+ print_exc()
+ self.dispatchEvent(event, *args)
def addRPC(self, plugin, func, doc):
plugin = plugin.rpartition(".")[2]
@@ -79,14 +79,12 @@ class HookManager:
else:
args = literal_eval(args)
- plugin = self.pluginMap[plugin]
+ plugin = self.plugins[plugin]
f = getattr(plugin, func)
return f(*args)
-
+ @lock
def createIndex(self):
- plugins = []
-
active = []
deactive = []
@@ -97,10 +95,9 @@ class HookManager:
if self.core.config.get(pluginname, "activated"):
pluginClass = self.core.pluginManager.loadClass("hooks", pluginname)
if not pluginClass: continue
-
+
plugin = pluginClass(self.core, self)
- plugins.append(plugin)
- self.pluginMap[pluginClass.__name__] = plugin
+ self.plugins[pluginClass.__name__] = plugin
if plugin.isActivated():
active.append(pluginClass.__name__)
else:
@@ -110,15 +107,12 @@ class HookManager:
except:
self.log.warning(_("Failed activating %(name)s") % {"name": pluginname})
if self.core.debug:
- traceback.print_exc()
+ print_exc()
self.log.info(_("Activated plugins: %s") % ", ".join(sorted(active)))
self.log.info(_("Deactivate plugins: %s") % ", ".join(sorted(deactive)))
- self.plugins = plugins
-
def manageHooks(self, plugin, name, value):
-
# check if section was a plugin
if plugin not in self.core.pluginManager.getPlugins("hooks"):
return
@@ -128,12 +122,11 @@ class HookManager:
elif name == "activated" and not value:
self.deactivateHook(plugin)
+ @lock
def activateHook(self, plugin):
-
#check if already loaded
- for inst in self.plugins:
- if inst.__name__ == plugin:
- return
+ if plugin in self.plugins:
+ return
pluginClass = self.core.pluginManager.loadClass("hooks", plugin)
@@ -142,105 +135,63 @@ class HookManager:
self.log.debug("Plugin loaded: %s" % plugin)
plugin = pluginClass(self.core, self)
- self.plugins.append(plugin)
- self.pluginMap[pluginClass.__name__] = plugin
+ self.plugins[pluginClass.__name__] = plugin
- # call core Ready
- start_new_thread(plugin.coreReady, tuple())
+ # active the hook in new thread
+ start_new_thread(plugin.activate, tuple())
+ @lock
def deactivateHook(self, plugin):
+ if plugin not in self.plugins:
+ return
+ else:
+ hook = self.plugins[plugin]
- hook = None
- for inst in self.plugins:
- if inst.__name__ == plugin:
- hook = inst
-
- if not hook: return
-
- hook.unload()
- self.log.debug("Plugin unloaded: %s" % plugin)
+ hook.deactivate()
+ self.log.debug("Plugin deactivated: %s" % plugin)
#remove periodic call
self.log.debug("Removed callback %s" % self.core.scheduler.removeJob(hook.cb))
- self.plugins.remove(hook)
- del self.pluginMap[hook.__name__]
+ del self.plugins[hook.__name__]
+ #remove event listener
+ for f in dir(hook):
+ if f.startswith("__") or type(getattr(hook, f)) != MethodType:
+ continue
+ self.core.eventManager.removeFromEvents(getattr(hook, f))
- @try_catch
- def coreReady(self):
- for plugin in self.plugins:
+ def activateHooks(self):
+ for plugin in self.plugins.itervalues():
if plugin.isActivated():
- plugin.coreReady()
-
- self.dispatchEvent("coreReady")
+ plugin.activate()
- @try_catch
- def coreExiting(self):
- for plugin in self.plugins:
+ def deactivateHooks(self):
+ """ Called when core is shutting down """
+ for plugin in self.plugins.itervalues():
if plugin.isActivated():
- plugin.coreExiting()
-
- self.dispatchEvent("coreExiting")
+ plugin.deactivate()
- @lock
def downloadPreparing(self, pyfile):
- for plugin in self.plugins:
- if plugin.isActivated():
- plugin.downloadPreparing(pyfile)
+ self.callInHooks("downloadPreparing", pyfile)
- self.dispatchEvent("downloadPreparing", pyfile)
-
- @lock
def downloadFinished(self, pyfile):
- for plugin in self.plugins:
- if plugin.isActivated():
- if "downloadFinished" in plugin.__threaded__:
- self.startThread(plugin.downloadFinished, pyfile)
- else:
- plugin.downloadFinished(pyfile)
-
- self.dispatchEvent("downloadFinished", pyfile)
+ self.callInHooks("downloadFinished", pyfile)
- @lock
- @try_catch
def downloadFailed(self, pyfile):
- for plugin in self.plugins:
- if plugin.isActivated():
- if "downloadFailed" in plugin.__threaded__:
- self.startThread(plugin.downloadFinished, pyfile)
- else:
- plugin.downloadFailed(pyfile)
-
- self.dispatchEvent("downloadFailed", pyfile)
+ self.callInHooks("downloadFailed", pyfile)
- @lock
def packageFinished(self, package):
- for plugin in self.plugins:
- if plugin.isActivated():
- if "packageFinished" in plugin.__threaded__:
- self.startThread(plugin.packageFinished, package)
- else:
- plugin.packageFinished(package)
-
- self.dispatchEvent("packageFinished", package)
+ self.callInHooks("packageFinished", package)
- @lock
def beforeReconnecting(self, ip):
- for plugin in self.plugins:
- plugin.beforeReconnecting(ip)
+ self.callInHooks("beforeReconnecting", ip)
- self.dispatchEvent("beforeReconnecting", ip)
-
- @lock
def afterReconnecting(self, ip):
- for plugin in self.plugins:
- if plugin.isActivated():
- plugin.afterReconnecting(ip)
-
- self.dispatchEvent("afterReconnecting", ip)
+ self.callInHooks("afterReconnecting", ip)
+ @lock
def startThread(self, function, *args, **kwargs):
- t = HookThread(self.core.threadManager, function, args, kwargs)
+ HookThread(self.core.threadManager, function, args, kwargs)
def activePlugins(self):
""" returns all active plugins """
@@ -249,42 +200,24 @@ class HookManager:
def getAllInfo(self):
"""returns info stored by hook plugins"""
info = {}
- for name, plugin in self.pluginMap.iteritems():
+ for name, plugin in self.plugins.iteritems():
if plugin.info:
#copy and convert so str
- info[name] = dict([(x, str(y) if not isinstance(y, basestring) else y) for x, y in plugin.info.iteritems()])
+ info[name] = dict(
+ [(x, str(y) if not isinstance(y, basestring) else y) for x, y in plugin.info.iteritems()])
return info
-
def getInfo(self, plugin):
info = {}
- if plugin in self.pluginMap and self.pluginMap[plugin].info:
+ if plugin in self.plugins and self.plugins[plugin].info:
info = dict([(x, str(y) if not isinstance(y, basestring) else y)
- for x, y in self.pluginMap[plugin].info.iteritems()])
+ for x, y in self.plugins[plugin].info.iteritems()])
return info
- def addEvent(self, event, func):
- """Adds an event listener for event name"""
- if event in self.events:
- self.events[event].append(func)
- else:
- self.events[event] = [func]
-
- def removeEvent(self, event, func):
- """removes previously added event listener"""
- if event in self.events:
- self.events[event].remove(func)
-
- def dispatchEvent(self, event, *args):
- """dispatches event with args"""
- if event in self.events:
- for f in self.events[event]:
- try:
- f(*args)
- except Exception, e:
- self.log.warning("Error calling event handler %s: %s, %s, %s"
- % (event, f, args, str(e)))
- if self.core.debug:
- traceback.print_exc()
+ def addEvent(self, *args):
+ self.core.eventManager.addEvent(*args)
+
+ def dispatchEvent(self, *args):
+ self.core.eventManager.dispatchEvent(*args)
diff --git a/module/interaction/EventManager.py b/module/interaction/EventManager.py
index 931f50446..38faa3c46 100644
--- a/module/interaction/EventManager.py
+++ b/module/interaction/EventManager.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
-from time import time
-from module.utils import uniqify
+from traceback import print_exc
+from time import time
class EventManager:
"""
@@ -10,70 +10,119 @@ class EventManager:
**Known Events:**
Most hook methods exists as events. These are some additional known events.
- ===================== ============== ==================================
- Name Arguments Description
- ===================== ============== ==================================
- downloadPreparing fid A download was just queued and will be prepared now.
- downloadStarts fid A plugin will immediately starts the download afterwards.
- linksAdded links, pid Someone just added links, you are able to modify the links.
- allDownloadsProcessed Every link was handled, pyload would idle afterwards.
- allDownloadsFinished Every download in queue is finished.
- unrarFinished folder, fname An Unrar job finished
- configChanged sec,opt,value The config was changed.
- ===================== ============== ==================================
+ ===================== ================ ===========================================================
+ Name Arguments Description
+ ===================== ================ ===========================================================
+ metaEvent eventName, *args Called for every event, with eventName and orginal args
+ downloadPreparing fid A download was just queued and will be prepared now.
+ downloadStarts fid A plugin will immediately starts the download afterwards.
+ linksAdded links, pid Someone just added links, you are able to modify the links.
+ allDownloadsProcessed Every link was handled, pyload would idle afterwards.
+ allDownloadsFinished Every download in queue is finished.
+ unrarFinished folder, fname An Unrar job finished
+ configChanged sec, opt, value The config was changed.
+ ===================== ================ ===========================================================
| Notes:
| allDownloadsProcessed is *always* called before allDownloadsFinished.
| configChanged is *always* called before pluginConfigChanged.
"""
+
+ CLIENT_EVENTS = ("packageUpdated", "packageInserted", "linkUpdated", "packageDeleted")
+
def __init__(self, core):
self.core = core
- self.clients = []
-
- def newClient(self, uuid):
- self.clients.append(Client(uuid))
+ self.log = core.log
- def clean(self):
- for n, client in enumerate(self.clients):
- if client.lastActive + 30 < time():
- del self.clients[n]
+ # uuid : list of events
+ self.clients = {}
+ self.events = {"metaEvent": []}
def getEvents(self, uuid):
- events = []
- validUuid = False
- for client in self.clients:
- if client.uuid == uuid:
- client.lastActive = time()
- validUuid = True
- while client.newEvents():
- events.append(client.popEvent().toList())
- break
- if not validUuid:
- self.newClient(uuid)
- events = [ReloadAllEvent("queue").toList(), ReloadAllEvent("collector").toList()]
- return uniqify(events, repr)
-
- def addEvent(self, event):
- for client in self.clients:
- client.addEvent(event)
-
- def dispatchEvent(self, *args):
- pass
+ """ Get accumulated events for uuid since last call, this also registeres new client """
+ if uuid not in self.clients:
+ self.clients[uuid] = Client()
+ return self.clients[uuid].get()
+
+ def addEvent(self, event, func):
+ """Adds an event listener for event name"""
+ if event in self.events:
+ if func in self.events[event]:
+ self.log.debug("Function already registered %s" % func)
+ else:
+ self.events[event].append(func)
+ else:
+ self.events[event] = [func]
+
+ def removeEvent(self, event, func):
+ """removes previously added event listener"""
+ if event in self.events:
+ self.events[event].remove(func)
+
+ def dispatchEvent(self, event, *args):
+ """dispatches event with args"""
+ for f in self.events["metaEvent"]:
+ try:
+ f(event, *args)
+ except Exception, e:
+ self.log.warning("Error calling event handler %s: %s, %s, %s"
+ % ("metaEvent", f, args, str(e)))
+ if self.core.debug:
+ print_exc()
+
+ if event in self.events:
+ for f in self.events[event]:
+ try:
+ f(*args)
+ except Exception, e:
+ self.log.warning("Error calling event handler %s: %s, %s, %s"
+ % (event, f, args, str(e)))
+ if self.core.debug:
+ print_exc()
+
+ # append to client event queue
+ if event in self.CLIENT_EVENTS:
+ for uuid, client in self.clients.items():
+ if client.delete():
+ del self.clients[uuid]
+ else:
+ client.append(event, args)
+
+
+ def removeFromEvents(self, func):
+ """ Removes func from all known events """
+ for name, events in self.events.iteritems():
+ if func in events:
+ events.remove(func)
+
class Client:
- def __init__(self, uuid):
- self.uuid = uuid
+
+ # delete clients after this time
+ TIMEOUT = 60 * 60
+ # max events, if this value is reached you should assume that older events were dropped
+ MAX = 30
+
+ def __init__(self):
self.lastActive = time()
self.events = []
- def newEvents(self):
- return len(self.events) > 0
+ def delete(self):
+ return self.lastActive + self.TIMEOUT < time()
+
+ def append(self, event, args):
+ ev = (event, args)
+ if ev not in self.events:
+ self.events.insert(0, ev)
- def popEvent(self):
- if not len(self.events):
- return None
- return self.events.pop(0)
+ del self.events[self.MAX:]
+
+
+ def get(self):
+ self.lastActive = time()
+
+ events = self.events
+ self.events = []
- def addEvent(self, event):
- self.events.append(event)
+ return [(ev, [str(x) for x in args]) for ev, args in events] \ No newline at end of file
diff --git a/module/plugins/Crypter.py b/module/plugins/Crypter.py
index fe7f0deb8..5d164da64 100644
--- a/module/plugins/Crypter.py
+++ b/module/plugins/Crypter.py
@@ -4,7 +4,7 @@ from traceback import print_exc
from module.Api import Destination
from module.common.packagetools import parseNames
-from module.utils import to_list, has_method
+from module.utils import to_list, has_method, uniqify
from module.utils.fs import exists, remove, fs_encode
from Base import Base, Retry
@@ -83,7 +83,7 @@ class Crypter(Base):
else: # single url
ret.append(url_or_pack)
# eliminate duplicates
- return set(ret)
+ return uniqify(ret)
def __init__(self, core, package=None, password=None):
Base.__init__(self, core)
diff --git a/module/plugins/Hook.py b/module/plugins/Hook.py
index fe464bdaa..76bc19dbe 100644
--- a/module/plugins/Hook.py
+++ b/module/plugins/Hook.py
@@ -19,6 +19,9 @@
from traceback import print_exc
+from functools import wraps
+from module.utils import has_method
+
from Base import Base
class Expose(object):
@@ -35,6 +38,7 @@ def AddEventListener(event):
return f
return _klass
+
class ConfigHandler(object):
""" register method as config handler """
def __new__(cls, f, *args, **kwargs):
@@ -42,13 +46,14 @@ class ConfigHandler(object):
return f
def threaded(f):
+ @wraps(f)
def run(*args,**kwargs):
hookManager.startThread(f, *args, **kwargs)
return run
class Hook(Base):
"""
- Base class for hook plugins.
+ Base class for hook plugins. Please use @threaded decorator for all longer running task.
"""
#: automatically register event listeners for functions, attribute will be deleted dont use it yourself
@@ -79,16 +84,16 @@ class Hook(Base):
for event, funcs in self.event_map.iteritems():
if type(funcs) in (list, tuple):
for f in funcs:
- self.manager.addEvent(event, getattr(self,f))
+ self.evm.addEvent(event, getattr(self,f))
else:
- self.manager.addEvent(event, getattr(self,funcs))
+ self.evm.addEvent(event, getattr(self,funcs))
#delete for various reasons
self.event_map = None
if self.event_list:
for f in self.event_list:
- self.manager.addEvent(f, getattr(self,f))
+ self.evm.addEvent(f, getattr(self,f))
self.event_list = None
@@ -121,23 +126,16 @@ class Hook(Base):
""" more init stuff if needed """
pass
- def unload(self):
- """ called when hook was deactivated """
- pass
-
- def deactivate(self):
- pass
-
def activate(self):
- pass
+ """ Used to activate the hook """
+ if has_method(self.__class__, "coreReady"):
+ self.logDebug("Deprecated method .coreReady() use activated() instead")
+ self.coreReady()
- #event methods - overwrite these if needed
- def coreReady(self):
+ def deactivate(self):
+ """ Used to deactivate the hook. """
pass
- def coreExiting(self):
- pass
-
def downloadPreparing(self, pyfile):
pass
diff --git a/module/plugins/internal/MultiHoster.py b/module/plugins/internal/MultiHoster.py
index 872e0b770..1629fdc5f 100644
--- a/module/plugins/internal/MultiHoster.py
+++ b/module/plugins/internal/MultiHoster.py
@@ -80,6 +80,6 @@ class MultiHoster(Hook):
hoster[self.__name__] = new
- def unload(self):
+ def deactivate(self):
for hoster in self.supported:
self.core.pluginManager.restoreState("hoster", hoster) \ No newline at end of file
diff --git a/module/threads/DecrypterThread.py b/module/threads/DecrypterThread.py
index a1b7e4f38..8edb97c34 100644
--- a/module/threads/DecrypterThread.py
+++ b/module/threads/DecrypterThread.py
@@ -4,6 +4,7 @@
from time import sleep
from traceback import print_exc
+from module.utils import uniqify
from module.plugins.Base import Retry
from module.plugins.Crypter import Package
@@ -54,6 +55,7 @@ class DecrypterThread(BaseThread):
plugin.logDebug("Decrypted", plugin_result)
result.extend(plugin_result)
+ result = uniqify(result)
pack_names = {}
urls = []
diff --git a/module/threads/HookThread.py b/module/threads/HookThread.py
index fe4a2a651..bffa72ca0 100644
--- a/module/threads/HookThread.py
+++ b/module/threads/HookThread.py
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
from copy import copy
+from traceback import print_exc
from BaseThread import BaseThread
@@ -48,6 +49,14 @@ class HookThread(BaseThread):
del self.kwargs["thread"]
self.f(*self.args, **self.kwargs)
+ except Exception, e:
+ if hasattr(self.f, "im_self"):
+ hook = self.f.im_self
+ hook.logError(_("An Error occured"), e)
+ if self.m.core.debug:
+ print_exc()
+ self.writeDebugReport(hook.__name__, plugin=hook)
+
finally:
local = copy(self.active)
for x in local:
diff --git a/module/threads/InfoThread.py b/module/threads/InfoThread.py
index 596153c4b..c1e4458ef 100644
--- a/module/threads/InfoThread.py
+++ b/module/threads/InfoThread.py
@@ -30,7 +30,7 @@ class InfoThread(BaseThread):
"""run method"""
plugins = {}
- container = []
+ crypter = {}
for url, plugin in self.data:
if plugin in plugins:
@@ -42,8 +42,7 @@ class InfoThread(BaseThread):
# filter out crypter plugins
for name in self.m.core.pluginManager.getPlugins("crypter"):
if name in plugins:
- container.extend([(name, url) for url in plugins[name]])
-
+ crypter[name] = plugins[name]
del plugins[name]
#directly write to database
@@ -60,11 +59,10 @@ class InfoThread(BaseThread):
self.m.core.files.save()
else: #post the results
- #TODO: finer crypter control
- for name, url in container:
+ for name, urls in crypter:
#attach container content
try:
- data = self.decryptContainer(name, url)
+ data = self.decrypt(name, urls)
except:
print_exc()
self.m.log.error("Could not decrypt container.")
@@ -169,34 +167,14 @@ class InfoThread(BaseThread):
cb(pluginname, result)
- def decryptContainer(self, plugin, url):
- data = []
- # only works on container plugins
-
- self.m.log.debug("Pre decrypting %s with %s" % (url, plugin))
-
- # dummy pyfile
- pyfile = PyFile(self.m.core.files, -1, url, url, 0, 0, "", plugin, -1, -1)
-
- pyfile.initPlugin()
-
- # little plugin lifecycle
- try:
- pyfile.plugin.setup()
- pyfile.plugin.loadToDisk()
- pyfile.plugin.decrypt(pyfile)
- pyfile.plugin.deleteTmp()
-
- for pack in pyfile.plugin.packages:
- pyfile.plugin.urls.extend(pack[1])
-
- data, crypter = self.m.core.pluginManager.parseUrls(pyfile.plugin.urls)
+ def decrypt(self, plugin, urls):
+ self.m.log.debug("Pre decrypting %s" % plugin)
+ klass = self.m.core.pluginManager.loadClass("crypter", plugin)
- self.m.log.debug("Got %d links." % len(data))
-
- except Exception, e:
- self.m.log.debug("Pre decrypting error: %s" % str(e))
- finally:
- pyfile.release()
+ # only decrypt files
+ if has_method(klass, "decryptFile"):
+ urls = p.decrypt(urls)
+ data, crypter = self.m.core.pluginManager.parseUrls(urls)
+ return data
- return data
+ return []
diff --git a/module/utils/__init__.py b/module/utils/__init__.py
index a237fde9b..46621c685 100644
--- a/module/utils/__init__.py
+++ b/module/utils/__init__.py
@@ -72,21 +72,10 @@ def freeSpace(folder):
return free_space(folder)
-def uniqify(seq, idfun=None):
-# order preserving
- if idfun is None:
- def idfun(x): return x
- seen = {}
- result = []
- for item in seq:
- marker = idfun(item)
- # in old Python versions:
- # if seen.has_key(marker)
- # but in new ones:
- if marker in seen: continue
- seen[marker] = 1
- result.append(item)
- return result
+def uniqify(seq): #by Dave Kirby
+ """ removes duplicates from list, preserve order """
+ seen = set()
+ return [x for x in seq if x not in seen and not seen.add(x)]
def parseFileSize(string, unit=None): #returns bytes
diff --git a/module/web/pyload_app.py b/module/web/pyload_app.py
index a025f6bcb..f73defb45 100644
--- a/module/web/pyload_app.py
+++ b/module/web/pyload_app.py
@@ -506,6 +506,7 @@ def setup():
return render_to_response('setup.html', {"user": False, "perms": False})
+@login_required("STATUS")
@route("/info")
def info():
conf = PYLOAD.getConfigDict()
diff --git a/pyLoadCore.py b/pyLoadCore.py
index f8b1ad6e8..54dc9ca39 100755
--- a/pyLoadCore.py
+++ b/pyLoadCore.py
@@ -439,9 +439,10 @@ class Core(object):
self.running = True
self.log.info(_("Activating Plugins..."))
- self.hookManager.coreReady()
+ self.hookManager.activateHooks()
self.log.info(_("pyLoad is up and running"))
+ self.eventManager.dispatchEvent("coreReady")
#test api
# from module.common.APIExerciser import startApiExerciser
@@ -550,10 +551,13 @@ class Core(object):
def shutdown(self):
self.log.info(_("shutting down..."))
+ self.eventManager.dispatchEvent("coreShutdown")
try:
if self.config['webinterface']['activated'] and hasattr(self, "webserver"):
self.webserver.quit()
+
+
for thread in self.threadManager.threads:
thread.put("quit")
pyfiles = self.files.cache.values()
@@ -561,7 +565,7 @@ class Core(object):
for pyfile in pyfiles:
pyfile.abortDownload()
- self.hookManager.coreExiting()
+ self.hookManager.deactivateHooks()
except:
if self.debug: