Files
pulse-mobile/PulseHealth/Services/HealthAPIService.swift

89 lines
4.0 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
class HealthAPIService {
static let shared = HealthAPIService()
let baseURL = "https://health.digital-home.site"
private var cachedToken: String? {
get { UserDefaults.standard.string(forKey: "healthJWTToken") }
set { UserDefaults.standard.set(newValue, forKey: "healthJWTToken") }
}
// Логин в health сервис (отдельный JWT)
func ensureToken() async throws -> String {
if let t = cachedToken { return t }
return try await refreshToken()
}
func refreshToken() async throws -> String {
var req = URLRequest(url: URL(string: "\(baseURL)/api/auth/login")!)
req.httpMethod = "POST"
req.setValue("application/json", forHTTPHeaderField: "Content-Type")
req.httpBody = try? JSONEncoder().encode(["email": "daniilklimov25@gmail.com", "password": "cosmo-health-2026"])
req.timeoutInterval = 15
let (data, _) = try await URLSession.shared.data(for: req)
struct LoginResp: Decodable { let token: String }
let resp = try JSONDecoder().decode(LoginResp.self, from: data)
cachedToken = resp.token
return resp.token
}
private func fetch<T: Decodable>(_ path: String) async throws -> T {
let token = try await ensureToken()
var req = URLRequest(url: URL(string: "\(baseURL)\(path)")!)
req.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
req.setValue("application/json", forHTTPHeaderField: "Content-Type")
req.timeoutInterval = 15
let (data, response) = try await URLSession.shared.data(for: req)
guard let http = response as? HTTPURLResponse else { throw APIError.networkError("No response") }
if http.statusCode == 401 {
// Token expired, retry once
cachedToken = nil
let newToken = try await refreshToken()
var req2 = URLRequest(url: URL(string: "\(baseURL)\(path)")!)
req2.setValue("Bearer \(newToken)", forHTTPHeaderField: "Authorization")
req2.setValue("application/json", forHTTPHeaderField: "Content-Type")
req2.timeoutInterval = 15
let (data2, _) = try await URLSession.shared.data(for: req2)
return try JSONDecoder().decode(T.self, from: data2)
}
if http.statusCode >= 400 {
throw APIError.serverError(http.statusCode, String(data: data, encoding: .utf8) ?? "")
}
return try JSONDecoder().decode(T.self, from: data)
}
func getLatest() async throws -> LatestHealthResponse {
return try await fetch("/api/health/latest")
}
func getReadiness() async throws -> ReadinessResponse {
return try await fetch("/api/health/readiness")
}
func getHeatmap(days: Int = 30) async throws -> [HeatmapEntry] {
let token = try await ensureToken()
var req = URLRequest(url: URL(string: "\(baseURL)/api/health/heatmap?days=\(days)")!)
req.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
req.timeoutInterval = 15
let (data, _) = try await URLSession.shared.data(for: req)
if let entries = try? JSONDecoder().decode([HeatmapEntry].self, from: data) { return entries }
struct HeatmapResponse: Decodable { let data: [HeatmapEntry] }
let wrapped = try JSONDecoder().decode(HeatmapResponse.self, from: data)
return wrapped.data
}
func sendHealthData(apiKey: String, payload: Data) async throws {
let url = URL(string: "\(baseURL)/api/health?key=\(apiKey)")!
var req = URLRequest(url: url)
req.httpMethod = "POST"
req.setValue("application/json", forHTTPHeaderField: "Content-Type")
req.httpBody = payload
req.timeoutInterval = 30
let (_, response) = try await URLSession.shared.data(for: req)
guard let http = response as? HTTPURLResponse, (200...299).contains(http.statusCode) else {
throw APIError.serverError((response as? HTTPURLResponse)?.statusCode ?? 0, "Ошибка отправки")
}
}
}