mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-29 00:51:53 +08:00
better error handling
This commit is contained in:
@@ -30,6 +30,12 @@ import aiohttp
|
|||||||
from ... import __version__
|
from ... import __version__
|
||||||
|
|
||||||
|
|
||||||
|
# =====
|
||||||
|
class KvmdError(Exception):
|
||||||
|
def __init__(self, err: Exception):
|
||||||
|
super().__init__(f"{type(err).__name__} {err}")
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
class KvmdClient:
|
class KvmdClient:
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -62,28 +68,36 @@ class KvmdClient:
|
|||||||
except aiohttp.ClientResponseError as err:
|
except aiohttp.ClientResponseError as err:
|
||||||
if err.status in [401, 403]:
|
if err.status in [401, 403]:
|
||||||
return False
|
return False
|
||||||
raise
|
raise KvmdError(err)
|
||||||
|
except aiohttp.ClientError as err:
|
||||||
|
raise KvmdError(err)
|
||||||
|
|
||||||
@contextlib.asynccontextmanager
|
@contextlib.asynccontextmanager
|
||||||
async def ws(self, user: str, passwd: str) -> AsyncGenerator[aiohttp.ClientWebSocketResponse, None]:
|
async def ws(self, user: str, passwd: str) -> AsyncGenerator[aiohttp.ClientWebSocketResponse, None]:
|
||||||
async with self.__make_session(user, passwd) as session:
|
try:
|
||||||
async with session.ws_connect(
|
async with self.__make_session(user, passwd) as session:
|
||||||
url=f"http://{self.__host}:{self.__port}/ws",
|
async with session.ws_connect(
|
||||||
timeout=self.__timeout,
|
url=f"http://{self.__host}:{self.__port}/ws",
|
||||||
) as ws:
|
timeout=self.__timeout,
|
||||||
yield ws
|
) as ws:
|
||||||
|
yield ws
|
||||||
|
except aiohttp.ClientError as err:
|
||||||
|
raise KvmdError(err)
|
||||||
|
|
||||||
async def set_streamer_params(self, user: str, passwd: str, quality: int, desired_fps: int) -> None:
|
async def set_streamer_params(self, user: str, passwd: str, quality: int, desired_fps: int) -> None:
|
||||||
async with self.__make_session(user, passwd) as session:
|
try:
|
||||||
async with session.post(
|
async with self.__make_session(user, passwd) as session:
|
||||||
url=f"http://{self.__host}:{self.__port}/streamer/set_params",
|
async with session.post(
|
||||||
timeout=self.__timeout,
|
url=f"http://{self.__host}:{self.__port}/streamer/set_params",
|
||||||
params={
|
timeout=self.__timeout,
|
||||||
"quality": quality,
|
params={
|
||||||
"desired_fps": desired_fps,
|
"quality": quality,
|
||||||
},
|
"desired_fps": desired_fps,
|
||||||
) as response:
|
},
|
||||||
response.raise_for_status()
|
) as response:
|
||||||
|
response.raise_for_status()
|
||||||
|
except aiohttp.ClientError as err:
|
||||||
|
raise KvmdError(err)
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
|
|
||||||
|
|||||||
@@ -31,12 +31,25 @@ from .errors import RfbConnectionError
|
|||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
|
def rfb_format_remote(writer: asyncio.StreamWriter) -> str:
|
||||||
|
return "[%s]:%d" % (writer.transport.get_extra_info("peername")[:2])
|
||||||
|
|
||||||
|
|
||||||
|
async def rfb_close_writer(writer: asyncio.StreamWriter) -> bool:
|
||||||
|
closing = writer.is_closing()
|
||||||
|
if not closing:
|
||||||
|
writer.transport.abort() # type: ignore
|
||||||
|
writer.close()
|
||||||
|
await writer.wait_closed()
|
||||||
|
return (not closing)
|
||||||
|
|
||||||
|
|
||||||
class RfbClientStream:
|
class RfbClientStream:
|
||||||
def __init__(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
|
def __init__(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
|
||||||
self.__reader = reader
|
self.__reader = reader
|
||||||
self.__writer = writer
|
self.__writer = writer
|
||||||
|
|
||||||
self._remote = "[%s]:%d" % (self.__writer.transport.get_extra_info("peername")[:2])
|
self._remote = rfb_format_remote(writer)
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
|
|
||||||
@@ -129,9 +142,4 @@ class RfbClientStream:
|
|||||||
self.__writer = ssl_writer
|
self.__writer = ssl_writer
|
||||||
|
|
||||||
async def _close(self) -> None:
|
async def _close(self) -> None:
|
||||||
self.__writer.transport.abort() # type: ignore
|
await rfb_close_writer(self.__writer)
|
||||||
try:
|
|
||||||
self.__writer.close()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
await self.__writer.wait_closed()
|
|
||||||
|
|||||||
@@ -37,11 +37,14 @@ from ...logging import get_logger
|
|||||||
from ... import aiotools
|
from ... import aiotools
|
||||||
|
|
||||||
from .rfb import RfbClient
|
from .rfb import RfbClient
|
||||||
|
from .rfb.stream import rfb_format_remote
|
||||||
|
from .rfb.stream import rfb_close_writer
|
||||||
from .rfb.errors import RfbError
|
from .rfb.errors import RfbError
|
||||||
|
|
||||||
from .vncauth import VncAuthKvmdCredentials
|
from .vncauth import VncAuthKvmdCredentials
|
||||||
from .vncauth import VncAuthManager
|
from .vncauth import VncAuthManager
|
||||||
|
|
||||||
|
from .kvmd import KvmdError
|
||||||
from .kvmd import KvmdClient
|
from .kvmd import KvmdClient
|
||||||
|
|
||||||
from .streamer import StreamerError
|
from .streamer import StreamerError
|
||||||
@@ -318,19 +321,34 @@ class VncServer: # pylint: disable=too-many-instance-attributes
|
|||||||
shared_params = _SharedParams()
|
shared_params = _SharedParams()
|
||||||
|
|
||||||
async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
|
async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
|
||||||
await _Client(
|
logger = get_logger(0)
|
||||||
reader=reader,
|
remote = rfb_format_remote(writer)
|
||||||
writer=writer,
|
logger.info("Preparing client %s ...", remote)
|
||||||
tls_ciphers=tls_ciphers,
|
try:
|
||||||
tls_timeout=tls_timeout,
|
try:
|
||||||
desired_fps=desired_fps,
|
none_auth_only = await kvmd.authorize("", "")
|
||||||
symmap=symmap,
|
except KvmdError as err:
|
||||||
kvmd=kvmd,
|
logger.error("Client %s: Can't check KVMD auth mode: %s", remote, err)
|
||||||
streamer=streamer,
|
return
|
||||||
vnc_credentials=(await self.__vnc_auth_manager.read_credentials())[0],
|
|
||||||
none_auth_only=(await kvmd.authorize("", "")),
|
await _Client(
|
||||||
shared_params=shared_params,
|
reader=reader,
|
||||||
).run()
|
writer=writer,
|
||||||
|
tls_ciphers=tls_ciphers,
|
||||||
|
tls_timeout=tls_timeout,
|
||||||
|
desired_fps=desired_fps,
|
||||||
|
symmap=symmap,
|
||||||
|
kvmd=kvmd,
|
||||||
|
streamer=streamer,
|
||||||
|
vnc_credentials=(await self.__vnc_auth_manager.read_credentials())[0],
|
||||||
|
none_auth_only=none_auth_only,
|
||||||
|
shared_params=shared_params,
|
||||||
|
).run()
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Client %s: Unhandled exception in client task", remote)
|
||||||
|
finally:
|
||||||
|
if (await rfb_close_writer(writer)):
|
||||||
|
logger.info("Connection is closed in an emergency: %s", remote)
|
||||||
|
|
||||||
self.__handle_client = handle_client
|
self.__handle_client = handle_client
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ from ... import __version__
|
|||||||
|
|
||||||
# =====
|
# =====
|
||||||
class StreamerError(Exception):
|
class StreamerError(Exception):
|
||||||
pass
|
def __init__(self, err: Exception):
|
||||||
|
super().__init__(f"{type(err).__name__} {err}")
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
@@ -71,7 +72,7 @@ class StreamerClient:
|
|||||||
bytes(await frame.read()),
|
bytes(await frame.read()),
|
||||||
)
|
)
|
||||||
except Exception as err: # Тут бывают и ассерты, и KeyError, и прочая херня из-за корявых исключений в MultipartReader
|
except Exception as err: # Тут бывают и ассерты, и KeyError, и прочая херня из-за корявых исключений в MultipartReader
|
||||||
raise StreamerError(f"{type(err).__name__}: {str(err)}")
|
raise StreamerError(err)
|
||||||
|
|
||||||
def __make_session(self) -> aiohttp.ClientSession:
|
def __make_session(self) -> aiohttp.ClientSession:
|
||||||
kwargs: Dict = {
|
kwargs: Dict = {
|
||||||
|
|||||||
Reference in New Issue
Block a user