initial commit
This commit is contained in:
83
server/utils/deviceUtils.js
Normal file
83
server/utils/deviceUtils.js
Normal file
@@ -0,0 +1,83 @@
|
||||
import { sanitizeStreamUrl } from './feedUtils.js'
|
||||
|
||||
const DEVICE_TYPES = Object.freeze(['alpr', 'nvr', 'doorbell', 'feed', 'traffic', 'ip', 'drone'])
|
||||
const SOURCE_TYPES = Object.freeze(['mjpeg', 'hls'])
|
||||
|
||||
/** @typedef {{ id: string, name: string, device_type: string, vendor: string | null, lat: number, lng: number, stream_url: string, source_type: string, config: string | null }} DeviceRow */
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
* @returns {string} 'mjpeg' or 'hls'
|
||||
*/
|
||||
function normalizeSourceType(s) {
|
||||
return SOURCE_TYPES.includes(s) ? s : 'mjpeg'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown} row
|
||||
* @returns {DeviceRow | null} Normalized device row or null if invalid
|
||||
*/
|
||||
export function rowToDevice(row) {
|
||||
if (!row || typeof row !== 'object') return null
|
||||
const r = /** @type {Record<string, unknown>} */ (row)
|
||||
if (typeof r.id !== 'string' || typeof r.name !== 'string' || typeof r.device_type !== 'string') return null
|
||||
if (typeof r.lat !== 'number' && typeof r.lat !== 'string') return null
|
||||
if (typeof r.lng !== 'number' && typeof r.lng !== 'string') return null
|
||||
const lat = Number(r.lat)
|
||||
const lng = Number(r.lng)
|
||||
if (!Number.isFinite(lat) || !Number.isFinite(lng)) return null
|
||||
return {
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
device_type: r.device_type,
|
||||
vendor: typeof r.vendor === 'string' ? r.vendor : null,
|
||||
lat,
|
||||
lng,
|
||||
stream_url: typeof r.stream_url === 'string' ? r.stream_url : '',
|
||||
source_type: normalizeSourceType(r.source_type),
|
||||
config: typeof r.config === 'string' ? r.config : null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize device for API response (safe stream URL, valid sourceType).
|
||||
* @param {DeviceRow} device
|
||||
* @returns {{ id: string, name: string, device_type: string, vendor: string | null, lat: number, lng: number, streamUrl: string, sourceType: string, config: string | null }} Sanitized device for API response
|
||||
*/
|
||||
export function sanitizeDeviceForResponse(device) {
|
||||
return {
|
||||
id: device.id,
|
||||
name: device.name,
|
||||
device_type: device.device_type,
|
||||
vendor: device.vendor,
|
||||
lat: device.lat,
|
||||
lng: device.lng,
|
||||
streamUrl: sanitizeStreamUrl(device.stream_url),
|
||||
sourceType: normalizeSourceType(device.source_type),
|
||||
config: device.config,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and normalize device body for POST.
|
||||
* @param {unknown} body
|
||||
* @returns {{ name: string, device_type: string, vendor: string | null, lat: number, lng: number, stream_url: string, source_type: string, config: string | null }} Validated and normalized body fields
|
||||
*/
|
||||
export function validateDeviceBody(body) {
|
||||
if (!body || typeof body !== 'object') throw createError({ statusCode: 400, message: 'body required' })
|
||||
const b = /** @type {Record<string, unknown>} */ (body)
|
||||
const name = typeof b.name === 'string' ? b.name.trim() || '' : ''
|
||||
const deviceType = typeof b.device_type === 'string' && DEVICE_TYPES.includes(b.device_type) ? b.device_type : 'feed'
|
||||
const vendor = typeof b.vendor === 'string' ? b.vendor.trim() || null : null
|
||||
const lat = Number(b.lat)
|
||||
const lng = Number(b.lng)
|
||||
if (!Number.isFinite(lat) || !Number.isFinite(lng)) {
|
||||
throw createError({ statusCode: 400, message: 'lat and lng required as finite numbers' })
|
||||
}
|
||||
const streamUrl = typeof b.stream_url === 'string' ? b.stream_url.trim() : ''
|
||||
const sourceType = normalizeSourceType(b.source_type)
|
||||
const config = typeof b.config === 'string' ? b.config : (b.config != null ? JSON.stringify(b.config) : null)
|
||||
return { name, device_type: deviceType, vendor, lat, lng, stream_url: streamUrl, source_type: sourceType, config }
|
||||
}
|
||||
|
||||
export { DEVICE_TYPES, SOURCE_TYPES }
|
||||
Reference in New Issue
Block a user