332d14e37d
- daemon: send full snapshot on connect; versions/tick now carry the full state of one subsystem (subsystem + data); no legacy updated/subsystems payloads; refresh_state and POST /status/refresh broadcast per-subsystem versions with data - client: modelSet() patches models in place; onMessage/topic refresh retired; 3s initial-load fallback via new POST /api/status/refresh - schema: lib/schema.py TypedDicts + hoover/schema.js defaults + docs/state-model.md as single source of truth for state shapes - system: poll at 1s, volatile metrics registered, dashboard uses a dedicated system model (status model removed) - firewall: refuse to strip both https and ssh from the default zone (409, force override via UI confirm); set_zone_services persists services to the declarative config; collector exposes default_zone - UI: pages migrate to flat state shapes; post-mutation modelFetch refreshes removed (WS delta covers it) - tests: ws snapshot/delta/broadcast, refresh-state, schema types, model-set/js ws handler and reconnect fallback
81 lines
2.2 KiB
JavaScript
81 lines
2.2 KiB
JavaScript
/**
|
|
* Hoover — schema.js
|
|
*
|
|
* State-store schema defaults — one module per subsystem.
|
|
*
|
|
* `defaults` initializes model.data so pages don't need null guards
|
|
* during the first render (before the WS snapshot or HTTP fallback
|
|
* delivers real data). The shapes match the daemon state store
|
|
* (docs/state-model.md); the WebSocket streams these exact shapes.
|
|
*
|
|
* `POLL_INTERVALS` is client-side awareness of the daemon's expected
|
|
* refresh cadence per subsystem (for "last updated" displays).
|
|
*/
|
|
|
|
export const SUBSYSTEMS = {
|
|
firewall: {
|
|
defaults: {
|
|
config: {},
|
|
active_zones: {},
|
|
interfaces: [],
|
|
available_services: [],
|
|
zones: {},
|
|
rich_rules: {},
|
|
pending: {},
|
|
},
|
|
},
|
|
dnsmasq: {
|
|
defaults: {
|
|
config: {},
|
|
status: { service_active: false, config_file_exists: false, active_leases: 0, pending_changes: false },
|
|
leases: [],
|
|
},
|
|
},
|
|
nginx: {
|
|
defaults: {
|
|
config: {},
|
|
domains: [],
|
|
status: { pending_changes: false },
|
|
},
|
|
},
|
|
acme: {
|
|
defaults: {
|
|
certs: [],
|
|
email: '',
|
|
account: { registered: false, email: '', ca: '', key_length: null },
|
|
},
|
|
},
|
|
wireguard: {
|
|
defaults: {
|
|
config: {},
|
|
status: { up: false, interface: {}, peers: [], classes: {}, pending_changes: false },
|
|
peers: [],
|
|
},
|
|
},
|
|
networkd: {
|
|
defaults: {
|
|
config: {},
|
|
interfaces: {},
|
|
status: { pending_changes: false },
|
|
},
|
|
},
|
|
system: {
|
|
defaults: {
|
|
load: { load1: 0, load5: 0, load15: 0 },
|
|
memory: { total: 0, available: 0, used: 0, used_pct: 0 },
|
|
swap: { total: 0, used: 0, used_pct: 0 },
|
|
traffic: {},
|
|
},
|
|
},
|
|
};
|
|
|
|
export const POLL_INTERVALS = {
|
|
firewall: 30,
|
|
wireguard: 10,
|
|
dnsmasq: 10,
|
|
networkd: 10,
|
|
system: 1, // Phase 5: 30 → 1 (real-time metrics)
|
|
nginx: 60, // matches _DEFAULT_POLL_INTERVALS (config-drift self-heal)
|
|
acme: 300, // matches _DEFAULT_POLL_INTERVALS (config-drift self-heal)
|
|
};
|