BLLicenseClient.checkStatus: percent-encode key before inserting into URL path to prevent malformed URLs with special characters. BLKillSwitchClient: add X-Product-Id and X-Request-Id headers for consistency with BLPlatformClient request tracing pattern.
61 lines
2.3 KiB
Swift
61 lines
2.3 KiB
Swift
// ── Kill Switch Client ──────────────────────────────────────
|
|
// Checks platform-service kill switch at app launch.
|
|
// If the app is disabled server-side, surfaces a maintenance message.
|
|
// Fails open — network errors allow the app to run.
|
|
|
|
import Foundation
|
|
|
|
/// Generic kill switch client for all ByteLyst iOS apps.
|
|
/// Checks GET /api/settings/kill-switch?productId=X at launch.
|
|
public final class BLKillSwitchClient {
|
|
|
|
private let config: BLPlatformConfig
|
|
|
|
/// Whether the app is disabled by the server.
|
|
public private(set) var isDisabled = false
|
|
|
|
/// Maintenance message from the server (empty if not disabled).
|
|
public private(set) var maintenanceMessage = ""
|
|
|
|
public init(config: BLPlatformConfig) {
|
|
self.config = config
|
|
}
|
|
|
|
/// Check kill switch status. Non-blocking — defaults to enabled on failure (fail open).
|
|
public func check() async {
|
|
guard let url = URL(string: "\(config.baseURL)/api/settings/kill-switch?productId=\(config.productId)") else { return }
|
|
|
|
var request = URLRequest(url: url)
|
|
request.timeoutInterval = 5
|
|
request.setValue(config.productId, forHTTPHeaderField: "X-Product-Id")
|
|
request.setValue(UUID().uuidString, forHTTPHeaderField: "X-Request-Id")
|
|
|
|
do {
|
|
let (data, response) = try await URLSession.shared.data(for: request)
|
|
guard let http = response as? HTTPURLResponse, http.statusCode == 200 else { return }
|
|
|
|
struct KillSwitchResponse: Codable {
|
|
let enabled: Bool?
|
|
let disabled: Bool?
|
|
let message: String?
|
|
}
|
|
|
|
let result = try JSONDecoder().decode(KillSwitchResponse.self, from: data)
|
|
|
|
// Support both `enabled: false` and `disabled: true` patterns
|
|
if result.disabled == true || result.enabled == false {
|
|
isDisabled = true
|
|
maintenanceMessage = result.message ?? "\(config.productId) is temporarily unavailable for maintenance."
|
|
}
|
|
} catch {
|
|
// Network error — allow the app to run (fail open)
|
|
}
|
|
}
|
|
|
|
/// Reset the kill switch state (e.g. for retry).
|
|
public func reset() {
|
|
isDisabled = false
|
|
maintenanceMessage = ""
|
|
}
|
|
}
|