refactoring

This commit is contained in:
Maxim Devaev
2024-09-18 04:37:43 +03:00
parent 45270a09d7
commit 7a53f14456
83 changed files with 517 additions and 516 deletions

View File

@@ -45,9 +45,9 @@ class AtxApi:
return make_json_response(await self.__atx.get_state())
@exposed_http("POST", "/atx/power")
async def __power_handler(self, request: Request) -> Response:
action = valid_atx_power_action(request.query.get("action"))
wait = valid_bool(request.query.get("wait", False))
async def __power_handler(self, req: Request) -> Response:
action = valid_atx_power_action(req.query.get("action"))
wait = valid_bool(req.query.get("wait", False))
await ({
"on": self.__atx.power_on,
"off": self.__atx.power_off,
@@ -57,9 +57,9 @@ class AtxApi:
return make_json_response()
@exposed_http("POST", "/atx/click")
async def __click_handler(self, request: Request) -> Response:
button = valid_atx_button(request.query.get("button"))
wait = valid_bool(request.query.get("wait", False))
async def __click_handler(self, req: Request) -> Response:
button = valid_atx_button(req.query.get("button"))
wait = valid_bool(req.query.get("wait", False))
await ({
"power": self.__atx.click_power,
"power_long": self.__atx.click_power_long,

View File

@@ -43,34 +43,34 @@ from ..auth import AuthManager
_COOKIE_AUTH_TOKEN = "auth_token"
async def check_request_auth(auth_manager: AuthManager, exposed: HttpExposed, request: Request) -> None:
async def check_request_auth(auth_manager: AuthManager, exposed: HttpExposed, req: Request) -> None:
if auth_manager.is_auth_required(exposed):
user = request.headers.get("X-KVMD-User", "")
user = req.headers.get("X-KVMD-User", "")
if user:
user = valid_user(user)
passwd = request.headers.get("X-KVMD-Passwd", "")
set_request_auth_info(request, f"{user} (xhdr)")
passwd = req.headers.get("X-KVMD-Passwd", "")
set_request_auth_info(req, f"{user} (xhdr)")
if not (await auth_manager.authorize(user, valid_passwd(passwd))):
raise ForbiddenError()
return
token = request.cookies.get(_COOKIE_AUTH_TOKEN, "")
token = req.cookies.get(_COOKIE_AUTH_TOKEN, "")
if token:
user = auth_manager.check(valid_auth_token(token)) # type: ignore
if not user:
set_request_auth_info(request, "- (token)")
set_request_auth_info(req, "- (token)")
raise ForbiddenError()
set_request_auth_info(request, f"{user} (token)")
set_request_auth_info(req, f"{user} (token)")
return
basic_auth = request.headers.get("Authorization", "")
basic_auth = req.headers.get("Authorization", "")
if basic_auth and basic_auth[:6].lower() == "basic ":
try:
(user, passwd) = base64.b64decode(basic_auth[6:]).decode("utf-8").split(":")
except Exception:
raise UnauthorizedError()
user = valid_user(user)
set_request_auth_info(request, f"{user} (basic)")
set_request_auth_info(req, f"{user} (basic)")
if not (await auth_manager.authorize(user, valid_passwd(passwd))):
raise ForbiddenError()
return
@@ -85,9 +85,9 @@ class AuthApi:
# =====
@exposed_http("POST", "/auth/login", auth_required=False)
async def __login_handler(self, request: Request) -> Response:
async def __login_handler(self, req: Request) -> Response:
if self.__auth_manager.is_auth_enabled():
credentials = await request.post()
credentials = await req.post()
token = await self.__auth_manager.login(
user=valid_user(credentials.get("user", "")),
passwd=valid_passwd(credentials.get("passwd", "")),
@@ -98,9 +98,9 @@ class AuthApi:
return make_json_response()
@exposed_http("POST", "/auth/logout")
async def __logout_handler(self, request: Request) -> Response:
async def __logout_handler(self, req: Request) -> Response:
if self.__auth_manager.is_auth_enabled():
token = valid_auth_token(request.cookies.get(_COOKIE_AUTH_TOKEN, ""))
token = valid_auth_token(req.cookies.get(_COOKIE_AUTH_TOKEN, ""))
self.__auth_manager.logout(token)
return make_json_response()

View File

@@ -85,22 +85,22 @@ class HidApi:
return make_json_response(await self.__hid.get_state())
@exposed_http("POST", "/hid/set_params")
async def __set_params_handler(self, request: Request) -> Response:
async def __set_params_handler(self, req: Request) -> Response:
params = {
key: validator(request.query.get(key))
key: validator(req.query.get(key))
for (key, validator) in [
("keyboard_output", valid_hid_keyboard_output),
("mouse_output", valid_hid_mouse_output),
("jiggler", valid_bool),
]
if request.query.get(key) is not None
if req.query.get(key) is not None
}
self.__hid.set_params(**params) # type: ignore
return make_json_response()
@exposed_http("POST", "/hid/set_connected")
async def __set_connected_handler(self, request: Request) -> Response:
self.__hid.set_connected(valid_bool(request.query.get("connected")))
async def __set_connected_handler(self, req: Request) -> Response:
self.__hid.set_connected(valid_bool(req.query.get("connected")))
return make_json_response()
@exposed_http("POST", "/hid/reset")
@@ -128,12 +128,12 @@ class HidApi:
return make_json_response(await self.get_keymaps())
@exposed_http("POST", "/hid/print")
async def __print_handler(self, request: Request) -> Response:
text = await request.text()
limit = int(valid_int_f0(request.query.get("limit", 1024)))
async def __print_handler(self, req: Request) -> Response:
text = await req.text()
limit = int(valid_int_f0(req.query.get("limit", 1024)))
if limit > 0:
text = text[:limit]
symmap = self.__ensure_symmap(request.query.get("keymap", self.__default_keymap_name))
symmap = self.__ensure_symmap(req.query.get("keymap", self.__default_keymap_name))
self.__hid.send_key_events(text_to_web_keys(text, symmap))
return make_json_response()
@@ -257,21 +257,21 @@ class HidApi:
# =====
@exposed_http("POST", "/hid/events/send_key")
async def __events_send_key_handler(self, request: Request) -> Response:
key = valid_hid_key(request.query.get("key"))
async def __events_send_key_handler(self, req: Request) -> Response:
key = valid_hid_key(req.query.get("key"))
if key not in self.__ignore_keys:
if "state" in request.query:
state = valid_bool(request.query["state"])
if "state" in req.query:
state = valid_bool(req.query["state"])
self.__hid.send_key_events([(key, state)])
else:
self.__hid.send_key_events([(key, True), (key, False)])
return make_json_response()
@exposed_http("POST", "/hid/events/send_mouse_button")
async def __events_send_mouse_button_handler(self, request: Request) -> Response:
button = valid_hid_mouse_button(request.query.get("button"))
if "state" in request.query:
state = valid_bool(request.query["state"])
async def __events_send_mouse_button_handler(self, req: Request) -> Response:
button = valid_hid_mouse_button(req.query.get("button"))
if "state" in req.query:
state = valid_bool(req.query["state"])
self.__hid.send_mouse_button_event(button, state)
else:
self.__hid.send_mouse_button_event(button, True)
@@ -279,23 +279,23 @@ class HidApi:
return make_json_response()
@exposed_http("POST", "/hid/events/send_mouse_move")
async def __events_send_mouse_move_handler(self, request: Request) -> Response:
to_x = valid_hid_mouse_move(request.query.get("to_x"))
to_y = valid_hid_mouse_move(request.query.get("to_y"))
async def __events_send_mouse_move_handler(self, req: Request) -> Response:
to_x = valid_hid_mouse_move(req.query.get("to_x"))
to_y = valid_hid_mouse_move(req.query.get("to_y"))
self.__send_mouse_move_event(to_x, to_y)
return make_json_response()
@exposed_http("POST", "/hid/events/send_mouse_relative")
async def __events_send_mouse_relative_handler(self, request: Request) -> Response:
return self.__process_http_delta_event(request, self.__hid.send_mouse_relative_event)
async def __events_send_mouse_relative_handler(self, req: Request) -> Response:
return self.__process_http_delta_event(req, self.__hid.send_mouse_relative_event)
@exposed_http("POST", "/hid/events/send_mouse_wheel")
async def __events_send_mouse_wheel_handler(self, request: Request) -> Response:
return self.__process_http_delta_event(request, self.__hid.send_mouse_wheel_event)
async def __events_send_mouse_wheel_handler(self, req: Request) -> Response:
return self.__process_http_delta_event(req, self.__hid.send_mouse_wheel_event)
def __process_http_delta_event(self, request: Request, handler: Callable[[int, int], None]) -> Response:
delta_x = valid_hid_mouse_delta(request.query.get("delta_x"))
delta_y = valid_hid_mouse_delta(request.query.get("delta_y"))
def __process_http_delta_event(self, req: Request, handler: Callable[[int, int], None]) -> Response:
delta_x = valid_hid_mouse_delta(req.query.get("delta_x"))
delta_y = valid_hid_mouse_delta(req.query.get("delta_y"))
handler(delta_x, delta_y)
return make_json_response()

View File

@@ -41,17 +41,17 @@ class InfoApi:
# =====
@exposed_http("GET", "/info")
async def __common_state_handler(self, request: Request) -> Response:
fields = self.__valid_info_fields(request)
async def __common_state_handler(self, req: Request) -> Response:
fields = self.__valid_info_fields(req)
results = dict(zip(fields, await asyncio.gather(*[
self.__info_manager.get_submanager(field).get_state()
for field in fields
])))
return make_json_response(results)
def __valid_info_fields(self, request: Request) -> list[str]:
def __valid_info_fields(self, req: Request) -> list[str]:
subs = self.__info_manager.get_subs()
return sorted(valid_info_fields(
arg=request.query.get("fields", ",".join(subs)),
arg=req.query.get("fields", ",".join(subs)),
variants=subs,
) or subs)

View File

@@ -47,12 +47,12 @@ class LogApi:
# =====
@exposed_http("GET", "/log")
async def __log_handler(self, request: Request) -> StreamResponse:
async def __log_handler(self, req: Request) -> StreamResponse:
if self.__log_reader is None:
raise LogReaderDisabledError()
seek = valid_log_seek(request.query.get("seek", 0))
follow = valid_bool(request.query.get("follow", False))
response = await start_streaming(request, "text/plain")
seek = valid_log_seek(req.query.get("seek", 0))
follow = valid_bool(req.query.get("follow", False))
response = await start_streaming(req, "text/plain")
async for record in self.__log_reader.poll_log(seek, follow):
await response.write(("[%s %s] --- %s" % (
record["dt"].strftime("%Y-%m-%d %H:%M:%S"),

View File

@@ -66,29 +66,29 @@ class MsdApi:
return make_json_response(await self.__msd.get_state())
@exposed_http("POST", "/msd/set_params")
async def __set_params_handler(self, request: Request) -> Response:
async def __set_params_handler(self, req: Request) -> Response:
params = {
key: validator(request.query.get(param))
key: validator(req.query.get(param))
for (param, key, validator) in [
("image", "name", (lambda arg: str(arg).strip() and valid_msd_image_name(arg))),
("cdrom", "cdrom", valid_bool),
("rw", "rw", valid_bool),
]
if request.query.get(param) is not None
if req.query.get(param) is not None
}
await self.__msd.set_params(**params) # type: ignore
return make_json_response()
@exposed_http("POST", "/msd/set_connected")
async def __set_connected_handler(self, request: Request) -> Response:
await self.__msd.set_connected(valid_bool(request.query.get("connected")))
async def __set_connected_handler(self, req: Request) -> Response:
await self.__msd.set_connected(valid_bool(req.query.get("connected")))
return make_json_response()
# =====
@exposed_http("GET", "/msd/read")
async def __read_handler(self, request: Request) -> StreamResponse:
name = valid_msd_image_name(request.query.get("image"))
async def __read_handler(self, req: Request) -> StreamResponse:
name = valid_msd_image_name(req.query.get("image"))
compressors = {
"": ("", None),
"none": ("", None),
@@ -96,7 +96,7 @@ class MsdApi:
"zstd": (".zst", (lambda: zstandard.ZstdCompressor().compressobj())), # pylint: disable=unnecessary-lambda
}
(suffix, make_compressor) = compressors[check_string_in_list(
arg=request.query.get("compress", ""),
arg=req.query.get("compress", ""),
name="Compression mode",
variants=set(compressors),
)]
@@ -127,7 +127,7 @@ class MsdApi:
src = compressed()
size = -1
response = await start_streaming(request, "application/octet-stream", size, name + suffix)
response = await start_streaming(req, "application/octet-stream", size, name + suffix)
async for chunk in src:
await response.write(chunk)
return response
@@ -135,28 +135,28 @@ class MsdApi:
# =====
@exposed_http("POST", "/msd/write")
async def __write_handler(self, request: Request) -> Response:
unsafe_prefix = request.query.get("prefix", "") + "/"
name = valid_msd_image_name(unsafe_prefix + request.query.get("image", ""))
size = valid_int_f0(request.content_length)
remove_incomplete = self.__get_remove_incomplete(request)
async def __write_handler(self, req: Request) -> Response:
unsafe_prefix = req.query.get("prefix", "") + "/"
name = valid_msd_image_name(unsafe_prefix + req.query.get("image", ""))
size = valid_int_f0(req.content_length)
remove_incomplete = self.__get_remove_incomplete(req)
written = 0
async with self.__msd.write_image(name, size, remove_incomplete) as writer:
chunk_size = writer.get_chunk_size()
while True:
chunk = await request.content.read(chunk_size)
chunk = await req.content.read(chunk_size)
if not chunk:
break
written = await writer.write_chunk(chunk)
return make_json_response(self.__make_write_info(name, size, written))
@exposed_http("POST", "/msd/write_remote")
async def __write_remote_handler(self, request: Request) -> (Response | StreamResponse): # pylint: disable=too-many-locals
unsafe_prefix = request.query.get("prefix", "") + "/"
url = valid_url(request.query.get("url"))
insecure = valid_bool(request.query.get("insecure", False))
timeout = valid_float_f01(request.query.get("timeout", 10.0))
remove_incomplete = self.__get_remove_incomplete(request)
async def __write_remote_handler(self, req: Request) -> (Response | StreamResponse): # pylint: disable=too-many-locals
unsafe_prefix = req.query.get("prefix", "") + "/"
url = valid_url(req.query.get("url"))
insecure = valid_bool(req.query.get("insecure", False))
timeout = valid_float_f01(req.query.get("timeout", 10.0))
remove_incomplete = self.__get_remove_incomplete(req)
name = ""
size = written = 0
@@ -174,7 +174,7 @@ class MsdApi:
read_timeout=(7 * 24 * 3600),
) as remote:
name = str(request.query.get("image", "")).strip()
name = str(req.query.get("image", "")).strip()
if len(name) == 0:
name = htclient.get_filename(remote)
name = valid_msd_image_name(unsafe_prefix + name)
@@ -184,7 +184,7 @@ class MsdApi:
get_logger(0).info("Downloading image %r as %r to MSD ...", url, name)
async with self.__msd.write_image(name, size, remove_incomplete) as writer:
chunk_size = writer.get_chunk_size()
response = await start_streaming(request, "application/x-ndjson")
response = await start_streaming(req, "application/x-ndjson")
await stream_write_info()
last_report_ts = 0
async for chunk in remote.content.iter_chunked(chunk_size):
@@ -197,16 +197,16 @@ class MsdApi:
await stream_write_info()
return response
except Exception as err:
except Exception as ex:
if response is not None:
await stream_write_info()
await stream_json_exception(response, err)
elif isinstance(err, aiohttp.ClientError):
return make_json_exception(err, 400)
await stream_json_exception(response, ex)
elif isinstance(ex, aiohttp.ClientError):
return make_json_exception(ex, 400)
raise
def __get_remove_incomplete(self, request: Request) -> (bool | None):
flag: (str | None) = request.query.get("remove_incomplete")
def __get_remove_incomplete(self, req: Request) -> (bool | None):
flag: (str | None) = req.query.get("remove_incomplete")
return (valid_bool(flag) if flag is not None else None)
def __make_write_info(self, name: str, size: int, written: int) -> dict:
@@ -215,8 +215,8 @@ class MsdApi:
# =====
@exposed_http("POST", "/msd/remove")
async def __remove_handler(self, request: Request) -> Response:
await self.__msd.remove(valid_msd_image_name(request.query.get("image")))
async def __remove_handler(self, req: Request) -> Response:
await self.__msd.remove(valid_msd_image_name(req.query.get("image")))
return make_json_response()
@exposed_http("POST", "/msd/reset")

View File

@@ -111,10 +111,10 @@ class RedfishApi:
}, wrap_result=False)
@exposed_http("POST", "/redfish/v1/Systems/0/Actions/ComputerSystem.Reset")
async def __power_handler(self, request: Request) -> Response:
async def __power_handler(self, req: Request) -> Response:
try:
action = check_string_in_list(
arg=(await request.json())["ResetType"],
arg=(await req.json()).get("ResetType"),
name="Redfish ResetType",
variants=set(self.__actions),
lower=False,

View File

@@ -52,36 +52,36 @@ class StreamerApi:
return make_json_response(await self.__streamer.get_state())
@exposed_http("GET", "/streamer/snapshot")
async def __take_snapshot_handler(self, request: Request) -> Response:
async def __take_snapshot_handler(self, req: Request) -> Response:
snapshot = await self.__streamer.take_snapshot(
save=valid_bool(request.query.get("save", False)),
load=valid_bool(request.query.get("load", False)),
allow_offline=valid_bool(request.query.get("allow_offline", False)),
save=valid_bool(req.query.get("save", False)),
load=valid_bool(req.query.get("load", False)),
allow_offline=valid_bool(req.query.get("allow_offline", False)),
)
if snapshot:
if valid_bool(request.query.get("ocr", False)):
if valid_bool(req.query.get("ocr", False)):
langs = self.__ocr.get_available_langs()
return Response(
body=(await self.__ocr.recognize(
data=snapshot.data,
langs=valid_string_list(
arg=str(request.query.get("ocr_langs", "")).strip(),
arg=str(req.query.get("ocr_langs", "")).strip(),
subval=(lambda lang: check_string_in_list(lang, "OCR lang", langs)),
name="OCR langs list",
),
left=int(valid_number(request.query.get("ocr_left", -1))),
top=int(valid_number(request.query.get("ocr_top", -1))),
right=int(valid_number(request.query.get("ocr_right", -1))),
bottom=int(valid_number(request.query.get("ocr_bottom", -1))),
left=int(valid_number(req.query.get("ocr_left", -1))),
top=int(valid_number(req.query.get("ocr_top", -1))),
right=int(valid_number(req.query.get("ocr_right", -1))),
bottom=int(valid_number(req.query.get("ocr_bottom", -1))),
)),
headers=dict(snapshot.headers),
content_type="text/plain",
)
elif valid_bool(request.query.get("preview", False)):
elif valid_bool(req.query.get("preview", False)):
data = await snapshot.make_preview(
max_width=valid_int_f0(request.query.get("preview_max_width", 0)),
max_height=valid_int_f0(request.query.get("preview_max_height", 0)),
quality=valid_stream_quality(request.query.get("preview_quality", 80)),
max_width=valid_int_f0(req.query.get("preview_max_width", 0)),
max_height=valid_int_f0(req.query.get("preview_max_height", 0)),
quality=valid_stream_quality(req.query.get("preview_quality", 80)),
)
else:
data = snapshot.data

View File

@@ -48,17 +48,17 @@ class UserGpioApi:
})
@exposed_http("POST", "/gpio/switch")
async def __switch_handler(self, request: Request) -> Response:
channel = valid_ugpio_channel(request.query.get("channel"))
state = valid_bool(request.query.get("state"))
wait = valid_bool(request.query.get("wait", False))
async def __switch_handler(self, req: Request) -> Response:
channel = valid_ugpio_channel(req.query.get("channel"))
state = valid_bool(req.query.get("state"))
wait = valid_bool(req.query.get("wait", False))
await self.__user_gpio.switch(channel, state, wait)
return make_json_response()
@exposed_http("POST", "/gpio/pulse")
async def __pulse_handler(self, request: Request) -> Response:
channel = valid_ugpio_channel(request.query.get("channel"))
delay = valid_float_f0(request.query.get("delay", 0.0))
wait = valid_bool(request.query.get("wait", False))
async def __pulse_handler(self, req: Request) -> Response:
channel = valid_ugpio_channel(req.query.get("channel"))
delay = valid_float_f0(req.query.get("delay", 0.0))
wait = valid_bool(req.query.get("wait", False))
await self.__user_gpio.pulse(channel, delay, wait)
return make_json_response()