Continue adopting async/await.

This commit is contained in:
Brent Simmons
2023-07-11 20:17:13 -07:00
parent 46838dd4eb
commit 29cb574f3a
9 changed files with 243 additions and 289 deletions

View File

@@ -752,12 +752,12 @@ public enum FetchType {
return try database.fetchStarredArticlesCount(flattenedFeeds().feedIDs())
}
public func fetchUnreadArticleIDs(_ completion: @escaping ArticleIDsCompletionBlock) {
database.fetchUnreadArticleIDsAsync(completion: completion)
public func fetchUnreadArticleIDs() async throws -> Set<String> {
return try await database.fetchUnreadArticleIDsAsync()
}
public func fetchStarredArticleIDs(_ completion: @escaping ArticleIDsCompletionBlock) {
database.fetchStarredArticleIDsAsync(completion: completion)
public func fetchStarredArticleIDs() async throws -> Set<String> {
return try await database.fetchStarredArticleIDsAsync()
}
/// Fetch articleIDs for articles that we should have, but dont. These articles are either (starred) or (newer than the article cutoff date).

View File

@@ -1276,102 +1276,81 @@ private extension FeedbinAccountDelegate {
database.selectPendingReadStatusArticleIDs() { result in
@MainActor func process(_ pendingArticleIDs: Set<String>) {
let feedbinUnreadArticleIDs = Set(articleIDs.map { String($0) } )
let updatableFeedbinUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(pendingArticleIDs)
account.fetchUnreadArticleIDs { articleIDsResult in
guard let currentUnreadArticleIDs = try? articleIDsResult.get() else {
return
}
func process(_ pendingArticleIDs: Set<String>) {
let group = DispatchGroup()
// Mark articles as unread
let deltaUnreadArticleIDs = updatableFeedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs)
group.enter()
account.markAsUnread(deltaUnreadArticleIDs) { _ in
group.leave()
}
Task { @MainActor in
let feedbinUnreadArticleIDs = Set(articleIDs.map { String($0) } )
let updatableFeedbinUnreadArticleIDs = feedbinUnreadArticleIDs.subtracting(pendingArticleIDs)
// Mark articles as read
let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableFeedbinUnreadArticleIDs)
group.enter()
account.markAsRead(deltaReadArticleIDs) { _ in
group.leave()
}
group.notify(queue: DispatchQueue.main) {
completion()
}
}
do {
let currentUnreadArticleIDs = try await account.fetchUnreadArticleIDs()
// Mark articles as unread
let deltaUnreadArticleIDs = updatableFeedbinUnreadArticleIDs.subtracting(currentUnreadArticleIDs)
account.markAsUnread(deltaUnreadArticleIDs)
// Mark articles as read
let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableFeedbinUnreadArticleIDs)
account.markAsRead(deltaReadArticleIDs)
} catch let error {
self.logger.error("Sync Articles Read Status failed: \(error.localizedDescription, privacy: .public)")
}
completion()
}
}
}
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
self.logger.error("Sync Articles Read Status failed: \(error.localizedDescription, privacy: .public)")
}
}
}
func syncArticleStarredState(account: Account, articleIDs: [Int]?, completion: @escaping (() -> Void)) {
guard let articleIDs = articleIDs else {
completion()
return
}
func syncArticleStarredState(account: Account, articleIDs: [Int]?, completion: @escaping (() -> Void)) {
guard let articleIDs = articleIDs else {
completion()
return
}
database.selectPendingStarredStatusArticleIDs() { result in
database.selectPendingStarredStatusArticleIDs() { result in
@MainActor func process(_ pendingArticleIDs: Set<String>) {
let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } )
let updatableFeedbinStarredArticleIDs = feedbinStarredArticleIDs.subtracting(pendingArticleIDs)
func process(_ pendingArticleIDs: Set<String>) {
account.fetchStarredArticleIDs { articleIDsResult in
guard let currentStarredArticleIDs = try? articleIDsResult.get() else {
return
}
Task { @MainActor in
let feedbinStarredArticleIDs = Set(articleIDs.map { String($0) } )
let updatableFeedbinStarredArticleIDs = feedbinStarredArticleIDs.subtracting(pendingArticleIDs)
let group = DispatchGroup()
// Mark articles as starred
let deltaStarredArticleIDs = updatableFeedbinStarredArticleIDs.subtracting(currentStarredArticleIDs)
group.enter()
account.markAsStarred(deltaStarredArticleIDs) { _ in
group.leave()
}
do {
let currentStarredArticleIDs = try await account.fetchStarredArticleIDs()
// Mark articles as unstarred
let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableFeedbinStarredArticleIDs)
group.enter()
account.markAsUnstarred(deltaUnstarredArticleIDs) { _ in
group.leave()
}
// Mark articles as starred
let deltaStarredArticleIDs = updatableFeedbinStarredArticleIDs.subtracting(currentStarredArticleIDs)
account.markAsStarred(deltaStarredArticleIDs)
group.notify(queue: DispatchQueue.main) {
completion()
}
}
}
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
// Mark articles as unstarred
let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableFeedbinStarredArticleIDs)
account.markAsUnstarred(deltaUnstarredArticleIDs)
} catch let error {
self.logger.error("Sync Article Starred Status failed: \(error.localizedDescription, privacy: .public)")
}
completion()
}
}
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
self.logger.error("Sync Article Starred Status failed: \(error.localizedDescription, privacy: .public)")
}
}
}
}
}
}
func deleteTagging(for account: Account, with feed: Feed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) {

View File

@@ -93,16 +93,22 @@ final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation, Logging {
didFinish()
return
}
account.fetchStarredArticleIDs { result in
switch result {
case .success(let localStarredArticleIDs):
self.processStarredArticleIDs(localStarredArticleIDs)
case .failure(let error):
self.didFinish(with: error)
}
}
Task { @MainActor in
var localStarredArticleIDs: Set<String>?
do {
localStarredArticleIDs = try await account.fetchStarredArticleIDs()
} catch {
didFinish(with: error)
return
}
if let localStarredArticleIDs {
processStarredArticleIDs(localStarredArticleIDs)
}
}
}
func processStarredArticleIDs(_ localStarredArticleIDs: Set<String>) {

View File

@@ -94,16 +94,21 @@ final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation, Logging {
didFinish()
return
}
account.fetchUnreadArticleIDs { result in
switch result {
case .success(let localUnreadArticleIDs):
self.processUnreadArticleIDs(localUnreadArticleIDs)
case .failure(let error):
self.didFinish(with: error)
}
}
Task { @MainActor in
var localUnreadArticleIDs: Set<String>?
do {
localUnreadArticleIDs = try await account.fetchUnreadArticleIDs()
} catch {
didFinish(with: error)
return
}
if let localUnreadArticleIDs {
processUnreadArticleIDs(localUnreadArticleIDs)
}
}
}
private func processUnreadArticleIDs(_ localUnreadArticleIDs: Set<String>) {

View File

@@ -316,53 +316,45 @@ extension NewsBlurAccountDelegate {
}
}
func syncStoryReadState(account: Account, hashes: [NewsBlurStoryHash]?, completion: @escaping (() -> Void)) {
guard let hashes = hashes else {
completion()
return
}
func syncStoryReadState(account: Account, hashes: [NewsBlurStoryHash]?, completion: @escaping (() -> Void)) {
guard let hashes = hashes else {
completion()
return
}
database.selectPendingReadStatusArticleIDs() { result in
database.selectPendingReadStatusArticleIDs() { result in
@MainActor func process(_ pendingStoryHashes: Set<String>) {
let newsBlurUnreadStoryHashes = Set(hashes.map { $0.hash } )
let updatableNewsBlurUnreadStoryHashes = newsBlurUnreadStoryHashes.subtracting(pendingStoryHashes)
Task { @MainActor in
let newsBlurUnreadStoryHashes = Set(hashes.map { $0.hash } )
let updatableNewsBlurUnreadStoryHashes = newsBlurUnreadStoryHashes.subtracting(pendingStoryHashes)
account.fetchUnreadArticleIDs { articleIDsResult in
guard let currentUnreadArticleIDs = try? articleIDsResult.get() else {
return
}
do {
let currentUnreadArticleIDs = try await account.fetchUnreadArticleIDs()
let group = DispatchGroup()
// Mark articles as unread
let deltaUnreadArticleIDs = updatableNewsBlurUnreadStoryHashes.subtracting(currentUnreadArticleIDs)
group.enter()
account.markAsUnread(deltaUnreadArticleIDs) { _ in
group.leave()
}
// Mark articles as unread
let deltaUnreadArticleIDs = updatableNewsBlurUnreadStoryHashes.subtracting(currentUnreadArticleIDs)
account.markAsUnread(deltaUnreadArticleIDs)
// Mark articles as read
let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableNewsBlurUnreadStoryHashes)
group.enter()
account.markAsRead(deltaReadArticleIDs) { _ in
group.leave()
}
group.notify(queue: DispatchQueue.main) {
completion()
}
}
}
// Mark articles as read
let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableNewsBlurUnreadStoryHashes)
account.markAsRead(deltaReadArticleIDs)
} catch let error {
self.logger.error("Sync story read status failed: \(error.localizedDescription, privacy: .public)")
}
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
self.logger.error("Sync story read status failed: \(error.localizedDescription, privacy: .public)")
}
}
}
completion()
}
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
self.logger.error("Sync story read status failed: \(error.localizedDescription, privacy: .public)")
}
}
}
}
func syncStoryStarredState(account: Account, hashes: [NewsBlurStoryHash]?, completion: @escaping (() -> Void)) {
guard let hashes = hashes else {
@@ -372,37 +364,29 @@ extension NewsBlurAccountDelegate {
database.selectPendingStarredStatusArticleIDs() { result in
@MainActor func process(_ pendingStoryHashes: Set<String>) {
func process(_ pendingStoryHashes: Set<String>) {
let newsBlurStarredStoryHashes = Set(hashes.map { $0.hash } )
let updatableNewsBlurUnreadStoryHashes = newsBlurStarredStoryHashes.subtracting(pendingStoryHashes)
Task { @MainActor in
let newsBlurStarredStoryHashes = Set(hashes.map { $0.hash } )
let updatableNewsBlurUnreadStoryHashes = newsBlurStarredStoryHashes.subtracting(pendingStoryHashes)
account.fetchStarredArticleIDs { articleIDsResult in
guard let currentStarredArticleIDs = try? articleIDsResult.get() else {
return
}
do {
let currentStarredArticleIDs = try await account.fetchStarredArticleIDs()
let group = DispatchGroup()
// Mark articles as starred
let deltaStarredArticleIDs = updatableNewsBlurUnreadStoryHashes.subtracting(currentStarredArticleIDs)
group.enter()
account.markAsStarred(deltaStarredArticleIDs) { _ in
group.leave()
}
// Mark articles as starred
let deltaStarredArticleIDs = updatableNewsBlurUnreadStoryHashes.subtracting(currentStarredArticleIDs)
account.markAsStarred(deltaStarredArticleIDs)
// Mark articles as unstarred
let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableNewsBlurUnreadStoryHashes)
group.enter()
account.markAsUnstarred(deltaUnstarredArticleIDs) { _ in
group.leave()
}
// Mark articles as unstarred
let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableNewsBlurUnreadStoryHashes)
account.markAsUnstarred(deltaUnstarredArticleIDs)
} catch let error {
self.logger.error("Sync story starred status failed: \(error.localizedDescription, privacy: .public)")
}
group.notify(queue: DispatchQueue.main) {
completion()
}
}
}
completion()
}
}
switch result {
case .success(let pendingArticleIDs):

View File

@@ -1078,102 +1078,82 @@ private extension ReaderAPIAccountDelegate {
}
func syncArticleReadState(account: Account, articleIDs: [String]?, completion: @escaping (() -> Void)) {
guard let articleIDs = articleIDs else {
completion()
return
}
func syncArticleReadState(account: Account, articleIDs: [String]?, completion: @escaping (() -> Void)) {
guard let articleIDs = articleIDs else {
completion()
return
}
database.selectPendingReadStatusArticleIDs() { result in
database.selectPendingReadStatusArticleIDs() { result in
@MainActor func process(_ pendingArticleIDs: Set<String>) {
let updatableReaderUnreadArticleIDs = Set(articleIDs).subtracting(pendingArticleIDs)
account.fetchUnreadArticleIDs { articleIDsResult in
guard let currentUnreadArticleIDs = try? articleIDsResult.get() else {
return
}
Task { @MainActor in
let updatableReaderUnreadArticleIDs = Set(articleIDs).subtracting(pendingArticleIDs)
do {
let currentUnreadArticleIDs = try await account.fetchUnreadArticleIDs()
let group = DispatchGroup()
// Mark articles as unread
let deltaUnreadArticleIDs = updatableReaderUnreadArticleIDs.subtracting(currentUnreadArticleIDs)
group.enter()
account.markAsUnread(deltaUnreadArticleIDs) { _ in
group.leave()
}
// Mark articles as unread
let deltaUnreadArticleIDs = updatableReaderUnreadArticleIDs.subtracting(currentUnreadArticleIDs)
account.markAsUnread(deltaUnreadArticleIDs)
// Mark articles as read
let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableReaderUnreadArticleIDs)
group.enter()
account.markAsRead(deltaReadArticleIDs) { _ in
group.leave()
}
group.notify(queue: DispatchQueue.main) {
completion()
}
}
}
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
self.logger.error("Sync Article Read Status failed: \(error.localizedDescription, privacy: .public)")
}
}
}
func syncArticleStarredState(account: Account, articleIDs: [String]?, completion: @escaping (() -> Void)) {
guard let articleIDs = articleIDs else {
completion()
return
}
// Mark articles as read
let deltaReadArticleIDs = currentUnreadArticleIDs.subtracting(updatableReaderUnreadArticleIDs)
account.markAsRead(deltaReadArticleIDs)
} catch let error {
self.logger.error("Sync Article Read Status failed: \(error.localizedDescription, privacy: .public)")
}
database.selectPendingStarredStatusArticleIDs() { result in
completion()
}
@MainActor func process(_ pendingArticleIDs: Set<String>) {
let updatableReaderUnreadArticleIDs = Set(articleIDs).subtracting(pendingArticleIDs)
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
self.logger.error("Sync Article Read Status failed: \(error.localizedDescription, privacy: .public)")
}
}
}
}
account.fetchStarredArticleIDs { articleIDsResult in
guard let currentStarredArticleIDs = try? articleIDsResult.get() else {
return
}
func syncArticleStarredState(account: Account, articleIDs: [String]?, completion: @escaping (() -> Void)) {
guard let articleIDs = articleIDs else {
completion()
return
}
let group = DispatchGroup()
// Mark articles as starred
let deltaStarredArticleIDs = updatableReaderUnreadArticleIDs.subtracting(currentStarredArticleIDs)
group.enter()
account.markAsStarred(deltaStarredArticleIDs) { _ in
group.leave()
}
database.selectPendingStarredStatusArticleIDs() { result in
// Mark articles as unstarred
let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableReaderUnreadArticleIDs)
group.enter()
account.markAsUnstarred(deltaUnstarredArticleIDs) { _ in
group.leave()
}
func process(_ pendingArticleIDs: Set<String>) {
group.notify(queue: DispatchQueue.main) {
completion()
}
}
}
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
Task { @MainActor in
do {
let updatableReaderUnreadArticleIDs = Set(articleIDs).subtracting(pendingArticleIDs)
let currentStarredArticleIDs = try await account.fetchStarredArticleIDs()
// Mark articles as starred
let deltaStarredArticleIDs = updatableReaderUnreadArticleIDs.subtracting(currentStarredArticleIDs)
account.markAsStarred(deltaStarredArticleIDs)
// Mark articles as unstarred
let deltaUnstarredArticleIDs = currentStarredArticleIDs.subtracting(updatableReaderUnreadArticleIDs)
account.markAsUnstarred(deltaUnstarredArticleIDs)
} catch let error {
self.logger.error("Sync Article Starred Status failed: \(error.localizedDescription, privacy: .public)")
}
completion()
}
}
switch result {
case .success(let pendingArticleIDs):
process(pendingArticleIDs)
case .failure(let error):
self.logger.error("Sync Article Starred Status failed: \(error.localizedDescription, privacy: .public)")
}
}
}
}
}
}
}

View File

@@ -239,13 +239,13 @@ public typealias ArticleStatusesResultBlock = (ArticleStatusesResult) -> Void
// MARK: - Status
/// Fetch the articleIDs of unread articles.
public func fetchUnreadArticleIDsAsync(completion: @escaping ArticleIDsCompletionBlock) {
articlesTable.fetchUnreadArticleIDsAsync(completion)
public func fetchUnreadArticleIDsAsync() async throws -> Set<String> {
return try await articlesTable.fetchUnreadArticleIDsAsync()
}
/// Fetch the articleIDs of starred articles.
public func fetchStarredArticleIDsAsync(completion: @escaping ArticleIDsCompletionBlock) {
articlesTable.fetchStarredArticleIDsAsync(completion)
public func fetchStarredArticleIDsAsync() async throws -> Set<String> {
return try await articlesTable.fetchStarredArticleIDsAsync()
}
/// Fetch articleIDs for articles that we should have, but dont. These articles are either (starred) or (newer than the article cutoff date).

View File

@@ -461,12 +461,12 @@ final class ArticlesTable: DatabaseTable {
// MARK: - Statuses
func fetchUnreadArticleIDsAsync(_ completion: @escaping ArticleIDsCompletionBlock) {
statusesTable.fetchArticleIDsAsync(.read, false, completion)
func fetchUnreadArticleIDsAsync() async throws -> Set<String> {
return try await statusesTable.fetchArticleIDsAsync(.read, false)
}
func fetchStarredArticleIDsAsync(_ completion: @escaping ArticleIDsCompletionBlock) {
statusesTable.fetchArticleIDsAsync(.starred, true, completion)
func fetchStarredArticleIDsAsync() async throws -> Set<String> {
return try await statusesTable.fetchArticleIDsAsync(.starred, true)
}
func fetchStarredArticleIDs() throws -> Set<String> {

View File

@@ -100,38 +100,38 @@ final class StatusesTable: DatabaseTable {
func fetchStarredArticleIDs() throws -> Set<String> {
return try fetchArticleIDs("select articleID from statuses where starred=1;")
}
func fetchArticleIDsAsync(_ statusKey: ArticleStatus.Key, _ value: Bool, _ completion: @escaping ArticleIDsCompletionBlock) {
queue.runInDatabase { databaseResult in
func makeDatabaseCalls(_ database: FMDatabase) {
var sql = "select articleID from statuses where \(statusKey.rawValue)="
sql += value ? "1" : "0"
sql += ";"
func fetchArticleIDsAsync(_ statusKey: ArticleStatus.Key, _ value: Bool) async throws -> Set<String> {
guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else {
DispatchQueue.main.async {
completion(.success(Set<String>()))
}
return
}
return try await withCheckedThrowingContinuation { continuation in
let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) }
DispatchQueue.main.async {
completion(.success(articleIDs))
}
}
Task { @MainActor in
queue.runInDatabase { databaseResult in
switch databaseResult {
case .success(let database):
makeDatabaseCalls(database)
case .failure(let databaseError):
DispatchQueue.main.async {
completion(.failure(databaseError))
}
}
}
}
func makeDatabaseCalls(_ database: FMDatabase) {
var sql = "select articleID from statuses where \(statusKey.rawValue)="
sql += value ? "1" : "0"
sql += ";"
guard let resultSet = database.executeQuery(sql, withArgumentsIn: nil) else {
continuation.resume(returning: Set<String>())
return
}
let articleIDs = resultSet.mapToSet{ $0.string(forColumnIndex: 0) }
continuation.resume(returning: articleIDs)
}
switch databaseResult {
case .success(let database):
makeDatabaseCalls(database)
case .failure(let databaseError):
continuation.resume(throwing: databaseError)
}
}
}
}
}
func fetchArticleIDsForStatusesWithoutArticlesNewerThan(_ cutoffDate: Date, _ completion: @escaping ArticleIDsCompletionBlock) {
queue.runInDatabase { databaseResult in