import Foundation // MARK: - Server Info Domain Model struct ServerInfo: Codable, Hashable, Equatable { struct Load: Codable, Hashable, Equatable { let minute1: Double let minute5: Double let minute15: Double let percent: Double let cpuCount: Int let level: String init(minute1: Double, minute5: Double, minute15: Double, percent: Double, cpuCount: Int, level: String) { self.minute1 = minute1 self.minute5 = minute5 self.minute15 = minute15 self.percent = percent self.cpuCount = cpuCount self.level = level } } struct Memory: Codable, Hashable, Equatable { let free: Int let used: Int let total: Int let percent: Double init(free: Int, used: Int, total: Int, percent: Double) { self.free = free self.used = used self.total = total self.percent = percent } } struct DiskSpace: Codable, Hashable, Equatable { let free: Int let used: Int let total: Int let percent: Double init(free: Int, used: Int, total: Int, percent: Double) { self.free = free self.used = used self.total = total self.percent = percent } } struct ServicePort: Codable, Hashable, Identifiable, Equatable { var id: String { "\(service)-\(port)-\(proto)" } let service: String let status: String let port: Int let proto: String init(service: String, status: String, port: Int, proto: String) { self.service = service self.status = status self.port = port self.proto = proto } } struct PHPInterpreter: Codable, Hashable, Identifiable, Equatable { var id: String { versionFull } let version: String let path: String? let configFile: String? let extensions: [String] let memoryLimit: String? let maxExecutionTime: String? init( version: String, path: String? = nil, configFile: String? = nil, extensions: [String] = [], memoryLimit: String? = nil, maxExecutionTime: String? = nil ) { self.version = version self.path = path self.configFile = configFile self.extensions = extensions self.memoryLimit = memoryLimit self.maxExecutionTime = maxExecutionTime } var versionFull: String { var components = [version] if let path, !path.isEmpty { components.append(path) } return components.joined(separator: " – ") } } var hostname: String var ipAddresses: [String] var cpuCores: Int var serverTime: String var uptime: String var processCount: Int var apacheVersion: String var phpVersion: String var mysqlVersion: String? var mariadbVersion: String? var ports: [ServicePort]? var load: Load var memory: Memory var swap: Memory var diskSpace: DiskSpace var panelVersion: String var panelBuild: String var apiVersion: String var additionalPHPInterpreters: [PHPInterpreter]? var formattedVersion: String { "KeyHelp \(panelVersion) • Build \(panelBuild) • API \(apiVersion)" } var formattedServerTime: String { guard let date = ServerInfo.isoFormatter.date(from: serverTime) else { return serverTime } return ServerInfo.displayFormatter.string(from: date) } } // MARK: - Helpers & Sample Data extension ServerInfo { private static let isoFormatter: ISO8601DateFormatter = { let formatter = ISO8601DateFormatter() formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds, .withColonSeparatorInTimeZone] return formatter }() private static let displayFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateStyle = .medium formatter.timeStyle = .medium return formatter }() static let placeholder = ServerInfo( hostname: "preview.example.com", ipAddresses: ["192.168.1.1", "fe80::1"], cpuCores: 4, serverTime: "2025-04-04T18:00:00+0200", uptime: "3 Days / 12 Hours / 30 Minutes", processCount: 123, apacheVersion: "2.4.58", phpVersion: "8.2.12", mysqlVersion: "8.0.33", mariadbVersion: nil, ports: [ ServicePort(service: "HTTP", status: "online", port: 80, proto: "tcp"), ServicePort(service: "HTTPS", status: "online", port: 443, proto: "tcp"), ServicePort(service: "SSH", status: "offline", port: 22, proto: "tcp") ], load: Load(minute1: 0.5, minute5: 0.3, minute15: 0.2, percent: 10.0, cpuCount: 4, level: "low"), memory: Memory(free: 8_000_000_000, used: 4_000_000_000, total: 12_000_000_000, percent: 33.3), swap: Memory(free: 4_000_000_000, used: 1_000_000_000, total: 5_000_000_000, percent: 20.0), diskSpace: DiskSpace(free: 100_000_000_000, used: 50_000_000_000, total: 150_000_000_000, percent: 33.3), panelVersion: "25.0", panelBuild: "3394", apiVersion: "2", additionalPHPInterpreters: [ PHPInterpreter(version: "8.3", path: "/usr/bin/php8.3"), PHPInterpreter(version: "8.2", path: "/usr/bin/php8.2") ] ) }