import Foundation import ComposableArchitecture // MARK: - HTTP Method enum HTTPMethod: String, CaseIterable { case GET = "GET" case POST = "POST" case PUT = "PUT" case DELETE = "DELETE" case PATCH = "PATCH" } // MARK: - API Error Types enum APIError: Error, Equatable { case invalidURL case noData case decodingError(String) case networkError(String) case httpError(statusCode: Int, message: String?) case timeout case resourceTooLarge case unknown(String) var localizedDescription: String { switch self { case .invalidURL: return "无效的 URL" case .noData: return "没有收到数据" case .decodingError(let message): return "数据解析失败: \(message)" case .networkError(let message): return "网络错误: \(message)" case .httpError(let statusCode, let message): return "HTTP 错误 \(statusCode): \(message ?? "未知错误")" case .timeout: return "请求超时" case .resourceTooLarge: return "响应数据过大" case .unknown(let message): return "未知错误: \(message)" } } } // MARK: - Base Request Parameters struct BaseRequest: Codable { let acceptLanguage: String let os: String = "iOS" let osVersion: String let ispType: String let channel: String = "molistar_enterprise" let model: String let deviceId: String let appVersion: String let app: String = "youmi" let mcc: String? let spType: String? let pubSign: String enum CodingKeys: String, CodingKey { case acceptLanguage = "Accept-Language" case appVersion = "appVersion" case os, osVersion, ispType, channel, model, deviceId case app, mcc, spType case pubSign = "pub_sign" } init() { // 获取系统首选语言 self.acceptLanguage = Locale.current.languageCode ?? "en" // 获取系统版本 self.osVersion = UIDevice.current.systemVersion // 获取设备型号 self.model = UIDevice.current.model // 生成设备ID (这里使用 identifierForVendor,实际项目中可能需要更稳定的方案) self.deviceId = UIDevice.current.identifierForVendor?.uuidString ?? UUID().uuidString // 获取应用版本 self.appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0.0" // 运营商相关信息(简化处理) self.ispType = "65535" self.mcc = nil self.spType = nil // 生成签名(这里使用时间戳的 MD5,实际项目中需要根据具体签名规则) let timestamp = String(Int(Date().timeIntervalSince1970)) self.pubSign = timestamp.md5() } } // MARK: - API Request Protocol protocol APIRequestProtocol { associatedtype Response: Codable var endpoint: String { get } var method: HTTPMethod { get } var queryParameters: [String: String]? { get } var bodyParameters: [String: Any]? { get } var headers: [String: String]? { get } var timeout: TimeInterval { get } var includeBaseParameters: Bool { get } } extension APIRequestProtocol { var timeout: TimeInterval { 30.0 } var includeBaseParameters: Bool { true } var headers: [String: String]? { nil } } // MARK: - Generic API Response struct APIResponse: Codable { let data: T? let status: String? let message: String? let code: Int? } // MARK: - String MD5 Extension extension String { func md5() -> String { let data = Data(self.utf8) let hash = data.withUnsafeBytes { bytes -> [UInt8] in var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) CC_MD5(bytes.baseAddress, CC_LONG(data.count), &hash) return hash } return hash.map { String(format: "%02x", $0) }.joined() } } // 需要导入 CommonCrypto import CommonCrypto