Convert account.update to async await.

This commit is contained in:
Brent Simmons 2024-04-04 22:05:46 -07:00
parent a88d57952e
commit 9f67b3f498
9 changed files with 119 additions and 125 deletions

View File

@ -809,56 +809,34 @@ public enum FetchType {
return articleChanges
}
func update(feedIDsAndItems: [String: Set<ParsedItem>], defaultRead: Bool, completion: @escaping DatabaseCompletionBlock) {
func update(feedIDsAndItems: [String: Set<ParsedItem>], defaultRead: Bool) async throws {
precondition(Thread.isMainThread)
precondition(type != .onMyMac && type != .cloudKit)
guard !feedIDsAndItems.isEmpty else {
completion(nil)
return
}
database.update(feedIDsAndItems: feedIDsAndItems, defaultRead: defaultRead) { updateArticlesResult in
MainActor.assumeIsolated {
switch updateArticlesResult {
case .success(let newAndUpdatedArticles):
self.sendNotificationAbout(newAndUpdatedArticles)
completion(nil)
case .failure(let databaseError):
completion(databaseError)
}
}
}
let articleChanges = try await database.update(feedIDsAndItems: feedIDsAndItems, defaultRead: defaultRead)
sendNotificationAbout(articleChanges)
}
func update(_ articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool, completion: @escaping ArticleSetResultBlock) {
func update(articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) async throws -> Set<Article> {
// Returns set of Articles whose statuses did change.
// Return set of Articles whose statuses did change.
guard !articles.isEmpty else {
completion(.success(Set<Article>()))
return
if articles.isEmpty {
return Set<Article>()
}
Task { @MainActor in
let updatedStatuses = try await database.mark(articles: articles, statusKey: statusKey, flag: flag) ?? Set<ArticleStatus>()
do {
var updatedArticles = Set<Article>()
let updatedArticleIDs = updatedStatuses.articleIDs()
let updatedArticles = Set(articles.filter{ updatedArticleIDs.contains($0.articleID) })
self.noteStatusesForArticlesDidChange(updatedArticles)
if let updatedStatuses = try await database.mark(articles: articles, statusKey: statusKey, flag: flag) {
let updatedArticleIDs = updatedStatuses.articleIDs()
updatedArticles = Set(articles.filter{ updatedArticleIDs.contains($0.articleID) })
self.noteStatusesForArticlesDidChange(updatedArticles)
}
completion(.success(updatedArticles))
} catch {
completion(.failure(.suspended))
}
}
return updatedArticles
}
/// Make sure statuses exist. Any existing statuses wont be touched.

View File

@ -616,21 +616,25 @@ enum CloudKitAccountDelegateError: LocalizedError {
}
private func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool, completion: @escaping (Result<Void, Error>) -> Void) {
account.update(articles, statusKey: statusKey, flag: flag) { result in
switch result {
case .success(let articles):
Task { @MainActor in
do {
let articles = try await account.update(articles: articles, statusKey: statusKey, flag: flag)
let syncStatuses = articles.map { article in
return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag)
}
Task { @MainActor in
try? await self.database.insertStatuses(syncStatuses)
if let count = try? await self.database.selectPendingCount(), count > 100 {
self.sendArticleStatus(for: account, showProgress: false) { _ in }
}
completion(.success(()))
try? await self.database.insertStatuses(syncStatuses)
if let count = try? await self.database.selectPendingCount(), count > 100 {
self.sendArticleStatus(for: account, showProgress: false) { _ in }
}
case .failure(let error):
completion(.success(()))
} catch {
completion(.failure(error))
}
}

View File

@ -751,23 +751,25 @@ final class FeedbinAccountDelegate: AccountDelegate {
}
private func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool, completion: @escaping (Result<Void, Error>) -> Void) {
account.update(articles, statusKey: statusKey, flag: flag) { result in
switch result {
case .success(let articles):
Task { @MainActor in
do {
let articles = try await account.update(articles: articles, statusKey: statusKey, flag: flag)
let syncStatuses = articles.map { article in
return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag)
}
Task { @MainActor in
try? await self.database.insertStatuses(syncStatuses)
try? await self.database.insertStatuses(syncStatuses)
if let count = try? await self.database.selectPendingCount(), count > 100 {
self.sendArticleStatus(for: account) { _ in }
}
completion(.success(()))
if let count = try? await self.database.selectPendingCount(), count > 100 {
self.sendArticleStatus(for: account) { _ in }
}
completion(.success(()))
case .failure(let error):
} catch {
completion(.failure(error))
}
}
@ -1467,13 +1469,22 @@ private extension FeedbinAccountDelegate {
}
}
}
func processEntries(account: Account, entries: [FeedbinEntry]?, completion: @escaping DatabaseCompletionBlock) {
let parsedItems = mapEntriesToParsedItems(entries: entries)
let feedIDsAndItems = Dictionary(grouping: parsedItems, by: { item in item.feedURL } ).mapValues { Set($0) }
account.update(feedIDsAndItems: feedIDsAndItems, defaultRead: true, completion: completion)
Task { @MainActor in
do {
try await account.update(feedIDsAndItems: feedIDsAndItems, defaultRead: true)
completion(nil)
} catch {
completion(.suspended)
}
}
}
func mapEntriesToParsedItems(entries: [FeedbinEntry]?) -> Set<ParsedItem> {
guard let entries = entries else {
return Set<ParsedItem>()

View File

@ -730,23 +730,25 @@ final class FeedlyAccountDelegate: AccountDelegate {
}
private func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool, completion: @escaping (Result<Void, Error>) -> Void) {
account.update(articles, statusKey: statusKey, flag: flag) { result in
switch result {
case .success(let articles):
Task { @MainActor in
do {
let articles = try await account.update(articles: articles, statusKey: statusKey, flag: flag)
let syncStatuses = articles.map { article in
return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag)
}
Task { @MainActor in
try? await self.database.insertStatuses(syncStatuses)
try? await self.database.insertStatuses(syncStatuses)
if let count = try? await self.database.selectPendingCount(), count > 100 {
self.sendArticleStatus(for: account) { _ in }
}
completion(.success(()))
if let count = try? await self.database.selectPendingCount(), count > 100 {
self.sendArticleStatus(for: account) { _ in }
}
case .failure(let error):
completion(.success(()))
} catch {
completion(.failure(error))
}
}

View File

@ -19,23 +19,25 @@ final class FeedlyUpdateAccountFeedsWithItemsOperation: FeedlyOperation {
private let log: OSLog
init(account: Account, organisedItemsProvider: FeedlyParsedItemsByFeedProviding, log: OSLog) {
self.account = account
self.organisedItemsProvider = organisedItemsProvider
self.log = log
}
override func run() {
let feedIDsAndItems = organisedItemsProvider.parsedItemsKeyedByFeedId
account.update(feedIDsAndItems: feedIDsAndItems, defaultRead: true) { databaseError in
MainActor.assumeIsolated {
if let error = databaseError {
self.didFinish(with: error)
return
}
Task { @MainActor in
do {
try await account.update(feedIDsAndItems: feedIDsAndItems, defaultRead: true)
os_log(.debug, log: self.log, "Updated %i feeds for \"%@\"", feedIDsAndItems.count, self.organisedItemsProvider.parsedItemsByFeedProviderName)
self.didFinish()
} catch {
self.didFinish(with: error)
}
}
}

View File

@ -142,16 +142,7 @@ final class LocalAccountDelegate: AccountDelegate {
func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) async throws {
try await withCheckedThrowingContinuation { continuation in
account.update(articles, statusKey: statusKey, flag: flag) { result in
switch result {
case .success:
continuation.resume()
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
try await account.update(articles: articles, statusKey: statusKey, flag: flag)
}
func accountDidInitialize(_ account: Account) {

View File

@ -368,6 +368,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
func processStories(account: Account, stories: [NewsBlurStory]?, since: Date? = nil, completion: @escaping (Result<Bool, DatabaseError>) -> Void) {
let parsedItems = mapStoriesToParsedItems(stories: stories).filter {
guard let datePublished = $0.datePublished, let since = since else {
return true
@ -379,13 +380,13 @@ final class NewsBlurAccountDelegate: AccountDelegate {
Set($0)
}
account.update(feedIDsAndItems: feedIDsAndItems, defaultRead: true) { error in
if let error = error {
completion(.failure(error))
return
Task { @MainActor in
do {
try await account.update(feedIDsAndItems: feedIDsAndItems, defaultRead: true)
completion(.success(!feedIDsAndItems.isEmpty))
} catch {
completion(.failure(.suspended))
}
completion(.success(!feedIDsAndItems.isEmpty))
}
}
@ -788,23 +789,25 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
private func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool, completion: @escaping (Result<Void, Error>) -> Void) {
account.update(articles, statusKey: statusKey, flag: flag) { result in
switch result {
case .success(let articles):
Task { @MainActor in
do {
let articles = try await account.update(articles: articles, statusKey: statusKey, flag: flag)
let syncStatuses = articles.map { article in
return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag)
}
Task { @MainActor in
try? await self.database.insertStatuses(syncStatuses)
try? await self.database.insertStatuses(syncStatuses)
if let count = try? await self.database.selectPendingCount(), count > 100 {
self.sendArticleStatus(for: account) { _ in }
}
completion(.success(()))
if let count = try? await self.database.selectPendingCount(), count > 100 {
self.sendArticleStatus(for: account) { _ in }
}
case .failure(let error):
completion(.success(()))
} catch {
completion(.failure(error))
}
}

View File

@ -803,25 +803,25 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
}
private func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool, completion: @escaping (Result<Void, Error>) -> Void) {
account.update(articles, statusKey: statusKey, flag: flag) { result in
switch result {
case .success(let articles):
Task { @MainActor in
do {
let articles = try await account.update(articles: articles, statusKey: statusKey, flag: flag)
let syncStatuses = articles.map { article in
return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag)
}
Task { @MainActor in
try? await self.database.insertStatuses(syncStatuses)
try? await self.database.insertStatuses(syncStatuses)
if let count = try? await self.database.selectPendingCount(), count > 100 {
self.sendArticleStatus(for: account) { _ in }
}
completion(.success(()))
if let count = try? await self.database.selectPendingCount(), count > 100 {
self.sendArticleStatus(for: account) { _ in }
}
case .failure(let error):
completion(.success(()))
} catch {
completion(.failure(error))
}
}
@ -1246,9 +1246,12 @@ private extension ReaderAPIAccountDelegate {
}
func processEntries(account: Account, entries: [ReaderAPIEntry]?, completion: @escaping VoidCompletionBlock) {
let parsedItems = mapEntriesToParsedItems(account: account, entries: entries)
let feedIDsAndItems = Dictionary(grouping: parsedItems, by: { item in item.feedURL } ).mapValues { Set($0) }
account.update(feedIDsAndItems: feedIDsAndItems, defaultRead: true) { _ in
Task { @MainActor in
try? await account.update(feedIDsAndItems: feedIDsAndItems, defaultRead: true)
completion()
}
}

View File

@ -38,17 +38,17 @@ public extension ArticlesDatabase {
// }
/// Update articles and save new ones for sync systems (Feedbin, Feedly, etc.).
nonisolated func update(feedIDsAndItems: [String: Set<ParsedItem>], defaultRead: Bool, completion: @escaping UpdateArticlesCompletionBlock) {
Task {
do {
let articleChanges = try await update(feedIDsAndItems: feedIDsAndItems, defaultRead: defaultRead)
callUpdateArticlesCompletion(completion, .success(articleChanges))
} catch {
callUpdateArticlesCompletion(completion, .failure(.suspended))
}
}
}
// nonisolated func update(feedIDsAndItems: [String: Set<ParsedItem>], defaultRead: Bool, completion: @escaping UpdateArticlesCompletionBlock) {
//
// Task {
// do {
// let articleChanges = try await update(feedIDsAndItems: feedIDsAndItems, defaultRead: defaultRead)
// callUpdateArticlesCompletion(completion, .success(articleChanges))
// } catch {
// callUpdateArticlesCompletion(completion, .failure(.suspended))
// }
// }
// }
nonisolated private func callUpdateArticlesCompletion(_ completion: @escaping UpdateArticlesCompletionBlock, _ result: UpdateArticlesResult) {