From 2bed16a87d5cd11b01c0cb66eab3b37d110fc6ef Mon Sep 17 00:00:00 2001 From: maxim Date: Tue, 7 Feb 2023 19:20:36 +0300 Subject: [PATCH] Copy BackupManager getBackup methods to integration Debug backup path Change path to \backup (hardcode) add debug Change read.me Change path Change path change version --- README.md | 6 ++ custom_components/yabackup/__init__.py | 5 +- custom_components/yabackup/manifest.json | 4 +- custom_components/yabackup/yad.py | 76 +++++++++++++++++++++--- 4 files changed, 79 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index f98e2ea..e001f5d 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,12 @@ Для работы компонента необходимо создать приложение Яндекс в своём Яндекс аккаунте и дать ему права на доступ к ЯндексДиску. +> :warning: + **Внимание: Интеграция не работает без ручного вмешательства в конфигурацию контейнера с homeassistant** +> +> Необходимо вручную добавить маппирование каталога backup, вот такая особенность выяснилась в последний момент :( +> +> HACS интеграции работают внутри контейнера homeassistant, в который не смаппирован этот каталог. ## Установка diff --git a/custom_components/yabackup/__init__.py b/custom_components/yabackup/__init__.py index 5cb9421..536d4e0 100644 --- a/custom_components/yabackup/__init__.py +++ b/custom_components/yabackup/__init__.py @@ -6,7 +6,7 @@ from homeassistant.core import HomeAssistant from .constants import DOMAIN -from .yad import YaDsk +from .yad import YaDsk, BackupObserver # _LOGGER = logging.getLogger(__name__) @@ -35,7 +35,8 @@ async def update_yad_option(option: dict): # add options handler entry.add_update_listener(async_update_options) - ya_dsk = YaDsk(hass, entry.options, entry.entry_id) + backup_observer = BackupObserver(hass, "/backup") + ya_dsk = YaDsk(hass, backup_observer, entry.options, entry.entry_id) _LOGGER.info("Create YaDisk " + ya_dsk.get_info()) ya_dsk.add_update_listener(update_yad_option) diff --git a/custom_components/yabackup/manifest.json b/custom_components/yabackup/manifest.json index 3d6cafd..d25591c 100644 --- a/custom_components/yabackup/manifest.json +++ b/custom_components/yabackup/manifest.json @@ -6,8 +6,8 @@ "issue_tracker": "https://github.com/maxifly/YaBackup/issues", "codeowners": ["@maxi_fly"], "dependencies": [], - "after_dependencies": ["backup"], + "after_dependencies": [], "requirements": ["yadisk==1.2.17"], - "version": "1.0.0", + "version": "1.0.1", "iot_class": "local_polling" } diff --git a/custom_components/yabackup/yad.py b/custom_components/yabackup/yad.py index 6f731dc..05db212 100644 --- a/custom_components/yabackup/yad.py +++ b/custom_components/yabackup/yad.py @@ -1,13 +1,15 @@ """ Core integration objects""" import base64 import datetime +import json import logging +import tarfile +from dataclasses import dataclass +from pathlib import Path from typing import Generator import requests import yadisk as yadisk -from homeassistant.components.backup import BackupManager -from homeassistant.components.backup.const import DOMAIN as BACKUP_DOMAIN from homeassistant.core import HomeAssistant from yadisk.objects import ResourceObject from yadisk.objects import TokenObject @@ -78,10 +80,68 @@ def _get_auth_string(client_id, client_secret): return base64.b64encode(bytes(client_id + ':' + client_secret, 'utf-8')).decode('utf-8') +@dataclass +class Backup: + """Backup class.""" + + slug: str + name: str + date: str + path: Path + size: float + + +class BackupObserver: + """Backup observer. + Base on core BackupManager + """ + + def __init__(self, hass: HomeAssistant, backup_dir: str) -> None: + """ Initialize the backup observer.""" + self.hass = hass + self.backup_dir = Path(hass.config.path("backups")) if backup_dir is None else Path(backup_dir) + + async def get_backups(self) -> dict[str, Backup]: + """ Get data of stored backup files.""" + backups = await self.hass.async_add_executor_job(self._read_backups) + + _LOGGER.debug("Loaded %s backups", len(backups)) + + return backups + + def _read_backups(self) -> dict[str, Backup]: + """Read backups from disk.""" + _LOGGER.debug("Check %s path", self.backup_dir) + + _LOGGER.debug("Size %s", len(list(self.backup_dir.glob("*")))) + + for backup_path in self.backup_dir.glob("*"): + _LOGGER.debug("backup_path %s", backup_path) + + backups: dict[str, Backup] = {} + for backup_path in self.backup_dir.glob("*.tar"): + try: + with tarfile.open(backup_path, "r:") as backup_file: + if data_file := backup_file.extractfile("./backup.json"): + data = json.loads(data_file.read()) + backup = Backup( + slug=data["slug"], + name=data["name"], + date=data["date"], + path=backup_path, + size=round(backup_path.stat().st_size / 1_048_576, 2), + ) + backups[backup.slug] = backup + except (OSError, tarfile.TarError, json.JSONDecodeError, KeyError) as err: + _LOGGER.warning("Unable to read backup %s: %s", backup_path, err) + return backups + + class YaDsk: """ Core integration class. Contains all method for YandexDisk communication. """ + _backup_observer = None _token = None _path = None _upload_without_suffix = True @@ -98,10 +158,10 @@ def file_amount(self): @property def file_markdown_list(self): - """ File list in markdown format """ + """ File list in Markdown format """ return self._file_markdown_list - def __init__(self, hass: HomeAssistant, config: dict, unique_id=None): + def __init__(self, hass: HomeAssistant, backup_observer: BackupObserver, config: dict, unique_id=None): self._options = {} self._options.update(config) self._token = config[CONF_TOKEN] @@ -112,6 +172,7 @@ def __init__(self, hass: HomeAssistant, config: dict, unique_id=None): self._client_id = config[CONF_CLIENT_ID] self._client_s = config[CONF_CLIENT_SECRET] self._hass = hass + self._backup_observer = backup_observer def get_info(self): """ Get class info """ @@ -144,7 +205,7 @@ async def list_yandex_disk(self): def _list_yandex_disk(self): """ List yandex disk directory. - Fill file amount< file markdown list and file simple list. + Fill file amount< file Markdown list and file simple list. """ try: @@ -199,12 +260,11 @@ async def upload_files(self): async def get_local_files_list(self): """ Get list of home assistant backups """ - manager: BackupManager = self._hass.data[BACKUP_DOMAIN] - backups = await manager.get_backups() + backups = await self._backup_observer.get_backups() result = {} for backup in backups.values(): - key = backup.name + '_' + backup.slug + key = (backup.name + '_' + backup.slug).replace(" ","-").replace(":","_") if not self._upload_without_suffix: key += '.tar' result[key] = backup.path