From 9a29dc6c2ef08857b306612c9540afbf7b690a1a Mon Sep 17 00:00:00 2001 From: mofeng-git Date: Wed, 1 Jan 2025 15:23:18 +0000 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=BD=91=E9=A1=B5=E6=A0=B9?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E3=80=81=E7=BD=91=E7=AB=99=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E5=92=8C=E7=AB=AF=E5=8F=A3=E7=9A=84=E9=85=8D=E7=BD=AE=E9=80=89?= =?UTF-8?q?=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kvmd/apps/__init__.py | 3 ++ kvmd/apps/kvmd/__init__.py | 3 ++ kvmd/apps/kvmd/api/info.py | 65 +------------------------------ kvmd/apps/kvmd/server.py | 66 +++++++++++++++++++++++++++++++- kvmd/apps/kvmd/streamer.py | 4 +- kvmd/htserver.py | 6 +-- kvmd_data/etc/kvmd/override.yaml | 5 ++- 7 files changed, 81 insertions(+), 71 deletions(-) diff --git a/kvmd/apps/__init__.py b/kvmd/apps/__init__.py index cfc39499..d9a2d97a 100644 --- a/kvmd/apps/__init__.py +++ b/kvmd/apps/__init__.py @@ -353,6 +353,9 @@ def _get_config_scheme() -> dict: "heartbeat": Option(15.0, type=valid_float_f01), "access_log_format": Option("[%P / %{X-Real-IP}i] '%r' => %s; size=%b ---" " referer='%{Referer}i'; user_agent='%{User-Agent}i'"), + "web_path": Option("/usr/share/kvmd/web", type=valid_abs_path), + "host": Option("127.0.0.1", type=valid_ip_or_host), + "port": Option(8080, type=valid_port), }, "auth": { diff --git a/kvmd/apps/kvmd/__init__.py b/kvmd/apps/kvmd/__init__.py index 495a320f..6972f52a 100644 --- a/kvmd/apps/kvmd/__init__.py +++ b/kvmd/apps/kvmd/__init__.py @@ -103,6 +103,9 @@ def main(argv: (list[str] | None)=None) -> None: ), keymap_path=config.hid.keymap, + web_path=config.server.web_path, + host=config.server.host, + port=config.server.port, stream_forever=config.streamer.forever, ).run(**config.server._unpack()) diff --git a/kvmd/apps/kvmd/api/info.py b/kvmd/apps/kvmd/api/info.py index f2badaee..4c75a6f5 100644 --- a/kvmd/apps/kvmd/api/info.py +++ b/kvmd/apps/kvmd/api/info.py @@ -19,19 +19,8 @@ # # # ========================================================================== # - -import os -from aiohttp import ClientConnectionError, ClientSession -from aiohttp import UnixConnector from aiohttp.web import Request from aiohttp.web import Response -from aiohttp.web import HTTPForbidden -from aiohttp.web import HTTPNotFound -from aiohttp.web import FileResponse -from aiohttp.web import HTTPInternalServerError - -from aiohttp.web import StreamResponse -from urllib.parse import urlparse, urlunparse, parse_qs, urlencode from ....htserver import exposed_http from ....htserver import make_json_response @@ -45,12 +34,9 @@ from ..info import InfoManager class InfoApi: def __init__(self, info_manager: InfoManager) -> None: self.__info_manager = info_manager - self.static_dir = 'kvmd_data/usr/share/kvmd/web' - self.target_stream_server = 'http://127.0.0.1:8081' # ===== - @exposed_http("GET", "/api/info") async def __common_state_handler(self, req: Request) -> Response: fields = self.__valid_info_fields(req) @@ -61,53 +47,4 @@ class InfoApi: return sorted(valid_info_fields( arg=req.query.get("fields", ",".join(available)), variants=available, - ) or available) - - @exposed_http("GET", "/streamer/stream") - async def proxy_stream_handler(self, request): - socket_path = '/home/mofeng/One-KVM/kvmd_data/run/kvmd/ustreamer.sock' - query_string = urlencode(request.query) - headers = request.headers.copy() - try: - async with ClientSession(connector=UnixConnector(path=socket_path)) as session: - backend_url = f'http://localhost/stream?{query_string}' if query_string else 'http://localhost/stream' - async with session.get(backend_url, headers=headers) as resp: - response = StreamResponse(status=resp.status, reason=resp.reason, headers=resp.headers) - await response.prepare(request) - while True: - chunk = await resp.content.read(512000) - if not chunk: - break - await response.write(chunk) - return response - except ClientConnectionError: - return Response(status=500, text="Client connection was closed") - - - @exposed_http("GET", "/{path:.*}", auth_required=False) - async def __html_file_handler(self, req: Request) -> Response: - path = req.match_info['path'] - full_path = os.path.normpath(os.path.join(self.static_dir, path)) - print("---------------") - print(full_path) - - # 安全检查:确保请求的文件在允许的基础目录内 - if not full_path.startswith(self.static_dir): - raise HTTPForbidden(text="Access denied.") - - if os.path.isdir(full_path): - index_path = os.path.join(full_path, 'index.html') - if os.path.isfile(index_path): - full_path = index_path - else: - raise HTTPNotFound(text="Directory does not contain an index.html file.") - - # 检查调整后的路径是否为现有文件 - if not (os.path.exists(full_path) and os.path.isfile(full_path)): - raise HTTPNotFound(text="File not found.") - - try: - return FileResponse(full_path) - except IOError as e: - raise HTTPInternalServerError(text=str(e)) - \ No newline at end of file + ) or available) \ No newline at end of file diff --git a/kvmd/apps/kvmd/server.py b/kvmd/apps/kvmd/server.py index a3595c6b..e33201db 100644 --- a/kvmd/apps/kvmd/server.py +++ b/kvmd/apps/kvmd/server.py @@ -30,6 +30,18 @@ from typing import Any from aiohttp.web import Request from aiohttp.web import Response from aiohttp.web import WebSocketResponse +from aiohttp.web import HTTPForbidden +from aiohttp.web import HTTPNotFound +from aiohttp.web import FileResponse +from aiohttp.web import HTTPInternalServerError +from aiohttp.web import StreamResponse + +import os +from aiohttp import ClientConnectionError +from aiohttp import ClientSession +from aiohttp import UnixConnector +from urllib.parse import urlencode + from ... import __version__ @@ -153,7 +165,9 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins snapshoter: Snapshoter, keymap_path: str, - + web_path: str, + host: str, + port: int, stream_forever: bool, ) -> None: @@ -194,6 +208,9 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins self.__streamer_notifier = aiotools.AioNotifier() self.__reset_streamer = False self.__new_streamer_params: dict = {} + self.__web_path = web_path + self.__host = host + self.__port = port # ===== STREAMER CONTROLLER @@ -306,6 +323,53 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins self._get_wss(), ))) + # ===== WEB TASKS + @exposed_http("GET", "/streamer/stream") + async def proxy_stream_handler(self, request): + socket_path = self.__streamer.get_path() + query_string = urlencode(request.query) + headers = request.headers.copy() + try: + async with ClientSession(connector=UnixConnector(path=socket_path)) as session: + backend_url = f'http://localhost/stream?{query_string}' if query_string else 'http://localhost/stream' + async with session.get(backend_url, headers=headers) as resp: + response = StreamResponse(status=resp.status, reason=resp.reason, headers=resp.headers) + await response.prepare(request) + while True: + chunk = await resp.content.read(512000) + if not chunk: + break + await response.write(chunk) + return response + except ClientConnectionError: + return Response(status=500, text="Client connection was closed") + + + @exposed_http("GET", "/{path:.*}", auth_required=False) + async def __html_file_handler(self, req: Request) -> Response: + path = req.match_info['path'] + if not os.path.exists(self.__web_path): + raise HTTPNotFound(text="Web root directory not found.") + full_path = os.path.normpath(os.path.join(self.__web_path, path)) + + if not full_path.startswith(self.__web_path): + raise HTTPForbidden(text="Access denied.") + + if os.path.isdir(full_path): + index_path = os.path.join(full_path, 'index.html') + if os.path.isfile(index_path): + full_path = index_path + else: + raise HTTPNotFound(text="404 Not Found") + + if not (os.path.exists(full_path) and os.path.isfile(full_path)): + raise HTTPNotFound(text="404 Not Found") + + try: + return FileResponse(full_path) + except IOError as e: + raise HTTPInternalServerError(text=str(e)) + # ===== SYSTEM TASKS async def __stream_controller(self) -> None: diff --git a/kvmd/apps/kvmd/streamer.py b/kvmd/apps/kvmd/streamer.py index 08c48eb1..3422a9bf 100644 --- a/kvmd/apps/kvmd/streamer.py +++ b/kvmd/apps/kvmd/streamer.py @@ -271,7 +271,9 @@ class Streamer: # pylint: disable=too-many-instance-attributes def get_params(self) -> dict: return self.__params.get_params() - + + def get_path(self) -> str: + return self.__unix_path # ===== async def get_state(self) -> dict: diff --git a/kvmd/htserver.py b/kvmd/htserver.py index 6b02f36a..4efbaa29 100644 --- a/kvmd/htserver.py +++ b/kvmd/htserver.py @@ -288,12 +288,12 @@ class HttpServer: unix_mode: int, heartbeat: float, access_log_format: str, + web_path: str, + host: str, + port: int, ) -> None: self.__ws_heartbeat = heartbeat - # 默认绑定到所有地址 - host = '0.0.0.0' - port = 8080 #if unix_rm and os.path.exists(unix_path): #os.remove(unix_path) #server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) diff --git a/kvmd_data/etc/kvmd/override.yaml b/kvmd_data/etc/kvmd/override.yaml index 0b9cd197..a2c368b2 100644 --- a/kvmd_data/etc/kvmd/override.yaml +++ b/kvmd_data/etc/kvmd/override.yaml @@ -17,8 +17,9 @@ kvmd: server: unix: kvmd_data/run/kvmd/kvmd.sock - #unix_mode: 432 - #unix_rm: true + web_path: kvmd_data/usr/share/kvmd/web + host: 0.0.0.0 + port: 8080 atx: type: disabled