feat: 更新依赖和项目配置,优化代码结构
- 在Package.swift中注释掉旧的swift-composable-architecture依赖,并添加swift-case-paths依赖。 - 在Podfile中将iOS平台版本更新至16.0,并移除QCloudCOSXML/Transfer依赖,改为使用QCloudCOSXML。 - 更新Podfile.lock以反映依赖变更,确保项目依赖的准确性。 - 新增架构分析需求文档,明确项目架构评估和改进建议。 - 在多个文件中实现async/await语法,提升异步操作的可读性和性能。 - 更新日志输出方法,确保在调试模式下提供一致的调试信息。 - 优化多个视图组件,提升用户体验和代码可维护性。
This commit is contained in:
@@ -111,9 +111,10 @@ struct BaseRequest: Codable {
|
||||
case pubSign = "pub_sign"
|
||||
}
|
||||
|
||||
@MainActor
|
||||
init() {
|
||||
// 获取系统首选语言
|
||||
let preferredLanguage = Locale.current.languageCode ?? "en"
|
||||
let preferredLanguage = Locale.current.language.languageCode?.identifier ?? "en"
|
||||
self.acceptLanguage = preferredLanguage
|
||||
self.lang = preferredLanguage
|
||||
|
||||
@@ -237,6 +238,7 @@ struct CarrierInfoManager {
|
||||
|
||||
// MARK: - User Info Manager (for Headers)
|
||||
struct UserInfoManager {
|
||||
@MainActor
|
||||
private static let keychain = KeychainManager.shared
|
||||
|
||||
// MARK: - Storage Keys
|
||||
@@ -246,72 +248,66 @@ struct UserInfoManager {
|
||||
}
|
||||
|
||||
// MARK: - 内存缓存
|
||||
private static var accountModelCache: AccountModel?
|
||||
private static var userInfoCache: UserInfo?
|
||||
// 已迁移到 UserInfoCacheActor
|
||||
private static let cacheQueue = DispatchQueue(label: "com.yana.userinfo.cache", attributes: .concurrent)
|
||||
|
||||
// MARK: - User ID Management (基于 AccountModel)
|
||||
static func getCurrentUserId() -> String? {
|
||||
return getAccountModel()?.uid
|
||||
static func getCurrentUserId() async -> String? {
|
||||
return await getAccountModel()?.uid
|
||||
}
|
||||
|
||||
// MARK: - Access Token Management (基于 AccountModel)
|
||||
static func getAccessToken() -> String? {
|
||||
return getAccountModel()?.accessToken
|
||||
static func getAccessToken() async -> String? {
|
||||
return await getAccountModel()?.accessToken
|
||||
}
|
||||
|
||||
// MARK: - Ticket Management (优先从 AccountModel 获取)
|
||||
private static var currentTicket: String?
|
||||
// 已迁移到 UserInfoCacheActor
|
||||
|
||||
static func getCurrentUserTicket() -> String? {
|
||||
static func getCurrentUserTicket() async -> String? {
|
||||
// 优先从 AccountModel 获取 ticket(确保一致性)
|
||||
if let accountTicket = getAccountModel()?.ticket, !accountTicket.isEmpty {
|
||||
if let accountTicket = await getAccountModel()?.ticket, !accountTicket.isEmpty {
|
||||
return accountTicket
|
||||
}
|
||||
|
||||
// 备选:从内存获取(用于兼容性)
|
||||
return currentTicket
|
||||
// 备选:从 actor 获取(用于兼容性)
|
||||
return await cacheActor.getCurrentTicket()
|
||||
}
|
||||
|
||||
static func saveTicket(_ ticket: String) {
|
||||
currentTicket = ticket
|
||||
debugInfo("💾 保存 Ticket 到内存")
|
||||
static func saveTicket(_ ticket: String) async {
|
||||
await cacheActor.setCurrentTicket(ticket)
|
||||
debugInfoSync("💾 保存 Ticket 到内存")
|
||||
}
|
||||
|
||||
static func clearTicket() {
|
||||
currentTicket = nil
|
||||
debugInfo("🗑️ 清除 Ticket")
|
||||
static func clearTicket() async {
|
||||
await cacheActor.clearCurrentTicket()
|
||||
debugInfoSync("🗑️ 清除 Ticket")
|
||||
}
|
||||
|
||||
// MARK: - User Info Management
|
||||
static func saveUserInfo(_ userInfo: UserInfo) {
|
||||
cacheQueue.async(flags: .barrier) {
|
||||
do {
|
||||
try keychain.store(userInfo, forKey: StorageKeys.userInfo)
|
||||
userInfoCache = userInfo
|
||||
debugInfo("💾 保存用户信息成功")
|
||||
} catch {
|
||||
debugError("❌ 保存用户信息失败: \(error)")
|
||||
}
|
||||
static func saveUserInfo(_ userInfo: UserInfo) async {
|
||||
do {
|
||||
try await keychain.store(userInfo, forKey: StorageKeys.userInfo)
|
||||
await cacheActor.setUserInfo(userInfo)
|
||||
debugInfoSync("💾 保存用户信息成功")
|
||||
} catch {
|
||||
debugErrorSync("❌ 保存用户信息失败: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
static func getUserInfo() -> UserInfo? {
|
||||
return cacheQueue.sync {
|
||||
// 先检查缓存
|
||||
if let cached = userInfoCache {
|
||||
return cached
|
||||
}
|
||||
|
||||
// 从 Keychain 读取
|
||||
do {
|
||||
let userInfo = try keychain.retrieve(UserInfo.self, forKey: StorageKeys.userInfo)
|
||||
userInfoCache = userInfo
|
||||
return userInfo
|
||||
} catch {
|
||||
debugError("❌ 读取用户信息失败: \(error)")
|
||||
return nil
|
||||
}
|
||||
static func getUserInfo() async -> UserInfo? {
|
||||
// 先检查缓存
|
||||
if let cached = await cacheActor.getUserInfo() {
|
||||
return cached
|
||||
}
|
||||
// 从 Keychain 读取
|
||||
do {
|
||||
let userInfo = try await keychain.retrieve(UserInfo.self, forKey: StorageKeys.userInfo)
|
||||
await cacheActor.setUserInfo(userInfo)
|
||||
return userInfo
|
||||
} catch {
|
||||
debugErrorSync("❌ 读取用户信息失败: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +318,7 @@ struct UserInfoManager {
|
||||
ticket: String,
|
||||
uid: Int?,
|
||||
userInfo: UserInfo?
|
||||
) {
|
||||
) async {
|
||||
// 创建新的 AccountModel
|
||||
let accountModel = AccountModel(
|
||||
uid: uid != nil ? "\(uid!)" : nil,
|
||||
@@ -336,38 +332,40 @@ struct UserInfoManager {
|
||||
ticket: ticket
|
||||
)
|
||||
|
||||
saveAccountModel(accountModel)
|
||||
saveTicket(ticket)
|
||||
await saveAccountModel(accountModel)
|
||||
await saveTicket(ticket)
|
||||
|
||||
if let userInfo = userInfo {
|
||||
saveUserInfo(userInfo)
|
||||
await saveUserInfo(userInfo)
|
||||
}
|
||||
|
||||
debugInfo("✅ 完整认证信息保存成功")
|
||||
debugInfoSync("✅ 完整认证信息保存成功")
|
||||
}
|
||||
|
||||
/// 检查是否有有效的认证信息
|
||||
static func hasValidAuthentication() -> Bool {
|
||||
return getAccessToken() != nil && getCurrentUserTicket() != nil
|
||||
static func hasValidAuthentication() async -> Bool {
|
||||
let token = await getAccessToken()
|
||||
let ticket = await getCurrentUserTicket()
|
||||
return token != nil && ticket != nil
|
||||
}
|
||||
|
||||
/// 清除所有认证信息
|
||||
static func clearAllAuthenticationData() {
|
||||
clearAccountModel()
|
||||
clearUserInfo()
|
||||
clearTicket()
|
||||
static func clearAllAuthenticationData() async {
|
||||
await clearAccountModel()
|
||||
await clearUserInfo()
|
||||
await clearTicket()
|
||||
|
||||
debugInfo("🗑️ 清除所有认证信息")
|
||||
debugInfoSync("🗑️ 清除所有认证信息")
|
||||
}
|
||||
|
||||
/// 尝试恢复 Ticket(用于应用重启后)
|
||||
static func restoreTicketIfNeeded() async -> Bool {
|
||||
guard let accessToken = getAccessToken(),
|
||||
getCurrentUserTicket() == nil else {
|
||||
guard let _ = await getAccessToken(),
|
||||
await getCurrentUserTicket() == nil else {
|
||||
return false
|
||||
}
|
||||
|
||||
debugInfo("🔄 尝试使用 Access Token 恢复 Ticket...")
|
||||
debugInfoSync("🔄 尝试使用 Access Token 恢复 Ticket...")
|
||||
|
||||
// 这里需要注入 APIService 依赖,暂时返回 false
|
||||
// 实际实现中应该调用 TicketHelper.createTicketRequest
|
||||
@@ -377,50 +375,48 @@ struct UserInfoManager {
|
||||
// MARK: - Account Model Management
|
||||
/// 保存 AccountModel
|
||||
/// - Parameter accountModel: 要保存的账户模型
|
||||
static func saveAccountModel(_ accountModel: AccountModel) {
|
||||
cacheQueue.async(flags: .barrier) {
|
||||
do {
|
||||
try keychain.store(accountModel, forKey: StorageKeys.accountModel)
|
||||
accountModelCache = accountModel
|
||||
|
||||
// 同步更新 ticket 到内存
|
||||
if let ticket = accountModel.ticket {
|
||||
saveTicket(ticket)
|
||||
}
|
||||
|
||||
debugInfo("💾 AccountModel 保存成功")
|
||||
} catch {
|
||||
debugError("❌ AccountModel 保存失败: \(error)")
|
||||
static func saveAccountModel(_ accountModel: AccountModel) async {
|
||||
do {
|
||||
try await keychain.store(accountModel, forKey: StorageKeys.accountModel)
|
||||
await cacheActor.setAccountModel(accountModel)
|
||||
|
||||
// 同步更新 ticket 到内存
|
||||
if let ticket = accountModel.ticket {
|
||||
await saveTicket(ticket)
|
||||
}
|
||||
|
||||
debugInfoSync("💾 AccountModel 保存成功")
|
||||
} catch {
|
||||
debugErrorSync("❌ AccountModel 保存失败: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取 AccountModel
|
||||
/// - Returns: 存储的账户模型,如果不存在或解析失败返回 nil
|
||||
static func getAccountModel() -> AccountModel? {
|
||||
return cacheQueue.sync {
|
||||
// 先检查缓存
|
||||
if let cached = accountModelCache {
|
||||
return cached
|
||||
}
|
||||
|
||||
// 从 Keychain 读取
|
||||
do {
|
||||
let accountModel = try keychain.retrieve(AccountModel.self, forKey: StorageKeys.accountModel)
|
||||
accountModelCache = accountModel
|
||||
return accountModel
|
||||
} catch {
|
||||
debugError("❌ 读取 AccountModel 失败: \(error)")
|
||||
return nil
|
||||
}
|
||||
static func getAccountModel() async -> AccountModel? {
|
||||
// 先检查缓存
|
||||
if let cached = await cacheActor.getAccountModel() {
|
||||
return cached
|
||||
}
|
||||
// 从 Keychain 读取
|
||||
do {
|
||||
let accountModel = try await keychain.retrieve(
|
||||
AccountModel.self,
|
||||
forKey: StorageKeys.accountModel
|
||||
)
|
||||
await cacheActor.setAccountModel(accountModel)
|
||||
return accountModel
|
||||
} catch {
|
||||
debugErrorSync("❌ 读取 AccountModel 失败: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// 更新 AccountModel 中的 ticket
|
||||
/// - Parameter ticket: 新的票据
|
||||
static func updateAccountModelTicket(_ ticket: String) {
|
||||
guard var accountModel = getAccountModel() else {
|
||||
debugError("❌ 无法更新 ticket:AccountModel 不存在")
|
||||
static func updateAccountModelTicket(_ ticket: String) async {
|
||||
guard var accountModel = await getAccountModel() else {
|
||||
debugErrorSync("❌ 无法更新 ticket:AccountModel 不存在")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -436,97 +432,78 @@ struct UserInfoManager {
|
||||
ticket: ticket
|
||||
)
|
||||
|
||||
saveAccountModel(accountModel)
|
||||
saveTicket(ticket) // 同时更新内存中的 ticket
|
||||
await saveAccountModel(accountModel)
|
||||
await saveTicket(ticket) // 同时更新内存中的 ticket
|
||||
}
|
||||
|
||||
/// 检查是否有有效的 AccountModel
|
||||
/// - Returns: 是否存在有效的账户模型
|
||||
static func hasValidAccountModel() -> Bool {
|
||||
guard let accountModel = getAccountModel() else {
|
||||
static func hasValidAccountModel() async -> Bool {
|
||||
guard let accountModel = await getAccountModel() else {
|
||||
return false
|
||||
}
|
||||
return accountModel.hasValidAuthentication
|
||||
}
|
||||
|
||||
/// 清除 AccountModel
|
||||
static func clearAccountModel() {
|
||||
cacheQueue.async(flags: .barrier) {
|
||||
do {
|
||||
try keychain.delete(forKey: StorageKeys.accountModel)
|
||||
accountModelCache = nil
|
||||
debugInfo("🗑️ AccountModel 已清除")
|
||||
} catch {
|
||||
debugError("❌ 清除 AccountModel 失败: \(error)")
|
||||
}
|
||||
static func clearAccountModel() async {
|
||||
do {
|
||||
try await keychain.delete(forKey: StorageKeys.accountModel)
|
||||
await cacheActor.clearAccountModel()
|
||||
debugInfoSync("🗑️ AccountModel 已清除")
|
||||
} catch {
|
||||
debugErrorSync("❌ 清除 AccountModel 失败: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
/// 清除用户信息
|
||||
static func clearUserInfo() {
|
||||
cacheQueue.async(flags: .barrier) {
|
||||
do {
|
||||
try keychain.delete(forKey: StorageKeys.userInfo)
|
||||
userInfoCache = nil
|
||||
debugInfo("🗑️ UserInfo 已清除")
|
||||
} catch {
|
||||
debugError("❌ 清除 UserInfo 失败: \(error)")
|
||||
}
|
||||
static func clearUserInfo() async {
|
||||
do {
|
||||
try await keychain.delete(forKey: StorageKeys.userInfo)
|
||||
await cacheActor.clearUserInfo()
|
||||
debugInfoSync("🗑️ UserInfo 已清除")
|
||||
} catch {
|
||||
debugErrorSync("❌ 清除 UserInfo 失败: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
/// 清除所有缓存(用于测试或重置)
|
||||
static func clearAllCache() {
|
||||
cacheQueue.async(flags: .barrier) {
|
||||
accountModelCache = nil
|
||||
userInfoCache = nil
|
||||
debugInfo("🗑️ 清除所有内存缓存")
|
||||
}
|
||||
static func clearAllCache() async {
|
||||
await cacheActor.clearAccountModel()
|
||||
await cacheActor.clearUserInfo()
|
||||
debugInfoSync("🗑️ 清除所有内存缓存")
|
||||
}
|
||||
|
||||
/// 预加载缓存(提升首次访问性能)
|
||||
static func preloadCache() {
|
||||
cacheQueue.async {
|
||||
// 预加载 AccountModel
|
||||
_ = getAccountModel()
|
||||
// 预加载 UserInfo
|
||||
_ = getUserInfo()
|
||||
debugInfo("🚀 缓存预加载完成")
|
||||
}
|
||||
static func preloadCache() async {
|
||||
await cacheActor.setAccountModel(await getAccountModel())
|
||||
await cacheActor.setUserInfo(await getUserInfo())
|
||||
debugInfoSync("🚀 缓存预加载完成")
|
||||
}
|
||||
|
||||
// MARK: - Authentication Validation
|
||||
|
||||
/// 检查当前认证状态是否有效
|
||||
/// - Returns: 认证状态结果
|
||||
static func checkAuthenticationStatus() -> AuthenticationStatus {
|
||||
return cacheQueue.sync {
|
||||
guard let accountModel = getAccountModel() else {
|
||||
debugInfo("🔍 认证检查:未找到 AccountModel")
|
||||
return .notFound
|
||||
}
|
||||
|
||||
// 检查 uid 是否有效
|
||||
guard let uid = accountModel.uid, !uid.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
|
||||
debugInfo("🔍 认证检查:uid 无效")
|
||||
return .invalid
|
||||
}
|
||||
|
||||
// 检查 ticket 是否有效
|
||||
guard let ticket = accountModel.ticket, !ticket.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
|
||||
debugInfo("🔍 认证检查:ticket 无效")
|
||||
return .invalid
|
||||
}
|
||||
|
||||
// 可选:检查 access token 是否有效
|
||||
guard let accessToken = accountModel.accessToken, !accessToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
|
||||
debugInfo("🔍 认证检查:access token 无效")
|
||||
return .invalid
|
||||
}
|
||||
|
||||
debugInfo("🔍 认证检查:认证有效 - uid: \(uid), ticket: \(ticket.prefix(10))...")
|
||||
return .valid
|
||||
static func checkAuthenticationStatus() async -> AuthenticationStatus {
|
||||
guard let accountModel = await getAccountModel() else {
|
||||
debugInfoSync("🔍 认证检查:未找到 AccountModel")
|
||||
return .notFound
|
||||
}
|
||||
guard let uid = accountModel.uid, !uid.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
|
||||
debugInfoSync("🔍 认证检查:uid 无效")
|
||||
return .invalid
|
||||
}
|
||||
guard let ticket = accountModel.ticket, !ticket.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
|
||||
debugInfoSync("🔍 认证检查:ticket 无效")
|
||||
return .invalid
|
||||
}
|
||||
guard let accessToken = accountModel.accessToken, !accessToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
|
||||
debugInfoSync("🔍 认证检查:access token 无效")
|
||||
return .invalid
|
||||
}
|
||||
debugInfoSync("🔍 认证检查:认证有效 - uid: \(uid), ticket: \(ticket.prefix(10))...")
|
||||
return .valid
|
||||
}
|
||||
|
||||
/// 认证状态枚举
|
||||
@@ -556,19 +533,19 @@ struct UserInfoManager {
|
||||
|
||||
/// 测试认证 header 功能(仅用于调试)
|
||||
/// 模拟用户登录状态并验证 header 添加逻辑
|
||||
static func testAuthenticationHeaders() {
|
||||
static func testAuthenticationHeaders() async {
|
||||
#if DEBUG
|
||||
debugInfo("\n🧪 开始测试认证 header 功能")
|
||||
debugInfoSync("\n🧪 开始测试认证 header 功能")
|
||||
|
||||
// 测试1:未登录状态
|
||||
debugInfo("📝 测试1:未登录状态")
|
||||
clearAllAuthenticationData()
|
||||
let headers1 = APIConfiguration.defaultHeaders
|
||||
debugInfoSync("📝 测试1:未登录状态")
|
||||
await clearAllAuthenticationData()
|
||||
let headers1 = await APIConfiguration.defaultHeaders()
|
||||
let hasAuthHeaders1 = headers1.keys.contains("pub_uid") || headers1.keys.contains("pub_ticket")
|
||||
debugInfo(" 认证 headers 存在: \(hasAuthHeaders1) (应该为 false)")
|
||||
debugInfoSync(" 认证 headers 存在: \(hasAuthHeaders1) (应该为 false)")
|
||||
|
||||
// 测试2:模拟登录状态
|
||||
debugInfo("📝 测试2:模拟登录状态")
|
||||
debugInfoSync("📝 测试2:模拟登录状态")
|
||||
let testAccount = AccountModel(
|
||||
uid: "12345",
|
||||
jti: "test-jti",
|
||||
@@ -580,22 +557,48 @@ struct UserInfoManager {
|
||||
scope: "read write",
|
||||
ticket: "test-ticket-12345678901234567890"
|
||||
)
|
||||
saveAccountModel(testAccount)
|
||||
await saveAccountModel(testAccount)
|
||||
|
||||
let headers2 = APIConfiguration.defaultHeaders
|
||||
let headers2 = await APIConfiguration.defaultHeaders()
|
||||
let hasUid = headers2["pub_uid"] == "12345"
|
||||
let hasTicket = headers2["pub_ticket"] == "test-ticket-12345678901234567890"
|
||||
debugInfo(" pub_uid 正确: \(hasUid) (应该为 true)")
|
||||
debugInfo(" pub_ticket 正确: \(hasTicket) (应该为 true)")
|
||||
debugInfoSync(" pub_uid 正确: \(hasUid) (应该为 true)")
|
||||
debugInfoSync(" pub_ticket 正确: \(hasTicket) (应该为 true)")
|
||||
|
||||
// 测试3:清理测试数据
|
||||
debugInfo("📝 测试3:清理测试数据")
|
||||
clearAllAuthenticationData()
|
||||
debugInfo("✅ 认证 header 测试完成\n")
|
||||
debugInfoSync("📝 测试3:清理测试数据")
|
||||
await clearAllAuthenticationData()
|
||||
debugInfoSync("✅ 认证 header 测试完成\n")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - User Info Cache Actor
|
||||
actor UserInfoCacheActor {
|
||||
private var accountModelCache: AccountModel?
|
||||
private var userInfoCache: UserInfo?
|
||||
private var currentTicket: String?
|
||||
|
||||
// AccountModel
|
||||
func getAccountModel() -> AccountModel? { accountModelCache }
|
||||
func setAccountModel(_ model: AccountModel?) { accountModelCache = model }
|
||||
func clearAccountModel() { accountModelCache = nil }
|
||||
|
||||
// UserInfo
|
||||
func getUserInfo() -> UserInfo? { userInfoCache }
|
||||
func setUserInfo(_ info: UserInfo?) { userInfoCache = info }
|
||||
func clearUserInfo() { userInfoCache = nil }
|
||||
|
||||
// Ticket
|
||||
func getCurrentTicket() -> String? { currentTicket }
|
||||
func setCurrentTicket(_ ticket: String?) { currentTicket = ticket }
|
||||
func clearCurrentTicket() { currentTicket = nil }
|
||||
}
|
||||
|
||||
extension UserInfoManager {
|
||||
static let cacheActor = UserInfoCacheActor()
|
||||
}
|
||||
|
||||
// MARK: - API Request Protocol
|
||||
|
||||
/// API 请求协议
|
||||
@@ -604,7 +607,7 @@ struct UserInfoManager {
|
||||
/// 每个具体的 API 请求都应该实现这个协议。
|
||||
///
|
||||
/// 协议要求:
|
||||
/// - Response: 关联类型,定义响应数据的类型
|
||||
/// - Response: 关联类型,定义响应数据的类型,必须 Sendable
|
||||
/// - endpoint: API 端点路径
|
||||
/// - method: HTTP 请求方法
|
||||
/// - 可选的查询参数、请求体参数、请求头等
|
||||
@@ -618,8 +621,8 @@ struct UserInfoManager {
|
||||
/// // ... 其他属性
|
||||
/// }
|
||||
/// ```
|
||||
protocol APIRequestProtocol {
|
||||
associatedtype Response: Codable
|
||||
protocol APIRequestProtocol: Sendable {
|
||||
associatedtype Response: Codable & Sendable
|
||||
|
||||
var endpoint: String { get }
|
||||
var method: HTTPMethod { get }
|
||||
|
Reference in New Issue
Block a user