AuthManager.swift 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import Foundation
  2. import Combine
  3. /// Manages authentication state, user session, profile management, and audio sync access authorization.
  4. final class AuthManager: ObservableObject {
  5. static let shared = AuthManager()
  6. @Published private(set) var currentUser: UserAccount?
  7. @Published var isProcessing: Bool = false
  8. @Published var authErrorMessage: String?
  9. @Published private(set) var isRestoringSession: Bool = true
  10. var isLoggedIn: Bool {
  11. currentUser != nil
  12. }
  13. /// Production server authentication service.
  14. private let authService: AuthServiceProtocol
  15. init(authService: AuthServiceProtocol = RemoteAuthService()) {
  16. self.authService = authService
  17. self.currentUser = authService.getCurrentUser()
  18. authService.restoreSession { [weak self] result in
  19. DispatchQueue.main.async {
  20. guard let self else { return }
  21. self.isRestoringSession = false
  22. switch result {
  23. case .success(let user):
  24. self.currentUser = user
  25. case .failure(let error):
  26. self.currentUser = nil
  27. self.authErrorMessage = error.localizedDescription
  28. }
  29. }
  30. }
  31. }
  32. // MARK: - Auth Actions
  33. /// User login via username/email/phone & password.
  34. func login(identifier: String, password: String, completion: ((Bool, String?) -> Void)? = nil) {
  35. isProcessing = true
  36. authErrorMessage = nil
  37. let req = LoginRequest(identifier: identifier, password: password)
  38. authService.login(request: req) { [weak self] result in
  39. DispatchQueue.main.async {
  40. guard let self = self else { return }
  41. self.isProcessing = false
  42. switch result {
  43. case .success(let user):
  44. self.currentUser = user
  45. completion?(true, nil)
  46. case .failure(let error):
  47. self.authErrorMessage = error.localizedDescription
  48. completion?(false, error.localizedDescription)
  49. }
  50. }
  51. }
  52. }
  53. /// User registration.
  54. func register(username: String, identifier: String, password: String, completion: ((Bool, String?) -> Void)? = nil) {
  55. isProcessing = true
  56. authErrorMessage = nil
  57. let req = RegisterRequest(username: username, identifier: identifier, password: password)
  58. authService.register(request: req) { [weak self] result in
  59. DispatchQueue.main.async {
  60. guard let self = self else { return }
  61. self.isProcessing = false
  62. switch result {
  63. case .success(let user):
  64. self.currentUser = user
  65. completion?(true, nil)
  66. case .failure(let error):
  67. self.authErrorMessage = error.localizedDescription
  68. completion?(false, error.localizedDescription)
  69. }
  70. }
  71. }
  72. }
  73. /// Update profile information (nickname, email, phone, avatar).
  74. func updateProfile(username: String?, email: String?, phoneNumber: String?, avatarURL: String?, completion: ((Bool, String?) -> Void)? = nil) {
  75. isProcessing = true
  76. authErrorMessage = nil
  77. let req = UpdateProfileRequest(username: username, email: email, phoneNumber: phoneNumber, avatarURL: avatarURL)
  78. authService.updateProfile(request: req) { [weak self] result in
  79. DispatchQueue.main.async {
  80. guard let self = self else { return }
  81. self.isProcessing = false
  82. switch result {
  83. case .success(let user):
  84. self.currentUser = user
  85. completion?(true, nil)
  86. case .failure(let error):
  87. self.authErrorMessage = error.localizedDescription
  88. completion?(false, error.localizedDescription)
  89. }
  90. }
  91. }
  92. }
  93. /// Change password.
  94. func changePassword(oldPassword: String, newPassword: String, completion: ((Bool, String?) -> Void)? = nil) {
  95. isProcessing = true
  96. authErrorMessage = nil
  97. let req = ChangePasswordRequest(oldPassword: oldPassword, newPassword: newPassword)
  98. authService.changePassword(request: req) { [weak self] result in
  99. DispatchQueue.main.async {
  100. guard let self = self else { return }
  101. self.isProcessing = false
  102. switch result {
  103. case .success:
  104. completion?(true, nil)
  105. case .failure(let error):
  106. self.authErrorMessage = error.localizedDescription
  107. completion?(false, error.localizedDescription)
  108. }
  109. }
  110. }
  111. }
  112. /// Logout current user.
  113. func logout() {
  114. authService.logout { [weak self] in
  115. DispatchQueue.main.async {
  116. self?.currentUser = nil
  117. }
  118. }
  119. }
  120. }