proxy backend

This commit is contained in:
Oli Passey
2025-12-21 16:54:13 +00:00
parent 1fb43156e8
commit 77bf4ffd05
30 changed files with 3010 additions and 79 deletions

View File

@@ -1,6 +1,7 @@
import { Router, Request, Response } from 'express';
import { z } from 'zod';
import { deviceService } from '../services/deviceService';
import { discoveryService } from '../services/discoveryService';
const router = Router();
@@ -202,4 +203,112 @@ router.post('/all/turn-off', async (req: Request, res: Response) => {
}
});
// POST /api/devices/:id/sync
router.post('/:id/sync', async (req: Request, res: Response) => {
try {
const { targetIds } = z.object({
targetIds: z.array(z.string()).min(1, 'At least one target device is required'),
}).parse(req.body);
const result = await deviceService.syncDeviceState(req.params.id, targetIds);
res.json(result);
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({
error: 'ValidationError',
details: error.errors.map((e) => ({ field: e.path.join('.'), message: e.message })),
});
}
if (error instanceof Error && error.message.includes('not found')) {
return res.status(404).json({ error: 'NotFound', message: error.message });
}
console.error('Error syncing device state:', error);
res.status(500).json({ error: 'InternalError', message: 'Failed to sync device state' });
}
});
// POST /api/devices/:sourceId/copy-to/:targetId
router.post('/:sourceId/copy-to/:targetId', async (req: Request, res: Response) => {
try {
await deviceService.copyDeviceConfig(req.params.sourceId, req.params.targetId);
res.json({ status: 'ok', message: 'Configuration copied successfully' });
} catch (error) {
if (error instanceof Error && error.message.includes('not found')) {
return res.status(404).json({ error: 'NotFound', message: error.message });
}
console.error('Error copying device config:', error);
res.status(500).json({ error: 'InternalError', message: 'Failed to copy configuration' });
}
});
// POST /api/devices/discover/mdns
router.post('/discover/mdns', async (req: Request, res: Response) => {
try {
const { timeout } = z.object({
timeout: z.number().int().positive().optional(),
}).parse(req.body);
const discoveredDevices = await discoveryService.discoverDevices(timeout);
res.json({ devices: discoveredDevices, count: discoveredDevices.length });
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({
error: 'ValidationError',
details: error.errors.map((e) => ({ field: e.path.join('.'), message: e.message })),
});
}
console.error('Error discovering devices:', error);
res.status(500).json({ error: 'InternalError', message: 'Failed to discover devices' });
}
});
// POST /api/devices/discover/scan
router.post('/discover/scan', async (req: Request, res: Response) => {
try {
const { baseIp, startRange, endRange } = z.object({
baseIp: z.string().regex(/^\d{1,3}\.\d{1,3}\.\d{1,3}$/, 'Invalid base IP format (e.g., 192.168.1)'),
startRange: z.number().int().min(1).max(254).optional(),
endRange: z.number().int().min(1).max(254).optional(),
}).parse(req.body);
const discoveredDevices = await discoveryService.scanIpRange(baseIp, startRange, endRange);
res.json({ devices: discoveredDevices, count: discoveredDevices.length });
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({
error: 'ValidationError',
details: error.errors.map((e) => ({ field: e.path.join('.'), message: e.message })),
});
}
console.error('Error scanning IP range:', error);
res.status(500).json({ error: 'InternalError', message: 'Failed to scan IP range' });
}
});
// POST /api/devices/discover/verify
router.post('/discover/verify', async (req: Request, res: Response) => {
try {
const { ipAddress, port } = z.object({
ipAddress: z.string().min(1, 'IP address is required'),
port: z.number().int().positive().optional(),
}).parse(req.body);
const device = await discoveryService.verifyDevice(ipAddress, port);
if (device) {
res.json({ found: true, device });
} else {
res.json({ found: false, message: 'No WLED device found at this address' });
}
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({
error: 'ValidationError',
details: error.errors.map((e) => ({ field: e.path.join('.'), message: e.message })),
});
}
console.error('Error verifying device:', error);
res.status(500).json({ error: 'InternalError', message: 'Failed to verify device' });
}
});
export default router;