import { useState, useEffect, useCallback, useRef } from 'react'; import { useAuthStore } from '../store/authStore'; import { pingWithCredentials, scheduleInstantMixProbeForServer } from '../api/subsonic'; export type ConnectionStatus = 'connected' | 'disconnected' | 'checking'; export function isLanUrl(url: string): boolean { try { const hostname = new URL(url.startsWith('http') ? url : `http://${url}`).hostname; return ( hostname === 'localhost' || hostname.endsWith('.local') || /^127\./.test(hostname) || /^10\./.test(hostname) || /^192\.168\./.test(hostname) || /^172\.(1[6-9]|2\d|3[01])\./.test(hostname) ); } catch { return false; } } export function useConnectionStatus() { const [status, setStatus] = useState('checking'); const [isRetrying, setIsRetrying] = useState(false); const intervalRef = useRef | null>(null); const check = useCallback(async () => { const server = useAuthStore.getState().getActiveServer(); if (!server) { setStatus('disconnected'); return; } if (!navigator.onLine) { setStatus('disconnected'); return; } const ping = await pingWithCredentials(server.url, server.username, server.password); if (ping.ok) { const sid = useAuthStore.getState().activeServerId; if (sid) { const identity = { type: ping.type, serverVersion: ping.serverVersion, openSubsonic: ping.openSubsonic, }; useAuthStore.getState().setSubsonicServerIdentity(sid, identity); scheduleInstantMixProbeForServer(sid, server.url, server.username, server.password, identity); } } setStatus(ping.ok ? 'connected' : 'disconnected'); }, []); const retry = useCallback(async () => { setIsRetrying(true); await check(); setIsRetrying(false); }, [check]); useEffect(() => { check(); intervalRef.current = setInterval(check, 120_000); const handleOnline = () => check(); const handleOffline = () => setStatus('disconnected'); window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { if (intervalRef.current) clearInterval(intervalRef.current); window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, [check]); const server = useAuthStore(s => s.getActiveServer()); return { status, isRetrying, retry, isLan: server ? isLanUrl(server.url) : false, serverName: server?.name ?? '', }; }