summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kvmd/apps/__init__.py26
-rw-r--r--kvmd/apps/kvmd/__init__.py2
-rw-r--r--kvmd/apps/kvmd/api/wol.py46
-rw-r--r--kvmd/apps/kvmd/server.py5
-rw-r--r--kvmd/plugins/ugpio/wol.py (renamed from kvmd/apps/kvmd/wol.py)87
-rw-r--r--web/kvm/index.html2
-rw-r--r--web/kvm/navbar-system.pug4
-rw-r--r--web/share/js/kvm/gpio.js1
-rw-r--r--web/share/js/kvm/session.js3
-rw-r--r--web/share/js/kvm/wol.js70
10 files changed, 80 insertions, 166 deletions
diff --git a/kvmd/apps/__init__.py b/kvmd/apps/__init__.py
index d930ed8f..5b07aae5 100644
--- a/kvmd/apps/__init__.py
+++ b/kvmd/apps/__init__.py
@@ -79,7 +79,6 @@ from ..validators.os import valid_options
from ..validators.os import valid_command
from ..validators.net import valid_ip_or_host
-from ..validators.net import valid_ip
from ..validators.net import valid_net
from ..validators.net import valid_port
from ..validators.net import valid_ports_list
@@ -183,7 +182,7 @@ def _init_config(config_path: str, override_options: List[str], **load_flags: bo
raise SystemExit(f"ConfigError: {err}")
-def _patch_raw(raw_config: Dict) -> None:
+def _patch_raw(raw_config: Dict) -> None: # pylint: disable=too-many-branches
if isinstance(raw_config.get("otg"), dict):
for (old, new) in [
("msd", "msd"),
@@ -195,6 +194,23 @@ def _patch_raw(raw_config: Dict) -> None:
raw_config["otg"]["devices"] = {}
raw_config["otg"]["devices"][new] = raw_config["otg"].pop(old)
+ if isinstance(raw_config.get("kvmd"), dict) and isinstance(raw_config["kvmd"].get("wol"), dict):
+ if not isinstance(raw_config["kvmd"].get("gpio"), dict):
+ raw_config["kvmd"]["gpio"] = {}
+ for section in ["drivers", "scheme"]:
+ if not isinstance(raw_config["kvmd"]["gpio"].get(section), dict):
+ raw_config["kvmd"]["gpio"][section] = {}
+ raw_config["kvmd"]["gpio"]["drivers"]["__wol__"] = {
+ "type": "wol",
+ **raw_config["kvmd"].pop("wol"),
+ }
+ raw_config["kvmd"]["gpio"]["scheme"]["__wol__"] = {
+ "driver": "__wol__",
+ "pin": 0,
+ "mode": "output",
+ "switch": False,
+ }
+
if isinstance(raw_config.get("kvmd"), dict) and isinstance(raw_config["kvmd"].get("streamer"), dict):
streamer_config = raw_config["kvmd"]["streamer"]
@@ -359,12 +375,6 @@ def _get_config_scheme() -> Dict:
},
},
- "wol": {
- "ip": Option("255.255.255.255", type=functools.partial(valid_ip, v6=False)),
- "port": Option(9, type=valid_port),
- "mac": Option("", type=_make_ifarg(valid_mac, "")),
- },
-
"hid": {
"type": Option("", type=valid_stripped_string_not_empty),
diff --git a/kvmd/apps/kvmd/__init__.py b/kvmd/apps/kvmd/__init__.py
index 678b23e8..b49c0190 100644
--- a/kvmd/apps/kvmd/__init__.py
+++ b/kvmd/apps/kvmd/__init__.py
@@ -34,7 +34,6 @@ from .. import init
from .auth import AuthManager
from .info import InfoManager
from .logreader import LogReader
-from .wol import WakeOnLan
from .ugpio import UserGpio
from .streamer import Streamer
from .snapshoter import Snapshoter
@@ -86,7 +85,6 @@ def main(argv: Optional[List[str]]=None) -> None:
),
info_manager=InfoManager(global_config),
log_reader=LogReader(),
- wol=WakeOnLan(**config.wol._unpack()),
user_gpio=UserGpio(config.gpio, global_config.otg.udc),
hid=hid,
diff --git a/kvmd/apps/kvmd/api/wol.py b/kvmd/apps/kvmd/api/wol.py
deleted file mode 100644
index ded6f6bf..00000000
--- a/kvmd/apps/kvmd/api/wol.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# ========================================================================== #
-# #
-# KVMD - The main Pi-KVM daemon. #
-# #
-# Copyright (C) 2018-2021 Maxim Devaev <[email protected]> #
-# #
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU General Public License as published by #
-# the Free Software Foundation, either version 3 of the License, or #
-# (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU General Public License for more details. #
-# #
-# You should have received a copy of the GNU General Public License #
-# along with this program. If not, see <https://www.gnu.org/licenses/>. #
-# #
-# ========================================================================== #
-
-
-from aiohttp.web import Request
-from aiohttp.web import Response
-
-from ..wol import WakeOnLan
-
-from ..http import exposed_http
-from ..http import make_json_response
-
-
-# =====
-class WolApi:
- def __init__(self, wol: WakeOnLan) -> None:
- self.__wol = wol
-
- # =====
-
- @exposed_http("GET", "/wol")
- async def __state_handler(self, _: Request) -> Response:
- return make_json_response(await self.__wol.get_state())
-
- @exposed_http("POST", "/wol/wakeup")
- async def __wakeup_handler(self, _: Request) -> Response:
- await self.__wol.wakeup()
- return make_json_response()
diff --git a/kvmd/apps/kvmd/server.py b/kvmd/apps/kvmd/server.py
index a5681580..08b310d0 100644
--- a/kvmd/apps/kvmd/server.py
+++ b/kvmd/apps/kvmd/server.py
@@ -65,7 +65,6 @@ from ... import aioproc
from .auth import AuthManager
from .info import InfoManager
from .logreader import LogReader
-from .wol import WakeOnLan
from .ugpio import UserGpio
from .streamer import Streamer
from .snapshoter import Snapshoter
@@ -85,7 +84,6 @@ from .api.auth import check_request_auth
from .api.info import InfoApi
from .api.log import LogApi
-from .api.wol import WolApi
from .api.ugpio import UserGpioApi
from .api.hid import HidApi
from .api.atx import AtxApi
@@ -148,7 +146,6 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
auth_manager: AuthManager,
info_manager: InfoManager,
log_reader: LogReader,
- wol: WakeOnLan,
user_gpio: UserGpio,
hid: BaseHid,
@@ -186,7 +183,6 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
for sub in sorted(info_manager.get_subs())
],
*[
- _Component("Wake-on-LAN", "wol_state", wol),
_Component("User-GPIO", "gpio_state", user_gpio),
_Component("HID", "hid_state", hid),
_Component("ATX", "atx_state", atx),
@@ -201,7 +197,6 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
AuthApi(auth_manager),
InfoApi(info_manager),
LogApi(log_reader),
- WolApi(wol),
UserGpioApi(user_gpio),
self.__hid_api,
AtxApi(atx),
diff --git a/kvmd/apps/kvmd/wol.py b/kvmd/plugins/ugpio/wol.py
index 70c60a89..deeb06c6 100644
--- a/kvmd/apps/kvmd/wol.py
+++ b/kvmd/plugins/ugpio/wol.py
@@ -27,46 +27,69 @@ from typing import Optional
from ...logging import get_logger
-from ...errors import OperationError
-
from ... import aiotools
+from ...yamlconf import Option
-# =====
-class WolDisabledError(OperationError):
- def __init__(self) -> None:
- super().__init__("WoL is disabled")
+from ...validators.net import valid_ip
+from ...validators.net import valid_port
+from ...validators.net import valid_mac
+
+from . import GpioDriverOfflineError
+from . import BaseUserGpioDriver
# =====
-class WakeOnLan:
- def __init__(self, ip: str, port: int, mac: str) -> None:
+class Plugin(BaseUserGpioDriver): # pylint: disable=too-many-instance-attributes
+ def __init__( # pylint: disable=super-init-not-called
+ self,
+ instance_name: str,
+ notifier: aiotools.AioNotifier,
+
+ ip: str,
+ port: int,
+ mac: str,
+ ) -> None:
+
+ super().__init__(instance_name, notifier)
+
self.__ip = ip
self.__port = port
self.__mac = mac
- self.__magic = b""
-
- if mac:
- assert len(mac) == 17, mac
- self.__magic = bytes.fromhex("FF" * 6 + mac.replace(":", "") * 16)
- async def get_state(self) -> Dict:
+ @classmethod
+ def get_plugin_options(cls) -> Dict:
return {
- "enabled": bool(self.__magic),
- "target": {
- "ip": self.__ip,
- "port": self.__port,
- "mac": self.__mac,
- },
+ "ip": Option("255.255.255.255", type=(lambda arg: valid_ip(arg, v6=False))),
+ "port": Option(9, type=valid_port),
+ "mac": Option("", type=(lambda arg: (valid_mac(arg) if arg else ""))),
}
- @aiotools.atomic
- async def wakeup(self) -> None:
- if not self.__magic:
- raise WolDisabledError()
+ def register_input(self, pin: int, debounce: float) -> None:
+ _ = pin
+ _ = debounce
- logger = get_logger(0)
- logger.info("Waking up %s (%s:%s) using Wake-on-LAN ...", self.__mac, self.__ip, self.__port)
+ def register_output(self, pin: int, initial: Optional[bool]) -> None:
+ _ = pin
+ _ = initial
+
+ def prepare(self) -> None:
+ get_logger(0).info("Probing driver %s on MAC %s and %s:%d ...", self, self.__mac, self.__ip, self.__port)
+
+ async def run(self) -> None:
+ await aiotools.wait_infinite()
+
+ async def cleanup(self) -> None:
+ pass
+
+ async def read(self, pin: int) -> bool:
+ _ = pin
+ return False
+
+ async def write(self, pin: int, state: bool) -> None:
+ _ = pin
+ if not state:
+ return
sock: Optional[socket.socket] = None
try:
@@ -74,14 +97,18 @@ class WakeOnLan:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.connect((self.__ip, self.__port))
- sock.send(self.__magic)
+ sock.send(bytes.fromhex("FF" * 6 + self.__mac.replace(":", "") * 16))
except Exception:
- logger.exception("Can't send Wake-on-LAN packet")
- else:
- logger.info("Wake-on-LAN packet sent")
+ get_logger(0).exception("Can't send Wake-on-LAN packet via %s to %s", self, self.__mac)
+ raise GpioDriverOfflineError(self)
finally:
if sock:
try:
sock.close()
except Exception:
pass
+
+ def __str__(self) -> str:
+ return f"WakeOnLan({self._instance_name})"
+
+ __repr__ = __str__
diff --git a/web/kvm/index.html b/web/kvm/index.html
index 94c0863c..59870d50 100644
--- a/web/kvm/index.html
+++ b/web/kvm/index.html
@@ -121,7 +121,7 @@
<button class="small" data-force-hide-menu id="open-log-button">&bull; Log</button>
</td>
<td class="feature-disabled" id="wol">
- <button class="small" disabled data-force-hide-menu id="wol-wakeup-button">&bull; WoL</button>
+ <button class="gpio-button small" data-force-hide-menu id="gpio-button-__wol__" data-channel="__wol__" data-confirm="Are you sure to send Wake-on-LAN packet to the server?">&bull; WoL</button>
</td>
</tr>
</table>
diff --git a/web/kvm/navbar-system.pug b/web/kvm/navbar-system.pug
index 8602e673..03910cb2 100644
--- a/web/kvm/navbar-system.pug
+++ b/web/kvm/navbar-system.pug
@@ -12,7 +12,9 @@ li(class="right")
td(id="webterm" class="feature-disabled") #[button(data-force-hide-menu data-show-window="webterm-window" class="small") &bull; Term]
td #[button(data-force-hide-menu data-show-window="about-window" class="small") &bull; About]
td #[button(data-force-hide-menu id="open-log-button" class="small") &bull; Log]
- td(id="wol" class="feature-disabled") #[button(disabled data-force-hide-menu id="wol-wakeup-button" class="small") &bull; WoL]
+ td(id="wol" class="feature-disabled")
+ button(data-force-hide-menu id="gpio-button-__wol__" class="gpio-button small" data-channel="__wol__"
+ data-confirm="Are you sure to send Wake-on-LAN packet to the server?") &bull; WoL
hr
table(class="kv" style="width: calc(100% - 20px)")
tr(id="stream-resolution" class="feature-disabled")
diff --git a/web/share/js/kvm/gpio.js b/web/share/js/kvm/gpio.js
index f31dbf05..d1969f39 100644
--- a/web/share/js/kvm/gpio.js
+++ b/web/share/js/kvm/gpio.js
@@ -105,6 +105,7 @@ export function Gpio() {
}
tools.featureSetEnabled($("v3-usb-breaker"), ("__v3_usb_breaker__" in model.scheme.outputs));
+ tools.featureSetEnabled($("wol"), ("__wol__" in model.scheme.outputs));
self.setState(__state);
};
diff --git a/web/share/js/kvm/session.js b/web/share/js/kvm/session.js
index 3a0b501c..12eb46fd 100644
--- a/web/share/js/kvm/session.js
+++ b/web/share/js/kvm/session.js
@@ -30,7 +30,6 @@ import {Hid} from "./hid.js";
import {Atx} from "./atx.js";
import {Msd} from "./msd.js";
import {Streamer} from "./stream.js";
-import {WakeOnLan} from "./wol.js";
import {Gpio} from "./gpio.js";
@@ -48,7 +47,6 @@ export function Session() {
var __hid = new Hid(__streamer.getResolution);
var __atx = new Atx();
var __msd = new Msd();
- var __wol = new WakeOnLan();
var __gpio = new Gpio();
var __init__ = function() {
@@ -243,7 +241,6 @@ export function Session() {
case "info_hw_state": __setAboutInfoHw(data.event); break;
case "info_system_state": __setAboutInfoSystem(data.event); break;
case "info_extras_state": __setExtras(data.event); break;
- case "wol_state": __wol.setState(data.event); break;
case "gpio_model_state": __gpio.setModel(data.event); break;
case "gpio_state": __gpio.setState(data.event); break;
case "hid_keymaps_state": __hid.setKeymaps(data.event); break;
diff --git a/web/share/js/kvm/wol.js b/web/share/js/kvm/wol.js
deleted file mode 100644
index c0f68883..00000000
--- a/web/share/js/kvm/wol.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/*****************************************************************************
-# #
-# KVMD - The main Pi-KVM daemon. #
-# #
-# Copyright (C) 2018-2021 Maxim Devaev <[email protected]> #
-# #
-# This program is free software: you can redistribute it and/or modify #
-# it under the terms of the GNU General Public License as published by #
-# the Free Software Foundation, either version 3 of the License, or #
-# (at your option) any later version. #
-# #
-# This program is distributed in the hope that it will be useful, #
-# but WITHOUT ANY WARRANTY; without even the implied warranty of #
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
-# GNU General Public License for more details. #
-# #
-# You should have received a copy of the GNU General Public License #
-# along with this program. If not, see <https://www.gnu.org/licenses/>. #
-# #
-*****************************************************************************/
-
-
-"use strict";
-
-
-import {tools, $} from "../tools.js";
-import {wm} from "../wm.js";
-
-
-export function WakeOnLan() {
- var self = this;
-
- /************************************************************************/
-
- var __target = {};
-
- var __init__ = function() {
- tools.setOnClick($("wol-wakeup-button"), __clickWakeupButton);
- };
-
- /************************************************************************/
-
- self.setState = function(state) {
- if (state) {
- tools.featureSetEnabled($("wol"), state.enabled);
- __target = state.target;
- }
- wm.setElementEnabled($("wol-wakeup-button"), (state && state.enabled));
- };
-
- var __clickWakeupButton = function() {
- let msg = `
- Are you sure to send Wake-on-LAN packet to the server?<br>
- Target: <b>${__target.mac}</b> (${__target.ip}:${__target.port})?
- `;
- wm.confirm(msg).then(function(ok) {
- if (ok) {
- let http = tools.makeRequest("POST", "/api/wol/wakeup", function() {
- if (http.readyState === 4) {
- if (http.status !== 200) {
- wm.error("Wakeup error:<br>", http.responseText);
- }
- }
- });
- }
- });
- };
-
- __init__();
-}