From a6d29b203c60266b45241972d6cbce4ea8c1dd93 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Wed, 26 Jan 2022 23:07:35 -0500 Subject: [PATCH] Use batch update endpoint for marking items (un)read --- Fervor/FervorClient.swift | 14 +++++++++++ Reader/FervorController.swift | 44 ++++++++++++++++++----------------- Reader/SceneDelegate.swift | 6 +---- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/Fervor/FervorClient.swift b/Fervor/FervorClient.swift index a8c42bd..aec7e2d 100644 --- a/Fervor/FervorClient.swift +++ b/Fervor/FervorClient.swift @@ -131,6 +131,20 @@ public class FervorClient { return try await performRequest(request) } + public func read(ids: [FervorID]) async throws -> [FervorID] { + var request = URLRequest(url: buildURL(path: "/api/v1/items/read")) + request.httpMethod = "POST" + request.setURLEncodedBody(params: ["ids": ids.joined(separator: ",")]) + return try await performRequest(request) + } + + public func unread(ids: [FervorID]) async throws -> [FervorID] { + var request = URLRequest(url: buildURL(path: "/api/v1/items/unread")) + request.httpMethod = "POST" + request.setURLEncodedBody(params: ["ids": ids.joined(separator: ",")]) + return try await performRequest(request) + } + public struct Auth { public let accessToken: String public let refreshToken: String? diff --git a/Reader/FervorController.swift b/Reader/FervorController.swift index 823e67d..c5dfb8d 100644 --- a/Reader/FervorController.swift +++ b/Reader/FervorController.swift @@ -87,36 +87,38 @@ class FervorController { } @MainActor - func syncReadToServer() async throws { + func syncReadToServer() async { var count = 0 - // todo: there should be a batch update api endpoint - for case let item as Item in persistentContainer.viewContext.updatedObjects { - let f = item.read ? client.read(item:) : client.unread(item:) - do { - let _ = try await f(item.id!) - count += 1 - } catch { - logger.error("Failed to sync read state: \(String(describing: error), privacy: .public)") - item.needsReadStateSync = true - } - } // try to sync items which failed last time let req = Item.fetchRequest() req.predicate = NSPredicate(format: "needsReadStateSync = YES") - if let needsSync = try? persistentContainer.viewContext.fetch(req) { - for item in needsSync { - let f = item.read ? client.read(item:) : client.unread(item:) + if var needsSync = try? persistentContainer.viewContext.fetch(req) { + let firstReadIndex = needsSync.partition(by: \.read) + let unreadIDs = needsSync[..() + if !unreadIDs.isEmpty { do { - let _ = try await f(item.id!) - count += 1 - item.needsReadStateSync = false + let ids = try await client.unread(ids: unreadIDs) + updatedIDs.formUnion(ids) } catch { - logger.error("Failed to sync read state again: \(String(describing: error), privacy: .public)") - item.needsReadStateSync = true - // todo: this should probably fail after a certain number of attempts + logger.error("Failed to sync unread state: \(String(describing: error), privacy: .public)") } } + if !readIDs.isEmpty { + do { + let ids = try await client.read(ids: readIDs) + updatedIDs.formUnion(ids) + } catch { + logger.error("Failed to sync read state: \(String(describing: error), privacy: .public)") + } + } + + count += updatedIDs.count + for item in needsSync where updatedIDs.contains(item.id!) { + item.needsReadStateSync = false + } } logger.info("Synced \(count, privacy: .public) read/unread to server") diff --git a/Reader/SceneDelegate.swift b/Reader/SceneDelegate.swift index 18abaa5..3ad2ac8 100644 --- a/Reader/SceneDelegate.swift +++ b/Reader/SceneDelegate.swift @@ -81,11 +81,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { if let fervorController = fervorController { Task(priority: .userInitiated) { - do { - try await fervorController.syncReadToServer() - } catch { - logger.error("Unable to sync read state to server: \(String(describing: error), privacy: .public)") - } + await fervorController.syncReadToServer() } } }