/** * useMonitoring Hook * Encapsulates all monitoring logic and state management */ import { useState, useCallback, useRef, useEffect } from 'react'; import { analyzeFrame } from '../services/geminiService'; import { SecurityEvent, SystemStats, ThreatSeverity } from '../types'; interface UseMonitoringReturn { isMonitoring: boolean; backendConnected: boolean; // ✅ added events: SecurityEvent[]; currentAnalysis: SecurityEvent | null; stats: SystemStats; toggleMonitoring: () => void; handleFrameCapture: (base64: string) => Promise; clearEvents: () => void; resetStats: () => void; } export const useMonitoring = (): UseMonitoringReturn => { const [isMonitoring, setIsMonitoring] = useState(false); const [backendConnected, setBackendConnected] = useState(true); // ✅ added const [events, setEvents] = useState([]); const [currentAnalysis, setCurrentAnalysis] = useState(null); const [stats, setStats] = useState({ scansPerformed: 0, incidentsDetected: 0, lastScanTime: Date.now(), uptime: 0, cpuUsage: 12, memoryUsage: 24 }); const audioContextRef = useRef(null); const startTimeRef = useRef(Date.now()); // Initialize audio context useEffect(() => { audioContextRef.current = new (window.AudioContext || (window as any).webkitAudioContext)(); return () => { audioContextRef.current?.close(); }; }, []); // Update uptime useEffect(() => { if (!isMonitoring) return; const interval = setInterval(() => { setStats(prev => ({ ...prev, uptime: Math.floor((Date.now() - startTimeRef.current) / 1000) })); }, 1000); return () => clearInterval(interval); }, [isMonitoring]); const playAlert = useCallback(() => { const ctx = audioContextRef.current; if (!ctx) return; const oscillator = ctx.createOscillator(); const gainNode = ctx.createGain(); oscillator.connect(gainNode); gainNode.connect(ctx.destination); oscillator.frequency.value = 800; oscillator.type = 'sawtooth'; gainNode.gain.value = 0.1; oscillator.start(); oscillator.stop(ctx.currentTime + 0.5); }, []); const handleFrameCapture = useCallback(async (base64: string) => { if (!isMonitoring) return; // Update scan stats setStats(prev => ({ ...prev, scansPerformed: prev.scansPerformed + 1, lastScanTime: Date.now(), cpuUsage: Math.min(100, Math.floor(Math.random() * 40) + 40) })); try { const result = await analyzeFrame(base64); // backend reachable setBackendConnected(true); if (result) { const newEvent: SecurityEvent = { id: crypto.randomUUID(), timestamp: Date.now(), incident: result.incident, type: result.type, severity: result.severity as ThreatSeverity, confidence: result.confidence, reasoning: result.reasoning, recommended_actions: result.recommended_actions, snapshot: base64 }; setCurrentAnalysis(newEvent); if (result.incident) { setEvents(prev => [...prev, newEvent]); setStats(prev => ({ ...prev, incidentsDetected: prev.incidentsDetected + 1 })); // Play alert for high severity if (result.severity === 'high' || result.severity === 'critical') { playAlert(); } } } } catch (error) { console.error('Frame analysis error:', error); // backend unreachable setBackendConnected(false); // ✅ logical fallback } finally { // CPU settle setTimeout(() => { setStats(prev => ({ ...prev, cpuUsage: Math.floor(Math.random() * 15) + 10 })); }, 500); } }, [isMonitoring, playAlert]); const toggleMonitoring = useCallback(() => { setIsMonitoring(prev => { const newState = !prev; if (newState) { // Starting monitoring startTimeRef.current = Date.now(); } return newState; }); }, []); const clearEvents = useCallback(() => { setEvents([]); setCurrentAnalysis(null); }, []); const resetStats = useCallback(() => { setStats({ scansPerformed: 0, incidentsDetected: 0, lastScanTime: Date.now(), uptime: 0, cpuUsage: 12, memoryUsage: 24 }); startTimeRef.current = Date.now(); }, []); return { isMonitoring, backendConnected, // ✅ now valid events, currentAnalysis, stats, toggleMonitoring, handleFrameCapture, clearEvents, resetStats }; };