# -*- coding: utf-8 -*- from threading import Lock from traceback import print_exc from time import time from module.utils import lock class EventManager: """ Handles all event-related tasks, also stores an event queue for clients, so they can retrieve them later. **Known Events:** Most addon methods exist as events. These are some additional known events. ===================== ================ =========================================================== Name Arguments Description ===================== ================ =========================================================== metaEvent eventName, *args Called for every event, with eventName and original args downloadPreparing fid A download was just queued and will be prepared now. downloadStarts fid A plugin will immediately start the download afterwards. linksAdded links, pid Someone just added links, you are able to modify these links. allDownloadsProcessed All links were handled, pyLoad would idle afterwards. allDownloadsFinished All downloads in the queue are 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.log = core.log # uuid : list of events self.clients = {} self.events = {"metaEvent": []} self.lock = Lock() def getEvents(self, uuid): """ Get accumulated events for uuid since last call, this also registers a 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() self.updateClients(event, args) @lock def updateClients(self, event, args): # 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: # 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 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) del self.events[self.MAX:] def get(self): self.lastActive = time() events = self.events self.events = [] return [(ev, [str(x) for x in args]) for ev, args in events]