Files
mitm-webserver/frontend/src/hooks/useBackendAPI.ts
malmert b60a1d3118
Some checks failed
Build and Deploy MITM Webserver / build (push) Failing after 3s
file structure and comments unified
2026-03-06 19:03:26 +01:00

230 lines
6.3 KiB
TypeScript

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<InterfaceInfo[]>({
queryKey: ['interfaces'],
queryFn: api.fetchInterfaces,
enabled: interfacesEnabled,
...commonOptions,
});
const linksQuery = useQuery<InterfaceInfo[]>({
queryKey: ['links'],
queryFn: api.fetchLinks,
enabled: linksEnabled,
...commonOptions,
});
const routesQuery = useQuery<RouteInfo[]>({
queryKey: ['routes'],
queryFn: api.fetchRoutes,
enabled: routesEnabled,
...commonOptions,
});
const bridgesQuery = useQuery<BridgeInfo[]>({
queryKey: ['bridges'],
queryFn: api.fetchBridges,
enabled: bridgesEnabled,
...commonOptions,
});
const fullStateQuery = useQuery<FullState>({
queryKey: ['full-state'],
queryFn: api.fetchFullState,
enabled: fullStateEnabled,
...commonOptions,
});
const snifferStatusQuery = useQuery<SnifferStatusResponse>({
queryKey: ['sniffer-status'],
queryFn: api.fetchSnifferStatus,
enabled: snifferStatusEnabled,
...commonOptions,
});
const fetchInterfaces = useCallback(async () => {
const result = await queryClient.fetchQuery<InterfaceInfo[]>({
queryKey: ['interfaces'],
queryFn: api.fetchInterfaces,
staleTime: TEN_SECONDS,
});
setInterfacesEnabled(true);
return result;
}, [queryClient]);
const fetchLinks = useCallback(async () => {
const result = await queryClient.fetchQuery<InterfaceInfo[]>({
queryKey: ['links'],
queryFn: api.fetchLinks,
staleTime: TEN_SECONDS,
});
setLinksEnabled(true);
return result;
}, [queryClient]);
const fetchRoutes = useCallback(async () => {
const result = await queryClient.fetchQuery<RouteInfo[]>({
queryKey: ['routes'],
queryFn: api.fetchRoutes,
staleTime: TEN_SECONDS,
});
setRoutesEnabled(true);
return result;
}, [queryClient]);
const fetchBridges = useCallback(async () => {
const result = await queryClient.fetchQuery<BridgeInfo[]>({
queryKey: ['bridges'],
queryFn: api.fetchBridges,
staleTime: TEN_SECONDS,
});
setBridgesEnabled(true);
return result;
}, [queryClient]);
const fetchFullState = useCallback(async () => {
const result = await queryClient.fetchQuery<FullState>({
queryKey: ['full-state'],
queryFn: api.fetchFullState,
staleTime: FIVE_SECONDS,
});
setFullStateEnabled(true);
return result;
}, [queryClient]);
const fetchSnifferStatus = useCallback(async () => {
const result = await queryClient.fetchQuery<SnifferStatusResponse>({
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,
};
}