Avoid enumerating the whole state machine on api service calls (#103147)
parent
daee5baef6
commit
78e546b35a
|
@ -1,9 +1,11 @@
|
||||||
"""Rest API for Home Assistant."""
|
"""Rest API for Home Assistant."""
|
||||||
import asyncio
|
import asyncio
|
||||||
from asyncio import timeout
|
from asyncio import timeout
|
||||||
|
from collections.abc import Collection
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp.web_exceptions import HTTPBadRequest
|
from aiohttp.web_exceptions import HTTPBadRequest
|
||||||
|
@ -16,6 +18,7 @@ from homeassistant.components.http import HomeAssistantView, require_admin
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONTENT_TYPE_JSON,
|
CONTENT_TYPE_JSON,
|
||||||
EVENT_HOMEASSISTANT_STOP,
|
EVENT_HOMEASSISTANT_STOP,
|
||||||
|
EVENT_STATE_CHANGED,
|
||||||
MATCH_ALL,
|
MATCH_ALL,
|
||||||
URL_API,
|
URL_API,
|
||||||
URL_API_COMPONENTS,
|
URL_API_COMPONENTS,
|
||||||
|
@ -38,10 +41,12 @@ from homeassistant.exceptions import (
|
||||||
Unauthorized,
|
Unauthorized,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers import config_validation as cv, template
|
from homeassistant.helpers import config_validation as cv, template
|
||||||
|
from homeassistant.helpers.event import EventStateChangedData
|
||||||
from homeassistant.helpers.json import json_dumps
|
from homeassistant.helpers.json import json_dumps
|
||||||
from homeassistant.helpers.service import async_get_all_descriptions
|
from homeassistant.helpers.service import async_get_all_descriptions
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType, EventType
|
||||||
from homeassistant.util.json import json_loads
|
from homeassistant.util.json import json_loads
|
||||||
|
from homeassistant.util.read_only_dict import ReadOnlyDict
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -369,6 +374,18 @@ class APIDomainServicesView(HomeAssistantView):
|
||||||
)
|
)
|
||||||
|
|
||||||
context = self.context(request)
|
context = self.context(request)
|
||||||
|
changed_states: list[ReadOnlyDict[str, Collection[Any]]] = []
|
||||||
|
|
||||||
|
@ha.callback
|
||||||
|
def _async_save_changed_entities(
|
||||||
|
event: EventType[EventStateChangedData],
|
||||||
|
) -> None:
|
||||||
|
if event.context == context and (state := event.data["new_state"]):
|
||||||
|
changed_states.append(state.as_dict())
|
||||||
|
|
||||||
|
cancel_listen = hass.bus.async_listen(
|
||||||
|
EVENT_STATE_CHANGED, _async_save_changed_entities, run_immediately=True
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
|
@ -376,12 +393,8 @@ class APIDomainServicesView(HomeAssistantView):
|
||||||
)
|
)
|
||||||
except (vol.Invalid, ServiceNotFound) as ex:
|
except (vol.Invalid, ServiceNotFound) as ex:
|
||||||
raise HTTPBadRequest() from ex
|
raise HTTPBadRequest() from ex
|
||||||
|
finally:
|
||||||
changed_states = []
|
cancel_listen()
|
||||||
|
|
||||||
for state in hass.states.async_all():
|
|
||||||
if state.context is context:
|
|
||||||
changed_states.append(state)
|
|
||||||
|
|
||||||
return self.json(changed_states)
|
return self.json(changed_states)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue