import Foundation import UIKit #if os(iOS) import SystemConfiguration #endif /// Device state collector public struct DeviceStateCollector { /// Collect current device state public static func collect() -> DiagnosticsDeviceState { #if os(iOS) return DiagnosticsDeviceState( memoryMB: getMemoryUsage(), batteryLevel: getBatteryLevel(), isCharging: getIsCharging(), storageMB: getStorageUsage(), networkType: getNetworkType(), isOnline: getIsOnline(), thermalState: getThermalState() ) #elseif os(macOS) return DiagnosticsDeviceState( memoryMB: getMemoryUsage(), batteryLevel: nil, isCharging: nil, storageMB: nil, networkType: nil, isOnline: getIsOnline(), thermalState: nil ) #else return DiagnosticsDeviceState( memoryMB: nil, batteryLevel: nil, isCharging: nil, storageMB: nil, networkType: nil, isOnline: true, thermalState: nil ) #endif } #if os(iOS) private static func getMemoryUsage() -> Int? { var info = mach_task_basic_info() var count = mach_msg_type_number_t(MemoryLayout.size)/4 let kerr: kern_return_t = withUnsafeMutablePointer(to: &info) { $0.withMemoryRebound(to: integer_t.self, capacity: 1) { task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count) } } guard kerr == KERN_SUCCESS else { return nil } return Int(info.resident_size / 1024 / 1024) } private static func getBatteryLevel() -> Double? { UIDevice.current.isBatteryMonitoringEnabled = true return Double(UIDevice.current.batteryLevel) } private static func getIsCharging() -> Bool? { UIDevice.current.isBatteryMonitoringEnabled = true return UIDevice.current.batteryState == .charging } private static func getStorageUsage() -> Int? { do { let attributes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory()) if let totalSize = attributes[.systemSize] as? NSNumber, let freeSize = attributes[.systemFreeSize] as? NSNumber { let usedSize = totalSize.int64Value - freeSize.int64Value return Int(usedSize / 1024 / 1024) } } catch { return nil } return nil } private static func getNetworkType() -> String? { // Simplified - would need more complex reachability check for actual implementation if getIsOnline() { return "wifi" // Default assumption } return "offline" } private static func getThermalState() -> DiagnosticsThermalState? { switch ProcessInfo.processInfo.thermalState { case .nominal: return .nominal case .fair: return .fair case .serious: return .serious case .critical: return .critical @unknown default: return nil } } #endif private static func getIsOnline() -> Bool { #if os(iOS) || os(macOS) var zeroAddress = sockaddr_in() zeroAddress.sin_len = UInt8(MemoryLayout.size) zeroAddress.sin_family = sa_family_t(AF_INET) guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, { $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { SCNetworkReachabilityCreateWithAddress(nil, $0) } }) else { return false } var flags: SCNetworkReachabilityFlags = [] if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) { return false } let isReachable = flags.contains(.reachable) let needsConnection = flags.contains(.connectionRequired) return isReachable && !needsConnection #else return true #endif } } // MARK: - Connectivity Monitoring #if os(iOS) || os(macOS) import SystemConfiguration /// Monitor network connectivity changes public final class ConnectivityMonitor { private var reachability: SCNetworkReachability? private var callback: ((Bool) -> Void)? public init() { var zeroAddress = sockaddr_in() zeroAddress.sin_len = UInt8(MemoryLayout.size) zeroAddress.sin_family = sa_family_t(AF_INET) reachability = withUnsafePointer(to: &zeroAddress) { $0.withMemoryRebound(to: sockaddr.self, capacity: 1) { SCNetworkReachabilityCreateWithAddress(nil, $0) } } } public func startMonitoring(callback: @escaping (Bool) -> Void) { self.callback = callback guard let reachability = reachability else { return } let context = SCNetworkReachabilityContext( version: 0, info: Unmanaged.passUnretained(self).toOpaque(), retain: nil, release: nil, copyDescription: nil ) SCNetworkReachabilitySetCallback(reachability, { (_, flags, info) in guard let info = info else { return } let monitor = Unmanaged.fromOpaque(info).takeUnretainedValue() let isReachable = flags.contains(.reachable) let needsConnection = flags.contains(.connectionRequired) let isConnected = isReachable && !needsConnection monitor.callback?(isConnected) }, &context) SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue) } public func stopMonitoring() { guard let reachability = reachability else { return } SCNetworkReachabilityUnscheduleFromRunLoop(reachability, CFRunLoopGetMain(), CFRunLoopMode.commonModes.rawValue) } } #endif