mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	dashboard: move storage json update to a background task in edit save (#6280)
* dashboard: move storage json update to a background task in edit save * dashboard: move storage json update to a background task in edit save * fix typing * docs
This commit is contained in:
		| @@ -8,3 +8,5 @@ MAX_EXECUTOR_WORKERS = 48 | |||||||
|  |  | ||||||
|  |  | ||||||
| SENTINEL = object() | SENTINEL = object() | ||||||
|  |  | ||||||
|  | DASHBOARD_COMMAND = ["esphome", "--dashboard"] | ||||||
|   | |||||||
| @@ -1,11 +1,13 @@ | |||||||
| from __future__ import annotations | from __future__ import annotations | ||||||
|  |  | ||||||
| import asyncio | import asyncio | ||||||
|  | import contextlib | ||||||
| import logging | import logging | ||||||
| import threading | import threading | ||||||
| from dataclasses import dataclass | from dataclasses import dataclass | ||||||
| from functools import partial | from functools import partial | ||||||
| from typing import TYPE_CHECKING, Any, Callable | from typing import TYPE_CHECKING, Any, Callable | ||||||
|  | from collections.abc import Coroutine | ||||||
|  |  | ||||||
| from ..zeroconf import DiscoveredImport | from ..zeroconf import DiscoveredImport | ||||||
| from .dns import DNSCache | from .dns import DNSCache | ||||||
| @@ -71,6 +73,7 @@ class ESPHomeDashboard: | |||||||
|         "mdns_status", |         "mdns_status", | ||||||
|         "settings", |         "settings", | ||||||
|         "dns_cache", |         "dns_cache", | ||||||
|  |         "_background_tasks", | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     def __init__(self) -> None: |     def __init__(self) -> None: | ||||||
| @@ -85,6 +88,7 @@ class ESPHomeDashboard: | |||||||
|         self.mdns_status: MDNSStatus | None = None |         self.mdns_status: MDNSStatus | None = None | ||||||
|         self.settings = DashboardSettings() |         self.settings = DashboardSettings() | ||||||
|         self.dns_cache = DNSCache() |         self.dns_cache = DNSCache() | ||||||
|  |         self._background_tasks: set[asyncio.Task] = set() | ||||||
|  |  | ||||||
|     async def async_setup(self) -> None: |     async def async_setup(self) -> None: | ||||||
|         """Setup the dashboard.""" |         """Setup the dashboard.""" | ||||||
| @@ -132,7 +136,19 @@ class ESPHomeDashboard: | |||||||
|             if settings.status_use_mqtt: |             if settings.status_use_mqtt: | ||||||
|                 status_thread_mqtt.join() |                 status_thread_mqtt.join() | ||||||
|                 self.mqtt_ping_request.set() |                 self.mqtt_ping_request.set() | ||||||
|  |             for task in self._background_tasks: | ||||||
|  |                 task.cancel() | ||||||
|  |                 with contextlib.suppress(asyncio.CancelledError): | ||||||
|  |                     await task | ||||||
|             await asyncio.sleep(0) |             await asyncio.sleep(0) | ||||||
|  |  | ||||||
|  |     def async_create_background_task( | ||||||
|  |         self, coro: Coroutine[Any, Any, Any] | ||||||
|  |     ) -> asyncio.Task: | ||||||
|  |         """Create a background task.""" | ||||||
|  |         task = self.loop.create_task(coro) | ||||||
|  |         task.add_done_callback(self._background_tasks.discard) | ||||||
|  |         return task | ||||||
|  |  | ||||||
|  |  | ||||||
| DASHBOARD = ESPHomeDashboard() | DASHBOARD = ESPHomeDashboard() | ||||||
|   | |||||||
| @@ -10,12 +10,14 @@ from esphome import const, util | |||||||
| from esphome.storage_json import StorageJSON, ext_storage_path | from esphome.storage_json import StorageJSON, ext_storage_path | ||||||
|  |  | ||||||
| from .const import ( | from .const import ( | ||||||
|  |     DASHBOARD_COMMAND, | ||||||
|     EVENT_ENTRY_ADDED, |     EVENT_ENTRY_ADDED, | ||||||
|     EVENT_ENTRY_REMOVED, |     EVENT_ENTRY_REMOVED, | ||||||
|     EVENT_ENTRY_STATE_CHANGED, |     EVENT_ENTRY_STATE_CHANGED, | ||||||
|     EVENT_ENTRY_UPDATED, |     EVENT_ENTRY_UPDATED, | ||||||
| ) | ) | ||||||
| from .enum import StrEnum | from .enum import StrEnum | ||||||
|  | from .util.subprocess import async_run_system_command | ||||||
|  |  | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|     from .core import ESPHomeDashboard |     from .core import ESPHomeDashboard | ||||||
| @@ -235,6 +237,14 @@ class DashboardEntries: | |||||||
|             ) |             ) | ||||||
|         return path_to_cache_key |         return path_to_cache_key | ||||||
|  |  | ||||||
|  |     def async_schedule_storage_json_update(self, filename: str) -> None: | ||||||
|  |         """Schedule a task to update the storage JSON file.""" | ||||||
|  |         self._dashboard.async_create_background_task( | ||||||
|  |             async_run_system_command( | ||||||
|  |                 [*DASHBOARD_COMMAND, "compile", "--only-generate", filename] | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class DashboardEntry: | class DashboardEntry: | ||||||
|     """Represents a single dashboard entry. |     """Represents a single dashboard entry. | ||||||
|   | |||||||
| @@ -9,11 +9,11 @@ import hashlib | |||||||
| import json | import json | ||||||
| import logging | import logging | ||||||
| import os | import os | ||||||
| import time |  | ||||||
| import secrets | import secrets | ||||||
| import shutil | import shutil | ||||||
| import subprocess | import subprocess | ||||||
| import threading | import threading | ||||||
|  | import time | ||||||
| from collections.abc import Iterable | from collections.abc import Iterable | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
| from typing import TYPE_CHECKING, Any, Callable, TypeVar | from typing import TYPE_CHECKING, Any, Callable, TypeVar | ||||||
| @@ -40,6 +40,7 @@ from esphome.storage_json import StorageJSON, ext_storage_path, trash_storage_pa | |||||||
| from esphome.util import get_serial_ports, shlex_quote | from esphome.util import get_serial_ports, shlex_quote | ||||||
| from esphome.yaml_util import FastestAvailableSafeLoader | from esphome.yaml_util import FastestAvailableSafeLoader | ||||||
|  |  | ||||||
|  | from .const import DASHBOARD_COMMAND | ||||||
| from .core import DASHBOARD | from .core import DASHBOARD | ||||||
| from .entries import EntryState, entry_state_to_bool | from .entries import EntryState, entry_state_to_bool | ||||||
| from .util.file import write_file | from .util.file import write_file | ||||||
| @@ -286,9 +287,6 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): | |||||||
|         raise NotImplementedError |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |  | ||||||
| DASHBOARD_COMMAND = ["esphome", "--dashboard"] |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class EsphomePortCommandWebSocket(EsphomeCommandWebSocket): | class EsphomePortCommandWebSocket(EsphomeCommandWebSocket): | ||||||
|     """Base class for commands that require a port.""" |     """Base class for commands that require a port.""" | ||||||
|  |  | ||||||
| @@ -855,9 +853,7 @@ class EditRequestHandler(BaseHandler): | |||||||
|         loop = asyncio.get_running_loop() |         loop = asyncio.get_running_loop() | ||||||
|         await loop.run_in_executor(None, self._write_file, filename, self.request.body) |         await loop.run_in_executor(None, self._write_file, filename, self.request.body) | ||||||
|         # Ensure the StorageJSON is updated as well |         # Ensure the StorageJSON is updated as well | ||||||
|         await async_run_system_command( |         DASHBOARD.entries.async_schedule_storage_json_update(filename) | ||||||
|             [*DASHBOARD_COMMAND, "compile", "--only-generate", filename] |  | ||||||
|         ) |  | ||||||
|         self.set_status(200) |         self.set_status(200) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user