Mercurial > libervia-web
annotate libervia/web/pages/_browser/bridge.py @ 1616:6bfeb9f0fb84
browser (calls): conferences implementation:
- Handle A/V conferences calls creation/joining by entering a conference room JID in the
search box.
- Group call box has been improved and is used both for group calls (small number of
participants) and A/V conferences (larger number of participants).
- Fullscreen button for group call is working.
- Avatar/user nickname are shown in group call on peer user, as an overlay on video
stream.
- Use `user` metadata when present to display the right user avatar/name when receiving a
stream from SFU (i.e. A/V conference).
- Peer user have a new 3 dots menu with a `pin` item to (un)pin it (i.e. display it on
full container with on top).
- Updated webrtc to handle unidirectional streams correctly and to adapt to A/V conference
specification.
rel 448
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 07 Aug 2024 00:01:57 +0200 |
parents | 5db55d01ce05 |
children |
rev | line source |
---|---|
1510
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
1 from browser import window, aio, timer, console as log |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
2 import time |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
3 import random |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
4 import json |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
5 import dialog |
1297
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
6 import javascript |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
7 |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
8 |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
9 log.warning = log.warn |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
10 tab_id = random.randint(0, 2**64) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
11 log.info(f"TAB ID is {tab_id}") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
12 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
13 |
1510
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
14 class BridgeException(Exception): |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
15 """An exception which has been raised from the backend and arrived to the frontend.""" |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
16 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
17 def __init__(self, name, message="", condition=""): |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
18 """ |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
19 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
20 @param name (str): full exception class name (with module) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
21 @param message (str): error message |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
22 @param condition (str) : error condition |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
23 """ |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
24 Exception.__init__(self) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
25 self.fullname = str(name) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
26 self.message = str(message) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
27 self.condition = str(condition) if condition else "" |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
28 self.module, __, self.classname = str(self.fullname).rpartition(".") |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
29 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
30 def __str__(self): |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
31 return f"{self.classname}: {self.message or ''}" |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
32 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
33 def __eq__(self, other): |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
34 return self.classname == other |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
35 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
36 |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
37 class WebSocket: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
38 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
39 def __init__(self, broadcast_channel): |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
40 self.broadcast_channel = broadcast_channel |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
41 self.token = window.ws_token |
1545
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
42 self.socket = None |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
43 self.create_socket() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
44 self.retrying = False |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
45 self.network_error = False |
1545
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
46 self._ready_fut = aio.Future() |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
47 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
48 @property |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
49 def profile(self): |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
50 return self.broadcast_channel.profile |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
51 |
1545
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
52 @property |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
53 def is_ready(self): |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
54 return False if self.socket is None else self.socket.readyState == "OPEN" |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
55 |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
56 @property |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
57 def connection_ready_fut(self): |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
58 """Future resolved when connection is ready""" |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
59 return self._ready_fut |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
60 |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
61 def retry_connect(self) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
62 if self.retrying: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
63 return |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
64 self.retrying = True |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
65 try: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
66 notif = dialog.RetryNotification(self.create_socket) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
67 notif.show( |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
68 "Can't connect to server", |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
69 delay=random.randint(0, 30) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
70 ) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
71 except Exception as e: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
72 # for security reasons, browser don't give the reason of the error with |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
73 # WebSockets, thus we try to detect network error here, as if we can't show |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
74 # the retry dialog, that probably means that it's not reachable |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
75 try: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
76 name = e.name |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
77 except AttributeError: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
78 name = None |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
79 if name == "NetworkError": |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
80 self.network_error = True |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
81 log.warning("network error detected, server may be down") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
82 log.error(f"Can't show retry dialog: {e}") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
83 log.info("retrying in 30s") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
84 timer.set_timeout(self.create_socket, 30000) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
85 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
86 raise e |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
87 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
88 # if we can show the retry dialog, the network is fine |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
89 self.network_error = False |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
90 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
91 def create_socket(self) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
92 log.debug("creating socket") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
93 self.retrying = False |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
94 self.socket = window.WebSocket.new(window.ws_url, "libervia-page") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
95 self.socket_start = time.time() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
96 self.socket.bind("open", self.on_open) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
97 self.socket.bind("error", self.on_error) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
98 self.socket.bind("close", self.on_close) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
99 self.socket.bind("message", self.on_message) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
100 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
101 def send(self, data_type: str, data: dict) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
102 self.socket.send(json.dumps({ |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
103 "type": data_type, |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
104 "data": data |
1579
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
105 }, ensure_ascii=False)) |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
106 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
107 def close(self) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
108 log.debug("closing socket") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
109 self.broadcast_channel.ws = None |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
110 self.socket.close() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
111 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
112 def on_open(self, evt) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
113 log.info("websocket connection opened") |
1545
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
114 self._ready_fut.set_result(None) |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
115 self.send("init", {"profile": self.profile, "token": self.token}) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
116 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
117 def on_error(self, evt) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
118 if not self.network_error and time.time() - self.socket_start < 5: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
119 # disconnection is happening fast, we try to reload |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
120 log.warning("Reloading due to suspected session error") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
121 window.location.reload() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
122 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
123 self.retry_connect() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
124 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
125 def on_close(self, evt) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
126 log.warning(f"websocket is closed {evt.code=} {evt.reason=}") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
127 if self.broadcast_channel.ws is None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
128 # this is a close requested locally |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
129 return |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
130 elif evt.code == 4401: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
131 log.info( |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
132 "no authorized, the session is probably not valid anymore, reloading" |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
133 ) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
134 window.location.reload() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
135 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
136 # close event may be due to normal tab closing, thus we try to reconnect only |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
137 # after a delay |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
138 timer.set_timeout(self.retry_connect, 5000) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
139 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
140 def on_message(self, message_evt): |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
141 msg_data = json.loads(message_evt.data) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
142 msg_type = msg_data.get("type") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
143 if msg_type == "bridge": |
1506 | 144 log.debug( |
145 f"==> bridge message: {msg_data=}" | |
146 ) | |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
147 self.broadcast_channel.post( |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
148 msg_type, |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
149 msg_data["data"] |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
150 ) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
151 elif msg_type == "force_close": |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
152 log.warning(f"force closing connection: {msg_data.get('reason')}") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
153 self.close() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
154 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
155 dialog.notification.show( |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
156 f"Unexpected message type {msg_type}" |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
157 "error" |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
158 ) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
159 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
160 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
161 class BroadcastChannel: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
162 handlers = {} |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
163 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
164 def __init__(self): |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
165 log.debug(f"BroadcastChannel init with profile {self.profile!r}") |
1545
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
166 self.ws = None |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
167 self._connected = False |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
168 self.start = time.time() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
169 self.bc = window.BroadcastChannel.new("libervia") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
170 self.bc.bind("message", self.on_message) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
171 # there is no way to check if there is already a connection in BroadcastChannel |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
172 # API, thus we wait a bit to see if somebody is answering. If not, we are probably |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
173 # the first tab. |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
174 self.check_connection_timer = timer.set_timeout(self.establish_connection, 20) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
175 # set of all known tab ids |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
176 self.tabs_ids = {tab_id} |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
177 self.post("salut_a_vous", { |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
178 "profile": self.profile |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
179 }) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
180 window.bind("unload", self.on_unload) |
1545
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
181 self._wait_connection_fut = aio.Future() |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
182 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
183 @property |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
184 def profile(self): |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
185 return window.profile or "" |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
186 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
187 @property |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
188 def connecting_tab(self) -> bool: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
189 """True is this tab is the one establishing the websocket connection""" |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
190 return self.ws is not None |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
191 |
1545
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
192 async def _wait_for_ws(self): |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
193 assert self.ws is not None |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
194 await self.ws.connection_ready_fut |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
195 self._wait_connection_fut.set_result(None) |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
196 self._connected = True |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
197 |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
198 @connecting_tab.setter |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
199 def connecting_tab(self, connecting: bool) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
200 if connecting: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
201 if self.ws is None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
202 self.ws = WebSocket(self) |
1579
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
203 self.post("connection", {}) |
1545
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
204 aio.run(self._wait_for_ws()) |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
205 |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
206 elif self.ws is not None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
207 self.ws.close() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
208 |
1545
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
209 @property |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
210 def connected(self): |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
211 return self._connected |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
212 |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
213 async def wait_for_connection(self): |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
214 if self._connected: |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
215 return |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
216 await self._wait_connection_fut |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
217 |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
218 def establish_connection(self) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
219 """Called when there is no existing connection""" |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
220 timer.clear_timeout(self.check_connection_timer) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
221 log.debug(f"Establishing connection {tab_id=}") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
222 self.connecting_tab = True |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
223 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
224 def handle_bridge_signal(self, data: dict) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
225 """Forward bridge signals to registered handlers""" |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
226 signal = data["signal"] |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
227 handlers = self.handlers.get(signal, []) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
228 for handler in handlers: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
229 handler(*data["args"]) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
230 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
231 def on_message(self, evt) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
232 data = json.loads(evt.data) |
1579
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
233 # FIXME: we convert back to int, see FIXME in [post] for details |
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
234 data["id"] = int(data["id"]) |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
235 if data["type"] == "bridge": |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
236 self.handle_bridge_signal(data) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
237 elif data["type"] == "salut_a_toi": |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
238 # this is a response from existing tabs |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
239 other_tab_id = data["id"] |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
240 if other_tab_id == tab_id: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
241 # in the unlikely case that this happens, we simply reload this tab to get |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
242 # a new ID |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
243 log.warning("duplicate tab id, we reload the page: {tab_id=}") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
244 window.location.reload() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
245 return |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
246 self.tabs_ids.add(other_tab_id) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
247 if data["connecting_tab"] and self.check_connection_timer is not None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
248 # this tab has the websocket connection to server |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
249 log.info(f"there is already a connection to server at tab {other_tab_id}") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
250 timer.clear_timeout(self.check_connection_timer) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
251 self.check_connection_timer = None |
1545
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
252 self._wait_connection_fut.set_result(None) |
be20e6ac9f22
browser (bridge): add methods/properties to wait for Websocket/BroadcastChannel to be ready
Goffi <goffi@goffi.org>
parents:
1518
diff
changeset
|
253 self._connected = True |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
254 elif data["type"] == "salut_a_vous": |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
255 # a new tab has just been created |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
256 if data["profile"] != self.profile: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
257 log.info( |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
258 f"we are now connected with the profile {data['profile']}, " |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
259 "reloading the page" |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
260 ) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
261 window.location.reload() |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
262 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
263 self.tabs_ids.add(data["id"]) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
264 self.post("salut_a_toi", { |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
265 "id": tab_id, |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
266 "connecting_tab": self.connecting_tab |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
267 }) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
268 elif data["type"] == "connection": |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
269 log.info(f"tab {data['id']} is the new connecting tab") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
270 elif data["type"] == "salut_a_rantanplan": |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
271 # a tab is being closed |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
272 other_tab_id = data["id"] |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
273 # it is unlikely that there is a collision, but just in case we check it |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
274 if other_tab_id != tab_id: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
275 self.tabs_ids.discard(other_tab_id) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
276 if data["connecting_tab"]: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
277 log.info(f"connecting tab with id {other_tab_id} has been closed") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
278 if max(self.tabs_ids) == tab_id: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
279 log.info("this is the new connecting tab, establish_connection") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
280 self.connecting_tab = True |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
281 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
282 log.info(f"tab with id {other_tab_id} has been closed") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
283 else: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
284 log.warning(f"unknown message type: {data}") |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
285 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
286 def post(self, data_type, data: dict): |
1579
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
287 data["type"] = str(data_type) |
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
288 # FIXME: for some reason, JSON.stringify fail when a random.randint is used with |
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
289 # Brython 3.11 . See https://github.com/brython-dev/brython/issues/2332, |
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
290 # workaround may be removed once fixed version is used. |
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
291 data["id"] = str(tab_id) |
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
292 # FIXME: json.dumps doesn't support "ensure_ascii=False" and fails to correctly |
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
293 # dump emoji. See https://github.com/brython-dev/brython/issues/2331, workaround |
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
294 # may be removed once fixed version is used. |
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
295 dumped = javascript.JSON.stringify(data) |
5db55d01ce05
browser (bridge): workaround to fix unicode dumping of JSON:
Goffi <goffi@goffi.org>
parents:
1545
diff
changeset
|
296 self.bc.postMessage(dumped) |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
297 if data_type == "bridge": |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
298 self.handle_bridge_signal(data) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
299 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
300 def on_unload(self, evt) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
301 """Send a message to indicate that the tab is being closed""" |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
302 self.post("salut_a_rantanplan", { |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
303 "id": tab_id, |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
304 "connecting_tab": self.connecting_tab |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
305 }) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
306 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
307 |
1510
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
308 class Bridge: |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
309 bc: BroadcastChannel | None = None |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
310 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
311 def __init__(self) -> None: |
1510
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
312 if Bridge.bc is None: |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
313 Bridge.bc = BroadcastChannel() |
1297
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
314 |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
315 def __getattr__(self, attr): |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
316 return lambda *args, **kwargs: self.call(attr, *args, **kwargs) |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
317 |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
318 def on_load(self, xhr, ev, callback, errback): |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
319 if xhr.status == 200: |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
320 ret = javascript.JSON.parse(xhr.response) |
1314
8998f01088ac
browser (bridge): handle case where `callback` or `errback` is None
Goffi <goffi@goffi.org>
parents:
1297
diff
changeset
|
321 if callback is not None: |
8998f01088ac
browser (bridge): handle case where `callback` or `errback` is None
Goffi <goffi@goffi.org>
parents:
1297
diff
changeset
|
322 if ret is None: |
8998f01088ac
browser (bridge): handle case where `callback` or `errback` is None
Goffi <goffi@goffi.org>
parents:
1297
diff
changeset
|
323 callback() |
8998f01088ac
browser (bridge): handle case where `callback` or `errback` is None
Goffi <goffi@goffi.org>
parents:
1297
diff
changeset
|
324 else: |
8998f01088ac
browser (bridge): handle case where `callback` or `errback` is None
Goffi <goffi@goffi.org>
parents:
1297
diff
changeset
|
325 callback(ret) |
1297
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
326 elif xhr.status == 502: |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
327 # PROXY_ERROR is used for bridge error |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
328 ret = javascript.JSON.parse(xhr.response) |
1314
8998f01088ac
browser (bridge): handle case where `callback` or `errback` is None
Goffi <goffi@goffi.org>
parents:
1297
diff
changeset
|
329 if errback is not None: |
8998f01088ac
browser (bridge): handle case where `callback` or `errback` is None
Goffi <goffi@goffi.org>
parents:
1297
diff
changeset
|
330 errback(ret) |
1297
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
331 else: |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
332 log.error( |
1510
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
333 f"bridge call failed: code: {xhr.response}, text: {xhr.statusText}" |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
334 ) |
1314
8998f01088ac
browser (bridge): handle case where `callback` or `errback` is None
Goffi <goffi@goffi.org>
parents:
1297
diff
changeset
|
335 if errback is not None: |
1477
b28025a7cc28
browser (bride): use `BridgeInternalError` for unmanaged errors:
Goffi <goffi@goffi.org>
parents:
1314
diff
changeset
|
336 errback({"fullname": "BridgeInternalError", "message": xhr.statusText}) |
1297
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
337 |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
338 def call(self, method_name, *args, callback, errback, **kwargs): |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
339 xhr = window.XMLHttpRequest.new() |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
340 xhr.bind('load', lambda ev: self.on_load(xhr, ev, callback, errback)) |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
341 xhr.bind('error', lambda ev: errback( |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
342 {"fullname": "ConnectionError", "message": xhr.statusText})) |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
343 xhr.open("POST", f"/_bridge/{method_name}", True) |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
344 data = javascript.JSON.stringify({ |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
345 "args": args, |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
346 "kwargs": kwargs, |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
347 }) |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
348 xhr.setRequestHeader('X-Csrf-Token', window.csrf_token) |
999dccf0093e
browser: new bridge module to access restricted bridge from browser
Goffi <goffi@goffi.org>
parents:
diff
changeset
|
349 xhr.send(data) |
1504
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
350 |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
351 def register_signal(self, signal: str, handler, iface=None) -> None: |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
352 BroadcastChannel.handlers.setdefault(signal, []).append(handler) |
409d10211b20
server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents:
1477
diff
changeset
|
353 log.debug(f"signal {signal} has been registered") |
1510
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
354 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
355 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
356 class AsyncBridge: |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
357 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
358 def __getattr__(self, attr): |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
359 return lambda *args, **kwargs: self.call(attr, *args, **kwargs) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
360 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
361 async def call(self, method_name, *args, **kwargs): |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
362 print(f"calling {method_name}") |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
363 data = javascript.JSON.stringify({ |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
364 "args": args, |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
365 "kwargs": kwargs, |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
366 }) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
367 url = f"/_bridge/{method_name}" |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
368 r = await aio.post( |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
369 url, |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
370 headers={ |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
371 'X-Csrf-Token': window.csrf_token, |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
372 }, |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
373 data=data, |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
374 ) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
375 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
376 if r.status == 200: |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
377 return javascript.JSON.parse(r.data) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
378 elif r.status == 502: |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
379 ret = javascript.JSON.parse(r.data) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
380 raise BridgeException(ret['fullname'], ret['message'], ret['condition']) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
381 else: |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
382 print(f"bridge called failed: code: {r.status}, text: {r.statusText}") |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
383 raise BridgeException("InternalError", r.statusText) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
384 |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
385 def register_signal(self, signal: str, handler, iface=None) -> None: |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
386 BroadcastChannel.handlers.setdefault(signal, []).append(handler) |
5ea06e8b06ed
browser: make bridge API closer to the one use with other frontends:
Goffi <goffi@goffi.org>
parents:
1509
diff
changeset
|
387 log.debug(f"signal {signal} has been registered") |