const express = require('express'); const router = express.Router(); const db = require('../../db'); const { isAuthenticated, hasRole } = require('../../middleware/authMiddleware'); const { requireModule } = require('../../middleware/licenseMiddleware'); // Get all cameras - Protected by Module License router.get('/', requireModule('monitoring'), async (req, res) => { try { const [rows] = await db.query('SELECT * FROM camera_settings ORDER BY display_order ASC, created_at DESC'); res.json(rows); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Reorder cameras (Admin only) router.put('/reorder', hasRole('admin'), async (req, res) => { const { cameras } = req.body; // Array of { id, display_order } or just ordered IDs if (!Array.isArray(cameras)) { return res.status(400).json({ error: 'Invalid data format' }); } try { // Use a transaction for safety await db.query('START TRANSACTION'); for (let i = 0; i < cameras.length; i++) { const cam = cameras[i]; // If receiving array of IDs, use index as order const id = typeof cam === 'object' ? cam.id : cam; const order = i; await db.query('UPDATE camera_settings SET display_order = ? WHERE id = ?', [order, id]); } await db.query('COMMIT'); res.json({ message: 'Cameras reordered' }); } catch (err) { await db.query('ROLLBACK'); console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Get single camera router.get('/:id', async (req, res) => { try { const [rows] = await db.query('SELECT * FROM camera_settings WHERE id = ?', [req.params.id]); if (rows.length === 0) return res.status(404).json({ error: 'Camera not found' }); res.json(rows[0]); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Add camera (Admin only) router.post('/', hasRole('admin'), async (req, res) => { const { name, ip_address, port, username, password, stream_path, transport_mode, rtsp_encoding, quality } = req.body; try { const sql = `INSERT INTO camera_settings (name, ip_address, port, username, password, stream_path, transport_mode, rtsp_encoding, quality) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`; const [result] = await db.query(sql, [name, ip_address, port || 554, username, password, stream_path || '/stream1', transport_mode || 'tcp', rtsp_encoding || false, quality || 'low']); res.status(201).json({ message: 'Camera added', id: result.insertId }); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Update camera (Admin only) router.put('/:id', hasRole('admin'), async (req, res) => { const { name, ip_address, port, username, password, stream_path, transport_mode, rtsp_encoding, quality } = req.body; try { const sql = `UPDATE camera_settings SET name=?, ip_address=?, port=?, username=?, password=?, stream_path=?, transport_mode=?, rtsp_encoding=?, quality=? WHERE id=?`; const [result] = await db.query(sql, [name, ip_address, port, username, password, stream_path, transport_mode, rtsp_encoding, quality, req.params.id]); if (result.affectedRows === 0) return res.status(404).json({ error: 'Camera not found' }); // Force stream reset (kick clients to trigger reconnect) const streamRelay = req.app.get('streamRelay'); if (streamRelay) { console.log(`Settings changed for camera ${req.params.id}, resetting stream...`); streamRelay.resetStream(req.params.id); } res.json({ message: 'Camera updated' }); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Delete camera (Admin only) router.delete('/:id', hasRole('admin'), async (req, res) => { try { const [result] = await db.query('DELETE FROM camera_settings WHERE id = ?', [req.params.id]); if (result.affectedRows === 0) return res.status(404).json({ error: 'Camera not found' }); // Stop stream const streamRelay = req.app.get('streamRelay'); if (streamRelay) { streamRelay.stopStream(req.params.id); } res.json({ message: 'Camera deleted' }); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); const { exec } = require('child_process'); // ... existing routes ... // 7. Ping Test (Troubleshooting) router.get('/:id/ping', isAuthenticated, async (req, res) => { try { const [rows] = await db.query('SELECT ip_address FROM camera_settings WHERE id = ?', [req.params.id]); if (rows.length === 0) return res.status(404).json({ error: 'Camera not found' }); const ip = rows[0].ip_address; // Simple ping command const platform = process.platform; const cmd = platform === 'win32' ? `ping -n 1 ${ip}` : `ping -c 1 ${ip}`; exec(cmd, (error, stdout, stderr) => { res.json({ ip, success: !error, output: stdout, error: stderr }); }); } catch (err) { res.status(500).json({ error: 'Ping failed' }); } }); module.exports = router;