craftbeerpi4-pione/cbpi/controller/basic_controller.py
Manuel Fritsch b3af77fdb8 actor added
2021-02-02 00:07:58 +01:00

147 lines
5.4 KiB
Python

import logging
import os.path
import json
import sys, os
import shortuuid
import asyncio
from tabulate import tabulate
class BasicController:
def __init__(self, cbpi, file):
self.update_key = ""
self.name = self.__class__.__name__
self.cbpi = cbpi
self.cbpi.register(self)
self.service = self
self.types = {}
self.logger = logging.getLogger(__name__)
self.data = []
self.autostart = True
self._loop = asyncio.get_event_loop()
self.path = os.path.join(".", 'config', file)
self.cbpi.app.on_cleanup.append(self.shutdown)
async def init(self):
await self.load()
async def load(self):
logging.info("{} Load ".format(self.name))
with open(self.path) as json_file:
data = json.load(json_file)
self.data = data["data"]
if self.autostart is True:
for d in self.data:
logging.info("{} Starting ".format(self.name))
await self.start(d.get("id"))
await self.push_udpate()
async def save(self):
logging.info("{} Save ".format(self.name))
data = dict(data=list(map(lambda x: self.create_dict(x), self.data)))
with open(self.path, "w") as file:
json.dump(data, file, indent=4, sort_keys=True)
await self.push_udpate()
async def push_udpate(self):
self.cbpi.ws.send(dict(topic=self.update_key, data=list(map(lambda x: self.create_dict(x), self.data))))
def create_dict(self, data):
return dict(name=data.get("name"), id=data.get("id"), type=data.get("type"), status=data.get("status"),props=data.get("props", []))
def find_by_id(self, id):
return next((item for item in self.data if item["id"] == id), None)
def get_index_by_id(self, id):
return next((i for i, item in enumerate(self.data) if item["id"] == id), None)
async def shutdown(self, app):
logging.info("{} Shutdown ".format(self.name))
tasks = []
for item in self.data:
if item.get("instance") is not None and item.get("instance").running is True:
await item.get("instance").stop()
tasks.append(item.get("instance").task)
await asyncio.gather(*tasks)
await self.save()
async def stop(self, id):
logging.info("{} Stop Id {} ".format(self.name, id))
try:
item = self.find_by_id(id)
instance = item.get("instance")
await instance.stop()
await instance.task
await self.push_udpate()
except Exception as e:
logging.error("{} Cant stop {} - {}".format(self.name, id, e))
async def start(self, id):
logging.info("{} Start Id {} ".format(self.name, id))
try:
item = self.find_by_id(id)
instance = item.get("instance")
if instance is not None and instance.running is True:
logging.warning("{} already running {}".format(self.name, id))
return
type = item["type"]
clazz = self.types[type]["class"]
print("#####",item)
item["instance"] = clazz(self.cbpi, item["id"], item["props"])
await item["instance"].start()
item["instance"].task = self._loop.create_task(item["instance"].run())
logging.info("{} started {}".format(self.name, id))
except Exception as e:
logging.error("{} Cant start {} - {}".format(self.name, id, e))
def get_types(self):
logging.info("{} Get Types".format(self.name))
result = {}
for key, value in self.types.items():
result[key] = dict(name=value.get("name"), properties=value.get("properties"), actions=value.get("actions"))
return result
def get_state(self):
logging.info("{} Get State".format(self.name))
return {"data": list(map(lambda x: self.create_dict(x), self.data)), "types":self.get_types()}
async def add(self, data):
logging.info("{} Add".format(self.name))
id = shortuuid.uuid()
item = {**data, "id": id, "instance": None , "name": data.get("name"), "props": data.get("props", {})}
self.data.append(item)
if self.autostart is True:
await self.start(id)
await self.save()
return item
async def update(self, id, data) -> dict:
logging.info("{} Get Update".format(self.name))
await self.stop(id)
self.data = list(map(lambda old: {**old, **data} if old["id"] == id else old, self.data))
if self.autostart is True:
await self.start(id)
await self.save()
return self.find_by_id(id)
async def delete(self, id) -> None:
logging.info("{} Delete".format(self.name))
await self.stop(id)
self.data = list(filter(lambda x: x["id"] != id, self.data))
await self.save()
async def call_action(self, id, action, parameter) -> None:
logging.info("{} call all Action {} {}".format(self.name, id, action))
try:
item = self.find_by_id(id)
instance = item.get("instance")
await instance.__getattribute__(action)(**parameter)
except Exception as e:
logging.error("{} Faild to call action on {} {} {}".format(self.name, id, action, e))