ws: migrate push stream to data streaming
- 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
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 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)
|
||||
};
|
||||
Reference in New Issue
Block a user