From 7e4e739e8d5bcecaea825e2cac4b565c520edc40 Mon Sep 17 00:00:00 2001 From: archipelago Date: Fri, 31 Jul 2026 04:01:15 -0400 Subject: [PATCH] fix(02-review): WR-05 forward abort signal through vpnStatus()/dnsStatus() server.network-summary's fetcher batches four RPCs but only two forwarded the AbortSignal useCachedResource provides for abort-on-unmount; rpcClient.vpnStatus()/dnsStatus() had no signal parameter at all, so aborter.abort() couldn't cancel them, partially defeating the documented abort-on-unmount contract for this resource. Add an optional signal parameter to both convenience methods (mirroring the pattern used throughout rpc-client.ts) and forward it from Server.vue. Co-Authored-By: Claude --- neode-ui/src/api/rpc-client.ts | 6 ++++-- neode-ui/src/views/Server.vue | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/neode-ui/src/api/rpc-client.ts b/neode-ui/src/api/rpc-client.ts index fbccb4f6..5f147a10 100644 --- a/neode-ui/src/api/rpc-client.ts +++ b/neode-ui/src/api/rpc-client.ts @@ -1001,7 +1001,7 @@ class RPCClient { } // VPN - async vpnStatus(): Promise<{ + async vpnStatus(signal?: AbortSignal): Promise<{ connected: boolean provider?: string interface?: string @@ -1021,6 +1021,7 @@ class RPCClient { return this.call({ method: 'vpn.status', params: {}, + signal, dedup: true, // read-only status; safe to collapse concurrent callers (PERF-02) }) } @@ -1082,7 +1083,7 @@ class RPCClient { } // DNS - async dnsStatus(): Promise<{ + async dnsStatus(signal?: AbortSignal): Promise<{ provider: string servers: string[] doh_enabled: boolean @@ -1092,6 +1093,7 @@ class RPCClient { return this.call({ method: 'network.dns-status', params: {}, + signal, dedup: true, // read-only status; safe to collapse concurrent callers (PERF-02) }) } diff --git a/neode-ui/src/views/Server.vue b/neode-ui/src/views/Server.vue index d225eb21..656aec48 100644 --- a/neode-ui/src/views/Server.vue +++ b/neode-ui/src/views/Server.vue @@ -477,8 +477,8 @@ const networkRes: CachedResource = useCachedResource({ const [diagRes, fwdRes, vpnRes, dnsRes] = await Promise.allSettled([ rpcClient.call<{ wan_ip: string | null; nat_type: string; upnp_available: boolean; tor_connected: boolean; wifi_count?: number }>({ method: 'network.diagnostics', signal, dedup: true, maxRetries: 1 }), rpcClient.call<{ forwards: unknown[] }>({ method: 'router.list-forwards', signal, dedup: true, maxRetries: 1 }), - rpcClient.vpnStatus(), - rpcClient.dnsStatus(), + rpcClient.vpnStatus(signal), + rpcClient.dnsStatus(signal), ]) if (diagRes.status === 'fulfilled') { next.torConnected = diagRes.value.tor_connected; next.wifiCount = diagRes.value.wifi_count !== undefined ? `${diagRes.value.wifi_count} configured` : 'N/A'; next.wifiSsid = (diagRes.value as { wifi_ssid?: string | null }).wifi_ssid ?? null } if (fwdRes.status === 'fulfilled') { const c = fwdRes.value.forwards?.length ?? 0; next.forwardCount = `${c} rule${c !== 1 ? 's' : ''}` }