Use batch update endpoint for marking items (un)read

This commit is contained in:
Shadowfacts 2022-01-26 23:07:35 -05:00
parent c41a81414d
commit a6d29b203c
3 changed files with 38 additions and 26 deletions

View File

@ -131,6 +131,20 @@ public class FervorClient {
return try await performRequest(request) 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 struct Auth {
public let accessToken: String public let accessToken: String
public let refreshToken: String? public let refreshToken: String?

View File

@ -87,36 +87,38 @@ class FervorController {
} }
@MainActor @MainActor
func syncReadToServer() async throws { func syncReadToServer() async {
var count = 0 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 // try to sync items which failed last time
let req = Item.fetchRequest() let req = Item.fetchRequest()
req.predicate = NSPredicate(format: "needsReadStateSync = YES") req.predicate = NSPredicate(format: "needsReadStateSync = YES")
if let needsSync = try? persistentContainer.viewContext.fetch(req) { if var needsSync = try? persistentContainer.viewContext.fetch(req) {
for item in needsSync { let firstReadIndex = needsSync.partition(by: \.read)
let f = item.read ? client.read(item:) : client.unread(item:) let unreadIDs = needsSync[..<firstReadIndex].map(\.id.unsafelyUnwrapped)
let readIDs = needsSync[firstReadIndex...].map(\.id.unsafelyUnwrapped)
var updatedIDs = Set<FervorID>()
if !unreadIDs.isEmpty {
do { do {
let _ = try await f(item.id!) let ids = try await client.unread(ids: unreadIDs)
count += 1 updatedIDs.formUnion(ids)
item.needsReadStateSync = false
} catch { } catch {
logger.error("Failed to sync read state again: \(String(describing: error), privacy: .public)") logger.error("Failed to sync unread state: \(String(describing: error), privacy: .public)")
item.needsReadStateSync = true
// todo: this should probably fail after a certain number of attempts
} }
} }
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") logger.info("Synced \(count, privacy: .public) read/unread to server")

View File

@ -81,11 +81,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
if let fervorController = fervorController { if let fervorController = fervorController {
Task(priority: .userInitiated) { Task(priority: .userInitiated) {
do { await fervorController.syncReadToServer()
try await fervorController.syncReadToServer()
} catch {
logger.error("Unable to sync read state to server: \(String(describing: error), privacy: .public)")
}
} }
} }
} }