174 lines
6.1 KiB
Swift
174 lines
6.1 KiB
Swift
import Foundation
|
|
|
|
// swiftformat:disable:next redundantSendable
|
|
struct AntigravityQuotaSummary: Sendable, Equatable {
|
|
let description: String?
|
|
let groups: [AntigravityQuotaSummaryGroup]
|
|
}
|
|
|
|
// swiftformat:disable:next redundantSendable
|
|
struct AntigravityQuotaSummaryGroup: Sendable, Equatable {
|
|
let displayName: String
|
|
let description: String?
|
|
let buckets: [AntigravityQuotaSummaryBucket]
|
|
}
|
|
|
|
// swiftformat:disable:next redundantSendable
|
|
struct AntigravityQuotaSummaryBucket: Sendable, Equatable {
|
|
let bucketId: String
|
|
let displayName: String
|
|
let remainingFraction: Double?
|
|
let resetTime: Date?
|
|
let resetDescription: String?
|
|
let disabled: Bool
|
|
|
|
init(
|
|
bucketId: String,
|
|
displayName: String,
|
|
remainingFraction: Double?,
|
|
resetTime: Date? = nil,
|
|
resetDescription: String?,
|
|
disabled: Bool)
|
|
{
|
|
self.bucketId = bucketId
|
|
self.displayName = displayName
|
|
self.remainingFraction = remainingFraction
|
|
self.resetTime = resetTime
|
|
self.resetDescription = resetDescription
|
|
self.disabled = disabled
|
|
}
|
|
}
|
|
|
|
extension AntigravityStatusProbe {
|
|
static func parseQuotaSummaryResponse(_ data: Data) throws -> AntigravityStatusSnapshot {
|
|
let decoder = JSONDecoder()
|
|
let response = try decoder.decode(QuotaSummaryResponse.self, from: data)
|
|
if let invalid = Self.invalidCode(response.code) {
|
|
throw AntigravityStatusProbeError.apiError(invalid)
|
|
}
|
|
let payload = response.response ?? response.summary ?? response.rootPayload
|
|
guard let payload else {
|
|
throw AntigravityStatusProbeError.parseFailed("Missing quota summary")
|
|
}
|
|
let groups = payload.groups.compactMap(self.quotaSummaryGroup(from:))
|
|
guard !groups.isEmpty else {
|
|
throw AntigravityStatusProbeError.parseFailed("Missing quota groups")
|
|
}
|
|
return AntigravityStatusSnapshot(
|
|
quotaSummary: AntigravityQuotaSummary(
|
|
description: payload.description,
|
|
groups: groups),
|
|
accountEmail: nil,
|
|
accountPlan: nil,
|
|
source: .local)
|
|
}
|
|
|
|
private static func quotaSummaryGroup(from payload: QuotaSummaryGroupPayload) -> AntigravityQuotaSummaryGroup? {
|
|
let displayName = payload.displayName?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
let buckets = (payload.buckets ?? []).compactMap(self.quotaSummaryBucket(from:))
|
|
guard !buckets.isEmpty else { return nil }
|
|
return AntigravityQuotaSummaryGroup(
|
|
displayName: self.nonEmpty(displayName) ?? "Quota",
|
|
description: payload.description,
|
|
buckets: buckets)
|
|
}
|
|
|
|
private static func quotaSummaryBucket(from payload: QuotaSummaryBucketPayload) -> AntigravityQuotaSummaryBucket? {
|
|
let bucketId = payload.bucketId?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
let displayName = payload.displayName?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
guard let resolvedBucketId = bucketId, !resolvedBucketId.isEmpty else { return nil }
|
|
let resetTime = payload.resetTime.flatMap { Self.parseDate($0) }
|
|
return AntigravityQuotaSummaryBucket(
|
|
bucketId: resolvedBucketId,
|
|
displayName: self.nonEmpty(displayName) ?? resolvedBucketId,
|
|
remainingFraction: payload.resolvedRemainingFraction,
|
|
resetTime: resetTime,
|
|
resetDescription: payload.description,
|
|
disabled: payload.disabled ?? false)
|
|
}
|
|
|
|
private static func nonEmpty(_ value: String?) -> String? {
|
|
guard let value, !value.isEmpty else { return nil }
|
|
return value
|
|
}
|
|
}
|
|
|
|
private struct QuotaSummaryResponse: Decodable {
|
|
let code: CodeValue?
|
|
let message: String?
|
|
let response: QuotaSummaryPayload?
|
|
let summary: QuotaSummaryPayload?
|
|
let description: String?
|
|
let groups: [QuotaSummaryGroupPayload]?
|
|
|
|
var rootPayload: QuotaSummaryPayload? {
|
|
guard let groups else { return nil }
|
|
return QuotaSummaryPayload(description: self.description, groups: groups)
|
|
}
|
|
}
|
|
|
|
private struct QuotaSummaryPayload: Decodable {
|
|
let description: String?
|
|
let groups: [QuotaSummaryGroupPayload]
|
|
|
|
init(description: String?, groups: [QuotaSummaryGroupPayload]) {
|
|
self.description = description
|
|
self.groups = groups
|
|
}
|
|
|
|
private enum CodingKeys: String, CodingKey {
|
|
case description
|
|
case groups
|
|
}
|
|
|
|
init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
self.description = try container.decodeIfPresent(String.self, forKey: .description)
|
|
self.groups = try container.decodeIfPresent([QuotaSummaryGroupPayload].self, forKey: .groups) ?? []
|
|
}
|
|
}
|
|
|
|
private struct QuotaSummaryGroupPayload: Decodable {
|
|
let displayName: String?
|
|
let description: String?
|
|
let buckets: [QuotaSummaryBucketPayload]?
|
|
}
|
|
|
|
private struct QuotaSummaryBucketPayload: Decodable {
|
|
let bucketId: String?
|
|
let displayName: String?
|
|
let description: String?
|
|
let disabled: Bool?
|
|
let remainingFraction: Double?
|
|
let remaining: QuotaSummaryRemainingPayload?
|
|
let resetTime: String?
|
|
|
|
var resolvedRemainingFraction: Double? {
|
|
self.remainingFraction ?? self.remaining?.remainingFraction
|
|
}
|
|
}
|
|
|
|
private struct QuotaSummaryRemainingPayload: Decodable {
|
|
let remainingFraction: Double?
|
|
|
|
private enum CodingKeys: String, CodingKey {
|
|
case remainingFraction
|
|
case oneofCase = "case"
|
|
case value
|
|
}
|
|
|
|
init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
if let remainingFraction = try container.decodeIfPresent(Double.self, forKey: .remainingFraction) {
|
|
self.remainingFraction = remainingFraction
|
|
return
|
|
}
|
|
let oneofCase = try container.decodeIfPresent(String.self, forKey: .oneofCase)
|
|
if oneofCase == "remainingFraction" {
|
|
self.remainingFraction = try container.decodeIfPresent(Double.self, forKey: .value)
|
|
} else {
|
|
self.remainingFraction = nil
|
|
}
|
|
}
|
|
}
|