DnsUpdater/Sources/App/Model/DomainState.swift

103 lines
3.1 KiB
Swift
Raw Permalink Normal View History

2024-11-15 10:46:29 +01:00
import Foundation
struct DomainState: Codable {
/// The date of the last successful update
let date: Date
/// The last registered addresses
let addresses: Set<String>
/**
Number of successive errors signaled by the server.
Needed to prevent excessive requests and being flagged as abuse.
*/
let serverErrorCount: Int
/**
Number of errors on the client side.
Errors here will not force the algorithm to back off.
*/
let clientErrorCount: Int
/**
The time to wait before the next update attempt
*/
let currentWaitPeriod: TimeInterval
let lastResult: DNSChangeResponse
init(date: Date, addresses: Set<String>, serverErrorCount: Int, clientErrorCount: Int, currentWaitPeriod: TimeInterval, lastResult: DNSChangeResponse) {
self.date = date
self.addresses = addresses
self.serverErrorCount = serverErrorCount
self.clientErrorCount = clientErrorCount
self.currentWaitPeriod = currentWaitPeriod
self.lastResult = lastResult
}
init(initial date: Date) {
self.date = date
self.addresses = []
self.serverErrorCount = 0
self.clientErrorCount = 0
self.currentWaitPeriod = 0
self.lastResult = .success
}
var nextUpdate: Date {
date.addingTimeInterval(currentWaitPeriod)
}
private static let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
return formatter
}()
func logEntry(domain: String) -> String {
"\(domain);\(DomainState.formatter.string(from: date));\(addressList);\(serverErrorCount);\(clientErrorCount);\(currentWaitPeriod);\(lastResult.rawValue)"
}
var addressList: String {
addresses.sortedList
}
func needsUpdate(at now: Date, to addresses: Set<String>) -> Bool {
guard now >= nextUpdate else {
return false
}
return !self.addresses.subtracting(addresses).isEmpty
}
func updated(_ now: Date, from result: DNSChangeResponse, expecting addresses: Set<String>) -> DomainState {
let addresses = result.isSuccessStatus ? addresses : self.addresses
let serverError = result.isServerError ? serverErrorCount + 1 : 0
let clientError = result.isClientError ? clientErrorCount + 1 : 0
let waitTime = result.delayTime(previous: currentWaitPeriod)
return .init(
date: now,
addresses: addresses,
serverErrorCount: serverError,
clientErrorCount: clientError,
currentWaitPeriod: waitTime,
lastResult: result)
}
}
extension DomainState: Equatable {
static func == (lhs: DomainState, rhs: DomainState) -> Bool {
lhs.date == rhs.date &&
lhs.addresses == rhs.addresses &&
lhs.clientErrorCount == rhs.clientErrorCount &&
lhs.serverErrorCount == rhs.serverErrorCount &&
lhs.currentWaitPeriod == rhs.currentWaitPeriod &&
lhs.lastResult == rhs.lastResult
}
}