changeset 1545:be20e6ac9f22

browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
author Goffi <goffi@goffi.org>
date Thu, 06 Jul 2023 12:10:25 +0200
parents 9b451115e726
children 7f3f5ae7d65a
files libervia/web/pages/_browser/bridge.py
diffstat 1 files changed, 34 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/libervia/web/pages/_browser/bridge.py	Thu Jul 06 12:07:29 2023 +0200
+++ b/libervia/web/pages/_browser/bridge.py	Thu Jul 06 12:10:25 2023 +0200
@@ -39,14 +39,25 @@
     def __init__(self, broadcast_channel):
         self.broadcast_channel = broadcast_channel
         self.token = window.ws_token
+        self.socket = None
         self.create_socket()
         self.retrying = False
         self.network_error = False
+        self._ready_fut = aio.Future()
 
     @property
     def profile(self):
         return self.broadcast_channel.profile
 
+    @property
+    def is_ready(self):
+        return False if self.socket is None else self.socket.readyState == "OPEN"
+
+    @property
+    def connection_ready_fut(self):
+        """Future resolved when connection is ready"""
+        return self._ready_fut
+
     def retry_connect(self) -> None:
         if self.retrying:
             return
@@ -100,6 +111,7 @@
 
     def on_open(self, evt) -> None:
         log.info("websocket connection opened")
+        self._ready_fut.set_result(None)
         self.send("init", {"profile": self.profile, "token": self.token})
 
     def on_error(self, evt) -> None:
@@ -151,6 +163,8 @@
 
     def __init__(self):
         log.debug(f"BroadcastChannel init with profile {self.profile!r}")
+        self.ws = None
+        self._connected = False
         self.start = time.time()
         self.bc = window.BroadcastChannel.new("libervia")
         self.bc.bind("message", self.on_message)
@@ -158,7 +172,6 @@
         # API, thus we wait a bit to see if somebody is answering. If not, we are probably
         # the first tab.
         self.check_connection_timer = timer.set_timeout(self.establish_connection, 20)
-        self.ws = None
         # set of all known tab ids
         self.tabs_ids = {tab_id}
         self.post("salut_a_vous", {
@@ -166,6 +179,7 @@
             "profile": self.profile
         })
         window.bind("unload", self.on_unload)
+        self._wait_connection_fut = aio.Future()
 
     @property
     def profile(self):
@@ -176,6 +190,12 @@
         """True is this tab is the one establishing the websocket connection"""
         return self.ws is not None
 
+    async def _wait_for_ws(self):
+        assert self.ws is not None
+        await self.ws.connection_ready_fut
+        self._wait_connection_fut.set_result(None)
+        self._connected = True
+
     @connecting_tab.setter
     def connecting_tab(self, connecting: bool) -> None:
         if connecting:
@@ -184,9 +204,20 @@
                 self.post("connection", {
                     "tab_id": tab_id
                 })
+                aio.run(self._wait_for_ws())
+
         elif self.ws is not None:
             self.ws.close()
 
+    @property
+    def connected(self):
+        return self._connected
+
+    async def wait_for_connection(self):
+        if self._connected:
+            return
+        await self._wait_connection_fut
+
     def establish_connection(self) -> None:
         """Called when there is no existing connection"""
         timer.clear_timeout(self.check_connection_timer)
@@ -219,6 +250,8 @@
                 log.info(f"there is already a connection to server at tab {other_tab_id}")
                 timer.clear_timeout(self.check_connection_timer)
                 self.check_connection_timer = None
+                self._wait_connection_fut.set_result(None)
+                self._connected = True
         elif data["type"] == "salut_a_vous":
             # a new tab has just been created
             if data["profile"] != self.profile: