diff options
author | Devaev Maxim <[email protected]> | 2020-06-06 06:29:29 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2020-06-06 06:29:29 +0300 |
commit | 1d7d4100a57b5d654c1434c91e97187fe25698ef (patch) | |
tree | d4709afc3fa03ceac99f1880726ef8639845702d /kvmd | |
parent | 4f3ebf0fd1100d2076a626d9ae39f414e9adf90b (diff) |
common component interface
Diffstat (limited to 'kvmd')
-rw-r--r-- | kvmd/apps/kvmd/api/atx.py | 2 | ||||
-rw-r--r-- | kvmd/apps/kvmd/api/wol.py | 2 | ||||
-rw-r--r-- | kvmd/apps/kvmd/server.py | 88 | ||||
-rw-r--r-- | kvmd/apps/kvmd/wol.py | 2 | ||||
-rw-r--r-- | kvmd/plugins/atx/__init__.py | 2 | ||||
-rw-r--r-- | kvmd/plugins/atx/disabled.py | 4 | ||||
-rw-r--r-- | kvmd/plugins/atx/gpio.py | 15 |
7 files changed, 61 insertions, 54 deletions
diff --git a/kvmd/apps/kvmd/api/atx.py b/kvmd/apps/kvmd/api/atx.py index f4317c3c..5f1fb154 100644 --- a/kvmd/apps/kvmd/api/atx.py +++ b/kvmd/apps/kvmd/api/atx.py @@ -41,7 +41,7 @@ class AtxApi: @exposed_http("GET", "/atx") async def __state_handler(self, _: Request) -> Response: - return make_json_response(self.__atx.get_state()) + return make_json_response(await self.__atx.get_state()) @exposed_http("POST", "/atx/power") async def __power_handler(self, request: Request) -> Response: diff --git a/kvmd/apps/kvmd/api/wol.py b/kvmd/apps/kvmd/api/wol.py index 195cf640..b9aa74f6 100644 --- a/kvmd/apps/kvmd/api/wol.py +++ b/kvmd/apps/kvmd/api/wol.py @@ -38,7 +38,7 @@ class WolApi: @exposed_http("GET", "/wol") async def __state_handler(self, _: Request) -> Response: - return make_json_response(self.__wol.get_state()) + return make_json_response(await self.__wol.get_state()) @exposed_http("POST", "/wol/wakeup") async def __wakeup_handler(self, _: Request) -> Response: diff --git a/kvmd/apps/kvmd/server.py b/kvmd/apps/kvmd/server.py index aa4cd83b..da431754 100644 --- a/kvmd/apps/kvmd/server.py +++ b/kvmd/apps/kvmd/server.py @@ -23,14 +23,14 @@ import os import signal import asyncio +import dataclasses import json -from enum import Enum - from typing import List from typing import Dict from typing import Set from typing import Callable +from typing import Coroutine from typing import AsyncGenerator from typing import Optional from typing import Any @@ -86,13 +86,23 @@ from .api.streamer import StreamerApi # ===== -class _Events(Enum): - INFO_STATE = "info_state" - WOL_STATE = "wol_state" - HID_STATE = "hid_state" - ATX_STATE = "atx_state" - MSD_STATE = "msd_state" - STREAMER_STATE = "streamer_state" [email protected](frozen=True) +class _Component: + name: str + event_type: str + obj: object + get_state: Optional[Callable[[], Coroutine[Any, Any, Dict]]] = None + poll_state: Optional[Callable[[], AsyncGenerator[Dict, None]]] = None + cleanup: Optional[Callable[[], Coroutine[Any, Any, Dict]]] = None + + def __post_init__(self) -> None: + if isinstance(self.obj, BasePlugin): + object.__setattr__(self, "name", f"{self.name} ({self.obj.get_plugin_name()})") + + for field in ["get_state", "poll_state", "cleanup"]: + object.__setattr__(self, field, getattr(self.obj, field, None)) + if self.get_state or self.poll_state: + assert self.event_type, self class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-instance-attributes @@ -115,16 +125,21 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins ) -> None: self.__auth_manager = auth_manager - self.__info_manager = info_manager - self.__wol = wol - self.__hid = hid - self.__atx = atx - self.__msd = msd self.__streamer = streamer self.__heartbeat = heartbeat + self.__components = [ + _Component("Auth manager", "", auth_manager), + _Component("Info manager", "info_state", info_manager), + _Component("Wake-on-LAN", "wol_state", wol), + _Component("HID", "hid_state", hid), + _Component("ATX", "atx_state", atx), + _Component("MSD", "msd_state", msd), + _Component("Streamer", "streamer_state", streamer), + ] + self.__apis: List[object] = [ self, AuthApi(auth_manager), @@ -180,12 +195,9 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins await self.__register_socket(ws) try: await asyncio.gather(*[ - self.__broadcast_event(_Events.INFO_STATE, (await self.__info_manager.get_state())), - self.__broadcast_event(_Events.WOL_STATE, self.__wol.get_state()), - self.__broadcast_event(_Events.HID_STATE, (await self.__hid.get_state())), - self.__broadcast_event(_Events.ATX_STATE, self.__atx.get_state()), - self.__broadcast_event(_Events.MSD_STATE, (await self.__msd.get_state())), - self.__broadcast_event(_Events.STREAMER_STATE, (await self.__streamer.get_state())), + self.__broadcast_event(component.event_type, await component.get_state()) + for component in self.__components + if component.get_state ]) async for msg in ws: if msg.type == aiohttp.web.WSMsgType.TEXT: @@ -224,10 +236,9 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins app.on_cleanup.append(self.__on_cleanup) self.__run_system_task(self.__stream_controller) - self.__run_system_task(self.__poll_state, _Events.HID_STATE, self.__hid.poll_state()) - self.__run_system_task(self.__poll_state, _Events.ATX_STATE, self.__atx.poll_state()) - self.__run_system_task(self.__poll_state, _Events.MSD_STATE, self.__msd.poll_state()) - self.__run_system_task(self.__poll_state, _Events.STREAMER_STATE, self.__streamer.poll_state()) + for component in self.__components: + if component.poll_state: + self.__run_system_task(self.__poll_state, component.event_type, component.poll_state()) for api in self.__apis: for http_exposed in get_exposed_http(api): @@ -282,26 +293,19 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins async def __on_cleanup(self, _: aiohttp.web.Application) -> None: logger = get_logger(0) - for (name, obj) in [ - ("Auth manager", self.__auth_manager), - ("Streamer", self.__streamer), - ("MSD", self.__msd), - ("ATX", self.__atx), - ("HID", self.__hid), - ]: - if isinstance(obj, BasePlugin): - name = f"{name} ({obj.get_plugin_name()})" - logger.info("Cleaning up %s ...", name) - try: - await obj.cleanup() # type: ignore - except Exception: - logger.exception("Cleanup error on %s", name) - - async def __broadcast_event(self, event_type: _Events, event: Dict) -> None: + for component in self.__components: + if component.cleanup: + logger.info("Cleaning up %s ...", component.name) + try: + await component.cleanup() # type: ignore + except Exception: + logger.exception("Cleanup error on %s", component.name) + + async def __broadcast_event(self, event_type: str, event: Dict) -> None: if self.__sockets: await asyncio.gather(*[ ws.send_str(json.dumps({ - "event_type": event_type.value, + "event_type": event_type, "event": event, })) for ws in list(self.__sockets) @@ -351,6 +355,6 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins prev = cur await self.__streamer_notifier.wait() - async def __poll_state(self, event_type: _Events, poller: AsyncGenerator[Dict, None]) -> None: + async def __poll_state(self, event_type: str, poller: AsyncGenerator[Dict, None]) -> None: async for state in poller: await self.__broadcast_event(event_type, state) diff --git a/kvmd/apps/kvmd/wol.py b/kvmd/apps/kvmd/wol.py index f388f136..672b9ef6 100644 --- a/kvmd/apps/kvmd/wol.py +++ b/kvmd/apps/kvmd/wol.py @@ -50,7 +50,7 @@ class WakeOnLan: assert len(mac) == 17, mac self.__magic = bytes.fromhex("FF" * 6 + mac.replace(":", "") * 16) - def get_state(self) -> Dict: + async def get_state(self) -> Dict: return { "enabled": bool(self.__magic), "target": { diff --git a/kvmd/plugins/atx/__init__.py b/kvmd/plugins/atx/__init__.py index b536ef87..bc0c2c41 100644 --- a/kvmd/plugins/atx/__init__.py +++ b/kvmd/plugins/atx/__init__.py @@ -47,7 +47,7 @@ class AtxIsBusyError(IsBusyError, AtxError): # ===== class BaseAtx(BasePlugin): - def get_state(self) -> Dict: + async def get_state(self) -> Dict: raise NotImplementedError async def poll_state(self) -> AsyncGenerator[Dict, None]: diff --git a/kvmd/plugins/atx/disabled.py b/kvmd/plugins/atx/disabled.py index d480a337..93cfbb5b 100644 --- a/kvmd/plugins/atx/disabled.py +++ b/kvmd/plugins/atx/disabled.py @@ -37,7 +37,7 @@ class AtxDisabledError(AtxOperationError): # ===== class Plugin(BaseAtx): - def get_state(self) -> Dict: + async def get_state(self) -> Dict: return { "enabled": False, "busy": False, @@ -49,7 +49,7 @@ class Plugin(BaseAtx): async def poll_state(self) -> AsyncGenerator[Dict, None]: while True: - yield self.get_state() + yield (await self.get_state()) await aiotools.wait_infinite() # ===== diff --git a/kvmd/plugins/atx/gpio.py b/kvmd/plugins/atx/gpio.py index 0ed29b49..2631faec 100644 --- a/kvmd/plugins/atx/gpio.py +++ b/kvmd/plugins/atx/gpio.py @@ -92,7 +92,7 @@ class Plugin(BaseAtx): # pylint: disable=too-many-instance-attributes "state_poll": Option(0.1, type=valid_float_f01), } - def get_state(self) -> Dict: + async def get_state(self) -> Dict: return { "enabled": True, "busy": self.__region.is_busy(), @@ -105,7 +105,7 @@ class Plugin(BaseAtx): # pylint: disable=too-many-instance-attributes async def poll_state(self) -> AsyncGenerator[Dict, None]: prev_state: Dict = {} while True: - state = self.get_state() + state = await self.get_state() if state != prev_state: yield state prev_state = state @@ -124,25 +124,25 @@ class Plugin(BaseAtx): # pylint: disable=too-many-instance-attributes # ===== async def power_on(self) -> bool: - if not self.get_state()["leds"]["power"]: + if not (await self.__get_power()): await self.click_power() return True return False async def power_off(self) -> bool: - if self.get_state()["leds"]["power"]: + if (await self.__get_power()): await self.click_power() return True return False async def power_off_hard(self) -> bool: - if self.get_state()["leds"]["power"]: + if (await self.__get_power()): await self.click_power_long() return True return False async def power_reset_hard(self) -> bool: - if self.get_state()["leds"]["power"]: + if (await self.__get_power()): await self.click_reset() return True return False @@ -160,6 +160,9 @@ class Plugin(BaseAtx): # pylint: disable=too-many-instance-attributes # ===== + async def __get_power(self) -> bool: + return (await self.get_state())["leds"]["power"] + @aiotools.atomic async def __click(self, name: str, pin: int, delay: float) -> None: await aiotools.run_region_task( |