From e36edf47d4ad6706a53fa2bf61d5c90207276472 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 14 Jan 2021 01:40:52 -0500 Subject: [PATCH 1/3] only retrieve the feed IDs WIP fix for #2545 --- .../FeedWrangler/FeedWranglerAPICaller.swift | 136 +++++++++++++----- .../FeedWranglerAccountDelegate.swift | 8 +- .../FeedWrangler/FeedWranglerConfig.swift | 1 + .../FeedWrangler/FeedWranglerFeedItemId.swift | 19 +++ .../FeedWranglerFeedItemIdsRequest.swift | 25 ++++ 5 files changed, 152 insertions(+), 37 deletions(-) create mode 100644 Account/Sources/Account/FeedWrangler/FeedWranglerFeedItemId.swift create mode 100644 Account/Sources/Account/FeedWrangler/FeedWranglerFeedItemIdsRequest.swift diff --git a/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift b/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift index 0a947ccac..c1fdd100d 100644 --- a/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift +++ b/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift @@ -190,40 +190,75 @@ final class FeedWranglerAPICaller: NSObject { } } - func retrieveUnreadFeedItems(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItem], Error>) -> Void) { - let url = FeedWranglerConfig.clientURL - .appendingPathComponent("feed_items/list") - .appendingQueryItems([ - URLQueryItem(name: "read", value: "false"), - URLQueryItem(name: "offset", value: String(page * FeedWranglerConfig.pageSize)), - ]) - - standardSend(url: url, resultType: FeedWranglerFeedItemsRequest.self) { result in - switch result { - case .success(let (_, results)): - completion(.success(results?.feedItems ?? [])) + func retrieveUnreadFeedItems(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItem], Error>) -> Void) { + let url = FeedWranglerConfig.clientURL + .appendingPathComponent("feed_items/list") + .appendingQueryItems([ + URLQueryItem(name: "read", value: "false"), + URLQueryItem(name: "offset", value: String(page * FeedWranglerConfig.pageSize)), + ]) + + standardSend(url: url, resultType: FeedWranglerFeedItemsRequest.self) { result in + switch result { + case .success(let (_, results)): + completion(.success(results?.feedItems ?? [])) - case .failure(let error): - completion(.failure(error)) - } - } - } - - func retrieveAllUnreadFeedItems(foundItems: [FeedWranglerFeedItem] = [], page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItem], Error>) -> Void) { - retrieveUnreadFeedItems(page: page) { result in - switch result { - case .success(let newItems): - if newItems.count > 0 { - self.retrieveAllUnreadFeedItems(foundItems: foundItems + newItems, page: (page + 1), completion: completion) - } else { - completion(.success(foundItems + newItems)) - } - - case .failure(let error): - completion(.failure(error)) - } - } - } + case .failure(let error): + completion(.failure(error)) + } + } + } + + func retrieveAllUnreadFeedItems(foundItems: [FeedWranglerFeedItem] = [], page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItem], Error>) -> Void) { + retrieveUnreadFeedItems(page: page) { result in + switch result { + case .success(let newItems): + if newItems.count > 0 { + self.retrieveAllUnreadFeedItems(foundItems: foundItems + newItems, page: (page + 1), completion: completion) + } else { + completion(.success(foundItems + newItems)) + } + + case .failure(let error): + completion(.failure(error)) + } + } + } + + func retrieveUnreadFeedItemIds(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { + let url = FeedWranglerConfig.clientURL + .appendingPathComponent("feed_items/list_ids") + .appendingQueryItems([ + URLQueryItem(name: "read", value: "false"), + URLQueryItem(name: "offset", value: String(page * FeedWranglerConfig.idsPageSize)), + ]) + + standardSend(url: url, resultType: FeedWranglerFeedItemIdsRequest.self) { result in + switch result { + case .success(let (_, results)): + completion(.success(results?.feedItems ?? [])) + + case .failure(let error): + completion(.failure(error)) + } + } + } + + func retrieveAllUnreadFeedItemIds(foundItems: [FeedWranglerFeedItemId] = [], page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { + retrieveUnreadFeedItemIds(page: page) { result in + switch result { + case .success(let newItems): + if newItems.count > 0 { + self.retrieveAllUnreadFeedItemIds(foundItems: foundItems + newItems, page: (page + 1), completion: completion) + } else { + completion(.success(foundItems + newItems)) + } + + case .failure(let error): + completion(.failure(error)) + } + } + } func retrieveStarredFeedItems(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItem], Error>) -> Void) { let url = FeedWranglerConfig.clientURL @@ -259,6 +294,41 @@ final class FeedWranglerAPICaller: NSObject { } } } + + func retrieveStarredFeedItemIds(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { + let url = FeedWranglerConfig.clientURL + .appendingPathComponent("feed_items/list_ids") + .appendingQueryItems([ + URLQueryItem(name: "starred", value: "true"), + URLQueryItem(name: "offset", value: String(page * FeedWranglerConfig.idsPageSize)), + ]) + + standardSend(url: url, resultType: FeedWranglerFeedItemIdsRequest.self) { result in + switch result { + case .success(let (_, results)): + completion(.success(results?.feedItems ?? [])) + + case .failure(let error): + completion(.failure(error)) + } + } + } + + func retrieveAllStarredFeedItemIds(foundItems: [FeedWranglerFeedItemId] = [], page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { + retrieveStarredFeedItemIds(page: page) { result in + switch result { + case .success(let newItems): + if newItems.count > 0 { + self.retrieveAllStarredFeedItemIds(foundItems: foundItems + newItems, page: (page + 1), completion: completion) + } else { + completion(.success(foundItems + newItems)) + } + + case .failure(let error): + completion(.failure(error)) + } + } + } func updateArticleStatus(_ articleID: String, _ statuses: [SyncStatus], completion: @escaping () -> Void) { diff --git a/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift b/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift index 8ab0614db..a0afd2b42 100644 --- a/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift +++ b/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift @@ -249,7 +249,7 @@ final class FeedWranglerAccountDelegate: AccountDelegate { let group = DispatchGroup() group.enter() - caller.retrieveAllUnreadFeedItems { result in + caller.retrieveAllUnreadFeedItemIds { result in switch result { case .success(let items): self.syncArticleReadState(account, items) @@ -263,7 +263,7 @@ final class FeedWranglerAccountDelegate: AccountDelegate { // starred group.enter() - caller.retrieveAllStarredFeedItems { result in + caller.retrieveAllStarredFeedItemIds { result in switch result { case .success(let items): self.syncArticleStarredState(account, items) @@ -536,7 +536,7 @@ private extension FeedWranglerAccountDelegate { } } - func syncArticleReadState(_ account: Account, _ unreadFeedItems: [FeedWranglerFeedItem]) { + func syncArticleReadState(_ account: Account, _ unreadFeedItems: [FeedWranglerFeedItemId]) { let unreadServerItemIDs = Set(unreadFeedItems.map { String($0.feedItemID) }) account.fetchUnreadArticleIDs { articleIDsResult in guard let unreadLocalItemIDs = try? articleIDsResult.get() else { @@ -549,7 +549,7 @@ private extension FeedWranglerAccountDelegate { } } - func syncArticleStarredState(_ account: Account, _ starredFeedItems: [FeedWranglerFeedItem]) { + func syncArticleStarredState(_ account: Account, _ starredFeedItems: [FeedWranglerFeedItemId]) { let starredServerItemIDs = Set(starredFeedItems.map { String($0.feedItemID) }) account.fetchStarredArticleIDs { articleIDsResult in guard let starredLocalItemIDs = try? articleIDsResult.get() else { diff --git a/Account/Sources/Account/FeedWrangler/FeedWranglerConfig.swift b/Account/Sources/Account/FeedWrangler/FeedWranglerConfig.swift index 5d41fba17..eca64e64a 100644 --- a/Account/Sources/Account/FeedWrangler/FeedWranglerConfig.swift +++ b/Account/Sources/Account/FeedWrangler/FeedWranglerConfig.swift @@ -11,6 +11,7 @@ import Secrets enum FeedWranglerConfig { static let pageSize = 100 + static let idsPageSize = 1000 static let clientPath = "https://feedwrangler.net/api/v2/" static let clientURL = { URL(string: FeedWranglerConfig.clientPath)! diff --git a/Account/Sources/Account/FeedWrangler/FeedWranglerFeedItemId.swift b/Account/Sources/Account/FeedWrangler/FeedWranglerFeedItemId.swift new file mode 100644 index 000000000..856131b13 --- /dev/null +++ b/Account/Sources/Account/FeedWrangler/FeedWranglerFeedItemId.swift @@ -0,0 +1,19 @@ +// +// File.swift +// +// +// Created by Jonathan Bennett on 2021-01-14. +// + + +import Foundation + +struct FeedWranglerFeedItemId: Hashable, Codable { + + let feedItemID: Int + + enum CodingKeys: String, CodingKey { + case feedItemID = "feed_item_id" + } + +} diff --git a/Account/Sources/Account/FeedWrangler/FeedWranglerFeedItemIdsRequest.swift b/Account/Sources/Account/FeedWrangler/FeedWranglerFeedItemIdsRequest.swift new file mode 100644 index 000000000..dda666285 --- /dev/null +++ b/Account/Sources/Account/FeedWrangler/FeedWranglerFeedItemIdsRequest.swift @@ -0,0 +1,25 @@ +// +// FeedWranglerFeedItemsRequest.swift +// Account +// +// Created by Jonathan Bennett on 2021-01-14. +// Copyright © 2019 Ranchero Software, LLC. All rights reserved. +// + +import Foundation + +struct FeedWranglerFeedItemIdsRequest: Hashable, Codable { + + let count: Int + let feedItems: [FeedWranglerFeedItemId] + let error: String? + let result: String + + enum CodingKeys: String, CodingKey { + case count = "count" + case feedItems = "feed_items" + case error = "error" + case result = "result" + } + +} From 86541d4e3225de866d2fc5ae45508ad3a18ca787 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 14 Jan 2021 09:08:15 -0500 Subject: [PATCH 2/3] remove unused functions --- .../FeedWrangler/FeedWranglerAPICaller.swift | 70 ------------------- 1 file changed, 70 deletions(-) diff --git a/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift b/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift index c1fdd100d..73d4f7418 100644 --- a/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift +++ b/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift @@ -189,41 +189,6 @@ final class FeedWranglerAPICaller: NSObject { } } } - - func retrieveUnreadFeedItems(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItem], Error>) -> Void) { - let url = FeedWranglerConfig.clientURL - .appendingPathComponent("feed_items/list") - .appendingQueryItems([ - URLQueryItem(name: "read", value: "false"), - URLQueryItem(name: "offset", value: String(page * FeedWranglerConfig.pageSize)), - ]) - - standardSend(url: url, resultType: FeedWranglerFeedItemsRequest.self) { result in - switch result { - case .success(let (_, results)): - completion(.success(results?.feedItems ?? [])) - - case .failure(let error): - completion(.failure(error)) - } - } - } - - func retrieveAllUnreadFeedItems(foundItems: [FeedWranglerFeedItem] = [], page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItem], Error>) -> Void) { - retrieveUnreadFeedItems(page: page) { result in - switch result { - case .success(let newItems): - if newItems.count > 0 { - self.retrieveAllUnreadFeedItems(foundItems: foundItems + newItems, page: (page + 1), completion: completion) - } else { - completion(.success(foundItems + newItems)) - } - - case .failure(let error): - completion(.failure(error)) - } - } - } func retrieveUnreadFeedItemIds(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { let url = FeedWranglerConfig.clientURL @@ -259,41 +224,6 @@ final class FeedWranglerAPICaller: NSObject { } } } - - func retrieveStarredFeedItems(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItem], Error>) -> Void) { - let url = FeedWranglerConfig.clientURL - .appendingPathComponent("feed_items/list") - .appendingQueryItems([ - URLQueryItem(name: "starred", value: "true"), - URLQueryItem(name: "offset", value: String(page * FeedWranglerConfig.pageSize)), - ]) - - standardSend(url: url, resultType: FeedWranglerFeedItemsRequest.self) { result in - switch result { - case .success(let (_, results)): - completion(.success(results?.feedItems ?? [])) - - case .failure(let error): - completion(.failure(error)) - } - } - } - - func retrieveAllStarredFeedItems(foundItems: [FeedWranglerFeedItem] = [], page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItem], Error>) -> Void) { - retrieveStarredFeedItems(page: page) { result in - switch result { - case .success(let newItems): - if newItems.count > 0 { - self.retrieveAllStarredFeedItems(foundItems: foundItems + newItems, page: (page + 1), completion: completion) - } else { - completion(.success(foundItems + newItems)) - } - - case .failure(let error): - completion(.failure(error)) - } - } - } func retrieveStarredFeedItemIds(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { let url = FeedWranglerConfig.clientURL From a66759a065760fe6fa6559870d3c84001472771c Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Thu, 14 Jan 2021 10:36:11 -0500 Subject: [PATCH 3/3] DRY up feed id code only the filter really changes --- .../FeedWrangler/FeedWranglerAPICaller.swift | 52 ++++--------------- .../FeedWranglerAccountDelegate.swift | 4 +- 2 files changed, 13 insertions(+), 43 deletions(-) diff --git a/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift b/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift index 73d4f7418..06e880298 100644 --- a/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift +++ b/Account/Sources/Account/FeedWrangler/FeedWranglerAPICaller.swift @@ -189,32 +189,21 @@ final class FeedWranglerAPICaller: NSObject { } } } - - func retrieveUnreadFeedItemIds(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { - let url = FeedWranglerConfig.clientURL - .appendingPathComponent("feed_items/list_ids") - .appendingQueryItems([ - URLQueryItem(name: "read", value: "false"), - URLQueryItem(name: "offset", value: String(page * FeedWranglerConfig.idsPageSize)), - ]) - standardSend(url: url, resultType: FeedWranglerFeedItemIdsRequest.self) { result in - switch result { - case .success(let (_, results)): - completion(.success(results?.feedItems ?? [])) - - case .failure(let error): - completion(.failure(error)) - } - } + func retrieveUnreadFeedItemIds(completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { + retrieveAllFeedItemIds(filters: [URLQueryItem(name: "read", value: "false")], completion: completion) } - func retrieveAllUnreadFeedItemIds(foundItems: [FeedWranglerFeedItemId] = [], page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { - retrieveUnreadFeedItemIds(page: page) { result in + func retrieveStarredFeedItemIds(completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { + retrieveAllFeedItemIds(filters: [URLQueryItem(name: "starred", value: "true")], completion: completion) + } + + private func retrieveAllFeedItemIds(filters: [URLQueryItem] = [], foundItems: [FeedWranglerFeedItemId] = [], page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { + retrieveFeedItemIds(filters: filters, page: page) { result in switch result { case .success(let newItems): if newItems.count > 0 { - self.retrieveAllUnreadFeedItemIds(foundItems: foundItems + newItems, page: (page + 1), completion: completion) + self.retrieveAllFeedItemIds(filters: filters, foundItems: foundItems + newItems, page: (page + 1), completion: completion) } else { completion(.success(foundItems + newItems)) } @@ -225,13 +214,10 @@ final class FeedWranglerAPICaller: NSObject { } } - func retrieveStarredFeedItemIds(page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { + private func retrieveFeedItemIds(filters: [URLQueryItem] = [], page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { let url = FeedWranglerConfig.clientURL .appendingPathComponent("feed_items/list_ids") - .appendingQueryItems([ - URLQueryItem(name: "starred", value: "true"), - URLQueryItem(name: "offset", value: String(page * FeedWranglerConfig.idsPageSize)), - ]) + .appendingQueryItems(filters + [URLQueryItem(name: "offset", value: String(page * FeedWranglerConfig.idsPageSize))]) standardSend(url: url, resultType: FeedWranglerFeedItemIdsRequest.self) { result in switch result { @@ -243,22 +229,6 @@ final class FeedWranglerAPICaller: NSObject { } } } - - func retrieveAllStarredFeedItemIds(foundItems: [FeedWranglerFeedItemId] = [], page: Int = 0, completion: @escaping (Result<[FeedWranglerFeedItemId], Error>) -> Void) { - retrieveStarredFeedItemIds(page: page) { result in - switch result { - case .success(let newItems): - if newItems.count > 0 { - self.retrieveAllStarredFeedItemIds(foundItems: foundItems + newItems, page: (page + 1), completion: completion) - } else { - completion(.success(foundItems + newItems)) - } - - case .failure(let error): - completion(.failure(error)) - } - } - } func updateArticleStatus(_ articleID: String, _ statuses: [SyncStatus], completion: @escaping () -> Void) { diff --git a/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift b/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift index a0afd2b42..ecaafa2c1 100644 --- a/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift +++ b/Account/Sources/Account/FeedWrangler/FeedWranglerAccountDelegate.swift @@ -249,7 +249,7 @@ final class FeedWranglerAccountDelegate: AccountDelegate { let group = DispatchGroup() group.enter() - caller.retrieveAllUnreadFeedItemIds { result in + caller.retrieveUnreadFeedItemIds { result in switch result { case .success(let items): self.syncArticleReadState(account, items) @@ -263,7 +263,7 @@ final class FeedWranglerAccountDelegate: AccountDelegate { // starred group.enter() - caller.retrieveAllStarredFeedItemIds { result in + caller.retrieveStarredFeedItemIds { result in switch result { case .success(let items): self.syncArticleStarredState(account, items)