this is a big slop that might backfire lol... new config system and UI!

This commit is contained in:
legop3
2026-09-14 02:31:12 -04:00
parent 17b1404157
commit bfdb6555d8
108 changed files with 3212 additions and 701 deletions
@@ -118,7 +118,7 @@ function createPtzAudioPlayback(deps) {
/*
Write on every playback instead of trying to detect config drift. The file
is small, and this guarantees a camera password/host change in config.yaml
is small, and this guarantees a camera password/host configuration change
is reflected without an extra migration path or manual cleanup.
*/
await fsp.writeFile(configPath, body, { mode: 0o600 });
@@ -0,0 +1,33 @@
// PTZ Camera Configuration
// Purpose: Defines the optional ONVIF camera connection and replay behavior.
// Scope: Contains data-only metadata so validation never initializes camera hardware.
const { strictObject, string, boolean, integer } = require('../../configuration/schemaHelpers');
module.exports = {
key: 'ptzCamera',
feature: true,
defaultValue: {
enabled: false,
name: 'PTZ Camera',
color: '#38bdf8',
host: '',
onvifPort: 8000,
username: '',
password: '',
profileToken: '003',
turnDurationMs: 300000,
replayEnabled: false,
},
schema: strictObject({
enabled: boolean(),
name: string({ minLength: 1, maxLength: 120 }),
color: string({ pattern: '^#[0-9a-fA-F]{6}$' }),
host: string({ maxLength: 255 }),
onvifPort: integer({ title: 'ONVIF port', minimum: 1, maximum: 65535 }),
username: string({ maxLength: 255 }),
password: string({ writeOnly: true, maxLength: 10000 }),
profileToken: string({ maxLength: 255 }),
turnDurationMs: integer({ minimum: 1000, maximum: 86400000 }),
replayEnabled: boolean(),
}, { title: 'PTZ camera', required: ['enabled', 'name', 'color', 'host', 'onvifPort', 'username', 'password', 'profileToken', 'turnDurationMs', 'replayEnabled'] }),
};
@@ -9,9 +9,8 @@ const { Cam } = require('onvif');
const io = require('../../globals/io');
const logger = require('../../globals/logger').child('ptzCamera');
const { loadConfig } = require('../../helpers/configLoader');
const { loadConfig } = require('../../configuration');
const { resolveRoverSnapshotDir } = require('../../helpers/dataPaths');
const { isFeatureEnabled } = require('../../helpers/features');
const {
shouldUseSnapshotsForNonTurnVideo,
shouldUseSnapshotsForExternalSpectatorVideo,
@@ -54,7 +53,7 @@ const PUBLISHER_RTSP_TIMEOUT_US = 10000000;
const events = new EventEmitter();
const config = loadConfig();
const cameraConfig = config.ptzCamera || {};
const enabled = isFeatureEnabled('ptzCamera');
const enabled = Boolean(cameraConfig.enabled);
const state = {
initialized: false,
@@ -1058,8 +1057,8 @@ function requireOperator(socket) {
function requirePtzUser(socket) {
/*
Listing presets does not move the camera, but it still reveals operational
camera state. Use the same feature gate as queue entry so unverified users
cannot query PTZ-only data through raw socket calls.
camera state. Check the camera's own enabled switch just like queue entry so
unverified users cannot query PTZ-only data through raw socket calls.
*/
if (!enabled) throw new Error('PTZ camera disabled');
if (!canUsePtzFeature(socket)) throw new Error('Not authorized for PTZ camera');