From fa34b05c6c81063e7bb8fc6486a0c51e0969ae56 Mon Sep 17 00:00:00 2001
From: Fabio Manganiello <blacklight86@gmail.com>
Date: Thu, 4 Jan 2018 19:19:56 +0100
Subject: [PATCH] Priority-based algorithm for hooks, solves #41

---
 platypush/event/hook.py               | 12 +++++++++---
 platypush/event/processor/__init__.py | 14 ++++++++++----
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/platypush/event/hook.py b/platypush/event/hook.py
index fb81e785e..788acf617 100644
--- a/platypush/event/hook.py
+++ b/platypush/event/hook.py
@@ -114,13 +114,17 @@ class EventHook(object):
     """ Event hook class. It consists of one conditionss and
         one or multiple actions to be executed """
 
-    def __init__(self, name, condition=None, actions=[]):
+    def __init__(self, name, priority=None, condition=None, actions=[]):
         """ Construtor. Takes a name, a EventCondition object and a list of
-            EventAction objects as input """
+            EventAction objects as input. It may also have a priority attached
+            as a positive number. If multiple hooks match against an event,
+            only the ones that have either the maximum match score or the
+            maximum pre-configured priority will be run. """
 
         self.name = name
         self.condition = EventCondition.build(condition or {})
         self.actions = actions
+        self.priority = priority or 0
 
 
     @classmethod
@@ -134,13 +138,15 @@ class EventHook(object):
 
         condition = EventCondition.build(hook['if']) if 'if' in hook else None
         actions = []
+        priority = hook['priority'] if 'priority' in hook else None
+
         if 'then' in hook:
             if isinstance(hook['then'], list):
                 actions = [EventAction.build(action) for action in hook['then']]
             else:
                 actions = [EventAction.build(hook['then'])]
 
-        return cls(name=name, condition=condition, actions=actions)
+        return cls(name=name, condition=condition, actions=actions, priority=priority)
 
 
     def matches_event(self, event):
diff --git a/platypush/event/processor/__init__.py b/platypush/event/processor/__init__.py
index 06ce12e63..6753ab8a7 100644
--- a/platypush/event/processor/__init__.py
+++ b/platypush/event/processor/__init__.py
@@ -27,17 +27,23 @@ class EventProcessor(object):
     def process_event(self, event):
         """ Processes an event and runs the matched hooks with the highest score """
 
-        matched_hooks = []
-        max_score = -sys.maxsize
+        matched_hooks = set(); priority_hooks = set()
+        max_score = -sys.maxsize; max_prio = 0
 
         for hook in self.hooks:
             match = hook.matches_event(event)
             if match.is_match:
                 if match.score > max_score:
-                    matched_hooks = [hook]
+                    matched_hooks = set((hook,))
                 elif match.score == max_score:
-                    matched_hooks.append(hook)
+                    matched_hooks.add(hook)
 
+                if hook.priority > max_prio:
+                    priority_hooks = set((hook,))
+                elif hook.priority == max_prio:
+                    priority_hooks.add(hook)
+
+        matched_hooks.update(priority_hooks)
         for hook in matched_hooks:
             hook.run(event)