convert example & homeassistant specific configs to a generic with all optional fields

This commit is contained in:
Mikhail Epifanov
2024-01-17 22:25:02 +01:00
parent 245787b89e
commit 409c0295ec
20 changed files with 159 additions and 316 deletions

View File

@@ -1,9 +1,13 @@
from abc import ABC, abstractmethod
from cookbook.models import ShoppingListEntry, Space
from cookbook.models import ShoppingListEntry, Space, ConnectorConfig
class Connector(ABC):
@abstractmethod
def __init__(self, config: ConnectorConfig):
pass
@abstractmethod
async def on_shopping_list_entry_created(self, space: Space, instance: ShoppingListEntry) -> None:
pass
@@ -20,5 +24,4 @@ class Connector(ABC):
async def close(self) -> None:
pass
# TODO: Maybe add an 'IsEnabled(self) -> Bool' to here
# TODO: Add Recipes & possibly Meal Place listeners/hooks (And maybe more?)

View File

@@ -12,15 +12,13 @@ from typing import List, Any, Dict, Optional
from django_scopes import scope
from cookbook.connectors.connector import Connector
from cookbook.connectors.example import Example
from cookbook.connectors.homeassistant import HomeAssistant
from cookbook.models import ShoppingListEntry, Recipe, MealPlan, Space, HomeAssistantConfig, ExampleConfig
from cookbook.models import ShoppingListEntry, Recipe, MealPlan, Space, ConnectorConfig
multiprocessing.set_start_method('fork') # https://code.djangoproject.com/ticket/31169
QUEUE_MAX_SIZE = 25
REGISTERED_CLASSES: UnionType = ShoppingListEntry | Recipe | MealPlan
CONNECTOR_UPDATE_CLASSES: UnionType = HomeAssistantConfig | ExampleConfig
class ActionType(Enum):
@@ -37,7 +35,7 @@ class Work:
class ConnectorManager:
_queue: JoinableQueue
_listening_to_classes = REGISTERED_CLASSES | CONNECTOR_UPDATE_CLASSES
_listening_to_classes = REGISTERED_CLASSES | ConnectorConfig
def __init__(self):
self._queue = multiprocessing.JoinableQueue(maxsize=QUEUE_MAX_SIZE)
@@ -88,7 +86,7 @@ class ConnectorManager:
break
# If a Connector was changed/updated, refresh connector from the database for said space
refresh_connector_cache = isinstance(item.instance, CONNECTOR_UPDATE_CLASSES)
refresh_connector_cache = isinstance(item.instance, ConnectorConfig)
space: Space = item.instance.space
connectors: Optional[List[Connector]] = _connectors.get(space.name)
@@ -98,10 +96,11 @@ class ConnectorManager:
loop.run_until_complete(close_connectors(connectors))
with scope(space=space):
connectors: List[Connector] = [
*(HomeAssistant(config) for config in space.homeassistantconfig_set.all() if config.enabled),
*(Example(config) for config in space.exampleconfig_set.all() if config.enabled)
]
connectors: List[Connector] = list(
filter(
lambda x: x is not None,
[ConnectorManager.get_connected_for_config(config) for config in space.connectorconfig_set.all() if config.enabled],
))
_connectors[space.name] = connectors
if len(connectors) == 0 or refresh_connector_cache:
@@ -113,6 +112,14 @@ class ConnectorManager:
loop.close()
@staticmethod
def get_connected_for_config(config: ConnectorConfig) -> Optional[Connector]:
match config.type:
case ConnectorConfig.HOMEASSISTANT:
return HomeAssistant(config)
case _:
return None
async def close_connectors(connectors: List[Connector]):
tasks: List[Task] = [asyncio.create_task(connector.close()) for connector in connectors]

View File

@@ -1,27 +0,0 @@
from cookbook.connectors.connector import Connector
from cookbook.models import ExampleConfig, Space, ShoppingListEntry
class Example(Connector):
_config: ExampleConfig
def __init__(self, config: ExampleConfig):
self._config = config
async def on_shopping_list_entry_created(self, space: Space, shopping_list_entry: ShoppingListEntry) -> None:
if not self._config.on_shopping_list_entry_created_enabled:
return
pass
async def on_shopping_list_entry_updated(self, space: Space, shopping_list_entry: ShoppingListEntry) -> None:
if not self._config.on_shopping_list_entry_updated_enabled:
return
pass
async def on_shopping_list_entry_deleted(self, space: Space, shopping_list_entry: ShoppingListEntry) -> None:
if not self._config.on_shopping_list_entry_deleted_enabled:
return
pass
async def close(self) -> None:
pass

View File

@@ -4,16 +4,19 @@ from logging import Logger
from homeassistant_api import Client, HomeassistantAPIError, Domain
from cookbook.connectors.connector import Connector
from cookbook.models import ShoppingListEntry, HomeAssistantConfig, Space
from cookbook.models import ShoppingListEntry, ConnectorConfig, Space
class HomeAssistant(Connector):
_domains_cache: dict[str, Domain]
_config: HomeAssistantConfig
_config: ConnectorConfig
_logger: Logger
_client: Client
def __init__(self, config: HomeAssistantConfig):
def __init__(self, config: ConnectorConfig):
if not config.token or not config.url or not config.todo_entity:
raise ValueError("config for HomeAssistantConnector in incomplete")
self._domains_cache = dict()
self._config = config
self._logger = logging.getLogger("connector.HomeAssistant")