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)
}
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?

View File

@ -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[..<firstReadIndex].map(\.id.unsafelyUnwrapped)
let readIDs = needsSync[firstReadIndex...].map(\.id.unsafelyUnwrapped)
var updatedIDs = Set<FervorID>()
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")

View File

@ -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()
}
}
}