84 lines
2.7 KiB
Swift
84 lines
2.7 KiB
Swift
import Foundation
|
|
import SwiftUI
|
|
import Observation
|
|
|
|
@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]] = [:]
|
|
|
|
/// 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
|
|
|
|
setupCoordinator()
|
|
}
|
|
|
|
private func setupCoordinator() {
|
|
coordinator.sampleInterval = self.sampleInterval
|
|
coordinator.snapshotHandler = { [weak self] snapshot in
|
|
guard let self else { return }
|
|
self.latestSnapshot = snapshot
|
|
self.lastUpdateTimestamp = Date()
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|