// // ApiFactory.swift // iKeyMon // // Created by tracer on 13.11.25. // import Foundation enum APIVersion: String, CaseIterable { case v2_12 = "2.12" static func from(versionString: String) -> APIVersion? { if let version = APIVersion(rawValue: versionString) { return version } let components = versionString.split(separator: ".").compactMap { Int($0) } guard components.count >= 2 else { return nil } let major = components[0] let minor = components[1] switch (major, minor) { case (2, 12...): return .v2_12 default: return nil } } } protocol AnyServerAPI { func fetchSystemInfo() async throws -> SystemInfo func fetchLoadData() async throws -> Any func fetchMemoryData() async throws -> Any func fetchUtilizationData() async throws -> Any func fetchServerSummary(apiKey: String) async throws -> ServerInfo } private struct AnyServerAPIWrapper: AnyServerAPI { private let wrapped: T init(_ wrapped: T) { self.wrapped = wrapped } func fetchSystemInfo() async throws -> SystemInfo { return try await wrapped.fetchSystemInfo() } func fetchLoadData() async throws -> Any { return try await wrapped.fetchLoad() } func fetchMemoryData() async throws -> Any { return try await wrapped.fetchMemory() } func fetchUtilizationData() async throws -> Any { return try await wrapped.fetchUtilization() } func fetchServerSummary(apiKey: String) async throws -> ServerInfo { return try await wrapped.fetchServerSummary(apiKey: apiKey) } } class APIFactory { static func createAPI(baseURL: URL, version: APIVersion) -> AnyServerAPI { switch version { case .v2_12: return AnyServerAPIWrapper(APIv2_12(baseURL: baseURL)) } } static func createAPI(baseURL: URL, versionString: String) -> AnyServerAPI? { guard let version = APIVersion.from(versionString: versionString) else { return nil } return createAPI(baseURL: baseURL, version: version) } static func detectAndCreateAPI(baseURL: URL, apiKey: String? = nil) async throws -> AnyServerAPI { if let apiKey, !apiKey.isEmpty { do { let versionURL = baseURL.appendingPathComponent("api/v2/server") var request = URLRequest(url: versionURL) request.httpMethod = "GET" request.setValue(apiKey, forHTTPHeaderField: "X-API-KEY") request.timeoutInterval = 15 let (data, response) = try await URLSession.shared.data(for: request) if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 { let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase let probe = try decoder.decode(ServerMetaProbe.self, from: data) if let api = createAPI(baseURL: baseURL, versionString: probe.meta.apiVersion) { return api } } } catch { // Fall back to default version below } } return AnyServerAPIWrapper(APIv2_12(baseURL: baseURL)) } } private struct ServerMetaProbe: Decodable { struct Meta: Decodable { let apiVersion: String } let meta: Meta }