mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2025-02-03 12:27:32 +01:00
Update LocalAccountDelegate to use new FeedDownloader package. Temporarily comment-out feed refreshing in CloudKitAccountDelegate.
This commit is contained in:
parent
ea3a78b841
commit
33215ba9e3
@ -27,7 +27,8 @@ let package = Package(
|
|||||||
.package(path: "../LocalAccount"),
|
.package(path: "../LocalAccount"),
|
||||||
.package(path: "../FeedFinder"),
|
.package(path: "../FeedFinder"),
|
||||||
.package(path: "../Feedly"),
|
.package(path: "../Feedly"),
|
||||||
.package(path: "../CommonErrors")
|
.package(path: "../CommonErrors"),
|
||||||
|
.package(path: "../FeedDownloader")
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
@ -49,7 +50,8 @@ let package = Package(
|
|||||||
"LocalAccount",
|
"LocalAccount",
|
||||||
"FeedFinder",
|
"FeedFinder",
|
||||||
"CommonErrors",
|
"CommonErrors",
|
||||||
"Feedly"
|
"Feedly",
|
||||||
|
"FeedDownloader"
|
||||||
],
|
],
|
||||||
swiftSettings: [
|
swiftSettings: [
|
||||||
.enableExperimentalFeature("StrictConcurrency")
|
.enableExperimentalFeature("StrictConcurrency")
|
||||||
|
@ -180,6 +180,14 @@ public enum FetchType {
|
|||||||
return _externalIDToFeedDictionary
|
return _externalIDToFeedDictionary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var _feedURLToFeedDictionary = [String: Feed]()
|
||||||
|
var feedURLToFeedDictionary: [String: Feed] {
|
||||||
|
if feedDictionariesNeedUpdate {
|
||||||
|
rebuildFeedDictionaries()
|
||||||
|
}
|
||||||
|
return _feedURLToFeedDictionary
|
||||||
|
}
|
||||||
|
|
||||||
var flattenedFeedURLs: Set<String> {
|
var flattenedFeedURLs: Set<String> {
|
||||||
return Set(flattenedFeeds().map({ $0.url }))
|
return Set(flattenedFeeds().map({ $0.url }))
|
||||||
}
|
}
|
||||||
@ -1148,9 +1156,11 @@ private extension Account {
|
|||||||
func rebuildFeedDictionaries() {
|
func rebuildFeedDictionaries() {
|
||||||
var idDictionary = [String: Feed]()
|
var idDictionary = [String: Feed]()
|
||||||
var externalIDDictionary = [String: Feed]()
|
var externalIDDictionary = [String: Feed]()
|
||||||
|
var urlDictionary = [String: Feed]()
|
||||||
|
|
||||||
for feed in flattenedFeeds() {
|
for feed in flattenedFeeds() {
|
||||||
idDictionary[feed.feedID] = feed
|
idDictionary[feed.feedID] = feed
|
||||||
|
urlDictionary[feed.url] = feed
|
||||||
if let externalID = feed.externalID {
|
if let externalID = feed.externalID {
|
||||||
externalIDDictionary[externalID] = feed
|
externalIDDictionary[externalID] = feed
|
||||||
}
|
}
|
||||||
@ -1158,6 +1168,7 @@ private extension Account {
|
|||||||
|
|
||||||
_idToFeedDictionary = idDictionary
|
_idToFeedDictionary = idDictionary
|
||||||
_externalIDToFeedDictionary = externalIDDictionary
|
_externalIDToFeedDictionary = externalIDDictionary
|
||||||
|
_feedURLToFeedDictionary = urlDictionary
|
||||||
feedDictionariesNeedUpdate = false
|
feedDictionariesNeedUpdate = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1319,6 +1330,10 @@ extension Account {
|
|||||||
public func existingFeed(withExternalID externalID: String) -> Feed? {
|
public func existingFeed(withExternalID externalID: String) -> Feed? {
|
||||||
return externalIDToFeedDictionary[externalID]
|
return externalIDToFeedDictionary[externalID]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func existingFeed(urlString: String) -> Feed? {
|
||||||
|
return feedURLToFeedDictionary[urlString]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - OPMLRepresentable
|
// MARK: - OPMLRepresentable
|
||||||
|
@ -48,11 +48,11 @@ enum CloudKitAccountDelegateError: LocalizedError {
|
|||||||
|
|
||||||
private let mainThreadOperationQueue = MainThreadOperationQueue()
|
private let mainThreadOperationQueue = MainThreadOperationQueue()
|
||||||
|
|
||||||
private lazy var refresher: LocalAccountRefresher = {
|
// private lazy var refresher: LocalAccountRefresher = {
|
||||||
let refresher = LocalAccountRefresher()
|
// let refresher = LocalAccountRefresher()
|
||||||
refresher.delegate = self
|
// refresher.delegate = self
|
||||||
return refresher
|
// return refresher
|
||||||
}()
|
// }()
|
||||||
|
|
||||||
weak var account: Account?
|
weak var account: Account?
|
||||||
|
|
||||||
@ -459,7 +459,7 @@ enum CloudKitAccountDelegateError: LocalizedError {
|
|||||||
|
|
||||||
func suspendNetwork() {
|
func suspendNetwork() {
|
||||||
|
|
||||||
refresher.suspend()
|
// refresher.suspend()
|
||||||
}
|
}
|
||||||
|
|
||||||
func suspendDatabase() {
|
func suspendDatabase() {
|
||||||
@ -471,7 +471,7 @@ enum CloudKitAccountDelegateError: LocalizedError {
|
|||||||
|
|
||||||
func resume() {
|
func resume() {
|
||||||
|
|
||||||
refresher.resume()
|
// refresher.resume()
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
await database.resume()
|
await database.resume()
|
||||||
@ -536,7 +536,7 @@ private extension CloudKitAccountDelegate {
|
|||||||
|
|
||||||
func combinedRefresh(_ account: Account, _ feeds: Set<Feed>) async throws {
|
func combinedRefresh(_ account: Account, _ feeds: Set<Feed>) async throws {
|
||||||
|
|
||||||
await refresher.refreshFeeds(feeds)
|
// await refresher.refreshFeeds(feeds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRSSFeed(for account: Account, url: URL, editedName: String?, container: Container, validateFeed: Bool) async throws -> Feed {
|
func createRSSFeed(for account: Account, url: URL, editedName: String?, container: Container, validateFeed: Bool) async throws -> Feed {
|
||||||
@ -733,22 +733,22 @@ private extension CloudKitAccountDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CloudKitAccountDelegate: LocalAccountRefresherDelegate {
|
//extension CloudKitAccountDelegate: LocalAccountRefresherDelegate {
|
||||||
|
//
|
||||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: Feed) {
|
// func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: Feed) {
|
||||||
|
//
|
||||||
refreshProgress.completeTask()
|
// refreshProgress.completeTask()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, articleChanges: ArticleChanges, completion: @escaping () -> Void) {
|
// func localAccountRefresher(_ refresher: LocalAccountRefresher, articleChanges: ArticleChanges, completion: @escaping () -> Void) {
|
||||||
|
//
|
||||||
Task { @MainActor in
|
// Task { @MainActor in
|
||||||
await storeArticleChanges(new: articleChanges.newArticles,
|
// await storeArticleChanges(new: articleChanges.newArticles,
|
||||||
updated: articleChanges.updatedArticles,
|
// updated: articleChanges.updatedArticles,
|
||||||
deleted: articleChanges.deletedArticles)
|
// deleted: articleChanges.deletedArticles)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
extension CloudKitAccountDelegate: CloudKitFeedInfoDelegate {
|
extension CloudKitAccountDelegate: CloudKitFeedInfoDelegate {
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import Core
|
|||||||
import CommonErrors
|
import CommonErrors
|
||||||
import FeedFinder
|
import FeedFinder
|
||||||
import LocalAccount
|
import LocalAccount
|
||||||
|
import FeedDownloader
|
||||||
|
|
||||||
public enum LocalAccountDelegateError: String, Error {
|
public enum LocalAccountDelegateError: String, Error {
|
||||||
case invalidParameter = "An invalid parameter was used."
|
case invalidParameter = "An invalid parameter was used."
|
||||||
@ -25,16 +26,10 @@ public enum LocalAccountDelegateError: String, Error {
|
|||||||
|
|
||||||
final class LocalAccountDelegate: AccountDelegate {
|
final class LocalAccountDelegate: AccountDelegate {
|
||||||
|
|
||||||
private var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "LocalAccount")
|
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "LocalAccount")
|
||||||
|
|
||||||
weak var account: Account?
|
weak var account: Account?
|
||||||
|
|
||||||
private lazy var refresher: LocalAccountRefresher = {
|
|
||||||
let refresher = LocalAccountRefresher()
|
|
||||||
refresher.delegate = self
|
|
||||||
return refresher
|
|
||||||
}()
|
|
||||||
|
|
||||||
let behaviors: AccountBehaviors = []
|
let behaviors: AccountBehaviors = []
|
||||||
let isOPMLImportInProgress = false
|
let isOPMLImportInProgress = false
|
||||||
|
|
||||||
@ -42,8 +37,17 @@ final class LocalAccountDelegate: AccountDelegate {
|
|||||||
var credentials: Credentials?
|
var credentials: Credentials?
|
||||||
var accountMetadata: AccountMetadata?
|
var accountMetadata: AccountMetadata?
|
||||||
|
|
||||||
let refreshProgress = DownloadProgress(numberOfTasks: 0)
|
var refreshProgress: DownloadProgress {
|
||||||
|
feedDownloader.downloadProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
let feedDownloader: FeedDownloader
|
||||||
|
|
||||||
|
init() {
|
||||||
|
self.feedDownloader = FeedDownloader()
|
||||||
|
feedDownloader.delegate = self
|
||||||
|
}
|
||||||
|
|
||||||
func receiveRemoteNotification(for account: Account, userInfo: [AnyHashable : Any]) async {
|
func receiveRemoteNotification(for account: Account, userInfo: [AnyHashable : Any]) async {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,12 +58,10 @@ final class LocalAccountDelegate: AccountDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let feeds = account.flattenedFeeds()
|
let feeds = account.flattenedFeeds()
|
||||||
refreshProgress.addToNumberOfTasksAndRemaining(feeds.count)
|
let feedURLStrings = feeds.map { $0.url }
|
||||||
|
let feedURLs = Set(feedURLStrings.compactMap { URL(string: $0) })
|
||||||
|
|
||||||
await refresher.refreshFeeds(feeds)
|
feedDownloader.downloadFeeds(feedURLs)
|
||||||
|
|
||||||
self.refreshProgress.clear()
|
|
||||||
account.metadata.lastArticleFetchEndTime = Date()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncArticleStatus(for account: Account) async throws {
|
func syncArticleStatus(for account: Account) async throws {
|
||||||
@ -164,7 +166,9 @@ final class LocalAccountDelegate: AccountDelegate {
|
|||||||
// MARK: Suspend and Resume (for iOS)
|
// MARK: Suspend and Resume (for iOS)
|
||||||
|
|
||||||
func suspendNetwork() {
|
func suspendNetwork() {
|
||||||
refresher.suspend()
|
Task { @MainActor in
|
||||||
|
await feedDownloader.suspend()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func suspendDatabase() {
|
func suspendDatabase() {
|
||||||
@ -172,23 +176,10 @@ final class LocalAccountDelegate: AccountDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func resume() {
|
func resume() {
|
||||||
refresher.resume()
|
feedDownloader.resume()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension LocalAccountDelegate: LocalAccountRefresherDelegate {
|
|
||||||
|
|
||||||
|
|
||||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, requestCompletedFor: Feed) {
|
|
||||||
refreshProgress.completeTask()
|
|
||||||
}
|
|
||||||
|
|
||||||
func localAccountRefresher(_ refresher: LocalAccountRefresher, articleChanges: ArticleChanges, completion: @escaping () -> Void) {
|
|
||||||
completion()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension LocalAccountDelegate {
|
private extension LocalAccountDelegate {
|
||||||
|
|
||||||
func createRSSFeed(for account: Account, url: URL, editedName: String?, container: Container) async throws -> Feed {
|
func createRSSFeed(for account: Account, url: URL, editedName: String?, container: Container) async throws -> Feed {
|
||||||
@ -197,9 +188,7 @@ private extension LocalAccountDelegate {
|
|||||||
// container before the name has been downloaded. This will put it in the sidebar
|
// container before the name has been downloaded. This will put it in the sidebar
|
||||||
// with an Untitled name if we don't delay it being added to the sidebar.
|
// with an Untitled name if we don't delay it being added to the sidebar.
|
||||||
BatchUpdate.shared.start()
|
BatchUpdate.shared.start()
|
||||||
refreshProgress.addToNumberOfTasksAndRemaining(1)
|
|
||||||
defer {
|
defer {
|
||||||
refreshProgress.completeTask()
|
|
||||||
BatchUpdate.shared.end()
|
BatchUpdate.shared.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,3 +216,68 @@ private extension LocalAccountDelegate {
|
|||||||
return feed
|
return feed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension LocalAccountDelegate: FeedDownloaderDelegate {
|
||||||
|
|
||||||
|
func feedDownloader(_: FeedDownloader, requestCompletedForFeedURL feedURL: URL, response: URLResponse?, data: Data?, error: Error?) {
|
||||||
|
|
||||||
|
guard let account, let feed = account.existingFeed(urlString: feedURL.absoluteString) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let error {
|
||||||
|
logger.debug("Error downloading \(feed.url) - \(error)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let response, let data, !data.isEmpty else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parseAndUpdateFeed(feed, response: response, data: data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func feedDownloader(_: FeedDownloader, requestCanceledForFeedURL feedURL: URL, response: URLResponse?, data: Data?, error: Error?, reason: FeedDownloader.CancellationReason) {
|
||||||
|
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
func feedDownloaderSessionDidComplete(_: FeedDownloader) {
|
||||||
|
|
||||||
|
account?.metadata.lastArticleFetchEndTime = Date()
|
||||||
|
}
|
||||||
|
|
||||||
|
func feedDownloader(_: FeedDownloader, conditionalGetInfoFor feedURL: URL) -> HTTPConditionalGetInfo? {
|
||||||
|
|
||||||
|
guard let feed = account?.existingFeed(urlString: feedURL.absoluteString) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return feed.conditionalGetInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension LocalAccountDelegate {
|
||||||
|
|
||||||
|
func parseAndUpdateFeed(_ feed: Feed, response: URLResponse, data: Data) {
|
||||||
|
|
||||||
|
Task { @MainActor in
|
||||||
|
|
||||||
|
let dataHash = data.md5String
|
||||||
|
if dataHash == feed.contentHash {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let parserData = ParserData(url: feed.url, data: data)
|
||||||
|
|
||||||
|
guard let parsedFeed = try? await FeedParser.parse(parserData) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try await self.account?.update(feed: feed, with: parsedFeed)
|
||||||
|
|
||||||
|
if let httpResponse = response as? HTTPURLResponse {
|
||||||
|
feed.conditionalGetInfo = HTTPConditionalGetInfo(urlResponse: httpResponse)
|
||||||
|
}
|
||||||
|
feed.contentHash = dataHash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user