Use batch update endpoint for marking items (un)read
This commit is contained in:
parent
c41a81414d
commit
a6d29b203c
|
@ -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?
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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)")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue