FetchGlucoseManager.swift 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import Combine
  2. import Foundation
  3. import SwiftDate
  4. import Swinject
  5. protocol FetchGlucoseManager {}
  6. final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
  7. private let processQueue = DispatchQueue(label: "BaseGlucoseManager.processQueue")
  8. @Injected() var glucoseStorage: GlucoseStorage!
  9. @Injected() var nightscoutManager: NightscoutManager!
  10. @Injected() var apsManager: APSManager!
  11. @Injected() var settingsManager: SettingsManager!
  12. private var lifetime = Lifetime()
  13. private let timer = DispatchTimer(timeInterval: 1.minutes.timeInterval)
  14. private lazy var appGroupSource = AppGroupSource()
  15. private lazy var dexcomSource = DexcomSource()
  16. init(resolver: Resolver) {
  17. injectServices(resolver)
  18. updateGlucoseSource()
  19. subscribe()
  20. }
  21. var glucoseSource: GlucoseSource!
  22. private func updateGlucoseSource() {
  23. switch settingsManager.settings.cgm {
  24. case .xdrip:
  25. glucoseSource = appGroupSource
  26. case .dexcomG5,
  27. .dexcomG6:
  28. glucoseSource = dexcomSource
  29. case .nightscout,
  30. .none:
  31. glucoseSource = nightscoutManager
  32. }
  33. }
  34. private func subscribe() {
  35. timer.publisher
  36. .receive(on: processQueue)
  37. .flatMap { date -> AnyPublisher<(Date, Date, [BloodGlucose]), Never> in
  38. debug(.nightscout, "FetchGlucoseManager heartbeat")
  39. debug(.nightscout, "Start fetching glucose")
  40. self.updateGlucoseSource()
  41. return Publishers.CombineLatest3(
  42. Just(date),
  43. Just(self.glucoseStorage.syncDate()),
  44. self.glucoseSource.fetch()
  45. )
  46. .eraseToAnyPublisher()
  47. }
  48. .sink { date, syncDate, glucose in
  49. // Because of Spike dosn't respect a date query
  50. let filteredByDate = glucose.filter { $0.dateString > syncDate }
  51. let filtered = self.glucoseStorage.filterTooFrequentGlucose(filteredByDate, at: syncDate)
  52. if !filtered.isEmpty {
  53. debug(.nightscout, "New glucose found")
  54. self.glucoseStorage.storeGlucose(filtered)
  55. self.apsManager.heartbeat(date: date, force: false)
  56. self.nightscoutManager.uploadGlucose()
  57. }
  58. }
  59. .store(in: &lifetime)
  60. timer.fire()
  61. timer.resume()
  62. UserDefaults.standard
  63. .publisher(for: \.dexcomTransmitterID)
  64. .removeDuplicates()
  65. .sink { id in
  66. if id != self.dexcomSource.transmitterID {
  67. self.dexcomSource = DexcomSource()
  68. }
  69. }
  70. .store(in: &lifetime)
  71. }
  72. }
  73. extension UserDefaults {
  74. @objc var dexcomTransmitterID: String? {
  75. get {
  76. string(forKey: "DexcomSource.transmitterID")?.nonEmpty
  77. }
  78. set {
  79. set(newValue, forKey: "DexcomSource.transmitterID")
  80. }
  81. }
  82. }