GlucoseStorage.swift 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import Foundation
  2. import SwiftDate
  3. import Swinject
  4. protocol GlucoseStorage {
  5. func storeGlucose(_ glucose: [BloodGlucose])
  6. func recent() -> [BloodGlucose]
  7. func syncDate() -> Date
  8. func filterTooFrequentGlucose(_ glucose: [BloodGlucose], at: Date) -> [BloodGlucose]
  9. func lastGlucoseDate() -> Date
  10. func isGlucoseFresh() -> Bool
  11. }
  12. final class BaseGlucoseStorage: GlucoseStorage, Injectable {
  13. private let processQueue = DispatchQueue(label: "BaseGlucoseStorage.processQueue")
  14. @Injected() private var storage: FileStorage!
  15. @Injected() private var broadcaster: Broadcaster!
  16. private enum Config {
  17. static let filterTime: TimeInterval = 4.75 * 60
  18. }
  19. init(resolver: Resolver) {
  20. injectServices(resolver)
  21. }
  22. func storeGlucose(_ glucose: [BloodGlucose]) {
  23. processQueue.sync {
  24. let file = OpenAPS.Monitor.glucose
  25. self.storage.transaction { storage in
  26. storage.append(glucose, to: file, uniqBy: \.dateString)
  27. let uniqEvents = storage.retrieve(file, as: [BloodGlucose].self)?
  28. .filter { $0.dateString.addingTimeInterval(1.days.timeInterval) > Date() }
  29. .sorted { $0.dateString > $1.dateString } ?? []
  30. let glucose = Array(uniqEvents)
  31. storage.save(glucose, as: file)
  32. DispatchQueue.main.async {
  33. self.broadcaster.notify(GlucoseObserver.self, on: .main) {
  34. $0.glucoseDidUpdate(glucose.reversed())
  35. }
  36. }
  37. }
  38. }
  39. }
  40. func syncDate() -> Date {
  41. guard let events = storage.retrieve(OpenAPS.Monitor.glucose, as: [BloodGlucose].self),
  42. let recent = events.first
  43. else {
  44. return Date().addingTimeInterval(-1.days.timeInterval)
  45. }
  46. return recent.dateString
  47. }
  48. func recent() -> [BloodGlucose] {
  49. storage.retrieve(OpenAPS.Monitor.glucose, as: [BloodGlucose].self)?.reversed() ?? []
  50. }
  51. func lastGlucoseDate() -> Date {
  52. recent().last?.dateString ?? .distantPast
  53. }
  54. func isGlucoseFresh() -> Bool {
  55. Date().timeIntervalSince(lastGlucoseDate()) <= Config.filterTime
  56. }
  57. func filterTooFrequentGlucose(_ glucose: [BloodGlucose], at date: Date) -> [BloodGlucose] {
  58. var lastDate = date
  59. var filtered: [BloodGlucose] = []
  60. for entry in glucose.reversed() {
  61. guard entry.dateString.addingTimeInterval(-Config.filterTime) > lastDate else {
  62. continue
  63. }
  64. filtered.append(entry)
  65. lastDate = entry.dateString
  66. }
  67. return filtered
  68. }
  69. }
  70. protocol GlucoseObserver {
  71. func glucoseDidUpdate(_ glucose: [BloodGlucose])
  72. }