clan-app: Fix webview crash on exception in api wrapper
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 163 KiB |
@@ -1,63 +0,0 @@
|
|||||||
/* Insert custom styles here */
|
|
||||||
|
|
||||||
navigation-view {
|
|
||||||
padding: 5px;
|
|
||||||
/* padding-left: 5px;
|
|
||||||
padding-right: 5px;
|
|
||||||
padding-bottom: 5px; */
|
|
||||||
}
|
|
||||||
|
|
||||||
avatar {
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trust {
|
|
||||||
padding-top: 25px;
|
|
||||||
padding-bottom: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.join-list {
|
|
||||||
margin-top: 1px;
|
|
||||||
margin-left: 2px;
|
|
||||||
margin-right: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar {
|
|
||||||
margin-right: 25px;
|
|
||||||
min-width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-list {
|
|
||||||
background-color: inherit;
|
|
||||||
}
|
|
||||||
.group-list > .activatable:hover {
|
|
||||||
background-color: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-list > row {
|
|
||||||
margin-top: 12px;
|
|
||||||
border-bottom: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vm-list {
|
|
||||||
margin-top: 25px;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-shadow {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-entry {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
searchbar {
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-view {
|
|
||||||
margin-top: 12px;
|
|
||||||
font-family: monospace;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,13 @@ from collections.abc import Callable
|
|||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from clan_cli.api import MethodRegistry, dataclass_to_dict, from_dict
|
from clan_cli.api import (
|
||||||
|
ApiError,
|
||||||
|
ErrorDataClass,
|
||||||
|
MethodRegistry,
|
||||||
|
dataclass_to_dict,
|
||||||
|
from_dict,
|
||||||
|
)
|
||||||
|
|
||||||
from ._webview_ffi import _encode_c_string, _webview_lib
|
from ._webview_ffi import _encode_c_string, _webview_lib
|
||||||
|
|
||||||
@@ -20,6 +26,11 @@ class SizeHint(IntEnum):
|
|||||||
FIXED = 3
|
FIXED = 3
|
||||||
|
|
||||||
|
|
||||||
|
class FuncStatus(IntEnum):
|
||||||
|
SUCCESS = 0
|
||||||
|
FAILURE = 1
|
||||||
|
|
||||||
|
|
||||||
class Size:
|
class Size:
|
||||||
def __init__(self, width: int, height: int, hint: SizeHint) -> None:
|
def __init__(self, width: int, height: int, hint: SizeHint) -> None:
|
||||||
self.width = width
|
self.width = width
|
||||||
@@ -85,44 +96,48 @@ class Webview:
|
|||||||
try:
|
try:
|
||||||
args = json.loads(req.decode())
|
args = json.loads(req.decode())
|
||||||
|
|
||||||
try:
|
log.debug(f"Calling {method_name}({args[0]})")
|
||||||
log.debug(f"Calling {method_name}({args[0]})")
|
# Initialize dataclasses from the payload
|
||||||
# Initialize dataclasses from the payload
|
reconciled_arguments = {}
|
||||||
reconciled_arguments = {}
|
for k, v in args[0].items():
|
||||||
for k, v in args[0].items():
|
# Some functions expect to be called with dataclass instances
|
||||||
# Some functions expect to be called with dataclass instances
|
# But the js api returns dictionaries.
|
||||||
# But the js api returns dictionaries.
|
# Introspect the function and create the expected dataclass from dict dynamically
|
||||||
# Introspect the function and create the expected dataclass from dict dynamically
|
# Depending on the introspected argument_type
|
||||||
# Depending on the introspected argument_type
|
arg_class = api.get_method_argtype(method_name, k)
|
||||||
arg_class = api.get_method_argtype(method_name, k)
|
|
||||||
|
|
||||||
# TODO: rename from_dict into something like construct_checked_value
|
# TODO: rename from_dict into something like construct_checked_value
|
||||||
# from_dict really takes Anything and returns an instance of the type/class
|
# from_dict really takes Anything and returns an instance of the type/class
|
||||||
reconciled_arguments[k] = from_dict(arg_class, v)
|
reconciled_arguments[k] = from_dict(arg_class, v)
|
||||||
|
|
||||||
reconciled_arguments["op_key"] = seq.decode()
|
reconciled_arguments["op_key"] = seq.decode()
|
||||||
# TODO: We could remove the wrapper in the MethodRegistry
|
# TODO: We could remove the wrapper in the MethodRegistry
|
||||||
# and just call the method directly
|
# and just call the method directly
|
||||||
result = wrap_method(**reconciled_arguments)
|
result = wrap_method(**reconciled_arguments)
|
||||||
success = True
|
|
||||||
except Exception as e:
|
|
||||||
log.exception(f"Error calling {method_name}")
|
|
||||||
result = str(e)
|
|
||||||
success = False
|
|
||||||
|
|
||||||
try:
|
serialized = json.dumps(
|
||||||
serialized = json.dumps(
|
dataclass_to_dict(result), indent=4, ensure_ascii=False
|
||||||
dataclass_to_dict(result), indent=4, ensure_ascii=False
|
)
|
||||||
)
|
|
||||||
except TypeError:
|
|
||||||
log.exception(f"Error serializing result for {method_name}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
log.debug(f"Result for {method_name}: {serialized}")
|
log.debug(f"Result for {method_name}: {serialized}")
|
||||||
self.return_(seq.decode(), 0 if success else 1, serialized)
|
self.return_(seq.decode(), FuncStatus.SUCCESS, serialized)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(f"Unhandled error in webview {method_name}")
|
log.exception(f"Error while handling result of {method_name}")
|
||||||
self.return_(seq.decode(), 1, str(e))
|
result = ErrorDataClass(
|
||||||
|
op_key=seq.decode(),
|
||||||
|
status="error",
|
||||||
|
errors=[
|
||||||
|
ApiError(
|
||||||
|
message="An internal error occured",
|
||||||
|
description=str(e),
|
||||||
|
location=["bind_jsonschema_api", method_name],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
serialized = json.dumps(
|
||||||
|
dataclass_to_dict(result), indent=4, ensure_ascii=False
|
||||||
|
)
|
||||||
|
self.return_(seq.decode(), FuncStatus.FAILURE, serialized)
|
||||||
|
|
||||||
thread = threading.Thread(target=thread_task)
|
thread = threading.Thread(target=thread_task)
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|||||||
Reference in New Issue
Block a user