2017-05-23 13:24:42 -07:00
|
|
|
//
|
|
|
|
// LocalAccountRefresher.swift
|
2019-07-08 22:58:19 -07:00
|
|
|
// NetNewsWire
|
2017-05-23 13:24:42 -07:00
|
|
|
//
|
|
|
|
// Created by Brent Simmons on 9/6/16.
|
|
|
|
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import RSCore
|
2017-07-01 17:22:19 -07:00
|
|
|
import RSParser
|
2017-05-23 13:24:42 -07:00
|
|
|
import RSWeb
|
2018-07-23 18:29:08 -07:00
|
|
|
import Articles
|
2017-05-23 13:24:42 -07:00
|
|
|
|
2017-10-07 12:40:14 -07:00
|
|
|
final class LocalAccountRefresher {
|
2017-05-23 13:24:42 -07:00
|
|
|
|
2019-10-02 16:41:32 -05:00
|
|
|
private var completion: (() -> Void)?
|
2019-12-06 16:06:54 -07:00
|
|
|
private var isSuspended = false
|
2019-10-02 16:41:32 -05:00
|
|
|
|
2019-04-26 14:21:17 -05:00
|
|
|
private lazy var downloadSession: DownloadSession = {
|
|
|
|
return DownloadSession(delegate: self)
|
2017-05-23 13:24:42 -07:00
|
|
|
}()
|
|
|
|
|
2019-04-26 14:21:17 -05:00
|
|
|
var progress: DownloadProgress {
|
|
|
|
return downloadSession.progress
|
2017-05-23 13:24:42 -07:00
|
|
|
}
|
2019-04-26 14:21:17 -05:00
|
|
|
|
2019-11-14 20:11:41 -06:00
|
|
|
public func refreshFeeds(_ feeds: Set<WebFeed>, completion: @escaping () -> Void) {
|
2019-10-02 16:41:32 -05:00
|
|
|
self.completion = completion
|
2019-04-26 14:21:17 -05:00
|
|
|
downloadSession.downloadObjects(feeds as NSSet)
|
2017-05-23 13:24:42 -07:00
|
|
|
}
|
2019-11-04 20:41:08 -06:00
|
|
|
|
2019-12-06 16:06:54 -07:00
|
|
|
public func suspend() {
|
2019-11-04 20:41:08 -06:00
|
|
|
downloadSession.cancelAll()
|
2019-12-06 16:06:54 -07:00
|
|
|
isSuspended = true
|
|
|
|
}
|
|
|
|
|
|
|
|
public func resume() {
|
|
|
|
isSuspended = false
|
2019-11-04 20:41:08 -06:00
|
|
|
}
|
|
|
|
|
2017-10-07 12:40:14 -07:00
|
|
|
}
|
2017-05-23 13:24:42 -07:00
|
|
|
|
2017-10-07 12:40:14 -07:00
|
|
|
// MARK: - DownloadSessionDelegate
|
|
|
|
|
|
|
|
extension LocalAccountRefresher: DownloadSessionDelegate {
|
|
|
|
|
|
|
|
func downloadSession(_ downloadSession: DownloadSession, requestForRepresentedObject representedObject: AnyObject) -> URLRequest? {
|
2019-11-14 20:11:41 -06:00
|
|
|
guard let feed = representedObject as? WebFeed else {
|
2017-05-23 13:24:42 -07:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
guard let url = URL(string: feed.url) else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-01-27 22:58:59 -06:00
|
|
|
var request = URLRequest(url: url)
|
2017-09-26 21:43:40 -07:00
|
|
|
if let conditionalGetInfo = feed.conditionalGetInfo {
|
2020-01-27 22:58:59 -06:00
|
|
|
conditionalGetInfo.addRequestHeadersToURLRequest(&request)
|
2017-05-23 13:24:42 -07:00
|
|
|
}
|
|
|
|
|
2020-01-27 22:58:59 -06:00
|
|
|
return request
|
2017-05-23 13:24:42 -07:00
|
|
|
}
|
|
|
|
|
2019-12-07 16:26:38 -07:00
|
|
|
func downloadSession(_ downloadSession: DownloadSession, downloadDidCompleteForRepresentedObject representedObject: AnyObject, response: URLResponse?, data: Data, error: NSError?, completion: @escaping () -> Void) {
|
2019-12-06 16:06:54 -07:00
|
|
|
guard let feed = representedObject as? WebFeed, !data.isEmpty, !isSuspended else {
|
2019-12-08 10:00:20 -07:00
|
|
|
completion()
|
2017-05-23 13:24:42 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if let error = error {
|
|
|
|
print("Error downloading \(feed.url) - \(error)")
|
2019-12-08 10:00:20 -07:00
|
|
|
completion()
|
2017-05-23 13:24:42 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-01-18 01:00:56 -06:00
|
|
|
let dataHash = data.md5String
|
2017-05-23 13:24:42 -07:00
|
|
|
if dataHash == feed.contentHash {
|
2019-12-08 10:00:20 -07:00
|
|
|
completion()
|
2017-05-23 13:24:42 -07:00
|
|
|
return
|
|
|
|
}
|
2017-10-04 13:28:48 -07:00
|
|
|
|
2017-07-01 17:22:19 -07:00
|
|
|
let parserData = ParserData(url: feed.url, data: data)
|
|
|
|
FeedParser.parse(parserData) { (parsedFeed, error) in
|
2017-09-17 12:08:50 -07:00
|
|
|
guard let account = feed.account, let parsedFeed = parsedFeed, error == nil else {
|
2017-05-23 13:24:42 -07:00
|
|
|
return
|
|
|
|
}
|
2019-12-16 22:45:59 -08:00
|
|
|
account.update(feed, with: parsedFeed) { error in
|
|
|
|
if error == nil {
|
|
|
|
if let httpResponse = response as? HTTPURLResponse {
|
|
|
|
feed.conditionalGetInfo = HTTPConditionalGetInfo(urlResponse: httpResponse)
|
|
|
|
}
|
|
|
|
|
|
|
|
feed.contentHash = dataHash
|
2017-05-23 13:24:42 -07:00
|
|
|
}
|
2019-12-07 16:26:38 -07:00
|
|
|
completion()
|
2017-05-23 13:24:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-07 12:40:14 -07:00
|
|
|
func downloadSession(_ downloadSession: DownloadSession, shouldContinueAfterReceivingData data: Data, representedObject: AnyObject) -> Bool {
|
2019-12-06 16:06:54 -07:00
|
|
|
guard !isSuspended, let feed = representedObject as? WebFeed else {
|
2017-05-23 13:24:42 -07:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if data.isEmpty {
|
|
|
|
return true
|
|
|
|
}
|
2019-12-06 16:06:54 -07:00
|
|
|
|
2017-05-26 13:07:55 -07:00
|
|
|
if data.isDefinitelyNotFeed() {
|
2017-05-23 13:24:42 -07:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if data.count > 4096 {
|
2017-07-01 17:22:19 -07:00
|
|
|
let parserData = ParserData(url: feed.url, data: data)
|
2017-12-01 13:19:30 -08:00
|
|
|
return FeedParser.mightBeAbleToParseBasedOnPartialData(parserData)
|
2017-05-23 13:24:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2019-04-26 14:21:17 -05:00
|
|
|
func downloadSession(_ downloadSession: DownloadSession, didReceiveUnexpectedResponse response: URLResponse, representedObject: AnyObject) {
|
2019-04-25 07:13:14 -05:00
|
|
|
}
|
2019-04-26 14:21:17 -05:00
|
|
|
|
2019-04-25 07:13:14 -05:00
|
|
|
func downloadSession(_ downloadSession: DownloadSession, didReceiveNotModifiedResponse: URLResponse, representedObject: AnyObject) {
|
|
|
|
}
|
2019-10-02 16:41:32 -05:00
|
|
|
|
|
|
|
func downloadSessionDidCompleteDownloadObjects(_ downloadSession: DownloadSession) {
|
|
|
|
completion?()
|
|
|
|
completion = nil
|
|
|
|
}
|
|
|
|
|
2017-05-26 13:07:55 -07:00
|
|
|
}
|
2017-05-23 13:24:42 -07:00
|
|
|
|
2017-10-07 12:40:14 -07:00
|
|
|
// MARK: - Utility
|
|
|
|
|
2017-05-26 13:07:55 -07:00
|
|
|
private extension Data {
|
|
|
|
|
|
|
|
func isDefinitelyNotFeed() -> Bool {
|
|
|
|
// We only detect a few image types for now. This should get fleshed-out at some later date.
|
2020-01-18 01:00:56 -06:00
|
|
|
return self.isImage
|
2017-05-26 13:07:55 -07:00
|
|
|
}
|
2017-05-23 13:24:42 -07:00
|
|
|
}
|