Initial commit
This commit is contained in:
228
server/routes/droneDetection.js
Normal file
228
server/routes/droneDetection.js
Normal file
@@ -0,0 +1,228 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const Joi = require('joi');
|
||||
const { DroneDetection, Device } = require('../models');
|
||||
const { processAlert } = require('../services/alertService');
|
||||
const { validateRequest } = require('../middleware/validation');
|
||||
|
||||
// Validation schema for drone detection
|
||||
const droneDetectionSchema = Joi.object({
|
||||
device_id: Joi.number().integer().required(),
|
||||
geo_lat: Joi.number().min(-90).max(90).default(0),
|
||||
geo_lon: Joi.number().min(-180).max(180).default(0),
|
||||
device_timestamp: Joi.number().integer().min(0).default(0),
|
||||
drone_type: Joi.number().integer().min(0).default(0),
|
||||
rssi: Joi.number().integer().default(0),
|
||||
freq: Joi.number().integer().required(),
|
||||
drone_id: Joi.number().integer().required(),
|
||||
confidence_level: Joi.number().min(0).max(1).optional(),
|
||||
signal_duration: Joi.number().integer().min(0).optional()
|
||||
});
|
||||
|
||||
// POST /api/detections - Receive drone detection data
|
||||
router.post('/', validateRequest(droneDetectionSchema), async (req, res) => {
|
||||
try {
|
||||
const detectionData = req.body;
|
||||
|
||||
// Ensure device exists or create it
|
||||
const [device] = await Device.findOrCreate({
|
||||
where: { id: detectionData.device_id },
|
||||
defaults: {
|
||||
id: detectionData.device_id,
|
||||
geo_lat: detectionData.geo_lat || 0,
|
||||
geo_lon: detectionData.geo_lon || 0,
|
||||
last_heartbeat: new Date()
|
||||
}
|
||||
});
|
||||
|
||||
// Create the detection record
|
||||
const detection = await DroneDetection.create({
|
||||
...detectionData,
|
||||
server_timestamp: new Date()
|
||||
});
|
||||
|
||||
// Emit real-time update via Socket.IO
|
||||
req.io.emit('drone_detection', {
|
||||
id: detection.id,
|
||||
device_id: detection.device_id,
|
||||
drone_id: detection.drone_id,
|
||||
drone_type: detection.drone_type,
|
||||
rssi: detection.rssi,
|
||||
freq: detection.freq,
|
||||
geo_lat: detection.geo_lat,
|
||||
geo_lon: detection.geo_lon,
|
||||
server_timestamp: detection.server_timestamp,
|
||||
device: {
|
||||
id: device.id,
|
||||
name: device.name,
|
||||
geo_lat: device.geo_lat,
|
||||
geo_lon: device.geo_lon
|
||||
}
|
||||
});
|
||||
|
||||
// Process alerts asynchronously
|
||||
processAlert(detection).catch(error => {
|
||||
console.error('Alert processing error:', error);
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
data: detection,
|
||||
message: 'Drone detection recorded successfully'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error creating drone detection:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to record drone detection',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : 'Internal server error'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/detections - Get drone detections with filtering
|
||||
router.get('/', async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
device_id,
|
||||
drone_id,
|
||||
start_date,
|
||||
end_date,
|
||||
limit = 100,
|
||||
offset = 0,
|
||||
order = 'DESC'
|
||||
} = req.query;
|
||||
|
||||
const whereClause = {};
|
||||
|
||||
if (device_id) whereClause.device_id = device_id;
|
||||
if (drone_id) whereClause.drone_id = drone_id;
|
||||
|
||||
if (start_date || end_date) {
|
||||
whereClause.server_timestamp = {};
|
||||
if (start_date) whereClause.server_timestamp[Op.gte] = new Date(start_date);
|
||||
if (end_date) whereClause.server_timestamp[Op.lte] = new Date(end_date);
|
||||
}
|
||||
|
||||
const detections = await DroneDetection.findAndCountAll({
|
||||
where: whereClause,
|
||||
include: [{
|
||||
model: Device,
|
||||
as: 'device',
|
||||
attributes: ['id', 'name', 'geo_lat', 'geo_lon', 'location_description']
|
||||
}],
|
||||
limit: Math.min(parseInt(limit), 1000), // Max 1000 records
|
||||
offset: parseInt(offset),
|
||||
order: [['server_timestamp', order]]
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: detections.rows,
|
||||
pagination: {
|
||||
total: detections.count,
|
||||
limit: parseInt(limit),
|
||||
offset: parseInt(offset),
|
||||
pages: Math.ceil(detections.count / parseInt(limit))
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching drone detections:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to fetch drone detections',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : 'Internal server error'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/detections/stats - Get detection statistics
|
||||
router.get('/stats', async (req, res) => {
|
||||
try {
|
||||
const { device_id, hours = 24 } = req.query;
|
||||
|
||||
const whereClause = {
|
||||
server_timestamp: {
|
||||
[Op.gte]: new Date(Date.now() - hours * 60 * 60 * 1000)
|
||||
}
|
||||
};
|
||||
|
||||
if (device_id) whereClause.device_id = device_id;
|
||||
|
||||
const [totalDetections, uniqueDrones, uniqueDevices, avgRssi] = await Promise.all([
|
||||
DroneDetection.count({ where: whereClause }),
|
||||
DroneDetection.count({
|
||||
where: whereClause,
|
||||
distinct: true,
|
||||
col: 'drone_id'
|
||||
}),
|
||||
DroneDetection.count({
|
||||
where: whereClause,
|
||||
distinct: true,
|
||||
col: 'device_id'
|
||||
}),
|
||||
DroneDetection.findAll({
|
||||
where: whereClause,
|
||||
attributes: [
|
||||
[sequelize.fn('AVG', sequelize.col('rssi')), 'avg_rssi']
|
||||
]
|
||||
})
|
||||
]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
total_detections: totalDetections,
|
||||
unique_drones: uniqueDrones,
|
||||
active_devices: uniqueDevices,
|
||||
average_rssi: Math.round(avgRssi[0]?.dataValues?.avg_rssi || 0),
|
||||
time_period_hours: hours
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching detection stats:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to fetch detection statistics',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : 'Internal server error'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/detections/:id - Get specific detection
|
||||
router.get('/:id', async (req, res) => {
|
||||
try {
|
||||
const detection = await DroneDetection.findByPk(req.params.id, {
|
||||
include: [{
|
||||
model: Device,
|
||||
as: 'device',
|
||||
attributes: ['id', 'name', 'geo_lat', 'geo_lon', 'location_description']
|
||||
}]
|
||||
});
|
||||
|
||||
if (!detection) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: 'Detection not found'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: detection
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching detection:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: 'Failed to fetch detection',
|
||||
error: process.env.NODE_ENV === 'development' ? error.message : 'Internal server error'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user