Convert methods to async await.

This commit is contained in:
Brent Simmons 2024-04-23 20:48:06 -07:00
parent a56ffa9405
commit c2197ac854
7 changed files with 133 additions and 239 deletions

View File

@ -422,18 +422,9 @@ extension FeedlyAPICaller: FeedlyGetStreamContentsService {
extension FeedlyAPICaller: FeedlyGetStreamIDsService { extension FeedlyAPICaller: FeedlyGetStreamIDsService {
@MainActor func getStreamIDs(for resource: FeedlyResourceID, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIDs, Error>) -> ()) { @MainActor func getStreamIDs(for resource: FeedlyResourceID, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?) async throws -> FeedlyStreamIDs {
guard !isSuspended else {
return DispatchQueue.main.async {
completion(.failure(TransportError.suspended))
}
}
guard let accessToken = credentials?.secret else { guard !isSuspended else { throw TransportError.suspended }
return DispatchQueue.main.async {
completion(.failure(CredentialsError.incompleteCredentials))
}
}
var components = baseURLComponents var components = baseURLComponents
components.path = "/v3/streams/ids" components.path = "/v3/streams/ids"
@ -469,22 +460,16 @@ extension FeedlyAPICaller: FeedlyGetStreamIDsService {
} }
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.addValue("application/json", forHTTPHeaderField: HTTPRequestHeader.contentType) addJSONHeaders(&request)
request.addValue("application/json", forHTTPHeaderField: "Accept-Type") try addOAuthAccessToken(&request)
request.addValue("OAuth \(accessToken)", forHTTPHeaderField: HTTPRequestHeader.authorization)
send(request: request, resultType: FeedlyStreamIDs.self, dateDecoding: .millisecondsSince1970, keyDecoding: .convertFromSnakeCase) { result in let (_, collections) = try await send(request: request, resultType: FeedlyStreamIDs.self)
switch result {
case .success(let (_, collections)): guard let collections else {
if let response = collections { throw URLError(.cannotDecodeContentData)
completion(.success(response))
} else {
completion(.failure(URLError(.cannotDecodeContentData)))
}
case .failure(let error):
completion(.failure(error))
}
} }
return collections
} }
} }

View File

@ -45,78 +45,44 @@ final class FeedlyIngestStarredArticleIDsOperation: FeedlyOperation {
} }
private func getStreamIDs(_ continuation: String?) { private func getStreamIDs(_ continuation: String?) {
service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil, completion: didGetStreamIDs(_:))
}
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) { Task { @MainActor in
guard !isCanceled else {
didFinish()
return
}
switch result {
case .success(let streamIDs):
do {
let streamIDs = try await service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil)
remoteEntryIDs.formUnion(streamIDs.ids) remoteEntryIDs.formUnion(streamIDs.ids)
guard let continuation = streamIDs.continuation else { guard let continuation = streamIDs.continuation else {
removeEntryIDsWithPendingStatus() try await removeEntryIDsWithPendingStatus()
didFinish()
return return
} }
getStreamIDs(continuation) getStreamIDs(continuation)
case .failure(let error): } catch {
didFinish(with: error) didFinish(with: error)
} }
} }
}
/// Do not override pending statuses with the remote statuses of the same articles, otherwise an article will temporarily re-acquire the remote status before the pending status is pushed and subseqently pulled. /// Do not override pending statuses with the remote statuses of the same articles, otherwise an article will temporarily re-acquire the remote status before the pending status is pushed and subseqently pulled.
private func removeEntryIDsWithPendingStatus() { private func removeEntryIDsWithPendingStatus() async throws {
guard !isCanceled else {
didFinish() if let pendingArticleIDs = try await database.selectPendingStarredStatusArticleIDs() {
return remoteEntryIDs.subtract(pendingArticleIDs)
}
try await updateStarredStatuses()
} }
Task { @MainActor in private func updateStarredStatuses() async throws {
do {
if let pendingArticleIDs = try await self.database.selectPendingStarredStatusArticleIDs() {
self.remoteEntryIDs.subtract(pendingArticleIDs)
}
self.updateStarredStatuses()
} catch {
self.didFinish(with: error)
}
}
}
private func updateStarredStatuses() {
guard !isCanceled else {
didFinish()
return
}
Task { @MainActor in
do {
if let localStarredArticleIDs = try await account.fetchStarredArticleIDs() { if let localStarredArticleIDs = try await account.fetchStarredArticleIDs() {
self.processStarredArticleIDs(localStarredArticleIDs) try await processStarredArticleIDs(localStarredArticleIDs)
}
} catch {
self.didFinish(with: error)
}
} }
} }
func processStarredArticleIDs(_ localStarredArticleIDs: Set<String>) { func processStarredArticleIDs(_ localStarredArticleIDs: Set<String>) async throws {
guard !isCanceled else {
didFinish()
return
}
Task { @MainActor in
var markAsStarredError: Error? var markAsStarredError: Error?
var markAsUnstarredError: Error? var markAsUnstarredError: Error?
@ -136,10 +102,7 @@ final class FeedlyIngestStarredArticleIDsOperation: FeedlyOperation {
} }
if let markingError = markAsStarredError ?? markAsUnstarredError { if let markingError = markAsStarredError ?? markAsUnstarredError {
self.didFinish(with: markingError) throw markingError
}
self.didFinish()
} }
} }
} }

View File

@ -41,20 +41,12 @@ class FeedlyIngestStreamArticleIDsOperation: FeedlyOperation {
} }
private func getStreamIDs(_ continuation: String?) { private func getStreamIDs(_ continuation: String?) {
service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil, completion: didGetStreamIDs(_:))
}
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) {
guard !isCanceled else {
didFinish()
return
}
switch result {
case .success(let streamIDs):
Task { @MainActor in Task { @MainActor in
do { do {
let streamIDs = try await service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil)
try await account.createStatusesIfNeeded(articleIDs: Set(streamIDs.ids)) try await account.createStatusesIfNeeded(articleIDs: Set(streamIDs.ids))
guard let continuation = streamIDs.continuation else { guard let continuation = streamIDs.continuation else {
@ -62,15 +54,11 @@ class FeedlyIngestStreamArticleIDsOperation: FeedlyOperation {
self.didFinish() self.didFinish()
return return
} }
self.getStreamIDs(continuation) self.getStreamIDs(continuation)
} catch { } catch {
self.didFinish(with: error)
return
}
}
case .failure(let error):
didFinish(with: error) didFinish(with: error)
} }
} }
}
} }

View File

@ -46,81 +46,47 @@ final class FeedlyIngestUnreadArticleIDsOperation: FeedlyOperation {
} }
private func getStreamIDs(_ continuation: String?) { private func getStreamIDs(_ continuation: String?) {
service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: true, completion: didGetStreamIDs(_:))
}
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) { Task { @MainActor in
guard !isCanceled else {
didFinish()
return
}
switch result {
case .success(let streamIDs):
do {
let streamIDs = try await service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: true)
remoteEntryIDs.formUnion(streamIDs.ids) remoteEntryIDs.formUnion(streamIDs.ids)
guard let continuation = streamIDs.continuation else { guard let continuation = streamIDs.continuation else {
removeEntryIDsWithPendingStatus() try await removeEntryIDsWithPendingStatus()
didFinish()
return return
} }
getStreamIDs(continuation) getStreamIDs(continuation)
case .failure(let error): } catch {
didFinish(with: error) didFinish(with: error)
} }
} }
}
/// Do not override pending statuses with the remote statuses of the same articles, otherwise an article will temporarily re-acquire the remote status before the pending status is pushed and subseqently pulled. /// Do not override pending statuses with the remote statuses of the same articles, otherwise an article will temporarily re-acquire the remote status before the pending status is pushed and subseqently pulled.
private func removeEntryIDsWithPendingStatus() { private func removeEntryIDsWithPendingStatus() async throws {
guard !isCanceled else {
didFinish() if let pendingArticleIDs = try await database.selectPendingReadStatusArticleIDs() {
return remoteEntryIDs.subtract(pendingArticleIDs)
}
try await updateUnreadStatuses()
} }
Task { @MainActor in private func updateUnreadStatuses() async throws {
do {
if let pendingArticleIDs = try await self.database.selectPendingReadStatusArticleIDs() {
self.remoteEntryIDs.subtract(pendingArticleIDs)
}
self.updateUnreadStatuses()
} catch {
self.didFinish(with: error)
}
}
}
private func updateUnreadStatuses() {
guard !isCanceled else {
didFinish()
return
}
Task { @MainActor in
do {
if let localUnreadArticleIDs = try await account.fetchUnreadArticleIDs() { if let localUnreadArticleIDs = try await account.fetchUnreadArticleIDs() {
self.processUnreadArticleIDs(localUnreadArticleIDs) try await processUnreadArticleIDs(localUnreadArticleIDs)
}
} catch {
self.didFinish(with: error)
}
} }
} }
private func processUnreadArticleIDs(_ localUnreadArticleIDs: Set<String>) { private func processUnreadArticleIDs(_ localUnreadArticleIDs: Set<String>) async throws {
guard !isCanceled else {
didFinish()
return
}
let remoteUnreadArticleIDs = remoteEntryIDs let remoteUnreadArticleIDs = remoteEntryIDs
Task { @MainActor in
var markAsUnreadError: Error? var markAsUnreadError: Error?
var markAsReadError: Error? var markAsReadError: Error?
@ -138,10 +104,7 @@ final class FeedlyIngestUnreadArticleIDsOperation: FeedlyOperation {
} }
if let markingError = markAsReadError ?? markAsUnreadError { if let markingError = markAsReadError ?? markAsUnreadError {
self.didFinish(with: markingError) throw markingError
}
self.didFinish()
} }
} }
} }

View File

@ -10,6 +10,7 @@ import Foundation
import os.log import os.log
public protocol FeedlyGetStreamIDsOperationDelegate: AnyObject { public protocol FeedlyGetStreamIDsOperationDelegate: AnyObject {
func feedlyGetStreamIDsOperation(_ operation: FeedlyGetStreamIDsOperation, didGet streamIDs: FeedlyStreamIDs) func feedlyGetStreamIDsOperation(_ operation: FeedlyGetStreamIDsOperation, didGet streamIDs: FeedlyStreamIDs)
} }
@ -46,16 +47,15 @@ public final class FeedlyGetStreamIDsOperation: FeedlyOperation, FeedlyEntryIden
weak var streamIDsDelegate: FeedlyGetStreamIDsOperationDelegate? weak var streamIDsDelegate: FeedlyGetStreamIDsOperationDelegate?
public override func run() { public override func run() {
service.getStreamIDs(for: resource, continuation: continuation, newerThan: newerThan, unreadOnly: unreadOnly) { result in
switch result { Task { @MainActor in
case .success(let stream):
do {
let stream = try await service.getStreamIDs(for: resource, continuation: continuation, newerThan: newerThan, unreadOnly: unreadOnly)
self.streamIDs = stream self.streamIDs = stream
self.streamIDsDelegate?.feedlyGetStreamIDsOperation(self, didGet: stream) self.streamIDsDelegate?.feedlyGetStreamIDsOperation(self, didGet: stream)
self.didFinish() self.didFinish()
} catch {
case .failure(let error):
os_log(.debug, log: self.log, "Unable to get stream ids: %{public}@.", error as NSError) os_log(.debug, log: self.log, "Unable to get stream ids: %{public}@.", error as NSError)
self.didFinish(with: error) self.didFinish(with: error)
} }

View File

@ -45,25 +45,18 @@ public final class FeedlyGetUpdatedArticleIDsOperation: FeedlyOperation, FeedlyE
} }
private func getStreamIDs(_ continuation: String?) { private func getStreamIDs(_ continuation: String?) {
Task { @MainActor in
guard let date = newerThan else { guard let date = newerThan else {
os_log(.debug, log: log, "No date provided so everything must be new (nothing is updated).") os_log(.debug, log: log, "No date provided so everything must be new (nothing is updated).")
didFinish() didFinish()
return return
} }
service.getStreamIDs(for: resource, continuation: continuation, newerThan: date, unreadOnly: nil, completion: didGetStreamIDs(_:)) do {
} let streamIDs = try await service.getStreamIDs(for: resource, continuation: continuation, newerThan: date, unreadOnly: nil)
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) {
guard !isCanceled else {
didFinish()
return
}
switch result {
case .success(let streamIDs):
storedUpdatedArticleIDs.formUnion(streamIDs.ids) storedUpdatedArticleIDs.formUnion(streamIDs.ids)
guard let continuation = streamIDs.continuation else { guard let continuation = streamIDs.continuation else {
os_log(.debug, log: log, "%{public}i articles updated since last successful sync start date.", storedUpdatedArticleIDs.count) os_log(.debug, log: log, "%{public}i articles updated since last successful sync start date.", storedUpdatedArticleIDs.count)
didFinish() didFinish()
@ -72,8 +65,9 @@ public final class FeedlyGetUpdatedArticleIDsOperation: FeedlyOperation, FeedlyE
getStreamIDs(continuation) getStreamIDs(continuation)
case .failure(let error): } catch {
didFinish(with: error) didFinish(with: error)
} }
} }
}
} }

View File

@ -9,5 +9,6 @@
import Foundation import Foundation
public protocol FeedlyGetStreamIDsService: AnyObject { public protocol FeedlyGetStreamIDsService: AnyObject {
func getStreamIDs(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIDs, Error>) -> ())
@MainActor func getStreamIDs(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?) async throws -> FeedlyStreamIDs
} }