Mercurial > libervia-web
diff libervia/pages/_browser/bridge.py @ 1510:5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
`bridge.AsyncBridge` is not used instead of `aio_bridge.Bridge`
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 22 May 2023 11:57:44 +0200 |
parents | 106bae41f5c8 |
children |
line wrap: on
line diff
--- a/libervia/pages/_browser/bridge.py Sat Apr 08 13:44:11 2023 +0200 +++ b/libervia/pages/_browser/bridge.py Mon May 22 11:57:44 2023 +0200 @@ -1,4 +1,4 @@ -from browser import window, timer, console as log +from browser import window, aio, timer, console as log import time import random import json @@ -11,6 +11,29 @@ log.info(f"TAB ID is {tab_id}") +class BridgeException(Exception): + """An exception which has been raised from the backend and arrived to the frontend.""" + + def __init__(self, name, message="", condition=""): + """ + + @param name (str): full exception class name (with module) + @param message (str): error message + @param condition (str) : error condition + """ + Exception.__init__(self) + self.fullname = str(name) + self.message = str(message) + self.condition = str(condition) if condition else "" + self.module, __, self.classname = str(self.fullname).rpartition(".") + + def __str__(self): + return f"{self.classname}: {self.message or ''}" + + def __eq__(self, other): + return self.classname == other + + class WebSocket: def __init__(self, broadcast_channel): @@ -243,12 +266,12 @@ }) -class bridge: +class Bridge: bc: BroadcastChannel | None = None def __init__(self) -> None: - if bridge.bc is None: - bridge.bc = BroadcastChannel() + if Bridge.bc is None: + Bridge.bc = BroadcastChannel() def __getattr__(self, attr): return lambda *args, **kwargs: self.call(attr, *args, **kwargs) @@ -268,7 +291,7 @@ errback(ret) else: log.error( - f"bridge called failed: code: {xhr.response}, text: {xhr.statusText}" + f"bridge call failed: code: {xhr.response}, text: {xhr.statusText}" ) if errback is not None: errback({"fullname": "BridgeInternalError", "message": xhr.statusText}) @@ -289,3 +312,37 @@ def register_signal(self, signal: str, handler, iface=None) -> None: BroadcastChannel.handlers.setdefault(signal, []).append(handler) log.debug(f"signal {signal} has been registered") + + +class AsyncBridge: + + def __getattr__(self, attr): + return lambda *args, **kwargs: self.call(attr, *args, **kwargs) + + async def call(self, method_name, *args, **kwargs): + print(f"calling {method_name}") + data = javascript.JSON.stringify({ + "args": args, + "kwargs": kwargs, + }) + url = f"/_bridge/{method_name}" + r = await aio.post( + url, + headers={ + 'X-Csrf-Token': window.csrf_token, + }, + data=data, + ) + + if r.status == 200: + return javascript.JSON.parse(r.data) + elif r.status == 502: + ret = javascript.JSON.parse(r.data) + raise BridgeException(ret['fullname'], ret['message'], ret['condition']) + else: + print(f"bridge called failed: code: {r.status}, text: {r.statusText}") + raise BridgeException("InternalError", r.statusText) + + def register_signal(self, signal: str, handler, iface=None) -> None: + BroadcastChannel.handlers.setdefault(signal, []).append(handler) + log.debug(f"signal {signal} has been registered")