Check the CloudKit schema when packaging and show broken iCloud sync
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import ByreAPI
|
||||
import CloudKit
|
||||
import CoreData
|
||||
import Foundation
|
||||
import Observation
|
||||
@@ -11,6 +13,7 @@ final class Servers {
|
||||
|
||||
private(set) var entries: [(origin: String, record: ServerRecord)] = []
|
||||
private(set) var connections: [String: Connection] = [:]
|
||||
private var syncs: [NSPersistentCloudKitContainer.EventType: ClientSync] = [:]
|
||||
var current: String?
|
||||
@ObservationIgnored var openWindow: (() -> Void)?
|
||||
|
||||
@@ -19,7 +22,11 @@ final class Servers {
|
||||
current = origins.first
|
||||
Task {
|
||||
for await note in NotificationCenter.default.notifications(named: NSPersistentCloudKitContainer.eventChangedNotification) {
|
||||
if let event = note.userInfo?[NSPersistentCloudKitContainer.eventNotificationUserInfoKey] as? NSPersistentCloudKitContainer.Event, event.type == .import, event.endDate != nil {
|
||||
guard let event = note.userInfo?[NSPersistentCloudKitContainer.eventNotificationUserInfoKey] as? NSPersistentCloudKitContainer.Event, let end = event.endDate else {
|
||||
continue
|
||||
}
|
||||
synced(event, end)
|
||||
if event.type == .import {
|
||||
for connection in connections.values {
|
||||
connection.store?.drafts?.reload()
|
||||
}
|
||||
@@ -29,6 +36,26 @@ final class Servers {
|
||||
}
|
||||
}
|
||||
|
||||
private func synced(_ event: NSPersistentCloudKitContainer.Event, _ end: Date) {
|
||||
let error = event.succeeded ? nil : syncError(event.error)
|
||||
if let error {
|
||||
log.error("icloud \(String(describing: event.type), privacy: .public) failed: \(error, privacy: .public)")
|
||||
}
|
||||
syncs[event.type] = ClientSync(ok: event.succeeded, error: error, at: end)
|
||||
guard let sync else {
|
||||
return
|
||||
}
|
||||
for connection in connections.values {
|
||||
connection.store?.reportSync(sync)
|
||||
}
|
||||
}
|
||||
|
||||
// A failed export stays the state until an export succeeds, whatever imports do meanwhile.
|
||||
var sync: ClientSync? {
|
||||
let failed = syncs.values.filter { !$0.ok }
|
||||
return (failed.isEmpty ? Array(syncs.values) : failed).max { $0.at < $1.at }
|
||||
}
|
||||
|
||||
var origins: [String] {
|
||||
entries.map(\.origin)
|
||||
}
|
||||
@@ -103,6 +130,17 @@ final class Servers {
|
||||
}
|
||||
}
|
||||
|
||||
private func syncError(_ error: (any Error)?) -> String {
|
||||
guard let error else {
|
||||
return "failed with no error"
|
||||
}
|
||||
let ns = error as NSError
|
||||
if let partial = ns.userInfo[CKPartialErrorsByItemIDKey] as? [AnyHashable: any Error], let first = partial.values.first {
|
||||
return "\(first.localizedDescription) (\(partial.count) records)"
|
||||
}
|
||||
return "\(ns.localizedDescription) (\(ns.domain) \(ns.code))"
|
||||
}
|
||||
|
||||
func serverName(_ origin: String) -> String {
|
||||
let host = URL(string: origin)?.host() ?? origin
|
||||
return host.split(separator: ".").first.map(String.init) ?? host
|
||||
|
||||
Reference in New Issue
Block a user