mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
common component interface
This commit is contained in:
parent
4f3ebf0fd1
commit
1d7d4100a5
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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"
|
||||
@dataclasses.dataclass(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)
|
||||
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: _Events, event: Dict) -> None:
|
||||
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)
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -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]:
|
||||
|
||||
@ -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()
|
||||
|
||||
# =====
|
||||
|
||||
@ -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(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user