114 lines
3.3 KiB
Swift
114 lines
3.3 KiB
Swift
|
import Foundation
|
||
|
|
||
|
struct Files {
|
||
|
|
||
|
let configuration: DnsConfiguration
|
||
|
|
||
|
var lastDataURL: URL {
|
||
|
.init(fileURLWithPath: configuration.lastUpdateFilePath)
|
||
|
}
|
||
|
|
||
|
var logFileURL: URL {
|
||
|
.init(fileURLWithPath: configuration.logFilePath)
|
||
|
}
|
||
|
|
||
|
var domainConfigurationURL: URL {
|
||
|
.init(fileURLWithPath: configuration.domainConfigFilePath)
|
||
|
}
|
||
|
|
||
|
init(configurationFileURL: URL) throws {
|
||
|
let data: Data
|
||
|
do {
|
||
|
data = try Data(contentsOf: configurationFileURL)
|
||
|
} catch {
|
||
|
throw DNSError.failedToReadLogFile(error)
|
||
|
}
|
||
|
do {
|
||
|
self.configuration = try JSONDecoder().decode(DnsConfiguration.self, from: data)
|
||
|
} catch {
|
||
|
throw DNSError.failedToDecodeLogFile(error)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func loadDomainConfiguration() throws -> DomainConfiguration {
|
||
|
let data: Data
|
||
|
do {
|
||
|
data = try Data(contentsOf: domainConfigurationURL)
|
||
|
} catch {
|
||
|
throw DNSError.failedToReadDomainConfiguration(error)
|
||
|
}
|
||
|
do {
|
||
|
return try JSONDecoder().decode(DomainConfiguration.self, from: data)
|
||
|
} catch {
|
||
|
throw DNSError.failedToDecodeDomainConfiguration(error)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func loadLastState() throws -> AppState {
|
||
|
guard FileManager.default.fileExists(atPath: configuration.lastUpdateFilePath) else {
|
||
|
return .init(date: Date(), state: .nominal, domainStates: [:])
|
||
|
}
|
||
|
let data: Data
|
||
|
do {
|
||
|
data = try Data(contentsOf: lastDataURL)
|
||
|
} catch {
|
||
|
throw DNSError.failedToReadLastState(error)
|
||
|
}
|
||
|
let decoder = JSONDecoder()
|
||
|
decoder.dateDecodingStrategy = .secondsSince1970
|
||
|
let state: AppState
|
||
|
do {
|
||
|
state = try decoder.decode(AppState.self, from: data)
|
||
|
} catch {
|
||
|
throw DNSError.failedToDecodeLastState(error)
|
||
|
}
|
||
|
return state
|
||
|
}
|
||
|
|
||
|
func save(lastState: AppState) throws {
|
||
|
let encoder = JSONEncoder()
|
||
|
encoder.dateEncodingStrategy = .secondsSince1970
|
||
|
encoder.outputFormatting = .prettyPrinted
|
||
|
|
||
|
let data: Data
|
||
|
do {
|
||
|
data = try encoder.encode(lastState)
|
||
|
} catch {
|
||
|
throw DNSError.failedToEncodeState(error)
|
||
|
}
|
||
|
|
||
|
do {
|
||
|
try data.write(to: lastDataURL)
|
||
|
} catch {
|
||
|
throw DNSError.failedToWriteState(error)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func addLogEntry(changedDomains: [String : DomainState]) throws {
|
||
|
if !FileManager.default.fileExists(atPath: configuration.logFilePath) {
|
||
|
do {
|
||
|
try Data().write(to: logFileURL)
|
||
|
} catch {
|
||
|
throw DNSError.failedToCreateDNSLog(error)
|
||
|
}
|
||
|
}
|
||
|
guard let handle = FileHandle(forUpdatingAtPath: logFileURL.path) else {
|
||
|
throw DNSError.failedToOpenDNSLogForWriting
|
||
|
}
|
||
|
let entry = changedDomains.map {
|
||
|
$1.logEntry(domain: $0)
|
||
|
}
|
||
|
.joined(separator: "\n") + "\n"
|
||
|
let entryData = entry.data(using: .utf8)!
|
||
|
|
||
|
do {
|
||
|
try handle.seekToEnd()
|
||
|
try handle.write(contentsOf: entryData)
|
||
|
try handle.close()
|
||
|
} catch {
|
||
|
throw DNSError.failedToWriteDNSLog(error)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|