Replaces final os_log entries with Logging

This commit is contained in:
Stuart Breckenridge
2022-09-19 09:22:54 +08:00
parent 932ca403cd
commit d419beb15e
27 changed files with 191 additions and 252 deletions

View File

@@ -7,22 +7,21 @@
//
import Foundation
import os.log
import RSCore
public extension Notification.Name {
static let AccountsDidFailToSyncWithErrors = Notification.Name("AccountsDidFailToSyncWithErrors")
}
public struct AccountSyncError {
public struct AccountSyncError: Logging {
private static let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Application")
public let account: Account
public let error: Error
init(account: Account, error: Error) {
self.account = account
self.error = error
os_log(.error, log: AccountSyncError.log, "%@", error.localizedDescription)
AccountSyncError.logger.error("Account Sync Error: \(error.localizedDescription)")
}
}

View File

@@ -11,10 +11,9 @@ import RSCore
import RSParser
import RSWeb
import SyncDatabase
import os.log
import Secrets
final class FeedlyAccountDelegate: AccountDelegate {
final class FeedlyAccountDelegate: AccountDelegate, Logging {
/// Feedly has a sandbox API and a production API.
/// This property is referred to when clients need to know which environment it should be pointing to.
@@ -61,7 +60,6 @@ final class FeedlyAccountDelegate: AccountDelegate {
internal let caller: FeedlyAPICaller
private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Feedly")
private let database: SyncDatabase
private weak var currentSyncAllOperation: MainThreadOperation?
@@ -112,20 +110,18 @@ final class FeedlyAccountDelegate: AccountDelegate {
assert(Thread.isMainThread)
guard currentSyncAllOperation == nil else {
os_log(.debug, log: log, "Ignoring refreshAll: Feedly sync already in progress.")
self.logger.debug("Ignoring refreshAll: Feedly sync already in progress.")
completion(.success(()))
return
}
guard let credentials = credentials else {
os_log(.debug, log: log, "Ignoring refreshAll: Feedly account has no credentials.")
self.logger.debug("Ignoring refreshAll: Feedly account has no credentials.")
completion(.failure(FeedlyAccountDelegateError.notLoggedIn))
return
}
let log = self.log
let syncAllOperation = FeedlySyncAllOperation(account: account, feedlyUserId: credentials.username, caller: caller, database: database, lastSuccessfulFetchStartDate: accountMetadata?.lastArticleFetchStartTime, downloadProgress: refreshProgress, log: log)
let syncAllOperation = FeedlySyncAllOperation(account: account, feedlyUserId: credentials.username, caller: caller, database: database, lastSuccessfulFetchStartDate: accountMetadata?.lastArticleFetchStartTime, downloadProgress: refreshProgress)
syncAllOperation.downloadProgress = refreshProgress
@@ -136,7 +132,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
self?.accountMetadata?.lastArticleFetchEndTime = Date()
}
os_log(.debug, log: log, "Sync took %{public}.3f seconds", -date.timeIntervalSinceNow)
self?.logger.debug("Sync took \(-date.timeIntervalSinceNow) seconds.")
completion(result)
}
@@ -154,10 +150,12 @@ final class FeedlyAccountDelegate: AccountDelegate {
case .success:
completion?(.success(()))
case .failure(let error):
self.logger.error("Failed to refresh article status for account \(String(describing: account.type)): \(error.localizedDescription)")
completion?(.failure(error))
}
}
case .failure(let error):
self.logger.error("Failed to send article status for account \(String(describing: account.type)): \(error.localizedDescription)")
completion?(.failure(error))
}
}
@@ -165,7 +163,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
func sendArticleStatus(for account: Account, completion: @escaping ((Result<Void, Error>) -> Void)) {
// Ensure remote articles have the same status as they do locally.
let send = FeedlySendArticleStatusesOperation(database: database, service: caller, log: log)
let send = FeedlySendArticleStatusesOperation(database: database, service: caller)
send.completionBlock = { operation in
// TODO: not call with success if operation was canceled? Not sure.
DispatchQueue.main.async {
@@ -188,7 +186,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
let group = DispatchGroup()
let ingestUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil, log: log)
let ingestUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil)
group.enter()
ingestUnread.completionBlock = { _ in
@@ -196,7 +194,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
}
let ingestStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil, log: log)
let ingestStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil)
group.enter()
ingestStarred.completionBlock = { _ in
@@ -220,21 +218,21 @@ final class FeedlyAccountDelegate: AccountDelegate {
return
}
os_log(.debug, log: log, "Begin importing OPML...")
logger.debug("Begin importing OPML...")
isOPMLImportInProgress = true
refreshProgress.addToNumberOfTasksAndRemaining(1)
caller.importOpml(data) { result in
switch result {
case .success:
os_log(.debug, log: self.log, "Import OPML done.")
self.logger.debug("Import OPML done.")
self.refreshProgress.completeTask()
self.isOPMLImportInProgress = false
DispatchQueue.main.async {
completion(.success(()))
}
case .failure(let error):
os_log(.debug, log: self.log, "Import OPML failed.")
self.logger.error("Import OPML failed: \(error.localizedDescription)")
self.refreshProgress.completeTask()
self.isOPMLImportInProgress = false
DispatchQueue.main.async {
@@ -331,8 +329,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
getStreamContentsService: caller,
database: database,
container: container,
progress: refreshProgress,
log: log)
progress: refreshProgress)
addNewFeed.addCompletionHandler = { result in
completion(result)
@@ -388,7 +385,6 @@ final class FeedlyAccountDelegate: AccountDelegate {
service: caller,
container: container,
progress: refreshProgress,
log: log,
customFeedName: feed.editedName)
@@ -494,7 +490,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
case .success:
break
case .failure(let error):
os_log(.error, log: self.log, "Restore folder feed error: %@.", error.localizedDescription)
self.logger.error("Restore folder feed error: \(error.localizedDescription)")
}
}
@@ -534,7 +530,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
}
func accountWillBeDeleted(_ account: Account) {
let logout = FeedlyLogoutOperation(account: account, service: caller, log: log)
let logout = FeedlyLogoutOperation(account: account, service: caller)
// Dispatch on the shared queue because the lifetime of the account delegate is uncertain.
MainThreadOperationQueue.shared.add(logout)
}
@@ -582,7 +578,7 @@ extension FeedlyAccountDelegate: FeedlyAPICallerDelegate {
}
}
let refreshAccessToken = FeedlyRefreshAccessTokenOperation(account: account, service: self, oauthClient: oauthAuthorizationClient, log: log)
let refreshAccessToken = FeedlyRefreshAccessTokenOperation(account: account, service: self, oauthClient: oauthAuthorizationClient)
refreshAccessToken.downloadProgress = refreshProgress
/// This must be strongly referenced by the completionBlock of the `FeedlyRefreshAccessTokenOperation`.

View File

@@ -7,17 +7,16 @@
//
import Foundation
import os.log
import RSWeb
import RSCore
import Secrets
class FeedlyAddExistingFeedOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyCheckpointOperationDelegate {
class FeedlyAddExistingFeedOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyCheckpointOperationDelegate, Logging {
private let operationQueue = MainThreadOperationQueue()
var addCompletionHandler: ((Result<Void, Error>) -> ())?
init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceId, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, log: OSLog, customFeedName: String? = nil) throws {
init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceId, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, customFeedName: String? = nil) throws {
let validator = FeedlyFeedContainerValidator(container: container)
let (folder, collectionId) = try validator.getValidContainer()
@@ -33,7 +32,7 @@ class FeedlyAddExistingFeedOperation: FeedlyOperation, FeedlyOperationDelegate,
addRequest.downloadProgress = progress
self.operationQueue.add(addRequest)
let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest, log: log)
let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest)
createFeeds.downloadProgress = progress
createFeeds.addDependency(addRequest)
self.operationQueue.add(createFeeds)

View File

@@ -7,13 +7,12 @@
//
import Foundation
import os.log
import SyncDatabase
import RSWeb
import RSCore
import Secrets
class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlySearchOperationDelegate, FeedlyCheckpointOperationDelegate {
class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlySearchOperationDelegate, FeedlyCheckpointOperationDelegate, Logging {
private let operationQueue = MainThreadOperationQueue()
private let folder: Folder
@@ -26,11 +25,10 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
private let addToCollectionService: FeedlyAddFeedToCollectionService
private let syncUnreadIdsService: FeedlyGetStreamIdsService
private let getStreamContentsService: FeedlyGetStreamContentsService
private let log: OSLog
private var feedResourceId: FeedlyFeedResourceId?
var addCompletionHandler: ((Result<WebFeed, Error>) -> ())?
init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIdsService: FeedlyGetStreamIdsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress, log: OSLog) throws {
init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIdsService: FeedlyGetStreamIdsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress) throws {
let validator = FeedlyFeedContainerValidator(container: container)
@@ -45,7 +43,6 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
self.addToCollectionService = addToCollectionService
self.syncUnreadIdsService = syncUnreadIdsService
self.getStreamContentsService = getStreamContentsService
self.log = log
super.init()
@@ -91,19 +88,19 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
addRequest.downloadProgress = downloadProgress
operationQueue.add(addRequest)
let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest, log: log)
let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest)
createFeeds.delegate = self
createFeeds.addDependency(addRequest)
createFeeds.downloadProgress = downloadProgress
operationQueue.add(createFeeds)
let syncUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: syncUnreadIdsService, database: database, newerThan: nil, log: log)
let syncUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: syncUnreadIdsService, database: database, newerThan: nil)
syncUnread.addDependency(createFeeds)
syncUnread.downloadProgress = downloadProgress
syncUnread.delegate = self
operationQueue.add(syncUnread)
let syncFeed = FeedlySyncStreamContentsOperation(account: account, resource: feedResourceId, service: getStreamContentsService, isPagingEnabled: false, newerThan: nil, log: log)
let syncFeed = FeedlySyncStreamContentsOperation(account: account, resource: feedResourceId, service: getStreamContentsService, isPagingEnabled: false, newerThan: nil)
syncFeed.addDependency(syncUnread)
syncFeed.downloadProgress = downloadProgress
syncFeed.delegate = self
@@ -121,7 +118,7 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
addCompletionHandler?(.failure(error))
addCompletionHandler = nil
os_log(.debug, log: log, "Unable to add new feed: %{public}@.", error as NSError)
logger.debug("Unale to add new feed: \(error.localizedDescription, privacy: .public)")
cancel()
}

View File

@@ -7,19 +7,17 @@
//
import Foundation
import os.log
import RSCore
/// Single responsibility is to accurately reflect Collections and their Feeds as Folders and their Feeds.
final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation {
final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation, Logging {
let account: Account
let feedsAndFoldersProvider: FeedlyFeedsAndFoldersProviding
let log: OSLog
init(account: Account, feedsAndFoldersProvider: FeedlyFeedsAndFoldersProviding, log: OSLog) {
init(account: Account, feedsAndFoldersProvider: FeedlyFeedsAndFoldersProviding) {
self.feedsAndFoldersProvider = feedsAndFoldersProvider
self.account = account
self.log = log
}
override func run() {
@@ -40,7 +38,6 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation {
let feedsToRemove = feedsInFolder.filter { !feedsInCollection.contains($0.webFeedID) }
if !feedsToRemove.isEmpty {
folder.removeFeeds(feedsToRemove)
// os_log(.debug, log: log, "\"%@\" - removed: %@", collection.label, feedsToRemove.map { $0.feedID }, feedsInCollection)
}
}
@@ -94,7 +91,7 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation {
return (feed, folder)
}
os_log(.debug, log: log, "Processing %i feeds.", feedsAndFolders.count)
logger.debug("Processing \(feedsAndFolders.count) feeds.")
feedsAndFolders.forEach { (feed, folder) in
if !folder.has(feed) {
folder.addWebFeed(feed)
@@ -107,7 +104,7 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation {
account.removeFeeds(feedsWithoutCollections)
if !feedsWithoutCollections.isEmpty {
os_log(.debug, log: log, "Removed %i feeds", feedsWithoutCollections.count)
logger.debug("Removed \(feedsWithoutCollections.count) feeds.")
}
}
}

View File

@@ -7,28 +7,25 @@
//
import Foundation
import os.log
import RSCore
import RSWeb
class FeedlyDownloadArticlesOperation: FeedlyOperation {
class FeedlyDownloadArticlesOperation: FeedlyOperation, Logging {
private let account: Account
private let log: OSLog
private let missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding
private let updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding
private let getEntriesService: FeedlyGetEntriesService
private let operationQueue = MainThreadOperationQueue()
private let finishOperation: FeedlyCheckpointOperation
init(account: Account, missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding, updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding, getEntriesService: FeedlyGetEntriesService, log: OSLog) {
init(account: Account, missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding, updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding, getEntriesService: FeedlyGetEntriesService) {
self.account = account
self.operationQueue.suspend()
self.missingArticleEntryIdProvider = missingArticleEntryIdProvider
self.updatedArticleEntryIdProvider = updatedArticleEntryIdProvider
self.getEntriesService = getEntriesService
self.finishOperation = FeedlyCheckpointOperation()
self.log = log
super.init()
self.finishOperation.checkpointDelegate = self
self.operationQueue.add(self.finishOperation)
@@ -38,26 +35,24 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation {
var articleIds = missingArticleEntryIdProvider.entryIds
articleIds.formUnion(updatedArticleEntryIdProvider.entryIds)
os_log(.debug, log: log, "Requesting %{public}i articles.", articleIds.count)
self.logger.debug("Requesting \(articleIds.count) articles.")
let feedlyAPILimitBatchSize = 1000
for articleIds in Array(articleIds).chunked(into: feedlyAPILimitBatchSize) {
let provider = FeedlyEntryIdentifierProvider(entryIds: Set(articleIds))
let getEntries = FeedlyGetEntriesOperation(account: account, service: getEntriesService, provider: provider, log: log)
let getEntries = FeedlyGetEntriesOperation(account: account, service: getEntriesService, provider: provider)
getEntries.delegate = self
self.operationQueue.add(getEntries)
let organiseByFeed = FeedlyOrganiseParsedItemsByFeedOperation(account: account,
parsedItemProvider: getEntries,
log: log)
parsedItemProvider: getEntries)
organiseByFeed.delegate = self
organiseByFeed.addDependency(getEntries)
self.operationQueue.add(organiseByFeed)
let updateAccount = FeedlyUpdateAccountFeedsWithItemsOperation(account: account,
organisedItemsProvider: organiseByFeed,
log: log)
organisedItemsProvider: organiseByFeed)
updateAccount.delegate = self
updateAccount.addDependency(organiseByFeed)
@@ -70,8 +65,7 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation {
}
override func didCancel() {
// TODO: fix error on below line: "Expression type '()' is ambiguous without more context"
//os_log(.debug, log: log, "Cancelling %{public}@.", self)
logger.debug("Cancelling \(String(describing: self)).")
operationQueue.cancelAllOperations()
super.didCancel()
}
@@ -90,7 +84,7 @@ extension FeedlyDownloadArticlesOperation: FeedlyOperationDelegate {
assert(Thread.isMainThread)
// Having this log is useful for debugging missing required JSON keys in the response from Feedly, for example.
os_log(.debug, log: log, "%{public}@ failed with error: %{public}@.", String(describing: operation), error as NSError)
self.logger.debug("\(String(describing: operation)) failed with error: \(error.localizedDescription)")
cancel()
}

View File

@@ -7,18 +7,16 @@
//
import Foundation
import os.log
import RSCore
final class FeedlyFetchIdsForMissingArticlesOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
final class FeedlyFetchIdsForMissingArticlesOperation: FeedlyOperation, FeedlyEntryIdentifierProviding, Logging {
private let account: Account
private let log: OSLog
private(set) var entryIds = Set<String>()
init(account: Account, log: OSLog) {
init(account: Account) {
self.account = account
self.log = log
}
override func run() {
@@ -29,6 +27,7 @@ final class FeedlyFetchIdsForMissingArticlesOperation: FeedlyOperation, FeedlyEn
self.didFinish()
case .failure(let error):
self.logger.error("Failed to fetch articleIDs: \(error.localizedDescription).")
self.didFinish(with: error)
}
}

View File

@@ -7,37 +7,35 @@
//
import Foundation
import os.log
import RSCore
protocol FeedlyCollectionProviding: AnyObject {
var collections: [FeedlyCollection] { get }
}
/// Get Collections from Feedly.
final class FeedlyGetCollectionsOperation: FeedlyOperation, FeedlyCollectionProviding {
final class FeedlyGetCollectionsOperation: FeedlyOperation, FeedlyCollectionProviding, Logging {
let service: FeedlyGetCollectionsService
let log: OSLog
private(set) var collections = [FeedlyCollection]()
init(service: FeedlyGetCollectionsService, log: OSLog) {
init(service: FeedlyGetCollectionsService) {
self.service = service
self.log = log
}
override func run() {
os_log(.debug, log: log, "Requesting collections.")
logger.debug("Requesting collections.")
service.getCollections { result in
switch result {
case .success(let collections):
os_log(.debug, log: self.log, "Received collections: %{public}@", collections.map { $0.id })
self.logger.debug("Receving collections: \(collections.map({ $0.id }))")
self.collections = collections
self.didFinish()
case .failure(let error):
os_log(.debug, log: self.log, "Unable to request collections: %{public}@.", error as NSError)
self.logger.error("Unable to request collections: \(error.localizedDescription).")
self.didFinish(with: error)
}
}

View File

@@ -7,22 +7,20 @@
//
import Foundation
import os.log
import RSCore
import RSParser
/// Get full entries for the entry identifiers.
final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding {
final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding, Logging {
let account: Account
let service: FeedlyGetEntriesService
let provider: FeedlyEntryIdentifierProviding
let log: OSLog
init(account: Account, service: FeedlyGetEntriesService, provider: FeedlyEntryIdentifierProviding, log: OSLog) {
init(account: Account, service: FeedlyGetEntriesService, provider: FeedlyEntryIdentifierProviding) {
self.account = account
self.service = service
self.provider = provider
self.log = log
}
private (set) var entries = [FeedlyEntry]()
@@ -38,13 +36,12 @@ final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, Fe
FeedlyEntryParser(entry: $0).parsedItemRepresentation
})
// TODO: Fix the below. Theres an error on the os.log line: "Expression type '()' is ambiguous without more context"
// if parsed.count != entries.count {
// let entryIds = Set(entries.map { $0.id })
// let parsedIds = Set(parsed.map { $0.uniqueID })
// let difference = entryIds.subtracting(parsedIds)
// os_log(.debug, log: log, "%{public}@ dropping articles with ids: %{public}@.", self, difference)
// }
if parsed.count != entries.count {
let entryIds = Set(entries.map { $0.id })
let parsedIds = Set(parsed.map { $0.uniqueID })
let difference = entryIds.subtracting(parsedIds)
self.logger.debug("\(String(describing: self)) dropping articles with ids: \(difference)).")
}
storedParsedEntries = parsed
@@ -63,7 +60,7 @@ final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, Fe
self.didFinish()
case .failure(let error):
os_log(.debug, log: self.log, "Unable to get entries: %{public}@.", error as NSError)
self.logger.error("Unable to get entries: \(error.localizedDescription)")
self.didFinish(with: error)
}
}

View File

@@ -8,7 +8,7 @@
import Foundation
import RSParser
import os.log
import RSCore
protocol FeedlyEntryProviding {
var entries: [FeedlyEntry] { get }
@@ -24,7 +24,7 @@ protocol FeedlyGetStreamContentsOperationDelegate: AnyObject {
}
/// Get the stream content of a Collection from Feedly.
final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding {
final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding, Logging {
struct ResourceProvider: FeedlyResourceProviding {
var resource: FeedlyResourceId
@@ -58,7 +58,7 @@ final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProvid
let entryIds = Set(entries.map { $0.id })
let parsedIds = Set(parsed.map { $0.uniqueID })
let difference = entryIds.subtracting(parsedIds)
os_log(.debug, log: log, "Dropping articles with ids: %{public}@.", difference)
logger.debug("Dropping articles with ids: \(difference)")
}
storedParsedEntries = parsed
@@ -79,22 +79,20 @@ final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProvid
let unreadOnly: Bool?
let newerThan: Date?
let continuation: String?
let log: OSLog
weak var streamDelegate: FeedlyGetStreamContentsOperationDelegate?
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool? = nil, log: OSLog) {
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool? = nil) {
self.account = account
self.resourceProvider = ResourceProvider(resource: resource)
self.service = service
self.continuation = continuation
self.unreadOnly = unreadOnly
self.newerThan = newerThan
self.log = log
}
convenience init(account: Account, resourceProvider: FeedlyResourceProviding, service: FeedlyGetStreamContentsService, newerThan: Date?, unreadOnly: Bool? = nil, log: OSLog) {
self.init(account: account, resource: resourceProvider.resource, service: service, newerThan: newerThan, unreadOnly: unreadOnly, log: log)
convenience init(account: Account, resourceProvider: FeedlyResourceProviding, service: FeedlyGetStreamContentsService, newerThan: Date?, unreadOnly: Bool? = nil) {
self.init(account: account, resource: resourceProvider.resource, service: service, newerThan: newerThan, unreadOnly: unreadOnly)
}
override func run() {
@@ -108,7 +106,7 @@ final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProvid
self.didFinish()
case .failure(let error):
os_log(.debug, log: self.log, "Unable to get stream contents: %{public}@.", error as NSError)
self.logger.error("Unable to get stream contents: \(error.localizedDescription)")
self.didFinish(with: error)
}
}

View File

@@ -7,14 +7,14 @@
//
import Foundation
import os.log
import RSCore
protocol FeedlyGetStreamIdsOperationDelegate: AnyObject {
func feedlyGetStreamIdsOperation(_ operation: FeedlyGetStreamIdsOperation, didGet streamIds: FeedlyStreamIds)
}
/// Single responsibility is to get the stream ids from Feedly.
final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding, Logging {
var entryIds: Set<String> {
guard let ids = streamIds?.ids else {
@@ -32,16 +32,14 @@ final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierP
let resource: FeedlyResourceId
let unreadOnly: Bool?
let newerThan: Date?
let log: OSLog
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, continuation: String? = nil, newerThan: Date? = nil, unreadOnly: Bool?, log: OSLog) {
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, continuation: String? = nil, newerThan: Date? = nil, unreadOnly: Bool?) {
self.account = account
self.resource = resource
self.service = service
self.continuation = continuation
self.newerThan = newerThan
self.unreadOnly = unreadOnly
self.log = log
}
weak var streamIdsDelegate: FeedlyGetStreamIdsOperationDelegate?
@@ -57,7 +55,7 @@ final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierP
self.didFinish()
case .failure(let error):
os_log(.debug, log: self.log, "Unable to get stream ids: %{public}@.", error as NSError)
self.logger.error("Unable to get stream ids: \(error.localizedDescription)")
self.didFinish(with: error)
}
}

View File

@@ -7,32 +7,30 @@
//
import Foundation
import os.log
import RSCore
import Secrets
/// Single responsibility is to identify articles that have changed since a particular date.
///
/// Typically, it pages through the article ids of the global.all stream.
/// When all the article ids are collected, it is the responsibility of another operation to download them when appropriate.
class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding, Logging {
private let account: Account
private let resource: FeedlyResourceId
private let service: FeedlyGetStreamIdsService
private let newerThan: Date?
private let log: OSLog
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, newerThan: Date?, log: OSLog) {
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, newerThan: Date?) {
self.account = account
self.resource = resource
self.service = service
self.newerThan = newerThan
self.log = log
}
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, newerThan: Date?, log: OSLog) {
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, newerThan: Date?) {
let all = FeedlyCategoryResourceId.Global.all(for: userId)
self.init(account: account, resource: all, service: service, newerThan: newerThan, log: log)
self.init(account: account, resource: all, service: service, newerThan: newerThan)
}
var entryIds: Set<String> {
@@ -47,7 +45,7 @@ class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifie
private func getStreamIds(_ continuation: String?) {
guard let date = newerThan else {
os_log(.debug, log: log, "No date provided so everything must be new (nothing is updated).")
logger.debug("No date provided so everything must be new (nothing is updated).")
didFinish()
return
}
@@ -66,7 +64,7 @@ class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifie
storedUpdatedArticleIds.formUnion(streamIds.ids)
guard let continuation = streamIds.continuation else {
os_log(.debug, log: log, "%{public}i articles updated since last successful sync start date.", storedUpdatedArticleIds.count)
self.logger.debug("\(self.storedUpdatedArticleIds.count) articles updated since last successful sync start date.")
didFinish()
return
}
@@ -74,6 +72,7 @@ class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifie
getStreamIds(continuation)
case .failure(let error):
self.logger.error("Error getting FeedlyStreamIds: \(error.localizedDescription).")
didFinish(with: error)
}
}

View File

@@ -7,7 +7,7 @@
//
import Foundation
import os.log
import RSCore
import SyncDatabase
import Secrets
@@ -17,26 +17,24 @@ import Secrets
/// When all the article ids are collected, a status is created for each.
/// The article ids previously marked as starred but not collected become unstarred.
/// So this operation has side effects *for the entire account* it operates on.
final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation, Logging {
private let account: Account
private let resource: FeedlyResourceId
private let service: FeedlyGetStreamIdsService
private let database: SyncDatabase
private var remoteEntryIds = Set<String>()
private let log: OSLog
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?) {
let resource = FeedlyTagResourceId.Global.saved(for: userId)
self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan, log: log)
self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan)
}
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?) {
self.account = account
self.resource = resource
self.service = service
self.database = database
self.log = log
}
override func run() {

View File

@@ -7,7 +7,7 @@
//
import Foundation
import os.log
import RSCore
import Secrets
/// Ensure a status exists for every article id the user might be interested in.
@@ -15,23 +15,21 @@ import Secrets
/// Typically, it pages through the article ids of the global.all stream.
/// As the article ids are collected, a default read status is created for each.
/// So this operation has side effects *for the entire account* it operates on.
class FeedlyIngestStreamArticleIdsOperation: FeedlyOperation {
class FeedlyIngestStreamArticleIdsOperation: FeedlyOperation, Logging {
private let account: Account
private let resource: FeedlyResourceId
private let service: FeedlyGetStreamIdsService
private let log: OSLog
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, log: OSLog) {
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService) {
self.account = account
self.resource = resource
self.service = service
self.log = log
}
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, log: OSLog) {
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService) {
let all = FeedlyCategoryResourceId.Global.all(for: userId)
self.init(account: account, resource: all, service: service, log: log)
self.init(account: account, resource: all, service: service)
}
override func run() {
@@ -58,7 +56,7 @@ class FeedlyIngestStreamArticleIdsOperation: FeedlyOperation {
}
guard let continuation = streamIds.continuation else {
os_log(.debug, log: self.log, "Reached end of stream for %@", self.resource.id)
self.logger.debug("Reached end of stream: \(self.resource.id).")
self.didFinish()
return
}

View File

@@ -7,7 +7,7 @@
//
import Foundation
import os.log
import RSCore
import RSParser
import SyncDatabase
import Secrets
@@ -18,26 +18,24 @@ import Secrets
/// When all the unread article ids are collected, a status is created for each.
/// The article ids previously marked as unread but not collected become read.
/// So this operation has side effects *for the entire account* it operates on.
final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation, Logging {
private let account: Account
private let resource: FeedlyResourceId
private let service: FeedlyGetStreamIdsService
private let database: SyncDatabase
private var remoteEntryIds = Set<String>()
private let log: OSLog
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?) {
let resource = FeedlyCategoryResourceId.Global.all(for: userId)
self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan, log: log)
self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan)
}
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?) {
self.account = account
self.resource = resource
self.service = service
self.database = database
self.log = log
}
override func run() {

View File

@@ -7,26 +7,24 @@
//
import Foundation
import os.log
import RSCore
protocol FeedlyLogoutService {
func logout(completion: @escaping (Result<Void, Error>) -> ())
}
final class FeedlyLogoutOperation: FeedlyOperation {
final class FeedlyLogoutOperation: FeedlyOperation, Logging {
let service: FeedlyLogoutService
let account: Account
let log: OSLog
init(account: Account, service: FeedlyLogoutService, log: OSLog) {
init(account: Account, service: FeedlyLogoutService) {
self.service = service
self.account = account
self.log = log
}
override func run() {
os_log("Requesting logout of %{public}@ account.", "\(account.type)")
self.logger.debug("Requesting logout of \(String(describing: self.account.type)).")
service.logout(completion: didCompleteLogout(_:))
}
@@ -34,7 +32,7 @@ final class FeedlyLogoutOperation: FeedlyOperation {
assert(Thread.isMainThread)
switch result {
case .success:
os_log("Logged out of %{public}@ account.", log: log, "\(account.type)")
self.logger.debug("Logged out of \(String(describing: self.account.type)).")
do {
try account.removeCredentials(type: .oauthAccessToken)
try account.removeCredentials(type: .oauthRefreshToken)
@@ -44,7 +42,7 @@ final class FeedlyLogoutOperation: FeedlyOperation {
didFinish()
case .failure(let error):
os_log("Logout failed because %{public}@.", log: log, error as NSError)
self.logger.error("Logout failed because: \(error.localizedDescription)")
didFinish(with: error)
}
}

View File

@@ -7,25 +7,23 @@
//
import Foundation
import os.log
import RSCore
protocol FeedlyFeedsAndFoldersProviding {
var feedsAndFolders: [([FeedlyFeed], Folder)] { get }
}
/// Reflect Collections from Feedly as Folders.
final class FeedlyMirrorCollectionsAsFoldersOperation: FeedlyOperation, FeedlyFeedsAndFoldersProviding {
final class FeedlyMirrorCollectionsAsFoldersOperation: FeedlyOperation, FeedlyFeedsAndFoldersProviding, Logging {
let account: Account
let collectionsProvider: FeedlyCollectionProviding
let log: OSLog
private(set) var feedsAndFolders = [([FeedlyFeed], Folder)]()
init(account: Account, collectionsProvider: FeedlyCollectionProviding, log: OSLog) {
init(account: Account, collectionsProvider: FeedlyCollectionProviding) {
self.collectionsProvider = collectionsProvider
self.account = account
self.log = log
}
override func run() {
@@ -46,8 +44,8 @@ final class FeedlyMirrorCollectionsAsFoldersOperation: FeedlyOperation, FeedlyFe
return (collection.feeds, folder)
}
os_log(.debug, log: log, "Ensured %i folders for %i collections.", feedsAndFolders.count, collections.count)
self.logger.debug("Ensured \(self.feedsAndFolders.count) folders for \(collections.count) collections.")
// Remove folders without a corresponding collection
let collectionFolders = Set(feedsAndFolders.map { $0.1 })
let foldersWithoutCollections = localFolders.subtracting(collectionFolders)
@@ -57,7 +55,7 @@ final class FeedlyMirrorCollectionsAsFoldersOperation: FeedlyOperation, FeedlyFe
account.removeFolder(unmatched)
}
os_log(.debug, log: log, "Removed %i folders: %@", foldersWithoutCollections.count, foldersWithoutCollections.map { $0.externalID ?? $0.nameForDisplay })
self.logger.debug("Removed \(foldersWithoutCollections.count) folders: \(foldersWithoutCollections.map({ $0.externalID ?? $0.nameForDisplay }))")
}
}
}

View File

@@ -8,7 +8,7 @@
import Foundation
import RSParser
import os.log
import RSCore
protocol FeedlyParsedItemsByFeedProviding {
var parsedItemsByFeedProviderName: String { get }
@@ -16,11 +16,10 @@ protocol FeedlyParsedItemsByFeedProviding {
}
/// Group articles by their feeds.
final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyParsedItemsByFeedProviding {
final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyParsedItemsByFeedProviding, Logging {
private let account: Account
private let parsedItemProvider: FeedlyParsedItemProviding
private let log: OSLog
var parsedItemsByFeedProviderName: String {
return name ?? String(describing: Self.self)
@@ -33,10 +32,9 @@ final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyPar
private var itemsKeyedByFeedId = [String: Set<ParsedItem>]()
init(account: Account, parsedItemProvider: FeedlyParsedItemProviding, log: OSLog) {
init(account: Account, parsedItemProvider: FeedlyParsedItemProviding) {
self.account = account
self.parsedItemProvider = parsedItemProvider
self.log = log
}
override func run() {
@@ -60,7 +58,7 @@ final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyPar
dict[key] = value
}
os_log(.debug, log: log, "Grouped %i items by %i feeds for %@", items.count, dict.count, parsedItemProvider.parsedItemProviderName)
self.logger.debug("Grouped \(items.count) items by \(dict.count) feeds for \(self.parsedItemProvider.parsedItemProviderName).")
itemsKeyedByFeedId = dict
}

View File

@@ -7,22 +7,20 @@
//
import Foundation
import os.log
import RSCore
import RSWeb
import Secrets
final class FeedlyRefreshAccessTokenOperation: FeedlyOperation {
final class FeedlyRefreshAccessTokenOperation: FeedlyOperation, Logging {
let service: OAuthAccessTokenRefreshing
let oauthClient: OAuthAuthorizationClient
let account: Account
let log: OSLog
init(account: Account, service: OAuthAccessTokenRefreshing, oauthClient: OAuthAuthorizationClient, log: OSLog) {
init(account: Account, service: OAuthAccessTokenRefreshing, oauthClient: OAuthAuthorizationClient) {
self.oauthClient = oauthClient
self.service = service
self.account = account
self.log = log
}
override func run() {
@@ -30,7 +28,7 @@ final class FeedlyRefreshAccessTokenOperation: FeedlyOperation {
do {
guard let credentials = try account.retrieveCredentials(type: .oauthRefreshToken) else {
os_log(.debug, log: log, "Could not find a refresh token in the keychain. Check the refresh token is added to the Keychain, remove the account and add it again.")
self.logger.debug("Could not find a refresh token in the keychain. Check the refresh token is added to the Keychain, remove the account and add it again.")
throw TransportError.httpError(status: 403)
}
@@ -41,7 +39,7 @@ final class FeedlyRefreshAccessTokenOperation: FeedlyOperation {
return
}
os_log(.debug, log: log, "Refreshing access token.")
self.logger.debug("Refreshing access token.")
// Ignore cancellation after the request is resumed otherwise we may continue storing a potentially invalid token!
service.refreshAccessToken(with: refreshToken.secret, client: oauthClient) { result in
@@ -55,13 +53,13 @@ final class FeedlyRefreshAccessTokenOperation: FeedlyOperation {
switch result {
case .success(let grant):
do {
os_log(.debug, log: log, "Storing refresh token.")
self.logger.debug("Storing refresh token.")
// Store the refresh token first because it sends this token to the account delegate.
if let token = grant.refreshToken {
try account.storeCredentials(token)
}
os_log(.debug, log: log, "Storing access token.")
self.logger.debug("Storing access token.")
// Now store the access token because we want the account delegate to use it.
try account.storeCredentials(grant.accessToken)

View File

@@ -7,7 +7,7 @@
//
import Foundation
import os.log
import RSCore
protocol FeedlyRequestStreamsOperationDelegate: AnyObject {
func feedlyRequestStreamsOperation(_ operation: FeedlyRequestStreamsOperation, enqueue collectionStreamOperation: FeedlyGetStreamContentsOperation)
@@ -15,24 +15,22 @@ protocol FeedlyRequestStreamsOperationDelegate: AnyObject {
/// Create one stream request operation for one Feedly collection.
/// This is the start of the process of refreshing the entire contents of a Folder.
final class FeedlyRequestStreamsOperation: FeedlyOperation {
final class FeedlyRequestStreamsOperation: FeedlyOperation, Logging {
weak var queueDelegate: FeedlyRequestStreamsOperationDelegate?
let collectionsProvider: FeedlyCollectionProviding
let service: FeedlyGetStreamContentsService
let account: Account
let log: OSLog
let newerThan: Date?
let unreadOnly: Bool?
init(account: Account, collectionsProvider: FeedlyCollectionProviding, newerThan: Date?, unreadOnly: Bool?, service: FeedlyGetStreamContentsService, log: OSLog) {
init(account: Account, collectionsProvider: FeedlyCollectionProviding, newerThan: Date?, unreadOnly: Bool?, service: FeedlyGetStreamContentsService) {
self.account = account
self.service = service
self.collectionsProvider = collectionsProvider
self.newerThan = newerThan
self.unreadOnly = unreadOnly
self.log = log
}
override func run() {
@@ -50,11 +48,10 @@ final class FeedlyRequestStreamsOperation: FeedlyOperation {
resource: resource,
service: service,
newerThan: newerThan,
unreadOnly: unreadOnly,
log: log)
unreadOnly: unreadOnly)
queueDelegate?.feedlyRequestStreamsOperation(self, enqueue: operation)
}
os_log(.debug, log: log, "Requested %i collection streams", collectionsProvider.collections.count)
self.logger.debug("Requested \(self.collectionsProvider.collections.count) collections streams.")
}
}

View File

@@ -9,24 +9,22 @@
import Foundation
import Articles
import SyncDatabase
import os.log
import RSCore
/// Take changes to statuses of articles locally and apply them to the corresponding the articles remotely.
final class FeedlySendArticleStatusesOperation: FeedlyOperation {
final class FeedlySendArticleStatusesOperation: FeedlyOperation, Logging {
private let database: SyncDatabase
private let log: OSLog
private let service: FeedlyMarkArticlesService
init(database: SyncDatabase, service: FeedlyMarkArticlesService, log: OSLog) {
init(database: SyncDatabase, service: FeedlyMarkArticlesService) {
self.database = database
self.service = service
self.log = log
}
override func run() {
os_log(.debug, log: log, "Sending article statuses...")
logger.debug("Sending article statuses...")
database.selectForProcessing { result in
if self.isCanceled {
@@ -81,7 +79,7 @@ private extension FeedlySendArticleStatusesOperation {
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done sending article statuses.")
self.logger.debug("Done sending article statuses.")
self.didFinish()
}
}

View File

@@ -7,17 +7,15 @@
//
import Foundation
import os.log
import SyncDatabase
import RSWeb
import RSCore
import Secrets
/// Compose the operations necessary to get the entire set of articles, feeds and folders with the statuses the user expects between now and a certain date in the past.
final class FeedlySyncAllOperation: FeedlyOperation {
final class FeedlySyncAllOperation: FeedlyOperation, Logging {
private let operationQueue = MainThreadOperationQueue()
private let log: OSLog
let syncUUID: UUID
var syncCompletionHandler: ((Result<Void, Error>) -> ())?
@@ -34,9 +32,8 @@ final class FeedlySyncAllOperation: FeedlyOperation {
///
/// Download articles for statuses at the union of those statuses without its corresponding article and those included in 3 (changed since last successful sync).
///
init(account: Account, feedlyUserId: String, lastSuccessfulFetchStartDate: Date?, markArticlesService: FeedlyMarkArticlesService, getUnreadService: FeedlyGetStreamIdsService, getCollectionsService: FeedlyGetCollectionsService, getStreamContentsService: FeedlyGetStreamContentsService, getStarredService: FeedlyGetStreamIdsService, getStreamIdsService: FeedlyGetStreamIdsService, getEntriesService: FeedlyGetEntriesService, database: SyncDatabase, downloadProgress: DownloadProgress, log: OSLog) {
init(account: Account, feedlyUserId: String, lastSuccessfulFetchStartDate: Date?, markArticlesService: FeedlyMarkArticlesService, getUnreadService: FeedlyGetStreamIdsService, getCollectionsService: FeedlyGetCollectionsService, getStreamContentsService: FeedlyGetStreamContentsService, getStarredService: FeedlyGetStreamIdsService, getStreamIdsService: FeedlyGetStreamIdsService, getEntriesService: FeedlyGetEntriesService, database: SyncDatabase, downloadProgress: DownloadProgress) {
self.syncUUID = UUID()
self.log = log
self.operationQueue.suspend()
super.init()
@@ -44,38 +41,38 @@ final class FeedlySyncAllOperation: FeedlyOperation {
self.downloadProgress = downloadProgress
// Send any read/unread/starred article statuses to Feedly before anything else.
let sendArticleStatuses = FeedlySendArticleStatusesOperation(database: database, service: markArticlesService, log: log)
let sendArticleStatuses = FeedlySendArticleStatusesOperation(database: database, service: markArticlesService)
sendArticleStatuses.delegate = self
sendArticleStatuses.downloadProgress = downloadProgress
self.operationQueue.add(sendArticleStatuses)
// Get all the Collections the user has.
let getCollections = FeedlyGetCollectionsOperation(service: getCollectionsService, log: log)
let getCollections = FeedlyGetCollectionsOperation(service: getCollectionsService)
getCollections.delegate = self
getCollections.downloadProgress = downloadProgress
getCollections.addDependency(sendArticleStatuses)
self.operationQueue.add(getCollections)
// Ensure a folder exists for each Collection, removing Folders without a corresponding Collection.
let mirrorCollectionsAsFolders = FeedlyMirrorCollectionsAsFoldersOperation(account: account, collectionsProvider: getCollections, log: log)
let mirrorCollectionsAsFolders = FeedlyMirrorCollectionsAsFoldersOperation(account: account, collectionsProvider: getCollections)
mirrorCollectionsAsFolders.delegate = self
mirrorCollectionsAsFolders.addDependency(getCollections)
self.operationQueue.add(mirrorCollectionsAsFolders)
// Ensure feeds are created and grouped by their folders.
let createFeedsOperation = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: mirrorCollectionsAsFolders, log: log)
let createFeedsOperation = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: mirrorCollectionsAsFolders)
createFeedsOperation.delegate = self
createFeedsOperation.addDependency(mirrorCollectionsAsFolders)
self.operationQueue.add(createFeedsOperation)
let getAllArticleIds = FeedlyIngestStreamArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService, log: log)
let getAllArticleIds = FeedlyIngestStreamArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService)
getAllArticleIds.delegate = self
getAllArticleIds.downloadProgress = downloadProgress
getAllArticleIds.addDependency(createFeedsOperation)
self.operationQueue.add(getAllArticleIds)
// Get each page of unread article ids in the global.all stream for the last 31 days (nil = Feedly API default).
let getUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: feedlyUserId, service: getUnreadService, database: database, newerThan: nil, log: log)
let getUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: feedlyUserId, service: getUnreadService, database: database, newerThan: nil)
getUnread.delegate = self
getUnread.addDependency(getAllArticleIds)
getUnread.downloadProgress = downloadProgress
@@ -83,21 +80,21 @@ final class FeedlySyncAllOperation: FeedlyOperation {
// Get each page of the article ids which have been update since the last successful fetch start date.
// If the date is nil, this operation provides an empty set (everything is new, nothing is updated).
let getUpdated = FeedlyGetUpdatedArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService, newerThan: lastSuccessfulFetchStartDate, log: log)
let getUpdated = FeedlyGetUpdatedArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService, newerThan: lastSuccessfulFetchStartDate)
getUpdated.delegate = self
getUpdated.downloadProgress = downloadProgress
getUpdated.addDependency(createFeedsOperation)
self.operationQueue.add(getUpdated)
// Get each page of the article ids for starred articles.
let getStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: feedlyUserId, service: getStarredService, database: database, newerThan: nil, log: log)
let getStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: feedlyUserId, service: getStarredService, database: database, newerThan: nil)
getStarred.delegate = self
getStarred.downloadProgress = downloadProgress
getStarred.addDependency(createFeedsOperation)
self.operationQueue.add(getStarred)
// Now all the possible article ids we need have a status, fetch the article ids for missing articles.
let getMissingIds = FeedlyFetchIdsForMissingArticlesOperation(account: account, log: log)
let getMissingIds = FeedlyFetchIdsForMissingArticlesOperation(account: account)
getMissingIds.delegate = self
getMissingIds.downloadProgress = downloadProgress
getMissingIds.addDependency(getAllArticleIds)
@@ -110,8 +107,7 @@ final class FeedlySyncAllOperation: FeedlyOperation {
let downloadMissingArticles = FeedlyDownloadArticlesOperation(account: account,
missingArticleEntryIdProvider: getMissingIds,
updatedArticleEntryIdProvider: getUpdated,
getEntriesService: getEntriesService,
log: log)
getEntriesService: getEntriesService)
downloadMissingArticles.delegate = self
downloadMissingArticles.downloadProgress = downloadProgress
downloadMissingArticles.addDependency(getMissingIds)
@@ -126,17 +122,17 @@ final class FeedlySyncAllOperation: FeedlyOperation {
self.operationQueue.add(finishOperation)
}
convenience init(account: Account, feedlyUserId: String, caller: FeedlyAPICaller, database: SyncDatabase, lastSuccessfulFetchStartDate: Date?, downloadProgress: DownloadProgress, log: OSLog) {
self.init(account: account, feedlyUserId: feedlyUserId, lastSuccessfulFetchStartDate: lastSuccessfulFetchStartDate, markArticlesService: caller, getUnreadService: caller, getCollectionsService: caller, getStreamContentsService: caller, getStarredService: caller, getStreamIdsService: caller, getEntriesService: caller, database: database, downloadProgress: downloadProgress, log: log)
convenience init(account: Account, feedlyUserId: String, caller: FeedlyAPICaller, database: SyncDatabase, lastSuccessfulFetchStartDate: Date?, downloadProgress: DownloadProgress) {
self.init(account: account, feedlyUserId: feedlyUserId, lastSuccessfulFetchStartDate: lastSuccessfulFetchStartDate, markArticlesService: caller, getUnreadService: caller, getCollectionsService: caller, getStreamContentsService: caller, getStarredService: caller, getStreamIdsService: caller, getEntriesService: caller, database: database, downloadProgress: downloadProgress)
}
override func run() {
os_log(.debug, log: log, "Starting sync %{public}@", syncUUID.uuidString)
logger.debug("Starting sync \(self.syncUUID.uuidString).")
operationQueue.resume()
}
override func didCancel() {
os_log(.debug, log: log, "Cancelling sync %{public}@", syncUUID.uuidString)
logger.debug("Cancelling sync \(self.syncUUID.uuidString).")
self.operationQueue.cancelAllOperations()
syncCompletionHandler = nil
super.didCancel()
@@ -147,7 +143,7 @@ extension FeedlySyncAllOperation: FeedlyCheckpointOperationDelegate {
func feedlyCheckpointOperationDidReachCheckpoint(_ operation: FeedlyCheckpointOperation) {
assert(Thread.isMainThread)
os_log(.debug, log: self.log, "Sync completed: %{public}@", syncUUID.uuidString)
logger.debug("Sync completed: \(self.syncUUID.uuidString).")
syncCompletionHandler?(.success(()))
syncCompletionHandler = nil
@@ -162,7 +158,7 @@ extension FeedlySyncAllOperation: FeedlyOperationDelegate {
assert(Thread.isMainThread)
// Having this log is useful for debugging missing required JSON keys in the response from Feedly, for example.
os_log(.debug, log: log, "%{public}@ failed with error: %{public}@.", String(describing: operation), error as NSError)
logger.debug("\(String(describing: operation)) failed with error: \(error.localizedDescription).")
syncCompletionHandler?(.failure(error))
syncCompletionHandler = nil

View File

@@ -7,13 +7,12 @@
//
import Foundation
import os.log
import RSParser
import RSCore
import RSWeb
import Secrets
final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyGetStreamContentsOperationDelegate, FeedlyCheckpointOperationDelegate {
final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyGetStreamContentsOperationDelegate, FeedlyCheckpointOperationDelegate, Logging {
private let account: Account
private let resource: FeedlyResourceId
@@ -21,17 +20,15 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
private let service: FeedlyGetStreamContentsService
private let newerThan: Date?
private let isPagingEnabled: Bool
private let log: OSLog
private let finishOperation: FeedlyCheckpointOperation
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, isPagingEnabled: Bool, newerThan: Date?, log: OSLog) {
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, isPagingEnabled: Bool, newerThan: Date?) {
self.account = account
self.resource = resource
self.service = service
self.isPagingEnabled = isPagingEnabled
self.operationQueue.suspend()
self.newerThan = newerThan
self.log = log
self.finishOperation = FeedlyCheckpointOperation()
super.init()
@@ -41,9 +38,9 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
enqueueOperations(for: nil)
}
convenience init(account: Account, credentials: Credentials, service: FeedlyGetStreamContentsService, newerThan: Date?, log: OSLog) {
convenience init(account: Account, credentials: Credentials, service: FeedlyGetStreamContentsService, newerThan: Date?) {
let all = FeedlyCategoryResourceId.Global.all(for: credentials.username)
self.init(account: account, resource: all, service: service, isPagingEnabled: true, newerThan: newerThan, log: log)
self.init(account: account, resource: all, service: service, isPagingEnabled: true, newerThan: newerThan)
}
override func run() {
@@ -51,13 +48,13 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
}
override func didCancel() {
os_log(.debug, log: log, "Canceling sync stream contents for %{public}@", resource.id)
self.logger.debug("Cancelling sync stream contents for \(self.resource.id).")
operationQueue.cancelAllOperations()
super.didCancel()
}
func enqueueOperations(for continuation: String?) {
os_log(.debug, log: log, "Requesting page for %{public}@", resource.id)
self.logger.debug("Requesting page for \(self.resource.id).")
let operations = pageOperations(for: continuation)
operationQueue.addOperations(operations)
}
@@ -67,13 +64,12 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
resource: resource,
service: service,
continuation: continuation,
newerThan: newerThan,
log: log)
newerThan: newerThan)
let organiseByFeed = FeedlyOrganiseParsedItemsByFeedOperation(account: account, parsedItemProvider: getPage, log: log)
let organiseByFeed = FeedlyOrganiseParsedItemsByFeedOperation(account: account, parsedItemProvider: getPage)
let updateAccount = FeedlyUpdateAccountFeedsWithItemsOperation(account: account, organisedItemsProvider: organiseByFeed, log: log)
let updateAccount = FeedlyUpdateAccountFeedsWithItemsOperation(account: account, organisedItemsProvider: organiseByFeed)
getPage.delegate = self
getPage.streamDelegate = self
@@ -91,14 +87,14 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
func feedlyGetStreamContentsOperation(_ operation: FeedlyGetStreamContentsOperation, didGetContentsOf stream: FeedlyStream) {
guard !isCanceled else {
os_log(.debug, log: log, "Cancelled requesting page for %{public}@", resource.id)
self.logger.debug("Cancelled requesting page for \(self.resource.id).")
return
}
os_log(.debug, log: log, "Ingesting %i items from %{public}@", stream.items.count, stream.id)
self.logger.debug("Ingesting \(stream.items.count) from \(stream.id).")
guard isPagingEnabled, let continuation = stream.continuation else {
os_log(.debug, log: log, "Reached end of stream for %{public}@", stream.id)
self.logger.debug("Reached end of stream for \(stream.id).")
return
}
@@ -106,7 +102,7 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
}
func feedlyCheckpointOperationDidReachCheckpoint(_ operation: FeedlyCheckpointOperation) {
os_log(.debug, log: log, "Completed ingesting items from %{public}@", resource.id)
self.logger.debug("Completed ingesting items from \(self.resource.id).")
didFinish()
}

View File

@@ -8,19 +8,17 @@
import Foundation
import RSParser
import os.log
import RSCore
/// Combine the articles with their feeds for a specific account.
final class FeedlyUpdateAccountFeedsWithItemsOperation: FeedlyOperation {
final class FeedlyUpdateAccountFeedsWithItemsOperation: FeedlyOperation, Logging {
private let account: Account
private let organisedItemsProvider: FeedlyParsedItemsByFeedProviding
private let log: OSLog
init(account: Account, organisedItemsProvider: FeedlyParsedItemsByFeedProviding, log: OSLog) {
init(account: Account, organisedItemsProvider: FeedlyParsedItemsByFeedProviding) {
self.account = account
self.organisedItemsProvider = organisedItemsProvider
self.log = log
}
override func run() {
@@ -32,7 +30,7 @@ final class FeedlyUpdateAccountFeedsWithItemsOperation: FeedlyOperation {
return
}
os_log(.debug, log: self.log, "Updated %i feeds for \"%@\"", webFeedIDsAndItems.count, self.organisedItemsProvider.parsedItemsByFeedProviderName)
self.logger.debug("Updated \(webFeedIDsAndItems.count) feeds for \(self.organisedItemsProvider.parsedItemsByFeedProviderName).")
self.didFinish()
}
}

View File

@@ -13,12 +13,12 @@ import RSDatabase
import RSParser
import RSWeb
import SyncDatabase
import os.log
extension NewsBlurAccountDelegate {
func refreshFeeds(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
os_log(.debug, log: log, "Refreshing feeds...")
logger.debug("Refreshing feeds...")
caller.retrieveFeeds { result in
switch result {
@@ -39,7 +39,7 @@ extension NewsBlurAccountDelegate {
guard let folders = folders else { return }
assert(Thread.isMainThread)
os_log(.debug, log: log, "Syncing folders with %ld folders.", folders.count)
logger.debug("Syncing folders with \(folders.count) folders.")
let folderNames = folders.map { $0.name }
@@ -77,7 +77,7 @@ extension NewsBlurAccountDelegate {
guard let feeds = feeds else { return }
assert(Thread.isMainThread)
os_log(.debug, log: log, "Syncing feeds with %ld feeds.", feeds.count)
logger.debug("Syncing feeds with \(feeds.count) feeds.")
let newsBlurFeedIds = feeds.map { String($0.feedID) }
@@ -128,7 +128,7 @@ extension NewsBlurAccountDelegate {
guard let folders = folders else { return }
assert(Thread.isMainThread)
os_log(.debug, log: log, "Syncing folders with %ld folders.", folders.count)
logger.debug("Syncing folders with \(folders.count) folders.")
// Set up some structures to make syncing easier
let relationships = folders.map({ $0.asRelationships }).flatMap { $0 }
@@ -251,7 +251,7 @@ extension NewsBlurAccountDelegate {
}
self.refreshUnreadStories(for: account, hashes: Array(hashes[numberOfStories...]), updateFetchDate: date) { result in
os_log(.debug, log: self.log, "Done refreshing stories.")
self.logger.debug("Done refreshing stories.")
switch result {
case .success:
completion(.success(()))
@@ -300,7 +300,7 @@ extension NewsBlurAccountDelegate {
group.leave()
case .failure(let error):
errorOccurred = true
os_log(.error, log: self.log, "Story status sync call failed: %@.", error.localizedDescription)
self.logger.error("Story status sync call failed: \(error.localizedDescription)")
self.database.resetSelectedForProcessing(storyHashGroup.map { String($0) } )
group.leave()
}
@@ -359,7 +359,7 @@ extension NewsBlurAccountDelegate {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
os_log(.error, log: self.log, "Sync Story Read Status failed: %@.", error.localizedDescription)
self.logger.error("Sync story read status failed: \(error.localizedDescription)")
}
}
}
@@ -407,7 +407,7 @@ extension NewsBlurAccountDelegate {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
os_log(.error, log: self.log, "Sync Story Starred Status failed: %@.", error.localizedDescription)
self.logger.error("Sync story starred status failed: \(error.localizedDescription)")
}
}
}

View File

@@ -12,10 +12,9 @@ import RSDatabase
import RSParser
import RSWeb
import SyncDatabase
import os.log
import Secrets
final class NewsBlurAccountDelegate: AccountDelegate {
final class NewsBlurAccountDelegate: AccountDelegate, Logging {
var behaviors: AccountBehaviors = []
@@ -31,7 +30,6 @@ final class NewsBlurAccountDelegate: AccountDelegate {
var refreshProgress = DownloadProgress(numberOfTasks: 0)
let caller: NewsBlurAPICaller
let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "NewsBlur")
let database: SyncDatabase
init(dataFolder: String, transport: Transport?) {
@@ -133,8 +131,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
func sendArticleStatus(for account: Account, completion: @escaping (Result<Void, Error>) -> ()) {
os_log(.debug, log: log, "Sending story statuses...")
logger.debug("Sending story statuses...")
database.selectForProcessing { result in
func processStatuses(_ syncStatuses: [SyncStatus]) {
@@ -187,7 +184,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done sending article statuses.")
self.logger.debug("Done sending article statuses.")
if errorOccurred {
completion(.failure(NewsBlurError.unknown))
} else {
@@ -206,7 +203,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
func refreshArticleStatus(for account: Account, completion: @escaping (Result<Void, Error>) -> ()) {
os_log(.debug, log: log, "Refreshing story statuses...")
logger.debug("Refreshing story statuses...")
let group = DispatchGroup()
var errorOccurred = false
@@ -220,7 +217,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
case .failure(let error):
errorOccurred = true
os_log(.info, log: self.log, "Retrieving unread stories failed: %@.", error.localizedDescription)
self.logger.error("Retrieving unread stories failed: \(error.localizedDescription)")
group.leave()
}
}
@@ -234,13 +231,13 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
case .failure(let error):
errorOccurred = true
os_log(.info, log: self.log, "Retrieving starred stories failed: %@.", error.localizedDescription)
self.logger.error("Retrieving starred stories failed: \(error.localizedDescription)")
group.leave()
}
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done refreshing article statuses.")
self.logger.debug("Done refreshing article statuses.")
if errorOccurred {
completion(.failure(NewsBlurError.unknown))
} else {
@@ -250,9 +247,9 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
func refreshStories(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
os_log(.debug, log: log, "Refreshing stories...")
os_log(.debug, log: log, "Refreshing unread stories...")
self.logger.debug("Refreshing stories...")
self.logger.debug("Refreshing unread stories...")
caller.retrieveUnreadStoryHashes { result in
switch result {
case .success(let storyHashes):
@@ -269,7 +266,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
func refreshMissingStories(for account: Account, completion: @escaping (Result<Void, Error>) -> Void) {
os_log(.debug, log: log, "Refreshing missing stories...")
self.logger.debug("Refreshing missing stories...")
account.fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate { result in
@@ -296,7 +293,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
case .failure(let error):
errorOccurred = true
os_log(.error, log: self.log, "Refresh missing stories failed: %@.", error.localizedDescription)
self.logger.error("Refreshing missing stories failed: \(error.localizedDescription)")
group.leave()
}
}
@@ -304,7 +301,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
group.notify(queue: DispatchQueue.main) {
self.refreshProgress.completeTask()
os_log(.debug, log: self.log, "Done refreshing missing stories.")
self.logger.debug("Done refreshing stories.")
if errorOccurred {
completion(.failure(NewsBlurError.unknown))
} else {
@@ -568,12 +565,12 @@ final class NewsBlurAccountDelegate: AccountDelegate {
case .success:
break
case .failure(let error):
os_log(.error, log: self.log, "Restore folder feed error: %@.", error.localizedDescription)
self.logger.error("Restore folder feed error: \(error.localizedDescription)")
}
}
}
case .failure(let error):
os_log(.error, log: self.log, "Restore folder feed error: %@.", error.localizedDescription)
self.logger.error("Restore folder feed error: \(error.localizedDescription)")
}
}

View File

@@ -60,8 +60,8 @@
"repositoryURL": "https://github.com/Ranchero-Software/RSCore.git",
"state": {
"branch": null,
"revision": "814adfd956e5bd099b3b81b6680d0a4f6cd56130",
"version": "1.0.9"
"revision": "f50d5c2c0570f84d08d948a533510971e672a1c0",
"version": "1.0.11"
}
},
{