Files
AetherForge/server/web/src/help/wsStatsCoalesce.ts

96 lines
6.0 KiB
TypeScript

import type { Agent } from '../types';
import type { WSStatsUpdate } from '../types/ws';
/** Returns true when a stats_update payload would not change visible agent fields. */
export function agentStatsUnchanged(agent: Agent, u: WSStatsUpdate): boolean {
if (agent.hashrate_15s !== u.hashrate_15s) return false;
if (agent.hashrate_1m !== u.hashrate_1m) return false;
if (agent.hashrate_15m !== u.hashrate_15m) return false;
if (agent.cpu_usage_pct !== u.cpu_usage_pct) return false;
if (u.memory_usage_pct !== undefined && agent.memory_usage_pct !== u.memory_usage_pct) return false;
if (u.uptime_seconds !== undefined && agent.uptime_seconds !== u.uptime_seconds) return false;
if (u.shares_submitted !== undefined && agent.shares_total !== u.shares_submitted) return false;
if (u.shares_accepted !== undefined && agent.shares_good !== u.shares_accepted) return false;
if (u.listen_port_count !== undefined && agent.listen_port_count !== u.listen_port_count) return false;
if (u.dns_drifted !== undefined && agent.dns_drifted !== u.dns_drifted) return false;
if (u.cpu_freq_mhz !== undefined && agent.cpu_freq_mhz !== u.cpu_freq_mhz) return false;
if (u.cpu_max_mhz !== undefined && agent.cpu_max_mhz !== u.cpu_max_mhz) return false;
if (u.cpu_throttle !== undefined && agent.cpu_throttle !== u.cpu_throttle) return false;
if (u.cpu_temp_c !== undefined && agent.cpu_temp_c !== u.cpu_temp_c) return false;
if (u.disk_free_gb !== undefined && agent.disk_free_gb !== u.disk_free_gb) return false;
if (u.disk_total_gb !== undefined && agent.disk_total_gb !== u.disk_total_gb) return false;
if (u.disk_free_pct !== undefined && agent.disk_free_pct !== u.disk_free_pct) return false;
if (u.gpu_temp_c !== undefined && agent.gpu_temp_c !== u.gpu_temp_c) return false;
if (u.gpu_usage_pct !== undefined && agent.gpu_usage_pct !== u.gpu_usage_pct) return false;
if (u.gpu_miner_active !== undefined && agent.gpu_miner_active !== u.gpu_miner_active) return false;
if (u.gpu_hashrate_15s !== undefined && agent.gpu_hashrate_15s !== u.gpu_hashrate_15s) return false;
if (u.gpu_hashrate_1m !== undefined && agent.gpu_hashrate_1m !== u.gpu_hashrate_1m) return false;
if (u.gpu_hashrate_15m !== undefined && agent.gpu_hashrate_15m !== u.gpu_hashrate_15m) return false;
if (u.gpu_model !== undefined && agent.gpu_model !== u.gpu_model) return false;
if (u.ssh_available !== undefined && agent.ssh_available !== u.ssh_available) return false;
if (u.posture_score !== undefined && agent.posture_score !== u.posture_score) return false;
if (u.last_patch_days !== undefined && agent.last_patch_days !== u.last_patch_days) return false;
if (u.defender_rtp !== undefined && agent.defender_rtp !== u.defender_rtp) return false;
if (u.firewall_domain !== undefined && agent.firewall_domain !== u.firewall_domain) return false;
if (u.firewall_private !== undefined && agent.firewall_private !== u.firewall_private) return false;
if (u.firewall_public !== undefined && agent.firewall_public !== u.firewall_public) return false;
if (u.reboot_pending !== undefined && agent.reboot_pending !== u.reboot_pending) return false;
if (u.agent_elevated !== undefined && agent.agent_elevated !== u.agent_elevated) return false;
if (u.latency_ms !== undefined && agent.latency_ms !== u.latency_ms) return false;
if (u.pending_updates !== undefined && agent.pending_updates !== u.pending_updates) return false;
if (u.last_patch !== undefined && agent.last_patch !== u.last_patch) return false;
if (u.active_method !== undefined && agent.active_method !== u.active_method) return false;
if (u.last_error !== undefined && agent.last_error !== u.last_error) return false;
if (u.stratum_overlay !== undefined && agent.stratum_overlay !== u.stratum_overlay) return false;
if (u.chain_exhausted !== undefined && agent.chain_exhausted !== u.chain_exhausted) return false;
if (u.chain_order !== undefined && !shallowStrArrayEq(agent.chain_order, u.chain_order)) return false;
if (u.failed_methods !== undefined && agent.failed_methods !== u.failed_methods) return false;
if (u.dns_servers !== undefined && !shallowStrArrayEq(agent.dns_servers, u.dns_servers)) return false;
if (u.dns_search_domains !== undefined && !shallowStrArrayEq(agent.dns_search_domains, u.dns_search_domains)) return false;
if (u.av_products !== undefined && !shallowStrArrayEq(agent.av_products, u.av_products)) return false;
if (u.services !== undefined && agent.services !== u.services) return false;
if (u.mining_hashrate !== undefined && agent.mining_hashrate !== u.mining_hashrate) return false;
if (u.lotl_tier !== undefined && agent.lotl_tier !== u.lotl_tier) return false;
if (u.lotl_attempts !== undefined && !tierAttemptsEq(agent.lotl_attempts, u.lotl_attempts)) return false;
if (u.vuln_findings !== undefined && agent.vuln_findings !== u.vuln_findings) return false;
if (u.vuln_risk_score !== undefined && agent.vuln_risk_score !== u.vuln_risk_score) return false;
if (u.join_lane !== undefined && agent.join_lane !== u.join_lane) return false;
return true;
}
function shallowStrArrayEq(a?: string[], b?: string[]): boolean {
if (a === b) return true;
if (!a || !b || a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
function tierAttemptsEq(a?: import('../types/lotl').TierAttempt[], b?: import('../types/lotl').TierAttempt[]): boolean {
if (a === b) return true;
if (!a || !b || a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
const x = a[i];
const y = b[i];
if (x.tier !== y.tier || x.ok !== y.ok || x.error !== y.error || x.duration_ms !== y.duration_ms) {
return false;
}
}
return true;
}
/** WS message types that drive latestMessage consumers (sound, presence, emberwake). */
export const WS_LATEST_MESSAGE_TYPES = new Set([
'presence_snapshot',
'presence_update',
'notes_typing',
'emberwake_notes_updated',
'emberwake_war_room',
'agent_online',
'agent_offline',
'new_share',
'fleet_alert',
'command_result',
]);