TrioRemoteControl+Meal.swift 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import Foundation
  2. extension TrioRemoteControl {
  3. func handleMealCommand(_ pushMessage: PushMessage) async throws {
  4. guard pushMessage.carbs != nil || pushMessage.fat != nil || pushMessage.protein != nil else {
  5. await logError("Command rejected: meal data is incomplete or invalid.", pushMessage: pushMessage)
  6. return
  7. }
  8. let carbsDecimal = pushMessage.carbs != nil ? Decimal(pushMessage.carbs!) : nil
  9. let fatDecimal = pushMessage.fat != nil ? Decimal(pushMessage.fat!) : nil
  10. let proteinDecimal = pushMessage.protein != nil ? Decimal(pushMessage.protein!) : nil
  11. let settings = await TrioApp.resolver.resolve(SettingsManager.self)?.settings
  12. let maxCarbs = settings?.maxCarbs ?? Decimal(0)
  13. let maxFat = settings?.maxFat ?? Decimal(0)
  14. let maxProtein = settings?.maxProtein ?? Decimal(0)
  15. if let carbs = carbsDecimal, carbs > maxCarbs {
  16. await logError(
  17. "Command rejected: carbs amount (\(carbs)g) exceeds the maximum allowed (\(maxCarbs)g).",
  18. pushMessage: pushMessage
  19. )
  20. return
  21. }
  22. if let fat = fatDecimal, fat > maxFat {
  23. await logError(
  24. "Command rejected: fat amount (\(fat)g) exceeds the maximum allowed (\(maxFat)g).",
  25. pushMessage: pushMessage
  26. )
  27. return
  28. }
  29. if let protein = proteinDecimal, protein > maxProtein {
  30. await logError(
  31. "Command rejected: protein amount (\(protein)g) exceeds the maximum allowed (\(maxProtein)g).",
  32. pushMessage: pushMessage
  33. )
  34. return
  35. }
  36. let pushMessageDate = Date(timeIntervalSince1970: pushMessage.timestamp)
  37. let taskContext = CoreDataStack.shared.newTaskContext()
  38. let results = try await CoreDataStack.shared.fetchEntitiesAsync(
  39. ofType: CarbEntryStored.self,
  40. onContext: taskContext,
  41. predicate: NSPredicate(format: "date > %@", pushMessageDate as NSDate),
  42. key: "date",
  43. ascending: false
  44. )
  45. await taskContext.perform {
  46. guard let recentCarbEntries = results as? [CarbEntryStored] else { return }
  47. if !recentCarbEntries.isEmpty {
  48. Task {
  49. await self.logError(
  50. "Command rejected: newer carb entries have been logged since the command was sent.",
  51. pushMessage: pushMessage
  52. )
  53. return
  54. }
  55. }
  56. }
  57. let actualDate: Date?
  58. if let scheduledTime = pushMessage.scheduledTime {
  59. actualDate = Date(timeIntervalSince1970: scheduledTime)
  60. } else {
  61. actualDate = nil
  62. }
  63. let mealEntry = CarbsEntry(
  64. id: UUID().uuidString,
  65. createdAt: Date(),
  66. actualDate: actualDate,
  67. carbs: carbsDecimal ?? 0,
  68. fat: fatDecimal,
  69. protein: proteinDecimal,
  70. note: "Remote meal command",
  71. enteredBy: CarbsEntry.local,
  72. isFPU: false,
  73. fpuID: fatDecimal ?? 0 > 0 || proteinDecimal ?? 0 > 0 ? UUID().uuidString : nil
  74. )
  75. try await carbsStorage.storeCarbs([mealEntry], areFetchedFromRemote: false)
  76. // Only send success notification if there's no bolus
  77. // If there's a bolus, the bolus handler will send the notification
  78. if pushMessage.bolusAmount == nil {
  79. await logSuccess(
  80. "Remote command processed successfully. \(pushMessage.humanReadableDescription())",
  81. pushMessage: pushMessage
  82. )
  83. }
  84. }
  85. }