1
0
forked from GRIN/grim

Build 55: surface the Nym/relay connection promptly (fix stuck "Connecting…")

The nostr service only refreshed its connected flag inside the select!s
sleep(30s) branch, which restarted on every incoming notification — so the
flag could lag the real relay state by 30s+ (or, under steady event flow,
never update), leaving the UI stuck on "Connecting…" even though a relay
handshake over the Nym mixnet completes in ~2s (measured). Set the flag right
after the startup connect, and poll it on an independent 2s interval; the 30s
heartbeat work (persist last-seen, TTL prune) stays on its own cadence.
This commit is contained in:
2ro
2026-06-13 21:23:09 -04:00
parent 6621dc6aaa
commit 6dff408766
+36 -12
View File
@@ -554,10 +554,23 @@ async fn run_service(svc: Arc<NostrService>, wallet: Wallet) {
svc.store.set_last_connected_at(unix_time());
svc.store.prune_processed();
// Reflect the connection the moment we reach the loop instead of leaving the
// UI on "Connecting…" until the first heartbeat — by now catch-up has run, so
// a relay is typically already up.
svc.connected
.store(relays_connected(&client).await, Ordering::Relaxed);
let mut notifications = client.notifications();
// Re-run TTL pruning periodically, not just at startup: a session that
// never restarts would otherwise let the processed-dedup store grow
// unbounded under fresh-keypair spam (the 30-day TTL never applied).
// Poll connection state on a SHORT, INDEPENDENT interval. This used to live in
// the `select!` behind a `sleep(30s)` that restarted on every notification, so
// the flag could lag the real relay state by 30s+ (or, under steady event
// flow, never update) — that's the "stuck on Connecting…" the mixnet gets
// blamed for, even though a relay handshake over Nym takes ~2s. An `interval`
// fires on its own schedule regardless of notifications; the heavier heartbeat
// work (persisting last-seen, TTL pruning) stays on a ~30s cadence.
let mut status_tick = tokio::time::interval(Duration::from_secs(2));
status_tick.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
let mut last_heartbeat = unix_time();
let mut last_prune = unix_time();
loop {
if svc.shutdown.load(Ordering::SeqCst) || !wallet.is_open() {
@@ -576,15 +589,17 @@ async fn run_service(svc: Arc<NostrService>, wallet: Wallet) {
Err(tokio::sync::broadcast::error::RecvError::Closed) => break,
}
}
_ = tokio::time::sleep(Duration::from_secs(30)) => {
// Heartbeat: persist last seen time, update connection state.
svc.store.set_last_connected_at(unix_time());
let connected = client.relays().await.values()
.any(|r| r.status() == RelayStatus::Connected);
svc.connected.store(connected, Ordering::Relaxed);
if unix_time() - last_prune >= 3600 {
svc.store.prune_processed();
last_prune = unix_time();
_ = status_tick.tick() => {
svc.connected
.store(relays_connected(&client).await, Ordering::Relaxed);
let now = unix_time();
if now - last_heartbeat >= 30 {
last_heartbeat = now;
svc.store.set_last_connected_at(now);
if now - last_prune >= 3600 {
svc.store.prune_processed();
last_prune = now;
}
}
}
}
@@ -597,6 +612,15 @@ async fn run_service(svc: Arc<NostrService>, wallet: Wallet) {
client.disconnect().await;
}
/// True when at least one relay has completed its handshake.
async fn relays_connected(client: &Client) -> bool {
client
.relays()
.await
.values()
.any(|r| r.status() == RelayStatus::Connected)
}
/// Publish kind 10050 DM relay list and, for named identities, kind 0 metadata.
async fn publish_identity(svc: &Arc<NostrService>, client: &Client) {
let relays = svc.relays();