import Foundation public protocol SimAdminClientProtocol: Sendable { func send(_ route: UpstreamRoute, baseURL: URL, cookie: String?) async throws -> UpstreamResponse } extension SimAdminClient: SimAdminClientProtocol {} public enum ConnectionStatus: String, Equatable, Sendable { case online case offline case authRequired case degraded case unknown public var label: String { switch self { case .online: return "在线" case .offline: return "离线" case .authRequired: return "需登录" case .degraded: return "降级" case .unknown: return "未知" } } } public struct ConnectionResult: Equatable, Sendable { public let status: ConnectionStatus public let checkedAt: Date public init(status: ConnectionStatus, checkedAt: Date) { self.status = status self.checkedAt = checkedAt } } public struct ConnectionProbe: Sendable { private let client: any SimAdminClientProtocol public init(client: any SimAdminClientProtocol) { self.client = client } public func test(_ instance: Instance) async throws -> ConnectionResult { do { let response = try await client.send(.health, baseURL: instance.origin, cookie: nil) if response.status == 401 || response.status == 403 { return ConnectionResult(status: .authRequired, checkedAt: Date()) } return ConnectionResult(status: .online, checkedAt: Date()) } catch { switch error { case UpstreamError.unauthorized: return ConnectionResult(status: .authRequired, checkedAt: Date()) case UpstreamError.timeout, is URLError: return ConnectionResult(status: .offline, checkedAt: Date()) default: return ConnectionResult(status: .degraded, checkedAt: Date()) } } } }