mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Convert AccountDelegate.refreshAll to async/await.
This commit is contained in:
@@ -428,8 +428,8 @@ public enum FetchType {
|
||||
await delegate.receiveRemoteNotification(for: self, userInfo: userInfo)
|
||||
}
|
||||
|
||||
public func refreshAll(completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
delegate.refreshAll(for: self, completion: completion)
|
||||
public func refreshAll() async throws {
|
||||
try await delegate.refreshAll(for: self)
|
||||
}
|
||||
|
||||
public func sendArticleStatus(completion: ((Result<Void, Error>) -> Void)? = nil) {
|
||||
@@ -453,18 +453,23 @@ public enum FetchType {
|
||||
return
|
||||
}
|
||||
|
||||
delegate.importOPML(for: self, opmlFile: opmlFile) { [weak self] result in
|
||||
switch result {
|
||||
case .success:
|
||||
guard let self = self else { return }
|
||||
// Reset the last fetch date to get the article history for the added feeds.
|
||||
self.metadata.lastArticleFetchStartTime = nil
|
||||
self.delegate.refreshAll(for: self, completion: completion)
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
delegate.importOPML(for: self, opmlFile: opmlFile) { result in
|
||||
Task { @MainActor in
|
||||
switch result {
|
||||
case .success:
|
||||
// Reset the last fetch date to get the article history for the added feeds.
|
||||
self.metadata.lastArticleFetchStartTime = nil
|
||||
do {
|
||||
try await self.delegate.refreshAll(for: self)
|
||||
completion(result)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
case .failure:
|
||||
completion(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public func suspendNetwork() {
|
||||
|
||||
@@ -25,7 +25,7 @@ import Secrets
|
||||
|
||||
func receiveRemoteNotification(for account: Account, userInfo: [AnyHashable : Any]) async
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void)
|
||||
func refreshAll(for account: Account) async throws
|
||||
func syncArticleStatus(for account: Account, completion: ((Result<Void, Error>) -> Void)?)
|
||||
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void))
|
||||
func refreshArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void))
|
||||
|
||||
@@ -75,37 +75,37 @@ public enum FeedbinAccountDelegateError: String, Error {
|
||||
return
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
func refreshAll(for account: Account) async throws {
|
||||
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(5)
|
||||
|
||||
refreshAccount(account) { result in
|
||||
switch result {
|
||||
case .success():
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
refreshAccount(account) { result in
|
||||
switch result {
|
||||
case .success():
|
||||
|
||||
self.refreshArticlesAndStatuses(account) { result in
|
||||
switch result {
|
||||
case .success():
|
||||
completion(.success(()))
|
||||
case .failure(let error):
|
||||
DispatchQueue.main.async {
|
||||
self.refreshProgress.clear()
|
||||
let wrappedError = WrappedAccountError(accountID: account.accountID, accountNameForDisplay: account.nameForDisplay, underlyingError: error)
|
||||
completion(.failure(wrappedError))
|
||||
self.refreshArticlesAndStatuses(account) { result in
|
||||
switch result {
|
||||
case .success():
|
||||
continuation.resume()
|
||||
case .failure(let error):
|
||||
Task { @MainActor in
|
||||
self.refreshProgress.clear()
|
||||
let wrappedError = WrappedAccountError(accountID: account.accountID, accountNameForDisplay: account.nameForDisplay, underlyingError: error)
|
||||
continuation.resume(throwing: wrappedError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
DispatchQueue.main.async {
|
||||
self.refreshProgress.clear()
|
||||
let wrappedError = WrappedAccountError(accountID: account.accountID, accountNameForDisplay: account.nameForDisplay, underlyingError: error)
|
||||
completion(.failure(wrappedError))
|
||||
|
||||
case .failure(let error):
|
||||
Task { @MainActor in
|
||||
self.refreshProgress.clear()
|
||||
let wrappedError = WrappedAccountError(accountID: account.accountID, accountNameForDisplay: account.nameForDisplay, underlyingError: error)
|
||||
continuation.resume(throwing: wrappedError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func syncArticleStatus(for account: Account, completion: ((Result<Void, Error>) -> Void)? = nil) {
|
||||
|
||||
@@ -24,7 +24,7 @@ public enum LocalAccountDelegateError: String, Error {
|
||||
final class LocalAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
weak var account: Account?
|
||||
|
||||
|
||||
private lazy var refresher: LocalAccountRefresher? = {
|
||||
let refresher = LocalAccountRefresher()
|
||||
refresher.delegate = self
|
||||
@@ -44,28 +44,31 @@ final class LocalAccountDelegate: AccountDelegate, Logging {
|
||||
return
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func refreshAll(for account: Account) async throws {
|
||||
guard refreshProgress.isComplete else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
let feeds = account.flattenedFeeds()
|
||||
let feedURLs = Set(feeds.map{ $0.url })
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(feedURLs.count)
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
Task { @MainActor in
|
||||
let feeds = account.flattenedFeeds()
|
||||
let feedURLs = Set(feeds.map{ $0.url })
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(feedURLs.count)
|
||||
|
||||
let group = DispatchGroup()
|
||||
let group = DispatchGroup()
|
||||
|
||||
group.enter()
|
||||
refresher?.refreshFeedURLs(feedURLs) {
|
||||
group.leave()
|
||||
}
|
||||
group.enter()
|
||||
refresher?.refreshFeedURLs(feedURLs) {
|
||||
group.leave()
|
||||
}
|
||||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
self.refreshProgress.clear()
|
||||
account.metadata.lastArticleFetchEndTime = Date()
|
||||
completion(.success(()))
|
||||
}
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
self.refreshProgress.clear()
|
||||
account.metadata.lastArticleFetchEndTime = Date()
|
||||
continuation.resume()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
return
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
private func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> ()) {
|
||||
self.refreshProgress.addToNumberOfTasksAndRemaining(4)
|
||||
|
||||
refreshFeeds(for: account) { result in
|
||||
@@ -118,6 +118,19 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account) async throws {
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
self.refreshAll(for: account) { result in
|
||||
switch result {
|
||||
case .success():
|
||||
continuation.resume()
|
||||
case .failure(let error):
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func syncArticleStatus(for account: Account, completion: ((Result<Void, Error>) -> Void)? = nil) {
|
||||
sendArticleStatus(for: account) { result in
|
||||
switch result {
|
||||
|
||||
@@ -166,11 +166,22 @@ public enum ReaderAPIAccountDelegateError: LocalizedError {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account) async throws {
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
self.refreshAll(for: account) { result in
|
||||
switch result {
|
||||
case .success():
|
||||
continuation.resume()
|
||||
case .failure(let error):
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func syncArticleStatus(for account: Account, completion: ((Result<Void, Error>) -> Void)? = nil) {
|
||||
guard variant != .inoreader else {
|
||||
completion?(.success(()))
|
||||
|
||||
@@ -245,28 +245,23 @@ import RSDatabase
|
||||
}
|
||||
}
|
||||
|
||||
public func refreshAll(errorHandler: @escaping @MainActor (Error) -> Void, completion: (() -> Void)? = nil) {
|
||||
public func refreshAll(errorHandler: @escaping @MainActor (Error) -> Void) async {
|
||||
|
||||
guard let reachability = try? Reachability(hostname: "apple.com"), reachability.connection != .unavailable else { return }
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
||||
for account in activeAccounts {
|
||||
group.enter()
|
||||
account.refreshAll() { result in
|
||||
group.leave()
|
||||
switch result {
|
||||
case .success:
|
||||
break
|
||||
case .failure(let error):
|
||||
Task { @MainActor in
|
||||
errorHandler(error)
|
||||
}
|
||||
await withTaskGroup(of: Void.self) { group in
|
||||
for account in activeAccounts {
|
||||
group.addTask {
|
||||
do {
|
||||
try await account.refreshAll()
|
||||
} catch {
|
||||
Task { @MainActor in
|
||||
errorHandler(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
completion?()
|
||||
await group.waitForAll()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,20 +78,27 @@ final class CloudKitAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func refreshAll(for account: Account) async throws {
|
||||
guard refreshProgress.isComplete else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
let reachability = SCNetworkReachabilityCreateWithName(nil, "apple.com")
|
||||
var flags = SCNetworkReachabilityFlags()
|
||||
guard SCNetworkReachabilityGetFlags(reachability!, &flags), flags.contains(.reachable) else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
standardRefreshAll(for: account, completion: completion)
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
standardRefreshAll(for: account) { result in
|
||||
switch result {
|
||||
case .success():
|
||||
continuation.resume()
|
||||
case .failure(let error):
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func syncArticleStatus(for account: Account, completion: ((Result<Void, Error>) -> Void)? = nil) {
|
||||
|
||||
@@ -107,19 +107,17 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
|
||||
return
|
||||
}
|
||||
|
||||
func refreshAll(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func refreshAll(for account: Account) async throws {
|
||||
assert(Thread.isMainThread)
|
||||
|
||||
guard currentSyncAllOperation == nil else {
|
||||
self.logger.debug("Ignoring refreshAll: Feedly sync already in progress.")
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
guard let credentials = credentials else {
|
||||
self.logger.debug("Ignoring refreshAll: Feedly account has no credentials.")
|
||||
completion(.failure(FeedlyAccountDelegateError.notLoggedIn))
|
||||
return
|
||||
throw FeedlyAccountDelegateError.notLoggedIn
|
||||
}
|
||||
|
||||
let syncAllOperation = FeedlySyncAllOperation(account: account, feedlyUserID: credentials.username, caller: caller, database: database, lastSuccessfulFetchStartDate: accountMetadata?.lastArticleFetchStartTime, downloadProgress: refreshProgress)
|
||||
@@ -127,19 +125,25 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
|
||||
syncAllOperation.downloadProgress = refreshProgress
|
||||
|
||||
let date = Date()
|
||||
syncAllOperation.syncCompletionHandler = { [weak self] result in
|
||||
if case .success = result {
|
||||
self?.accountMetadata?.lastArticleFetchStartTime = date
|
||||
self?.accountMetadata?.lastArticleFetchEndTime = Date()
|
||||
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
syncAllOperation.syncCompletionHandler = { result in
|
||||
self.logger.debug("Sync took \(-date.timeIntervalSinceNow, privacy: .public) seconds.")
|
||||
|
||||
switch result {
|
||||
case .success():
|
||||
self.accountMetadata?.lastArticleFetchStartTime = date
|
||||
self.accountMetadata?.lastArticleFetchEndTime = Date()
|
||||
continuation.resume()
|
||||
case .failure(let error):
|
||||
continuation.resume(throwing: error)
|
||||
}
|
||||
}
|
||||
|
||||
self?.logger.debug("Sync took \(-date.timeIntervalSinceNow, privacy: .public) seconds.")
|
||||
completion(result)
|
||||
|
||||
currentSyncAllOperation = syncAllOperation
|
||||
|
||||
operationQueue.add(syncAllOperation)
|
||||
}
|
||||
|
||||
currentSyncAllOperation = syncAllOperation
|
||||
|
||||
operationQueue.add(syncAllOperation)
|
||||
}
|
||||
|
||||
func syncArticleStatus(for account: Account, completion: ((Result<Void, Error>) -> Void)? = nil) {
|
||||
|
||||
@@ -577,7 +577,9 @@ var appDelegate: AppDelegate!
|
||||
}
|
||||
|
||||
@IBAction func refreshAll(_ sender: Any?) {
|
||||
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present)
|
||||
Task {
|
||||
await AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present)
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func showAddFeedWindow(_ sender: Any?) {
|
||||
|
||||
@@ -94,13 +94,10 @@ import Secrets
|
||||
try self.account?.removeCredentials(type: .basic)
|
||||
try self.account?.storeCredentials(validatedCredentials)
|
||||
|
||||
self.account?.refreshAll() { result in
|
||||
switch result {
|
||||
case .success:
|
||||
break
|
||||
case .failure(let error):
|
||||
NSApplication.shared.presentError(error)
|
||||
}
|
||||
do {
|
||||
try await self.account?.refreshAll()
|
||||
} catch {
|
||||
NSApplication.shared.presentError(error)
|
||||
}
|
||||
|
||||
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
||||
|
||||
@@ -92,13 +92,10 @@ import Secrets
|
||||
try self.account?.storeCredentials(credentials)
|
||||
try self.account?.storeCredentials(validatedCredentials)
|
||||
|
||||
self.account?.refreshAll() { result in
|
||||
switch result {
|
||||
case .success:
|
||||
break
|
||||
case .failure(let error):
|
||||
NSApplication.shared.presentError(error)
|
||||
}
|
||||
do {
|
||||
try await self.account?.refreshAll()
|
||||
} catch {
|
||||
NSApplication.shared.presentError(error)
|
||||
}
|
||||
|
||||
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
||||
|
||||
@@ -272,12 +272,11 @@ extension AccountsPreferencesViewController: OAuthAccountAuthorizationOperationD
|
||||
// because the user probably wants to see the result of authorizing NetNewsWire to act on their behalf.
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
|
||||
account.refreshAll { [weak self] result in
|
||||
switch result {
|
||||
case .success:
|
||||
break
|
||||
case .failure(let error):
|
||||
self?.presentError(error)
|
||||
Task {
|
||||
do {
|
||||
try await account.refreshAll()
|
||||
} catch {
|
||||
self.presentError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,13 +151,10 @@ import ReaderAPI
|
||||
try self.account?.storeCredentials(credentials)
|
||||
try self.account?.storeCredentials(validatedCredentials)
|
||||
|
||||
self.account?.refreshAll() { result in
|
||||
switch result {
|
||||
case .success:
|
||||
break
|
||||
case .failure(let error):
|
||||
NSApplication.shared.presentError(error)
|
||||
}
|
||||
do {
|
||||
try await self.account?.refreshAll()
|
||||
} catch {
|
||||
NSApplication.shared.presentError(error)
|
||||
}
|
||||
|
||||
self.hostWindow?.endSheet(self.window!, returnCode: NSApplication.ModalResponse.OK)
|
||||
|
||||
@@ -73,6 +73,8 @@ import Account
|
||||
lastTimedRefresh = Date()
|
||||
update()
|
||||
|
||||
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.log, completion: nil)
|
||||
Task {
|
||||
await AccountManager.shared.refreshAll(errorHandler: ErrorHandler.log)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user