From b2da353e8aa4dbd6eb3f4f0a3c74e3cdeec990ea Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Mon, 25 Mar 2024 23:36:27 -0700 Subject: [PATCH] Convert refreshAll to async/await. --- Account/Sources/Account/Account.swift | 14 ++++ Account/Sources/Account/AccountManager.swift | 71 +++++++++----------- Mac/AppDelegate.swift | 5 +- Shared/Timer/AccountRefreshTimer.swift | 5 +- iOS/AppDelegate.swift | 34 +++++----- 5 files changed, 70 insertions(+), 59 deletions(-) diff --git a/Account/Sources/Account/Account.swift b/Account/Sources/Account/Account.swift index 35a29e794..c711e1fa6 100644 --- a/Account/Sources/Account/Account.swift +++ b/Account/Sources/Account/Account.swift @@ -425,6 +425,20 @@ public enum FetchType { delegate.refreshAll(for: self, completion: completion) } + public func refreshAll() async throws { + + try await withCheckedThrowingContinuation { continuation in + self.refreshAll { result in + switch result { + case .success: + continuation.resume() + case .failure(let error): + continuation.resume(throwing: error) + } + } + } + } + public func sendArticleStatus(completion: ((Result) -> Void)? = nil) { delegate.sendArticleStatus(for: self) { result in switch result { diff --git a/Account/Sources/Account/AccountManager.swift b/Account/Sources/Account/AccountManager.swift index 37b3c02a0..9a96fe421 100644 --- a/Account/Sources/Account/AccountManager.swift +++ b/Account/Sources/Account/AccountManager.swift @@ -221,55 +221,46 @@ import Secrets } } - public func refreshAll(errorHandler: @escaping (Error) -> Void, completion: (() -> Void)? = nil) { - guard let reachability = try? Reachability(hostname: "apple.com"), reachability.connection != .unavailable else { return } + private func internetIsReachable() -> Bool { - let group = DispatchGroup() - - activeAccounts.forEach { account in - group.enter() - account.refreshAll() { result in - group.leave() - switch result { - case .success: - break - case .failure(let error): - errorHandler(error) - } - } - } - - group.notify(queue: DispatchQueue.main) { - completion?() + guard let reachability = try? Reachability(hostname: "apple.com"), reachability.connection != .unavailable else { + return false } + + return true } - - public func refreshAll(completion: (() -> Void)? = nil) { - guard let reachability = try? Reachability(hostname: "apple.com"), reachability.connection != .unavailable else { return } + + public func refreshAll(errorHandler: ((Error) -> Void)? = nil) async { + + guard internetIsReachable() else { + return + } var syncErrors = [AccountSyncError]() - let group = DispatchGroup() - - activeAccounts.forEach { account in - group.enter() - account.refreshAll() { result in - group.leave() - switch result { - case .success: - break - case .failure(let error): - syncErrors.append(AccountSyncError(account: account, error: error)) + + await withTaskGroup(of: Void.self) { taskGroup in + + for account in self.activeAccounts { + + taskGroup.addTask { @MainActor in + do { + try await account.refreshAll() + } catch { + + if let errorHandler { + errorHandler(error) + } + + let syncError = AccountSyncError(account: account, error: error) + syncErrors.append(syncError) + } } } } - - group.notify(queue: DispatchQueue.main) { - if syncErrors.count > 0 { - NotificationCenter.default.post(Notification(name: .AccountsDidFailToSyncWithErrors, object: self, userInfo: [Account.UserInfoKey.syncErrors: syncErrors])) - } - completion?() + + if !syncErrors.isEmpty { + NotificationCenter.default.post(Notification(name: .AccountsDidFailToSyncWithErrors, object: self, userInfo: [Account.UserInfoKey.syncErrors: syncErrors])) } - } public func sendArticleStatusAll() async { diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index 0dc48e60c..5ab16d2a4 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -543,7 +543,10 @@ import Sparkle } @IBAction func refreshAll(_ sender: Any?) { - accountManager.refreshAll(errorHandler: ErrorHandler.present) + + Task { @MainActor in + await accountManager.refreshAll(errorHandler: ErrorHandler.present) + } } @IBAction func showAddFeedWindow(_ sender: Any?) { diff --git a/Shared/Timer/AccountRefreshTimer.swift b/Shared/Timer/AccountRefreshTimer.swift index ca38a81a9..ee147e70a 100644 --- a/Shared/Timer/AccountRefreshTimer.swift +++ b/Shared/Timer/AccountRefreshTimer.swift @@ -73,8 +73,9 @@ import Account lastTimedRefresh = Date() update() - //AccountManager.shared.refreshAll(errorHandler: ErrorHandler.log) - AccountManager.shared.refreshAll(completion: nil) + Task { @MainActor in + await AccountManager.shared.refreshAll() + } } } diff --git a/iOS/AppDelegate.swift b/iOS/AppDelegate.swift index 010505729..f4ff43079 100644 --- a/iOS/AppDelegate.swift +++ b/iOS/AppDelegate.swift @@ -161,7 +161,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD UIApplication.shared.connectedScenes.compactMap( { $0.delegate as? SceneDelegate } ).forEach { $0.cleanUp(conditional: true) } - accountManager.refreshAll(errorHandler: errorHandler) + + Task { @MainActor in + await self.accountManager.refreshAll(errorHandler: errorHandler) + } } func resumeDatabaseProcessingIfNecessary() { @@ -183,19 +186,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD extensionFeedAddRequestFile.resume() syncTimer?.update() - if let lastRefresh = AppDefaults.shared.lastRefresh { - if Date() > lastRefresh.addingTimeInterval(15 * 60) { - accountManager.refreshAll(errorHandler: ErrorHandler.log) - } else { - Task { @MainActor in + Task { @MainActor in + if let lastRefresh = AppDefaults.shared.lastRefresh { + if Date() > lastRefresh.addingTimeInterval(15 * 60) { + await accountManager.refreshAll(errorHandler: ErrorHandler.log) + } else { await accountManager.syncArticleStatusAll() } + } else { + await accountManager.refreshAll(errorHandler: ErrorHandler.log) } - } else { - accountManager.refreshAll(errorHandler: ErrorHandler.log) } } - + func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.list, .banner, .badge, .sound]) } @@ -398,13 +401,12 @@ private extension AppDelegate { if self.accountManager.isSuspended { self.accountManager.resumeAll() } - self.accountManager.refreshAll(errorHandler: ErrorHandler.log) { [unowned self] in - if !self.accountManager.isSuspended { - try? WidgetDataEncoder.shared.encodeWidgetData() - self.suspendApplication() - os_log("Account refresh operation completed.", log: self.log, type: .info) - task.setTaskCompleted(success: true) - } + await self.accountManager.refreshAll(errorHandler: ErrorHandler.log) + if !self.accountManager.isSuspended { + try? WidgetDataEncoder.shared.encodeWidgetData() + self.suspendApplication() + os_log("Account refresh operation completed.", log: self.log, type: .info) + task.setTaskCompleted(success: true) } }