// // UploadModels.swift // suixinkan // // Created by Codex on 2026/6/22. // import Foundation /// 阿里云 OSS STS 配置响应实体,表示一次临时上传授权。 struct AliyunOSSResponse: Decodable, Equatable { let baseUrl: String let endpoint: String let region: String let bucket: String let expireSeconds: Int let credentials: AliyunOSSCredentials /// 阿里云 OSS STS 配置响应 JSON 字段映射。 enum CodingKeys: String, CodingKey { case baseUrl = "base_url" case endpoint case region case bucket case expireSeconds = "expire_seconds" case credentials } /// 自定义解码,兼容后端字段类型不稳定的情况。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) baseUrl = try container.decodeLossyString(forKey: .baseUrl) endpoint = try container.decodeLossyString(forKey: .endpoint) region = try container.decodeLossyString(forKey: .region) bucket = try container.decodeLossyString(forKey: .bucket) expireSeconds = try container.decodeLossyInt(forKey: .expireSeconds) ?? 0 credentials = try container.decode(AliyunOSSCredentials.self, forKey: .credentials) } } /// 阿里云 OSS 临时凭证实体,表示 SDK 上传所需的访问密钥和安全 token。 struct AliyunOSSCredentials: Decodable, Equatable { let accessKeyId: String let accessKeySecret: String let securityToken: String /// 阿里云 OSS 临时凭证 JSON 字段映射。 enum CodingKeys: String, CodingKey { case accessKeyId = "access_key_id" case accessKeySecret = "access_key_secret" case securityToken = "security_token" } /// 自定义解码,兼容后端字段类型不稳定的情况。 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) accessKeyId = try container.decodeLossyString(forKey: .accessKeyId) accessKeySecret = try container.decodeLossyString(forKey: .accessKeySecret) securityToken = try container.decodeLossyString(forKey: .securityToken) } } private extension KeyedDecodingContainer { /// 将 String、数字和 Bool 宽松解码为字符串。 func decodeLossyString(forKey key: Key) throws -> String { if let value = try? decodeIfPresent(String.self, forKey: key) { return value } if let value = try? decodeIfPresent(Int.self, forKey: key) { return String(value) } if let value = try? decodeIfPresent(Double.self, forKey: key) { return String(value) } if let value = try? decodeIfPresent(Bool.self, forKey: key) { return value ? "true" : "false" } return "" } /// 将 Int、Double 或数字字符串宽松解码为整数。 func decodeLossyInt(forKey key: Key) throws -> Int? { if let value = try? decodeIfPresent(Int.self, forKey: key) { return value } if let value = try? decodeIfPresent(String.self, forKey: key) { let text = value.trimmingCharacters(in: .whitespacesAndNewlines) if let intValue = Int(text) { return intValue } if let doubleValue = Double(text) { return Int(doubleValue) } } if let value = try? decodeIfPresent(Double.self, forKey: key) { return Int(value) } return nil } }