Convert methods to async await.

This commit is contained in:
Brent Simmons 2024-04-23 20:58:14 -07:00
parent c2197ac854
commit 8f912ad22b
4 changed files with 46 additions and 87 deletions

View File

@ -475,56 +475,21 @@ extension FeedlyAPICaller: FeedlyGetStreamIDsService {
extension FeedlyAPICaller: FeedlyGetEntriesService {
func getEntries(for ids: Set<String>, completion: @escaping (Result<[FeedlyEntry], Error>) -> ()) {
guard !isSuspended else {
return DispatchQueue.main.async {
completion(.failure(TransportError.suspended))
}
}
guard let accessToken = credentials?.secret else {
return DispatchQueue.main.async {
completion(.failure(CredentialsError.incompleteCredentials))
}
}
var components = baseURLComponents
components.path = "/v3/entries/.mget"
guard let url = components.url else {
fatalError("\(components) does not produce a valid URL.")
}
var request = URLRequest(url: url)
do {
let body = Array(ids)
let encoder = JSONEncoder()
let data = try encoder.encode(body)
request.httpBody = data
} catch {
return DispatchQueue.main.async {
completion(.failure(error))
}
}
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: HTTPRequestHeader.contentType)
request.addValue("application/json", forHTTPHeaderField: "Accept-Type")
request.addValue("OAuth \(accessToken)", forHTTPHeaderField: HTTPRequestHeader.authorization)
send(request: request, resultType: [FeedlyEntry].self, dateDecoding: .millisecondsSince1970, keyDecoding: .convertFromSnakeCase) { result in
switch result {
case .success(let (_, entries)):
if let response = entries {
completion(.success(response))
} else {
completion(.failure(URLError(.cannotDecodeContentData)))
}
case .failure(let error):
completion(.failure(error))
}
@MainActor func getEntries(for ids: Set<String>) async throws -> [FeedlyEntry] {
guard !isSuspended else { throw TransportError.suspended }
var request = try urlRequest(path: "/v3/entries/.mget", method: HTTPMethod.post, includeJSONHeaders: true, includeOAuthToken: true)
let body = Array(ids)
try addObject(body, to: &request)
let (_, entries) = try await send(request: request, resultType: [FeedlyEntry].self)
guard let entries else {
throw URLError(.cannotDecodeContentData)
}
return entries
}
}
@ -604,14 +569,10 @@ extension FeedlyAPICaller: FeedlyMarkArticlesService {
extension FeedlyAPICaller: FeedlySearchService {
func getFeeds(for query: String, count: Int, locale: String, completion: @escaping (Result<FeedlyFeedsSearchResponse, Error>) -> ()) {
guard !isSuspended else {
return DispatchQueue.main.async {
completion(.failure(TransportError.suspended))
}
}
@MainActor func getFeeds(for query: String, count: Int, locale: String) async throws -> FeedlyFeedsSearchResponse {
guard !isSuspended else { throw TransportError.suspended }
var components = baseURLComponents
components.path = "/v3/search/feeds"
@ -620,29 +581,22 @@ extension FeedlyAPICaller: FeedlySearchService {
URLQueryItem(name: "count", value: String(count)),
URLQueryItem(name: "locale", value: locale)
]
guard let url = components.url else {
fatalError("\(components) does not produce a valid URL.")
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: HTTPRequestHeader.contentType)
request.addValue("application/json", forHTTPHeaderField: "Accept-Type")
send(request: request, resultType: FeedlyFeedsSearchResponse.self, dateDecoding: .millisecondsSince1970, keyDecoding: .convertFromSnakeCase) { result in
switch result {
case .success(let (_, searchResponse)):
if let response = searchResponse {
completion(.success(response))
} else {
completion(.failure(URLError(.cannotDecodeContentData)))
}
case .failure(let error):
completion(.failure(error))
}
addJSONHeaders(&request)
let (_, searchResponse) = try await send(request: request, resultType: FeedlyFeedsSearchResponse.self)
guard let searchResponse else {
throw URLError(.cannotDecodeContentData)
}
return searchResponse
}
}

View File

@ -54,13 +54,14 @@ public final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProvid
}
public override func run() {
service.getEntries(for: provider.entryIDs) { result in
switch result {
case .success(let entries):
Task { @MainActor in
do {
let entries = try await service.getEntries(for: provider.entryIDs)
self.entries = entries
self.didFinish()
case .failure(let error):
} catch {
os_log(.debug, log: self.log, "Unable to get entries: %{public}@.", error as NSError)
self.didFinish(with: error)
}

View File

@ -9,16 +9,18 @@
import Foundation
public protocol FeedlySearchService: AnyObject {
func getFeeds(for query: String, count: Int, locale: String, completion: @escaping (Result<FeedlyFeedsSearchResponse, Error>) -> ())
@MainActor func getFeeds(for query: String, count: Int, locale: String) async throws -> FeedlyFeedsSearchResponse
}
public protocol FeedlySearchOperationDelegate: AnyObject {
@MainActor func feedlySearchOperation(_ operation: FeedlySearchOperation, didGet response: FeedlyFeedsSearchResponse)
}
/// Find one and only one feed for a given query (usually, a URL).
/// What happens when a feed is found for the URL is delegated to the `searchDelegate`.
public class FeedlySearchOperation: FeedlyOperation {
public final class FeedlySearchOperation: FeedlyOperation {
let query: String
let locale: Locale
@ -32,14 +34,15 @@ public class FeedlySearchOperation: FeedlyOperation {
}
public override func run() {
searchService.getFeeds(for: query, count: 1, locale: locale.identifier) { result in
switch result {
case .success(let response):
assert(Thread.isMainThread)
self.searchDelegate?.feedlySearchOperation(self, didGet: response)
Task { @MainActor in
do {
let searchResponse = try await searchService.getFeeds(for: query, count: 1, locale: locale.identifier)
self.searchDelegate?.feedlySearchOperation(self, didGet: searchResponse)
self.didFinish()
case .failure(let error):
} catch {
self.didFinish(with: error)
}
}

View File

@ -9,5 +9,6 @@
import Foundation
public protocol FeedlyGetEntriesService: AnyObject {
func getEntries(for ids: Set<String>, completion: @escaping (Result<[FeedlyEntry], Error>) -> ())
@MainActor func getEntries(for ids: Set<String>) async throws -> [FeedlyEntry]
}