import Foundation import UserNotifications enum PingService { private static var previousPingStates: [String: Bool] = [:] static func ping(hostname: String, apiKey: String, notificationsEnabled: Bool = true) async -> Bool { guard let url = URL(string: "https://\(hostname)/api/v2/ping") else { print("❌ [PingService] Invalid URL for \(hostname)") return false } var request = URLRequest(url: url) request.httpMethod = "GET" request.setValue(apiKey, forHTTPHeaderField: "X-API-KEY") request.timeoutInterval = 10 do { let (data, response) = try await URLSession.shared.data(for: request) if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode != 200 { if let responseString = String(data: data, encoding: .utf8) { print("❌ [PingService] HTTP \(httpResponse.statusCode): \(responseString)") } handlePingFailure(for: hostname, notificationsEnabled: notificationsEnabled) return false } if let result = try? JSONDecoder().decode([String: String].self, from: data), result["response"] == "pong" { handlePingSuccess(for: hostname, notificationsEnabled: notificationsEnabled) return true } else { handlePingFailure(for: hostname, notificationsEnabled: notificationsEnabled) return false } } catch { print("❌ [PingService] Error pinging \(hostname): \(error)") handlePingFailure(for: hostname, notificationsEnabled: notificationsEnabled) return false } } private static func handlePingSuccess(for hostname: String, notificationsEnabled: Bool) { let wasPreviouslyDown = previousPingStates[hostname] == false previousPingStates[hostname] = true if wasPreviouslyDown && notificationsEnabled { sendNotification(title: "Server Online", body: "\(hostname) is now online") } } private static func handlePingFailure(for hostname: String, notificationsEnabled: Bool) { let wasPreviouslyUp = previousPingStates[hostname] != false previousPingStates[hostname] = false if wasPreviouslyUp && notificationsEnabled { sendNotification(title: "Server Offline", body: "\(hostname) is offline") } } private static func sendNotification(title: String, body: String) { let content = UNMutableNotificationContent() content.title = title content.body = body content.sound = .default let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) UNUserNotificationCenter.current().add(request) } }