AlertStorage.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import Combine
  2. import Foundation
  3. import SwiftDate
  4. import Swinject
  5. protocol AlertObserver {
  6. func AlertDidUpdate(_ alerts: [AlertEntry])
  7. }
  8. protocol AlertHistoryStorage {
  9. func storeAlert(_ alerts: AlertEntry)
  10. func syncDate() -> Date
  11. func recentNotAck() -> [AlertEntry]
  12. func deleteAlert(identifier: String)
  13. func ackAlert(_ alert: Date, _ error: String?)
  14. func forceNotification()
  15. var alertNotAck: PassthroughSubject<Bool, Never> { get }
  16. }
  17. final class BaseAlertHistoryStorage: AlertHistoryStorage, Injectable {
  18. private let processQueue = DispatchQueue.markedQueue(label: "BaseAlertsStorage.processQueue")
  19. @Injected() private var storage: FileStorage!
  20. @Injected() private var broadcaster: Broadcaster!
  21. let alertNotAck = PassthroughSubject<Bool, Never>()
  22. init(resolver: Resolver) {
  23. injectServices(resolver)
  24. alertNotAck.send(recentNotAck().isNotEmpty)
  25. }
  26. func storeAlert(_ alert: AlertEntry) {
  27. processQueue.sync {
  28. let file = OpenAPS.Monitor.alertHistory
  29. var uniqEvents: [AlertEntry] = []
  30. self.storage.transaction { storage in
  31. storage.append(alert, to: file, uniqBy: \.issuedDate)
  32. uniqEvents = storage.retrieve(file, as: [AlertEntry].self)?
  33. .filter { $0.issuedDate.addingTimeInterval(1.days.timeInterval) > Date() }
  34. .sorted { $0.issuedDate > $1.issuedDate } ?? []
  35. storage.save(Array(uniqEvents), as: file)
  36. }
  37. alertNotAck.send(self.recentNotAck().isNotEmpty)
  38. broadcaster.notify(AlertObserver.self, on: processQueue) {
  39. $0.AlertDidUpdate(uniqEvents)
  40. }
  41. }
  42. }
  43. func syncDate() -> Date {
  44. Date().addingTimeInterval(-1.days.timeInterval)
  45. }
  46. func recentNotAck() -> [AlertEntry] {
  47. storage.retrieve(OpenAPS.Monitor.alertHistory, as: [AlertEntry].self)?
  48. .filter { $0.issuedDate.addingTimeInterval(1.days.timeInterval) > Date() && $0.acknowledgedDate == nil }
  49. .sorted { $0.issuedDate > $1.issuedDate } ?? []
  50. }
  51. func ackAlert(_ alert: Date, _ error: String?) {
  52. processQueue.sync {
  53. var allValues = storage.retrieve(OpenAPS.Monitor.alertHistory, as: [AlertEntry].self) ?? []
  54. guard let entryIndex = allValues.firstIndex(where: { $0.issuedDate == alert }) else {
  55. return
  56. }
  57. if let error {
  58. allValues[entryIndex].errorMessage = error
  59. } else {
  60. allValues[entryIndex].acknowledgedDate = Date()
  61. }
  62. storage.save(allValues, as: OpenAPS.Monitor.alertHistory)
  63. alertNotAck.send(self.recentNotAck().isNotEmpty)
  64. }
  65. }
  66. func deleteAlert(identifier: String) {
  67. processQueue.sync {
  68. var allValues = storage.retrieve(OpenAPS.Monitor.alertHistory, as: [AlertEntry].self) ?? []
  69. guard let entryIndex = allValues.firstIndex(where: { $0.alertIdentifier == identifier }) else {
  70. return
  71. }
  72. allValues.remove(at: entryIndex)
  73. storage.save(allValues, as: OpenAPS.Monitor.alertHistory)
  74. alertNotAck.send(self.recentNotAck().isNotEmpty)
  75. broadcaster.notify(AlertObserver.self, on: processQueue) {
  76. $0.AlertDidUpdate(allValues)
  77. }
  78. }
  79. }
  80. func forceNotification() {
  81. processQueue.sync {
  82. let uniqEvents = storage.retrieve(OpenAPS.Monitor.alertHistory, as: [AlertEntry].self)?
  83. .filter { $0.issuedDate.addingTimeInterval(1.days.timeInterval) > Date() }
  84. .sorted { $0.issuedDate > $1.issuedDate } ?? []
  85. alertNotAck.send(self.recentNotAck().isNotEmpty)
  86. broadcaster.notify(AlertObserver.self, on: processQueue) {
  87. $0.AlertDidUpdate(uniqEvents)
  88. }
  89. }
  90. }
  91. }