match_condition should return immediately (no score-based fuzzy search) if an event condition is an exact match

This commit is contained in:
Fabio Manganiello 2022-08-04 01:04:00 +02:00
parent cbf8ba7fdd
commit 7c87238fec
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774

View file

@ -2,6 +2,7 @@ import copy
import hashlib import hashlib
import json import json
import re import re
import sys
import time import time
import uuid import uuid
@ -20,8 +21,16 @@ class Event(Message):
# high frequency that would otherwise pollute the logs e.g. camera capture # high frequency that would otherwise pollute the logs e.g. camera capture
# events # events
# pylint: disable=redefined-builtin # pylint: disable=redefined-builtin
def __init__(self, target=None, origin=None, id=None, timestamp=None, def __init__(
disable_logging=False, disable_web_clients_notification=False, **kwargs): self,
target=None,
origin=None,
id=None,
timestamp=None,
disable_logging=False,
disable_web_clients_notification=False,
**kwargs
):
""" """
Params: Params:
target -- Target node [String] target -- Target node [String]
@ -34,15 +43,20 @@ class Event(Message):
self.id = id if id else self._generate_id() self.id = id if id else self._generate_id()
self.target = target if target else Config.get('device_id') self.target = target if target else Config.get('device_id')
self.origin = origin if origin else Config.get('device_id') self.origin = origin if origin else Config.get('device_id')
self.type = '{}.{}'.format(self.__class__.__module__, self.type = '{}.{}'.format(self.__class__.__module__, self.__class__.__name__)
self.__class__.__name__)
self.args = kwargs self.args = kwargs
self.disable_logging = disable_logging self.disable_logging = disable_logging
self.disable_web_clients_notification = disable_web_clients_notification self.disable_web_clients_notification = disable_web_clients_notification
for arg, value in self.args.items(): for arg, value in self.args.items():
if arg not in [ if arg not in [
'id', 'args', 'origin', 'target', 'type', 'timestamp', 'disable_logging' 'id',
'args',
'origin',
'target',
'type',
'timestamp',
'disable_logging',
] and not arg.startswith('_'): ] and not arg.startswith('_'):
self.__setattr__(arg, value) self.__setattr__(arg, value)
@ -65,7 +79,9 @@ class Event(Message):
@staticmethod @staticmethod
def _generate_id(): def _generate_id():
"""Generate a unique event ID""" """Generate a unique event ID"""
return hashlib.md5(str(uuid.uuid1()).encode()).hexdigest() # lgtm [py/weak-sensitive-data-hashing] return hashlib.md5(
str(uuid.uuid1()).encode()
).hexdigest() # lgtm [py/weak-sensitive-data-hashing]
def matches_condition(self, condition): def matches_condition(self, condition):
""" """
@ -120,7 +136,13 @@ class Event(Message):
""" """
result = EventMatchResult(is_match=False) result = EventMatchResult(is_match=False)
event_tokens = re.split(r'\s+', self.args[argname].strip().lower()) if self.args.get(argname) == condition_value:
# In case of an exact match, return immediately
result.is_match = True
result.score = sys.maxsize
return result
event_tokens = re.split(r'\s+', self.args.get(argname, '').strip().lower())
condition_tokens = re.split(r'\s+', condition_value.strip().lower()) condition_tokens = re.split(r'\s+', condition_value.strip().lower())
while event_tokens and condition_tokens: while event_tokens and condition_tokens:
@ -148,9 +170,11 @@ class Event(Message):
else: else:
result.parsed_args[argname] += ' ' + event_token result.parsed_args[argname] += ' ' + event_token
if (len(condition_tokens) == 1 and len(event_tokens) == 1) \ if (len(condition_tokens) == 1 and len(event_tokens) == 1) or (
or (len(event_tokens) > 1 and len(condition_tokens) > 1 len(event_tokens) > 1
and event_tokens[1] == condition_tokens[1]): and len(condition_tokens) > 1
and event_tokens[1] == condition_tokens[1]
):
# Stop appending tokens to this argument, as the next # Stop appending tokens to this argument, as the next
# condition will be satisfied as well # condition will be satisfied as well
condition_tokens.pop(0) condition_tokens.pop(0)
@ -173,20 +197,20 @@ class Event(Message):
args = copy.deepcopy(self.args) args = copy.deepcopy(self.args)
flatten(args) flatten(args)
return json.dumps({ return json.dumps(
{
'type': 'event', 'type': 'event',
'target': self.target, 'target': self.target,
'origin': self.origin if hasattr(self, 'origin') else None, 'origin': self.origin if hasattr(self, 'origin') else None,
'id': self.id if hasattr(self, 'id') else None, 'id': self.id if hasattr(self, 'id') else None,
'_timestamp': self.timestamp, '_timestamp': self.timestamp,
'args': { 'args': {'type': self.type, **args},
'type': self.type,
**args
}, },
}, cls=self.Encoder) cls=self.Encoder,
)
class EventMatchResult(object): class EventMatchResult:
"""When comparing an event against an event condition, you want to """When comparing an event against an event condition, you want to
return this object. It contains the match status (True or False), return this object. It contains the match status (True or False),
any parsed arguments, and a match_score that identifies how "strong" any parsed arguments, and a match_score that identifies how "strong"
@ -196,7 +220,7 @@ class EventMatchResult(object):
def __init__(self, is_match, score=0, parsed_args=None): def __init__(self, is_match, score=0, parsed_args=None):
self.is_match = is_match self.is_match = is_match
self.score = score self.score = score
self.parsed_args = {} if not parsed_args else parsed_args self.parsed_args = parsed_args or {}
def flatten(args): def flatten(args):
@ -213,4 +237,5 @@ def flatten(args):
elif isinstance(arg, (dict, list)): elif isinstance(arg, (dict, list)):
flatten(args[i]) flatten(args[i])
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et: