summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kvmd/apps/kvmd/api/atx.py2
-rw-r--r--kvmd/apps/kvmd/api/wol.py2
-rw-r--r--kvmd/apps/kvmd/server.py88
-rw-r--r--kvmd/apps/kvmd/wol.py2
-rw-r--r--kvmd/plugins/atx/__init__.py2
-rw-r--r--kvmd/plugins/atx/disabled.py4
-rw-r--r--kvmd/plugins/atx/gpio.py15
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(