mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-04-07 13:54:00 +08:00
WifiManager: cache connections until new/removed connection (#37175)
* new/removed conns signal * clean up * only get connections when adding/removing not every refresh * add debug * block * Revert "block" This reverts commit 30bbffca8d2db21c53d7a3601ae46bf05e2a7cd5. * rm debug * block on any new message, faster conn rem/add reaction * better names
This commit is contained in:
@@ -146,6 +146,7 @@ class WifiManager:
|
||||
self._wifi_device: str | None = None
|
||||
|
||||
# State
|
||||
self._connections: dict[str, str] = {} # ssid -> connection path, updated via NM signals
|
||||
self._connecting_to_ssid: str = ""
|
||||
self._ipv4_address: str = ""
|
||||
self._current_network_metered: MeteredType = MeteredType.UNKNOWN
|
||||
@@ -181,7 +182,8 @@ class WifiManager:
|
||||
self._scan_thread.start()
|
||||
self._state_thread.start()
|
||||
|
||||
if Params is not None and self._tethering_ssid not in self._get_connections():
|
||||
self._update_connections()
|
||||
if Params is not None and self._tethering_ssid not in self._connections:
|
||||
self._add_tethering_connection()
|
||||
|
||||
self._tethering_password = self._get_tethering_password()
|
||||
@@ -235,45 +237,69 @@ class WifiManager:
|
||||
self._last_network_update = 0.0
|
||||
|
||||
def _monitor_state(self):
|
||||
rule = MatchRule(
|
||||
type="signal",
|
||||
interface=NM_DEVICE_IFACE,
|
||||
member="StateChanged",
|
||||
path=self._wifi_device,
|
||||
# Filter for signals
|
||||
rules = (
|
||||
MatchRule(
|
||||
type="signal",
|
||||
interface=NM_DEVICE_IFACE,
|
||||
member="StateChanged",
|
||||
path=self._wifi_device,
|
||||
),
|
||||
MatchRule(
|
||||
type="signal",
|
||||
interface=NM_SETTINGS_IFACE,
|
||||
member="NewConnection",
|
||||
path=NM_SETTINGS_PATH,
|
||||
),
|
||||
MatchRule(
|
||||
type="signal",
|
||||
interface=NM_SETTINGS_IFACE,
|
||||
member="ConnectionRemoved",
|
||||
path=NM_SETTINGS_PATH,
|
||||
)
|
||||
)
|
||||
|
||||
# Filter for StateChanged signal
|
||||
self._conn_monitor.send_and_get_reply(message_bus.AddMatch(rule))
|
||||
for rule in rules:
|
||||
self._conn_monitor.send_and_get_reply(message_bus.AddMatch(rule))
|
||||
|
||||
with self._conn_monitor.filter(rule, bufsize=SIGNAL_QUEUE_SIZE) as q:
|
||||
with (self._conn_monitor.filter(rules[0], bufsize=SIGNAL_QUEUE_SIZE) as state_q,
|
||||
self._conn_monitor.filter(rules[1], bufsize=SIGNAL_QUEUE_SIZE) as new_conn_q,
|
||||
self._conn_monitor.filter(rules[2], bufsize=SIGNAL_QUEUE_SIZE) as removed_conn_q):
|
||||
while not self._exit:
|
||||
if not self._active:
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
# Block until a matching signal arrives
|
||||
try:
|
||||
msg = self._conn_monitor.recv_until_filtered(q, timeout=1)
|
||||
self._conn_monitor.recv_messages(timeout=1)
|
||||
except TimeoutError:
|
||||
continue
|
||||
|
||||
new_state, previous_state, change_reason = msg.body
|
||||
# Connection added/removed
|
||||
if len(new_conn_q) or len(removed_conn_q):
|
||||
new_conn_q.clear()
|
||||
removed_conn_q.clear()
|
||||
self._update_connections()
|
||||
|
||||
# BAD PASSWORD
|
||||
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)
|
||||
self._enqueue_callbacks(self._need_auth, self._connecting_to_ssid)
|
||||
self._connecting_to_ssid = ""
|
||||
# Device state changes
|
||||
while len(state_q):
|
||||
new_state, previous_state, change_reason = state_q.popleft().body
|
||||
|
||||
elif new_state == NMDeviceState.ACTIVATED:
|
||||
if len(self._activated):
|
||||
self._update_networks()
|
||||
self._enqueue_callbacks(self._activated)
|
||||
self._connecting_to_ssid = ""
|
||||
# BAD PASSWORD
|
||||
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)
|
||||
self._enqueue_callbacks(self._need_auth, self._connecting_to_ssid)
|
||||
self._connecting_to_ssid = ""
|
||||
|
||||
elif new_state == NMDeviceState.DISCONNECTED and change_reason != NM_DEVICE_STATE_REASON_NEW_ACTIVATION:
|
||||
self._connecting_to_ssid = ""
|
||||
self._enqueue_callbacks(self._forgotten)
|
||||
elif new_state == NMDeviceState.ACTIVATED:
|
||||
if len(self._activated):
|
||||
self._update_networks()
|
||||
self._enqueue_callbacks(self._activated)
|
||||
self._connecting_to_ssid = ""
|
||||
|
||||
elif new_state == NMDeviceState.DISCONNECTED and change_reason != NM_DEVICE_STATE_REASON_NEW_ACTIVATION:
|
||||
self._connecting_to_ssid = ""
|
||||
self._enqueue_callbacks(self._forgotten)
|
||||
|
||||
def _network_scanner(self):
|
||||
while not self._exit:
|
||||
@@ -307,7 +333,7 @@ class WifiManager:
|
||||
cloudlog.exception(f"Error getting adapter type {adapter_type}: {e}")
|
||||
return None
|
||||
|
||||
def _get_connections(self) -> dict[str, str]:
|
||||
def _update_connections(self) -> None:
|
||||
settings_addr = DBusAddress(NM_SETTINGS_PATH, bus_name=NM, interface=NM_SETTINGS_IFACE)
|
||||
known_connections = self._router_main.send_and_get_reply(new_method_call(settings_addr, 'ListConnections')).body[0]
|
||||
|
||||
@@ -323,7 +349,7 @@ class WifiManager:
|
||||
ssid = settings['802-11-wireless']['ssid'][1].decode("utf-8", "replace")
|
||||
if ssid != "":
|
||||
conns[ssid] = conn_path
|
||||
return conns
|
||||
self._connections = conns
|
||||
|
||||
def _get_active_connections(self):
|
||||
return self._router_main.send_and_get_reply(Properties(self._nm).get('ActiveConnections')).body[0][1]
|
||||
@@ -413,7 +439,7 @@ class WifiManager:
|
||||
|
||||
def forget_connection(self, ssid: str, block: bool = False):
|
||||
def worker():
|
||||
conn_path = self._get_connections().get(ssid, None)
|
||||
conn_path = self._connections.get(ssid, None)
|
||||
if conn_path is not None:
|
||||
conn_addr = DBusAddress(conn_path, bus_name=NM, interface=NM_CONNECTION_IFACE)
|
||||
self._router_main.send_and_get_reply(new_method_call(conn_addr, 'Delete'))
|
||||
@@ -429,7 +455,7 @@ class WifiManager:
|
||||
|
||||
def activate_connection(self, ssid: str, block: bool = False):
|
||||
def worker():
|
||||
conn_path = self._get_connections().get(ssid, None)
|
||||
conn_path = self._connections.get(ssid, None)
|
||||
if conn_path is not None:
|
||||
if self._wifi_device is None:
|
||||
cloudlog.warning("No WiFi device found")
|
||||
@@ -465,7 +491,7 @@ class WifiManager:
|
||||
|
||||
def set_tethering_password(self, password: str):
|
||||
def worker():
|
||||
conn_path = self._get_connections().get(self._tethering_ssid, None)
|
||||
conn_path = self._connections.get(self._tethering_ssid, None)
|
||||
if conn_path is None:
|
||||
cloudlog.warning('No tethering connection found')
|
||||
return
|
||||
@@ -490,7 +516,7 @@ class WifiManager:
|
||||
threading.Thread(target=worker, daemon=True).start()
|
||||
|
||||
def _get_tethering_password(self) -> str:
|
||||
conn_path = self._get_connections().get(self._tethering_ssid, None)
|
||||
conn_path = self._connections.get(self._tethering_ssid, None)
|
||||
if conn_path is None:
|
||||
cloudlog.warning('No tethering connection found')
|
||||
return ''
|
||||
@@ -601,8 +627,7 @@ class WifiManager:
|
||||
# catch all for parsing errors
|
||||
cloudlog.exception(f"Failed to parse AP properties for {ap_path}")
|
||||
|
||||
known_connections = self._get_connections()
|
||||
networks = [Network.from_dbus(ssid, ap_list, ssid in known_connections) for ssid, ap_list in aps.items()]
|
||||
networks = [Network.from_dbus(ssid, ap_list, ssid in self._connections) for ssid, ap_list in aps.items()]
|
||||
# sort with quantized strength to reduce jumping
|
||||
networks.sort(key=lambda n: (-n.is_connected, -n.is_saved, -round(n.strength / 100 * 2), n.ssid.lower()))
|
||||
self._networks = networks
|
||||
|
||||
Reference in New Issue
Block a user