mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-05 05:22:07 +08:00
raylib networking: remove locking on UI thread (#36063)
* use callback queue to make this thread safe and remove locks (which lag ui thread?) * woah this works * no more lock! * always run signal handler and store callbacks, like qt * debug * more * okay not for now * combine _get_connections and _connection_by_ssid, closer to qt and not an explosion of GetSettings dbus calls * debug * try this * skip * len * skip hidden networks * actually slower * stash * back to 8929f37d495a524d4a996d66b82d4a947fbf4f1c * clean up
This commit is contained in:
@@ -133,12 +133,12 @@ class WifiManager:
|
||||
# State
|
||||
self._connecting_to_ssid: str = ""
|
||||
self._last_network_update: float = 0.0
|
||||
self._callback_queue: list[Callable] = []
|
||||
|
||||
# Callbacks
|
||||
# TODO: implement a callback queue to avoid blocking UI thread
|
||||
self._need_auth: Callable[[str], None] | None = None
|
||||
self._activated: Callable[[], None] | None = None
|
||||
self._forgotten: Callable[[str], None] | None = None
|
||||
self._forgotten: Callable[[], None] | None = None
|
||||
self._networks_updated: Callable[[list[Network]], None] | None = None
|
||||
self._disconnected: Callable[[], None] | None = None
|
||||
|
||||
@@ -154,7 +154,7 @@ class WifiManager:
|
||||
|
||||
def set_callbacks(self, need_auth: Callable[[str], None],
|
||||
activated: Callable[[], None] | None,
|
||||
forgotten: Callable[[str], None],
|
||||
forgotten: Callable[[], None],
|
||||
networks_updated: Callable[[list[Network]], None],
|
||||
disconnected: Callable[[], None]):
|
||||
self._need_auth = need_auth
|
||||
@@ -163,6 +163,15 @@ class WifiManager:
|
||||
self._networks_updated = networks_updated
|
||||
self._disconnected = disconnected
|
||||
|
||||
def _enqueue_callback(self, cb: Callable, *args):
|
||||
self._callback_queue.append(lambda: cb(*args))
|
||||
|
||||
def process_callbacks(self):
|
||||
# Call from UI thread to run any pending callbacks
|
||||
to_run, self._callback_queue = self._callback_queue, []
|
||||
for cb in to_run:
|
||||
cb()
|
||||
|
||||
def set_active(self, active: bool):
|
||||
self._active = active
|
||||
|
||||
@@ -187,7 +196,6 @@ class WifiManager:
|
||||
|
||||
with self._conn_monitor.filter(rule, bufsize=SIGNAL_QUEUE_SIZE) as q:
|
||||
while not self._exit:
|
||||
# TODO: always run, and ensure callbacks don't block UI thread
|
||||
if not self._active:
|
||||
time.sleep(1)
|
||||
continue
|
||||
@@ -204,19 +212,19 @@ class WifiManager:
|
||||
if new_state == NMDeviceState.NEED_AUTH and change_reason == NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT and len(self._connecting_to_ssid):
|
||||
self.forget_connection(self._connecting_to_ssid, block=True)
|
||||
if self._need_auth is not None:
|
||||
self._need_auth(self._connecting_to_ssid)
|
||||
self._enqueue_callback(self._need_auth, self._connecting_to_ssid)
|
||||
self._connecting_to_ssid = ""
|
||||
|
||||
elif new_state == NMDeviceState.ACTIVATED:
|
||||
if self._activated is not None:
|
||||
self._update_networks()
|
||||
self._activated()
|
||||
self._enqueue_callback(self._activated)
|
||||
self._connecting_to_ssid = ""
|
||||
|
||||
elif new_state == NMDeviceState.DISCONNECTED and change_reason != NM_DEVICE_STATE_REASON_NEW_ACTIVATION:
|
||||
self._connecting_to_ssid = ""
|
||||
if self._disconnected is not None:
|
||||
self._disconnected()
|
||||
self._enqueue_callback(self._disconnected)
|
||||
|
||||
def _network_scanner(self):
|
||||
self._wait_for_wifi_device()
|
||||
@@ -324,7 +332,7 @@ class WifiManager:
|
||||
|
||||
if self._forgotten is not None:
|
||||
self._update_networks()
|
||||
self._forgotten(ssid)
|
||||
self._enqueue_callback(self._forgotten)
|
||||
|
||||
if block:
|
||||
worker()
|
||||
@@ -400,7 +408,7 @@ class WifiManager:
|
||||
self._networks = networks
|
||||
|
||||
if self._networks_updated is not None:
|
||||
self._networks_updated(self._networks)
|
||||
self._enqueue_callback(self._networks_updated, self._networks)
|
||||
|
||||
def __del__(self):
|
||||
self.stop()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from enum import IntEnum
|
||||
from functools import partial
|
||||
from threading import Lock
|
||||
from typing import cast
|
||||
|
||||
import pyray as rl
|
||||
@@ -50,7 +49,6 @@ class WifiManagerUI(Widget):
|
||||
self._networks: list[Network] = []
|
||||
self._networks_buttons: dict[str, Button] = {}
|
||||
self._forget_networks_buttons: dict[str, Button] = {}
|
||||
self._lock = Lock()
|
||||
self._confirm_dialog = ConfirmDialog("", "Forget", "Cancel")
|
||||
|
||||
self.wifi_manager.set_callbacks(need_auth=self._on_need_auth,
|
||||
@@ -71,21 +69,22 @@ class WifiManagerUI(Widget):
|
||||
gui_app.texture(icon, ICON_SIZE, ICON_SIZE)
|
||||
|
||||
def _render(self, rect: rl.Rectangle):
|
||||
with self._lock:
|
||||
if not self._networks:
|
||||
gui_label(rect, "Scanning Wi-Fi networks...", 72, alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER)
|
||||
return
|
||||
self.wifi_manager.process_callbacks()
|
||||
|
||||
if self.state == UIState.NEEDS_AUTH and self._state_network:
|
||||
self.keyboard.set_title("Wrong password" if self._password_retry else "Enter password", f"for {self._state_network.ssid}")
|
||||
self.keyboard.reset()
|
||||
gui_app.set_modal_overlay(self.keyboard, lambda result: self._on_password_entered(cast(Network, self._state_network), result))
|
||||
elif self.state == UIState.SHOW_FORGET_CONFIRM and self._state_network:
|
||||
self._confirm_dialog.set_text(f'Forget Wi-Fi Network "{self._state_network.ssid}"?')
|
||||
self._confirm_dialog.reset()
|
||||
gui_app.set_modal_overlay(self._confirm_dialog, callback=lambda result: self.on_forgot_confirm_finished(self._state_network, result))
|
||||
else:
|
||||
self._draw_network_list(rect)
|
||||
if not self._networks:
|
||||
gui_label(rect, "Scanning Wi-Fi networks...", 72, alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER)
|
||||
return
|
||||
|
||||
if self.state == UIState.NEEDS_AUTH and self._state_network:
|
||||
self.keyboard.set_title("Wrong password" if self._password_retry else "Enter password", f"for {self._state_network.ssid}")
|
||||
self.keyboard.reset()
|
||||
gui_app.set_modal_overlay(self.keyboard, lambda result: self._on_password_entered(cast(Network, self._state_network), result))
|
||||
elif self.state == UIState.SHOW_FORGET_CONFIRM and self._state_network:
|
||||
self._confirm_dialog.set_text(f'Forget Wi-Fi Network "{self._state_network.ssid}"?')
|
||||
self._confirm_dialog.reset()
|
||||
gui_app.set_modal_overlay(self._confirm_dialog, callback=lambda result: self.on_forgot_confirm_finished(self._state_network, result))
|
||||
else:
|
||||
self._draw_network_list(rect)
|
||||
|
||||
def _on_password_entered(self, network: Network, result: int):
|
||||
if result == 1:
|
||||
@@ -211,36 +210,31 @@ class WifiManagerUI(Widget):
|
||||
self.wifi_manager.forget_connection(network.ssid)
|
||||
|
||||
def _on_network_updated(self, networks: list[Network]):
|
||||
with self._lock:
|
||||
self._networks = networks
|
||||
for n in self._networks:
|
||||
self._networks_buttons[n.ssid] = Button(n.ssid, partial(self._networks_buttons_callback, n), font_size=55, text_alignment=TextAlignment.LEFT,
|
||||
button_style=ButtonStyle.NO_EFFECT)
|
||||
self._forget_networks_buttons[n.ssid] = Button("Forget", partial(self._forget_networks_buttons_callback, n), button_style=ButtonStyle.FORGET_WIFI,
|
||||
font_size=45)
|
||||
self._networks = networks
|
||||
for n in self._networks:
|
||||
self._networks_buttons[n.ssid] = Button(n.ssid, partial(self._networks_buttons_callback, n), font_size=55, text_alignment=TextAlignment.LEFT,
|
||||
button_style=ButtonStyle.NO_EFFECT)
|
||||
self._forget_networks_buttons[n.ssid] = Button("Forget", partial(self._forget_networks_buttons_callback, n), button_style=ButtonStyle.FORGET_WIFI,
|
||||
font_size=45)
|
||||
|
||||
def _on_need_auth(self, ssid):
|
||||
with self._lock:
|
||||
network = next((n for n in self._networks if n.ssid == ssid), None)
|
||||
if network:
|
||||
self.state = UIState.NEEDS_AUTH
|
||||
self._state_network = network
|
||||
self._password_retry = True
|
||||
network = next((n for n in self._networks if n.ssid == ssid), None)
|
||||
if network:
|
||||
self.state = UIState.NEEDS_AUTH
|
||||
self._state_network = network
|
||||
self._password_retry = True
|
||||
|
||||
def _on_activated(self):
|
||||
with self._lock:
|
||||
if self.state == UIState.CONNECTING:
|
||||
self.state = UIState.IDLE
|
||||
if self.state == UIState.CONNECTING:
|
||||
self.state = UIState.IDLE
|
||||
|
||||
def _on_forgotten(self, ssid):
|
||||
with self._lock:
|
||||
if self.state == UIState.FORGETTING:
|
||||
self.state = UIState.IDLE
|
||||
def _on_forgotten(self):
|
||||
if self.state == UIState.FORGETTING:
|
||||
self.state = UIState.IDLE
|
||||
|
||||
def _on_disconnected(self):
|
||||
with self._lock:
|
||||
if self.state == UIState.CONNECTING:
|
||||
self.state = UIState.IDLE
|
||||
if self.state == UIState.CONNECTING:
|
||||
self.state = UIState.IDLE
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
Reference in New Issue
Block a user