import Foundation /// User-facing text for every failure the app can produce. /// /// The relay work is what forced this out of `ConnectionProbe`: with one hop there was one thing /// that could go wrong, and "请求失败" was an acceptable summary. With two hops there are four /// distinct situations that call for four different actions, and a message that cannot tell them /// apart is the difference between a five-second fix and a support thread. public enum ErrorMessage { public static let network = "暂时无法连接实例,请稍后重试。" public static let unauthorized = "实例登录状态已失效,请重新登录。" // MARK: - Relay mode /// Describes a relay-mode failure in terms of what the user should do next. public static func describe(_ error: UpstreamError, nodeName: String) -> String { switch error { case .relayUnreachable: return "无法连接中继服务器。请检查网络,或确认中继是否在运行。" case .relayTimeout: return "中继响应超时。稍后重试;如果反复出现,请检查中继负载。" case .relayRejectedDevice: return "中继已不再接受这台设备的凭据,需要在节点上重新配对。" case .relayNodeUnknown: return "中继不认识节点 \(nodeName)。可能节点已离线并被移出,或这台手机未与该节点配对。" case .agentOffline: return "节点 \(nodeName) 的 agent 当前未连接到中继。等它上线后重试。" case .nodeBusy: return "节点 \(nodeName) 正在处理其它请求,稍后重试。" case .agentTimeout: // The one message that must not invite a blind retry: the node may have executed it. return "节点 \(nodeName) 未在时限内应答。该操作可能已经执行,请先确认结果再决定是否重试。" case .relayBadEnvelope: return "中继拒绝了发往节点 \(nodeName) 的请求信封。这通常意味着两端版本不一致。" case .relayRateLimited: return "对节点 \(nodeName) 的请求过于频繁,已被中继限流。稍后再试。" case .relayPolicyDenied: return "节点 \(nodeName) 的 agent 不允许该操作。该路径不在它的授权范围内。" case .confirmationRejected: return "节点 \(nodeName) 拒绝了这次确认:确认信息与请求不匹配,操作未执行。请重新发起。" case .envelopeExpired: return "对节点 \(nodeName) 的请求已过期或重复。请重新发起;如果反复出现,请检查手机与节点的时钟。" case .nodeRateLimited: return "节点 \(nodeName) 限制了危险写操作频率,稍后再试。" case .nodeAuthFailed: return "节点 \(nodeName) 的 agent 无法登录本机 SimAdmin。需要在节点上修正 agent 的密码配置。" case .payloadTooLarge: return "请求内容超过节点 \(nodeName) 允许的大小。" case .relayResponseUnverifiable: return "节点 \(nodeName) 的应答未通过签名校验,已丢弃。这可能是中继被篡改或密钥不匹配。" case .relayResponseMismatch: return "中继返回了与请求不匹配的应答,已丢弃。" case .envelopeRejected: return "节点 \(nodeName) 拒绝了该请求的签名或格式。可能需要在节点上重新配对。" case .unauthorized: return unauthorized case .timeout, .transportFailed: return network default: return "请求失败:\(error)" } } }