| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- import Combine
- import Foundation
- import SwiftDate
- import Swinject
- protocol FetchGlucoseManager: SourceInfoProvider {}
- final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
- private let processQueue = DispatchQueue(label: "BaseGlucoseManager.processQueue")
- @Injected() var glucoseStorage: GlucoseStorage!
- @Injected() var nightscoutManager: NightscoutManager!
- @Injected() var apsManager: APSManager!
- @Injected() var settingsManager: SettingsManager!
- @Injected() var libreTransmitter: LibreTransmitterSource!
- @Injected() var healthKitManager: HealthKitManager!
- @Injected() var deviceDataManager: DeviceDataManager!
- private var lifetime = Lifetime()
- private let timer = DispatchTimer(timeInterval: 1.minutes.timeInterval)
- private lazy var appGroupSource = AppGroupSource()
- private lazy var dexcomSource = DexcomSource()
- private lazy var simulatorSource = GlucoseSimulatorSource()
- init(resolver: Resolver) {
- injectServices(resolver)
- updateGlucoseSource()
- subscribe()
- }
- var glucoseSource: GlucoseSource!
- private func updateGlucoseSource() {
- switch settingsManager.settings.cgm {
- case .xdrip:
- glucoseSource = appGroupSource
- case .dexcomG5,
- .dexcomG6:
- glucoseSource = dexcomSource
- case .nightscout:
- glucoseSource = nightscoutManager
- case .simulator:
- glucoseSource = simulatorSource
- case .libreTransmitter:
- glucoseSource = libreTransmitter
- case .glucoseDirect:
- glucoseSource = appGroupSource
- case .enlite:
- glucoseSource = deviceDataManager
- }
- if settingsManager.settings.cgm != .libreTransmitter {
- libreTransmitter.manager = nil
- }
- }
- private func subscribe() {
- timer.publisher
- .receive(on: processQueue)
- .flatMap { date -> AnyPublisher<(Date, Date, [BloodGlucose], [BloodGlucose]), Never> in
- debug(.nightscout, "FetchGlucoseManager heartbeat")
- debug(.nightscout, "Start fetching glucose")
- self.updateGlucoseSource()
- return Publishers.CombineLatest4(
- Just(date),
- Just(self.glucoseStorage.syncDate()),
- self.glucoseSource.fetch(),
- self.healthKitManager.fetch()
- )
- .eraseToAnyPublisher()
- }
- .sink { date, syncDate, glucose, glucoseFromHealth in
- let allGlucose = glucose + glucoseFromHealth
- guard allGlucose.isNotEmpty else { return }
- // Because of Spike dosn't respect a date query
- let filteredByDate = allGlucose.filter { $0.dateString > syncDate }
- let filtered = self.glucoseStorage.filterTooFrequentGlucose(filteredByDate, at: syncDate)
- guard filtered.isNotEmpty else { return }
- debug(.nightscout, "New glucose found")
- self.glucoseStorage.storeGlucose(filtered)
- self.apsManager.heartbeat(date: date, force: false)
- self.nightscoutManager.uploadGlucose()
- let glucoseForHealth = filteredByDate.filter { !glucoseFromHealth.contains($0) }
- guard glucoseForHealth.isNotEmpty else { return }
- self.healthKitManager.save(bloodGlucoses: glucoseForHealth, completion: nil)
- }
- .store(in: &lifetime)
- timer.fire()
- timer.resume()
- UserDefaults.standard
- .publisher(for: \.dexcomTransmitterID)
- .removeDuplicates()
- .sink { id in
- guard [.dexcomG5, .dexcomG6].contains(self.settingsManager.settings.cgm) else { return }
- if id != self.dexcomSource.transmitterID {
- self.dexcomSource = DexcomSource()
- }
- }
- .store(in: &lifetime)
- }
- func sourceInfo() -> [String: Any]? {
- glucoseSource.sourceInfo()
- }
- }
- extension UserDefaults {
- @objc var dexcomTransmitterID: String? {
- get {
- string(forKey: "DexcomSource.transmitterID")?.nonEmpty
- }
- set {
- set(newValue, forKey: "DexcomSource.transmitterID")
- }
- }
- }
|