55 lines
1.8 KiB
TypeScript
55 lines
1.8 KiB
TypeScript
import { useQuery } from '@tanstack/react-query';
|
|
import { probeRelay, type RelayProbeResult } from '@/lib/relayProbe';
|
|
|
|
export type RelayStatus = 'connecting' | 'connected' | 'offline';
|
|
|
|
/**
|
|
* useRelayStatus — live reachability of a single relay URL.
|
|
*
|
|
* Backed by react-query so every row that probes the same URL shares one result
|
|
* and we don't open redundant sockets. Returns a coarse status the UI can map to
|
|
* a coloured dot:
|
|
* - 'connecting': first probe in flight (no result yet).
|
|
* - 'connected': the relay answered a Nostr handshake.
|
|
* - 'offline': the probe finished and the relay did not answer.
|
|
*
|
|
* Reconnected relays are picked up because we keep polling while offline, and
|
|
* stop polling once connected to avoid churn (a healthy relay rarely vanishes
|
|
* silently, and any real read failure elsewhere is a separate concern).
|
|
*/
|
|
export function useRelayStatus(url: string): {
|
|
status: RelayStatus;
|
|
probing: boolean;
|
|
reason: string | null;
|
|
recheck: () => void;
|
|
} {
|
|
const { data, isFetching, isFetched, refetch } = useQuery<RelayProbeResult>({
|
|
queryKey: ['relay-status', url],
|
|
queryFn: () => probeRelay(url),
|
|
// Consider a result fresh for a minute so switching sub-screens doesn't
|
|
// re-probe every relay each time.
|
|
staleTime: 60_000,
|
|
// Poll only while still offline so a relay that comes back is detected;
|
|
// once connected, stop the background churn.
|
|
refetchInterval: (query) => (query.state.data?.ok ? false : 30_000),
|
|
refetchOnWindowFocus: (query) => !query.state.data?.ok,
|
|
retry: false,
|
|
});
|
|
|
|
const status: RelayStatus = !isFetched
|
|
? 'connecting'
|
|
: data?.ok
|
|
? 'connected'
|
|
: isFetching
|
|
? 'connecting'
|
|
: 'offline';
|
|
|
|
return {
|
|
status,
|
|
probing: isFetching,
|
|
reason: data?.reason ?? null,
|
|
recheck: () => {
|
|
refetch();
|
|
},
|
|
};
|
|
}
|