Convert methods to async await.

This commit is contained in:
Brent Simmons 2024-04-23 21:15:35 -07:00
parent 8f912ad22b
commit 54dc3ca7fd
3 changed files with 28 additions and 83 deletions

View File

@ -501,67 +501,21 @@ extension FeedlyAPICaller: FeedlyMarkArticlesService {
var entryIDs: [String]
}
func mark(_ articleIDs: Set<String>, as action: FeedlyMarkAction, completion: @escaping @Sendable (Result<Void, 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/markers"
guard let url = components.url else {
fatalError("\(components) does not produce a valid URL.")
}
func mark(_ articleIDs: Set<String>, as action: FeedlyMarkAction) async throws {
guard !isSuspended else { throw TransportError.suspended }
let articleIDChunks = Array(articleIDs).chunked(into: 300)
let dispatchGroup = DispatchGroup()
var groupError: Error? = nil
for articleIDChunk in articleIDChunks {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: HTTPRequestHeader.contentType)
request.addValue("application/json", forHTTPHeaderField: "Accept-Type")
request.addValue("OAuth \(accessToken)", forHTTPHeaderField: HTTPRequestHeader.authorization)
do {
let body = MarkerEntriesBody(action: action.actionValue, entryIDs: Array(articleIDChunk))
let encoder = JSONEncoder()
let data = try encoder.encode(body)
request.httpBody = data
} catch {
return DispatchQueue.main.async {
completion(.failure(error))
}
}
dispatchGroup.enter()
send(request: request, resultType: String.self, dateDecoding: .millisecondsSince1970, keyDecoding: .convertFromSnakeCase) { result in
switch result {
case .success(let (httpResponse, _)):
if httpResponse.statusCode != 200 {
groupError = URLError(.cannotDecodeContentData)
}
case .failure(let error):
groupError = error
}
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: .main) {
if let groupError = groupError {
completion(.failure(groupError))
} else {
completion(.success(()))
var request = try urlRequest(path: "/v3/markers", method: HTTPMethod.post, includeJSONHeaders: true, includeOAuthToken: true)
let body = MarkerEntriesBody(action: action.actionValue, entryIDs: Array(articleIDChunk))
try addObject(body, to: &request)
let (httpResponse, _) = try await send(request: request, resultType: String.self)
if httpResponse.statusCode != 200 {
throw URLError(.cannotDecodeContentData)
}
}
}
@ -569,25 +523,22 @@ extension FeedlyAPICaller: FeedlyMarkArticlesService {
extension FeedlyAPICaller: FeedlySearchService {
@MainActor func getFeeds(for query: String, count: Int, locale: String) async throws -> FeedlyFeedsSearchResponse {
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"
components.queryItems = [
URLQueryItem(name: "query", value: query),
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"
addJSONHeaders(&request)
let (_, searchResponse) = try await send(request: request, resultType: FeedlyFeedsSearchResponse.self)

View File

@ -42,6 +42,7 @@ public final class FeedlySendArticleStatusesOperation: FeedlyOperation {
private extension FeedlySendArticleStatusesOperation {
func processStatuses(_ pending: [SyncStatus]) {
let statuses: [(status: SyncStatus.Key, flag: Bool, action: FeedlyMarkAction)] = [
(.read, false, .unread),
(.read, true, .read),
@ -49,32 +50,25 @@ private extension FeedlySendArticleStatusesOperation {
(.starred, false, .unsaved),
]
let group = DispatchGroup()
Task { @MainActor in
for pairing in statuses {
let articleIDs = pending.filter { $0.key == pairing.status && $0.flag == pairing.flag }
guard !articleIDs.isEmpty else {
continue
}
for pairing in statuses {
let ids = Set(articleIDs.map { $0.articleID })
let database = self.database
group.enter()
service.mark(ids, as: pairing.action) { result in
Task { @MainActor in
switch result {
case .success:
try? await database.deleteSelectedForProcessing(Array(ids))
group.leave()
case .failure:
try? await database.resetSelectedForProcessing(Array(ids))
group.leave()
}
let articleIDs = pending.filter { $0.key == pairing.status && $0.flag == pairing.flag }
guard !articleIDs.isEmpty else {
continue
}
let ids = Set(articleIDs.map { $0.articleID })
do {
try await service.mark(ids, as: pairing.action)
try? await database.deleteSelectedForProcessing(Array(ids))
} catch {
try? await database.resetSelectedForProcessing(Array(ids))
}
}
}
group.notify(queue: DispatchQueue.main) {
os_log(.debug, log: self.log, "Done sending article statuses.")
self.didFinish()
}

View File

@ -33,5 +33,5 @@ public enum FeedlyMarkAction: String, Sendable {
public protocol FeedlyMarkArticlesService: AnyObject {
func mark(_ articleIDs: Set<String>, as action: FeedlyMarkAction, completion: @escaping @Sendable (Result<Void, Error>) -> ())
@MainActor func mark(_ articleIDs: Set<String>, as action: FeedlyMarkAction) async throws
}