summaryrefslogtreecommitdiff
path: root/DomainDataPortabilityService.swift
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-04-24 15:04:54 -0500
committerChristian Cleberg <[email protected]>2026-04-24 15:04:54 -0500
commit3f0b7746b1bee4c2f626eb805e3fd13c5f2f5d22 (patch)
tree17c710faf6191ac86ea5b6cab4df240cf2cefef9 /DomainDataPortabilityService.swift
parentd0b3b7a15b59266b4ae4262fdb0364245092c17c (diff)
downloaddomain-dig-3f0b7746b1bee4c2f626eb805e3fd13c5f2f5d22.tar.gz
domain-dig-3f0b7746b1bee4c2f626eb805e3fd13c5f2f5d22.tar.bz2
domain-dig-3f0b7746b1bee4c2f626eb805e3fd13c5f2f5d22.zip
DomainDig v3.8.0 — Smart Monitoring
* Stable domain intervals * Frequent changes decrease intervals * Duplicate states do not trigger alerts * Quiet hours suppress alerts * Quiet hours across midnight work correctly * Sensitivity levels alter behavior as expected
Diffstat (limited to 'DomainDataPortabilityService.swift')
-rw-r--r--DomainDataPortabilityService.swift30
1 files changed, 27 insertions, 3 deletions
diff --git a/DomainDataPortabilityService.swift b/DomainDataPortabilityService.swift
index fabdfdd..ab0bc0b 100644
--- a/DomainDataPortabilityService.swift
+++ b/DomainDataPortabilityService.swift
@@ -231,7 +231,9 @@ enum DataPortabilityCSV {
certificateWarningLevel: certificateLevel,
certificateDaysRemaining: Int(row["certificateDaysRemaining"] ?? ""),
lastMonitoredAt: parseDate(row["lastMonitoredAt"]),
- lastAlertAt: parseDate(row["lastAlertAt"])
+ lastAlertAt: parseDate(row["lastAlertAt"]),
+ monitoringState: MonitoringState(),
+ pendingMonitoringAlerts: []
)
}
}
@@ -1104,7 +1106,9 @@ enum DomainDataPortabilityService {
certificateWarningLevel: higherCertificateWarningLevel(existing.certificateWarningLevel, incoming.certificateWarningLevel),
certificateDaysRemaining: winner.certificateDaysRemaining ?? existing.certificateDaysRemaining ?? incoming.certificateDaysRemaining,
lastMonitoredAt: [existing.lastMonitoredAt, incoming.lastMonitoredAt].compactMap { $0 }.max(),
- lastAlertAt: [existing.lastAlertAt, incoming.lastAlertAt].compactMap { $0 }.max()
+ lastAlertAt: [existing.lastAlertAt, incoming.lastAlertAt].compactMap { $0 }.max(),
+ monitoringState: preferredMonitoringState(existing.monitoringState, incoming.monitoringState),
+ pendingMonitoringAlerts: deduplicatedPendingAlerts(existing.pendingMonitoringAlerts + incoming.pendingMonitoringAlerts)
)
}
@@ -1272,10 +1276,30 @@ enum DomainDataPortabilityService {
certificateWarningLevel: trackedDomain.certificateWarningLevel,
certificateDaysRemaining: trackedDomain.certificateDaysRemaining,
lastMonitoredAt: trackedDomain.lastMonitoredAt,
- lastAlertAt: trackedDomain.lastAlertAt
+ lastAlertAt: trackedDomain.lastAlertAt,
+ monitoringState: trackedDomain.monitoringState,
+ pendingMonitoringAlerts: trackedDomain.pendingMonitoringAlerts
)
}
+ private static func preferredMonitoringState(_ lhs: MonitoringState, _ rhs: MonitoringState) -> MonitoringState {
+ let lhsDate = [lhs.lastCheck, lhs.lastAlertDate, lhs.lastChangeDate].compactMap { $0 }.max() ?? .distantPast
+ let rhsDate = [rhs.lastCheck, rhs.lastAlertDate, rhs.lastChangeDate].compactMap { $0 }.max() ?? .distantPast
+ return lhsDate >= rhsDate ? lhs : rhs
+ }
+
+ private static func deduplicatedPendingAlerts(_ alerts: [MonitoringPendingAlert]) -> [MonitoringPendingAlert] {
+ var uniqueByHash: [String: MonitoringPendingAlert] = [:]
+ for alert in alerts {
+ if let existing = uniqueByHash[alert.changeHash] {
+ uniqueByHash[alert.changeHash] = existing.detectedAt >= alert.detectedAt ? existing : alert
+ } else {
+ uniqueByHash[alert.changeHash] = alert
+ }
+ }
+ return uniqueByHash.values.sorted { $0.detectedAt < $1.detectedAt }
+ }
+
private static func normalizedWorkflow(_ workflow: DomainWorkflow) -> DomainWorkflow {
DomainWorkflow(
id: workflow.id,