Files
iKeyMon/Sources/Model/API/ApiFactory.swift
2025-11-17 15:42:55 +01:00

114 lines
3.5 KiB
Swift

//
// 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<T: ServerAPIProtocol>: 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
}