diff options
author | Devaev Maxim <[email protected]> | 2019-02-15 07:20:26 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2019-02-15 07:20:26 +0300 |
commit | 7d79f48fd87083ffe38158fc456cad4737ab0242 (patch) | |
tree | 22e48f8102068e13b4680a34d0e97b7d624abfd2 /kvmd | |
parent | cdddf10b5d2e4a87d8a4276e197e828f89e12be5 (diff) |
big config refactoring
Diffstat (limited to 'kvmd')
-rw-r--r-- | kvmd/apps/__init__.py | 120 | ||||
-rw-r--r-- | kvmd/apps/kvmd/__init__.py | 101 | ||||
-rw-r--r-- | kvmd/apps/kvmd/atx.py | 27 | ||||
-rw-r--r-- | kvmd/apps/kvmd/hid.py | 10 | ||||
-rw-r--r-- | kvmd/apps/kvmd/msd.py | 22 | ||||
-rw-r--r-- | kvmd/apps/kvmd/server.py | 33 | ||||
-rw-r--r-- | kvmd/apps/kvmd/streamer.py | 18 | ||||
-rw-r--r-- | kvmd/yamlconf/__init__.py | 44 |
8 files changed, 157 insertions, 218 deletions
diff --git a/kvmd/apps/__init__.py b/kvmd/apps/__init__.py index 0c5e64c9..fa10b948 100644 --- a/kvmd/apps/__init__.py +++ b/kvmd/apps/__init__.py @@ -111,87 +111,83 @@ def _get_config_scheme() -> Dict: return { "kvmd": { "server": { - "host": Option(default="localhost"), - "port": Option(default=0), - "unix": Option(default="", type=_as_optional_path), - "unix_rm": Option(default=False), - "unix_mode": Option(default=0), - "heartbeat": Option(default=3.0), - "access_log_format": Option(default="[%P / %{X-Real-IP}i] '%r' => %s; size=%b ---" - " referer='%{Referer}i'; user_agent='%{User-Agent}i'"), + "host": Option("localhost"), + "port": Option(0), + "unix": Option("", type=_as_optional_path, rename="unix_path"), + "unix_rm": Option(False), + "unix_mode": Option(0), + "heartbeat": Option(3.0), + "access_log_format": Option("[%P / %{X-Real-IP}i] '%r' => %s; size=%b ---" + " referer='%{Referer}i'; user_agent='%{User-Agent}i'"), }, "auth": { - "htpasswd": Option(default="/etc/kvmd/htpasswd", type=_as_path), + "htpasswd": Option("/etc/kvmd/htpasswd", type=_as_path, rename="htpasswd_path"), }, "info": { - "meta": Option(default="/etc/kvmd/meta.yaml", type=_as_path), - "extras": Option(default="/usr/share/kvmd/extras", type=_as_path), + "meta": Option("/etc/kvmd/meta.yaml", type=_as_path, rename="meta_path"), + "extras": Option("/usr/share/kvmd/extras", type=_as_path, rename="extras_path"), }, "hid": { - "pinout": { - "reset": Option(default=0, type=_as_pin), - }, - "reset_delay": Option(default=0.1), - "device": Option(default="", type=_as_path), - "speed": Option(default=115200), - "read_timeout": Option(default=2.0), - "read_retries": Option(default=10), - "common_retries": Option(default=100), - "retries_delay": Option(default=0.1), - "noop": Option(default=False), - "state_poll": Option(default=0.1), + "reset_pin": Option(0, type=_as_pin), + "reset_delay": Option(0.1), + + "device": Option("", type=_as_path, rename="device_path"), + "speed": Option(115200), + "read_timeout": Option(2.0), + "read_retries": Option(10), + "common_retries": Option(100), + "retries_delay": Option(0.1), + "noop": Option(False), + + "state_poll": Option(0.1), }, "atx": { - "pinout": { - "power_led": Option(default=0, type=_as_pin), - "hdd_led": Option(default=0, type=_as_pin), - "power_switch": Option(default=0, type=_as_pin), - "reset_switch": Option(default=0, type=_as_pin), - }, - "click_delay": Option(default=0.1), - "long_click_delay": Option(default=5.5), - "state_poll": Option(default=0.1), + "power_led_pin": Option(0, type=_as_pin), + "hdd_led_pin": Option(0, type=_as_pin), + + "power_switch_pin": Option(0, type=_as_pin), + "reset_switch_pin": Option(0, type=_as_pin), + "click_delay": Option(0.1), + "long_click_delay": Option(5.5), + + "state_poll": Option(0.1), }, "msd": { - "pinout": { - "target": Option(default=0, type=_as_pin), - "reset": Option(default=0, type=_as_pin), - }, - "device": Option(default="", type=_as_path), - "init_delay": Option(default=2.0), - "reset_delay": Option(default=1.0), - "write_meta": Option(default=True), - "chunk_size": Option(default=65536), + "target_pin": Option(0, type=_as_pin), + "reset_pin": Option(0, type=_as_pin), + "device": Option("", type=_as_path, rename="device_path"), + "init_delay": Option(2.0), + "reset_delay": Option(1.0), + "write_meta": Option(True), + "chunk_size": Option(65536), }, "streamer": { - "pinout": { - "cap": Option(default=-1, type=_as_optional_pin), - "conv": Option(default=-1, type=_as_optional_pin), - }, - - "sync_delay": Option(default=1.0), - "init_delay": Option(default=1.0), - "init_restart_after": Option(default=0.0), - "shutdown_delay": Option(default=10.0), - "state_poll": Option(default=1.0), - - "quality": Option(default=80), - "desired_fps": Option(default=0), - - "host": Option(default="localhost"), - "port": Option(default=0), - "unix": Option(default="", type=_as_optional_path), - "timeout": Option(default=2.0), - - "cmd": Option(default=["/bin/true"], type=_as_string_list), + "cap_pin": Option(-1, type=_as_optional_pin), + "conv_pin": Option(-1, type=_as_optional_pin), + + "sync_delay": Option(1.0), + "init_delay": Option(1.0), + "init_restart_after": Option(0.0), + "shutdown_delay": Option(10.0), + "state_poll": Option(1.0), + + "quality": Option(80), + "desired_fps": Option(0), + + "host": Option("localhost"), + "port": Option(0), + "unix": Option("", type=_as_optional_path, rename="unix_path"), + "timeout": Option(2.0), + + "cmd": Option(["/bin/true"], type=_as_string_list), }, }, - "logging": Option(default={}), + "logging": Option({}), } diff --git a/kvmd/apps/kvmd/__init__.py b/kvmd/apps/kvmd/__init__.py index 2628b735..a78bdb97 100644 --- a/kvmd/apps/kvmd/__init__.py +++ b/kvmd/apps/kvmd/__init__.py @@ -20,101 +20,18 @@ from .server import Server def main() -> None: config = init("kvmd", description="The main Pi-KVM daemon")[2].kvmd with gpio.bcm(): + # pylint: disable=protected-access loop = asyncio.get_event_loop() - - auth_manager = AuthManager( - htpasswd_path=config.auth.htpasswd, - ) - - info_manager = InfoManager( - meta_path=config.info.meta, - extras_path=config.info.extras, - loop=loop, - ) - - log_reader = LogReader(loop) - - hid = Hid( - reset=config.hid.pinout.reset, - reset_delay=config.hid.reset_delay, - - device_path=config.hid.device, - speed=config.hid.speed, - read_timeout=config.hid.read_timeout, - read_retries=config.hid.read_retries, - common_retries=config.hid.common_retries, - retries_delay=config.hid.retries_delay, - noop=config.hid.noop, - - state_poll=config.hid.state_poll, - ) - - atx = Atx( - power_led=config.atx.pinout.power_led, - hdd_led=config.atx.pinout.hdd_led, - power_switch=config.atx.pinout.power_switch, - reset_switch=config.atx.pinout.reset_switch, - - click_delay=config.atx.click_delay, - long_click_delay=config.atx.long_click_delay, - state_poll=config.atx.state_poll, - ) - - msd = MassStorageDevice( - target=config.msd.pinout.target, - reset=config.msd.pinout.reset, - - device_path=config.msd.device, - init_delay=config.msd.init_delay, - reset_delay=config.msd.reset_delay, - write_meta=config.msd.write_meta, - - loop=loop, - ) - - streamer = Streamer( - cap_power=config.streamer.pinout.cap, - conv_power=config.streamer.pinout.conv, - sync_delay=config.streamer.sync_delay, - init_delay=config.streamer.init_delay, - init_restart_after=config.streamer.init_restart_after, - state_poll=config.streamer.state_poll, - - quality=config.streamer.quality, - desired_fps=config.streamer.desired_fps, - - host=config.streamer.host, - port=config.streamer.port, - unix_path=config.streamer.unix, - timeout=config.streamer.timeout, - - cmd=config.streamer.cmd, - - loop=loop, - ) - Server( - auth_manager=auth_manager, - info_manager=info_manager, - log_reader=log_reader, + auth_manager=AuthManager(**config.auth._unpack_renamed()), + info_manager=InfoManager(loop=loop, **config.info._unpack_renamed()), + log_reader=LogReader(loop=loop), - hid=hid, - atx=atx, - msd=msd, - streamer=streamer, - - access_log_format=config.server.access_log_format, - heartbeat=config.server.heartbeat, - streamer_shutdown_delay=config.streamer.shutdown_delay, - msd_chunk_size=config.msd.chunk_size, + hid=Hid(**config.hid._unpack_renamed()), + atx=Atx(**config.atx._unpack_renamed()), + msd=MassStorageDevice(loop=loop, **config.msd._unpack_renamed()), + streamer=Streamer(loop=loop, **config.streamer._unpack_renamed()), loop=loop, - ).run( - host=config.server.host, - port=config.server.port, - unix_path=config.server.unix, - unix_rm=config.server.unix_rm, - unix_mode=config.server.unix_mode, - ) - + ).run(**config.server._unpack_renamed()) get_logger().info("Bye-bye") diff --git a/kvmd/apps/kvmd/atx.py b/kvmd/apps/kvmd/atx.py index 34b08896..8bc34260 100644 --- a/kvmd/apps/kvmd/atx.py +++ b/kvmd/apps/kvmd/atx.py @@ -17,21 +17,22 @@ class AtxIsBusy(aioregion.RegionIsBusyError): class Atx: # pylint: disable=too-many-instance-attributes def __init__( self, - power_led: int, - hdd_led: int, - power_switch: int, - reset_switch: int, + power_led_pin: int, + hdd_led_pin: int, + power_switch_pin: int, + reset_switch_pin: int, click_delay: float, long_click_delay: float, + state_poll: float, ) -> None: - self.__power_led = gpio.set_input(power_led) - self.__hdd_led = gpio.set_input(hdd_led) + self.__power_led_pin = gpio.set_input(power_led_pin) + self.__hdd_led_pin = gpio.set_input(hdd_led_pin) - self.__power_switch = gpio.set_output(power_switch) - self.__reset_switch = gpio.set_output(reset_switch) + self.__power_switch_pin = gpio.set_output(power_switch_pin) + self.__reset_switch_pin = gpio.set_output(reset_switch_pin) self.__click_delay = click_delay self.__long_click_delay = long_click_delay @@ -43,8 +44,8 @@ class Atx: # pylint: disable=too-many-instance-attributes return { "busy": self.__region.is_busy(), "leds": { - "power": (not gpio.read(self.__power_led)), - "hdd": (not gpio.read(self.__hdd_led)), + "power": (not gpio.read(self.__power_led_pin)), + "hdd": (not gpio.read(self.__hdd_led_pin)), }, } @@ -55,15 +56,15 @@ class Atx: # pylint: disable=too-many-instance-attributes async def click_power(self) -> None: get_logger().info("Clicking power ...") - await self.__click(self.__power_switch, self.__click_delay) + await self.__click(self.__power_switch_pin, self.__click_delay) async def click_power_long(self) -> None: get_logger().info("Clicking power (long press) ...") - await self.__click(self.__power_switch, self.__long_click_delay) + await self.__click(self.__power_switch_pin, self.__long_click_delay) async def click_reset(self) -> None: get_logger().info("Clicking reset") - await self.__click(self.__reset_switch, self.__click_delay) + await self.__click(self.__reset_switch_pin, self.__click_delay) async def __click(self, pin: int, delay: float) -> None: self.__region.enter() diff --git a/kvmd/apps/kvmd/hid.py b/kvmd/apps/kvmd/hid.py index b1b10422..2ed148f0 100644 --- a/kvmd/apps/kvmd/hid.py +++ b/kvmd/apps/kvmd/hid.py @@ -85,7 +85,7 @@ class _MouseWheelEvent(NamedTuple): class Hid(multiprocessing.Process): # pylint: disable=too-many-instance-attributes def __init__( # pylint: disable=too-many-arguments self, - reset: int, + reset_pin: int, reset_delay: float, device_path: str, @@ -101,7 +101,7 @@ class Hid(multiprocessing.Process): # pylint: disable=too-many-instance-attribu super().__init__(daemon=True) - self.__reset = gpio.set_output(reset) + self.__reset_pin = gpio.set_output(reset_pin) self.__reset_delay = reset_delay self.__device_path = device_path @@ -137,9 +137,9 @@ class Hid(multiprocessing.Process): # pylint: disable=too-many-instance-attribu async def reset(self) -> None: async with self.__lock: - gpio.write(self.__reset, True) + gpio.write(self.__reset_pin, True) await asyncio.sleep(self.__reset_delay) - gpio.write(self.__reset, False) + gpio.write(self.__reset_pin, False) async def send_key_event(self, key: str, state: bool) -> None: if not self.__stop_event.is_set(): @@ -188,7 +188,7 @@ class Hid(multiprocessing.Process): # pylint: disable=too-many-instance-attribu else: get_logger().warning("Emergency cleaning up HID events ...") self.__emergency_clear_events() - gpio.write(self.__reset, False) + gpio.write(self.__reset_pin, False) def __unsafe_clear_events(self) -> None: for button in self.__pressed_mouse_buttons: diff --git a/kvmd/apps/kvmd/msd.py b/kvmd/apps/kvmd/msd.py index 79295109..5d029487 100644 --- a/kvmd/apps/kvmd/msd.py +++ b/kvmd/apps/kvmd/msd.py @@ -167,24 +167,26 @@ def _msd_operated(method: Callable) -> Callable: class MassStorageDevice: # pylint: disable=too-many-instance-attributes def __init__( self, - target: int, - reset: int, + target_pin: int, + reset_pin: int, device_path: str, init_delay: float, reset_delay: float, write_meta: bool, + chunk_size: int, loop: asyncio.AbstractEventLoop, ) -> None: - self.__target = gpio.set_output(target) - self.__reset = gpio.set_output(reset) + self.__target_pin = gpio.set_output(target_pin) + self.__reset_pin = gpio.set_output(reset_pin) self._device_path = device_path self.__init_delay = init_delay self.__reset_delay = reset_delay self.__write_meta = write_meta + self.chunk_size = chunk_size self.__loop = loop @@ -236,15 +238,15 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes async def cleanup(self) -> None: await self.__close_device_file() - gpio.write(self.__target, False) - gpio.write(self.__reset, False) + gpio.write(self.__target_pin, False) + gpio.write(self.__reset_pin, False) @_msd_operated async def connect_to_kvm(self, no_delay: bool=False) -> Dict: with self.__region: if self.__device_info: raise MsdAlreadyConnectedToKvmError() - gpio.write(self.__target, False) + gpio.write(self.__target_pin, False) if not no_delay: await asyncio.sleep(self.__init_delay) await self.__load_device_info() @@ -258,7 +260,7 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes with self.__region: if not self.__device_info: raise MsdAlreadyConnectedToPcError() - gpio.write(self.__target, True) + gpio.write(self.__target_pin, True) self.__device_info = None state = self.get_state() await self.__state_queue.put(state) @@ -269,9 +271,9 @@ class MassStorageDevice: # pylint: disable=too-many-instance-attributes async def reset(self) -> None: with self.__region: get_logger().info("Mass-storage device reset") - gpio.write(self.__reset, True) + gpio.write(self.__reset_pin, True) await asyncio.sleep(self.__reset_delay) - gpio.write(self.__reset, False) + gpio.write(self.__reset_pin, False) await self.__state_queue.put(self.get_state()) @_msd_operated diff --git a/kvmd/apps/kvmd/server.py b/kvmd/apps/kvmd/server.py index 37e6ca5b..7049ba32 100644 --- a/kvmd/apps/kvmd/server.py +++ b/kvmd/apps/kvmd/server.py @@ -209,7 +209,7 @@ class _Events(Enum): class Server: # pylint: disable=too-many-instance-attributes - def __init__( # pylint: disable=too-many-arguments + def __init__( self, auth_manager: AuthManager, info_manager: InfoManager, @@ -220,11 +220,6 @@ class Server: # pylint: disable=too-many-instance-attributes msd: MassStorageDevice, streamer: Streamer, - access_log_format: str, - heartbeat: float, - streamer_shutdown_delay: float, - msd_chunk_size: int, - loop: asyncio.AbstractEventLoop, ) -> None: @@ -237,13 +232,9 @@ class Server: # pylint: disable=too-many-instance-attributes self.__msd = msd self.__streamer = streamer - self.__access_log_format = access_log_format - self.__heartbeat = heartbeat - self.__streamer_shutdown_delay = streamer_shutdown_delay - self.__msd_chunk_size = msd_chunk_size - self.__loop = loop + self.__heartbeat: Optional[float] = None # Assigned in run() for consistance self.__sockets: Set[aiohttp.web.WebSocketResponse] = set() self.__sockets_lock = asyncio.Lock() @@ -252,11 +243,22 @@ class Server: # pylint: disable=too-many-instance-attributes self.__reset_streamer = False self.__streamer_params = streamer.get_params() - def run(self, host: str, port: int, unix_path: str, unix_rm: bool, unix_mode: int) -> None: + def run( + self, + host: str, + port: int, + unix_path: str, + unix_rm: bool, + unix_mode: int, + heartbeat: float, + access_log_format: str, + ) -> None: + self.__hid.start() setproctitle.setproctitle("[main] " + setproctitle.getproctitle()) + self.__heartbeat = heartbeat app = aiohttp.web.Application(loop=self.__loop) app.on_shutdown.append(self.__on_shutdown) app.on_cleanup.append(self.__on_cleanup) @@ -290,7 +292,7 @@ class Server: # pylint: disable=too-many-instance-attributes aiohttp.web.run_app( app=app, - access_log_format=self.__access_log_format, + access_log_format=access_log_format, print=self.__run_app_print, **socket_kwargs, ) @@ -354,6 +356,7 @@ class Server: # pylint: disable=too-many-instance-attributes @_exposed("GET", "/ws") async def __ws_handler(self, request: aiohttp.web.Request) -> aiohttp.web.WebSocketResponse: logger = get_logger(0) + assert self.__heartbeat is not None ws = aiohttp.web.WebSocketResponse(heartbeat=self.__heartbeat) await ws.prepare(request) await self.__register_socket(ws) @@ -476,7 +479,7 @@ class Server: # pylint: disable=too-many-instance-attributes logger.info("Writing image %r to mass-storage device ...", image_name) await self.__msd.write_image_info(image_name, False) while True: - chunk = await field.read_chunk(self.__msd_chunk_size) + chunk = await field.read_chunk(self.__msd.chunk_size) if not chunk: break written = await self.__msd.write_image_chunk(chunk) @@ -581,7 +584,7 @@ class Server: # pylint: disable=too-many-instance-attributes if not self.__streamer.is_running(): await self.__streamer.start(self.__streamer_params) elif prev > 0 and cur == 0: - shutdown_at = time.time() + self.__streamer_shutdown_delay + shutdown_at = time.time() + self.__streamer.shutdown_delay elif prev == 0 and cur == 0 and time.time() > shutdown_at: if self.__streamer.is_running(): await self.__streamer.stop() diff --git a/kvmd/apps/kvmd/streamer.py b/kvmd/apps/kvmd/streamer.py index 7c9b2419..7e287b99 100644 --- a/kvmd/apps/kvmd/streamer.py +++ b/kvmd/apps/kvmd/streamer.py @@ -19,12 +19,13 @@ from ... import gpio class Streamer: # pylint: disable=too-many-instance-attributes def __init__( # pylint: disable=too-many-arguments,too-many-locals self, - cap_power: int, - conv_power: int, + cap_pin: int, + conv_pin: int, sync_delay: float, init_delay: float, init_restart_after: float, + shutdown_delay: float, state_poll: float, quality: int, @@ -40,12 +41,13 @@ class Streamer: # pylint: disable=too-many-instance-attributes loop: asyncio.AbstractEventLoop, ) -> None: - self.__cap_power = (gpio.set_output(cap_power) if cap_power > 0 else cap_power) - self.__conv_power = (gpio.set_output(conv_power) if conv_power > 0 else conv_power) + self.__cap_pin = (gpio.set_output(cap_pin) if cap_pin > 0 else cap_pin) + self.__conv_pin = (gpio.set_output(conv_pin) if conv_pin > 0 else conv_pin) self.__sync_delay = sync_delay self.__init_delay = init_delay self.__init_restart_after = init_restart_after + self.shutdown_delay = shutdown_delay self.__state_poll = state_poll self.__params = { @@ -155,12 +157,12 @@ class Streamer: # pylint: disable=too-many-instance-attributes async def __set_hw_enabled(self, enabled: bool) -> None: # XXX: This sequence is very important to enable converter and cap board - if self.__cap_power > 0: - gpio.write(self.__cap_power, enabled) - if self.__conv_power > 0: + if self.__cap_pin > 0: + gpio.write(self.__cap_pin, enabled) + if self.__conv_pin > 0: if enabled: await asyncio.sleep(self.__sync_delay) - gpio.write(self.__conv_power, enabled) + gpio.write(self.__conv_pin, enabled) if enabled: await asyncio.sleep(self.__init_delay) diff --git a/kvmd/yamlconf/__init__.py b/kvmd/yamlconf/__init__.py index 5dd1da3d..60be81a3 100644 --- a/kvmd/yamlconf/__init__.py +++ b/kvmd/yamlconf/__init__.py @@ -44,35 +44,52 @@ class Section(dict): dict.__init__(self) self.__meta: Dict[str, Dict[str, Any]] = {} - def _set_meta(self, name: str, default: Any, help: str) -> None: # pylint: disable=redefined-builtin - self.__meta[name] = { + def _unpack_renamed(self) -> Dict[str, Any]: + unpacked: Dict[str, Any] = {} + for (key, value) in self.items(): + assert not isinstance(value, Section), (key, value) + key = (self.__meta[key]["rename"] or key) + unpacked[key] = value + return unpacked + + def _set_meta(self, key: str, default: Any, help: str, rename: str) -> None: # pylint: disable=redefined-builtin + self.__meta[key] = { "default": default, "help": help, + "rename": rename, } - def _get_default(self, name: str) -> Any: - return self.__meta[name]["default"] + def _get_default(self, key: str) -> Any: + return self.__meta[key]["default"] - def _get_help(self, name: str) -> str: - return self.__meta[name]["help"] + def _get_help(self, key: str) -> str: + return self.__meta[key]["help"] - def __getattribute__(self, name: str) -> Any: - if name in self: - return self[name] + def __getattribute__(self, key: str) -> Any: + if key in self: + return self[key] else: # For pickling - return dict.__getattribute__(self, name) + return dict.__getattribute__(self, key) class Option: __type = type - def __init__(self, default: Any, help: str="", type: Optional[Callable[[Any], Any]]=None) -> None: # pylint: disable=redefined-builtin + def __init__( + self, + default: Any, + help: str="", # pylint: disable=redefined-builtin + type: Optional[Callable[[Any], Any]]=None, # pylint: disable=redefined-builtin + rename: str="", + ) -> None: + self.default = default self.help = help self.type: Callable[[Any], Any] = (type or (self.__type(default) if default is not None else str)) # type: ignore + self.rename = rename def __repr__(self) -> str: - return "<Option(default={self.default}, type={self.type}, help={self.help})>".format(self=self) + return "<Option(default={self.default}, type={self.type}, help={self.help}, rename={self.rename})>".format(self=self) # ===== @@ -93,9 +110,10 @@ def make_config(raw: Dict[str, Any], scheme: Dict[str, Any], _keys: Tuple[str, . raise ValueError("Invalid value '{value}' for key '{key}'".format(key=full_name, value=value)) config[key] = value config._set_meta( # pylint: disable=protected-access - name=key, + key=key, default=option.default, help=option.help, + rename=option.rename, ) elif isinstance(option, dict): config[key] = make_config(raw.get(key, {}), option, full_key) |