"""Backup platform for the kitchen_sink integration.""" from __future__ import annotations import asyncio from collections.abc import AsyncIterator, Callable, Coroutine import logging from typing import Any from homeassistant.components.backup import ( AddonInfo, AgentBackup, BackupAgent, BackupNotFound, Folder, ) from homeassistant.core import HomeAssistant, callback from . import DATA_BACKUP_AGENT_LISTENERS, DOMAIN LOGGER = logging.getLogger(__name__) async def async_get_backup_agents( hass: HomeAssistant, ) -> list[BackupAgent]: """Register the backup agents.""" if not hass.config_entries.async_loaded_entries(DOMAIN): LOGGER.info("No config entry found or entry is not loaded") return [] return [KitchenSinkBackupAgent("syncer")] @callback def async_register_backup_agents_listener( hass: HomeAssistant, *, listener: Callable[[], None], **kwargs: Any, ) -> Callable[[], None]: """Register a listener to be called when agents are added or removed.""" hass.data.setdefault(DATA_BACKUP_AGENT_LISTENERS, []).append(listener) @callback def remove_listener() -> None: """Remove the listener.""" hass.data[DATA_BACKUP_AGENT_LISTENERS].remove(listener) return remove_listener class KitchenSinkBackupAgent(BackupAgent): """Kitchen sink backup agent.""" domain = DOMAIN def __init__(self, name: str) -> None: """Initialize the kitchen sink backup sync agent.""" super().__init__() self.name = self.unique_id = name self._uploads = [ AgentBackup( addons=[AddonInfo(name="Test", slug="test", version="1.0.0")], backup_id="abc123", database_included=False, date="1970-01-01T00:00:00Z", extra_metadata={}, folders=[Folder.MEDIA, Folder.SHARE], homeassistant_included=True, homeassistant_version="2024.12.0", name="Kitchen sink syncer", protected=False, size=1234, ) ] async def async_download_backup( self, backup_id: str, **kwargs: Any, ) -> AsyncIterator[bytes]: """Download a backup file.""" LOGGER.info("Downloading backup %s", backup_id) reader = asyncio.StreamReader() reader.feed_data(b"backup data") reader.feed_eof() return reader async def async_upload_backup( self, *, open_stream: Callable[[], Coroutine[Any, Any, AsyncIterator[bytes]]], backup: AgentBackup, **kwargs: Any, ) -> None: """Upload a backup.""" LOGGER.info("Uploading backup %s %s", backup.backup_id, backup) self._uploads.append(backup) async def async_delete_backup( self, backup_id: str, **kwargs: Any, ) -> None: """Delete a backup file.""" self._uploads = [ upload for upload in self._uploads if upload.backup_id != backup_id ] LOGGER.info("Deleted backup %s", backup_id) async def async_list_backups(self, **kwargs: Any) -> list[AgentBackup]: """List synced backups.""" return self._uploads async def async_get_backup( self, backup_id: str, **kwargs: Any, ) -> AgentBackup: """Return a backup.""" for backup in self._uploads: if backup.backup_id == backup_id: return backup raise BackupNotFound(f"Backup {backup_id} not found")