diff --git a/src/main.py b/src/main.py index 3dea1f7..1fa2482 100644 --- a/src/main.py +++ b/src/main.py @@ -275,12 +275,23 @@ def handle_display_npub(password_manager: PasswordManager): def _display_live_stats( password_manager: PasswordManager, interval: float = 1.0 ) -> None: - """Continuously refresh stats until the user presses Enter.""" + """Continuously refresh stats until the user presses Enter. + + Each refresh also triggers a background sync so the latest stats are + displayed if newer data exists on Nostr. + """ display_fn = getattr(password_manager, "display_stats", None) + sync_fn = getattr(password_manager, "start_background_sync", None) if not callable(display_fn): return + if callable(sync_fn): + try: + sync_fn() + except Exception as exc: # pragma: no cover - sync best effort + logging.debug("Background sync failed during stats display: %s", exc) + if not sys.stdin or not sys.stdin.isatty(): clear_screen() display_fn() @@ -292,6 +303,11 @@ def _display_live_stats( return while True: + if callable(sync_fn): + try: + sync_fn() + except Exception: # pragma: no cover - sync best effort + logging.debug("Background sync failed during stats display") clear_screen() display_fn() note = get_notification_text(password_manager) diff --git a/src/nostr/client.py b/src/nostr/client.py index 0155617..76fdb00 100644 --- a/src/nostr/client.py +++ b/src/nostr/client.py @@ -21,6 +21,7 @@ from nostr_sdk import ( Kind, KindStandard, Tag, + RelayUrl, ) from datetime import timedelta from nostr_sdk import EventId, Timestamp @@ -173,14 +174,26 @@ class NostrClient: async def _initialize_client_pool(self) -> None: if self.offline_mode or not self.relays: return + + formatted = [] + for relay in self.relays: + if isinstance(relay, str): + try: + formatted.append(RelayUrl.parse(relay)) + except Exception: + logger.error("Invalid relay URL: %s", relay) + else: + formatted.append(relay) + if hasattr(self.client, "add_relays"): - await self.client.add_relays(self.relays) + await self.client.add_relays(formatted) else: - for relay in self.relays: + for relay in formatted: await self.client.add_relay(relay) + await self.client.connect() self._connected = True - logger.info(f"NostrClient connected to relays: {self.relays}") + logger.info("NostrClient connected to relays: %s", formatted) async def _ping_relay(self, relay: str, timeout: float) -> bool: """Attempt to retrieve the latest event from a single relay.""" diff --git a/src/tests/test_nostr_client.py b/src/tests/test_nostr_client.py index 1aa998f..0fc5a61 100644 --- a/src/tests/test_nostr_client.py +++ b/src/tests/test_nostr_client.py @@ -91,7 +91,7 @@ def test_initialize_client_pool_add_relays_used(tmp_path): client = _setup_client(tmp_path, FakeAddRelaysClient) fc = client.client client.connect() - assert fc.added == [client.relays] + assert [[str(r) for r in relays] for relays in fc.added] == [client.relays] assert fc.connected is True @@ -99,7 +99,7 @@ def test_initialize_client_pool_add_relay_fallback(tmp_path): client = _setup_client(tmp_path, FakeAddRelayClient) fc = client.client client.connect() - assert fc.added == client.relays + assert [str(r) for r in fc.added] == client.relays assert fc.connected is True diff --git a/src/tests/test_stats_screen.py b/src/tests/test_stats_screen.py index f65d72d..182c7b9 100644 --- a/src/tests/test_stats_screen.py +++ b/src/tests/test_stats_screen.py @@ -9,7 +9,10 @@ import main def _make_pm(): - return SimpleNamespace(display_stats=lambda: print("stats")) + return SimpleNamespace( + display_stats=lambda: print("stats"), + start_background_sync=lambda: None, + ) def test_live_stats_shows_message(monkeypatch, capsys): @@ -36,3 +39,21 @@ def test_live_stats_shows_notification(monkeypatch, capsys): main._display_live_stats(pm) out = capsys.readouterr().out assert "note" in out + + +def test_live_stats_triggers_background_sync(monkeypatch): + called = {"sync": 0} + + pm = _make_pm() + pm.start_background_sync = lambda: called.__setitem__("sync", called["sync"] + 1) + + monkeypatch.setattr(main, "get_notification_text", lambda *_: "") + monkeypatch.setattr( + main, + "timed_input", + lambda *_: (_ for _ in ()).throw(KeyboardInterrupt()), + ) + + main._display_live_stats(pm) + + assert called["sync"] >= 1