243 lines
7.1 KiB
Swift
243 lines
7.1 KiB
Swift
|
|
|
|
// Created by AI on 2025-10-11.
|
|
|
|
|
|
import Foundation
|
|
|
|
|
|
@objc class EPSDKManager: NSObject, QCloudSignatureProvider, QCloudCredentailFenceQueueDelegate {
|
|
|
|
// MARK: - Singleton
|
|
|
|
@objc static let shared = EPSDKManager()
|
|
|
|
// MARK: - Properties
|
|
|
|
|
|
private var qcloudConfig: EPQCloudConfig?
|
|
|
|
|
|
private var isQCloudInitializing = false
|
|
|
|
|
|
private var qcloudInitCallbacks: [(Bool, String?) -> Void] = []
|
|
|
|
|
|
private var credentialFenceQueue: QCloudCredentailFenceQueue?
|
|
|
|
|
|
private let lock = NSLock()
|
|
|
|
|
|
private let uploader = EPImageUploader()
|
|
|
|
// MARK: - Initialization
|
|
|
|
private override init() {
|
|
super.init()
|
|
}
|
|
|
|
// MARK: - Public API (对外统一入口)
|
|
|
|
|
|
@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
|
|
}
|
|
|
|
|
|
ensureQCloudReady { [weak self] isReady, errorMsg in
|
|
guard let self = self, isReady else {
|
|
DispatchQueue.main.async {
|
|
failure(errorMsg ?? YMLocalizedString("error.qcloud_init_failed"))
|
|
}
|
|
return
|
|
}
|
|
|
|
|
|
self.uploader.performBatchUpload(
|
|
images,
|
|
bucket: self.qcloudConfig?.bucket ?? "",
|
|
customDomain: self.qcloudConfig?.customDomain ?? "",
|
|
progress: progress,
|
|
success: success,
|
|
failure: failure
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
@objc func isQCloudReady() -> Bool {
|
|
lock.lock()
|
|
defer { lock.unlock() }
|
|
|
|
guard let config = qcloudConfig else {
|
|
return false
|
|
}
|
|
return !config.isExpired
|
|
}
|
|
|
|
// MARK: - Internal Methods
|
|
|
|
|
|
private func ensureQCloudReady(completion: @escaping (Bool, String?) -> Void) {
|
|
if isQCloudReady() {
|
|
completion(true, nil)
|
|
return
|
|
}
|
|
|
|
|
|
initializeQCloud(completion: completion)
|
|
}
|
|
|
|
|
|
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.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
|
|
|
|
|
|
self.configureQCloudSDK(with: config)
|
|
|
|
|
|
self.isQCloudInitializing = false
|
|
let callbacks = self.qcloudInitCallbacks
|
|
self.qcloudInitCallbacks.removeAll()
|
|
self.lock.unlock()
|
|
|
|
|
|
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) }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private func configureQCloudSDK(with config: EPQCloudConfig) {
|
|
let configuration = QCloudServiceConfiguration()
|
|
configuration.appID = config.appId
|
|
|
|
let endpoint = QCloudCOSXMLEndPoint()
|
|
endpoint.regionName = config.region
|
|
endpoint.useHTTPS = true
|
|
|
|
|
|
if config.accelerate == 1 {
|
|
endpoint.suffix = "cos.accelerate.myqcloud.com"
|
|
}
|
|
|
|
configuration.endpoint = endpoint
|
|
configuration.signatureProvider = self
|
|
|
|
|
|
QCloudCOSXMLService.registerDefaultCOSXML(with: configuration)
|
|
QCloudCOSTransferMangerService.registerDefaultCOSTransferManger(with: configuration)
|
|
|
|
|
|
credentialFenceQueue = QCloudCredentailFenceQueue()
|
|
credentialFenceQueue?.delegate = self
|
|
}
|
|
|
|
// MARK: - QCloudSignatureProvider Protocol
|
|
|
|
|
|
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
|
|
|
|
|
|
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)
|
|
}
|
|
}
|