const express = require('express'); const cors = require('cors'); const fs = require('fs'); const path = require('path'); const morgan = require('morgan'); const app = express(); const PORT = process.env.PORT || 4000; const DATA_PATH = path.join(__dirname, 'data', 'devices.json'); app.use(cors()); app.use(express.json()); app.use(morgan('dev')); app.use(express.static(path.join(__dirname, 'public'), { extensions: ['html'] })); app.use((req, res, next) => { res.setHeader('Cache-Control', 'no-store'); next(); }); function ensureDataFile() { if (!fs.existsSync(DATA_PATH)) { fs.mkdirSync(path.dirname(DATA_PATH), { recursive: true }); fs.writeFileSync(DATA_PATH, JSON.stringify([] , null, 2)); } } function readDevices() { ensureDataFile(); const raw = fs.readFileSync(DATA_PATH, 'utf-8'); try { const devices = JSON.parse(raw); return Array.isArray(devices) ? devices : []; } catch (err) { console.error('Error parsing devices.json', err); return []; } } function writeDevices(devices) { ensureDataFile(); fs.writeFileSync(DATA_PATH, JSON.stringify(devices, null, 2)); } function sanitizeId(input) { return String(input || '').trim(); } app.get('/api/health', (req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString() }); }); app.get('/api/devices', (req, res) => { const devices = readDevices(); res.json({ devices }); }); app.post('/api/devices/register', (req, res) => { const { deviceId, deviceName, model, manufacturer, osVersion, appVersionName, appVersionCode } = req.body || {}; const trimmedId = sanitizeId(deviceId); if (!trimmedId) { return res.status(400).json({ error: 'deviceId is required' }); } const devices = readDevices(); const now = new Date().toISOString(); let existing = devices.find(d => d.deviceId === trimmedId); if (!existing) { existing = { deviceId: trimmedId, alias: '', deviceName: deviceName || '', model: model || '', manufacturer: manufacturer || '', osVersion: osVersion || '', appVersionName: appVersionName || '', appVersionCode: appVersionCode || 0, firstSeen: now, lastSeen: now, blocked: false, notes: '', installs: 1 }; devices.push(existing); } else { existing.deviceName = deviceName || existing.deviceName; existing.model = model || existing.model; existing.manufacturer = manufacturer || existing.manufacturer; existing.osVersion = osVersion || existing.osVersion; existing.appVersionName = appVersionName || existing.appVersionName; existing.appVersionCode = appVersionCode || existing.appVersionCode; existing.lastSeen = now; existing.installs = (existing.installs || 1) + 1; } writeDevices(devices); res.json({ blocked: existing.blocked, device: existing }); }); app.post('/api/devices/:deviceId/block', (req, res) => { const { deviceId } = req.params; const { reason } = req.body || {}; const devices = readDevices(); const existing = devices.find(d => d.deviceId === deviceId); if (!existing) { return res.status(404).json({ error: 'Device not found' }); } existing.blocked = true; existing.notes = reason || existing.notes; existing.blockedAt = new Date().toISOString(); writeDevices(devices); res.json({ blocked: true, device: existing }); }); app.post('/api/devices/:deviceId/unblock', (req, res) => { const { deviceId } = req.params; const devices = readDevices(); const existing = devices.find(d => d.deviceId === deviceId); if (!existing) { return res.status(404).json({ error: 'Device not found' }); } existing.blocked = false; writeDevices(devices); res.json({ blocked: false, device: existing }); }); app.put('/api/devices/:deviceId/alias', (req, res) => { const { deviceId } = req.params; const { alias } = req.body || {}; const devices = readDevices(); const existing = devices.find(d => d.deviceId === deviceId); if (!existing) { return res.status(404).json({ error: 'Device not found' }); } existing.alias = alias || ''; writeDevices(devices); res.json({ device: existing }); }); app.delete('/api/devices/:deviceId', (req, res) => { const { deviceId } = req.params; const devices = readDevices(); const filtered = devices.filter(d => d.deviceId !== deviceId); if (filtered.length === devices.length) { return res.status(404).json({ error: 'Device not found' }); } writeDevices(filtered); res.json({ removed: true }); }); app.listen(PORT, () => { ensureDataFile(); console.log(`StreamPlayer dashboard server listening on port ${PORT}`); });