|
@@ -126,26 +126,174 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
|
|
|
private var lastEnactedDetermination: Determination?
|
|
private var lastEnactedDetermination: Determination?
|
|
|
private var lastSuggestedDetermination: Determination?
|
|
private var lastSuggestedDetermination: Determination?
|
|
|
|
|
|
|
|
- // Queue for handling Core Data change notifications
|
|
|
|
|
- let queue = DispatchQueue(label: "BaseNightscoutManager.queue", qos: .utility)
|
|
|
|
|
-
|
|
|
|
|
- /// Emits changed Core Data object IDs from the app. We filter by entity names
|
|
|
|
|
- /// and request upload pipelines based on what changed.
|
|
|
|
|
- var coreDataPublisher: AnyPublisher<Set<NSManagedObjectID>, Never>?
|
|
|
|
|
-
|
|
|
|
|
/// Bag for Combine subscriptions owned by this manager.
|
|
/// Bag for Combine subscriptions owned by this manager.
|
|
|
var subscriptions = Set<AnyCancellable>()
|
|
var subscriptions = Set<AnyCancellable>()
|
|
|
|
|
|
|
|
|
|
+ let viewContext = CoreDataStack.shared.persistentContainer.viewContext
|
|
|
|
|
+
|
|
|
|
|
+ // MARK: - Upload triggers
|
|
|
|
|
+
|
|
|
|
|
+ //
|
|
|
|
|
+ // Each upload pipeline is driven by an NSFetchedResultsController whose predicate is the
|
|
|
|
|
+ // "not yet uploaded to Nightscout" set for that entity. The controller fires whenever
|
|
|
|
|
+ // un-uploaded items appear (or drop out after a successful upload), which we map to a
|
|
|
|
|
+ // `requestUpload(pipeline)` call (throttled per pipeline). Bound to the viewContext, they
|
|
|
|
|
+ // also pick up batch-inserted glucose via the persistent history merge in CoreDataStack —
|
|
|
|
|
+ // replacing the previous changedObjects publisher plus the glucoseStorage.updatePublisher
|
|
|
|
|
+ // fallback.
|
|
|
|
|
+
|
|
|
|
|
+ let determinationUploadControllerDelegate = FetchedResultsControllerDelegate()
|
|
|
|
|
+ lazy var determinationUploadController: NSFetchedResultsController<OrefDetermination> = {
|
|
|
|
|
+ let request = NSFetchRequest<OrefDetermination>(entityName: "OrefDetermination")
|
|
|
|
|
+ request.sortDescriptors = [NSSortDescriptor(keyPath: \OrefDetermination.deliverAt, ascending: true)]
|
|
|
|
|
+ request.predicate = NSPredicate(
|
|
|
|
|
+ format: "deliverAt >= %@ AND isUploadedToNS == %@",
|
|
|
|
|
+ Date.oneDayAgo as NSDate,
|
|
|
|
|
+ false as NSNumber
|
|
|
|
|
+ )
|
|
|
|
|
+ request.fetchBatchSize = 50
|
|
|
|
|
+ let controller = NSFetchedResultsController(
|
|
|
|
|
+ fetchRequest: request,
|
|
|
|
|
+ managedObjectContext: viewContext,
|
|
|
|
|
+ sectionNameKeyPath: nil,
|
|
|
|
|
+ cacheName: nil
|
|
|
|
|
+ )
|
|
|
|
|
+ controller.delegate = determinationUploadControllerDelegate
|
|
|
|
|
+ return controller
|
|
|
|
|
+ }()
|
|
|
|
|
+
|
|
|
|
|
+ let overrideUploadControllerDelegate = FetchedResultsControllerDelegate()
|
|
|
|
|
+ lazy var overrideUploadController: NSFetchedResultsController<OverrideStored> = {
|
|
|
|
|
+ let request = NSFetchRequest<OverrideStored>(entityName: "OverrideStored")
|
|
|
|
|
+ request.sortDescriptors = [NSSortDescriptor(keyPath: \OverrideStored.date, ascending: true)]
|
|
|
|
|
+ request.predicate = NSPredicate(
|
|
|
|
|
+ format: "date >= %@ AND isUploadedToNS == %@",
|
|
|
|
|
+ Date.oneDayAgo as NSDate,
|
|
|
|
|
+ false as NSNumber
|
|
|
|
|
+ )
|
|
|
|
|
+ let controller = NSFetchedResultsController(
|
|
|
|
|
+ fetchRequest: request,
|
|
|
|
|
+ managedObjectContext: viewContext,
|
|
|
|
|
+ sectionNameKeyPath: nil,
|
|
|
|
|
+ cacheName: nil
|
|
|
|
|
+ )
|
|
|
|
|
+ controller.delegate = overrideUploadControllerDelegate
|
|
|
|
|
+ return controller
|
|
|
|
|
+ }()
|
|
|
|
|
+
|
|
|
|
|
+ let overrideRunUploadControllerDelegate = FetchedResultsControllerDelegate()
|
|
|
|
|
+ lazy var overrideRunUploadController: NSFetchedResultsController<OverrideRunStored> = {
|
|
|
|
|
+ let request = NSFetchRequest<OverrideRunStored>(entityName: "OverrideRunStored")
|
|
|
|
|
+ request.sortDescriptors = [NSSortDescriptor(keyPath: \OverrideRunStored.startDate, ascending: true)]
|
|
|
|
|
+ request.predicate = NSPredicate(
|
|
|
|
|
+ format: "startDate >= %@ AND isUploadedToNS == %@",
|
|
|
|
|
+ Date.oneDayAgo as NSDate,
|
|
|
|
|
+ false as NSNumber
|
|
|
|
|
+ )
|
|
|
|
|
+ let controller = NSFetchedResultsController(
|
|
|
|
|
+ fetchRequest: request,
|
|
|
|
|
+ managedObjectContext: viewContext,
|
|
|
|
|
+ sectionNameKeyPath: nil,
|
|
|
|
|
+ cacheName: nil
|
|
|
|
|
+ )
|
|
|
|
|
+ controller.delegate = overrideRunUploadControllerDelegate
|
|
|
|
|
+ return controller
|
|
|
|
|
+ }()
|
|
|
|
|
+
|
|
|
|
|
+ let tempTargetUploadControllerDelegate = FetchedResultsControllerDelegate()
|
|
|
|
|
+ lazy var tempTargetUploadController: NSFetchedResultsController<TempTargetStored> = {
|
|
|
|
|
+ let request = NSFetchRequest<TempTargetStored>(entityName: "TempTargetStored")
|
|
|
|
|
+ request.sortDescriptors = [NSSortDescriptor(keyPath: \TempTargetStored.date, ascending: true)]
|
|
|
|
|
+ request.predicate = NSPredicate(
|
|
|
|
|
+ format: "date >= %@ AND isUploadedToNS == %@",
|
|
|
|
|
+ Date.oneDayAgo as NSDate,
|
|
|
|
|
+ false as NSNumber
|
|
|
|
|
+ )
|
|
|
|
|
+ let controller = NSFetchedResultsController(
|
|
|
|
|
+ fetchRequest: request,
|
|
|
|
|
+ managedObjectContext: viewContext,
|
|
|
|
|
+ sectionNameKeyPath: nil,
|
|
|
|
|
+ cacheName: nil
|
|
|
|
|
+ )
|
|
|
|
|
+ controller.delegate = tempTargetUploadControllerDelegate
|
|
|
|
|
+ return controller
|
|
|
|
|
+ }()
|
|
|
|
|
+
|
|
|
|
|
+ let tempTargetRunUploadControllerDelegate = FetchedResultsControllerDelegate()
|
|
|
|
|
+ lazy var tempTargetRunUploadController: NSFetchedResultsController<TempTargetRunStored> = {
|
|
|
|
|
+ let request = NSFetchRequest<TempTargetRunStored>(entityName: "TempTargetRunStored")
|
|
|
|
|
+ request.sortDescriptors = [NSSortDescriptor(keyPath: \TempTargetRunStored.startDate, ascending: true)]
|
|
|
|
|
+ request.predicate = NSPredicate(
|
|
|
|
|
+ format: "startDate >= %@ AND isUploadedToNS == %@",
|
|
|
|
|
+ Date.oneDayAgo as NSDate,
|
|
|
|
|
+ false as NSNumber
|
|
|
|
|
+ )
|
|
|
|
|
+ let controller = NSFetchedResultsController(
|
|
|
|
|
+ fetchRequest: request,
|
|
|
|
|
+ managedObjectContext: viewContext,
|
|
|
|
|
+ sectionNameKeyPath: nil,
|
|
|
|
|
+ cacheName: nil
|
|
|
|
|
+ )
|
|
|
|
|
+ controller.delegate = tempTargetRunUploadControllerDelegate
|
|
|
|
|
+ return controller
|
|
|
|
|
+ }()
|
|
|
|
|
+
|
|
|
|
|
+ let pumpEventUploadControllerDelegate = FetchedResultsControllerDelegate()
|
|
|
|
|
+ lazy var pumpEventUploadController: NSFetchedResultsController<PumpEventStored> = {
|
|
|
|
|
+ let request = NSFetchRequest<PumpEventStored>(entityName: "PumpEventStored")
|
|
|
|
|
+ request.sortDescriptors = [NSSortDescriptor(keyPath: \PumpEventStored.timestamp, ascending: true)]
|
|
|
|
|
+ request.predicate = NSPredicate.pumpEventsNotYetUploadedToNightscout
|
|
|
|
|
+ request.fetchBatchSize = 50
|
|
|
|
|
+ let controller = NSFetchedResultsController(
|
|
|
|
|
+ fetchRequest: request,
|
|
|
|
|
+ managedObjectContext: viewContext,
|
|
|
|
|
+ sectionNameKeyPath: nil,
|
|
|
|
|
+ cacheName: nil
|
|
|
|
|
+ )
|
|
|
|
|
+ controller.delegate = pumpEventUploadControllerDelegate
|
|
|
|
|
+ return controller
|
|
|
|
|
+ }()
|
|
|
|
|
+
|
|
|
|
|
+ let carbEntryUploadControllerDelegate = FetchedResultsControllerDelegate()
|
|
|
|
|
+ lazy var carbEntryUploadController: NSFetchedResultsController<CarbEntryStored> = {
|
|
|
|
|
+ let request = NSFetchRequest<CarbEntryStored>(entityName: "CarbEntryStored")
|
|
|
|
|
+ request.sortDescriptors = [NSSortDescriptor(keyPath: \CarbEntryStored.date, ascending: true)]
|
|
|
|
|
+ request.predicate = NSPredicate(
|
|
|
|
|
+ format: "date >= %@ AND isUploadedToNS == %@",
|
|
|
|
|
+ Date.oneDayAgo as NSDate,
|
|
|
|
|
+ false as NSNumber
|
|
|
|
|
+ )
|
|
|
|
|
+ request.fetchBatchSize = 50
|
|
|
|
|
+ let controller = NSFetchedResultsController(
|
|
|
|
|
+ fetchRequest: request,
|
|
|
|
|
+ managedObjectContext: viewContext,
|
|
|
|
|
+ sectionNameKeyPath: nil,
|
|
|
|
|
+ cacheName: nil
|
|
|
|
|
+ )
|
|
|
|
|
+ controller.delegate = carbEntryUploadControllerDelegate
|
|
|
|
|
+ return controller
|
|
|
|
|
+ }()
|
|
|
|
|
+
|
|
|
|
|
+ let glucoseUploadControllerDelegate = FetchedResultsControllerDelegate()
|
|
|
|
|
+ lazy var glucoseUploadController: NSFetchedResultsController<GlucoseStored> = {
|
|
|
|
|
+ let request = NSFetchRequest<GlucoseStored>(entityName: "GlucoseStored")
|
|
|
|
|
+ request.sortDescriptors = [NSSortDescriptor(keyPath: \GlucoseStored.date, ascending: true)]
|
|
|
|
|
+ request.predicate = NSPredicate.glucoseNotYetUploadedToNightscout
|
|
|
|
|
+ request.fetchBatchSize = 50
|
|
|
|
|
+ let controller = NSFetchedResultsController(
|
|
|
|
|
+ fetchRequest: request,
|
|
|
|
|
+ managedObjectContext: viewContext,
|
|
|
|
|
+ sectionNameKeyPath: nil,
|
|
|
|
|
+ cacheName: nil
|
|
|
|
|
+ )
|
|
|
|
|
+ controller.delegate = glucoseUploadControllerDelegate
|
|
|
|
|
+ return controller
|
|
|
|
|
+ }()
|
|
|
|
|
+
|
|
|
init(resolver: Resolver) {
|
|
init(resolver: Resolver) {
|
|
|
injectServices(resolver)
|
|
injectServices(resolver)
|
|
|
subscribe()
|
|
subscribe()
|
|
|
|
|
|
|
|
- coreDataPublisher =
|
|
|
|
|
- changedObjectsOnManagedObjectContextDidSavePublisher()
|
|
|
|
|
- .receive(on: queue)
|
|
|
|
|
- .share()
|
|
|
|
|
- .eraseToAnyPublisher()
|
|
|
|
|
-
|
|
|
|
|
setupNotification()
|
|
setupNotification()
|
|
|
|
|
|
|
|
setupLanePipelines()
|
|
setupLanePipelines()
|