moonraker: add register_component() method

Allow base modules to register themselves as components during
initialization.  This makes them accessible via lookup_component()
across the entire application.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Eric Callahan 2021-12-26 11:13:30 -05:00
parent 27c65e0a64
commit a652845843
4 changed files with 32 additions and 27 deletions

View File

@ -192,7 +192,7 @@ class MoonrakerApp:
'serve_traceback': self.debug, 'serve_traceback': self.debug,
'websocket_ping_interval': 10, 'websocket_ping_interval': 10,
'websocket_ping_timeout': 30, 'websocket_ping_timeout': 30,
'parent': self, 'server': self.server,
'default_handler_class': AuthorizedErrorHandler, 'default_handler_class': AuthorizedErrorHandler,
'default_handler_args': {}, 'default_handler_args': {},
'log_function': self.log_request 'log_function': self.log_request
@ -216,6 +216,12 @@ class MoonrakerApp:
"klippy.log", DEFAULT_KLIPPY_LOG_PATH, force=True) "klippy.log", DEFAULT_KLIPPY_LOG_PATH, force=True)
self.register_upload_handler("/server/files/upload") self.register_upload_handler("/server/files/upload")
# Register Server Components
self.server.register_component("application", self)
self.server.register_component("websockets", self.wsm)
self.server.register_component("internal_transport",
self.internal_transport)
def _get_path_option(self, config: ConfigHelper, option: str) -> str: def _get_path_option(self, config: ConfigHelper, option: str) -> str:
path: Optional[str] = config.get(option, None) path: Optional[str] = config.get(option, None)
if path is None: if path is None:
@ -265,12 +271,6 @@ class MoonrakerApp:
def get_server(self) -> Server: def get_server(self) -> Server:
return self.server return self.server
def get_websocket_manager(self) -> WebsocketManager:
return self.wsm
def get_internal_transport(self) -> InternalTransport:
return self.internal_transport
async def close(self) -> None: async def close(self) -> None:
if self.http_server is not None: if self.http_server is not None:
self.http_server.stop() self.http_server.stop()
@ -412,13 +412,13 @@ class MoonrakerApp:
class AuthorizedRequestHandler(tornado.web.RequestHandler): class AuthorizedRequestHandler(tornado.web.RequestHandler):
def initialize(self) -> None: def initialize(self) -> None:
self.server: Server = self.settings['parent'].get_server() self.server: Server = self.settings['server']
def set_default_headers(self) -> None: def set_default_headers(self) -> None:
origin: Optional[str] = self.request.headers.get("Origin") origin: Optional[str] = self.request.headers.get("Origin")
# it is necessary to look up the parent app here, # it is necessary to look up the parent app here,
# as initialize() may not yet be called # as initialize() may not yet be called
server: Server = self.settings['parent'].get_server() server: Server = self.settings['server']
auth: AuthComp = server.lookup_component('authorization', None) auth: AuthComp = server.lookup_component('authorization', None)
self.cors_enabled = False self.cors_enabled = False
if auth is not None: if auth is not None:
@ -448,8 +448,8 @@ class AuthorizedRequestHandler(tornado.web.RequestHandler):
except Exception: except Exception:
pass pass
else: else:
parent: MoonrakerApp = self.settings['parent'] wsm: WebsocketManager = self.server.lookup_component(
wsm: WebsocketManager = parent.get_websocket_manager() "websockets")
conn = wsm.get_websocket(conn_id) conn = wsm.get_websocket(conn_id)
return conn return conn
@ -468,13 +468,13 @@ class AuthorizedFileHandler(tornado.web.StaticFileHandler):
default_filename: Optional[str] = None default_filename: Optional[str] = None
) -> None: ) -> None:
super(AuthorizedFileHandler, self).initialize(path, default_filename) super(AuthorizedFileHandler, self).initialize(path, default_filename)
self.server: Server = self.settings['parent'].get_server() self.server: Server = self.settings['server']
def set_default_headers(self) -> None: def set_default_headers(self) -> None:
origin: Optional[str] = self.request.headers.get("Origin") origin: Optional[str] = self.request.headers.get("Origin")
# it is necessary to look up the parent app here, # it is necessary to look up the parent app here,
# as initialize() may not yet be called # as initialize() may not yet be called
server: Server = self.settings['parent'].get_server() server: Server = self.settings['server']
auth: AuthComp = server.lookup_component('authorization', None) auth: AuthComp = server.lookup_component('authorization', None)
self.cors_enabled = False self.cors_enabled = False
if auth is not None: if auth is not None:

View File

@ -24,7 +24,7 @@ from typing import (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from confighelper import ConfigHelper from confighelper import ConfigHelper
from websockets import WebRequest from websockets import WebRequest, WebsocketManager
from . import shell_command from . import shell_command
from .machine import Machine from .machine import Machine
@ -95,7 +95,8 @@ class ProcStats:
ts = await self._check_throttled_state() ts = await self._check_throttled_state()
cpu_temp = await self.event_loop.run_in_thread( cpu_temp = await self.event_loop.run_in_thread(
self._get_cpu_temperature) self._get_cpu_temperature)
websocket_count = self.server.get_websocket_manager().get_count() wsm: WebsocketManager = self.server.lookup_component("websockets")
websocket_count = wsm.get_count()
return { return {
'moonraker_stats': list(self.proc_stat_queue), 'moonraker_stats': list(self.proc_stat_queue),
'throttled_state': ts, 'throttled_state': ts,
@ -140,7 +141,8 @@ class ProcStats:
'mem_units': mem_units 'mem_units': mem_units
} }
self.proc_stat_queue.append(result) self.proc_stat_queue.append(result)
websocket_count = self.server.get_websocket_manager().get_count() wsm: WebsocketManager = self.server.lookup_component("websockets")
websocket_count = wsm.get_count()
self.server.send_event("proc_stats:proc_stat_update", { self.server.send_event("proc_stats:proc_stat_update", {
'moonraker_stats': result, 'moonraker_stats': result,
'cpu_temp': cpu_temp, 'cpu_temp': cpu_temp,

View File

@ -32,14 +32,13 @@ from typing import (
Optional, Optional,
Callable, Callable,
Coroutine, Coroutine,
Tuple,
Dict, Dict,
List, List,
Union, Union,
TypeVar, TypeVar,
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from websockets import WebRequest, Subscribable from websockets import WebRequest, Subscribable, WebsocketManager
from components.data_store import DataStore from components.data_store import DataStore
from components.klippy_apis import KlippyAPI from components.klippy_apis import KlippyAPI
from components.file_manager.file_manager import FileManager from components.file_manager.file_manager import FileManager
@ -110,6 +109,7 @@ class Server:
self.klippy_state: str = "disconnected" self.klippy_state: str = "disconnected"
self.klippy_disconnect_evt: Optional[asyncio.Event] = None self.klippy_disconnect_evt: Optional[asyncio.Event] = None
self.connection_init_lock: asyncio.Lock = asyncio.Lock() self.connection_init_lock: asyncio.Lock = asyncio.Lock()
self.components: Dict[str, Any] = {}
self.subscriptions: Dict[Subscribable, Dict[str, Any]] = {} self.subscriptions: Dict[Subscribable, Dict[str, Any]] = {}
self.failed_components: List[str] = [] self.failed_components: List[str] = []
self.warnings: List[str] = [] self.warnings: List[str] = []
@ -120,7 +120,6 @@ class Server:
self.register_endpoint = app.register_local_handler self.register_endpoint = app.register_local_handler
self.register_static_file_handler = app.register_static_file_handler self.register_static_file_handler = app.register_static_file_handler
self.register_upload_handler = app.register_upload_handler self.register_upload_handler = app.register_upload_handler
self.get_websocket_manager = app.get_websocket_manager
self.register_api_transport = app.register_api_transport self.register_api_transport = app.register_api_transport
self.register_endpoint( self.register_endpoint(
@ -150,7 +149,6 @@ class Server:
need_klippy_reg=False) need_klippy_reg=False)
# Component initialization # Component initialization
self.components: Dict[str, Any] = {}
self._load_components(config) self._load_components(config)
self.klippy_apis: KlippyAPI = self.lookup_component('klippy_apis') self.klippy_apis: KlippyAPI = self.lookup_component('klippy_apis')
config.validate_config() config.validate_config()
@ -275,11 +273,17 @@ class Server:
if component_name not in self.failed_components: if component_name not in self.failed_components:
self.failed_components.append(component_name) self.failed_components.append(component_name)
def register_component(self, component_name: str, component: Any) -> None:
if component_name in self.components:
raise self.error(
f"Component '{component_name}' already registered")
self.components[component_name] = component
def register_notification(self, def register_notification(self,
event_name: str, event_name: str,
notify_name: Optional[str] = None notify_name: Optional[str] = None
) -> None: ) -> None:
wsm = self.get_websocket_manager() wsm: WebsocketManager = self.lookup_component("websockets")
wsm.register_notification(event_name, notify_name) wsm.register_notification(event_name, notify_name)
def register_event_handler(self, def register_event_handler(self,
@ -682,6 +686,7 @@ class Server:
reg_dirs = [] reg_dirs = []
if file_manager is not None: if file_manager is not None:
reg_dirs = file_manager.get_registered_dirs() reg_dirs = file_manager.get_registered_dirs()
wsm: WebsocketManager = self.lookup_component('websockets')
return { return {
'klippy_connected': self.klippy_connection.is_connected(), 'klippy_connected': self.klippy_connection.is_connected(),
'klippy_state': self.klippy_state, 'klippy_state': self.klippy_state,
@ -689,7 +694,7 @@ class Server:
'failed_components': self.failed_components, 'failed_components': self.failed_components,
'registered_directories': reg_dirs, 'registered_directories': reg_dirs,
'warnings': self.warnings, 'warnings': self.warnings,
'websocket_count': self.get_websocket_manager().get_count(), 'websocket_count': wsm.get_count(),
'moonraker_version': self.app_args['software_version'] 'moonraker_version': self.app_args['software_version']
} }

View File

@ -27,8 +27,7 @@ from typing import (
) )
if TYPE_CHECKING: if TYPE_CHECKING:
from moonraker import Server from moonraker import Server
from eventloop import EventLoop from app import APIDefinition
from app import APIDefinition, MoonrakerApp
import components.authorization import components.authorization
_T = TypeVar("_T") _T = TypeVar("_T")
_C = TypeVar("_C", str, bool, float, int) _C = TypeVar("_C", str, bool, float, int)
@ -381,10 +380,9 @@ class WebsocketManager(APITransport):
class WebSocket(WebSocketHandler, Subscribable): class WebSocket(WebSocketHandler, Subscribable):
def initialize(self) -> None: def initialize(self) -> None:
app: MoonrakerApp = self.settings['parent'] self.server: Server = self.settings['server']
self.server = app.get_server()
self.event_loop = self.server.get_event_loop() self.event_loop = self.server.get_event_loop()
self.wsm = app.get_websocket_manager() self.wsm: WebsocketManager = self.server.lookup_component("websockets")
self.rpc = self.wsm.rpc self.rpc = self.wsm.rpc
self.uid = id(self) self.uid = id(self)
self.is_closed: bool = False self.is_closed: bool = False