diff --git a/Account/Sources/Account/Account.swift b/Account/Sources/Account/Account.swift index e0bc64866..2590e1348 100644 --- a/Account/Sources/Account/Account.swift +++ b/Account/Sources/Account/Account.swift @@ -520,8 +520,8 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, addOPMLItems(OPMLNormalizer.normalize(items)) } - public func markArticles(_ articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set
? { - return delegate.markArticles(for: self, articles: articles, statusKey: statusKey, flag: flag) + public func markArticles(_ articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) { + delegate.markArticles(for: self, articles: articles, statusKey: statusKey, flag: flag) } func existingContainer(withExternalID externalID: String) -> Container? { @@ -794,18 +794,23 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, } } - @discardableResult - func update(_ articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) throws -> Set
? { + func update(_ articles: Set
, statusKey: ArticleStatus.Key, flag: Bool, completion: @escaping ArticleSetResultBlock) { // Returns set of Articles whose statuses did change. - guard !articles.isEmpty, let updatedStatuses = try database.mark(articles, statusKey: statusKey, flag: flag) else { - return nil + guard !articles.isEmpty else { + completion(.success(Set
())) + return } - let updatedArticleIDs = updatedStatuses.articleIDs() - let updatedArticles = Set(articles.filter{ updatedArticleIDs.contains($0.articleID) }) - - noteStatusesForArticlesDidChange(updatedArticles) - return updatedArticles + database.mark(articles, statusKey: statusKey, flag: flag) { result in + switch result { + case .success(let updatedStatuses): + let updatedArticleIDs = updatedStatuses.articleIDs() + let updatedArticles = Set(articles.filter{ updatedArticleIDs.contains($0.articleID) }) + self.noteStatusesForArticlesDidChange(updatedArticles) + case .failure(let error): + completion(.failure(error)) + } + } } /// Make sure statuses exist. Any existing statuses won’t be touched. diff --git a/Account/Sources/Account/AccountDelegate.swift b/Account/Sources/Account/AccountDelegate.swift index d575434cb..913f59dd9 100644 --- a/Account/Sources/Account/AccountDelegate.swift +++ b/Account/Sources/Account/AccountDelegate.swift @@ -44,7 +44,7 @@ protocol AccountDelegate { func restoreWebFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result) -> Void) func restoreFolder(for account: Account, folder: Folder, completion: @escaping (Result) -> Void) - func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set
? + func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) // Called at the end of account’s init method. func accountDidInitialize(_ account: Account) diff --git a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift index 25a130633..f0f578c3d 100644 --- a/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift +++ b/Account/Sources/Account/CloudKit/CloudKitAccountDelegate.swift @@ -399,21 +399,25 @@ final class CloudKitAccountDelegate: AccountDelegate { } } - func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set
? { - let syncStatuses = articles.map { article in - return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) - } - - try? database.insertStatuses(syncStatuses) - let articles = try? account.update(articles, statusKey: statusKey, flag: flag) + func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) { + account.update(articles, statusKey: statusKey, flag: flag) { result in + switch result { + case .success(let articles): + let syncStatuses = articles.map { article in + return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) + } - database.selectPendingCount { result in - if let count = try? result.get(), count > 100 { - self.sendArticleStatus(for: account, showProgress: false) { _ in } + try? self.database.insertStatuses(syncStatuses) + + self.database.selectPendingCount { result in + if let count = try? result.get(), count > 100 { + self.sendArticleStatus(for: account, showProgress: false) { _ in } + } + } + case .failure(let error): + os_log(.error, log: self.log, "Error marking article status: %@", error.localizedDescription) } } - - return articles } func accountDidInitialize(_ account: Account) { diff --git a/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift b/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift index 5790cb008..7784f029b 100644 --- a/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift +++ b/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift @@ -435,19 +435,27 @@ final class FeedWranglerAccountDelegate: AccountDelegate { fatalError() } - func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set
? { - let syncStatuses = articles.map { SyncStatus(articleID: $0.articleID, key: SyncStatus.Key(statusKey), flag: flag)} - try? database.insertStatuses(syncStatuses) - - database.selectPendingCount { result in - if let count = try? result.get(), count > 0 { - self.sendArticleStatus(for: account) { _ in } + func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) { + account.update(articles, statusKey: statusKey, flag: flag) { result in + switch result { + case .success(let articles): + let syncStatuses = articles.map { article in + return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) + } + + try? self.database.insertStatuses(syncStatuses) + + self.database.selectPendingCount { result in + if let count = try? result.get(), count > 100 { + self.sendArticleStatus(for: account) { _ in } + } + } + case .failure(let error): + os_log(.error, log: self.log, "Error marking article status: %@", error.localizedDescription) } } - - return try? account.update(articles, statusKey: statusKey, flag: flag) } - + func accountDidInitialize(_ account: Account) { credentials = try? account.retrieveCredentials(type: .feedWranglerToken) } diff --git a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift index f6feb8a34..df4a49b59 100644 --- a/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Account/Sources/Account/Feedbin/FeedbinAccountDelegate.swift @@ -534,22 +534,27 @@ final class FeedbinAccountDelegate: AccountDelegate { } - func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set
? { + func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) { + account.update(articles, statusKey: statusKey, flag: flag) { result in + switch result { + case .success(let articles): + let syncStatuses = articles.map { article in + return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) + } - let syncStatuses = articles.map { article in - return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) - } - try? database.insertStatuses(syncStatuses) + try? self.database.insertStatuses(syncStatuses) - database.selectPendingCount { result in - if let count = try? result.get(), count > 100 { - self.sendArticleStatus(for: account) { _ in } + self.database.selectPendingCount { result in + if let count = try? result.get(), count > 100 { + self.sendArticleStatus(for: account) { _ in } + } + } + case .failure(let error): + os_log(.error, log: self.log, "Error marking article status: %@", error.localizedDescription) } } - - return try? account.update(articles, statusKey: statusKey, flag: flag) } - + func accountDidInitialize(_ account: Account) { credentials = try? account.retrieveCredentials(type: .basic) } diff --git a/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift b/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift index a5be6f994..b871a10f2 100644 --- a/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift +++ b/Account/Sources/Account/Feedly/FeedlyAccountDelegate.swift @@ -487,24 +487,27 @@ final class FeedlyAccountDelegate: AccountDelegate { } } - func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set
? { - - let syncStatuses = articles.map { article in - return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) - } - - try? database.insertStatuses(syncStatuses) - os_log(.debug, log: log, "Marking %@ as %@.", articles.map { $0.title }, syncStatuses) + func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) { + account.update(articles, statusKey: statusKey, flag: flag) { result in + switch result { + case .success(let articles): + let syncStatuses = articles.map { article in + return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) + } - database.selectPendingCount { result in - if let count = try? result.get(), count > 100 { - self.sendArticleStatus(for: account) { _ in } + try? self.database.insertStatuses(syncStatuses) + + self.database.selectPendingCount { result in + if let count = try? result.get(), count > 100 { + self.sendArticleStatus(for: account) { _ in } + } + } + case .failure(let error): + os_log(.error, log: self.log, "Error marking article status: %@", error.localizedDescription) } } - - return try? account.update(articles, statusKey: statusKey, flag: flag) } - + func accountDidInitialize(_ account: Account) { initializedAccount = account credentials = try? account.retrieveCredentials(type: .oauthAccessToken) diff --git a/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift b/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift index 8b69cfe46..5dd9ae59a 100644 --- a/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift +++ b/Account/Sources/Account/LocalAccount/LocalAccountDelegate.swift @@ -203,8 +203,8 @@ final class LocalAccountDelegate: AccountDelegate { completion(.success(())) } - func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set
? { - return try? account.update(articles, statusKey: statusKey, flag: flag) + func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) { + account.update(articles, statusKey: statusKey, flag: flag) { _ in } } func accountDidInitialize(_ account: Account) { diff --git a/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift b/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift index 02c0f16d2..d335719ad 100644 --- a/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift +++ b/Account/Sources/Account/NewsBlur/NewsBlurAccountDelegate.swift @@ -573,19 +573,25 @@ final class NewsBlurAccountDelegate: AccountDelegate { } } - func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set
? { - let syncStatuses = articles.map { article in - return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) - } - try? database.insertStatuses(syncStatuses) + func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) { + account.update(articles, statusKey: statusKey, flag: flag) { result in + switch result { + case .success(let articles): + let syncStatuses = articles.map { article in + return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) + } - database.selectPendingCount { result in - if let count = try? result.get(), count > 100 { - self.sendArticleStatus(for: account) { _ in } + try? self.database.insertStatuses(syncStatuses) + + self.database.selectPendingCount { result in + if let count = try? result.get(), count > 100 { + self.sendArticleStatus(for: account) { _ in } + } + } + case .failure(let error): + os_log(.error, log: self.log, "Error marking article status: %@", error.localizedDescription) } } - - return try? account.update(articles, statusKey: statusKey, flag: flag) } func accountDidInitialize(_ account: Account) { diff --git a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift index 773975de2..1168a143e 100644 --- a/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift +++ b/Account/Sources/Account/ReaderAPI/ReaderAPIAccountDelegate.swift @@ -471,24 +471,27 @@ final class ReaderAPIAccountDelegate: AccountDelegate { } - - func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set
? { - - let syncStatuses = articles.map { article in - return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) - } - try? database.insertStatuses(syncStatuses) - - database.selectPendingCount { result in - if let count = try? result.get(), count > 100 { - self.sendArticleStatus(for: account) { _ in } + func markArticles(for account: Account, articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) { + account.update(articles, statusKey: statusKey, flag: flag) { result in + switch result { + case .success(let articles): + let syncStatuses = articles.map { article in + return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag) + } + + try? self.database.insertStatuses(syncStatuses) + + self.database.selectPendingCount { result in + if let count = try? result.get(), count > 100 { + self.sendArticleStatus(for: account) { _ in } + } + } + case .failure(let error): + os_log(.error, log: self.log, "Error marking article status: %@", error.localizedDescription) } } - - return try? account.update(articles, statusKey: statusKey, flag: flag) - } - + func accountDidInitialize(_ account: Account) { credentials = try? account.retrieveCredentials(type: .readerAPIKey) } diff --git a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift index ddb33073e..ddb576ba9 100644 --- a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift +++ b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesDatabase.swift @@ -237,8 +237,8 @@ public final class ArticlesDatabase { articlesTable.fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate(completion) } - public func mark(_ articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) throws -> Set? { - return try articlesTable.mark(articles, statusKey, flag) + public func mark(_ articles: Set
, statusKey: ArticleStatus.Key, flag: Bool, completion: @escaping ArticleStatusesResultBlock) { + return articlesTable.mark(articles, statusKey, flag, completion) } public func markAndFetchNew(articleIDs: Set, statusKey: ArticleStatus.Key, flag: Bool, completion: @escaping ArticleIDsCompletionBlock) { diff --git a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift index e28fc0475..693faf087 100644 --- a/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift +++ b/ArticlesDatabase/Sources/ArticlesDatabase/ArticlesTable.swift @@ -434,22 +434,20 @@ final class ArticlesTable: DatabaseTable { statusesTable.fetchArticleIDsForStatusesWithoutArticlesNewerThan(articleCutoffDate, completion) } - func mark(_ articles: Set
, _ statusKey: ArticleStatus.Key, _ flag: Bool) throws -> Set? { - var statuses: Set? - var error: DatabaseError? - self.queue.runInTransactionSync { databaseResult in + func mark(_ articles: Set
, _ statusKey: ArticleStatus.Key, _ flag: Bool, _ completion: @escaping ArticleStatusesResultBlock) { + self.queue.runInTransaction { databaseResult in switch databaseResult { case .success(let database): - statuses = self.statusesTable.mark(articles.statuses(), statusKey, flag, database) + let statuses = self.statusesTable.mark(articles.statuses(), statusKey, flag, database) + DispatchQueue.main.async { + completion(.success(statuses ?? Set())) + } case .failure(let databaseError): - error = databaseError + DispatchQueue.main.async { + completion(.failure(databaseError)) + } } } - - if let error = error { - throw error - } - return statuses } func markAndFetchNew(_ articleIDs: Set, _ statusKey: ArticleStatus.Key, _ flag: Bool, _ completion: @escaping ArticleIDsCompletionBlock) { diff --git a/Shared/Extensions/ArticleUtilities.swift b/Shared/Extensions/ArticleUtilities.swift index cfc4e34fb..aeee931ae 100644 --- a/Shared/Extensions/ArticleUtilities.swift +++ b/Shared/Extensions/ArticleUtilities.swift @@ -13,25 +13,16 @@ import Account // These handle multiple accounts. -@discardableResult -func markArticles(_ articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) -> Set
? { +func markArticles(_ articles: Set
, statusKey: ArticleStatus.Key, flag: Bool) { let d: [String: Set
] = accountAndArticlesDictionary(articles) - var updatedArticles = Set
() for (accountID, accountArticles) in d { - guard let account = AccountManager.shared.existingAccount(with: accountID) else { continue } - - if let accountUpdatedArticles = account.markArticles(accountArticles, statusKey: statusKey, flag: flag) { - updatedArticles.formUnion(accountUpdatedArticles) - } - + account.markArticles(accountArticles, statusKey: statusKey, flag: flag) } - - return updatedArticles } private func accountAndArticlesDictionary(_ articles: Set
) -> [String: Set
] {