keep edit

This commit is contained in:
edwinQQQ
2025-10-17 14:52:29 +08:00
parent 22185d799e
commit 517365879a
622 changed files with 40518 additions and 7298 deletions

View File

@@ -0,0 +1,253 @@
//
// EPSDKManager.swift
// YuMi
//
// Created by AI on 2025-10-11.
//
import Foundation
/// 第三方 SDK 统一管理器(单例)
/// 统一入口:对外提供所有 SDK 能力
/// 内部管理QCloud 初始化、配置、上传等
@objc class EPSDKManager: NSObject, QCloudSignatureProvider, QCloudCredentailFenceQueueDelegate {
// MARK: - Singleton
@objc static let shared = EPSDKManager()
// MARK: - Properties
// QCloud 配置缓存
private var qcloudConfig: EPQCloudConfig?
// QCloud 初始化状态
private var isQCloudInitializing = false
// QCloud 初始化回调队列
private var qcloudInitCallbacks: [(Bool, String?) -> Void] = []
// QCloud 凭证队列
private var credentialFenceQueue: QCloudCredentailFenceQueue?
// 线程安全锁
private let lock = NSLock()
// 内部图片上传器
private let uploader = EPImageUploader()
// MARK: - Initialization
private override init() {
super.init()
}
// MARK: - Public API (对外统一入口)
/// 批量上传图片(统一入口)
/// - Parameters:
/// - images: 要上传的图片数组
/// - progress: 进度回调 (已上传数, 总数)
/// - success: 成功回调,返回图片信息数组
/// - failure: 失败回调
@objc func uploadImages(
_ images: [UIImage],
progress: @escaping (Int, Int) -> Void,
success: @escaping ([[String: Any]]) -> Void,
failure: @escaping (String) -> Void
) {
guard !images.isEmpty else {
success([])
return
}
// 确保 QCloud 已就绪
ensureQCloudReady { [weak self] isReady, errorMsg in
guard let self = self, isReady else {
DispatchQueue.main.async {
failure(errorMsg ?? YMLocalizedString("error.qcloud_init_failed"))
}
return
}
// 委托给内部 uploader 执行
self.uploader.performBatchUpload(
images,
bucket: self.qcloudConfig?.bucket ?? "",
customDomain: self.qcloudConfig?.customDomain ?? "",
progress: progress,
success: success,
failure: failure
)
}
}
/// 检查 QCloud 是否已就绪
/// - Returns: true 表示已初始化且未过期
@objc func isQCloudReady() -> Bool {
lock.lock()
defer { lock.unlock() }
guard let config = qcloudConfig else {
return false
}
return !config.isExpired
}
// MARK: - Internal Methods
/// 确保 QCloud 已就绪(自动初始化)
private func ensureQCloudReady(completion: @escaping (Bool, String?) -> Void) {
if isQCloudReady() {
completion(true, nil)
return
}
// 未初始化或已过期,重新初始化
initializeQCloud(completion: completion)
}
/// 初始化 QCloud获取 Token 并配置 SDK
private func initializeQCloud(completion: @escaping (Bool, String?) -> Void) {
lock.lock()
// 如果正在初始化,加入回调队列
if isQCloudInitializing {
qcloudInitCallbacks.append(completion)
lock.unlock()
return
}
// 如果已初始化且未过期,直接返回
if let config = qcloudConfig, !config.isExpired {
lock.unlock()
completion(true, nil)
return
}
// 开始初始化
isQCloudInitializing = true
qcloudInitCallbacks.append(completion)
lock.unlock()
// 调用 API 获取 QCloud Token
// API: GET tencent/cos/getToken
Api.getQCloudInfo { [weak self] (data, code, msg) in
guard let self = self else { return }
self.lock.lock()
if code == 200,
let dict = data?.data as? [String: Any],
let config = EPQCloudConfig(dictionary: dict) {
// 保存配置
self.qcloudConfig = config
// 配置 QCloud SDK
self.configureQCloudSDK(with: config)
// 初始化完成
self.isQCloudInitializing = false
let callbacks = self.qcloudInitCallbacks
self.qcloudInitCallbacks.removeAll()
self.lock.unlock()
// 短暂延迟确保 SDK 配置完成
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
callbacks.forEach { $0(true, nil) }
}
} else {
// 初始化失败
self.isQCloudInitializing = false
let callbacks = self.qcloudInitCallbacks
self.qcloudInitCallbacks.removeAll()
self.lock.unlock()
let errorMsg = msg ?? YMLocalizedString("error.qcloud_config_failed")
DispatchQueue.main.async {
callbacks.forEach { $0(false, errorMsg) }
}
}
}
}
/// 配置 QCloud SDK参考 UploadFile.m line 42-64
private func configureQCloudSDK(with config: EPQCloudConfig) {
let configuration = QCloudServiceConfiguration()
configuration.appID = config.appId
let endpoint = QCloudCOSXMLEndPoint()
endpoint.regionName = config.region
endpoint.useHTTPS = true
// 全球加速(参考 UploadFile.m line 56-59
if config.accelerate == 1 {
endpoint.suffix = "cos.accelerate.myqcloud.com"
}
configuration.endpoint = endpoint
configuration.signatureProvider = self
// 注册 COS 服务
QCloudCOSXMLService.registerDefaultCOSXML(with: configuration)
QCloudCOSTransferMangerService.registerDefaultCOSTransferManger(with: configuration)
// 初始化凭证队列
credentialFenceQueue = QCloudCredentailFenceQueue()
credentialFenceQueue?.delegate = self
}
// MARK: - QCloudSignatureProvider Protocol
/// 提供签名(参考 UploadFile.m line 67-104
func signature(
with fields: QCloudSignatureFields,
request: QCloudBizHTTPRequest,
urlRequest: NSMutableURLRequest,
compelete: @escaping QCloudHTTPAuthentationContinueBlock
) {
guard let config = qcloudConfig else {
let error = NSError(domain: "com.yumi.qcloud", code: -1,
userInfo: [NSLocalizedDescriptionKey: YMLocalizedString("error.qcloud_config_not_initialized")])
compelete(nil, error)
return
}
let credential = QCloudCredential()
credential.secretID = config.secretId
credential.secretKey = config.secretKey
credential.token = config.sessionToken
credential.startDate = Date(timeIntervalSince1970: TimeInterval(config.startTime))
credential.expirationDate = Date(timeIntervalSince1970: TimeInterval(config.expireTime))
let creator = QCloudAuthentationV5Creator(credential: credential)
let signature = creator?.signature(forData: urlRequest)
compelete(signature, nil)
}
// MARK: - QCloudCredentailFenceQueueDelegate Protocol
/// 管理凭证(参考 UploadFile.m line 107-133
func fenceQueue(
_ queue: QCloudCredentailFenceQueue,
requestCreatorWithContinue continueBlock: @escaping QCloudCredentailFenceQueueContinue
) {
guard let config = qcloudConfig else {
let error = NSError(domain: "com.yumi.qcloud", code: -1,
userInfo: [NSLocalizedDescriptionKey: YMLocalizedString("error.qcloud_config_not_initialized")])
continueBlock(nil, error)
return
}
let credential = QCloudCredential()
credential.secretID = config.secretId
credential.secretKey = config.secretKey
credential.token = config.sessionToken
credential.startDate = Date(timeIntervalSince1970: TimeInterval(config.startTime))
credential.expirationDate = Date(timeIntervalSince1970: TimeInterval(config.expireTime))
let creator = QCloudAuthentationV5Creator(credential: credential)
continueBlock(creator, nil)
}
}