import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useCallback, useState } from 'react'; import * as api from '../api/apiClient'; import type { BridgeCreateRequest, BridgeInfo, BridgeRemoveRequest, FullState, InterfaceInfo, RouteInfo, } from '../types/network'; import { SnifferStatusResponse } from '../types/sniffer'; const TEN_SECONDS = 1000 * 10; const FIVE_SECONDS = 1000 * 5; export function useBackendAPI() { const queryClient = useQueryClient(); const [interfacesEnabled, setInterfacesEnabled] = useState(false); const [linksEnabled, setLinksEnabled] = useState(false); const [routesEnabled, setRoutesEnabled] = useState(false); const [bridgesEnabled, setBridgesEnabled] = useState(false); const [fullStateEnabled, setFullStateEnabled] = useState(false); const [snifferStatusEnabled, setSnifferStatusEnabled] = useState(false); const commonOptions = { refetchOnWindowFocus: true, staleTime: TEN_SECONDS, }; const interfacesQuery = useQuery({ queryKey: ['interfaces'], queryFn: api.fetchInterfaces, enabled: interfacesEnabled, ...commonOptions, }); const linksQuery = useQuery({ queryKey: ['links'], queryFn: api.fetchLinks, enabled: linksEnabled, ...commonOptions, }); const routesQuery = useQuery({ queryKey: ['routes'], queryFn: api.fetchRoutes, enabled: routesEnabled, ...commonOptions, }); const bridgesQuery = useQuery({ queryKey: ['bridges'], queryFn: api.fetchBridges, enabled: bridgesEnabled, ...commonOptions, }); const fullStateQuery = useQuery({ queryKey: ['full-state'], queryFn: api.fetchFullState, enabled: fullStateEnabled, ...commonOptions, }); const snifferStatusQuery = useQuery({ queryKey: ['sniffer-status'], queryFn: api.fetchSnifferStatus, enabled: snifferStatusEnabled, ...commonOptions, }); const fetchInterfaces = useCallback(async () => { const result = await queryClient.fetchQuery({ queryKey: ['interfaces'], queryFn: api.fetchInterfaces, staleTime: TEN_SECONDS, }); setInterfacesEnabled(true); return result; }, [queryClient]); const fetchLinks = useCallback(async () => { const result = await queryClient.fetchQuery({ queryKey: ['links'], queryFn: api.fetchLinks, staleTime: TEN_SECONDS, }); setLinksEnabled(true); return result; }, [queryClient]); const fetchRoutes = useCallback(async () => { const result = await queryClient.fetchQuery({ queryKey: ['routes'], queryFn: api.fetchRoutes, staleTime: TEN_SECONDS, }); setRoutesEnabled(true); return result; }, [queryClient]); const fetchBridges = useCallback(async () => { const result = await queryClient.fetchQuery({ queryKey: ['bridges'], queryFn: api.fetchBridges, staleTime: TEN_SECONDS, }); setBridgesEnabled(true); return result; }, [queryClient]); const fetchFullState = useCallback(async () => { const result = await queryClient.fetchQuery({ queryKey: ['full-state'], queryFn: api.fetchFullState, staleTime: FIVE_SECONDS, }); setFullStateEnabled(true); return result; }, [queryClient]); const fetchSnifferStatus = useCallback(async () => { const result = await queryClient.fetchQuery({ queryKey: ['sniffer-status'], queryFn: api.fetchSnifferStatus, staleTime: FIVE_SECONDS, }); setSnifferStatusEnabled(true); return result; }, [queryClient]); const [isCreating, setIsCreating] = useState(false); const [isRemoving, setIsRemoving] = useState(false); async function createBridge(payload: BridgeCreateRequest) { setIsCreating(true); try { await api.createBridge(payload); await queryClient.invalidateQueries({ queryKey: ['bridges'] }); await queryClient.invalidateQueries({ queryKey: ['full-state'] }); await queryClient.invalidateQueries({ queryKey: ['interfaces'] }); } catch (error) { const message = error instanceof Error ? error.message : typeof error === 'string' ? error : 'Create bridge failed'; throw new Error(message); } finally { setIsCreating(false); } } async function removeBridge(payload: BridgeRemoveRequest) { setIsRemoving(true); try { await api.removeBridge(payload); await queryClient.invalidateQueries({ queryKey: ['bridges'] }); await queryClient.invalidateQueries({ queryKey: ['full-state'] }); await queryClient.invalidateQueries({ queryKey: ['interfaces'] }); await queryClient.invalidateQueries({ queryKey: ['sniffer-status'] }); } catch (error) { const message = error instanceof Error ? error.message : typeof error === 'string' ? error : 'Remove bridge failed'; throw new Error(message); } finally { setIsRemoving(false); } } function refreshInterfaces() { return queryClient.invalidateQueries({ queryKey: ['interfaces'] }); } function refreshLinks() { return queryClient.invalidateQueries({ queryKey: ['links'] }); } function refreshRoutes() { return queryClient.invalidateQueries({ queryKey: ['routes'] }); } function refreshBridges() { return queryClient.invalidateQueries({ queryKey: ['bridges'] }); } function refreshFullState() { return queryClient.invalidateQueries({ queryKey: ['full-state'] }); } function refreshSnifferStatus() { return queryClient.invalidateQueries({ queryKey: ['sniffer-status'] }); } function refreshAll() { refreshInterfaces(); refreshLinks(); refreshRoutes(); refreshBridges(); refreshFullState(); refreshSnifferStatus(); } return { interfacesQuery, linksQuery, routesQuery, bridgesQuery, fullStateQuery, snifferStatusQuery, fetchInterfaces, fetchLinks, fetchRoutes, fetchBridges, fetchFullState, fetchSnifferStatus, createBridge, removeBridge, isCreating, isRemoving, refreshInterfaces, refreshLinks, refreshRoutes, refreshBridges, refreshFullState, refreshSnifferStatus, refreshAll, }; }