class CraftBeerPi(): def __init__(self): self.version = "4.0.0.1" self.static_config = load_config("./config/config.yaml") self.database_file = "./craftbeerpi.db" 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), error_middleware ] self.app = web.Application(middlewares=middlewares) self.app["cbpi"] = self self._setup_shutdownhook() self.initializer = [] self.bus = CBPiEventBus(self.app.loop, self) self.job = JobController(self) self.config = ConfigController(self) self.ws = CBPiWebSocket(self) self.translation = TranslationController(self) self.actor = ActorController(self) self.sensor = SensorController(self) self.plugin = PluginController(self) self.log = LogController(self) self.system = SystemController(self) self.kettle = KettleController(self) self.step = StepController(self) self.dashboard = DashboardController(self) self.http_step = StepHttpEndpoints(self) self.http_sensor = SensorHttpEndpoints(self) self.http_config = ConfigHttpEndpoints(self) self.http_actor = ActorHttpEndpoints(self) self.http_kettle = KettleHttpEndpoints(self) self.http_dashboard = DashBoardHttpEndpoints(self) self.http_translation = TranslationHttpEndpoint(self) self.http_plugin = PluginHttpEndpoints(self) self.http_system = SystemHttpEndpoints(self) self.notification = NotificationController(self) self.http_log = LogHttpEndpoints(self) self.login = Login(self) def _setup_shutdownhook(self): self.shutdown = False async def on_cleanup(app): self.shutdown = True self.app.on_cleanup.append(on_cleanup) 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)) def register(self, obj, url_prefix=None, static=None): ''' 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 ''' self.register_http_endpoints(obj, url_prefix, static) self.bus.register_object(obj) #self.ws.register_object(obj) self.job.register_background_task(obj) self.register_on_startup(obj) def register_http_endpoints(self, obj, url_prefix=None, static=None): if url_prefix is None: logger.debug( "URL Prefix is None for %s. No endpoints will be registered. Please set / explicit if you want to add it to the root path" % obj) return 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") class_name = method.__self__.__class__.__name__ logger.info( "Register Endpoint : %s.%s %s %s%s " % (class_name, method.__name__, http_method, url_prefix, path)) def add_post(): routes.append(web.post(method.__getattribute__("path"), method)) def add_get(): routes.append( web.get(method.__getattribute__("path"), method, allow_head=False)) def add_delete(): routes.append(web.delete(path, method)) def add_put(): routes.append(web.put(path, method)) switcher = { "POST": add_post, "GET": add_get, "DELETE": add_delete, "PUT": add_put } switcher[http_method]() if url_prefix != "/": logger.debug("URL Prefix: %s " % (url_prefix, )) sub = web.Application() sub.add_routes(routes) if static is not None: sub.add_routes( [web.static('/static', static, show_index=False)]) self.app.add_subapp(url_prefix, sub) else: self.app.add_routes(routes) def _swagger_setup(self): ''' Internatl method to expose REST API documentation by swagger :return: ''' long_description = """ This is the api for CraftBeerPi """ setup_swagger(self.app, description=long_description, title=self.static_config.get("name", "CraftBeerPi"), api_version=self.static_config.get("version", ""), contact="*****@*****.**") def notify(self, key: str, message: str, type: str = "info") -> None: ''' 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: ''' self.bus.sync_fire(topic="notification/%s" % key, key=key, message=message, type=type) 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"]() def _print_logo(self): from pyfiglet import Figlet f = Figlet(font='big') logger.info("\n%s" % f.renderText("%s %s" % (self.static_config.get("name"), self.static_config.get("version")))) def _setup_http_index(self): async def http_index(request): url = self.config.static.get("index_url") if url is not None: raise web.HTTPFound(url) else: return web.Response(text="Hello from CraftbeerPi!") self.app.add_routes([ web.get('/', http_index), web.static('/static', os.path.join(os.path.dirname(__file__), "static"), show_index=True) ]) async def init_serivces(self): self._print_logo() await self.job.init() await DBModel.setup() await self.config.init() await self.translation.init() self._setup_http_index() 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) await self.dashboard.init() self._swagger_setup() return self.app def start(self): web.run_app(self.init_serivces(), port=self.static_config.get("port", 8080))
class CraftBeerPi: def __init__(self, configFolder): operationsystem= sys.platform if operationsystem.startswith('win'): set_event_loop_policy(WindowsSelectorEventLoopPolicy()) self.path = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-1]) # The path to the package dir self.version = __version__ self.codename = __codename__ self.config_folder = configFolder self.static_config = load_config(configFolder.get_file_path("config.yaml")) 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), error_middleware] # max upload size increased to 5 Mb. Default is 1 Mb -> config and svg upload self.app = web.Application(middlewares=middlewares, client_max_size=5*1024*1024) self.app["cbpi"] = self self._setup_shutdownhook() self.initializer = [] self.bus = CBPiEventBus(self.app.loop, self) self.job = JobController(self) self.config = ConfigController(self) self.ws = CBPiWebSocket(self) self.actor = ActorController(self) self.sensor = SensorController(self) self.plugin = PluginController(self) self.log = LogController(self) self.system = SystemController(self) self.kettle = KettleController(self) self.fermenter : FermentationController = FermentationController(self) self.step : StepController = StepController(self) self.recipe : RecipeController = RecipeController(self) self.fermenterrecipe : FermenterRecipeController = FermenterRecipeController(self) self.upload : UploadController = UploadController(self) self.notification : NotificationController = NotificationController(self) self.satellite = None if str(self.static_config.get("mqtt", False)).lower() == "true": self.satellite: SatelliteController = SatelliteController(self) self.dashboard = DashboardController(self) self.http_step = StepHttpEndpoints(self) self.http_recipe = RecipeHttpEndpoints(self) self.http_fermenterrecipe = FermenterRecipeHttpEndpoints(self) self.http_sensor = SensorHttpEndpoints(self) self.http_config = ConfigHttpEndpoints(self) self.http_actor = ActorHttpEndpoints(self) self.http_kettle = KettleHttpEndpoints(self) self.http_dashboard = DashBoardHttpEndpoints(self) self.http_plugin = PluginHttpEndpoints(self) self.http_system = SystemHttpEndpoints(self) self.http_log = LogHttpEndpoints(self) self.http_notification = NotificationHttpEndpoints(self) self.http_upload = UploadHttpEndpoints(self) self.http_fermenter = FermentationHttpEndpoints(self) self.login = Login(self) def _setup_shutdownhook(self): self.shutdown = False async def on_cleanup(app): self.shutdown = True self.app.on_cleanup.append(on_cleanup) 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)) def register(self, obj, url_prefix=None, static=None): ''' 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 ''' self.register_http_endpoints(obj, url_prefix, static) self.bus.register_object(obj) # self.ws.register_object(obj) self.job.register_background_task(obj) self.register_on_startup(obj) def register_http_endpoints(self, obj, url_prefix=None, static=None): if url_prefix is None: logger.debug( "URL Prefix is None for %s. No endpoints will be registered. Please set / explicit if you want to add it to the root path" % obj) return 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") class_name = method.__self__.__class__.__name__ logger.debug( "Register Endpoint : %s.%s %s %s%s " % (class_name, method.__name__, http_method, url_prefix, path)) def add_post(): routes.append(web.post(method.__getattribute__("path"), method)) def add_get(): routes.append(web.get(method.__getattribute__("path"), method, allow_head=False)) def add_delete(): routes.append(web.delete(path, method)) def add_put(): routes.append(web.put(path, method)) switcher = { "POST": add_post, "GET": add_get, "DELETE": add_delete, "PUT": add_put } switcher[http_method]() if url_prefix != "/": logger.debug("URL Prefix: %s " % (url_prefix,)) sub = web.Application() sub.add_routes(routes) if static is not None: sub.add_routes([web.static('/static', static, show_index=True)]) self.app.add_subapp(url_prefix, sub) else: self.app.add_routes(routes) def _swagger_setup(self): ''' Internal method to expose REST API documentation by swagger :return: ''' long_description = """ This is the api for CraftBeerPi """ setup_swagger(self.app, description=long_description, title="CraftBeerPi", api_version=self.version, contact="*****@*****.**") def notify(self, title: str, message: str, type: NotificationType = NotificationType.INFO, action=[]) -> None: self.notification.notify(title, message, type, action) def push_update(self, topic, data, retain=False) -> None: if self.satellite is not None: asyncio.create_task(self.satellite.publish(topic=topic, message=json.dumps(data), retain=retain)) 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"]() def _print_logo(self): from pyfiglet import Figlet f = Figlet(font='big') logger.info("\n%s" % f.renderText("CraftBeerPi %s " % self.version)) logger.info("www.CraftBeerPi.com") logger.info("(c) 2021/2022 Manuel Fritsch / Alexander Vollkopf") def _setup_http_index(self): async def http_index(request): url = self.config.static.get("index_url") if url is not None: raise web.HTTPFound(url) else: return web.Response(text="Hello from CraftbeerPi!") self.app.add_routes([web.get('/', http_index), web.static('/static', os.path.join(os.path.dirname(__file__), "static"), show_index=True)]) async def init_serivces(self): self._print_logo() await self.job.init() await self.config.init() if self.satellite is not None: await self.satellite.init() self._setup_http_index() self.plugin.load_plugins() self.plugin.load_plugins_from_evn() await self.fermenter.init() await self.sensor.init() await self.step.init() await self.actor.init() await self.kettle.init() await self.call_initializer(self.app) await self.dashboard.init() self._swagger_setup() level = logging.INFO logger = logging.getLogger() logger.setLevel(level) for handler in logger.handlers: handler.setLevel(level) return self.app def start(self): web.run_app(self.init_serivces(), port=self.static_config.get("port", 2202))