Digital PCT265 story ONEAPP-7249 - Polling behavior fixes and logging for clarity.

This commit is contained in:
Hedden, Kyle Matthew 2024-04-30 20:36:49 -04:00
parent 0ab05f4206
commit 3f77a261bc
2 changed files with 52 additions and 5 deletions

View File

@ -0,0 +1,9 @@
//
// MoleculeComparisonProtocol.swift
// MVMCoreUI
//
// Created by Kyle Hedden on 4/29/24.
// Copyright © 2024 Verizon Wireless. All rights reserved.
//
import Foundation

View File

@ -8,6 +8,7 @@
import Foundation import Foundation
import MVMCore import MVMCore
import Combine
public class PollingBehaviorModel: PageBehaviorModelProtocol { public class PollingBehaviorModel: PageBehaviorModelProtocol {
public class var identifier: String { "pollingBehavior" } public class var identifier: String { "pollingBehavior" }
@ -47,15 +48,24 @@ public class PollingBehaviorModel: PageBehaviorModelProtocol {
} }
} }
public class PollingBehavior: NSObject, PageVisibilityBehavior { extension PollingBehaviorModel: CustomDebugStringConvertible {
public var debugDescription: String {
return "\(Self.self) @ \(refreshInterval) firing \(self.refreshAction)"
}
}
public class PollingBehavior: NSObject, PageVisibilityBehavior, PageMoleculeTransformationBehavior, CoreLogging {
public static var loggingCategory: String? { return String(describing: Self.self) }
var model: PollingBehaviorModel var model: PollingBehaviorModel
var delegateObject: MVMCoreUIDelegateObject? var delegateObject: MVMCoreUIDelegateObject?
var lastRefresh = Date.distantPast var lastRefresh = Date() // Treat the last refresh as now on init. refreshOnShown will bypass otherwise.
var pollTimer: DispatchSourceTimer? var pollTimer: DispatchSourceTimer?
var backgroundEventSubscripiton: AnyCancellable?
var remainingTimeToRefresh: TimeInterval { var remainingTimeToRefresh: TimeInterval {
lastRefresh.timeIntervalSinceNow - model.refreshInterval model.refreshInterval + lastRefresh.timeIntervalSinceNow // timeIntervalSinceNow in negative since earlier recording (--)
} }
var firstTimeLoad = true var firstTimeLoad = true
@ -71,6 +81,14 @@ public class PollingBehavior: NSObject, PageVisibilityBehavior {
public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { public required init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) {
self.model = model as! PollingBehaviorModel self.model = model as! PollingBehaviorModel
self.delegateObject = delegateObject self.delegateObject = delegateObject
Self.debugLog("Initializing for \(model)")
}
public func onPageNew(rootMolecules: [any MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) {
if let behaviorVC = delegateObject?.moleculeDelegate as? ViewController, MVMCoreUIUtility.getCurrentVisibleController() == behaviorVC {
// If behavior is initialized after the page is shown, we need to start the timer.
resumePollingTimer(withRemainingTime: refreshOnShown ? 0 : remainingTimeToRefresh, refreshAction: model.refreshAction, interval: model.refreshInterval)
}
} }
public func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) { public func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) {
@ -79,23 +97,43 @@ public class PollingBehavior: NSObject, PageVisibilityBehavior {
public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) { public func onPageHidden(_ delegateObject: MVMCoreUIDelegateObject?) {
pollTimer?.cancel() pollTimer?.cancel()
backgroundEventSubscripiton = nil
} }
func resumePollingTimer(withRemainingTime timeRemaining: TimeInterval, refreshAction: ActionModelProtocol, interval: TimeInterval) { func resumePollingTimer(withRemainingTime timeRemaining: TimeInterval, refreshAction: ActionModelProtocol, interval: TimeInterval) {
let delegateObject = delegateObject let delegateObject = delegateObject
pollTimer?.cancel() pollTimer?.cancel()
let pollingId = UUID().uuidString
debugLog("Scheduling timed event \(pollingId) in \(timeRemaining), interval: \(interval)")
pollTimer = DispatchSource.makeTimerSource() pollTimer = DispatchSource.makeTimerSource()
pollTimer?.schedule(deadline: .now() + timeRemaining, repeating: interval) pollTimer?.schedule(deadline: .now() + timeRemaining, repeating: interval)
pollTimer?.setEventHandler(qos:.utility) { pollTimer?.setEventHandler(qos:.utility) { [weak self] in
Task { guard let self = self else { return }
lastRefresh = Date()
Task { [weak self] in
self?.debugLog("Firing timed event \(pollingId), \(refreshAction)")
if let delegateActionHandler = delegateObject?.actionDelegate as? ActionDelegateProtocol { if let delegateActionHandler = delegateObject?.actionDelegate as? ActionDelegateProtocol {
try? await delegateActionHandler.performAction(with: refreshAction, additionalData: nil, delegateObject: delegateObject) try? await delegateActionHandler.performAction(with: refreshAction, additionalData: nil, delegateObject: delegateObject)
} else { } else {
try? await MVMCoreActionHandler.shared()?.handleAction(with: refreshAction, additionalData: nil, delegateObject: delegateObject) try? await MVMCoreActionHandler.shared()?.handleAction(with: refreshAction, additionalData: nil, delegateObject: delegateObject)
} }
self?.debugLog("Finished timed event \(pollingId)")
} }
} }
pollTimer?.resume() pollTimer?.resume()
setupBackgroundingPause()
}
private func setupBackgroundingPause() {
backgroundEventSubscripiton = NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification).sink { [weak self] _ in
guard let self = self else { return }
pollTimer?.cancel()
backgroundEventSubscripiton = NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification).sink { [weak self] _ in
guard let self = self else { return }
resumePollingTimer(withRemainingTime: remainingTimeToRefresh, refreshAction: model.refreshAction, interval: model.refreshInterval)
}
}
} }
deinit { deinit {