Files
drone-detector/client/src/contexts/SocketContext.jsx
2025-08-17 09:36:12 +02:00

193 lines
5.7 KiB
JavaScript

import React, { createContext, useContext, useEffect, useState } from 'react';
import { io } from 'socket.io-client';
import { useAuth } from './AuthContext';
import toast from 'react-hot-toast';
const SocketContext = createContext();
export const SocketProvider = ({ children }) => {
const [socket, setSocket] = useState(null);
const [connected, setConnected] = useState(false);
const [recentDetections, setRecentDetections] = useState([]);
const [deviceStatus, setDeviceStatus] = useState({});
const [movementAlerts, setMovementAlerts] = useState([]);
const [droneTracking, setDroneTracking] = useState(new Map());
const { isAuthenticated } = useAuth();
useEffect(() => {
if (isAuthenticated) {
// Initialize socket connection
const newSocket = io(process.env.NODE_ENV === 'production'
? window.location.origin
: 'http://localhost:3001', {
path: process.env.NODE_ENV === 'production' ? '/drones/socket.io/' : '/socket.io/'
});
newSocket.on('connect', () => {
console.log('Connected to server');
setConnected(true);
// Join dashboard room for general updates
newSocket.emit('join_dashboard');
toast.success('Connected to real-time updates');
});
newSocket.on('disconnect', () => {
console.log('Disconnected from server');
setConnected(false);
toast.error('Disconnected from server');
});
newSocket.on('connect_error', (error) => {
console.error('Connection error:', error);
setConnected(false);
toast.error('Failed to connect to server');
});
// Listen for drone detections
newSocket.on('drone_detection', (detection) => {
console.log('New drone detection:', detection);
setRecentDetections(prev => [detection, ...prev.slice(0, 49)]); // Keep last 50
// Update drone tracking
if (detection.movement_analysis) {
const trackingKey = `${detection.drone_id}_${detection.device_id}`;
setDroneTracking(prev => {
const newTracking = new Map(prev);
newTracking.set(trackingKey, {
droneId: detection.drone_id,
deviceId: detection.device_id,
lastDetection: detection,
analysis: detection.movement_analysis,
timestamp: Date.now()
});
return newTracking;
});
}
// Show toast notification
toast.error(
`Drone ${detection.drone_id} detected by ${detection.device?.name || `Device ${detection.device_id}`}`,
{
duration: 5000,
icon: '🚨',
}
);
});
// Listen for drone movement alerts
newSocket.on('drone_movement_alert', (alertData) => {
console.log('Drone movement alert:', alertData);
setMovementAlerts(prev => [alertData, ...prev.slice(0, 19)]); // Keep last 20 alerts
// Show priority-based notifications
const alertIcon = alertData.analysis.alertLevel >= 3 ? '🚨' :
alertData.analysis.alertLevel >= 2 ? '⚠️' : '📍';
const alertColor = alertData.analysis.alertLevel >= 3 ? 'error' :
alertData.analysis.alertLevel >= 2 ? 'warning' : 'info';
toast[alertColor === 'error' ? 'error' : alertColor === 'warning' ? 'error' : 'info'](
alertData.analysis.description,
{
duration: alertData.analysis.alertLevel >= 2 ? 10000 : 6000,
icon: alertIcon,
style: {
background: alertData.analysis.alertLevel >= 3 ? '#fee2e2' :
alertData.analysis.alertLevel >= 2 ? '#fef3c7' : '#e0f2fe'
}
}
);
});
// Listen for device heartbeats
newSocket.on('device_heartbeat', (heartbeat) => {
console.log('Device heartbeat:', heartbeat);
setDeviceStatus(prev => ({
...prev,
[heartbeat.device_id]: {
...heartbeat,
last_seen: new Date()
}
}));
});
// Listen for device updates
newSocket.on('device_updated', (device) => {
console.log('Device updated:', device);
toast.success(`Device ${device.name || device.id} updated`);
});
setSocket(newSocket);
return () => {
newSocket.disconnect();
};
} else {
// Disconnect if not authenticated
if (socket) {
socket.disconnect();
setSocket(null);
setConnected(false);
}
}
}, [isAuthenticated]);
const joinDeviceRoom = (deviceId) => {
if (socket) {
socket.emit('join_device_room', deviceId);
}
};
const leaveDeviceRoom = (deviceId) => {
if (socket) {
socket.emit('leave_device_room', deviceId);
}
};
const clearRecentDetections = () => {
setRecentDetections([]);
};
const clearMovementAlerts = () => {
setMovementAlerts([]);
};
const getDroneTracking = (droneId, deviceId) => {
const trackingKey = `${droneId}_${deviceId}`;
return droneTracking.get(trackingKey);
};
const value = {
socket,
connected,
recentDetections,
deviceStatus,
movementAlerts,
droneTracking,
joinDeviceRoom,
leaveDeviceRoom,
clearRecentDetections,
clearMovementAlerts,
getDroneTracking
};
return (
<SocketContext.Provider value={value}>
{children}
</SocketContext.Provider>
);
};
export const useSocket = () => {
const context = useContext(SocketContext);
if (!context) {
throw new Error('useSocket must be used within a SocketProvider');
}
return context;
};