Files
MacMonitor/Sources/App/SystemTelemetryStore.swift
gronodandDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> 4a8fd0e5ef fix(telemetry): realign snapshot contract — provider IDs and dictionary field keys (fixes #30, fixes #31)
Providers emitted identifiers and field keys that decodeSnapshot never
looked up, leaving CPU/kernel/load/disk sections zeroed and memory%,
storage%, network, process RSS, and fan fields decoded as zero.

Store-side decode now reads the emitted schema; providers gain the
previously-missing fields: network isUp (IFF_UP via getifaddrs), process
isStopped/isZombie (pbi_status), fan name (F{i}ID). Memory utilization is
computed as used/total in the decoder. decodeSnapshot is internal for
@testable access; new MMSnapshotContractTests cover the emitted-key
contract with synthetic dictionaries (93 tests total, 0 failures).

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-08 15:09:19 +01:00

758 lines
34 KiB
Swift

import Foundation
import SwiftUI
import Observation
// MARK: - Typed Telemetry Models
public struct CPULoadMetrics: Sendable {
public var systemLoad: Double = 0
public var userLoad: Double = 0
public var idleLoad: Double = 100
public var totalLoad: Double = 0
public var perCoreLoad: [Double] = []
public var cpuFrequencyMHz: Double = 0
public var isThrottled: Bool = false
}
public struct MemoryMetrics: Sendable {
public var totalBytes: UInt64 = 0
public var usedBytes: UInt64 = 0
public var freeBytes: UInt64 = 0
public var activeBytes: UInt64 = 0
public var inactiveBytes: UInt64 = 0
public var wiredBytes: UInt64 = 0
public var compressedBytes: UInt64 = 0
public var swapTotalBytes: UInt64 = 0
public var swapUsedBytes: UInt64 = 0
public var utilizationPercentage: Double = 0
public var pressureLevel: String = "Normal"
}
public struct StorageVolumeItem: Identifiable, Sendable {
public var id: String { mountPoint }
public let mountPoint: String
public let volumeName: String
public let fileSystem: String
public let totalBytes: UInt64
public let freeBytes: UInt64
public let usedBytes: UInt64
public let usedPercentage: Double
public let isReadOnly: Bool
}
public struct CPUThermalMetrics: Sendable {
public var packageTemperature: Double = 0
public var averageCoreTemperature: Double = 0
public var peakCoreTemperature: Double = 0
public var coreTemperatures: [(index: Int, key: String, temperature: Double)] = []
public var thermalPressureState: String = "Nominal"
public var isThrottling: Bool = false
}
public struct FanTelemetryItem: Identifiable, Sendable {
public var id: Int { index }
public let index: Int
public let name: String
public let currentRPM: Double
public let minRPM: Double
public let maxRPM: Double
public let targetRPM: Double
public let utilization: Double
}
public struct ComponentThermalItem: Identifiable, Sendable {
public var id: String { key }
public let key: String
public let name: String
public let category: String
public let temperature: Double
}
public struct PowerMetrics: Sendable {
public var systemTotalWatts: Double = 0
public var cpuWatts: Double = 0
public var gpuWatts: Double = 0
public var memoryWatts: Double = 0
public var cpuVoltage: Double = 0
public var cpuCurrent: Double = 0
public var powerSource: String = "AC Power"
public var isCharging: Bool = false
public var batteryLevel: Double = 100.0
public var sensorReadings: [(key: String, name: String, value: Double, unit: String)] = []
}
// MARK: - Milestone 3 Advanced Telemetry Models
public struct KernelCountersMetrics: Sendable {
public var contextSwitchesPerSec: Double = 0
public var syscallsPerSec: Double = 0
public var pageFaultsPerSec: Double = 0
public var cowFaultsPerSec: Double = 0
public var zeroFillFaultsPerSec: Double = 0
public var pageinsPerSec: Double = 0
public var pageoutsPerSec: Double = 0
public var totalContextSwitches: UInt64 = 0
public var totalSyscalls: UInt64 = 0
public var totalPageFaults: UInt64 = 0
}
public struct SystemLoadMetrics: Sendable {
public var load1Min: Double = 0
public var load5Min: Double = 0
public var load15Min: Double = 0
public var taskCount: Int = 0
public var threadCount: Int = 0
public var machFactor: Double = 0
}
public struct DiskIOItem: Identifiable, Sendable {
public var id: String { bsdName }
public let bsdName: String
public let readBps: Double
public let writeBps: Double
public let readIOPS: Double
public let writeIOPS: Double
public let totalBytesRead: UInt64
public let totalBytesWritten: UInt64
}
public struct NetworkBandwidthItem: Identifiable, Sendable {
public var id: String { interfaceName }
public let interfaceName: String
public let ipAddress: String
public let isUp: Bool
public let downloadBps: Double
public let uploadBps: Double
public let downloadPps: Double
public let uploadPps: Double
public let totalBytesIn: UInt64
public let totalBytesOut: UInt64
}
public struct SocketItem: Identifiable, Sendable {
public var id: String { "\(pid)_\(fd)_\(localAddress):\(localPort)" }
public let pid: Int32
public let fd: Int32
public let processName: String
public let protocolName: String
public let localAddress: String
public let localPort: UInt16
public let remoteAddress: String
public let remotePort: UInt16
public let tcpState: String
}
public struct ProcessItem: Identifiable, Sendable {
public var id: Int32 { pid }
public let pid: Int32
public let ppid: Int32
public let name: String
public let cpuPercent: Double
public let residentSize: UInt64
public let virtualSize: UInt64
public let threadCount: Int32
public let uid: UInt32
public let username: String
public let isStopped: Bool
public let isZombie: Bool
}
public struct GPUCardItem: Identifiable, Sendable {
public var id: String { name }
public let name: String
public let isDiscrete: Bool
public let isLowPower: Bool
public let vramTotalBytes: UInt64
public let vramUsedBytes: UInt64
public let utilizationPercent: Double
public let temperature: Double
}
public struct BatteryHealthMetrics: Sendable {
public var hasBattery: Bool = false
public var installed: Bool = false
public var healthCondition: String = "Normal"
public var healthPercent: Double = 100.0
public var cycleCount: Int = 0
public var designCycleCount: Int = 1000
public var currentCapacity: Int = 0
public var maxCapacity: Int = 0
public var designCapacity: Int = 0
public var temperature: Double = 0
public var voltage: Double = 0
public var amperage: Double = 0
public var watts: Double = 0
public var isCharging: Bool = false
public var isCharged: Bool = false
public var externalConnected: Bool = false
public var timeRemainingMinutes: Int = -1
public var manufacturer: String = "Apple"
public var serial: String = ""
public var adapterWatts: Int = 0
}
public struct PeripheralDeviceItem: Identifiable, Sendable {
public var id: String { "\(busType)_\(locationID)_\(name)" }
public let name: String
public let busType: String
public let vendorName: String
public let vendorID: UInt32
public let productID: UInt32
public let serialNumber: String
public let locationID: UInt64
public let isBuiltIn: Bool
}
public struct AudioDeviceItem: Identifiable, Sendable {
public var id: UInt32 { deviceID }
public let deviceID: UInt32
public let name: String
public let manufacturer: String
public let isInput: Bool
public let isOutput: Bool
public let isDefaultInput: Bool
public let isDefaultOutput: Bool
public let sampleRate: Double
public let channelCount: UInt32
public let volume: Float
public let isMuted: Bool
}
// MARK: - SystemTelemetryStore
@Observable
@MainActor
public final class SystemTelemetryStore {
public static let shared = SystemTelemetryStore()
public private(set) var isRunning: Bool = false
public private(set) var lastUpdateTimestamp: Date = .now
public private(set) var sampleInterval: TimeInterval = 1.0
/// Raw snapshots organized by provider identifier
public private(set) var latestSnapshot: [String: [String: Any]] = [:]
/// Milestone 2 Structured Metrics
public private(set) var cpuLoad = CPULoadMetrics()
public private(set) var memory = MemoryMetrics()
public private(set) var storageVolumes: [StorageVolumeItem] = []
public private(set) var cpuThermal = CPUThermalMetrics()
public private(set) var fans: [FanTelemetryItem] = []
public private(set) var componentTemps: [ComponentThermalItem] = []
public private(set) var power = PowerMetrics()
/// Milestone 3 Structured Metrics
public private(set) var kernelCounters = KernelCountersMetrics()
public private(set) var systemLoad = SystemLoadMetrics()
public private(set) var diskIO: [DiskIOItem] = []
public private(set) var networkBandwidth: [NetworkBandwidthItem] = []
public private(set) var networkSockets: [SocketItem] = []
public private(set) var processes: [ProcessItem] = []
public private(set) var gpus: [GPUCardItem] = []
public private(set) var batteryHealth = BatteryHealthMetrics()
public private(set) var peripherals: [PeripheralDeviceItem] = []
public private(set) var audioDevices: [AudioDeviceItem] = []
public private(set) var displays: [MMDisplayInfo] = []
/// Historical Telemetry Store
public let historyStore = TelemetryHistoryStore.shared
/// Threshold alert engine (evaluated after every decode pass)
public let alertEngine = AlertEngine.shared
/// Display Manager helper
public let displayManager = MMDisplayManager.shared()
/// Process detail inspection helper
public let processInspector = MMProcessDetailInspector()
/// System identification
public let hostModel: String
public let osVersion: String
public let kernelVersion: String
public let physicalCpuCount: Int
public let logicalCpuCount: Int
private let coordinator = MMTelemetryCoordinator.shared
private init() {
self.hostModel = SystemTelemetryStore.readSysctlString("hw.model") ?? "Intel Mac"
self.osVersion = ProcessInfo.processInfo.operatingSystemVersionString
self.kernelVersion = SystemTelemetryStore.readSysctlString("kern.osrelease") ?? "Unknown Kernel"
self.physicalCpuCount = SystemTelemetryStore.readSysctlInt("hw.physicalcpu") ?? 1
self.logicalCpuCount = SystemTelemetryStore.readSysctlInt("hw.logicalcpu") ?? 1
registerDefaultProviders()
setupCoordinator()
}
private func registerDefaultProviders() {
// Milestone 2 Primary System & Thermal Telemetry
coordinator.register(MMCPULoadProvider())
coordinator.register(MMMemoryTelemetryProvider())
coordinator.register(MMStorageTelemetryProvider())
coordinator.register(MMCPUThermalProvider())
coordinator.register(MMFanTelemetryProvider())
coordinator.register(MMComponentThermalProvider())
coordinator.register(MMPowerTelemetryProvider())
// Milestone 3 Advanced Kernel, Process & Peripheral Telemetry
coordinator.register(MMKernelTelemetryProvider())
coordinator.register(MMLoadAverageProvider())
coordinator.register(MMDiskIOProvider())
coordinator.register(MMNetworkBandwidthProvider())
coordinator.register(MMNetworkSocketsProvider())
coordinator.register(MMProcessTelemetryProvider())
coordinator.register(MMGPUTelemetryProvider())
coordinator.register(MMBatteryTelemetryProvider())
coordinator.register(MMPeripheralsProvider())
coordinator.register(MMAudioTelemetryProvider())
}
private func setupCoordinator() {
coordinator.sampleInterval = self.sampleInterval
coordinator.snapshotHandler = { [weak self] snapshot in
guard let self else { return }
self.latestSnapshot = snapshot
self.lastUpdateTimestamp = Date()
self.decodeSnapshot(snapshot)
}
}
func decodeSnapshot(_ snapshot: [String: [String: Any]]) {
// 1. CPU Load
if let cpuDict = snapshot["com.i3omb.macmonitor.telemetry.cpuload"] {
var m = CPULoadMetrics()
m.systemLoad = (cpuDict["systemPercent"] as? NSNumber)?.doubleValue ?? 0
m.userLoad = (cpuDict["userPercent"] as? NSNumber)?.doubleValue ?? 0
m.idleLoad = (cpuDict["idlePercent"] as? NSNumber)?.doubleValue ?? 100
m.totalLoad = (cpuDict["totalPercent"] as? NSNumber)?.doubleValue ?? 0
if let cores = cpuDict["cores"] as? [[String: Any]] {
m.perCoreLoad = cores.map { ($0["totalPercent"] as? NSNumber)?.doubleValue ?? 0 }
}
m.cpuFrequencyMHz = ((cpuDict["frequencyHz"] as? NSNumber)?.doubleValue ?? 0) / 1e6
m.isThrottled = (cpuDict["isThrottled"] as? NSNumber)?.boolValue ?? false
self.cpuLoad = m
}
// 2. Memory
if let memDict = snapshot["com.i3omb.macmonitor.telemetry.memory"] {
var m = MemoryMetrics()
m.totalBytes = (memDict["totalBytes"] as? NSNumber)?.uint64Value ?? 0
m.usedBytes = (memDict["usedBytes"] as? NSNumber)?.uint64Value ?? 0
m.freeBytes = (memDict["freeBytes"] as? NSNumber)?.uint64Value ?? 0
m.activeBytes = (memDict["activeBytes"] as? NSNumber)?.uint64Value ?? 0
m.inactiveBytes = (memDict["inactiveBytes"] as? NSNumber)?.uint64Value ?? 0
m.wiredBytes = (memDict["wiredBytes"] as? NSNumber)?.uint64Value ?? 0
m.compressedBytes = (memDict["compressedBytes"] as? NSNumber)?.uint64Value ?? 0
m.swapTotalBytes = (memDict["swapTotalBytes"] as? NSNumber)?.uint64Value ?? 0
m.swapUsedBytes = (memDict["swapUsedBytes"] as? NSNumber)?.uint64Value ?? 0
m.utilizationPercentage = m.totalBytes > 0
? Double(m.usedBytes) / Double(m.totalBytes) * 100.0 : 0
m.pressureLevel = memDict["memoryPressureStatus"] as? String
?? memDict["pressureLevel"] as? String ?? "Normal"
self.memory = m
}
// 3. Storage Volumes
if let stgDict = snapshot["com.i3omb.macmonitor.telemetry.storage"],
let volArray = stgDict["volumes"] as? [[String: Any]] {
self.storageVolumes = volArray.compactMap { dict in
guard let mount = dict["mountPoint"] as? String else { return nil }
return StorageVolumeItem(
mountPoint: mount,
volumeName: dict["volumeName"] as? String ?? mount,
fileSystem: dict["fsType"] as? String ?? "APFS",
totalBytes: (dict["totalBytes"] as? NSNumber)?.uint64Value ?? 0,
freeBytes: (dict["freeBytes"] as? NSNumber)?.uint64Value ?? 0,
usedBytes: (dict["usedBytes"] as? NSNumber)?.uint64Value ?? 0,
usedPercentage: (dict["usedPercent"] as? NSNumber)?.doubleValue ?? 0,
isReadOnly: (dict["isReadOnly"] as? NSNumber)?.boolValue ?? false
)
}
}
// 4. CPU Thermal
if let thDict = snapshot["com.i3omb.macmonitor.telemetry.thermal.cpu"] {
var m = CPUThermalMetrics()
m.packageTemperature = (thDict["packageTemperature"] as? NSNumber)?.doubleValue ?? 0
m.averageCoreTemperature = (thDict["averageCoreTemperature"] as? NSNumber)?.doubleValue ?? 0
m.peakCoreTemperature = (thDict["peakCoreTemperature"] as? NSNumber)?.doubleValue ?? 0
m.thermalPressureState = thDict["thermalPressureState"] as? String ?? "Nominal"
m.isThrottling = (thDict["isThrottling"] as? NSNumber)?.boolValue ?? false
if let coresList = thDict["coreTemperatures"] as? [[String: Any]] {
m.coreTemperatures = coresList.compactMap { d in
let idx = (d["coreIndex"] as? NSNumber)?.intValue ?? 0
let key = d["key"] as? String ?? "TC\(idx)C"
let temp = (d["temperature"] as? NSNumber)?.doubleValue ?? 0
return (index: idx, key: key, temperature: temp)
}
}
self.cpuThermal = m
}
// 5. Fans
if let fanDict = snapshot["com.i3omb.macmonitor.telemetry.fan"],
let fanArray = fanDict["fans"] as? [[String: Any]] {
self.fans = fanArray.compactMap { d in
let idx = (d["fanIndex"] as? NSNumber)?.intValue ?? 0
return FanTelemetryItem(
index: idx,
name: d["name"] as? String ?? "Fan \(idx + 1)",
currentRPM: (d["currentRPM"] as? NSNumber)?.doubleValue ?? 0,
minRPM: (d["minRPM"] as? NSNumber)?.doubleValue ?? 0,
maxRPM: (d["maxRPM"] as? NSNumber)?.doubleValue ?? 0,
targetRPM: (d["targetRPM"] as? NSNumber)?.doubleValue ?? 0,
utilization: (d["utilizationPercent"] as? NSNumber)?.doubleValue ?? 0
)
}
}
// 6. Component Thermals
if let compDict = snapshot["com.i3omb.macmonitor.telemetry.thermal.components"],
let compArray = compDict["components"] as? [[String: Any]] {
self.componentTemps = compArray.compactMap { d in
guard let key = d["key"] as? String else { return nil }
return ComponentThermalItem(
key: key,
name: d["name"] as? String ?? key,
category: d["category"] as? String ?? "Other",
temperature: (d["temperature"] as? NSNumber)?.doubleValue ?? 0
)
}
}
// 7. Power
if let pwrDict = snapshot["com.i3omb.macmonitor.telemetry.power"] {
var m = PowerMetrics()
m.systemTotalWatts = (pwrDict["systemTotalWatts"] as? NSNumber)?.doubleValue ?? 0
m.cpuWatts = (pwrDict["cpuWatts"] as? NSNumber)?.doubleValue ?? 0
m.gpuWatts = (pwrDict["gpuWatts"] as? NSNumber)?.doubleValue ?? 0
m.memoryWatts = (pwrDict["memoryWatts"] as? NSNumber)?.doubleValue ?? 0
m.cpuVoltage = (pwrDict["cpuVoltage"] as? NSNumber)?.doubleValue ?? 0
m.cpuCurrent = (pwrDict["cpuCurrent"] as? NSNumber)?.doubleValue ?? 0
m.powerSource = pwrDict["powerSource"] as? String ?? "AC Power"
m.isCharging = (pwrDict["isCharging"] as? NSNumber)?.boolValue ?? false
m.batteryLevel = (pwrDict["batteryLevel"] as? NSNumber)?.doubleValue ?? 100.0
if let sensorList = pwrDict["sensors"] as? [[String: Any]] {
m.sensorReadings = sensorList.compactMap { d in
guard let k = d["key"] as? String else { return nil }
let n = d["name"] as? String ?? k
let v = (d["value"] as? NSNumber)?.doubleValue ?? 0
let u = d["unit"] as? String ?? ""
return (key: k, name: n, value: v, unit: u)
}
}
self.power = m
}
// 8. Kernel Counters
if let kDict = snapshot["com.i3omb.macmonitor.telemetry.kernel.counters"] {
var m = KernelCountersMetrics()
m.contextSwitchesPerSec = (kDict["contextSwitchesRate"] as? NSNumber)?.doubleValue ?? 0
m.syscallsPerSec = (kDict["syscallsRate"] as? NSNumber)?.doubleValue ?? 0
m.pageFaultsPerSec = (kDict["pageFaultsRate"] as? NSNumber)?.doubleValue ?? 0
m.cowFaultsPerSec = (kDict["cowFaultsRate"] as? NSNumber)?.doubleValue ?? 0
m.zeroFillFaultsPerSec = (kDict["zeroFillsRate"] as? NSNumber)?.doubleValue ?? 0
m.pageinsPerSec = (kDict["pageinsRate"] as? NSNumber)?.doubleValue ?? 0
m.pageoutsPerSec = (kDict["pageoutsRate"] as? NSNumber)?.doubleValue ?? 0
m.totalContextSwitches = (kDict["cumulative_contextSwitches"] as? NSNumber)?.uint64Value ?? 0
m.totalSyscalls = (kDict["cumulative_syscalls"] as? NSNumber)?.uint64Value ?? 0
m.totalPageFaults = (kDict["cumulative_pageFaults"] as? NSNumber)?.uint64Value ?? 0
self.kernelCounters = m
}
// 9. System Load Average & Mach Factor
if let loadDict = snapshot["com.i3omb.macmonitor.telemetry.system.load"] {
var m = SystemLoadMetrics()
m.load1Min = (loadDict["load1m"] as? NSNumber)?.doubleValue ?? 0
m.load5Min = (loadDict["load5m"] as? NSNumber)?.doubleValue ?? 0
m.load15Min = (loadDict["load15m"] as? NSNumber)?.doubleValue ?? 0
m.taskCount = (loadDict["taskCount"] as? NSNumber)?.intValue ?? 0
m.threadCount = (loadDict["threadCount"] as? NSNumber)?.intValue ?? 0
m.machFactor = (loadDict["machFactor"] as? NSNumber)?.doubleValue ?? 0
self.systemLoad = m
}
// 10. Disk I/O & IOPS
if let diskDict = snapshot["com.i3omb.macmonitor.telemetry.storage.io"],
let disks = diskDict["disks"] as? [[String: Any]] {
self.diskIO = disks.compactMap { d in
guard let bsd = d["bsdName"] as? String else { return nil }
return DiskIOItem(
bsdName: bsd,
readBps: (d["readBytesPerSec"] as? NSNumber)?.doubleValue ?? 0,
writeBps: (d["writeBytesPerSec"] as? NSNumber)?.doubleValue ?? 0,
readIOPS: (d["readIOPS"] as? NSNumber)?.doubleValue ?? 0,
writeIOPS: (d["writeIOPS"] as? NSNumber)?.doubleValue ?? 0,
totalBytesRead: (d["cumulativeReadBytes"] as? NSNumber)?.uint64Value ?? 0,
totalBytesWritten: (d["cumulativeWriteBytes"] as? NSNumber)?.uint64Value ?? 0
)
}
}
// 11. Network Bandwidth
if let netDict = snapshot["com.i3omb.macmonitor.telemetry.network.bandwidth"],
let ifaces = netDict["interfaces"] as? [[String: Any]] {
self.networkBandwidth = ifaces.compactMap { d in
guard let name = d["name"] as? String else { return nil }
return NetworkBandwidthItem(
interfaceName: name,
ipAddress: d["ipv4Address"] as? String ?? "",
isUp: (d["isUp"] as? NSNumber)?.boolValue ?? false,
downloadBps: (d["downloadBytesPerSec"] as? NSNumber)?.doubleValue ?? 0,
uploadBps: (d["uploadBytesPerSec"] as? NSNumber)?.doubleValue ?? 0,
downloadPps: (d["downloadPacketsPerSec"] as? NSNumber)?.doubleValue ?? 0,
uploadPps: (d["uploadPacketsPerSec"] as? NSNumber)?.doubleValue ?? 0,
totalBytesIn: (d["cumulativeInBytes"] as? NSNumber)?.uint64Value ?? 0,
totalBytesOut: (d["cumulativeOutBytes"] as? NSNumber)?.uint64Value ?? 0
)
}
}
// 12. Network Sockets
if let sockDict = snapshot["com.i3omb.macmonitor.telemetry.network.sockets"],
let socks = sockDict["sockets"] as? [[String: Any]] {
self.networkSockets = socks.compactMap { d in
let pid = (d["pid"] as? NSNumber)?.int32Value ?? 0
let fd = (d["fd"] as? NSNumber)?.int32Value ?? 0
return SocketItem(
pid: pid,
fd: fd,
processName: d["processName"] as? String ?? "",
protocolName: d["protocol"] as? String ?? "TCP",
localAddress: d["localAddress"] as? String ?? "*",
localPort: (d["localPort"] as? NSNumber)?.uint16Value ?? 0,
remoteAddress: d["remoteAddress"] as? String ?? "*",
remotePort: (d["remotePort"] as? NSNumber)?.uint16Value ?? 0,
tcpState: d["tcpState"] as? String ?? "ESTABLISHED"
)
}
}
// 13. Processes
if let procDict = snapshot["com.i3omb.macmonitor.telemetry.process"],
let procs = procDict["processes"] as? [[String: Any]] {
self.processes = procs.compactMap { d in
guard let pid = (d["pid"] as? NSNumber)?.int32Value else { return nil }
return ProcessItem(
pid: pid,
ppid: (d["ppid"] as? NSNumber)?.int32Value ?? 0,
name: d["name"] as? String ?? "Unknown",
cpuPercent: (d["cpuPercent"] as? NSNumber)?.doubleValue ?? 0,
residentSize: (d["residentBytes"] as? NSNumber)?.uint64Value ?? 0,
virtualSize: (d["virtualBytes"] as? NSNumber)?.uint64Value ?? 0,
threadCount: (d["threadCount"] as? NSNumber)?.int32Value ?? 1,
uid: (d["uid"] as? NSNumber)?.uint32Value ?? 0,
username: d["username"] as? String ?? "",
isStopped: (d["isStopped"] as? NSNumber)?.boolValue ?? false,
isZombie: (d["isZombie"] as? NSNumber)?.boolValue ?? false
)
}
}
// 14. GPU Telemetry
if let gpuDict = snapshot["com.i3omb.macmonitor.telemetry.gpu"],
let cards = gpuDict["gpus"] as? [[String: Any]] {
self.gpus = cards.compactMap { d in
guard let name = d["name"] as? String else { return nil }
return GPUCardItem(
name: name,
isDiscrete: (d["isDiscrete"] as? NSNumber)?.boolValue ?? false,
isLowPower: (d["isLowPower"] as? NSNumber)?.boolValue ?? false,
vramTotalBytes: (d["vramTotalBytes"] as? NSNumber)?.uint64Value ?? 0,
vramUsedBytes: (d["vramUsedBytes"] as? NSNumber)?.uint64Value ?? 0,
utilizationPercent: (d["utilizationPercent"] as? NSNumber)?.doubleValue ?? 0,
temperature: (d["temperature"] as? NSNumber)?.doubleValue ?? 0
)
}
}
// 15. Battery Health
if let battDict = snapshot["com.i3omb.macmonitor.telemetry.battery"] {
var m = BatteryHealthMetrics()
m.hasBattery = (battDict["hasBattery"] as? NSNumber)?.boolValue ?? false
m.installed = (battDict["installed"] as? NSNumber)?.boolValue ?? false
m.healthCondition = battDict["healthCondition"] as? String ?? "Normal"
m.healthPercent = (battDict["healthPercent"] as? NSNumber)?.doubleValue ?? 100.0
m.cycleCount = (battDict["cycleCount"] as? NSNumber)?.intValue ?? 0
m.designCycleCount = (battDict["designCycleCount"] as? NSNumber)?.intValue ?? 1000
m.currentCapacity = (battDict["currentCapacity"] as? NSNumber)?.intValue ?? 0
m.maxCapacity = (battDict["maxCapacity"] as? NSNumber)?.intValue ?? 0
m.designCapacity = (battDict["designCapacity"] as? NSNumber)?.intValue ?? 0
m.temperature = (battDict["temperature"] as? NSNumber)?.doubleValue ?? 0
m.voltage = (battDict["voltage"] as? NSNumber)?.doubleValue ?? 0
m.amperage = (battDict["amperage"] as? NSNumber)?.doubleValue ?? 0
m.watts = (battDict["watts"] as? NSNumber)?.doubleValue ?? 0
m.isCharging = (battDict["isCharging"] as? NSNumber)?.boolValue ?? false
m.isCharged = (battDict["isCharged"] as? NSNumber)?.boolValue ?? false
m.externalConnected = (battDict["externalConnected"] as? NSNumber)?.boolValue ?? false
m.timeRemainingMinutes = (battDict["timeRemainingMinutes"] as? NSNumber)?.intValue ?? -1
m.manufacturer = battDict["manufacturer"] as? String ?? "Apple"
m.serial = battDict["serial"] as? String ?? ""
m.adapterWatts = (battDict["adapterWatts"] as? NSNumber)?.intValue ?? 0
self.batteryHealth = m
}
// 16. Connected Peripherals
if let periphDict = snapshot["com.i3omb.macmonitor.telemetry.peripherals"] {
var allDevs: [PeripheralDeviceItem] = []
if let usb = periphDict["usbDevices"] as? [[String: Any]] {
allDevs.append(contentsOf: usb.compactMap { d in
guard let name = d["name"] as? String else { return nil }
return PeripheralDeviceItem(
name: name,
busType: "USB",
vendorName: d["vendorName"] as? String ?? "",
vendorID: (d["vendorID"] as? NSNumber)?.uint32Value ?? 0,
productID: (d["productID"] as? NSNumber)?.uint32Value ?? 0,
serialNumber: d["serialNumber"] as? String ?? "",
locationID: (d["locationID"] as? NSNumber)?.uint64Value ?? 0,
isBuiltIn: (d["isBuiltIn"] as? NSNumber)?.boolValue ?? false
)
})
}
if let tb = periphDict["thunderboltDevices"] as? [[String: Any]] {
allDevs.append(contentsOf: tb.compactMap { d in
guard let name = d["name"] as? String else { return nil }
return PeripheralDeviceItem(
name: name,
busType: "Thunderbolt",
vendorName: d["vendorName"] as? String ?? "",
vendorID: (d["vendorID"] as? NSNumber)?.uint32Value ?? 0,
productID: (d["productID"] as? NSNumber)?.uint32Value ?? 0,
serialNumber: "",
locationID: 0,
isBuiltIn: false
)
})
}
if let pci = periphDict["pciDevices"] as? [[String: Any]] {
allDevs.append(contentsOf: pci.compactMap { d in
guard let name = d["name"] as? String else { return nil }
return PeripheralDeviceItem(
name: name,
busType: "PCI",
vendorName: "Apple / Intel",
vendorID: (d["vendorID"] as? NSNumber)?.uint32Value ?? 0,
productID: (d["productID"] as? NSNumber)?.uint32Value ?? 0,
serialNumber: "",
locationID: 0,
isBuiltIn: true
)
})
}
self.peripherals = allDevs
}
// 17. Audio Devices
if let audioDict = snapshot["com.i3omb.macmonitor.telemetry.audio"],
let devs = audioDict["devices"] as? [[String: Any]] {
self.audioDevices = devs.compactMap { d in
guard let devID = (d["deviceID"] as? NSNumber)?.uint32Value else { return nil }
return AudioDeviceItem(
deviceID: devID,
name: d["name"] as? String ?? "Audio Device",
manufacturer: d["manufacturer"] as? String ?? "Apple Inc.",
isInput: (d["isInput"] as? NSNumber)?.boolValue ?? false,
isOutput: (d["isOutput"] as? NSNumber)?.boolValue ?? false,
isDefaultInput: (d["isDefaultInput"] as? NSNumber)?.boolValue ?? false,
isDefaultOutput: (d["isDefaultOutput"] as? NSNumber)?.boolValue ?? false,
sampleRate: (d["sampleRate"] as? NSNumber)?.doubleValue ?? 44100.0,
channelCount: (d["channelCount"] as? NSNumber)?.uint32Value ?? 2,
volume: (d["volume"] as? NSNumber)?.floatValue ?? 0,
isMuted: (d["isMuted"] as? NSNumber)?.boolValue ?? false
)
}
}
// 18. Display Hardware
self.displays = self.displayManager.activeDisplays()
// 19. Record to Historical Ring Buffers
let totalDownBps = self.networkBandwidth.reduce(0.0) { $0 + $1.downloadBps }
let totalUpBps = self.networkBandwidth.reduce(0.0) { $0 + $1.uploadBps }
let totalDiskReadBps = self.diskIO.reduce(0.0) { $0 + $1.readBps }
let totalDiskWriteBps = self.diskIO.reduce(0.0) { $0 + $1.writeBps }
let snapshotRecord = TelemetrySnapshotRecord(
cpuLoad: self.cpuLoad.totalLoad,
memoryUsedPercent: self.memory.utilizationPercentage,
networkInBps: totalDownBps,
networkOutBps: totalUpBps,
diskReadBps: totalDiskReadBps,
diskWriteBps: totalDiskWriteBps,
cpuTemp: self.cpuThermal.packageTemperature,
systemPowerWatts: self.power.systemTotalWatts,
timestamp: self.lastUpdateTimestamp
)
self.historyStore.record(snapshot: snapshotRecord)
// 20. Evaluate Threshold Alert Rules
var context = AlertEvaluationContext(timestamp: self.lastUpdateTimestamp)
context.peakCoreTemperature = self.cpuThermal.peakCoreTemperature
context.packageTemperature = self.cpuThermal.packageTemperature
context.fanRPMs = Dictionary(uniqueKeysWithValues: self.fans.map { ($0.index, $0.currentRPM) })
context.memoryFreeBytes = self.memory.freeBytes
context.memoryPressureLevel = self.memory.pressureLevel
context.volumes = self.storageVolumes.map {
StorageVolumeContext(
mountPoint: $0.mountPoint,
volumeName: $0.volumeName,
freeBytes: $0.freeBytes,
freePercent: $0.totalBytes > 0
? Double($0.freeBytes) / Double($0.totalBytes) * 100.0
: 0
)
}
context.batteryLevel = self.power.batteryLevel
context.hasBattery = self.batteryHealth.hasBattery
context.onExternalPower = self.batteryHealth.externalConnected
context.isCharging = self.batteryHealth.isCharging || self.power.isCharging
self.alertEngine.evaluate(context)
}
public func terminateProcess(pid: pid_t, force: Bool) -> Bool {
return MMProcessTelemetryProvider.terminateProcess(withPID: pid, force: force)
}
public func start() {
coordinator.start()
isRunning = coordinator.isRunning
}
public func stop() {
coordinator.stop()
isRunning = coordinator.isRunning
}
public func setSampleInterval(_ interval: TimeInterval) {
self.sampleInterval = interval
coordinator.sampleInterval = interval
}
public func triggerManualSample() {
coordinator.sampleImmediately()
}
public var registeredProviderCount: Int {
coordinator.registeredProviders().count
}
private static func readSysctlString(_ name: String) -> String? {
var size: size_t = 0
sysctlbyname(name, nil, &size, nil, 0)
guard size > 0 else { return nil }
var buffer = [CChar](repeating: 0, count: size)
sysctlbyname(name, &buffer, &size, nil, 0)
return String(cString: buffer)
}
private static func readSysctlInt(_ name: String) -> Int? {
var value: Int32 = 0
var size = MemoryLayout<Int32>.size
let result = sysctlbyname(name, &value, &size, nil, 0)
return result == 0 ? Int(value) : nil
}
}