Convert update methods to async await.
This commit is contained in:
parent
3f2db0ef12
commit
a88d57952e
@ -784,58 +784,36 @@ public enum FetchType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
func update(_ feed: Feed, with parsedFeed: ParsedFeed) async throws -> ArticleChanges {
|
func update(feed: Feed, with parsedFeed: ParsedFeed) async throws -> ArticleChanges {
|
||||||
|
|
||||||
try await withCheckedThrowingContinuation { continuation in
|
|
||||||
self.update(feed, with: parsedFeed) { result in
|
|
||||||
switch result {
|
|
||||||
case .success(let articleChanges):
|
|
||||||
continuation.resume(returning: articleChanges)
|
|
||||||
case .failure(let error):
|
|
||||||
continuation.resume(throwing: error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func update(_ feed: Feed, with parsedFeed: ParsedFeed, _ completion: @escaping UpdateArticlesCompletionBlock) {
|
|
||||||
// Used only by an On My Mac or iCloud account.
|
|
||||||
precondition(Thread.isMainThread)
|
precondition(Thread.isMainThread)
|
||||||
precondition(type == .onMyMac || type == .cloudKit)
|
precondition(type == .onMyMac || type == .cloudKit)
|
||||||
|
|
||||||
feed.takeSettings(from: parsedFeed)
|
feed.takeSettings(from: parsedFeed)
|
||||||
|
|
||||||
let parsedItems = parsedFeed.items
|
let parsedItems = parsedFeed.items
|
||||||
guard !parsedItems.isEmpty else {
|
if parsedItems.isEmpty {
|
||||||
completion(.success(ArticleChanges()))
|
return ArticleChanges()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update(feed.feedID, with: parsedItems, completion: completion)
|
return try await update(feedID: feed.feedID, with: parsedItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(_ feedID: String, with parsedItems: Set<ParsedItem>, deleteOlder: Bool = true, completion: @escaping UpdateArticlesCompletionBlock) {
|
func update(feedID: String, with parsedItems: Set<ParsedItem>, deleteOlder: Bool = true) async throws -> ArticleChanges {
|
||||||
// Used only by an On My Mac or iCloud account.
|
|
||||||
precondition(Thread.isMainThread)
|
precondition(Thread.isMainThread)
|
||||||
precondition(type == .onMyMac || type == .cloudKit)
|
precondition(type == .onMyMac || type == .cloudKit)
|
||||||
|
|
||||||
database.update(with: parsedItems, feedID: feedID, deleteOlder: deleteOlder) { updateArticlesResult in
|
|
||||||
|
|
||||||
MainActor.assumeIsolated {
|
let articleChanges = try await database.update(parsedItems: parsedItems, feedID: feedID, deleteOlder: deleteOlder)
|
||||||
switch updateArticlesResult {
|
self.sendNotificationAbout(articleChanges)
|
||||||
case .success(let articleChanges):
|
return articleChanges
|
||||||
self.sendNotificationAbout(articleChanges)
|
|
||||||
completion(.success(articleChanges))
|
|
||||||
case .failure(let databaseError):
|
|
||||||
completion(.failure(databaseError))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(feedIDsAndItems: [String: Set<ParsedItem>], defaultRead: Bool, completion: @escaping DatabaseCompletionBlock) {
|
func update(feedIDsAndItems: [String: Set<ParsedItem>], defaultRead: Bool, completion: @escaping DatabaseCompletionBlock) {
|
||||||
// Used only by syncing systems.
|
|
||||||
precondition(Thread.isMainThread)
|
precondition(Thread.isMainThread)
|
||||||
precondition(type != .onMyMac && type != .cloudKit)
|
precondition(type != .onMyMac && type != .cloudKit)
|
||||||
|
|
||||||
guard !feedIDsAndItems.isEmpty else {
|
guard !feedIDsAndItems.isEmpty else {
|
||||||
completion(nil)
|
completion(nil)
|
||||||
return
|
return
|
||||||
|
@ -849,45 +849,43 @@ private extension CloudKitAccountDelegate {
|
|||||||
InitialFeedDownloader.download(url) { parsedFeed in
|
InitialFeedDownloader.download(url) { parsedFeed in
|
||||||
self.refreshProgress.completeTask()
|
self.refreshProgress.completeTask()
|
||||||
|
|
||||||
if let parsedFeed = parsedFeed {
|
if let parsedFeed {
|
||||||
account.update(feed, with: parsedFeed) { result in
|
|
||||||
MainActor.assumeIsolated {
|
Task { @MainActor in
|
||||||
switch result {
|
|
||||||
case .success:
|
do {
|
||||||
|
try await account.update(feed: feed, with: parsedFeed)
|
||||||
self.accountZone.createFeed(url: bestFeedSpecifier.urlString,
|
|
||||||
name: parsedFeed.title,
|
self.accountZone.createFeed(url: bestFeedSpecifier.urlString,
|
||||||
editedName: editedName,
|
name: parsedFeed.title,
|
||||||
homePageURL: parsedFeed.homePageURL,
|
editedName: editedName,
|
||||||
container: container) { result in
|
homePageURL: parsedFeed.homePageURL,
|
||||||
|
container: container) { result in
|
||||||
self.refreshProgress.completeTask()
|
|
||||||
switch result {
|
self.refreshProgress.completeTask()
|
||||||
case .success(let externalID):
|
switch result {
|
||||||
feed.externalID = externalID
|
case .success(let externalID):
|
||||||
self.sendNewArticlesToTheCloud(account, feed)
|
feed.externalID = externalID
|
||||||
completion(.success(feed))
|
self.sendNewArticlesToTheCloud(account, feed)
|
||||||
case .failure(let error):
|
completion(.success(feed))
|
||||||
container.removeFeed(feed)
|
case .failure(let error):
|
||||||
self.refreshProgress.completeTasks(2)
|
container.removeFeed(feed)
|
||||||
completion(.failure(error))
|
self.refreshProgress.completeTasks(2)
|
||||||
}
|
completion(.failure(error))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case .failure(let error):
|
|
||||||
container.removeFeed(feed)
|
|
||||||
self.refreshProgress.completeTasks(3)
|
|
||||||
completion(.failure(error))
|
|
||||||
}
|
}
|
||||||
|
} catch {
|
||||||
|
container.removeFeed(feed)
|
||||||
|
self.refreshProgress.completeTasks(3)
|
||||||
|
completion(.failure(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.refreshProgress.completeTasks(3)
|
self.refreshProgress.completeTasks(3)
|
||||||
container.removeFeed(feed)
|
container.removeFeed(feed)
|
||||||
completion(.failure(AccountError.createErrorNotFound))
|
completion(.failure(AccountError.createErrorNotFound))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case .failure:
|
case .failure:
|
||||||
|
@ -139,27 +139,27 @@ private extension CloudKitArticlesZoneDelegate {
|
|||||||
let parsedItems = records.compactMap { self.makeParsedItem($0) }
|
let parsedItems = records.compactMap { self.makeParsedItem($0) }
|
||||||
let feedIDsAndItems = Dictionary(grouping: parsedItems, by: { item in item.feedURL } ).mapValues { Set($0) }
|
let feedIDsAndItems = Dictionary(grouping: parsedItems, by: { item in item.feedURL } ).mapValues { Set($0) }
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
Task { @MainActor in
|
||||||
for (feedID, parsedItems) in feedIDsAndItems {
|
for (feedID, parsedItems) in feedIDsAndItems {
|
||||||
group.enter()
|
group.enter()
|
||||||
self.account?.update(feedID, with: parsedItems, deleteOlder: false) { result in
|
|
||||||
Task { @MainActor in
|
do {
|
||||||
switch result {
|
|
||||||
case .success(let articleChanges):
|
let articleChanges = try await self.account?.update(feedID: feedID, with: parsedItems, deleteOlder: false)
|
||||||
guard let deletes = articleChanges.deletedArticles, !deletes.isEmpty else {
|
|
||||||
group.leave()
|
guard let deletes = articleChanges?.deletedArticles, !deletes.isEmpty else {
|
||||||
return
|
group.leave()
|
||||||
}
|
return
|
||||||
|
|
||||||
let syncStatuses = deletes.map { SyncStatus(articleID: $0.articleID, key: .deleted, flag: true) }
|
|
||||||
try? await self.database.insertStatuses(syncStatuses)
|
|
||||||
group.leave()
|
|
||||||
case .failure(let databaseError):
|
|
||||||
errorOccurred = true
|
|
||||||
os_log(.error, log: self.log, "Error occurred while storing articles: %@", databaseError.localizedDescription)
|
|
||||||
group.leave()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let syncStatuses = deletes.map { SyncStatus(articleID: $0.articleID, key: .deleted, flag: true) }
|
||||||
|
try? await self.database.insertStatuses(syncStatuses)
|
||||||
|
group.leave()
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
errorOccurred = true
|
||||||
|
os_log(.error, log: self.log, "Error occurred while storing articles: %@", error.localizedDescription)
|
||||||
|
group.leave()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ private extension LocalAccountDelegate {
|
|||||||
feed.editedName = editedName
|
feed.editedName = editedName
|
||||||
container.addFeed(feed)
|
container.addFeed(feed)
|
||||||
|
|
||||||
try await account.update(feed, with: parsedFeed)
|
try await account.update(feed: feed, with: parsedFeed)
|
||||||
|
|
||||||
return feed
|
return feed
|
||||||
}
|
}
|
||||||
|
@ -109,24 +109,26 @@ extension LocalAccountRefresher: DownloadSessionDelegate {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
account.update(feed, with: parsedFeed) { result in
|
Task { @MainActor in
|
||||||
MainActor.assumeIsolated {
|
|
||||||
if case .success(let articleChanges) = result {
|
do {
|
||||||
if let httpResponse = response as? HTTPURLResponse {
|
let articleChanges = try await account.update(feed: feed, with: parsedFeed)
|
||||||
feed.conditionalGetInfo = HTTPConditionalGetInfo(urlResponse: httpResponse)
|
|
||||||
}
|
if let httpResponse = response as? HTTPURLResponse {
|
||||||
feed.contentHash = dataHash
|
feed.conditionalGetInfo = HTTPConditionalGetInfo(urlResponse: httpResponse)
|
||||||
self.delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
|
||||||
self.delegate?.localAccountRefresher(self, articleChanges: articleChanges) {
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completion()
|
|
||||||
self.delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
|
||||||
}
|
}
|
||||||
|
feed.contentHash = dataHash
|
||||||
|
|
||||||
|
self.delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||||
|
self.delegate?.localAccountRefresher(self, articleChanges: articleChanges) {
|
||||||
|
completion()
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
completion()
|
||||||
|
self.delegate?.localAccountRefresher(self, requestCompletedFor: feed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import Parser
|
|||||||
|
|
||||||
public typealias UnreadCountDictionary = [String: Int] // feedID: unreadCount
|
public typealias UnreadCountDictionary = [String: Int] // feedID: unreadCount
|
||||||
|
|
||||||
public struct ArticleChanges {
|
public struct ArticleChanges: Sendable {
|
||||||
public let newArticles: Set<Article>?
|
public let newArticles: Set<Article>?
|
||||||
public let updatedArticles: Set<Article>?
|
public let updatedArticles: Set<Article>?
|
||||||
public let deletedArticles: Set<Article>?
|
public let deletedArticles: Set<Article>?
|
||||||
|
@ -25,17 +25,17 @@ public extension ArticlesDatabase {
|
|||||||
// MARK: - Saving, Updating, and Deleting Articles
|
// MARK: - Saving, Updating, and Deleting Articles
|
||||||
|
|
||||||
/// Update articles and save new ones — for feed-based systems (local and iCloud).
|
/// Update articles and save new ones — for feed-based systems (local and iCloud).
|
||||||
nonisolated func update(with parsedItems: Set<ParsedItem>, feedID: String, deleteOlder: Bool, completion: @escaping UpdateArticlesCompletionBlock) {
|
// nonisolated func update(with parsedItems: Set<ParsedItem>, feedID: String, deleteOlder: Bool, completion: @escaping UpdateArticlesCompletionBlock) {
|
||||||
|
//
|
||||||
Task {
|
// Task {
|
||||||
do {
|
// do {
|
||||||
let articleChanges = try await update(parsedItems: parsedItems, feedID: feedID, deleteOlder: deleteOlder)
|
// let articleChanges = try await update(parsedItems: parsedItems, feedID: feedID, deleteOlder: deleteOlder)
|
||||||
callUpdateArticlesCompletion(completion, .success(articleChanges))
|
// callUpdateArticlesCompletion(completion, .success(articleChanges))
|
||||||
} catch {
|
// } catch {
|
||||||
callUpdateArticlesCompletion(completion, .failure(.suspended))
|
// callUpdateArticlesCompletion(completion, .failure(.suspended))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Update articles and save new ones — for sync systems (Feedbin, Feedly, etc.).
|
/// Update articles and save new ones — for sync systems (Feedbin, Feedly, etc.).
|
||||||
nonisolated func update(feedIDsAndItems: [String: Set<ParsedItem>], defaultRead: Bool, completion: @escaping UpdateArticlesCompletionBlock) {
|
nonisolated func update(feedIDsAndItems: [String: Set<ParsedItem>], defaultRead: Bool, completion: @escaping UpdateArticlesCompletionBlock) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user