项目文件夹

文件
2026-07-13 12:22:33 +08:00

188 行
5.7 KiB
Swift

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
import CodexBarCore
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
struct ProviderPayload: Encodable {
let provider: String
let account: String?
let cacheAccountKey: String?
let version: String?
let source: String
let status: ProviderStatusPayload?
let usage: UsageSnapshot?
let credits: CreditsSnapshot?
let antigravityPlanInfo: AntigravityPlanInfoSummary?
let openaiDashboard: OpenAIDashboardSnapshot?
let error: ProviderErrorPayload?
let pace: ProviderPacePayload?
private enum CodingKeys: String, CodingKey {
case provider
case account
case version
case source
case status
case usage
case credits
case antigravityPlanInfo
case openaiDashboard
case error
case pace
}
init(
provider: UsageProvider,
account: String?,
cacheAccountKey: String? = nil,
version: String?,
source: String,
status: ProviderStatusPayload?,
usage: UsageSnapshot?,
credits: CreditsSnapshot?,
antigravityPlanInfo: AntigravityPlanInfoSummary?,
openaiDashboard: OpenAIDashboardSnapshot?,
error: ProviderErrorPayload?,
pace: ProviderPacePayload? = nil)
{
self.provider = provider.rawValue
self.account = account
self.cacheAccountKey = cacheAccountKey
self.version = version
self.source = source
self.status = status
self.usage = usage
self.credits = credits
self.antigravityPlanInfo = antigravityPlanInfo
self.openaiDashboard = openaiDashboard
self.error = error
self.pace = pace
}
init(
providerID: String,
account: String?,
cacheAccountKey: String? = nil,
version: String?,
source: String,
status: ProviderStatusPayload?,
usage: UsageSnapshot?,
credits: CreditsSnapshot?,
antigravityPlanInfo: AntigravityPlanInfoSummary?,
openaiDashboard: OpenAIDashboardSnapshot?,
error: ProviderErrorPayload?,
pace: ProviderPacePayload? = nil)
{
self.provider = providerID
self.account = account
self.cacheAccountKey = cacheAccountKey
self.version = version
self.source = source
self.status = status
self.usage = usage
self.credits = credits
self.antigravityPlanInfo = antigravityPlanInfo
self.openaiDashboard = openaiDashboard
self.error = error
self.pace = pace
}
}
struct ProviderPacePayload: Encodable {
let primary: PacePayload?
let secondary: PacePayload?
}
struct PacePayload: Encodable {
let stage: String
/// Rounded (used expected); positive = deficit, negative = reserve.
let deltaPercent: Double
let expectedUsedPercent: Double
let willLastToReset: Bool
let etaSeconds: TimeInterval?
/// Always absent in CLI output; kept for schema parity.
let runOutProbability: Double?
let summary: String
}
struct ProviderStatusPayload: Encodable {
let indicator: ProviderStatusIndicator
let description: String?
let updatedAt: Date?
let url: String
enum ProviderStatusIndicator: String, Encodable {
case none
case minor
case major
case critical
case maintenance
case unknown
var label: String {
switch self {
case .none: "Operational"
case .minor: "Partial outage"
case .major: "Major outage"
case .critical: "Critical issue"
case .maintenance: "Maintenance"
case .unknown: "Status unknown"
}
}
}
var descriptionSuffix: String {
guard let description, !description.isEmpty else { return "" }
return " – \(description)"
}
}
enum StatusFetcher {
static func fetch(from baseURL: URL) async throws -> ProviderStatusPayload {
let apiURL = baseURL.appendingPathComponent("api/v2/status.json")
var request = URLRequest(url: apiURL)
request.timeoutInterval = 10
let (data, _) = try await URLSession.shared.data(for: request)
struct Response: Decodable {
struct Status: Decodable {
let indicator: String
let description: String?
}
struct Page: Decodable {
let updatedAt: Date?
private enum CodingKeys: String, CodingKey {
case updatedAt = "updated_at"
}
}
let page: Page?
let status: Status
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom { decoder in
let container = try decoder.singleValueContainer()
let raw = try container.decode(String.self)
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
if let date = formatter.date(from: raw) { return date }
formatter.formatOptions = [.withInternetDateTime]
if let date = formatter.date(from: raw) { return date }
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid ISO8601 date")
}
let response = try decoder.decode(Response.self, from: data)
let indicator = ProviderStatusPayload.ProviderStatusIndicator(rawValue: response.status.indicator) ?? .unknown
return ProviderStatusPayload(
indicator: indicator,
description: response.status.description,
updatedAt: response.page?.updatedAt,
url: baseURL.absoluteString)
}
}