From 48dbc4958f398e4bc3b88304223e2fd91fded2a0 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sun, 26 Apr 2020 11:26:41 -0500 Subject: [PATCH] Rebuild the import OPML and initial device add processes. --- .../CloudKit/CloudKitAccountDelegate.swift | 84 ++++---- .../CloudKit/CloudKitAccountZone.swift | 4 +- .../CloudKitAccountZoneDelegate.swift | 183 +++--------------- 3 files changed, 64 insertions(+), 207 deletions(-) diff --git a/Frameworks/Account/CloudKit/CloudKitAccountDelegate.swift b/Frameworks/Account/CloudKit/CloudKitAccountDelegate.swift index 296307f2a..3f714497b 100644 --- a/Frameworks/Account/CloudKit/CloudKitAccountDelegate.swift +++ b/Frameworks/Account/CloudKit/CloudKitAccountDelegate.swift @@ -97,11 +97,6 @@ final class CloudKitAccountDelegate: AccountDelegate { } func sendArticleStatus(for account: Account, completion: @escaping ((Result) -> Void)) { - guard refreshProgress.isComplete else { - completion(.success(())) - return - } - os_log(.debug, log: log, "Sending article statuses...") database.selectForProcessing { result in @@ -154,11 +149,6 @@ final class CloudKitAccountDelegate: AccountDelegate { func refreshArticleStatus(for account: Account, completion: @escaping ((Result) -> Void)) { - guard refreshProgress.isComplete else { - completion(.success(())) - return - } - os_log(.debug, log: log, "Refreshing article statuses...") articlesZone.refreshArticles() { result in @@ -214,7 +204,7 @@ final class CloudKitAccountDelegate: AccountDelegate { let normalizedItems = OPMLNormalizer.normalize(opmlItems) self.accountZone.importOPML(rootExternalID: rootExternalID, items: normalizedItems) { _ in - self.initialRefreshAll(for: account, completion: completion) + self.standardRefreshAll(for: account, completion: completion) } } @@ -309,7 +299,7 @@ final class CloudKitAccountDelegate: AccountDelegate { func restoreWebFeed(for account: Account, feed: WebFeed, container: Container, completion: @escaping (Result) -> Void) { refreshProgress.addToNumberOfTasksAndRemaining(1) - accountZone.createWebFeed(url: feed.url, editedName: feed.editedName, container: container) { result in + accountZone.createWebFeed(url: feed.url, name: feed.name, editedName: feed.editedName, container: container) { result in self.refreshProgress.completeTask() switch result { case .success(let externalID): @@ -494,28 +484,18 @@ private extension CloudKitAccountDelegate { completion(.failure(error)) } - refreshProgress.addToNumberOfTasksAndRemaining(3) - refreshArticleStatus(for: account) { result in + refreshProgress.addToNumberOfTasksAndRemaining(2) + accountZone.fetchChangesInZone() { result in + self.refreshProgress.completeTask() + switch result { case .success: - - self.refreshProgress.completeTask() - self.accountZone.fetchChangesInZone() { result in + self.refreshArticleStatus(for: account) { result in + self.refreshProgress.completeTask() switch result { case .success: - - self.refreshProgress.completeTask() - self.sendArticleStatus(for: account) { result in - switch result { - case .success: - self.refreshProgress.clear() - account.metadata.lastArticleFetchEndTime = Date() - completion(.success(())) - case .failure(let error): - fail(error) - } - } - + account.metadata.lastArticleFetchEndTime = Date() + completion(.success(())) case .failure(let error): fail(error) } @@ -667,7 +647,7 @@ private extension CloudKitAccountDelegate { return } - self.accountZone.createWebFeed(url: urlString, editedName: editedName, container: container) { result in + self.accountZone.createWebFeed(url: urlString, name: name, editedName: editedName, container: container) { result in self.refreshProgress.completeTask() switch result { @@ -751,26 +731,27 @@ private extension CloudKitAccountDelegate { return } - self.accountZone.createWebFeed(url: bestFeedSpecifier.urlString, editedName: editedName, container: container) { result in + let feed = account.createWebFeed(with: nil, url: url.absoluteString, webFeedID: url.absoluteString, homePageURL: nil) + feed.editedName = editedName + container.addWebFeed(feed) + InitialFeedDownloader.download(url) { parsedFeed in self.refreshProgress.completeTask() - switch result { - case .success(let externalID): - - let feed = account.createWebFeed(with: nil, url: url.absoluteString, webFeedID: url.absoluteString, homePageURL: nil) - feed.editedName = editedName - feed.externalID = externalID - container.addWebFeed(feed) - InitialFeedDownloader.download(url) { parsedFeed in - self.refreshProgress.completeTask() + if let parsedFeed = parsedFeed { + account.update(feed, with: parsedFeed) { result in + switch result { + case .success(let articleChanges): + BatchUpdate.shared.end() + + self.accountZone.createWebFeed(url: bestFeedSpecifier.urlString, name: parsedFeed.title, editedName: editedName, container: container) { result in - if let parsedFeed = parsedFeed { - account.update(feed, with: parsedFeed) { result in + self.refreshProgress.completeTask() switch result { - case .success(let articleChanges): + case .success(let externalID): + + feed.externalID = externalID - BatchUpdate.shared.end() var newAndUpdatedArticles = articleChanges.newArticles ?? Set
() newAndUpdatedArticles.formUnion(articleChanges.updatedArticles ?? Set
()) let deletedArticles = articleChanges.deletedArticles ?? Set
() @@ -787,23 +768,24 @@ private extension CloudKitAccountDelegate { } case .failure(let error): + BatchUpdate.shared.end() self.refreshProgress.clear() completion(.failure(error)) } } - } else { + + case .failure(let error): self.refreshProgress.clear() - completion(.success(feed)) + completion(.failure(error)) } } - - case .failure(let error): - BatchUpdate.shared.end() + } else { self.refreshProgress.clear() - completion(.failure(error)) + completion(.success(feed)) } + } case .failure: diff --git a/Frameworks/Account/CloudKit/CloudKitAccountZone.swift b/Frameworks/Account/CloudKit/CloudKitAccountZone.swift index 69ff6bef2..2bb242c81 100644 --- a/Frameworks/Account/CloudKit/CloudKitAccountZone.swift +++ b/Frameworks/Account/CloudKit/CloudKitAccountZone.swift @@ -28,6 +28,7 @@ final class CloudKitAccountZone: CloudKitZone { static let recordType = "AccountWebFeed" struct Fields { static let url = "url" + static let name = "name" static let editedName = "editedName" static let containerExternalIDs = "containerExternalIDs" } @@ -81,10 +82,11 @@ final class CloudKitAccountZone: CloudKitZone { } /// Persist a web feed record to iCloud and return the external key - func createWebFeed(url: String, editedName: String?, container: Container, completion: @escaping (Result) -> Void) { + func createWebFeed(url: String, name: String?, editedName: String?, container: Container, completion: @escaping (Result) -> Void) { let recordID = CKRecord.ID(recordName: url.md5String, zoneID: Self.zoneID) let record = CKRecord(recordType: CloudKitWebFeed.recordType, recordID: recordID) record[CloudKitWebFeed.Fields.url] = url + record[CloudKitWebFeed.Fields.name] = name if let editedName = editedName { record[CloudKitWebFeed.Fields.editedName] = editedName } diff --git a/Frameworks/Account/CloudKit/CloudKitAccountZoneDelegate.swift b/Frameworks/Account/CloudKit/CloudKitAccountZoneDelegate.swift index 1a3fa0666..be5b26ccd 100644 --- a/Frameworks/Account/CloudKit/CloudKitAccountZoneDelegate.swift +++ b/Frameworks/Account/CloudKit/CloudKitAccountZoneDelegate.swift @@ -15,7 +15,7 @@ import Articles class CloudKitAcountZoneDelegate: CloudKitZoneDelegate { - private typealias UnclaimedWebFeed = (url: URL, editedName: String?, webFeedExternalID: String) + private typealias UnclaimedWebFeed = (url: URL, name: String?, editedName: String?, webFeedExternalID: String) private var unclaimedWebFeeds = [String: [UnclaimedWebFeed]]() private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "CloudKit") @@ -42,65 +42,41 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate { } } - let group = DispatchGroup() - for changedRecord in changed { switch changedRecord.recordType { case CloudKitAccountZone.CloudKitWebFeed.recordType: - group.enter() - addOrUpdateWebFeed(changedRecord) { - group.leave() - } + addOrUpdateWebFeed(changedRecord) case CloudKitAccountZone.CloudKitContainer.recordType: - group.enter() - addOrUpdateContainer(changedRecord) { - group.leave() - } + addOrUpdateContainer(changedRecord) default: assertionFailure("Unknown record type: \(changedRecord.recordType)") } } - group.notify(queue: DispatchQueue.main) { - completion(.success(())) - } + completion(.success(())) } - func addOrUpdateWebFeed(_ record: CKRecord, completion: @escaping () -> Void) { + func addOrUpdateWebFeed(_ record: CKRecord) { guard let account = account, let urlString = record[CloudKitAccountZone.CloudKitWebFeed.Fields.url] as? String, let containerExternalIDs = record[CloudKitAccountZone.CloudKitWebFeed.Fields.containerExternalIDs] as? [String], let url = URL(string: urlString) else { - completion() return } + let name = record[CloudKitAccountZone.CloudKitWebFeed.Fields.name] as? String let editedName = record[CloudKitAccountZone.CloudKitWebFeed.Fields.editedName] as? String if let webFeed = account.existingWebFeed(withExternalID: record.externalID) { - - updateWebFeed(webFeed, editedName: editedName, containerExternalIDs: containerExternalIDs) - completion() - + updateWebFeed(webFeed, name: name, editedName: editedName, containerExternalIDs: containerExternalIDs) } else { - - let group = DispatchGroup() for containerExternalID in containerExternalIDs { - group.enter() if let container = account.existingContainer(withExternalID: containerExternalID) { - createWebFeedIfNecessary(url: url, editedName: editedName, webFeedExternalID: record.externalID, container: container) { webFeed in - group.leave() - } + createWebFeedIfNecessary(url: url, name: name, editedName: editedName, webFeedExternalID: record.externalID, container: container) } else { - addUnclaimedWebFeed(url: url, editedName: editedName, webFeedExternalID: record.externalID, containerExternalID: containerExternalID) - group.leave() + addUnclaimedWebFeed(url: url, name: name, editedName: editedName, webFeedExternalID: record.externalID, containerExternalID: containerExternalID) } } - - group.notify(queue: DispatchQueue.main) { - completion() - } - } } @@ -110,12 +86,11 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate { } } - func addOrUpdateContainer(_ record: CKRecord, completion: @escaping () -> Void) { + func addOrUpdateContainer(_ record: CKRecord) { guard let account = account, let name = record[CloudKitAccountZone.CloudKitContainer.Fields.name] as? String, let isAccount = record[CloudKitAccountZone.CloudKitContainer.Fields.isAccount] as? String, isAccount != "1" else { - completion() return } @@ -128,26 +103,17 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate { } if let folder = folder, let containerExternalID = folder.externalID, let unclaimedWebFeeds = unclaimedWebFeeds[containerExternalID] { - - let group = DispatchGroup() - for unclaimedWebFeed in unclaimedWebFeeds { - group.enter() - createWebFeedIfNecessary(url: unclaimedWebFeed.url, editedName: unclaimedWebFeed.editedName, webFeedExternalID: unclaimedWebFeed.webFeedExternalID, container: folder) { webFeed in - group.leave() - } + createWebFeedIfNecessary(url: unclaimedWebFeed.url, + name: unclaimedWebFeed.name, + editedName: unclaimedWebFeed.editedName, + webFeedExternalID: unclaimedWebFeed.webFeedExternalID, + container: folder) } - group.notify(queue: DispatchQueue.main) { - self.unclaimedWebFeeds.removeValue(forKey: containerExternalID) - completion() - } - - } else { - - completion() - + self.unclaimedWebFeeds.removeValue(forKey: containerExternalID) } + } func removeContainer(_ externalID: String) { @@ -160,8 +126,10 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate { private extension CloudKitAcountZoneDelegate { - func updateWebFeed(_ webFeed: WebFeed, editedName: String?, containerExternalIDs: [String]) { + func updateWebFeed(_ webFeed: WebFeed, name: String?, editedName: String?, containerExternalIDs: [String]) { guard let account = account else { return } + + webFeed.name = name webFeed.editedName = editedName let existingContainers = account.existingContainers(withWebFeed: webFeed) @@ -183,121 +151,26 @@ private extension CloudKitAcountZoneDelegate { } } - func createWebFeedIfNecessary(url: URL, editedName: String?, webFeedExternalID: String, container: Container, completion: @escaping (WebFeed) -> Void) { - guard let account = account, let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return } + func createWebFeedIfNecessary(url: URL, name: String?, editedName: String?, webFeedExternalID: String, container: Container) { + guard let account = account else { return } - if let webFeed = account.existingWebFeed(withExternalID: webFeedExternalID) { - completion(webFeed) + if account.existingWebFeed(withExternalID: webFeedExternalID) != nil { return } - let webFeed = account.createWebFeed(with: nil, url: url.absoluteString, webFeedID: url.absoluteString, homePageURL: nil) + let webFeed = account.createWebFeed(with: name, url: url.absoluteString, webFeedID: url.absoluteString, homePageURL: nil) webFeed.editedName = editedName webFeed.externalID = webFeedExternalID - - if let feedProvider = FeedProviderManager.shared.best(for: urlComponents) { - - refreshProgress?.addToNumberOfTasksAndRemaining(5) - feedProvider.assignName(urlComponents) { result in - self.refreshProgress?.completeTask() - switch result { - case .success(let name): - - webFeed.name = name - container.addWebFeed(webFeed) - - feedProvider.refresh(webFeed) { result in - self.refreshProgress?.completeTask() - switch result { - case .success(let parsedItems): - account.update(url.absoluteString, with: parsedItems) { result in - switch result { - case .success(let articleChanges): - - var newAndUpdatedArticles = articleChanges.newArticles ?? Set
() - newAndUpdatedArticles.formUnion(articleChanges.updatedArticles ?? Set
()) - let deletedArticles = articleChanges.deletedArticles ?? Set
() - newAndUpdatedArticles = newAndUpdatedArticles.subtracting(deletedArticles) - - self.articlesZone?.deleteArticles(deletedArticles) { _ in - self.refreshProgress?.completeTask() - self.articlesZone?.saveNewArticles(newAndUpdatedArticles) { _ in - self.refreshProgress?.completeTask() - self.articlesZone?.fetchChangesInZone() { _ in - self.refreshProgress?.completeTask() - completion(webFeed) - } - } - } - - case .failure: - completion(webFeed) - } - } - case .failure: - completion(webFeed) - } - } - - case .failure: - completion(webFeed) - } - } - - } else { - - refreshProgress?.addToNumberOfTasksAndRemaining(4) - - BatchUpdate.shared.start() - InitialFeedDownloader.download(url) { parsedFeed in - self.refreshProgress?.completeTask() - - if let parsedFeed = parsedFeed { - container.addWebFeed(webFeed) - - account.update(webFeed, with: parsedFeed, { result in - BatchUpdate.shared.end() - switch result { - case .success(let articleChanges): - - var newAndUpdatedArticles = articleChanges.newArticles ?? Set
() - newAndUpdatedArticles.formUnion(articleChanges.updatedArticles ?? Set
()) - let deletedArticles = articleChanges.deletedArticles ?? Set
() - newAndUpdatedArticles = newAndUpdatedArticles.subtracting(deletedArticles) - - self.articlesZone?.deleteArticles(deletedArticles) { _ in - self.refreshProgress?.completeTask() - self.articlesZone?.saveNewArticles(newAndUpdatedArticles) { _ in - self.refreshProgress?.completeTask() - self.articlesZone?.fetchChangesInZone() { _ in - self.refreshProgress?.completeTask() - completion(webFeed) - } - } - } - case .failure: - completion(webFeed) - } - }) - - } else { - BatchUpdate.shared.end() - completion(webFeed) - } - - } - - } - + container.addWebFeed(webFeed) } - func addUnclaimedWebFeed(url: URL, editedName: String?, webFeedExternalID: String, containerExternalID: String) { + func addUnclaimedWebFeed(url: URL, name: String?, editedName: String?, webFeedExternalID: String, containerExternalID: String) { if var unclaimedWebFeeds = self.unclaimedWebFeeds[containerExternalID] { - unclaimedWebFeeds.append(UnclaimedWebFeed(url: url, editedName: editedName, webFeedExternalID: webFeedExternalID)) + unclaimedWebFeeds.append(UnclaimedWebFeed(url: url, name: name, editedName: editedName, webFeedExternalID: webFeedExternalID)) self.unclaimedWebFeeds[containerExternalID] = unclaimedWebFeeds } else { var unclaimedWebFeeds = [UnclaimedWebFeed]() - unclaimedWebFeeds.append(UnclaimedWebFeed(url: url, editedName: editedName, webFeedExternalID: webFeedExternalID)) + unclaimedWebFeeds.append(UnclaimedWebFeed(url: url, name: name, editedName: editedName, webFeedExternalID: webFeedExternalID)) self.unclaimedWebFeeds[containerExternalID] = unclaimedWebFeeds } }