fix: VPN IP dedup, status polling, pair-a-device text

- VPN status: don't show WG IP as NostrVPN IP when tunnel not up
- VPN section polls every 15s so IP updates after pairing
- NostrVPN shows "Pair a device" when service active but no tunnel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-04-10 04:48:08 -04:00
parent b9044e58c7
commit b7ff0b1d38
2 changed files with 22 additions and 3 deletions

View File

@@ -46,11 +46,17 @@ impl RpcHandler {
let wg_pubkey = tokio::fs::read_to_string("/var/lib/archipelago/wireguard/public.key")
.await.ok().map(|s| s.trim().to_string());
// Don't report NostrVPN ip_address if it's the same as WireGuard (means tunnel not up)
let nvpn_ip = status.ip_address.as_ref().and_then(|ip| {
let clean = ip.split('/').next().unwrap_or(ip);
if wg_ip.as_deref() == Some(clean) { None } else { Some(ip.clone()) }
});
Ok(serde_json::json!({
"connected": status.connected || wg_ip.is_some(),
"provider": status.provider,
"interface": status.interface,
"ip_address": status.ip_address,
"ip_address": nvpn_ip,
"hostname": status.hostname,
"peers_connected": status.peers_connected,
"bytes_in": status.bytes_in,

View File

@@ -214,7 +214,7 @@
<div class="w-2 h-2 rounded-full" :class="networkData.vpnIp ? 'bg-green-400' : 'bg-white/20'"></div>
<span class="text-xs text-white/50">NostrVPN</span>
</div>
<span class="text-sm font-mono" :class="networkData.vpnIp ? 'text-white' : 'text-white/30'">{{ networkData.vpnIp || 'Not active' }}</span>
<span class="text-sm font-mono" :class="networkData.vpnIp ? 'text-white' : 'text-white/30'">{{ networkData.vpnIp || (networkData.vpnConnected ? 'Pair a device' : 'Not active') }}</span>
</div>
</div>
@@ -444,7 +444,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { rpcClient } from '@/api/rpc-client'
import { useAppStore } from '@/stores/app'
import QuickActionsCard from './server/QuickActionsCard.vue'
@@ -805,6 +805,19 @@ async function createService(name: string, port: number | null) {
}
onMounted(() => { checkTorStatus(); loadNetworkData(); loadInterfaces(); loadDiskStatus(); loadTorServices(); loadVpnPeers() })
// Poll VPN status every 15s so IP updates after pairing
const vpnPollInterval = setInterval(async () => {
try {
const vpnRes = await rpcClient.vpnStatus()
networkData.value.vpnConnected = vpnRes.connected
networkData.value.vpnProvider = vpnRes.provider ?? ''
networkData.value.vpnIp = (vpnRes.ip_address ?? '').replace(/\/\d+$/, '')
networkData.value.wgIp = vpnRes.wg_ip ?? ''
} catch { /* ignore */ }
}, 15000)
onUnmounted(() => clearInterval(vpnPollInterval))
watch(showWifiModal, (open) => { if (open) scanWifi() })
watch(showDnsModal, (open) => { if (open) { dnsSelectedProvider.value = networkData.value.dnsProvider || 'system'; dnsError.value = '' } })