From 7fe996848e611132fbf7bbbc6f8a1633cb8366bd Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Thu, 9 Jan 2025 09:10:36 +0100 Subject: [PATCH] Webview: fix thread_task cannot raise exceptions --- .../clan-app/clan_app/deps/webview/webview.py | 70 ++++++++++--------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/pkgs/clan-app/clan_app/deps/webview/webview.py b/pkgs/clan-app/clan_app/deps/webview/webview.py index 9aa4a16cf..f422066eb 100644 --- a/pkgs/clan-app/clan_app/deps/webview/webview.py +++ b/pkgs/clan-app/clan_app/deps/webview/webview.py @@ -82,43 +82,47 @@ class Webview: method_name: str = name, ) -> None: def thread_task() -> None: - args = json.loads(req.decode()) - try: - log.debug(f"Calling {method_name}({args[0]})") - # Initialize dataclasses from the payload - reconciled_arguments = {} - for k, v in args[0].items(): - # Some functions expect to be called with dataclass instances - # But the js api returns dictionaries. - # Introspect the function and create the expected dataclass from dict dynamically - # Depending on the introspected argument_type - arg_class = api.get_method_argtype(method_name, k) + args = json.loads(req.decode()) - # TODO: rename from_dict into something like construct_checked_value - # from_dict really takes Anything and returns an instance of the type/class - reconciled_arguments[k] = from_dict(arg_class, v) + try: + log.debug(f"Calling {method_name}({args[0]})") + # Initialize dataclasses from the payload + reconciled_arguments = {} + for k, v in args[0].items(): + # Some functions expect to be called with dataclass instances + # But the js api returns dictionaries. + # Introspect the function and create the expected dataclass from dict dynamically + # Depending on the introspected argument_type + arg_class = api.get_method_argtype(method_name, k) - reconciled_arguments["op_key"] = seq.decode() - # TODO: We could remove the wrapper in the MethodRegistry - # and just call the method directly - result = wrap_method(**reconciled_arguments) - success = True + # TODO: rename from_dict into something like construct_checked_value + # from_dict really takes Anything and returns an instance of the type/class + reconciled_arguments[k] = from_dict(arg_class, v) + + reconciled_arguments["op_key"] = seq.decode() + # TODO: We could remove the wrapper in the MethodRegistry + # and just call the method directly + 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( + 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}") + self.return_(seq.decode(), 0 if success else 1, serialized) except Exception as e: - log.exception(f"Error calling {method_name}") - result = str(e) - success = False - - try: - serialized = json.dumps( - 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}") - self.return_(seq.decode(), 0 if success else 1, serialized) + log.exception(f"Unhandled error in webview {method_name}") + self.return_(seq.decode(), 1, str(e)) thread = threading.Thread(target=thread_task) thread.start()