From 8f038acc1a99238318220608d7f41adc4dd2cd7d Mon Sep 17 00:00:00 2001 From: Mallory Paine Date: Mon, 28 Aug 2017 15:18:27 -0400 Subject: [PATCH] Cache the previous stable time --- Sources/Clock.swift | 23 +++++++++++++++++++++-- Sources/TimeFreeze.swift | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Sources/Clock.swift b/Sources/Clock.swift index dd5d5a1..ae66d8d 100644 --- a/Sources/Clock.swift +++ b/Sources/Clock.swift @@ -16,7 +16,16 @@ import Foundation /// ``` public struct Clock { - private static var stableTime: TimeFreeze? + private static let kDefaultsKey = "KronosStableTime" + + private static var stableTime: TimeFreeze? { + didSet { + guard let stableTime = self.stableTime else { + return + } + UserDefaults.standard.set(stableTime.toDictionary(), forKey: kDefaultsKey) + } + } /// The most accurate timestamp that we have so far (nil if no synchronization was done yet) public static var timestamp: TimeInterval? { @@ -42,7 +51,7 @@ public struct Clock { first: ((Date, TimeInterval) -> Void)? = nil, completion: ((Date?, TimeInterval?) -> Void)? = nil) { - self.reset() + self.loadFromDefaults() NTPClient().query(pool: pool, numberOfSamples: samples) { offset, done, total in if let offset = offset { @@ -64,4 +73,14 @@ public struct Clock { public static func reset() { self.stableTime = nil } + + private static func loadFromDefaults() { + guard let stored = UserDefaults.standard.value(forKey: kDefaultsKey) as? [String: TimeInterval], + let previousStableTime = TimeFreeze(from: stored) else + { + self.stableTime = nil + return + } + self.stableTime = previousStableTime + } } diff --git a/Sources/TimeFreeze.swift b/Sources/TimeFreeze.swift index 00311ef..bf39734 100644 --- a/Sources/TimeFreeze.swift +++ b/Sources/TimeFreeze.swift @@ -1,5 +1,9 @@ import Foundation +private let kUptimeKey = "Uptime" +private let kTimestampKey = "Timestamp" +private let kOffsetKey = "Offset" + struct TimeFreeze { private let uptime: TimeInterval private let timestamp: TimeInterval @@ -22,6 +26,35 @@ struct TimeFreeze { self.uptime = TimeFreeze.systemUptime() } + init?(from dictionary: [String: TimeInterval]) { + guard let uptime = dictionary[kUptimeKey], let timestamp = dictionary[kTimestampKey], + let offset = dictionary[kOffsetKey] else + { + return nil + } + + let currentBoot = TimeFreeze.systemUptime() - currentTime() + let previousBoot = uptime - timestamp + if rint(currentBoot) - rint(previousBoot) != 0 { + return nil + } + + self.uptime = uptime + self.timestamp = timestamp + self.offset = offset + } + + /// Convert this TimeFreeze to a dictionary representation. + /// + /// - returns: A dictionary representation. + func toDictionary() -> [String: TimeInterval] { + return [ + kUptimeKey: self.uptime, + kTimestampKey: self.timestamp, + kOffsetKey: self.offset, + ] + } + /// Returns a high-resolution measurement of system uptime, that continues ticking through device sleep /// *and* user- or system-generated clock adjustments. This allows for stable differences to be calculated /// between timestamps.