Commit e1ae935a by Demid Merzlyakov

Alerts parsing is working.

parent e45681f9
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
buildConfiguration = "Debug"> buildConfiguration = "Debug">
</AnalyzeAction> </AnalyzeAction>
<ArchiveAction <ArchiveAction
buildConfiguration = "Debug" buildConfiguration = "Release"
revealArchiveInOrganizer = "YES"> revealArchiveInOrganizer = "YES">
</ArchiveAction> </ArchiveAction>
</Scheme> </Scheme>
...@@ -166,6 +166,8 @@ public class LocationManager { ...@@ -166,6 +166,8 @@ public class LocationManager {
self.storage = storage self.storage = storage
self.deviceLocationMonitor.delegate = self self.deviceLocationMonitor.delegate = self
self.nwsAlertsManager.delegate = self
storage.load { [weak self] (locations, selectedIndex, error) in storage.load { [weak self] (locations, selectedIndex, error) in
DispatchQueue.main.async { DispatchQueue.main.async {
guard let self = self else { return } guard let self = self else { return }
...@@ -473,3 +475,14 @@ extension LocationManager: DeviceLocationMonitorDelegate { ...@@ -473,3 +475,14 @@ extension LocationManager: DeviceLocationMonitorDelegate {
} }
} }
} }
// MARK: - NWSAlertsManagerDelegate
extension LocationManager: NWSAlertsManagerDelegate {
public func extendedInfoAvailable(from alertsManager: NWSAlertsManager, for alert: NWSAlert) {
DispatchQueue.main.async {
if let alertIndex = self.selectedLocation?.notifications?.nwsAlerts.firstIndex(of: alert) {
self.selectedLocation?.notifications?.nwsAlerts[alertIndex] = alert
}
}
}
}
...@@ -9,5 +9,5 @@ import Foundation ...@@ -9,5 +9,5 @@ import Foundation
public struct Notifications { public struct Notifications {
public let updatedAt: Date public let updatedAt: Date
public let nwsAlerts: [NWSAlert] public var nwsAlerts: [NWSAlert]
} }
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
import Foundation import Foundation
public struct NWSAlert: Codable, Equatable, Hashable { public struct NWSAlert: Codable, Equatable, Hashable {
public var issueDate: Date?
public let weatherID: String public let weatherID: String
public let messageID: String public let messageID: String
public let messageURL: String public let messageURL: String
......
...@@ -18,8 +18,7 @@ class NWSAlertInfoParser { ...@@ -18,8 +18,7 @@ class NWSAlertInfoParser {
} }
let urlSession = URLSession.shared let urlSession = URLSession.shared
urlSession.dataTask(with: url) { [weak self] (data, response, error) in urlSession.dataTask(with: url) { (data, response, error) in
guard let self = self else { return }
if let httpResponse = response as? HTTPURLResponse { if let httpResponse = response as? HTTPURLResponse {
guard httpResponse.statusCode >= 200 && httpResponse.statusCode < 400 else { guard httpResponse.statusCode >= 200 && httpResponse.statusCode < 400 else {
log.error("HTTP error \(httpResponse.statusCode)") log.error("HTTP error \(httpResponse.statusCode)")
...@@ -32,9 +31,16 @@ class NWSAlertInfoParser { ...@@ -32,9 +31,16 @@ class NWSAlertInfoParser {
completion(nil) completion(nil)
return return
} }
log.debug("Response: \(responseString)")
let extendedInfo: NWSAlertExtendedInfo = self.parseExtendedInfo(from: responseString) let extendedInfo: NWSAlertExtendedInfo = self.parseExtendedInfo(from: responseString)
let debugEncoder = JSONEncoder()
debugEncoder.outputFormatting = .prettyPrinted
debugEncoder.dateEncodingStrategy = .iso8601
if let jsonData = try? debugEncoder.encode(extendedInfo), let json = String(data: jsonData, encoding: .utf8) {
log.debug("Parsed: \(json)")
}
completion(extendedInfo) completion(extendedInfo)
} }.resume()
} }
// MARK: - Private methods // MARK: - Private methods
......
...@@ -15,7 +15,12 @@ public enum NWSError: Error { ...@@ -15,7 +15,12 @@ public enum NWSError: Error {
case badServerResponse(Error?) case badServerResponse(Error?)
} }
public protocol NWSAlertsManagerDelegate: class {
func extendedInfoAvailable(from alertsManager: NWSAlertsManager, for alert: NWSAlert)
}
public class NWSAlertsManager { public class NWSAlertsManager {
public weak var delegate: NWSAlertsManagerDelegate?
public typealias Completion = ([NWSAlert]?, NWSError?) -> () public typealias Completion = ([NWSAlert]?, NWSError?) -> ()
#if DEBUG #if DEBUG
public let updateInterval = TimeInterval(2 * 60) // 2 minutes public let updateInterval = TimeInterval(2 * 60) // 2 minutes
...@@ -33,11 +38,12 @@ public class NWSAlertsManager { ...@@ -33,11 +38,12 @@ public class NWSAlertsManager {
private let log = Logger(componentName: "NWSAlertsManager") private let log = Logger(componentName: "NWSAlertsManager")
private var locationsBeingUpdated = Set<Location>() private var locationsBeingUpdated = Set<Location>()
private var extendedInfoBeingFetched = Set<NWSAlert>()
private var baseUrl: String { private var baseUrl: String {
useStaging ? baseUrlStaging : baseUrlProduction useStaging ? baseUrlStaging : baseUrlProduction
} }
/// This queue is needed to synchronize access to locationsBeingUpdated and the alerts list. Also, to make logging more clear. /// This queue is needed to synchronize access to locationsBeingUpdated and extendedInfoBeingFetched. Also, to make logging more clear.
private let internalQueue: OperationQueue = { private let internalQueue: OperationQueue = {
let queue = OperationQueue() let queue = OperationQueue()
queue.name = "WdtWeatherSource Queue" queue.name = "WdtWeatherSource Queue"
...@@ -66,6 +72,10 @@ public class NWSAlertsManager { ...@@ -66,6 +72,10 @@ public class NWSAlertsManager {
} }
} }
public func extendedInfo(for alert: NWSAlert) -> NWSAlertExtendedInfo? {
return alerts.first(where: { $0 == alert })?.extendedInfo
}
private func fetchActiveAlertsInternal(for location: Location, completion: @escaping NWSAlertsManager.Completion) { private func fetchActiveAlertsInternal(for location: Location, completion: @escaping NWSAlertsManager.Completion) {
guard !locationsBeingUpdated.contains(location) else { guard !locationsBeingUpdated.contains(location) else {
completion(nil, .alreadyBeingUpdated) completion(nil, .alreadyBeingUpdated)
...@@ -133,6 +143,7 @@ public class NWSAlertsManager { ...@@ -133,6 +143,7 @@ public class NWSAlertsManager {
self.merge(alerts: eventsWithLocation) self.merge(alerts: eventsWithLocation)
completion(eventsWithLocation, nil) completion(eventsWithLocation, nil)
} }
catch { catch {
completion(nil, .badServerResponse(error)) completion(nil, .badServerResponse(error))
...@@ -141,7 +152,35 @@ public class NWSAlertsManager { ...@@ -141,7 +152,35 @@ public class NWSAlertsManager {
dataTask.resume() dataTask.resume()
} }
func merge(alerts newAlerts: [NWSAlert]) { private func fetchAllExtendedInfo(for alerts: [NWSAlert]) {
internalQueue.addOperation { [weak self] in
guard let self = self else { return }
var newAlertsToFetch = [NWSAlert]()
let parser = NWSAlertInfoParser()
for alert in alerts {
if !self.extendedInfoBeingFetched.contains(alert) {
self.extendedInfoBeingFetched.insert(alert)
parser.fetchExtendedInfo(for: alert) { [weak self] (extendedInfo) in
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
guard let alertIndex = self.alerts.firstIndex(where: { $0 == alert }) else {
return
}
self.alerts[alertIndex].extendedInfo = extendedInfo
self.internalQueue.addOperation {
self.extendedInfoBeingFetched.remove(alert)
}
self.delegate?.extendedInfoAvailable(from: self, for: self.alerts[alertIndex])
}
}
}
}
}
}
private func merge(alerts newAlerts: [NWSAlert]) {
//TODO: optimize //TODO: optimize
var resultingSet = Set<NWSAlert>() var resultingSet = Set<NWSAlert>()
for alert in self.alerts { for alert in self.alerts {
...@@ -150,7 +189,7 @@ public class NWSAlertsManager { ...@@ -150,7 +189,7 @@ public class NWSAlertsManager {
} }
} }
for alert in newAlerts { for alert in newAlerts {
if !alert.expired { if !alert.expired && !resultingSet.contains(alert) {
resultingSet.insert(alert) resultingSet.insert(alert)
} }
} }
...@@ -163,5 +202,6 @@ public class NWSAlertsManager { ...@@ -163,5 +202,6 @@ public class NWSAlertsManager {
DispatchQueue.main.sync { DispatchQueue.main.sync {
self.alerts = resultingAlerts self.alerts = resultingAlerts
} }
fetchAllExtendedInfo(for: resultingAlerts)
} }
} }
...@@ -83,7 +83,7 @@ class TodayAlertCell: UITableViewCell { ...@@ -83,7 +83,7 @@ class TodayAlertCell: UITableViewCell {
infoLabel.text = infoTemplate infoLabel.text = infoTemplate
if let issueDate = mostSevereAlert.issueDate { if let extendedInfo = mostSevereAlert.extendedInfo, let issueDate = extendedInfo.issueDate {
let secondsAgo = Date().timeIntervalSince(issueDate) let secondsAgo = Date().timeIntervalSince(issueDate)
let formatter = DateComponentsFormatter() let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.day, .hour, .minute, .second] formatter.allowedUnits = [.day, .hour, .minute, .second]
......
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