Files
iKeyMon/Sources/Model/API/ServerInfo.swift
2025-12-07 16:47:34 +01:00

271 lines
8.6 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 { [fullVersion, path ?? ""].joined(separator: "|") }
let version: String
let fullVersion: String
let path: String?
let configFile: String?
let extensions: [String]
let memoryLimit: String?
let maxExecutionTime: String?
init(
version: String,
fullVersion: String? = nil,
path: String? = nil,
configFile: String? = nil,
extensions: [String] = [],
memoryLimit: String? = nil,
maxExecutionTime: String? = nil
) {
self.version = version
self.fullVersion = fullVersion ?? version
self.path = path
self.configFile = configFile
self.extensions = extensions
self.memoryLimit = memoryLimit
self.maxExecutionTime = maxExecutionTime
}
var versionWithPath: String {
var components = [fullVersion]
if let path, !path.isEmpty {
components.append(path)
}
return components.joined(separator: " ")
}
}
struct OperatingSystem: Codable, Hashable, Equatable {
struct UpdateStatus: Codable, Hashable, Equatable {
let updateCount: Int
let securityUpdateCount: Int
let rebootRequired: Bool
init(updateCount: Int, securityUpdateCount: Int, rebootRequired: Bool) {
self.updateCount = updateCount
self.securityUpdateCount = securityUpdateCount
self.rebootRequired = rebootRequired
}
}
let label: String
let distribution: String
let version: String
let architecture: String
let endOfLife: Bool
let updates: UpdateStatus?
init(
label: String,
distribution: String,
version: String,
architecture: String,
endOfLife: Bool,
updates: UpdateStatus?
) {
self.label = label
self.distribution = distribution
self.version = version
self.architecture = architecture
self.endOfLife = endOfLife
self.updates = updates
}
}
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 emailsInQueue: Int?
var operatingSystem: OperatingSystem?
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 {
let normalizedServerTime = ServerInfo.normalizedServerTime(serverTime)
if let date = ServerInfo.serverTimeParsers
.lazy
.compactMap({ $0.date(from: normalizedServerTime) })
.first {
return ServerInfo.displayFormatter.string(from: date)
}
return serverTime
}
var operatingSystemSummary: String? {
guard let operatingSystem else { return nil }
let components = [
operatingSystem.label,
operatingSystem.architecture
].filter { !$0.isEmpty }
return components.isEmpty ? nil : components.joined(separator: "")
}
}
// MARK: - Helpers & Sample Data
extension ServerInfo {
private static let serverTimeParsers: [ISO8601DateFormatter] = {
let withFractional = ISO8601DateFormatter()
withFractional.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let withoutFractional = ISO8601DateFormatter()
withoutFractional.formatOptions = [.withInternetDateTime]
let noColonTimeZone = ISO8601DateFormatter()
noColonTimeZone.formatOptions = [.withFullDate, .withTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withTimeZone]
return [withFractional, withoutFractional, noColonTimeZone]
}()
private static let displayFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = .autoupdatingCurrent
formatter.dateStyle = .medium
formatter.timeStyle = .medium
return formatter
}()
private static func normalizedServerTime(_ value: String) -> String {
if value.range(of: #"[+-]\d{2}:\d{2}$"#, options: .regularExpression) != nil {
return value
}
guard value.range(of: #"[+-]\d{4}$"#, options: .regularExpression) != nil else {
return value
}
var normalized = value
let insertionIndex = normalized.index(normalized.endIndex, offsetBy: -2)
normalized.insert(":", at: insertionIndex)
return normalized
}
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,
emailsInQueue: 0,
operatingSystem: OperatingSystem(
label: "Debian 12.12 (64-bit)",
distribution: "Debian",
version: "12.12",
architecture: "x86_64",
endOfLife: false,
updates: OperatingSystem.UpdateStatus(
updateCount: 12,
securityUpdateCount: 8,
rebootRequired: true
)
),
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")
]
)
}