From 6d73c60a3898bd545371a62ae6424a4ef7e6c2dc Mon Sep 17 00:00:00 2001 From: Eric Callahan Date: Thu, 23 Feb 2023 19:34:04 -0500 Subject: [PATCH] moonraker: move common classes to common.py Signed-off-by: Eric Callahan --- moonraker/app.py | 21 +-- moonraker/common.py | 169 ++++++++++++++++++ moonraker/components/announcements.py | 2 +- moonraker/components/authorization.py | 3 +- moonraker/components/data_store.py | 2 +- moonraker/components/database.py | 2 +- moonraker/components/extensions.py | 2 +- .../components/file_manager/file_manager.py | 2 +- moonraker/components/history.py | 2 +- moonraker/components/job_queue.py | 2 +- moonraker/components/klippy_apis.py | 3 +- moonraker/components/machine.py | 2 +- moonraker/components/mqtt.py | 3 +- moonraker/components/notifier.py | 2 +- moonraker/components/octoprint_compat.py | 2 +- moonraker/components/power.py | 2 +- moonraker/components/proc_stats.py | 3 +- moonraker/components/sensor.py | 2 +- moonraker/components/simplyprint.py | 2 +- .../update_manager/update_manager.py | 2 +- moonraker/components/webcam.py | 2 +- moonraker/components/wled.py | 2 +- moonraker/klippy_connection.py | 2 +- moonraker/loghelper.py | 2 +- moonraker/server.py | 3 +- moonraker/websockets.py | 123 +------------ 26 files changed, 199 insertions(+), 165 deletions(-) create mode 100644 moonraker/common.py diff --git a/moonraker/app.py b/moonraker/app.py index cf87f8a..acec8d9 100644 --- a/moonraker/app.py +++ b/moonraker/app.py @@ -22,12 +22,11 @@ from tornado.escape import url_unescape, url_escape from tornado.routing import Rule, PathMatches, AnyMatches from tornado.http1connection import HTTP1Connection from tornado.log import access_log +from .common import WebRequest, APIDefinition, APITransport from .utils import ServerError, source_info from .websockets import ( - WebRequest, WebsocketManager, WebSocket, - APITransport, BridgeSocket ) from streaming_form_data import StreamingFormDataParser @@ -111,24 +110,6 @@ class MutableRouter(tornado.web.ReversibleRuleRouter): except Exception: logging.exception(f"Unable to remove rule: {pattern}") -class APIDefinition: - def __init__(self, - endpoint: str, - http_uri: str, - jrpc_methods: List[str], - request_methods: Union[str, List[str]], - transports: List[str], - callback: Optional[APICallback], - need_object_parser: bool): - self.endpoint = endpoint - self.uri = http_uri - self.jrpc_methods = jrpc_methods - if not isinstance(request_methods, list): - request_methods = [request_methods] - self.request_methods = request_methods - self.supported_transports = transports - self.callback = callback - self.need_object_parser = need_object_parser class InternalTransport(APITransport): def __init__(self, server: Server) -> None: diff --git a/moonraker/common.py b/moonraker/common.py new file mode 100644 index 0000000..6ea4b06 --- /dev/null +++ b/moonraker/common.py @@ -0,0 +1,169 @@ +# Common classes used throughout Moonraker +# +# Copyright (C) 2023 Eric Callahan +# +# This file may be distributed under the terms of the GNU GPLv3 license + +from __future__ import annotations +import ipaddress +from .utils import ServerError, Sentinel + +# Annotation imports +from typing import ( + TYPE_CHECKING, + Any, + Optional, + Callable, + Coroutine, + Type, + TypeVar, + Union, + Dict, + List, +) + +if TYPE_CHECKING: + from .websockets import BaseSocketClient + from .components.authorization import Authorization + _T = TypeVar("_T") + _C = TypeVar("_C", str, bool, float, int) + IPUnion = Union[ipaddress.IPv4Address, ipaddress.IPv6Address] + ConvType = Union[str, bool, float, int] + ArgVal = Union[None, int, float, bool, str] + RPCCallback = Callable[..., Coroutine] + AuthComp = Optional[Authorization] + +class Subscribable: + def send_status(self, + status: Dict[str, Any], + eventtime: float + ) -> None: + raise NotImplementedError + +class WebRequest: + def __init__(self, + endpoint: str, + args: Dict[str, Any], + action: Optional[str] = "", + conn: Optional[Subscribable] = None, + ip_addr: str = "", + user: Optional[Dict[str, Any]] = None + ) -> None: + self.endpoint = endpoint + self.action = action or "" + self.args = args + self.conn = conn + self.ip_addr: Optional[IPUnion] = None + try: + self.ip_addr = ipaddress.ip_address(ip_addr) + except Exception: + self.ip_addr = None + self.current_user = user + + def get_endpoint(self) -> str: + return self.endpoint + + def get_action(self) -> str: + return self.action + + def get_args(self) -> Dict[str, Any]: + return self.args + + def get_subscribable(self) -> Optional[Subscribable]: + return self.conn + + def get_client_connection(self) -> Optional[BaseSocketClient]: + if isinstance(self.conn, BaseSocketClient): + return self.conn + return None + + def get_ip_address(self) -> Optional[IPUnion]: + return self.ip_addr + + def get_current_user(self) -> Optional[Dict[str, Any]]: + return self.current_user + + def _get_converted_arg(self, + key: str, + default: Union[Sentinel, _T], + dtype: Type[_C] + ) -> Union[_C, _T]: + if key not in self.args: + if default is Sentinel.MISSING: + raise ServerError(f"No data for argument: {key}") + return default + val = self.args[key] + try: + if dtype is not bool: + return dtype(val) + else: + if isinstance(val, str): + val = val.lower() + if val in ["true", "false"]: + return True if val == "true" else False # type: ignore + elif isinstance(val, bool): + return val # type: ignore + raise TypeError + except Exception: + raise ServerError( + f"Unable to convert argument [{key}] to {dtype}: " + f"value recieved: {val}") + + def get(self, + key: str, + default: Union[Sentinel, _T] = Sentinel.MISSING + ) -> Union[_T, Any]: + val = self.args.get(key, default) + if val is Sentinel.MISSING: + raise ServerError(f"No data for argument: {key}") + return val + + def get_str(self, + key: str, + default: Union[Sentinel, _T] = Sentinel.MISSING + ) -> Union[str, _T]: + return self._get_converted_arg(key, default, str) + + def get_int(self, + key: str, + default: Union[Sentinel, _T] = Sentinel.MISSING + ) -> Union[int, _T]: + return self._get_converted_arg(key, default, int) + + def get_float(self, + key: str, + default: Union[Sentinel, _T] = Sentinel.MISSING + ) -> Union[float, _T]: + return self._get_converted_arg(key, default, float) + + def get_boolean(self, + key: str, + default: Union[Sentinel, _T] = Sentinel.MISSING + ) -> Union[bool, _T]: + return self._get_converted_arg(key, default, bool) + +class APIDefinition: + def __init__(self, + endpoint: str, + http_uri: str, + jrpc_methods: List[str], + request_methods: Union[str, List[str]], + transports: List[str], + callback: Optional[Callable[[WebRequest], Coroutine]], + need_object_parser: bool): + self.endpoint = endpoint + self.uri = http_uri + self.jrpc_methods = jrpc_methods + if not isinstance(request_methods, list): + request_methods = [request_methods] + self.request_methods = request_methods + self.supported_transports = transports + self.callback = callback + self.need_object_parser = need_object_parser + +class APITransport: + def register_api_handler(self, api_def: APIDefinition) -> None: + raise NotImplementedError + + def remove_api_handler(self, api_def: APIDefinition) -> None: + raise NotImplementedError diff --git a/moonraker/components/announcements.py b/moonraker/components/announcements.py index 711fd28..6b825ff 100644 --- a/moonraker/components/announcements.py +++ b/moonraker/components/announcements.py @@ -22,7 +22,7 @@ from typing import ( ) if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from .http_client import HttpClient from .database import MoonrakerDatabase diff --git a/moonraker/components/authorization.py b/moonraker/components/authorization.py index 5b201f2..f75c49d 100644 --- a/moonraker/components/authorization.py +++ b/moonraker/components/authorization.py @@ -35,7 +35,8 @@ from typing import ( if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest, WebsocketManager + from ..common import WebRequest + from ..websockets import WebsocketManager from tornado.httputil import HTTPServerRequest from tornado.web import RequestHandler from .database import MoonrakerDatabase as DBComp diff --git a/moonraker/components/data_store.py b/moonraker/components/data_store.py index 00fab7e..e01f207 100644 --- a/moonraker/components/data_store.py +++ b/moonraker/components/data_store.py @@ -21,7 +21,7 @@ from typing import ( ) if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from .klippy_apis import KlippyAPI as APIComp GCQueue = Deque[Dict[str, Any]] TempStore = Dict[str, Dict[str, Deque[float]]] diff --git a/moonraker/components/database.py b/moonraker/components/database.py index afe08c7..db79f6f 100644 --- a/moonraker/components/database.py +++ b/moonraker/components/database.py @@ -34,7 +34,7 @@ from typing import ( ) if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest DBRecord = Union[int, float, bool, str, List[Any], Dict[str, Any]] DBType = Optional[DBRecord] _T = TypeVar("_T") diff --git a/moonraker/components/extensions.py b/moonraker/components/extensions.py index 90b78d6..1989145 100644 --- a/moonraker/components/extensions.py +++ b/moonraker/components/extensions.py @@ -24,7 +24,7 @@ from typing import ( if TYPE_CHECKING: from ..server import Server from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from ..klippy_connection import KlippyConnection as Klippy UNIX_BUFFER_LIMIT = 20 * 1024 * 1024 diff --git a/moonraker/components/file_manager/file_manager.py b/moonraker/components/file_manager/file_manager.py index adf82c3..d325677 100644 --- a/moonraker/components/file_manager/file_manager.py +++ b/moonraker/components/file_manager/file_manager.py @@ -41,7 +41,7 @@ from typing import ( if TYPE_CHECKING: from inotify_simple import Event as InotifyEvent from ...confighelper import ConfigHelper - from ...websockets import WebRequest + from ...common import WebRequest from ...klippy_connection import KlippyConnection from .. import database from .. import klippy_apis diff --git a/moonraker/components/history.py b/moonraker/components/history.py index 704ec7a..84f5612 100644 --- a/moonraker/components/history.py +++ b/moonraker/components/history.py @@ -18,7 +18,7 @@ from typing import ( ) if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from .database import MoonrakerDatabase as DBComp from .job_state import JobState from .file_manager.file_manager import FileManager diff --git a/moonraker/components/job_queue.py b/moonraker/components/job_queue.py index 7d11970..2b55d1d 100644 --- a/moonraker/components/job_queue.py +++ b/moonraker/components/job_queue.py @@ -20,7 +20,7 @@ from typing import ( ) if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from .klippy_apis import KlippyAPI from .file_manager.file_manager import FileManager diff --git a/moonraker/components/klippy_apis.py b/moonraker/components/klippy_apis.py index a668a4c..e52071c 100644 --- a/moonraker/components/klippy_apis.py +++ b/moonraker/components/klippy_apis.py @@ -6,7 +6,7 @@ from __future__ import annotations from ..utils import Sentinel -from ..websockets import WebRequest, Subscribable +from ..common import WebRequest, Subscribable # Annotation imports from typing import ( @@ -21,7 +21,6 @@ from typing import ( ) if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest from ..klippy_connection import KlippyConnection as Klippy Subscription = Dict[str, Optional[List[Any]]] _T = TypeVar("_T") diff --git a/moonraker/components/machine.py b/moonraker/components/machine.py index 75ded07..7f89c96 100644 --- a/moonraker/components/machine.py +++ b/moonraker/components/machine.py @@ -40,7 +40,7 @@ from typing import ( if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from ..app import MoonrakerApp from ..klippy_connection import KlippyConnection from .shell_command import ShellCommandFactory as SCMDComp diff --git a/moonraker/components/mqtt.py b/moonraker/components/mqtt.py index 914f51c..80b3ba1 100644 --- a/moonraker/components/mqtt.py +++ b/moonraker/components/mqtt.py @@ -13,7 +13,8 @@ import pathlib import ssl from collections import deque import paho.mqtt.client as paho_mqtt -from ..websockets import Subscribable, WebRequest, JsonRPC, APITransport +from ..common import Subscribable, WebRequest, APITransport +from ..websockets import JsonRPC # Annotation imports from typing import ( diff --git a/moonraker/components/notifier.py b/moonraker/components/notifier.py index ba973df..fbe0c87 100644 --- a/moonraker/components/notifier.py +++ b/moonraker/components/notifier.py @@ -19,7 +19,7 @@ from typing import ( if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from .http_client import HttpClient from .klippy_apis import KlippyAPI as APIComp diff --git a/moonraker/components/octoprint_compat.py b/moonraker/components/octoprint_compat.py index c0cfab1..d0ff5a2 100644 --- a/moonraker/components/octoprint_compat.py +++ b/moonraker/components/octoprint_compat.py @@ -16,7 +16,7 @@ from typing import ( ) if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from .klippy_apis import KlippyAPI as APIComp from .file_manager.file_manager import FileManager from .job_queue import JobQueue diff --git a/moonraker/components/power.py b/moonraker/components/power.py index 14068f6..d8aea78 100644 --- a/moonraker/components/power.py +++ b/moonraker/components/power.py @@ -28,7 +28,7 @@ from typing import ( if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from .machine import Machine from .klippy_apis import KlippyAPI as APIComp from .mqtt import MQTTClient diff --git a/moonraker/components/proc_stats.py b/moonraker/components/proc_stats.py index f88cb66..1f87fc5 100644 --- a/moonraker/components/proc_stats.py +++ b/moonraker/components/proc_stats.py @@ -27,7 +27,8 @@ from typing import ( ) if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest, WebsocketManager + from ..common import WebRequest + from ..websockets import WebsocketManager from . import shell_command STAT_CALLBACK = Callable[[int], Optional[Awaitable]] diff --git a/moonraker/components/sensor.py b/moonraker/components/sensor.py index 73310d4..c144ba6 100644 --- a/moonraker/components/sensor.py +++ b/moonraker/components/sensor.py @@ -28,7 +28,7 @@ from typing import ( if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from .mqtt import MQTTClient SENSOR_UPDATE_TIME = 1.0 diff --git a/moonraker/components/simplyprint.py b/moonraker/components/simplyprint.py index a629ee6..b8f5983 100644 --- a/moonraker/components/simplyprint.py +++ b/moonraker/components/simplyprint.py @@ -18,7 +18,7 @@ import logging.handlers import tempfile from queue import SimpleQueue from ..loghelper import LocalQueueHandler -from ..websockets import Subscribable, WebRequest +from ..common import Subscribable, WebRequest from typing import ( TYPE_CHECKING, diff --git a/moonraker/components/update_manager/update_manager.py b/moonraker/components/update_manager/update_manager.py index 2725b85..d335930 100644 --- a/moonraker/components/update_manager/update_manager.py +++ b/moonraker/components/update_manager/update_manager.py @@ -39,7 +39,7 @@ from typing import ( if TYPE_CHECKING: from ...server import Server from ...confighelper import ConfigHelper - from ...websockets import WebRequest + from ...common import WebRequest from ...klippy_connection import KlippyConnection from ..shell_command import ShellCommandFactory as SCMDComp from ..database import MoonrakerDatabase as DBComp diff --git a/moonraker/components/webcam.py b/moonraker/components/webcam.py index 4a09f2a..f0a8d21 100644 --- a/moonraker/components/webcam.py +++ b/moonraker/components/webcam.py @@ -22,7 +22,7 @@ from typing import ( if TYPE_CHECKING: from ..server import Server from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest from .database import MoonrakerDatabase from .machine import Machine from .shell_command import ShellCommandFactory diff --git a/moonraker/components/wled.py b/moonraker/components/wled.py index 439ddf9..d0b4487 100644 --- a/moonraker/components/wled.py +++ b/moonraker/components/wled.py @@ -29,7 +29,7 @@ from typing import ( if TYPE_CHECKING: from ..confighelper import ConfigHelper - from ..websockets import WebRequest + from ..common import WebRequest class OnOff(str, Enum): on: str = "on" diff --git a/moonraker/klippy_connection.py b/moonraker/klippy_connection.py index ff75b85..fd52ab3 100644 --- a/moonraker/klippy_connection.py +++ b/moonraker/klippy_connection.py @@ -31,7 +31,7 @@ from typing import ( if TYPE_CHECKING: from .server import Server from .app import MoonrakerApp - from .websockets import WebRequest, Subscribable + from .common import WebRequest, Subscribable from .confighelper import ConfigHelper from .components.klippy_apis import KlippyAPI from .components.file_manager.file_manager import FileManager diff --git a/moonraker/loghelper.py b/moonraker/loghelper.py index d3b49c0..337ef8d 100644 --- a/moonraker/loghelper.py +++ b/moonraker/loghelper.py @@ -24,7 +24,7 @@ from typing import ( if TYPE_CHECKING: from .server import Server - from .websockets import WebRequest + from .common import WebRequest from .klippy_connection import KlippyConnection # Coroutine friendly QueueHandler courtesy of Martjin Pieters: diff --git a/moonraker/server.py b/moonraker/server.py index 6635036..3d93322 100755 --- a/moonraker/server.py +++ b/moonraker/server.py @@ -38,7 +38,8 @@ from typing import ( TypeVar, ) if TYPE_CHECKING: - from .websockets import WebRequest, WebsocketManager + from .common import WebRequest + from .websockets import WebsocketManager from .components.file_manager.file_manager import FileManager from .components.machine import Machine from .components.extensions import ExtensionManager diff --git a/moonraker/websockets.py b/moonraker/websockets.py index 9c8053c..93c99ea 100644 --- a/moonraker/websockets.py +++ b/moonraker/websockets.py @@ -12,6 +12,7 @@ import asyncio import copy from tornado.websocket import WebSocketHandler, WebSocketClosedError from tornado.web import HTTPError +from .common import WebRequest, Subscribable, APITransport, APIDefinition from .utils import ServerError, Sentinel # Annotation imports @@ -23,20 +24,16 @@ from typing import ( Callable, Coroutine, Tuple, - Type, - TypeVar, Union, Dict, List, ) + if TYPE_CHECKING: from .server import Server - from .app import APIDefinition from .klippy_connection import KlippyConnection as Klippy from .components.extensions import ExtensionManager from .components.authorization import Authorization - _T = TypeVar("_T") - _C = TypeVar("_C", str, bool, float, int) IPUnion = Union[ipaddress.IPv4Address, ipaddress.IPv6Address] ConvType = Union[str, bool, float, int] ArgVal = Union[None, int, float, bool, str] @@ -45,115 +42,6 @@ if TYPE_CHECKING: CLIENT_TYPES = ["web", "mobile", "desktop", "display", "bot", "agent", "other"] -class Subscribable: - def send_status(self, - status: Dict[str, Any], - eventtime: float - ) -> None: - raise NotImplementedError - -class WebRequest: - def __init__(self, - endpoint: str, - args: Dict[str, Any], - action: Optional[str] = "", - conn: Optional[Subscribable] = None, - ip_addr: str = "", - user: Optional[Dict[str, Any]] = None - ) -> None: - self.endpoint = endpoint - self.action = action or "" - self.args = args - self.conn = conn - self.ip_addr: Optional[IPUnion] = None - try: - self.ip_addr = ipaddress.ip_address(ip_addr) - except Exception: - self.ip_addr = None - self.current_user = user - - def get_endpoint(self) -> str: - return self.endpoint - - def get_action(self) -> str: - return self.action - - def get_args(self) -> Dict[str, Any]: - return self.args - - def get_subscribable(self) -> Optional[Subscribable]: - return self.conn - - def get_client_connection(self) -> Optional[BaseSocketClient]: - if isinstance(self.conn, BaseSocketClient): - return self.conn - return None - - def get_ip_address(self) -> Optional[IPUnion]: - return self.ip_addr - - def get_current_user(self) -> Optional[Dict[str, Any]]: - return self.current_user - - def _get_converted_arg(self, - key: str, - default: Union[Sentinel, _T], - dtype: Type[_C] - ) -> Union[_C, _T]: - if key not in self.args: - if default is Sentinel.MISSING: - raise ServerError(f"No data for argument: {key}") - return default - val = self.args[key] - try: - if dtype is not bool: - return dtype(val) - else: - if isinstance(val, str): - val = val.lower() - if val in ["true", "false"]: - return True if val == "true" else False # type: ignore - elif isinstance(val, bool): - return val # type: ignore - raise TypeError - except Exception: - raise ServerError( - f"Unable to convert argument [{key}] to {dtype}: " - f"value recieved: {val}") - - def get(self, - key: str, - default: Union[Sentinel, _T] = Sentinel.MISSING - ) -> Union[_T, Any]: - val = self.args.get(key, default) - if val is Sentinel.MISSING: - raise ServerError(f"No data for argument: {key}") - return val - - def get_str(self, - key: str, - default: Union[Sentinel, _T] = Sentinel.MISSING - ) -> Union[str, _T]: - return self._get_converted_arg(key, default, str) - - def get_int(self, - key: str, - default: Union[Sentinel, _T] = Sentinel.MISSING - ) -> Union[int, _T]: - return self._get_converted_arg(key, default, int) - - def get_float(self, - key: str, - default: Union[Sentinel, _T] = Sentinel.MISSING - ) -> Union[float, _T]: - return self._get_converted_arg(key, default, float) - - def get_boolean(self, - key: str, - default: Union[Sentinel, _T] = Sentinel.MISSING - ) -> Union[bool, _T]: - return self._get_converted_arg(key, default, bool) - class JsonRPC: def __init__( self, server: Server, transport: str = "Websocket" @@ -339,13 +227,6 @@ class JsonRPC: 'id': req_id } -class APITransport: - def register_api_handler(self, api_def: APIDefinition) -> None: - raise NotImplementedError - - def remove_api_handler(self, api_def: APIDefinition) -> None: - raise NotImplementedError - class WebsocketManager(APITransport): def __init__(self, server: Server) -> None: self.server = server