コード例 #1
0
ファイル: craftbeerpi.py プロジェクト: shrank/craftbeerpi4
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))
コード例 #2
0
ファイル: craftbeerpi.py プロジェクト: avollkopf/craftbeerpi4
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))