From 86d5f198071b0478b480804d055ed80c88341ee1 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 10 Jun 2024 18:37:52 -0500 Subject: [PATCH] feat: avoid linear searches to process websocket packets (#21) --- src/uiprotect/api.py | 7 +++++-- src/uiprotect/data/bootstrap.py | 4 ++-- src/uiprotect/data/types.py | 20 ++++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/uiprotect/api.py b/src/uiprotect/api.py index 81d29706..9a9b5e45 100644 --- a/src/uiprotect/api.py +++ b/src/uiprotect/api.py @@ -1075,7 +1075,10 @@ async def get_events( for event_dict in response: # ignore unknown events - if "type" not in event_dict or event_dict["type"] not in EventType.values(): + if ( + "type" not in event_dict + or event_dict["type"] not in EventType.values_set() + ): _LOGGER.debug("Unknown event type: %s", event_dict) continue @@ -1086,7 +1089,7 @@ async def get_events( continue if ( - event.type.value in EventType.device_events() + event.type.value in EventType.device_events_set() and event.score >= self._minimum_score ): events.append(event) diff --git a/src/uiprotect/data/bootstrap.py b/src/uiprotect/data/bootstrap.py index 72840148..6fba0fe3 100644 --- a/src/uiprotect/data/bootstrap.py +++ b/src/uiprotect/data/bootstrap.py @@ -553,7 +553,7 @@ def process_ws_packet( if action["newUpdateId"] is not None: self.last_update_id = action["newUpdateId"] - if action["modelKey"] not in ModelType.values(): + if action["modelKey"] not in ModelType.values_set(): _LOGGER.debug("Unknown model type: %s", action["modelKey"]) self._create_stat(packet, [], True) return None @@ -577,7 +577,7 @@ def process_ws_packet( if action["modelKey"] == ModelType.NVR.value: return self._process_nvr_update(packet, data, ignore_stats) if ( - action["modelKey"] in ModelType.bootstrap_models() + action["modelKey"] in ModelType.bootstrap_models_set() or action["modelKey"] == ModelType.EVENT.value ): return self._process_device_update( diff --git a/src/uiprotect/data/types.py b/src/uiprotect/data/types.py index 2025a58a..2f490192 100644 --- a/src/uiprotect/data/types.py +++ b/src/uiprotect/data/types.py @@ -2,6 +2,7 @@ import enum from collections.abc import Callable, Coroutine +from functools import cache from typing import Any, Literal, Optional, TypeVar, Union from packaging.version import Version as BaseVersion @@ -58,11 +59,17 @@ class ValuesEnumMixin: _values_normalized: dict[str, str] | None = None @classmethod + @cache def values(cls) -> list[str]: if cls._values is None: cls._values = [e.value for e in cls] # type: ignore[attr-defined] return cls._values + @classmethod + @cache + def values_set(cls) -> set[str]: + return set(cls.values()) + @classmethod def _missing_(cls, value: Any) -> Any | None: if cls._values_normalized is None: @@ -103,6 +110,7 @@ class ModelType(str, UnknownValuesEnumMixin, enum.Enum): UNKNOWN = "unknown" @staticmethod + @cache def bootstrap_models() -> tuple[str, ...]: # TODO: # legacyUFV @@ -121,6 +129,11 @@ def bootstrap_models() -> tuple[str, ...]: ModelType.CHIME.value, ) + @staticmethod + @cache + def bootstrap_models_set() -> set[str]: + return set(ModelType.bootstrap_models()) + @enum.unique class EventType(str, ValuesEnumMixin, enum.Enum): @@ -204,6 +217,7 @@ class EventType(str, ValuesEnumMixin, enum.Enum): RECORDING_OFF = "recordingOff" @staticmethod + @cache def device_events() -> list[str]: return [ EventType.MOTION.value, @@ -212,6 +226,12 @@ def device_events() -> list[str]: ] @staticmethod + @cache + def device_events_set() -> set[str]: + return set(EventType.device_events()) + + @staticmethod + @cache def motion_events() -> list[str]: return [EventType.MOTION.value, EventType.SMART_DETECT.value]