Commit 9c6caa7b by Dmitriy Stepanets

Finished API

parent f301fe0f
...@@ -31,16 +31,43 @@ public class BlendMinutelySource: MinutelyForecastSource { ...@@ -31,16 +31,43 @@ public class BlendMinutelySource: MinutelyForecastSource {
fmt.dateFormat = "yyyy-MM-dd'T'hh:mm:ss.sss'Z'" fmt.dateFormat = "yyyy-MM-dd'T'hh:mm:ss.sss'Z'"
return fmt return fmt
}() }()
/// This queue is needed to synchronize access to locationsBeingUpdated. Also, to make logging more clear.
private let internalQueue: OperationQueue = {
let queue = OperationQueue()
queue.name = "BlendMinutelySource Queue"
queue.maxConcurrentOperationCount = 1
return queue
}()
private var locationsBeingUpdated = Set<Location>()
//Public //Public
#if DEBUG #if DEBUG
public let healthUpdateInterval = TimeInterval(2 * 60) // 2 minutes public let minutelyUpdateInterval = TimeInterval(2 * 60) // 2 minutes
#else #else
public let healthUpdateInterval = TimeInterval(15 * 60) // 15 minutes public let minutelyUpdateInterval = TimeInterval(15 * 60) // 15 minutes
#endif #endif
public init() {} public init() {}
public func getMinutelyForecast(forLocation location: Location, completion: @escaping MinutelyForecastCompletion) { public func getMinutelyForecast(forLocation location: Location, completion: @escaping MinutelyForecastCompletion) {
internalQueue.addOperation { [weak self] in
let extendedCompletion: MinutelyForecastCompletion = { [weak self] result in
self?.internalQueue.addOperation {
completion(result)
self?.locationsBeingUpdated.remove(location)
}
}
self?.getMinutelyForecastInternal(forLocation: location, completion: extendedCompletion)
}
}
private func getMinutelyForecastInternal(forLocation location: Location, completion: @escaping MinutelyForecastCompletion) {
guard !locationsBeingUpdated.contains(location) else {
completion(.failure(BlendMinutelySourceError.alreadyBeingUpdated))
return
}
locationsBeingUpdated.insert(location)
guard location.region != nil, location.cityName != nil else { guard location.region != nil, location.cityName != nil else {
completion(.failure(BlendMinutelySourceError.invalidParameters)) completion(.failure(BlendMinutelySourceError.invalidParameters))
return return
......
...@@ -375,7 +375,7 @@ public class LocationManager { ...@@ -375,7 +375,7 @@ public class LocationManager {
public func updateMinutelyForecast(for location: Location) { public func updateMinutelyForecast(for location: Location) {
if let lastTimeUpdated = location.minutely?.lastUpdateTime { if let lastTimeUpdated = location.minutely?.lastUpdateTime {
guard Date().timeIntervalSince(lastTimeUpdated) >= minutelyForecastSource.healthUpdateInterval else { guard Date().timeIntervalSince(lastTimeUpdated) >= minutelyForecastSource.minutelyUpdateInterval else {
log.verbose("Update minutely forecast (\(location)): fresh enough (last updated at \(lastTimeUpdated)), skip update.") log.verbose("Update minutely forecast (\(location)): fresh enough (last updated at \(lastTimeUpdated)), skip update.")
return return
} }
...@@ -386,7 +386,11 @@ public class LocationManager { ...@@ -386,7 +386,11 @@ public class LocationManager {
switch result { switch result {
case .success(let minutelyForecast): case .success(let minutelyForecast):
self.make self.makeChanges(to: location, in: "minutely") { (location) -> Location in
var updatedLocation = location
updatedLocation.minutely = minutelyForecast
return updatedLocation
}
case .failure(let error): case .failure(let error):
self.log.error("Update minutely (\(location) error: \(error)") self.log.error("Update minutely (\(location) error: \(error)")
} }
......
...@@ -10,7 +10,7 @@ import Foundation ...@@ -10,7 +10,7 @@ import Foundation
public typealias MinutelyForecastCompletion = (_ result: Result<MinutelyForecast, Error>) -> () public typealias MinutelyForecastCompletion = (_ result: Result<MinutelyForecast, Error>) -> ()
public protocol MinutelyForecastSource { public protocol MinutelyForecastSource {
var healthUpdateInterval: TimeInterval { get } var minutelyUpdateInterval: TimeInterval { get }
func getMinutelyForecast(forLocation location: Location, completion: @escaping MinutelyForecastCompletion) func getMinutelyForecast(forLocation location: Location, completion: @escaping MinutelyForecastCompletion)
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment