Move diagnostics into settings, remove the app-local notification module, unify the global theme switcher, refine privacy copy and the instance detail experience, and rebuild the app icon.
219 lines
5.8 KiB
Swift
219 lines
5.8 KiB
Swift
import Foundation
|
|
|
|
public enum RuntimeLogSource: String, Codable, Equatable, Sendable, CaseIterable {
|
|
case delivery
|
|
|
|
public var label: String {
|
|
switch self {
|
|
case .delivery: return "节点运行"
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum RuntimeLogLevel: String, Codable, Equatable, Sendable, CaseIterable {
|
|
case info
|
|
case warning
|
|
case error
|
|
|
|
public var label: String {
|
|
switch self {
|
|
case .info: return "信息"
|
|
case .warning: return "警告"
|
|
case .error: return "错误"
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum ConnectionOutcome: String, Codable, Equatable, Sendable, CaseIterable {
|
|
case success
|
|
case stale
|
|
case failed
|
|
case unsupported
|
|
|
|
public var label: String {
|
|
switch self {
|
|
case .success: return "成功"
|
|
case .stale: return "需登录"
|
|
case .failed: return "失败"
|
|
case .unsupported: return "不支持"
|
|
}
|
|
}
|
|
}
|
|
|
|
public struct RuntimeLogEntry: Codable, Equatable, Identifiable, Sendable {
|
|
public let id: String
|
|
public let source: RuntimeLogSource
|
|
public let level: RuntimeLogLevel
|
|
public let message: String
|
|
public let eventType: String?
|
|
public let instanceID: UUID?
|
|
public let instanceName: String?
|
|
public let occurredAt: Date
|
|
public let code: String?
|
|
public let durationMs: Int?
|
|
|
|
public init(
|
|
id: String,
|
|
source: RuntimeLogSource,
|
|
level: RuntimeLogLevel,
|
|
message: String,
|
|
eventType: String? = nil,
|
|
instanceID: UUID? = nil,
|
|
instanceName: String? = nil,
|
|
occurredAt: Date,
|
|
code: String? = nil,
|
|
durationMs: Int? = nil
|
|
) {
|
|
self.id = id
|
|
self.source = source
|
|
self.level = level
|
|
self.message = message
|
|
self.eventType = eventType
|
|
self.instanceID = instanceID
|
|
self.instanceName = instanceName
|
|
self.occurredAt = occurredAt
|
|
self.code = code
|
|
self.durationMs = durationMs
|
|
}
|
|
}
|
|
|
|
public struct ConnectionLogEntry: Codable, Equatable, Identifiable, Sendable {
|
|
public let id: String
|
|
public let instanceID: UUID
|
|
public let instanceName: String
|
|
public let outcome: ConnectionOutcome
|
|
public let state: String
|
|
public let errorCode: String?
|
|
public let httpStatus: Int?
|
|
public let durationMs: Int
|
|
public let observedAt: Date
|
|
|
|
public init(
|
|
id: String,
|
|
instanceID: UUID,
|
|
instanceName: String,
|
|
outcome: ConnectionOutcome,
|
|
state: String,
|
|
errorCode: String? = nil,
|
|
httpStatus: Int? = nil,
|
|
durationMs: Int,
|
|
observedAt: Date
|
|
) {
|
|
self.id = id
|
|
self.instanceID = instanceID
|
|
self.instanceName = instanceName
|
|
self.outcome = outcome
|
|
self.state = state
|
|
self.errorCode = errorCode
|
|
self.httpStatus = httpStatus
|
|
self.durationMs = durationMs
|
|
self.observedAt = observedAt
|
|
}
|
|
}
|
|
|
|
public struct LogCapabilitySummary: Equatable, Sendable {
|
|
public let total: Int
|
|
public let supported: Int
|
|
public let unsupported: Int
|
|
public let authRequired: Int
|
|
public let degraded: Int
|
|
public let unknown: Int
|
|
|
|
public init(
|
|
total: Int,
|
|
supported: Int,
|
|
unsupported: Int,
|
|
authRequired: Int,
|
|
degraded: Int,
|
|
unknown: Int
|
|
) {
|
|
self.total = total
|
|
self.supported = supported
|
|
self.unsupported = unsupported
|
|
self.authRequired = authRequired
|
|
self.degraded = degraded
|
|
self.unknown = unknown
|
|
}
|
|
}
|
|
|
|
public struct ConnectionSummary: Equatable, Sendable {
|
|
public let total: Int
|
|
public let success: Int
|
|
public let failed: Int
|
|
public let averageDurationMs: Int
|
|
public let availabilityPercent: Int
|
|
}
|
|
|
|
public struct InstanceDiagnostic: Equatable, Identifiable, Sendable {
|
|
public let id: UUID
|
|
public let name: String
|
|
public let origin: String
|
|
public let tags: [String]
|
|
public let state: ConnectionStatus
|
|
public let healthStatus: String?
|
|
public let version: String?
|
|
public let platform: String?
|
|
public let observedAt: Date
|
|
public let featureStatus: [FeatureStatus]
|
|
public let connection: ConnectionSummary?
|
|
|
|
public init(
|
|
id: UUID,
|
|
name: String,
|
|
origin: String,
|
|
tags: [String],
|
|
state: ConnectionStatus,
|
|
healthStatus: String?,
|
|
version: String?,
|
|
platform: String?,
|
|
observedAt: Date,
|
|
featureStatus: [FeatureStatus],
|
|
connection: ConnectionSummary?
|
|
) {
|
|
self.id = id
|
|
self.name = name
|
|
self.origin = origin
|
|
self.tags = tags
|
|
self.state = state
|
|
self.healthStatus = healthStatus
|
|
self.version = version
|
|
self.platform = platform
|
|
self.observedAt = observedAt
|
|
self.featureStatus = featureStatus
|
|
self.connection = connection
|
|
}
|
|
}
|
|
|
|
public struct FeatureStatus: Equatable, Identifiable, Sendable {
|
|
public enum State: Equatable, Sendable {
|
|
case ready
|
|
case requiresLogin
|
|
case unavailable
|
|
}
|
|
|
|
public var id: String { name }
|
|
public let name: String
|
|
public let state: State
|
|
|
|
public init(name: String, state: State) {
|
|
self.name = name
|
|
self.state = state
|
|
}
|
|
}
|
|
|
|
public struct LogSnapshot: Equatable, Sendable {
|
|
public let observedAt: Date
|
|
public let runtime: [RuntimeLogEntry]
|
|
public let counts: [RuntimeLogSource: Int]
|
|
public let connections: [ConnectionLogEntry]
|
|
public let diagnostics: [InstanceDiagnostic]
|
|
}
|
|
|
|
public protocol LogStore: Sendable {
|
|
func runtimeLogs() async throws -> [RuntimeLogEntry]
|
|
func connectionLogs() async throws -> [ConnectionLogEntry]
|
|
func append(runtime: [RuntimeLogEntry], connections: [ConnectionLogEntry]) async throws
|
|
func pruneConnections(before: Date) async throws -> Int
|
|
func clearRuntimeLogs() async throws -> Int
|
|
}
|