mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 17:20:30 +08:00
improved info handler
This commit is contained in:
parent
fe7c275d1a
commit
cb9597679d
2
PKGBUILD
2
PKGBUILD
@ -50,7 +50,7 @@ depends=(
|
|||||||
patch
|
patch
|
||||||
sudo
|
sudo
|
||||||
raspberrypi-io-access
|
raspberrypi-io-access
|
||||||
"ustreamer>=1.13"
|
"ustreamer>=1.17"
|
||||||
)
|
)
|
||||||
makedepends=(python-setuptools)
|
makedepends=(python-setuptools)
|
||||||
source=("$url/archive/v$pkgver.tar.gz")
|
source=("$url/archive/v$pkgver.tar.gz")
|
||||||
|
|||||||
@ -214,9 +214,9 @@ def _get_config_scheme() -> Dict:
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
"info": {
|
"info": { # Accessed via global config, see kvmd/info.py for details
|
||||||
"meta": Option("/etc/kvmd/meta.yaml", type=valid_abs_file, unpack_as="meta_path"),
|
"meta": Option("/etc/kvmd/meta.yaml", type=valid_abs_file),
|
||||||
"extras": Option("/usr/share/kvmd/extras", type=valid_abs_dir, unpack_as="extras_path"),
|
"extras": Option("/usr/share/kvmd/extras", type=valid_abs_dir),
|
||||||
},
|
},
|
||||||
|
|
||||||
"wol": {
|
"wol": {
|
||||||
|
|||||||
@ -72,7 +72,7 @@ def main(argv: Optional[List[str]]=None) -> None:
|
|||||||
force_internal_users=config.auth.internal.force_users,
|
force_internal_users=config.auth.internal.force_users,
|
||||||
enabled=config.auth.enabled,
|
enabled=config.auth.enabled,
|
||||||
),
|
),
|
||||||
info_manager=InfoManager(global_config, **config.info._unpack()),
|
info_manager=InfoManager(global_config),
|
||||||
log_reader=LogReader(),
|
log_reader=LogReader(),
|
||||||
wol=WakeOnLan(**config.wol._unpack()),
|
wol=WakeOnLan(**config.wol._unpack()),
|
||||||
|
|
||||||
|
|||||||
41
kvmd/apps/kvmd/api/info.py
Normal file
41
kvmd/apps/kvmd/api/info.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# ========================================================================== #
|
||||||
|
# #
|
||||||
|
# KVMD - The main Pi-KVM daemon. #
|
||||||
|
# #
|
||||||
|
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
|
||||||
|
# #
|
||||||
|
# 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 ..info import InfoManager
|
||||||
|
|
||||||
|
from ..http import exposed_http
|
||||||
|
from ..http import make_json_response
|
||||||
|
|
||||||
|
|
||||||
|
# =====
|
||||||
|
class InfoApi:
|
||||||
|
def __init__(self, info_manager: InfoManager) -> None:
|
||||||
|
self.__info_manager = info_manager
|
||||||
|
|
||||||
|
# =====
|
||||||
|
|
||||||
|
@exposed_http("GET", "/info")
|
||||||
|
async def __state_handler(self, _: Request) -> Response:
|
||||||
|
return make_json_response(await self.__info_manager.get_state())
|
||||||
@ -21,9 +21,12 @@
|
|||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import asyncio
|
||||||
|
import platform
|
||||||
import contextlib
|
import contextlib
|
||||||
|
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import dbus # pylint: disable=import-error
|
import dbus # pylint: disable=import-error
|
||||||
import dbus.exceptions
|
import dbus.exceptions
|
||||||
@ -34,35 +37,87 @@ from ...yamlconf import Section
|
|||||||
from ...yamlconf.loader import load_yaml_file
|
from ...yamlconf.loader import load_yaml_file
|
||||||
|
|
||||||
from ... import aiotools
|
from ... import aiotools
|
||||||
|
from ... import aioproc
|
||||||
|
|
||||||
|
from ... import __version__
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
class InfoManager:
|
class InfoManager:
|
||||||
def __init__(
|
def __init__(self, global_config: Section) -> None:
|
||||||
self,
|
|
||||||
global_config: Section,
|
|
||||||
meta_path: str,
|
|
||||||
extras_path: str,
|
|
||||||
) -> None:
|
|
||||||
|
|
||||||
self.__global_config = global_config
|
self.__global_config = global_config
|
||||||
self.__meta_path = meta_path
|
|
||||||
self.__extras_path = extras_path
|
|
||||||
|
|
||||||
async def get_meta(self) -> Dict:
|
async def get_state(self) -> Dict:
|
||||||
return (await aiotools.run_async(load_yaml_file, self.__meta_path))
|
(streamer_info, meta_info, extras_info) = await asyncio.gather(
|
||||||
|
self.__get_streamer_info(),
|
||||||
|
self.__get_meta_info(),
|
||||||
|
self.__get_extras_info(),
|
||||||
|
)
|
||||||
|
uname_info = platform.uname() # Uname using the internal cache
|
||||||
|
return {
|
||||||
|
"system": {
|
||||||
|
"kvmd": {"version": __version__},
|
||||||
|
"streamer": streamer_info,
|
||||||
|
"kernel": {
|
||||||
|
field: getattr(uname_info, field)
|
||||||
|
for field in ["system", "release", "version", "machine"]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"meta": meta_info,
|
||||||
|
"extras": extras_info,
|
||||||
|
}
|
||||||
|
|
||||||
async def get_extras(self) -> Dict:
|
# =====
|
||||||
return (await aiotools.run_async(self.__inner_get_extras))
|
|
||||||
|
|
||||||
def __inner_get_extras(self) -> Dict:
|
async def __get_streamer_info(self) -> Dict:
|
||||||
extras: Dict[str, Dict] = {}
|
version = ""
|
||||||
for app in os.listdir(self.__extras_path):
|
features: Dict[str, bool] = {}
|
||||||
if app[0] != "." and os.path.isdir(os.path.join(self.__extras_path, app)):
|
try:
|
||||||
extras[app] = load_yaml_file(os.path.join(self.__extras_path, app, "manifest.yaml"))
|
path = self.__global_config.kvmd.streamer.cmd[0]
|
||||||
self.__rewrite_app_daemon(extras[app])
|
((_, version), (_, features_text)) = await asyncio.gather(
|
||||||
self.__rewrite_app_port(extras[app])
|
aioproc.read_process([path, "--version"], err_to_null=True),
|
||||||
return extras
|
aioproc.read_process([path, "--features"], err_to_null=True),
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
get_logger(0).exception("Can't get streamer info")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
for line in features_text.split("\n"):
|
||||||
|
(status, name) = map(str.strip, line.split(" "))
|
||||||
|
features[name] = (status == "+")
|
||||||
|
except Exception:
|
||||||
|
get_logger(0).exception("Can't parse streamer features")
|
||||||
|
return {
|
||||||
|
"app": os.path.basename(path),
|
||||||
|
"version": version,
|
||||||
|
"features": features,
|
||||||
|
}
|
||||||
|
|
||||||
|
async def __get_meta_info(self) -> Optional[Dict]:
|
||||||
|
try:
|
||||||
|
return ((await aiotools.run_async(load_yaml_file, self.__global_config.kvmd.info.meta)) or {})
|
||||||
|
except Exception:
|
||||||
|
get_logger(0).exception("Can't parse meta")
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def __get_extras_info(self) -> Optional[Dict]:
|
||||||
|
return (await aiotools.run_async(self.__inner_get_extras_info))
|
||||||
|
|
||||||
|
# =====
|
||||||
|
|
||||||
|
def __inner_get_extras_info(self) -> Optional[Dict]:
|
||||||
|
try:
|
||||||
|
extras_path = self.__global_config.kvmd.info.extras
|
||||||
|
extras: Dict[str, Dict] = {}
|
||||||
|
for app in os.listdir(extras_path):
|
||||||
|
if app[0] != "." and os.path.isdir(os.path.join(extras_path, app)):
|
||||||
|
extras[app] = load_yaml_file(os.path.join(extras_path, app, "manifest.yaml"))
|
||||||
|
self.__rewrite_app_daemon(extras[app])
|
||||||
|
self.__rewrite_app_port(extras[app])
|
||||||
|
return extras
|
||||||
|
except Exception:
|
||||||
|
get_logger(0).exception("Can't parse extras")
|
||||||
|
return None
|
||||||
|
|
||||||
def __rewrite_app_daemon(self, extras: Dict) -> None:
|
def __rewrite_app_daemon(self, extras: Dict) -> None:
|
||||||
daemon = extras.get("daemon", "")
|
daemon = extras.get("daemon", "")
|
||||||
|
|||||||
@ -57,8 +57,6 @@ from ...validators.kvm import valid_stream_fps
|
|||||||
|
|
||||||
from ... import aiotools
|
from ... import aiotools
|
||||||
|
|
||||||
from ... import __version__
|
|
||||||
|
|
||||||
from .auth import AuthManager
|
from .auth import AuthManager
|
||||||
from .info import InfoManager
|
from .info import InfoManager
|
||||||
from .logreader import LogReader
|
from .logreader import LogReader
|
||||||
@ -78,6 +76,7 @@ from .http import HttpServer
|
|||||||
from .api.auth import AuthApi
|
from .api.auth import AuthApi
|
||||||
from .api.auth import check_request_auth
|
from .api.auth import check_request_auth
|
||||||
|
|
||||||
|
from .api.info import InfoApi
|
||||||
from .api.log import LogApi
|
from .api.log import LogApi
|
||||||
from .api.wol import WolApi
|
from .api.wol import WolApi
|
||||||
from .api.hid import HidApi
|
from .api.hid import HidApi
|
||||||
@ -129,6 +128,7 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
|
|||||||
self.__apis: List[object] = [
|
self.__apis: List[object] = [
|
||||||
self,
|
self,
|
||||||
AuthApi(auth_manager),
|
AuthApi(auth_manager),
|
||||||
|
InfoApi(info_manager),
|
||||||
LogApi(log_reader),
|
LogApi(log_reader),
|
||||||
WolApi(wol),
|
WolApi(wol),
|
||||||
HidApi(hid, keymap_path),
|
HidApi(hid, keymap_path),
|
||||||
@ -148,24 +148,6 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
|
|||||||
self.__reset_streamer = False
|
self.__reset_streamer = False
|
||||||
self.__new_streamer_params: Dict = {}
|
self.__new_streamer_params: Dict = {}
|
||||||
|
|
||||||
async def __make_info(self) -> Dict:
|
|
||||||
streamer_info = await self.__streamer.get_info()
|
|
||||||
return {
|
|
||||||
"version": {
|
|
||||||
"kvmd": __version__,
|
|
||||||
"streamer": streamer_info["version"],
|
|
||||||
},
|
|
||||||
"streamer": streamer_info["app"],
|
|
||||||
"meta": await self.__info_manager.get_meta(),
|
|
||||||
"extras": await self.__info_manager.get_extras(),
|
|
||||||
}
|
|
||||||
|
|
||||||
# ===== SYSTEM
|
|
||||||
|
|
||||||
@exposed_http("GET", "/info")
|
|
||||||
async def __info_handler(self, _: aiohttp.web.Request) -> aiohttp.web.Response:
|
|
||||||
return make_json_response(await self.__make_info())
|
|
||||||
|
|
||||||
# ===== STREAMER CONTROLLER
|
# ===== STREAMER CONTROLLER
|
||||||
|
|
||||||
@exposed_http("POST", "/streamer/set_params")
|
@exposed_http("POST", "/streamer/set_params")
|
||||||
@ -198,7 +180,7 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
|
|||||||
await self.__register_socket(ws)
|
await self.__register_socket(ws)
|
||||||
try:
|
try:
|
||||||
await asyncio.gather(*[
|
await asyncio.gather(*[
|
||||||
self.__broadcast_event(_Events.INFO_STATE, (await self.__make_info())),
|
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.WOL_STATE, self.__wol.get_state()),
|
||||||
self.__broadcast_event(_Events.HID_STATE, (await self.__hid.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.ATX_STATE, self.__atx.get_state()),
|
||||||
|
|||||||
@ -20,7 +20,6 @@
|
|||||||
# ========================================================================== #
|
# ========================================================================== #
|
||||||
|
|
||||||
|
|
||||||
import os
|
|
||||||
import signal
|
import signal
|
||||||
import asyncio
|
import asyncio
|
||||||
import asyncio.subprocess
|
import asyncio.subprocess
|
||||||
@ -246,13 +245,6 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
# =====
|
# =====
|
||||||
|
|
||||||
async def get_info(self) -> Dict:
|
|
||||||
version = (await aioproc.read_process([self.__cmd[0], "--version"], err_to_null=True))[1]
|
|
||||||
return {
|
|
||||||
"app": os.path.basename(self.__cmd[0]),
|
|
||||||
"version": version,
|
|
||||||
}
|
|
||||||
|
|
||||||
async def make_snapshot(self, save: bool, load: bool, allow_offline: bool) -> Optional[StreamerSnapshot]:
|
async def make_snapshot(self, save: bool, load: bool, allow_offline: bool) -> Optional[StreamerSnapshot]:
|
||||||
if load:
|
if load:
|
||||||
return self.__snapshot
|
return self.__snapshot
|
||||||
|
|||||||
@ -150,13 +150,17 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
async def __process_ws_event(self, event: Dict) -> None:
|
async def __process_ws_event(self, event: Dict) -> None:
|
||||||
if event["event_type"] == "info_state":
|
if event["event_type"] == "info_state":
|
||||||
host = event["event"]["meta"].get("server", {}).get("host")
|
try:
|
||||||
if isinstance(host, str):
|
host = event["event"]["meta"]["server"]["host"]
|
||||||
name = f"Pi-KVM: {host}"
|
except Exception:
|
||||||
async with self.__lock:
|
host = None
|
||||||
if self._encodings.has_rename:
|
else:
|
||||||
await self._send_rename(name)
|
if isinstance(host, str):
|
||||||
self.__shared_params.name = name
|
name = f"Pi-KVM: {host}"
|
||||||
|
async with self.__lock:
|
||||||
|
if self._encodings.has_rename:
|
||||||
|
await self._send_rename(name)
|
||||||
|
self.__shared_params.name = name
|
||||||
|
|
||||||
elif event["event_type"] == "hid_state":
|
elif event["event_type"] == "hid_state":
|
||||||
async with self.__lock:
|
async with self.__lock:
|
||||||
|
|||||||
@ -650,25 +650,18 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" class="copyright">Copyright © 2018 Pi-KVM Developers Team</td>
|
<td colspan="2" class="copyright">Copyright © 2018 Pi-KVM Developers Team</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><br></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="version">
|
|
||||||
<td>KVMD:</td>
|
|
||||||
<td id="about-version-kvmd"></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="version">
|
|
||||||
<td>Streamer:</td>
|
|
||||||
<td id="about-version-streamer"></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<br>
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<input type="radio" name="about-tab-button" id="about-tab-info-button" value="" checked>
|
<input type="radio" name="about-tab-button" id="about-tab-info-button" value="" checked>
|
||||||
<label for="about-tab-info-button">Info</label>
|
<label for="about-tab-info-button">Info</label>
|
||||||
|
|
||||||
|
<input type="radio" name="about-tab-button" id="about-tab-version-button" value="">
|
||||||
|
<label for="about-tab-version-button">Version</label>
|
||||||
|
|
||||||
<input type="radio" name="about-tab-button" id="about-tab-thanks-button" value="">
|
<input type="radio" name="about-tab-button" id="about-tab-thanks-button" value="">
|
||||||
<label for="about-tab-thanks-button">Thanks</label>
|
<label for="about-tab-thanks-button">Thanks</label>
|
||||||
|
|
||||||
@ -677,8 +670,15 @@
|
|||||||
<span class="code-comment">No data</span>
|
<span class="code-comment">No data</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="about-tab-version-content">
|
||||||
|
<div id="about-version" class="code">
|
||||||
|
<span class="code-comment">No data</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="about-tab-thanks-content">
|
<div id="about-tab-thanks-content">
|
||||||
<div class="code" style="max-height: 300px">
|
<div id="about-thanks" class="code">
|
||||||
<span class="code-comment">
|
<span class="code-comment">
|
||||||
// These kind people donated money to the Pi-KVM project<br>
|
// These kind people donated money to the Pi-KVM project<br>
|
||||||
// and supported the work on it. We are very grateful<br>
|
// and supported the work on it. We are very grateful<br>
|
||||||
|
|||||||
@ -41,15 +41,12 @@ div#about td.copyright {
|
|||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div#about tr.version {
|
div#about div#about-meta, div#about-version, div#about-thanks {
|
||||||
font-family: monospace;
|
height: 250px;
|
||||||
}
|
|
||||||
|
|
||||||
div#about div#about-meta {
|
|
||||||
height: 200px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#about-tab-info-button:checked~#about-tab-info-content,
|
#about-tab-info-button:checked~#about-tab-info-content,
|
||||||
|
#about-tab-version-button:checked~#about-tab-version-content,
|
||||||
#about-tab-thanks-button:checked~#about-tab-thanks-content {
|
#about-tab-thanks-button:checked~#about-tab-thanks-content {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,15 +56,20 @@ function __loadKvmdInfo() {
|
|||||||
if (http.status === 200) {
|
if (http.status === 200) {
|
||||||
let info = JSON.parse(http.responseText).result;
|
let info = JSON.parse(http.responseText).result;
|
||||||
|
|
||||||
let apps = Object.values(info.extras).sort(function(a, b) {
|
let apps = [];
|
||||||
if (a.place < b.place) {
|
if (info.extras === null) {
|
||||||
return -1;
|
wm.error("Not all applications in the menu can be displayed<br>due an error. See KVMD logs for details.");
|
||||||
} else if (a.place > b.place) {
|
} else {
|
||||||
return 1;
|
apps = Object.values(info.extras).sort(function(a, b) {
|
||||||
} else {
|
if (a.place < b.place) {
|
||||||
return 0;
|
return -1;
|
||||||
}
|
} else if (a.place > b.place) {
|
||||||
});
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$("apps-box").innerHTML = "<ul id=\"apps\"></ul>";
|
$("apps-box").innerHTML = "<ul id=\"apps\"></ul>";
|
||||||
|
|
||||||
@ -79,7 +84,7 @@ function __loadKvmdInfo() {
|
|||||||
$("apps").innerHTML += __makeApp("logout-button", "#", "share/svg/logout.svg", "Logout");
|
$("apps").innerHTML += __makeApp("logout-button", "#", "share/svg/logout.svg", "Logout");
|
||||||
tools.setOnClick($("logout-button"), __logout);
|
tools.setOnClick($("logout-button"), __logout);
|
||||||
|
|
||||||
if (info.meta && info.meta.server && info.meta.server.host) {
|
if (info.meta !== null && info.meta.server && info.meta.server.host) {
|
||||||
$("kvmd-meta-server-host").innerHTML = info.meta.server.host;
|
$("kvmd-meta-server-host").innerHTML = info.meta.server.host;
|
||||||
document.title = `Pi-KVM Index: ${info.meta.server.host}`;
|
document.title = `Pi-KVM Index: ${info.meta.server.host}`;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -55,8 +55,8 @@ export function Session() {
|
|||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
var __setKvmdInfo = function(state) {
|
var __setAboutInfo = function(state) {
|
||||||
if (state.meta) {
|
if (state.meta != null) {
|
||||||
let text = JSON.stringify(state.meta, undefined, 4).replace(/ /g, " ").replace(/\n/g, "<br>");
|
let text = JSON.stringify(state.meta, undefined, 4).replace(/ /g, " ").replace(/\n/g, "<br>");
|
||||||
$("about-meta").innerHTML = `
|
$("about-meta").innerHTML = `
|
||||||
<span class="code-comment">// The Pi-KVM metadata.<br>
|
<span class="code-comment">// The Pi-KVM metadata.<br>
|
||||||
@ -75,8 +75,48 @@ export function Session() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$("about-version-kvmd").innerHTML = state.version.kvmd;
|
let sys = state.system;
|
||||||
$("about-version-streamer").innerHTML = `${state.version.streamer} (${state.streamer})`;
|
$("about-version").innerHTML = `
|
||||||
|
KVMD: <span class="code-comment">${sys.kvmd.version}</span><br>
|
||||||
|
<hr>
|
||||||
|
Streamer: <span class="code-comment">${sys.streamer.version} (${sys.streamer.app})</span>
|
||||||
|
${__formatStreamerFeatures(sys.streamer.features)}
|
||||||
|
<hr>
|
||||||
|
${sys.kernel.system} kernel:
|
||||||
|
${__formatUname(sys.kernel)}
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
var __formatStreamerFeatures = function(features) {
|
||||||
|
let pairs = [];
|
||||||
|
for (let field of Object.keys(features).sort()) {
|
||||||
|
pairs.push([
|
||||||
|
field,
|
||||||
|
(features[field] ? "Yes" : "No"),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return __formatUl(pairs);
|
||||||
|
};
|
||||||
|
|
||||||
|
var __formatUname = function(kernel) {
|
||||||
|
let pairs = [];
|
||||||
|
for (let field of Object.keys(kernel).sort()) {
|
||||||
|
if (field != "system") {
|
||||||
|
pairs.push([
|
||||||
|
field[0].toUpperCase() + field.slice(1),
|
||||||
|
kernel[field],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return __formatUl(pairs);
|
||||||
|
};
|
||||||
|
|
||||||
|
var __formatUl = function(pairs) {
|
||||||
|
let text = "<ul>";
|
||||||
|
for (let pair of pairs) {
|
||||||
|
text += `<li>${pair[0]}: <span class="code-comment">${pair[1]}</span></li>`;
|
||||||
|
}
|
||||||
|
return text + "</ul>";
|
||||||
};
|
};
|
||||||
|
|
||||||
var __startSession = function() {
|
var __startSession = function() {
|
||||||
@ -117,7 +157,7 @@ export function Session() {
|
|||||||
let data = JSON.parse(event.data);
|
let data = JSON.parse(event.data);
|
||||||
switch (data.event_type) {
|
switch (data.event_type) {
|
||||||
case "pong": __missed_heartbeats = 0; break;
|
case "pong": __missed_heartbeats = 0; break;
|
||||||
case "info_state": __setKvmdInfo(data.event); break;
|
case "info_state": __setAboutInfo(data.event); break;
|
||||||
case "wol_state": __wol.setState(data.event); break;
|
case "wol_state": __wol.setState(data.event); break;
|
||||||
case "hid_state": __hid.setState(data.event); break;
|
case "hid_state": __hid.setState(data.event); break;
|
||||||
case "atx_state": __atx.setState(data.event); break;
|
case "atx_state": __atx.setState(data.event); break;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user