From 7745155ee8eefcdabcbd17a5c210f37c410ebdf3 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sat, 12 Jul 2025 09:04:48 -0400 Subject: [PATCH] check relays asynchronously --- src/main.py | 4 +++ src/password_manager/manager.py | 40 +++++++++++++++++------- src/tests/test_auto_sync.py | 1 + src/tests/test_background_relay_check.py | 23 ++++++++++++++ src/tests/test_cli_invalid_input.py | 1 + src/tests/test_inactivity_lock.py | 2 ++ src/tests/test_menu_navigation.py | 1 + src/tests/test_menu_options.py | 1 + src/tests/test_menu_search.py | 1 + 9 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 src/tests/test_background_relay_check.py diff --git a/src/main.py b/src/main.py index d22c8d6..33c8661 100644 --- a/src/main.py +++ b/src/main.py @@ -742,6 +742,7 @@ def handle_settings(password_manager: PasswordManager) -> None: print(colored("Vault locked. Please re-enter your password.", "yellow")) password_manager.unlock_vault() password_manager.start_background_sync() + getattr(password_manager, "start_background_relay_check", lambda: None)() pause() elif choice == "13": handle_display_stats(password_manager) @@ -779,6 +780,7 @@ def display_menu( display_fn() pause() password_manager.start_background_sync() + getattr(password_manager, "start_background_relay_check", lambda: None)() while True: fp, parent_fp, child_fp = getattr( password_manager, @@ -796,6 +798,7 @@ def display_menu( password_manager.lock_vault() password_manager.unlock_vault() password_manager.start_background_sync() + getattr(password_manager, "start_background_relay_check", lambda: None)() continue # Periodically push updates to Nostr if ( @@ -819,6 +822,7 @@ def display_menu( password_manager.lock_vault() password_manager.unlock_vault() password_manager.start_background_sync() + getattr(password_manager, "start_background_relay_check", lambda: None)() continue password_manager.update_activity() if not choice: diff --git a/src/password_manager/manager.py b/src/password_manager/manager.py index 7f414ce..428d7ce 100644 --- a/src/password_manager/manager.py +++ b/src/password_manager/manager.py @@ -925,17 +925,6 @@ class PasswordManager: parent_seed=getattr(self, "parent_seed", None), ) - if hasattr(self.nostr_client, "check_relay_health"): - healthy = self.nostr_client.check_relay_health(MIN_HEALTHY_RELAYS) - if healthy < MIN_HEALTHY_RELAYS: - print( - colored( - f"Only {healthy} relay(s) responded with your latest event." - " Consider adding more relays via Settings.", - "yellow", - ) - ) - logger.debug("Managers re-initialized for the new fingerprint.") except Exception as e: @@ -984,6 +973,35 @@ class PasswordManager: self._sync_thread = threading.Thread(target=_worker, daemon=True) self._sync_thread.start() + def start_background_relay_check(self) -> None: + """Check relay health in a background thread.""" + if ( + hasattr(self, "_relay_thread") + and self._relay_thread + and self._relay_thread.is_alive() + ): + return + + def _worker() -> None: + try: + if getattr(self, "nostr_client", None) and hasattr( + self.nostr_client, "check_relay_health" + ): + healthy = self.nostr_client.check_relay_health(MIN_HEALTHY_RELAYS) + if healthy < MIN_HEALTHY_RELAYS: + print( + colored( + f"Only {healthy} relay(s) responded with your latest event." + " Consider adding more relays via Settings.", + "yellow", + ) + ) + except Exception as exc: + logger.warning(f"Relay health check failed: {exc}") + + self._relay_thread = threading.Thread(target=_worker, daemon=True) + self._relay_thread.start() + def sync_index_from_nostr_if_missing(self) -> None: """Retrieve the password database from Nostr if it doesn't exist locally.""" index_file = self.fingerprint_dir / "seedpass_entries_db.json.enc" diff --git a/src/tests/test_auto_sync.py b/src/tests/test_auto_sync.py index c5dc13c..26f0e22 100644 --- a/src/tests/test_auto_sync.py +++ b/src/tests/test_auto_sync.py @@ -23,6 +23,7 @@ def test_auto_sync_triggers_post(monkeypatch): lock_vault=lambda: None, unlock_vault=lambda: None, start_background_sync=lambda: None, + start_background_relay_check=lambda: None, ) called = False diff --git a/src/tests/test_background_relay_check.py b/src/tests/test_background_relay_check.py new file mode 100644 index 0000000..e1af48e --- /dev/null +++ b/src/tests/test_background_relay_check.py @@ -0,0 +1,23 @@ +import time +from types import SimpleNamespace +from pathlib import Path +import sys + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from password_manager.manager import PasswordManager +from constants import MIN_HEALTHY_RELAYS + + +def test_background_relay_check_runs_async(monkeypatch): + pm = PasswordManager.__new__(PasswordManager) + called = {"args": None} + pm.nostr_client = SimpleNamespace( + check_relay_health=lambda min_relays: called.__setitem__("args", min_relays) + or min_relays + ) + + pm.start_background_relay_check() + time.sleep(0.05) + + assert called["args"] == MIN_HEALTHY_RELAYS diff --git a/src/tests/test_cli_invalid_input.py b/src/tests/test_cli_invalid_input.py index 57686a9..0882df4 100644 --- a/src/tests/test_cli_invalid_input.py +++ b/src/tests/test_cli_invalid_input.py @@ -47,6 +47,7 @@ def _make_pm(called, locked=None): lock_vault=lock, unlock_vault=unlock, start_background_sync=lambda: None, + start_background_relay_check=lambda: None, ) return pm, locked diff --git a/src/tests/test_inactivity_lock.py b/src/tests/test_inactivity_lock.py index 2e7c4ed..32d81da 100644 --- a/src/tests/test_inactivity_lock.py +++ b/src/tests/test_inactivity_lock.py @@ -35,6 +35,7 @@ def test_inactivity_triggers_lock(monkeypatch): lock_vault=lock_vault, unlock_vault=unlock_vault, start_background_sync=lambda: None, + start_background_relay_check=lambda: None, ) monkeypatch.setattr(main, "timed_input", lambda *_: "") @@ -72,6 +73,7 @@ def test_input_timeout_triggers_lock(monkeypatch): lock_vault=lock_vault, unlock_vault=unlock_vault, start_background_sync=lambda: None, + start_background_relay_check=lambda: None, ) responses = iter([TimeoutError(), ""]) diff --git a/src/tests/test_menu_navigation.py b/src/tests/test_menu_navigation.py index 9b426e7..f7ef100 100644 --- a/src/tests/test_menu_navigation.py +++ b/src/tests/test_menu_navigation.py @@ -31,6 +31,7 @@ def _make_pm(calls): lock_vault=lambda: None, unlock_vault=lambda: None, start_background_sync=lambda: None, + start_background_relay_check=lambda: None, ) diff --git a/src/tests/test_menu_options.py b/src/tests/test_menu_options.py index 9638300..d70b609 100644 --- a/src/tests/test_menu_options.py +++ b/src/tests/test_menu_options.py @@ -25,6 +25,7 @@ def _make_pm(calls): lock_vault=lambda: None, unlock_vault=lambda: None, start_background_sync=lambda: None, + start_background_relay_check=lambda: None, ) diff --git a/src/tests/test_menu_search.py b/src/tests/test_menu_search.py index 01c8747..e1f78c8 100644 --- a/src/tests/test_menu_search.py +++ b/src/tests/test_menu_search.py @@ -24,6 +24,7 @@ def _make_pm(called): lock_vault=lambda: None, unlock_vault=lambda: None, start_background_sync=lambda: None, + start_background_relay_check=lambda: None, ) return pm