101 lines
3.5 KiB
Swift
101 lines
3.5 KiB
Swift
//
|
||
// 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
|
||
}
|
||
}
|