craftbeerpi4-pione/core/craftbeerpi.py

287 lines
9.3 KiB
Python
Raw Normal View History

2018-11-01 19:50:04 +01:00
import asyncio
import logging
from os import urandom
2018-11-16 20:35:59 +01:00
import os
2018-11-01 19:50:04 +01:00
import yaml
from aiohttp import web
from aiohttp_auth import auth
from aiohttp_session import session_middleware
from aiohttp_session.cookie_storage import EncryptedCookieStorage
from aiohttp_swagger import setup_swagger
2018-11-18 15:40:10 +01:00
from core.controller.config_controller import ConfigController
from core.controller.kettle_controller import KettleController
2018-12-03 22:16:03 +01:00
from core.controller.step_controller import StepController
from core.extension.comp import MyComp
2018-11-18 15:40:10 +01:00
from core.job.aiohttp import setup, get_scheduler_from_app
2018-11-01 19:50:04 +01:00
from core.controller.actor_controller import ActorController
2018-11-16 20:35:59 +01:00
from core.controller.notification_controller import NotificationController
2018-11-04 00:47:26 +01:00
from core.controller.plugin_controller import PluginController
2018-11-01 21:25:42 +01:00
from core.controller.sensor_controller import SensorController
2018-11-01 19:50:04 +01:00
from core.controller.system_controller import SystemController
from core.database.model import DBModel
from core.eventbus import CBPiEventBus
2018-11-01 19:50:04 +01:00
from core.http_endpoints.http_login import Login
2018-11-04 00:47:26 +01:00
from core.utils import *
2018-11-01 19:50:04 +01:00
from core.websocket import WebSocket
2018-12-29 00:27:19 +01:00
from core.utils.encoder import ComplexEncoder
2018-11-01 19:50:04 +01:00
2018-12-29 00:27:19 +01:00
logger = logging.getLogger(__name__)
2018-11-01 19:50:04 +01:00
logging.basicConfig(level=logging.INFO)
2018-11-16 20:35:59 +01:00
"""
This is a module docstring
"""
2018-11-01 19:50:04 +01:00
class CraftBeerPi():
2018-11-16 20:35:59 +01:00
"""
This is a Hello class docstring
"""
2018-11-04 00:47:26 +01:00
2018-11-01 19:50:04 +01:00
def __init__(self):
2018-11-16 20:35:59 +01:00
this_directory = os.path.dirname(__file__)
self.config = load_config(os.path.join(this_directory, '../config/config.yaml'))
2018-11-01 19:50:04 +01:00
logger.info("Init CraftBeerPI")
policy = auth.SessionTktAuthentication(urandom(32), 60, include_ip=True)
middlewares = [web.normalize_path_middleware(), session_middleware(EncryptedCookieStorage(urandom(32))), auth.auth_middleware(policy)]
2018-11-01 19:50:04 +01:00
self.app = web.Application(middlewares=middlewares)
2018-11-04 00:47:26 +01:00
self.initializer = []
2018-12-16 21:42:47 +01:00
self.shutdown = False
async def on_cleanup(app):
self.shutdown = True
self.app.on_cleanup.append(on_cleanup)
2018-11-01 19:50:04 +01:00
2018-11-30 23:27:11 +01:00
setup(self.app, self)
2018-12-16 21:42:47 +01:00
self.bus = CBPiEventBus(self.app.loop, self)
2018-11-01 19:50:04 +01:00
self.ws = WebSocket(self)
self.actor = ActorController(self)
self.sensor = SensorController(self)
2018-11-04 00:47:26 +01:00
self.plugin = PluginController(self)
2018-11-01 19:50:04 +01:00
self.system = SystemController(self)
2018-11-18 15:40:10 +01:00
self.config2 = ConfigController(self)
self.kettle = KettleController(self)
2018-12-03 22:16:03 +01:00
self.step = StepController(self)
2018-11-16 20:35:59 +01:00
self.notification = NotificationController(self)
2018-11-01 19:50:04 +01:00
self.login = Login(self)
2018-12-03 22:16:03 +01:00
self.register_events(self.ws)
2018-11-16 20:35:59 +01:00
2018-11-01 19:50:04 +01:00
def register_events(self, obj):
2018-11-01 21:25:42 +01:00
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "eventbus")]:
2018-11-01 19:50:04 +01:00
doc = None
if method.__doc__ is not None:
2018-11-18 15:40:10 +01:00
try:
doc = yaml.load(method.__doc__)
doc["topic"] = method.__getattribute__("topic")
except:
pass
2018-11-29 21:59:08 +01:00
self.bus.register(method.__getattribute__("topic"), method)
2018-11-01 19:50:04 +01:00
def register_background_task(self, obj):
2018-11-16 20:35:59 +01:00
'''
This method parses all method for the @background_task decorator and registers the background job
which will be launched during start up of the server
:param obj: the object to parse
:return:
'''
2018-11-01 19:50:04 +01:00
2018-11-04 01:55:54 +01:00
async def job_loop(app, name, interval, method):
logger.info("Start Background Task %s Interval %s Method %s" % (name, interval, method))
while True:
2018-11-16 20:35:59 +01:00
logger.debug("Execute Task %s - interval(%s second(s)" % (name, interval))
2018-11-04 01:55:54 +01:00
await asyncio.sleep(interval)
await method()
async def spawn_job(app):
scheduler = get_scheduler_from_app(self.app)
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "background_task")]:
name = method.__getattribute__("name")
interval = method.__getattribute__("interval")
2018-11-18 15:40:10 +01:00
job = await scheduler.spawn(job_loop(self.app, name, interval, method),name, "background")
2018-11-04 01:55:54 +01:00
2018-11-01 19:50:04 +01:00
2018-11-04 01:55:54 +01:00
self.app.on_startup.append(spawn_job)
2018-11-01 19:50:04 +01:00
2018-11-04 00:47:26 +01:00
def register_on_startup(self, obj):
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "on_startup")]:
name = method.__getattribute__("name")
order = method.__getattribute__("order")
self.initializer.append(dict(name=name, method=method, order=order))
2018-11-01 19:50:04 +01:00
def register_ws(self, obj):
if self.ws is None:
return
2018-11-01 21:25:42 +01:00
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "ws")]:
2018-11-01 19:50:04 +01:00
self.ws.add_callback(method, method.__getattribute__("key"))
2018-12-07 00:18:35 +01:00
def register(self, obj, url_prefix=None, static=None):
2018-11-16 20:35:59 +01:00
'''
This method parses the provided object
:param obj: the object wich will be parsed for registration
:param url_prefix: that prefix for HTTP Endpoints
:return: None
'''
2018-12-07 00:18:35 +01:00
self.register_http_endpoints(obj, url_prefix, static)
2018-11-01 19:50:04 +01:00
self.register_events(obj)
self.register_ws(obj)
self.register_background_task(obj)
2018-11-04 00:47:26 +01:00
self.register_on_startup(obj)
2018-11-01 19:50:04 +01:00
2018-12-07 00:18:35 +01:00
def register_http_endpoints(self, obj, url_prefix=None, static=None):
2018-11-16 20:35:59 +01:00
'''
This method parses the provided object for @request_mapping decorator
:param obj: the object which will be analyzed
:param url_prefix: the prefix which will be used for the all http endpoints of the object
:return:
'''
2018-11-01 19:50:04 +01:00
routes = []
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "route")]:
http_method = method.__getattribute__("method")
path = method.__getattribute__("path")
2018-11-01 21:25:42 +01:00
class_name = method.__self__.__class__.__name__
2018-11-16 20:35:59 +01:00
logger.info("Register Endpoint : %s.%s %s %s%s " % (class_name, method.__name__, http_method, url_prefix, path))
2018-11-01 19:50:04 +01:00
def add_post():
routes.append(web.post(method.__getattribute__("path"), method))
def add_get():
routes.append(web.get(method.__getattribute__("path"), method))
def add_delete():
routes.append(web.delete(path, method))
def add_put():
routes.append(web.put(path, method))
2018-11-01 21:25:42 +01:00
2018-11-01 19:50:04 +01:00
switcher = {
"POST": add_post,
"GET": add_get,
"DELETE": add_delete,
"PUT": add_put
}
switcher[http_method]()
2018-12-07 00:18:35 +01:00
2018-11-16 20:35:59 +01:00
if url_prefix is not None:
2018-12-29 00:27:19 +01:00
logger.debug("URL Prefix: %s " % (url_prefix,))
2018-11-01 19:50:04 +01:00
sub = web.Application()
sub.add_routes(routes)
2018-12-07 00:18:35 +01:00
if static is not None:
sub.add_routes([web.static('/static', static, show_index=False)])
2018-11-16 20:35:59 +01:00
self.app.add_subapp(url_prefix, sub)
2018-11-01 19:50:04 +01:00
else:
2018-11-01 19:50:04 +01:00
self.app.add_routes(routes)
2018-11-18 15:40:10 +01:00
async def start_job(self, method, name, type):
scheduler = get_scheduler_from_app(self.app)
return await scheduler.spawn(method, name, type)
2018-11-04 00:47:26 +01:00
def _swagger_setup(self):
2018-11-16 20:35:59 +01:00
'''
Internatl method to expose REST API documentation by swagger
:return:
'''
2018-11-04 00:47:26 +01:00
long_description = """
2018-11-18 15:40:10 +01:00
This is the api for CraftBeerPi
2018-11-04 00:47:26 +01:00
"""
setup_swagger(self.app,
description=long_description,
title=self.config.get("name", "CraftBeerPi"),
api_version=self.config.get("version", ""),
contact="info@craftbeerpi.com")
2018-11-16 20:35:59 +01:00
def notify(self, key, message, type="info"):
'''
This is a convinience method to send notification to the client
:param key: notification key
:param message: notification message
:param type: notification type (info,warning,danger,successs)
:return:
'''
2018-12-13 21:45:33 +01:00
self.bus.sync_fire(topic="notification/%s" % key, key=key, message=message, type=type)
2018-11-01 19:50:04 +01:00
2018-11-16 20:35:59 +01:00
def setup(self):
'''
This method will start the server
:return:
'''
2018-12-29 00:27:19 +01:00
2018-11-01 19:50:04 +01:00
#async def init_database(app):
2018-12-29 00:27:19 +01:00
2018-11-04 00:47:26 +01:00
#self.app.on_startup.append(call_initializer)
2018-11-04 00:47:26 +01:00
async def call_initializer(self, app):
self.initializer = sorted(self.initializer, key=lambda k: k['order'])
for i in self.initializer:
logger.info("CALL INITIALIZER %s - %s " % (i["name"], i["method"].__name__))
await i["method"]()
2018-11-04 00:47:26 +01:00
def _print_logo(self):
from pyfiglet import Figlet
f = Figlet(font='big')
logger.info("\n%s" % f.renderText("%s %s" % (self.config.get("name"), self.config.get("version"))))
2018-11-04 00:47:26 +01:00
async def init_serivces(self):
2018-11-04 00:47:26 +01:00
self._print_logo()
await DBModel.test_connection()
await self.config2.init()
self.plugin.load_plugins()
self.plugin.load_plugins_from_evn()
await self.sensor.init()
await self.step.init()
await self.actor.init()
await self.kettle.init()
await self.call_initializer(self.app)
2018-11-16 20:35:59 +01:00
logger.info(self.sensor.info())
logger.info(self.actor.info())
2018-11-16 20:35:59 +01:00
2018-11-04 00:47:26 +01:00
self._swagger_setup()
2018-11-16 20:35:59 +01:00
return self.app
2018-11-16 20:35:59 +01:00
def start(self):
web.run_app(self.init_serivces(), port=self.config.get("port", 8080))