diff options
| author | 2012-03-20 14:57:45 +0100 | |
|---|---|---|
| committer | 2012-03-20 14:57:45 +0100 | |
| commit | 50d4df8b4d48b855bd18e9922355b7f3f2b4da4e (patch) | |
| tree | 6301b05677a90cf86f131d5a7ae3f879b38e84d2 /module/interaction | |
| parent | renamed hooks to addons, new filemanager and database, many new api methods (diff) | |
| download | pyload-50d4df8b4d48b855bd18e9922355b7f3f2b4da4e.tar.xz | |
captcha decrypting for all plugin types, new interaction manager
Diffstat (limited to 'module/interaction')
| -rw-r--r-- | module/interaction/InteractionManager.py | 127 | ||||
| -rw-r--r-- | module/interaction/InteractionTask.py | 17 | 
2 files changed, 105 insertions, 39 deletions
diff --git a/module/interaction/InteractionManager.py b/module/interaction/InteractionManager.py index c547e1c97..0c125bdd4 100644 --- a/module/interaction/InteractionManager.py +++ b/module/interaction/InteractionManager.py @@ -15,10 +15,13 @@      @author: RaNaN  """ -from traceback import print_exc  from threading import Lock +from time import time -from module.utils import lock, bits_set +from new_collections import OrderedDict + +from module.utils import lock, bits_set, to_list +from module.Api import Input, Output  from InteractionTask import InteractionTask @@ -28,69 +31,127 @@ class InteractionManager:      Arbitary task with predefined output and input type can be set off.      Asyncronous callbacks and default values keeps the ability to fallback if no user is present.      """ + +    # number of seconds a client is classified as active +    CLIENT_THRESHOLD = 60 +      def __init__(self, core):          self.lock = Lock()          self.core = core -        self.tasks = [] #task store, for outgoing tasks only +        self.tasks = OrderedDict() #task store, for outgoing tasks only +        self.notifications = [] #list of notifications -        self.last_clients = {} +        self.last_clients = { +            Output.Notification : 0, +            Output.Captcha : 0, +            Output.Query : 0, +        }          self.ids = 0 #only for internal purpose +    def isClientConnected(self, mode=Output.All): +        if mode == Output.All: +            return max(self.last_clients.values()) + self.CLIENT_THRESHOLD <= time() +        else: +            self.last_clients.get(mode, 0) + self.CLIENT_THRESHOLD <= time() + +    def updateClient(self, mode): +        t = time() +        for output in self.last_clients: +            if bits_set(output, mode): +                self.last_clients[output] = t + +    @lock      def work(self): -        pass +        # old notifications will be removed +        for n in [x for x in self.notifications if x.timedOut()]: +            self.notifications.remove(n) + +        # store at most 100 notifications +        del self.notifications[50:] +      @lock -    def newNotification(self): -        pass +    def createNotification(self, title, content, desc="", plugin=""): +        """ Creates and queues a new Notification + +        :param title: short title +        :param content: text content +        :param desc: short form of the notification +        :param plugin: plugin name +        :return: :class:`InteractionTask` +        """ +        task = InteractionTask(self.ids, Input.Text, [content], Output.Notification, "", title, desc, plugin) +        self.ids += 1 +        self.notifications.insert(0, task) +        self.handleTask(task) +        return task      @lock -    def newQueryTask(self): -        pass +    def newQueryTask(self, input, data, desc, default="", plugin=""): +        task = InteractionTask(self.ids, input, to_list(data), Output.Query, default, _("Query"), desc, plugin) +        self.ids += 1 +        return task      @lock -    def newCaptchaTask(self, img, format, file, result_type): -        task = InteractionTask(self.ids, img, format, file, result_type) +    def newCaptchaTask(self, img, format, filename, plugin="", input=Input.Text): +        #todo: title desc plugin +        task = InteractionTask(self.ids, input, [img, format, filename],Output.Captcha, +            "", _("Captcha request"), _("Please solve the captcha."), plugin)          self.ids += 1          return task      @lock      def removeTask(self, task): -        if task in self.tasks: -            self.tasks.remove(task) +        if task.iid in self.tasks: +            del self.tasks[task.iid]      @lock -    def getTask(self): -        for task in self.tasks: -            return task +    def getTask(self, mode=Output.All): +        self.updateClient(mode) + +        for task in self.tasks.itervalues(): +            if mode == Output.All or bits_set(task.output, mode): +                return task + +    @lock +    def getNotifications(self): +        """retrieves notifications, old ones are only deleted after a while\ +             client has to make sure itself to dont display it twice""" +        for n in self.notifications: +            n.setWaiting(self.CLIENT_THRESHOLD * 5, True) +            #store notification for shorter period, lock the timeout + +        return self.notifications + +    def isTaskWaiting(self, mode=Output.All): +        return self.getTask(mode) is not None      @lock      def getTaskByID(self, iid): -        for task in self.tasks: -            if task.id == iid: -                return task +        if iid in self.tasks: +            task = self.tasks[iid] +            del self.tasks[iid] +            return task -    def handleCaptcha(self, task): -        cli = self.core.isClientConnected() +    def handleTask(self, task): +        cli = self.isClientConnected(task.output) -        if cli: #client connected -> should solve the captcha -            task.setWaiting(50) #wait 50 sec for response +        if cli: #client connected -> should handle the task +            task.setWaiting(self.CLIENT_THRESHOLD) # wait for response + +        if task.output == Output.Notification: +            task.setWaiting(60 * 60 * 30) # notifications are valid for 30h          for plugin in self.core.addonManager.activePlugins():              try: -                plugin.newCaptchaTask(task) +                plugin.newInteractionTask(task)              except: -                if self.core.debug: -                    print_exc() - -        if task.handler or cli: #the captcha was handled -            self.tasks.append(task) -            return True - -        task.error = _("No Client connected for captcha decrypting") +                self.core.print_exc() -        return False +        if task.output != Output.Notification: +            self.tasks[task.iid] = task  if __name__ == "__main__": diff --git a/module/interaction/InteractionTask.py b/module/interaction/InteractionTask.py index 7963a5c72..b372321b0 100644 --- a/module/interaction/InteractionTask.py +++ b/module/interaction/InteractionTask.py @@ -30,12 +30,14 @@ class InteractionTask(BaseInteractionTask):      storage = None      #: Timestamp when task expires      wait_until = 0 -    #: The received result as string representation +    #: The received result      result = None      #: List of registered handles      handler = None      #: Error Message      error = None +    #: Timeout locked +    locked = False      def __init__(self, *args, **kwargs):          BaseInteractionTask.__init__(self, *args, **kwargs) @@ -46,25 +48,28 @@ class InteractionTask(BaseInteractionTask):          self.wait_until = 0      def convertResult(self, value): +        #TODO: convert based on input/output          return value      def getResult(self):          return self.result      def setResult(self, value): -        pass +        self.result = self.convertResult(value) -    def setWaiting(self, sec): -        self.wait_until = max(time() + sec, self.wait_until) +    def setWaiting(self, sec, lock=False): +        if not self.locked: +            self.wait_until = max(time() + sec, self.wait_until) +            if lock: self.locked = True -    def isWaiting(self, sec): +    def isWaiting(self):          if self.result or self.error or time() > self.waitUntil:              return False          return True      def timedOut(self): -        return time() > self.waitUntil +        return time() > self.wait_until > 0      def correct(self):          [x.taskCorrect(self) for x in self.handler]  | 
