AppGroupSource.swift 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import Combine
  2. import Foundation
  3. struct AppGroupSource: GlucoseSource {
  4. let from: String
  5. func fetch() -> AnyPublisher<[BloodGlucose], Never> {
  6. guard let suiteName = Bundle.main.appGroupSuiteName,
  7. let sharedDefaults = UserDefaults(suiteName: suiteName)
  8. else {
  9. return Just([]).eraseToAnyPublisher()
  10. }
  11. return Just(fetchLastBGs(60, sharedDefaults)).eraseToAnyPublisher()
  12. }
  13. private func fetchLastBGs(_ count: Int, _ sharedDefaults: UserDefaults) -> [BloodGlucose] {
  14. guard let sharedData = sharedDefaults.data(forKey: "latestReadings") else {
  15. return []
  16. }
  17. let decoded = try? JSONSerialization.jsonObject(with: sharedData, options: [])
  18. guard let sgvs = decoded as? [AnyObject] else {
  19. return []
  20. }
  21. var results: [BloodGlucose] = []
  22. for sgv in sgvs.prefix(count) {
  23. guard
  24. let glucose = sgv["Value"] as? Int,
  25. let direction = sgv["direction"] as? String,
  26. let timestamp = sgv["DT"] as? String,
  27. let date = parseDate(timestamp)
  28. else { continue }
  29. if let from = sgv["from"] as? String {
  30. guard from == self.from else { continue }
  31. }
  32. results.append(
  33. BloodGlucose(
  34. sgv: glucose,
  35. direction: BloodGlucose.Direction(rawValue: direction),
  36. date: Decimal(Int(date.timeIntervalSince1970 * 1000)),
  37. dateString: date,
  38. unfiltered: nil,
  39. filtered: nil,
  40. noise: nil,
  41. glucose: glucose,
  42. type: "sgv"
  43. )
  44. )
  45. }
  46. return results
  47. }
  48. private func parseDate(_ timestamp: String) -> Date? {
  49. // timestamp looks like "/Date(1462404576000)/"
  50. guard let re = try? NSRegularExpression(pattern: "\\((.*)\\)"),
  51. let match = re.firstMatch(in: timestamp, range: NSMakeRange(0, timestamp.count))
  52. else {
  53. return nil
  54. }
  55. let matchRange = match.range(at: 1)
  56. let epoch = Double((timestamp as NSString).substring(with: matchRange))! / 1000
  57. return Date(timeIntervalSince1970: epoch)
  58. }
  59. func sourceInfo() -> [String: Any]? {
  60. [GlucoseSourceKey.description.rawValue: "Group ID: \(Bundle.main.appGroupSuiteName ?? "Not set"))"]
  61. }
  62. }
  63. public extension Bundle {
  64. var appGroupSuiteName: String? {
  65. object(forInfoDictionaryKey: "AppGroupID") as? String
  66. }
  67. }