Files
admins 702d080a1e New Addon
Google BK
2023-04-23 18:17:03 +07:00

147 lines
6.5 KiB
Python

from backup.config import Config, Setting
from backup.file import JsonFileSaver
from backup.worker import Worker
from backup.exceptions import SupervisorFileSystemError
from .harequests import HaRequests
from injector import inject, singleton
from backup.time import Time
from backup.logger import getLogger
from datetime import timedelta
from asyncio import Lock
LOGGER = getLogger(__name__)
CHECK_DURATION = timedelta(seconds=60)
ATTR_STATE = "state"
ATTR_WATCHDOG = "watchdog"
ATTR_NAME = "name"
STATE_STOPPED = "stopped"
STATE_STARTED = "started"
STATES_STOPPED = ["stopped", "unknown", "error"]
@singleton
class AddonStopper(Worker):
@inject
def __init__(self, config: Config, requests: HaRequests, time: Time):
super().__init__("StartandStopTimer", self.check, time, 10)
self.requests = requests
self.config = config
self.time = time
self.must_start = set()
self.must_enable_watchdog = set()
self.stop_start_check_time = time.now()
self._backing_up = False
self.allow_run = False
self.lock = Lock()
async def start(self, schedule=True):
if schedule:
await super().start()
path = self.config.get(Setting.STOP_ADDON_STATE_PATH)
if JsonFileSaver.exists(path):
data = JsonFileSaver.read(path)
self.must_enable_watchdog = set(data.get("watchdog", []))
self.must_start = set(data.get("start", []))
def allowRun(self):
if not self.allow_run:
for slug in self.config.get(Setting.STOP_ADDONS).split(','):
if len(slug) == 0:
continue
self.must_start.add(slug)
self.allow_run = True
def isBackingUp(self, backingUp):
self._backing_up = backingUp
async def stopAddons(self, self_slug):
async with self.lock:
self._backing_up = True
for slug in self.config.get(Setting.STOP_ADDONS).split(','):
if slug == self_slug or len(slug) == 0:
# Don't ask the supervisor to stop yourself. That would be BAD.
continue
try:
info = await self.requests.getAddonInfo(slug)
if info.get(ATTR_STATE, None) == STATE_STARTED:
if info.get(ATTR_WATCHDOG, False):
try:
LOGGER.info("Temporarily disabling watchdog for addon '%s'", info.get(ATTR_NAME, slug))
await self.requests.updateAddonOptions(slug, {ATTR_WATCHDOG: False})
self.must_enable_watchdog.add(slug)
except Exception as e:
LOGGER.error("Unable to disable watchdog for addon {0}".format(info.get(ATTR_NAME, slug)))
LOGGER.printException(e)
try:
LOGGER.info("Stopping addon '%s'", info.get(ATTR_NAME, slug))
await self.requests.stopAddon(slug)
self.must_start.add(slug)
except Exception as e:
LOGGER.error("Unable to stop addon '{0}'".format(info.get(ATTR_NAME, slug)))
LOGGER.printException(e)
except Exception as e:
LOGGER.error("Unable to lookup info for addon '{0}', please check your configuration".format(slug))
LOGGER.printException(e)
self._save()
async def startAddons(self):
self._backing_up = False
self.stop_start_check_time = self.time.now() + CHECK_DURATION
await self.check()
async def check(self):
async with self.lock:
if self._backing_up:
return
if not self.allow_run:
return
changes = False
if len(self.must_start) > 0:
for slug in list(self.must_start):
try:
info = await self.requests.getAddonInfo(slug)
state = info.get(ATTR_STATE, None)
if info.get(ATTR_STATE, None) in STATES_STOPPED:
LOGGER.info("Starting addon '%s'", info.get(ATTR_NAME, slug))
await self.requests.startAddon(slug)
self.must_start.remove(slug)
changes = True
elif info.get(ATTR_STATE, None) == STATE_STARTED and self.time.now() > self.stop_start_check_time:
# Give up on restarting it, looks like it was never stopped
self.must_start.remove(slug)
changes = True
else:
LOGGER.error(f"Addon '{info.get(ATTR_NAME, slug)} had unrecognized state {state}'. The addon will most likely be unable to automatically restart this addon.", )
except Exception as e:
LOGGER.error("Unable to start addon '%s'", slug)
LOGGER.printException(e)
self.must_start.remove(slug)
changes = True
if len(self.must_enable_watchdog) > 0:
for slug in list(self.must_enable_watchdog):
if slug in self.must_start:
# Wait until we're done trying to start the addon before re-enabling the watchdog, otherwise the supervisor complains
continue
try:
info = await self.requests.getAddonInfo(slug)
if not info.get(ATTR_WATCHDOG, True):
LOGGER.info("Re-enabling watchdog for addon '%s'", info.get(ATTR_NAME, slug))
await self.requests.updateAddonOptions(slug, {ATTR_WATCHDOG: True})
except Exception as e:
LOGGER.error("Unable to re-enable watchdog for addon '%s'", slug)
LOGGER.printException(e)
self.must_enable_watchdog.remove(slug)
changes = True
if changes:
self._save()
def _save(self):
try:
path = self.config.get(Setting.STOP_ADDON_STATE_PATH)
data = {"start": list(self.must_start), "watchdog": list(self.must_enable_watchdog)}
JsonFileSaver.write(path, data)
except OSError:
raise SupervisorFileSystemError()