import Foundation import ComposableArchitecture // MARK: - Token 服务协议 /// Token 服务协议 public protocol COSTokenServiceProtocol: Sendable { /// 获取有效的Token func getValidToken() async throws -> TcTokenData /// 刷新Token func refreshToken() async throws -> TcTokenData /// 清除缓存的Token func clearCachedToken() /// 获取Token状态信息 func getTokenStatus() async -> String } // MARK: - Token 服务实现 /// Token 服务实现 public struct COSTokenService: COSTokenServiceProtocol { private let apiService: any APIServiceProtocol & Sendable private let tokenCache: TokenCacheProtocol init( apiService: any APIServiceProtocol & Sendable, tokenCache: TokenCacheProtocol = TokenCache() ) { self.apiService = apiService self.tokenCache = tokenCache } /// 获取有效的Token public func getValidToken() async throws -> TcTokenData { // 首先检查缓存 if let cachedToken = await tokenCache.getValidCachedToken() { debugInfoSync("🔐 使用缓存的 COS Token") return cachedToken } // 缓存无效,请求新Token debugInfoSync("🔐 开始请求腾讯云 COS Token...") return try await requestNewToken() } /// 刷新Token public func refreshToken() async throws -> TcTokenData { // 清除缓存 await tokenCache.clearCachedToken() debugInfoSync("🔄 清除缓存,开始刷新 Token") // 请求新Token return try await requestNewToken() } /// 清除缓存的Token public func clearCachedToken() { Task { await tokenCache.clearCachedToken() debugInfoSync("🗑️ 清除缓存的 COS Token") } } /// 获取Token状态信息 public func getTokenStatus() async -> String { if let cachedToken = await tokenCache.getCachedToken() { let isExpired = !cachedToken.isValid return "Token 状态: \(isExpired ? "已过期" : "有效"), 过期时间: \(cachedToken.expirationDate)" } else { return "Token 状态: 未缓存" } } // MARK: - 私有方法 /// 请求新Token private func requestNewToken() async throws -> TcTokenData { do { let request = TcTokenRequest() let response: TcTokenResponse = try await apiService.request(request) guard response.code == 200, let tokenData = response.data else { throw COSError.tokenInvalid } // 缓存Token await tokenCache.cacheToken(tokenData) debugInfoSync("✅ COS Token 获取成功") debugInfoSync(" - 存储桶: \(tokenData.bucket)") debugInfoSync(" - 地域: \(tokenData.region)") debugInfoSync(" - 过期时间: \(tokenData.expirationDate)") debugInfoSync(" - 剩余时间: \(tokenData.remainingTime)秒") return tokenData } catch { debugErrorSync("❌ COS Token 请求异常: \(error.localizedDescription)") throw COSError.networkError(error.localizedDescription) } } } // MARK: - Token 缓存协议 /// Token 缓存协议 public protocol TokenCacheProtocol: Sendable { /// 获取缓存的Token func getCachedToken() async -> TcTokenData? /// 获取有效的缓存Token func getValidCachedToken() async -> TcTokenData? /// 缓存Token func cacheToken(_ tokenData: TcTokenData) async /// 清除缓存的Token func clearCachedToken() async } // MARK: - Token 缓存实现 /// Token 缓存实现 public actor TokenCache: TokenCacheProtocol { private var cachedToken: TcTokenData? private var tokenExpirationDate: Date? public init() {} /// 获取缓存的Token public func getCachedToken() async -> TcTokenData? { return cachedToken } /// 获取有效的缓存Token public func getValidCachedToken() async -> TcTokenData? { guard let cached = cachedToken, let expiration = tokenExpirationDate, Date() < expiration else { return nil } return cached } /// 缓存Token public func cacheToken(_ tokenData: TcTokenData) async { cachedToken = tokenData tokenExpirationDate = tokenData.expirationDate debugInfoSync("💾 COS Token 已缓存,过期时间: \(tokenExpirationDate?.description ?? "未知")") } /// 清除缓存的Token public func clearCachedToken() async { cachedToken = nil tokenExpirationDate = nil debugInfoSync("🗑️ 清除缓存的 COS Token") } } // MARK: - TCA 依赖扩展 extension DependencyValues { /// COS Token 服务依赖 public var cosTokenService: COSTokenServiceProtocol { get { self[COSTokenServiceKey.self] } set { self[COSTokenServiceKey.self] = newValue } } } /// COS Token 服务依赖键 private enum COSTokenServiceKey: DependencyKey { static let liveValue: COSTokenServiceProtocol = COSTokenService( apiService: LiveAPIService() ) static let testValue: COSTokenServiceProtocol = MockCOSTokenService() } // MARK: - Mock 服务(用于测试) /// Mock Token 服务(用于测试) public struct MockCOSTokenService: COSTokenServiceProtocol { public var getValidTokenResult: Result = .failure(COSError.tokenInvalid) public var refreshTokenResult: Result = .failure(COSError.tokenInvalid) public var tokenStatusResult: String = "Mock Token Status" public init() {} public func getValidToken() async throws -> TcTokenData { switch getValidTokenResult { case .success(let token): return token case .failure(let error): throw error } } public func refreshToken() async throws -> TcTokenData { switch refreshTokenResult { case .success(let token): return token case .failure(let error): throw error } } public func clearCachedToken() { // Mock 实现,无需实际操作 } public func getTokenStatus() async -> String { return tokenStatusResult } }