Cache serialize of manifest for loaded integrations (#117965)
* Cache serialize of manifest for loaded integrations The manifest/list and manifest/get websocket apis are called frequently when moving around in the UI. Since the manifest does not change we can make the the serialized version a cached property * reduce * reduce
This commit is contained in:
parent
09e7156d2d
commit
c5cc9801a6
3 changed files with 26 additions and 12 deletions
|
@ -46,10 +46,10 @@ from homeassistant.helpers.json import (
|
||||||
ExtendedJSONEncoder,
|
ExtendedJSONEncoder,
|
||||||
find_paths_unserializable_data,
|
find_paths_unserializable_data,
|
||||||
json_bytes,
|
json_bytes,
|
||||||
|
json_fragment,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers.service import async_get_all_descriptions
|
from homeassistant.helpers.service import async_get_all_descriptions
|
||||||
from homeassistant.loader import (
|
from homeassistant.loader import (
|
||||||
Integration,
|
|
||||||
IntegrationNotFound,
|
IntegrationNotFound,
|
||||||
async_get_integration,
|
async_get_integration,
|
||||||
async_get_integration_descriptions,
|
async_get_integration_descriptions,
|
||||||
|
@ -505,19 +505,15 @@ async def handle_manifest_list(
|
||||||
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
|
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Handle integrations command."""
|
"""Handle integrations command."""
|
||||||
wanted_integrations = msg.get("integrations")
|
ints_or_excs = await async_get_integrations(
|
||||||
if wanted_integrations is None:
|
hass, msg.get("integrations") or async_get_loaded_integrations(hass)
|
||||||
wanted_integrations = async_get_loaded_integrations(hass)
|
)
|
||||||
|
manifest_json_fragments: list[json_fragment] = []
|
||||||
ints_or_excs = await async_get_integrations(hass, wanted_integrations)
|
|
||||||
integrations: list[Integration] = []
|
|
||||||
for int_or_exc in ints_or_excs.values():
|
for int_or_exc in ints_or_excs.values():
|
||||||
if isinstance(int_or_exc, Exception):
|
if isinstance(int_or_exc, Exception):
|
||||||
raise int_or_exc
|
raise int_or_exc
|
||||||
integrations.append(int_or_exc)
|
manifest_json_fragments.append(int_or_exc.manifest_json_fragment)
|
||||||
connection.send_result(
|
connection.send_result(msg["id"], manifest_json_fragments)
|
||||||
msg["id"], [integration.manifest for integration in integrations]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@decorators.websocket_command(
|
@decorators.websocket_command(
|
||||||
|
@ -530,9 +526,10 @@ async def handle_manifest_get(
|
||||||
"""Handle integrations command."""
|
"""Handle integrations command."""
|
||||||
try:
|
try:
|
||||||
integration = await async_get_integration(hass, msg["integration"])
|
integration = await async_get_integration(hass, msg["integration"])
|
||||||
connection.send_result(msg["id"], integration.manifest)
|
|
||||||
except IntegrationNotFound:
|
except IntegrationNotFound:
|
||||||
connection.send_error(msg["id"], const.ERR_NOT_FOUND, "Integration not found")
|
connection.send_error(msg["id"], const.ERR_NOT_FOUND, "Integration not found")
|
||||||
|
else:
|
||||||
|
connection.send_result(msg["id"], integration.manifest_json_fragment)
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
|
|
@ -39,6 +39,7 @@ from .generated.mqtt import MQTT
|
||||||
from .generated.ssdp import SSDP
|
from .generated.ssdp import SSDP
|
||||||
from .generated.usb import USB
|
from .generated.usb import USB
|
||||||
from .generated.zeroconf import HOMEKIT, ZEROCONF
|
from .generated.zeroconf import HOMEKIT, ZEROCONF
|
||||||
|
from .helpers.json import json_bytes, json_fragment
|
||||||
from .util.hass_dict import HassKey
|
from .util.hass_dict import HassKey
|
||||||
from .util.json import JSON_DECODE_EXCEPTIONS, json_loads
|
from .util.json import JSON_DECODE_EXCEPTIONS, json_loads
|
||||||
|
|
||||||
|
@ -762,6 +763,11 @@ class Integration:
|
||||||
self._top_level_files = top_level_files or set()
|
self._top_level_files = top_level_files or set()
|
||||||
_LOGGER.info("Loaded %s from %s", self.domain, pkg_path)
|
_LOGGER.info("Loaded %s from %s", self.domain, pkg_path)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def manifest_json_fragment(self) -> json_fragment:
|
||||||
|
"""Return manifest as a JSON fragment."""
|
||||||
|
return json_fragment(json_bytes(self.manifest))
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
"""Return name."""
|
"""Return name."""
|
||||||
|
|
|
@ -15,6 +15,8 @@ from homeassistant.components import http, hue
|
||||||
from homeassistant.components.hue import light as hue_light
|
from homeassistant.components.hue import light as hue_light
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers import frame
|
from homeassistant.helpers import frame
|
||||||
|
from homeassistant.helpers.json import json_dumps
|
||||||
|
from homeassistant.util.json import json_loads
|
||||||
|
|
||||||
from .common import MockModule, async_get_persistent_notifications, mock_integration
|
from .common import MockModule, async_get_persistent_notifications, mock_integration
|
||||||
|
|
||||||
|
@ -1959,3 +1961,12 @@ async def test_hass_helpers_use_reported(
|
||||||
"Detected that custom integration 'test_integration_frame' "
|
"Detected that custom integration 'test_integration_frame' "
|
||||||
"accesses hass.helpers.aiohttp_client. This is deprecated"
|
"accesses hass.helpers.aiohttp_client. This is deprecated"
|
||||||
) in caplog.text
|
) in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
async def test_manifest_json_fragment_round_trip(hass: HomeAssistant) -> None:
|
||||||
|
"""Test json_fragment roundtrip."""
|
||||||
|
integration = await loader.async_get_integration(hass, "hue")
|
||||||
|
assert (
|
||||||
|
json_loads(json_dumps(integration.manifest_json_fragment))
|
||||||
|
== integration.manifest
|
||||||
|
)
|
||||||
|
|
Loading…
Add table
Reference in a new issue