diff --git a/Frameworks/Account/ReaderAPI/ReaderAPIAccountDelegate.swift b/Frameworks/Account/ReaderAPI/ReaderAPIAccountDelegate.swift index fdbfb6f74..73d7cd499 100644 --- a/Frameworks/Account/ReaderAPI/ReaderAPIAccountDelegate.swift +++ b/Frameworks/Account/ReaderAPI/ReaderAPIAccountDelegate.swift @@ -454,8 +454,8 @@ private extension ReaderAPIAccountDelegate { } func syncFolders(_ account: Account, _ tags: [ReaderAPITag]?) { - guard let tags = tags else { return } + assert(Thread.isMainThread) os_log(.debug, log: log, "Syncing folders with %ld tags.", tags.count) @@ -465,13 +465,11 @@ private extension ReaderAPIAccountDelegate { if let folders = account.folders { folders.forEach { folder in if !tagNames.contains(folder.name ?? "") { - DispatchQueue.main.sync { - for feed in folder.topLevelFeeds { - account.addFeed(feed) - clearFolderRelationship(for: feed, withFolderName: folder.name ?? "") - } - account.removeFolder(folder) + for feed in folder.topLevelFeeds { + account.addFeed(feed) + clearFolderRelationship(for: feed, withFolderName: folder.name ?? "") } + account.removeFolder(folder) } } } @@ -487,9 +485,7 @@ private extension ReaderAPIAccountDelegate { // Make any folders Reader has, but we don't tagNames.forEach { tagName in if !folderNames.contains(tagName) { - DispatchQueue.main.sync { - _ = account.ensureFolder(with: tagName) - } + _ = account.ensureFolder(with: tagName) } } @@ -523,7 +519,8 @@ private extension ReaderAPIAccountDelegate { func syncFeeds(_ account: Account, _ subscriptions: [ReaderAPISubscription]?) { guard let subscriptions = subscriptions else { return } - + assert(Thread.isMainThread) + os_log(.debug, log: log, "Syncing feeds with %ld subscriptions.", subscriptions.count) let subFeedIds = subscriptions.map { String($0.feedID) } @@ -533,9 +530,7 @@ private extension ReaderAPIAccountDelegate { for folder in folders { for feed in folder.topLevelFeeds { if !subFeedIds.contains(feed.feedID) { - DispatchQueue.main.sync { - folder.removeFeed(feed) - } + folder.removeFeed(feed) } } } @@ -543,9 +538,7 @@ private extension ReaderAPIAccountDelegate { for feed in account.topLevelFeeds { if !subFeedIds.contains(feed.feedID) { - DispatchQueue.main.sync { - account.removeFeed(feed) - } + account.removeFeed(feed) } } @@ -553,17 +546,14 @@ private extension ReaderAPIAccountDelegate { subscriptions.forEach { subscription in let subFeedId = String(subscription.feedID) - - DispatchQueue.main.sync { - if let feed = account.idToFeedDictionary[subFeedId] { - feed.name = subscription.name - feed.homePageURL = subscription.homePageURL - } else { - let feed = account.createFeed(with: subscription.name, url: subscription.url, feedID: subFeedId, homePageURL: subscription.homePageURL) - feed.iconURL = subscription.iconURL - feed.subscriptionID = String(subscription.feedID) - account.addFeed(feed) - } + if let feed = account.idToFeedDictionary[subFeedId] { + feed.name = subscription.name + feed.homePageURL = subscription.homePageURL + } else { + let feed = account.createFeed(with: subscription.name, url: subscription.url, feedID: subFeedId, homePageURL: subscription.homePageURL) + feed.iconURL = subscription.iconURL + feed.subscriptionID = String(subscription.feedID) + account.addFeed(feed) } } @@ -573,6 +563,7 @@ private extension ReaderAPIAccountDelegate { func syncTaggings(_ account: Account, _ subscriptions: [ReaderAPISubscription]?) { guard let subscriptions = subscriptions else { return } + assert(Thread.isMainThread) os_log(.debug, log: log, "Syncing taggings with %ld subscriptions.", subscriptions.count) @@ -613,11 +604,9 @@ private extension ReaderAPIAccountDelegate { // Move any feeds not in the folder to the account for feed in folder.topLevelFeeds { if !taggingFeedIDs.contains(feed.feedID) { - DispatchQueue.main.sync { - folder.removeFeed(feed) - clearFolderRelationship(for: feed, withFolderName: folder.name ?? "") - account.addFeed(feed) - } + folder.removeFeed(feed) + clearFolderRelationship(for: feed, withFolderName: folder.name ?? "") + account.addFeed(feed) } } @@ -631,10 +620,8 @@ private extension ReaderAPIAccountDelegate { guard let feed = idDictionary[taggingFeedID] else { continue } - DispatchQueue.main.sync { - saveFolderRelationship(for: feed, withFolderName: folderName, id: String(subscription.feedID)) - folder.addFeed(feed) - } + saveFolderRelationship(for: feed, withFolderName: folderName, id: String(subscription.feedID)) + folder.addFeed(feed) } } @@ -643,11 +630,9 @@ private extension ReaderAPIAccountDelegate { let taggedFeedIDs = Set(subscriptions.map { String($0.feedID) }) // Remove all feeds from the account container that have a tag - DispatchQueue.main.sync { - for feed in account.topLevelFeeds { - if taggedFeedIDs.contains(feed.feedID) { - account.removeFeed(feed) - } + for feed in account.topLevelFeeds { + if taggedFeedIDs.contains(feed.feedID) { + account.removeFeed(feed) } } diff --git a/Frameworks/Account/ReaderAPI/ReaderAPICaller.swift b/Frameworks/Account/ReaderAPI/ReaderAPICaller.swift index b2491a0a0..6d92e84f7 100644 --- a/Frameworks/Account/ReaderAPI/ReaderAPICaller.swift +++ b/Frameworks/Account/ReaderAPI/ReaderAPICaller.swift @@ -321,79 +321,102 @@ final class ReaderAPICaller: NSObject { return } - self.requestAuthorizationToken(endpoint: baseURL) { (result) in + guard let url = URL(string: url) else { + completion(.failure(LocalAccountDelegateError.invalidParameter)) + return + } + + FeedFinder.find(url: url) { result in + switch result { - case .success(let token): - guard var components = URLComponents(url: baseURL.appendingPathComponent(ReaderAPIEndpoints.subscriptionAdd.rawValue), resolvingAgainstBaseURL: false) else { - completion(.failure(TransportError.noURL)) - return + case .success(let feedSpecifiers): + guard let bestFeedSpecifier = FeedSpecifier.bestFeed(in: feedSpecifiers), + let url = URL(string: bestFeedSpecifier.urlString) else { + completion(.failure(AccountError.createErrorNotFound)) + return } - - components.queryItems = [ - URLQueryItem(name: "quickadd", value: url) - ] - - guard let callURL = components.url else { - completion(.failure(TransportError.noURL)) - return - } - - var request = URLRequest(url: callURL, credentials: self.credentials) - request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") - request.httpMethod = "POST" - - let postData = "T=\(token)".data(using: String.Encoding.utf8) - - self.transport.send(request: request, method: HTTPMethod.post, data: postData!, resultType: ReaderAPIQuickAddResult.self, completion: { (result) in + self.requestAuthorizationToken(endpoint: baseURL) { (result) in switch result { - case .success(let (_, subResult)): - - switch subResult?.numResults { - case 0: - completion(.success(.alreadySubscribed)) - default: - // We have a feed ID but need to get feed information - guard let streamId = subResult?.streamId else { - completion(.failure(AccountError.createErrorNotFound)) - return - } - - // There is no call to get a single subscription entry, so we get them all, - // look up the one we just subscribed to and return that - self.retrieveSubscriptions(completion: { (result) in - switch result { - case .success(let subscriptions): - guard let subscriptions = subscriptions else { + case .success(let token): + guard var components = URLComponents(url: baseURL.appendingPathComponent(ReaderAPIEndpoints.subscriptionAdd.rawValue), resolvingAgainstBaseURL: false) else { + completion(.failure(TransportError.noURL)) + return + } + + components.queryItems = [ + URLQueryItem(name: "quickadd", value: url.absoluteString) + ] + + guard let callURL = components.url else { + completion(.failure(TransportError.noURL)) + return + } + + var request = URLRequest(url: callURL, credentials: self.credentials) + request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") + request.httpMethod = "POST" + + let postData = "T=\(token)".data(using: String.Encoding.utf8) + + self.transport.send(request: request, method: HTTPMethod.post, data: postData!, resultType: ReaderAPIQuickAddResult.self, completion: { (result) in + switch result { + case .success(let (_, subResult)): + + switch subResult?.numResults { + case 0: + completion(.success(.alreadySubscribed)) + default: + // We have a feed ID but need to get feed information + guard let streamId = subResult?.streamId else { completion(.failure(AccountError.createErrorNotFound)) return } - - let newStreamId = "feed/\(streamId)" - - guard let subscription = subscriptions.first(where: { (sub) -> Bool in - sub.feedID == newStreamId - }) else { - completion(.failure(AccountError.createErrorNotFound)) - return + + // There is no call to get a single subscription entry, so we get them all, + // look up the one we just subscribed to and return that + self.retrieveSubscriptions(completion: { (result) in + switch result { + case .success(let subscriptions): + guard let subscriptions = subscriptions else { + completion(.failure(AccountError.createErrorNotFound)) + return + } + + let newStreamId = "feed/\(streamId)" + + guard let subscription = subscriptions.first(where: { (sub) -> Bool in + sub.feedID == newStreamId + }) else { + completion(.failure(AccountError.createErrorNotFound)) + return + } + + completion(.success(.created(subscription))) + + case .failure(let error): + completion(.failure(error)) + } + }) } - - completion(.success(.created(subscription))) - - case .failure(let error): - completion(.failure(error)) - } - }) + case .failure(let error): + completion(.failure(error)) } + }) + + case .failure(let error): completion(.failure(error)) } - }) + } - case .failure(let error): - completion(.failure(error)) + + case .failure: + completion(.failure(AccountError.createErrorNotFound)) } + } +// } func renameSubscription(subscriptionID: String, newName: String, completion: @escaping (Result) -> Void) {